|
| 1 | +--- |
| 2 | +"@objectstack/cloud-connection": patch |
| 3 | +"@objectstack/lint": patch |
| 4 | +"@objectstack/mcp": patch |
| 5 | +"@objectstack/metadata-core": patch |
| 6 | +"@objectstack/metadata-fs": patch |
| 7 | +"@objectstack/metadata-protocol": patch |
| 8 | +"@objectstack/metadata": patch |
| 9 | +"@objectstack/observability": patch |
| 10 | +"@objectstack/plugin-webhooks": patch |
| 11 | +"@objectstack/rest": patch |
| 12 | +"@objectstack/runtime": patch |
| 13 | +"@objectstack/service-analytics": patch |
| 14 | +"@objectstack/service-automation": patch |
| 15 | +"@objectstack/service-cache": patch |
| 16 | +"@objectstack/service-cluster-redis": patch |
| 17 | +"@objectstack/service-cluster": patch |
| 18 | +"@objectstack/service-datasource": patch |
| 19 | +"@objectstack/service-i18n": patch |
| 20 | +"@objectstack/service-job": patch |
| 21 | +"@objectstack/service-knowledge": patch |
| 22 | +"@objectstack/service-messaging": patch |
| 23 | +"@objectstack/service-package": patch |
| 24 | +"@objectstack/service-queue": patch |
| 25 | +"@objectstack/service-realtime": patch |
| 26 | +"@objectstack/service-settings": patch |
| 27 | +"@objectstack/service-storage": patch |
| 28 | +"@objectstack/verify": patch |
| 29 | +--- |
| 30 | + |
| 31 | +fix(build): give each `exports` condition its own `types` target in the 28 dual-build packages (#13112) |
| 32 | + |
| 33 | +**Published-surface change, zero runtime change.** No emitted byte moves; what |
| 34 | +moves is which declaration file a resolver READS. Maintainer ruling 2026-08-29 |
| 35 | +(decision batch #3, verbatim 「同意」) chose declaring the files over deleting |
| 36 | +them. |
| 37 | + |
| 38 | +## What was wrong |
| 39 | + |
| 40 | +These 28 packages are `"type": "module"` and dual-built, and each spelled one |
| 41 | +`types` condition as a **sibling** of `import`/`require`: |
| 42 | + |
| 43 | +```json |
| 44 | +"exports": { ".": { |
| 45 | + "types": "./dist/index.d.ts", "import": "./dist/index.js", "require": "./dist/index.cjs" |
| 46 | +} } |
| 47 | +``` |
| 48 | + |
| 49 | +A sibling `types` answers for **both** conditions, so a CommonJS consumer was |
| 50 | +handed `dist/index.d.ts` — an ES-module declaration, because the package is |
| 51 | +`"type": "module"` — for an entry point it reaches with `require`. Measured with |
| 52 | +`tsc --traceResolution` on a `"type": "commonjs"` fixture at `moduleResolution: |
| 53 | +node16`: |
| 54 | + |
| 55 | +``` |
| 56 | +error TS1479: The current file is a CommonJS module whose imports will produce |
| 57 | +'require' calls; however, the referenced file is an ECMAScript module and cannot |
| 58 | +be imported with 'require'. |
| 59 | +``` |
| 60 | + |
| 61 | +The JavaScript at `dist/index.cjs` loads perfectly (`check:dual-build-cjs-loads` |
| 62 | +has asserted that for months). It is the **types** that told the consumer the |
| 63 | +supported `require` entry point could not be required. The `dist/index.d.cts` |
| 64 | +twin tsup emits beside it — 36 files, 5,517,701 B on this build — was named by |
| 65 | +no condition at all and shipped in every tarball unreachable. |
| 66 | + |
| 67 | +## What changed |
| 68 | + |
| 69 | +Each condition now names its own declaration, the shape TypeScript documents: |
| 70 | + |
| 71 | +```json |
| 72 | +"exports": { ".": { |
| 73 | + "import": { "types": "./dist/index.d.ts", "default": "./dist/index.js" }, |
| 74 | + "require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" } |
| 75 | +} } |
| 76 | +``` |
| 77 | + |
| 78 | +33 entry points across 27 packages, subpaths included. The root `types` field is |
| 79 | +untouched, so `node10` resolvers are unaffected; the `import` condition resolves |
| 80 | +exactly what it resolved before, measured as an unchanged control in the same |
| 81 | +run. |
| 82 | + |
| 83 | +## `@objectstack/core` is deliberately NOT changed |
| 84 | + |
| 85 | +Splitting a declaration in two makes TypeScript compare it nominally, and |
| 86 | +`ObjectKernel` carries a `private plugins` member that reaches every plugin |
| 87 | +through `PluginContext.getKernel()`. With core split, whole-repo `pnpm build` |
| 88 | +fails in `@objectstack/verify` with 5 × TS2345 ("Types have separate |
| 89 | +declarations of a private property 'plugins'"); with core held back and the |
| 90 | +other 27 split, 71/71 tasks pass. So core keeps the sibling-`types` shape and |
| 91 | +its two `.d.cts` files (220,854 B) stay unreachable, declared as such in |
| 92 | +`check:dual-build-cjs-loads`. Splitting it needs a decision about core's public |
| 93 | +types, not about an exports map. |
| 94 | + |
| 95 | +## For consumers |
| 96 | + |
| 97 | +- **ESM consumers: nothing changes.** Same declaration file, byte for byte. |
| 98 | +- **CJS consumers under `node16`/`nodenext`: TS1479 goes away** and the |
| 99 | + declarations they get are the ones built for CommonJS. |
| 100 | +- **`node10` / `moduleResolution: node` consumers: nothing changes** — they never |
| 101 | + read `exports`. |
| 102 | +- Nothing is removed: every path that resolved before still resolves. |
| 103 | + |
| 104 | +Packages that are CJS-first (`require` → `./dist/index.js`, no `"type": "module"`) |
| 105 | +were already correct and are untouched — their `dist/index.d.ts` really is the |
| 106 | +CommonJS declaration. Their ESM mirror (an unreachable `.d.mts` under the |
| 107 | +`import` condition) is a separate, larger population and is filed separately per |
| 108 | +the ruling, not fixed here. |
| 109 | + |
| 110 | +`check:dual-build-cjs-loads` grew a fourth invariant (TYPED) that reds on the old |
| 111 | +shape, so the drift cannot return silently. |
0 commit comments