Skip to content

fix: route CJS consumers to CJS declarations#852

Merged
hassiebp merged 2 commits into
mainfrom
hassiebbot/fix-cjs-types-exports
Jun 30, 2026
Merged

fix: route CJS consumers to CJS declarations#852
hassiebp merged 2 commits into
mainfrom
hassiebbot/fix-cjs-types-exports

Conversation

@hassiebp

@hassiebp hassiebp commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Route package export maps through nested import/require conditions with declaration files that match the runtime module kind.
  • Point NodeNext/CommonJS consumers at generated ./dist/index.d.cts files while keeping ESM consumers on ./dist/index.d.ts.
  • Apply the same metadata fix to all published SDK packages and add a unit regression test for the export-map shape.

Root Cause

The packages publish CJS runtime entrypoints via require, but exports["."].types always pointed TypeScript at ./dist/index.d.ts. Because these packages are type: "module", Node16/NodeNext CommonJS consumers resolved a CJS runtime file with an ESM declaration file, triggering TS1479/ATTW "Masquerading as ESM" failures.

Tsup already emits matching .d.cts declarations; they were just unreachable from the package export maps.

Refs LFE-10565 and langfuse/langfuse#14640.

Validation

  • corepack pnpm test:unit -- package-exports
  • corepack pnpm format:check
  • corepack pnpm typecheck
  • corepack pnpm lint
  • PATH=/Users/hassieb/.nvm/versions/node/v24.14.0/bin:$PATH corepack pnpm build
  • PATH=/Users/hassieb/.nvm/versions/node/v24.14.0/bin:$PATH corepack pnpm dlx @arethetypeswrong/cli --pack packages/core --format table --no-emoji --no-color
  • PATH=/Users/hassieb/.nvm/versions/node/v24.14.0/bin:$PATH corepack pnpm dlx @arethetypeswrong/cli --pack packages/langchain --format table --no-emoji --no-color
  • Local packed @langfuse/core tarball in a CJS project with module: "node16" and moduleResolution: "node16"; both value and type-only imports pass tsc --noEmit.
  • Husky pre-commit hook passed check:lint, check:type, and check:format.

Greptile Summary

This PR fixes a TypeScript type-resolution bug where CJS consumers using moduleResolution: "node16" or "nodenext" were being directed to ESM declaration files (.d.ts), triggering TS1479 "Masquerading as ESM" errors. The fix restructures the exports map in all eight published packages from a flat types/import/require shape to nested import and require conditions, each carrying its own matching types pointer.

  • All eight package.json files are updated consistently: require now points TypeScript at ./dist/index.d.cts while import keeps ./dist/index.d.ts. The types condition is correctly ordered first in each block, which TypeScript requires when evaluating conditions.
  • A new unit test (tests/unit/package-exports.test.ts) asserts the exact structure and key ordering of every package's export map, providing a regression guard for future edits.

Confidence Score: 5/5

Safe to merge; the change is mechanically consistent across all eight packages and has been validated with ATTW, tsc, and the new unit test.

The restructured export maps are applied identically to all eight packages, the types condition is correctly ordered before default in both blocks, and the top-level types fallback remains for older TypeScript versions. The new unit test locks down key ordering so future edits cannot silently regress back to the broken shape. No logic errors or missing cases found.

No files require special attention; the changes are uniform boilerplate and the test covers all packages.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    Consumer[TypeScript Consumer]
    Consumer -->|moduleResolution: node16/nodenext| ExportMap["package.json exports['.']"]

    ExportMap -->|ESM import| ImportBlock["import condition"]
    ExportMap -->|CJS require| RequireBlock["require condition"]

    ImportBlock --> ImportTypes["types: ./dist/index.d.ts (ESM declaration)"]
    ImportBlock --> ImportDefault["default: ./dist/index.mjs (ESM runtime)"]

    RequireBlock --> RequireTypes["types: ./dist/index.d.cts (CJS declaration) - Fixed"]
    RequireBlock --> RequireDefault["default: ./dist/index.cjs (CJS runtime)"]

    style RequireTypes fill:#90EE90
    style ImportTypes fill:#90EE90
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 -->|moduleResolution: node16/nodenext| ExportMap["package.json exports['.']"]

    ExportMap -->|ESM import| ImportBlock["import condition"]
    ExportMap -->|CJS require| RequireBlock["require condition"]

    ImportBlock --> ImportTypes["types: ./dist/index.d.ts (ESM declaration)"]
    ImportBlock --> ImportDefault["default: ./dist/index.mjs (ESM runtime)"]

    RequireBlock --> RequireTypes["types: ./dist/index.d.cts (CJS declaration) - Fixed"]
    RequireBlock --> RequireDefault["default: ./dist/index.cjs (CJS runtime)"]

    style RequireTypes fill:#90EE90
    style ImportTypes fill:#90EE90
Loading

Reviews (1): Last reviewed commit: "psuh" | Re-trigger Greptile

@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
langfuse-js Ready Ready Preview Jun 30, 2026 3:34pm

Request Review

@hassiebp hassiebp marked this pull request as ready for review June 30, 2026 15:32
@github-actions

Copy link
Copy Markdown

@claude review

@hassiebp hassiebp merged commit d1b8183 into main Jun 30, 2026
14 checks passed
@hassiebp hassiebp deleted the hassiebbot/fix-cjs-types-exports branch June 30, 2026 15:58
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.

1 participant