Skip to content

fix(packaging): resolve correct .d.cts types for CJS consumers#846

Closed
david-illing-ck wants to merge 4 commits into
langfuse:mainfrom
david-illing-ck:fix/cjs-types-dual-package-exports
Closed

fix(packaging): resolve correct .d.cts types for CJS consumers#846
david-illing-ck wants to merge 4 commits into
langfuse:mainfrom
david-illing-ck:fix/cjs-types-dual-package-exports

Conversation

@david-illing-ck

@david-illing-ck david-illing-ck commented Jun 22, 2026

Copy link
Copy Markdown

Problem

Fixes #748.

Importing any @langfuse/* package from a CommonJS project using TypeScript moduleResolution: node16/nodenext fails to type-check. Each package ships a single top-level types in its exports map pointing at the ESM .d.ts, and because every package is "type": "module", node16/nodenext resolution interprets that declaration as ESM. A CommonJS consumer therefore resolves an ESM declaration for a require() and the compiler rejects it:

  • TS1479 on value imports
  • TS1541 on type-only imports

This blocks CJS consumers on modern module resolution even though a working .cjs runtime build already ships.

Changes

The matching .d.cts declarations are already emitted by tsup — they were just never referenced in the exports map. This PR nests the types condition under each import/require branch so CJS consumers resolve .d.cts and ESM consumers resolve .d.ts:

// before
"exports": { ".": {
  "types":   "./dist/index.d.ts",
  "import":  "./dist/index.mjs",
  "require": "./dist/index.cjs"
}}

// after
"exports": { ".": {
  "import":  { "types": "./dist/index.d.ts",  "default": "./dist/index.mjs" },
  "require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" }
}}

Applied identically to all 7 packages: core, client, tracing, otel, openai, langchain, and browser.

This is purely additive to type resolution — ESM consumers still resolve import.types → .d.ts byte-for-byte, runtime default entries are unchanged, and node/classic-resolution and bundler consumers are unaffected. No build config changes (the .d.cts artifacts already exist).

Verification

  • @arethetypeswrong/cli — "No problems found" for every package across node10, node16 (from CJS), node16 (from ESM), and bundler (previously failed node16 (from CJS)).
  • Real consumer build — a CommonJS + moduleResolution: node16 project went from failing to a clean tsc with no consumer-side source changes.

It apears I'm missing credentials to run to some of the tests, but I've run what I can without them.

  • pnpm lint
  • pnpm typecheck
  • pnpm test
  • pnpm test:integration
  • pnpm test:e2e
  • pnpm format:check

Release info

Bump level

  • Major
  • Minor
  • Patch

Libraries affected

  • All of them
  • @langfuse/core
  • @langfuse/client
  • @langfuse/tracing
  • @langfuse/otel
  • @langfuse/openai
  • @langfuse/langchain

Greptile Summary

This PR fixes TypeScript TS1479/TS1541 errors for CommonJS consumers using moduleResolution: node16 or nodenext by restructuring the exports field in all 7 package.json files. Previously, a single top-level types condition pointed only at the ESM .d.ts declaration; CJS consumers resolved that ESM declaration for a require() call, which modern TypeScript rejects.

  • Type declaration routing fixed: The exports map is restructured so require.types resolves .d.cts and import.types resolves .d.ts, using the runtime files already emitted by tsup (dts: true with a CJS .cjs extension produces .d.cts automatically).
  • Zero runtime impact: All default entries point to the same .mjs/.cjs artifacts as before; the top-level "types" fallback for pre-exports tooling is preserved.

Confidence Score: 5/5

Safe to merge — changes are confined to exports metadata in package manifests with no modifications to build config or source code.

All 7 packages receive an identical, mechanical change that adds nested types resolution under each import/require branch. The .d.cts artifacts were already being emitted by tsup; this PR simply wires the exports map to reference them. Runtime entries (default) are byte-for-byte unchanged, the top-level types fallback is preserved, and the PR author verified correctness with @arethetypeswrong/cli across all four resolution modes.

No files require special attention — all changes are structurally identical across the 7 package manifests.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    Consumer([TypeScript Consumer])

    Consumer -->|ESM / import| ImportBranch["exports.import"]
    Consumer -->|CJS / require| RequireBranch["exports.require"]

    ImportBranch --> ImportTypes["types: ./dist/index.d.ts"]
    ImportBranch --> ImportDefault["default: ./dist/index.mjs"]

    RequireBranch --> RequireTypes["types: ./dist/index.d.cts"]
    RequireBranch --> RequireDefault["default: ./dist/index.cjs"]

    ImportTypes --> ESMDecl["ESM declaration (.d.ts)"]
    RequireTypes --> CJSDecl["CJS declaration (.d.cts) new"]

    ImportDefault --> ESMRuntime[".mjs runtime"]
    RequireDefault --> CJSRuntime[".cjs runtime"]

    style CJSDecl fill:#22c55e,color:#fff
    style RequireTypes fill:#22c55e,color:#fff
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    Consumer([TypeScript Consumer])

    Consumer -->|ESM / import| ImportBranch["exports.import"]
    Consumer -->|CJS / require| RequireBranch["exports.require"]

    ImportBranch --> ImportTypes["types: ./dist/index.d.ts"]
    ImportBranch --> ImportDefault["default: ./dist/index.mjs"]

    RequireBranch --> RequireTypes["types: ./dist/index.d.cts"]
    RequireBranch --> RequireDefault["default: ./dist/index.cjs"]

    ImportTypes --> ESMDecl["ESM declaration (.d.ts)"]
    RequireTypes --> CJSDecl["CJS declaration (.d.cts) new"]

    ImportDefault --> ESMRuntime[".mjs runtime"]
    RequireDefault --> CJSRuntime[".cjs runtime"]

    style CJSDecl fill:#22c55e,color:#fff
    style RequireTypes fill:#22c55e,color:#fff
Loading

Reviews (1): Last reviewed commit: "fix(packaging): resolve correct .d.cts t..." | Re-trigger Greptile

@vercel

vercel Bot commented Jun 22, 2026

Copy link
Copy Markdown

@david-illing-ck is attempting to deploy a commit to the langfuse Team on Vercel.

A member of the Team first needs to authorize it.

@CLAassistant

CLAassistant commented Jun 22, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Each package shipped a single top-level "types" in its exports map
pointing at the ESM `.d.ts`. Because every package is `"type": "module"`,
TypeScript's node16/nodenext resolution interprets that declaration as
ESM, so CommonJS consumers (moduleResolution node16/nodenext) cannot
import the packages:
  - TS1479 on value imports
  - TS1541 on type-only imports

The matching `.d.cts` declarations are already emitted by tsup but were
never referenced. Nest the `types` condition under each `import`/`require`
branch so CJS consumers resolve `.d.cts` and ESM consumers resolve `.d.ts`.
This is purely additive to type resolution — runtime entries and ESM
consumers are unchanged.

Verified with @arethetypeswrong/cli (all green across node10, node16
from CJS and ESM, and bundler) and against a real CommonJS + node16
consumer build.

Fixes langfuse#748

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@david-illing-ck
david-illing-ck force-pushed the fix/cjs-types-dual-package-exports branch from 22e67fa to e3bb635 Compare June 22, 2026 20:53
@david-illing-ck
david-illing-ck marked this pull request as ready for review June 22, 2026 21:06

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CJS type mismatch when using @langfuse/langchain with TypeScript nodenext module resolution

2 participants