Skip to content

Ship dual CJS/ESM types for Node16 TypeScript compatibility #350

@jaredatron

Description

@jaredatron

Problem

@stackone/ai currently ships only .d.mts type declarations and ESM runtime files. The published "exports" field is:

{
  ".": "./dist/index.mjs",
  "./package.json": "./package.json"
}

And "types" points at ./dist/index.d.mts.

TypeScript projects using "module": "Node16" or "moduleResolution": "Node16" — which is the recommended config for Node.js libraries — cannot resolve these types. TypeScript raises TS1479:

The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced module is an ESM-only package and cannot be imported with 'require'.

This is because TypeScript under Node16 resolution follows Node's conditional exports algorithm, and .d.mts files are only resolvable in an ESM context. Without a "types" condition in exports or .d.ts fallback files, TypeScript has no way to load the type declarations.

Impact

Any consumer that isn't fully ESM (which is still the majority of production Node.js codebases and monorepos) cannot use @stackone/ai without building a wrapper that re-bundles the runtime and manually converts .d.mts.d.ts.

Suggested Fix

The tsdown.config.ts currently generates only ESM output:

export default defineConfig({
  format: 'esm',
  dts: { tsgo: true, resolve: [/^@types\//, 'type-fest', 'ai'] },
  // ...
});

Add dual CJS/ESM output:

export default defineConfig({
  format: ['esm', 'cjs'],
  // ...
});

And update exports to include both formats with proper "types" conditions nested inside each format (per the conditional exports and nested conditions spec):

{
  "exports": {
    ".": {
      "import": {
        "types": "./dist/index.d.mts",
        "default": "./dist/index.mjs"
      },
      "require": {
        "types": "./dist/index.d.ts",
        "default": "./dist/index.js"
      }
    },
    "./package.json": "./package.json"
  }
}

This gives ESM consumers the existing .mjs + .d.mts files, and CJS/Node16 consumers get .js + .d.ts files that TypeScript can resolve.

Environment

  • @stackone/ai version: 2.4.0
  • TypeScript: 5.x with "module": "Node16", "moduleResolution": "Node16"
  • Package manager: pnpm

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions