ESM-only package manifest

Rule

The manifest declares "type": "module", "sideEffects": false, engines.node of >=22.12, and one exports entry for "." whose conditions are types first, then import. There is no require condition, no main pointing at CommonJS, and no tsup. build runs tsc -p tsconfig.build.json.

Do

{
  "name": "@ap/search-bm25",
  "version": "0.1.0",
  "type": "module",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js"
    }
  },
  "files": ["dist"],
  "sideEffects": false,
  "engines": { "node": ">=22.12" },
  "scripts": {
    "build": "tsc -p tsconfig.build.json"
  }
}

Don’t

{
  "name": "@ap/search-bm25",
  "exports": {
    ".": {
      "import": "./dist/esm/index.js",
      "require": "./dist/cjs/index.js",
      "types": "./dist/esm/index.d.ts"
    }
  },
  "scripts": {
    "build": "tsup"
  }
}

Rationale

Consumers in this portfolio are ESM, and Node 22.12 and later can require() an ESM package that has no top-level await, so a CommonJS build adds a tool and the dual-package hazard without adding reach. TypeScript reads export conditions in order, so types listed after import is never used. The manifest is a protected file; this rule guides kernel and scaffold authors, and review stage S2 checks it until the ops-core shape check exists.