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.