Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .changeset/testing-subpath-exports-esm-only.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
---
"@objectstack/metadata-core": minor
"@objectstack/service-cluster": minor
---

fix: the `./testing` subpaths are ESM-only — they no longer advertise a `require` condition vitest refuses to serve (#12985)

Both packages published their test-harness subpath as a dual entry point:

```jsonc
// FROM — @objectstack/metadata-core and @objectstack/service-cluster
"./testing": {
"types": "./dist/testing.d.ts",
"import": "./dist/testing.js",
"require": "./dist/testing.cjs"
}

// TO
"./testing": {
"types": "./dist/testing.d.ts",
"import": "./dist/testing.js"
}
```

The `require` half was a promise neither package could keep. Both subpaths
re-export `vitest`, and vitest **refuses** to be loaded from CommonJS by
design — its CJS entry is a single `throw`:

```
node -e "require('@objectstack/metadata-core/testing')"
Error: Vitest cannot be imported in a CommonJS module using require(). Please use "import" instead.
```

The emitted bytes parse; the load fails inside vitest's own entry, for every
consumer and every code path. So the condition could never resolve to working
code, on any release, since it was first declared. It is removed rather than
repaired because the failure is not ours to fix: a test harness has no business
advertising a `require` condition when the test runner it re-exports does not
serve one.

**Nothing that worked stops working**, and that is why this is not filed as a
breaking removal. A CJS consumer that resolved through the old condition got a
hard `Error` at load; it now gets a resolution error from node instead — a
different message for the same non-working call, and an earlier and clearer
one. The `import` condition, the types and the runtime API are untouched, and
every in-repo consumer already reaches these subpaths through `import`
(`@objectstack/metadata-fs`, `@objectstack/metadata-protocol`,
`@objectstack/rest`, `@objectstack/runtime`, `@objectstack/service-cluster-redis`).

**If you did spell it as `require`** — `require('@objectstack/metadata-core/testing')`
or `require('@objectstack/service-cluster/testing')` — switch the call to
`await import('@objectstack/metadata-core/testing')`, or move the calling
module to ESM. That is the same change the old condition already forced on
you, one error message earlier.

`dist/testing.cjs` is still emitted (both packages build every entry in both
formats) and still parsed by `pnpm check:dual-build-cjs-loads`; it is simply no
longer reachable through the manifest. Removing it from the build is a
tsup-config change with its own risks and is not folded in here.
3 changes: 1 addition & 2 deletions packages/metadata-core/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,8 +14,7 @@
},
"./testing": {
"types": "./dist/testing.d.ts",
"import": "./dist/testing.js",
"require": "./dist/testing.cjs"
"import": "./dist/testing.js"
}
},
"files": [
Expand Down
3 changes: 1 addition & 2 deletions packages/services/service-cluster/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,8 +14,7 @@
},
"./testing": {
"types": "./dist/testing.d.ts",
"import": "./dist/testing.js",
"require": "./dist/testing.cjs"
"import": "./dist/testing.js"
}
},
"scripts": {
Expand Down
11 changes: 1 addition & 10 deletions scripts/dual-build-cjs-loads.baseline.json
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,4 @@
{
"$comment": "Shrink-only, hand-edited. Published `require` entry points that legitimately cannot be require()d, each with the reason. Read by scripts/check-dual-build-cjs-loads.mjs. An entry that starts loading must be DELETED in the same PR that fixes it — the gate reds on a stale exemption. ⛔ A parse failure (SyntaxError in our own emitted bytes) is NEVER ledgerable: the gate ignores an entry here for that class on purpose, because a parse failure is always a fact about what we emitted, never about a dependency. Its steady state is NOT empty — read the reasons, never the count.",
"entries": {
"@objectstack/metadata-core#./testing": {
"reason": "The subpath re-exports vitest, and vitest REFUSES to be loaded from CommonJS by design ('Vitest cannot be imported in a CommonJS module using require(). Please use \"import\" instead.'). The bytes parse; the load fails inside vitest's own entry. Pre-existing and independent of #12971 — the same `require` condition is present at b489d3c725e8, before the import.meta line landed. The real repair is at the manifest (a test-harness subpath has no business advertising a `require` condition), which is a published-exports change and belongs to its own card.",
"diagnostic": "Error: Vitest cannot be imported in a CommonJS module using require()."
},
"@objectstack/service-cluster#./testing": {
"reason": "Same shape as @objectstack/metadata-core#./testing — a vitest-backed test-harness subpath that declares a `require` condition vitest itself refuses to serve. Bytes parse, load fails inside vitest. Repair is the same manifest-level one and belongs to the same card.",
"diagnostic": "Error: Vitest cannot be imported in a CommonJS module using require()."
}
}
"entries": {}
}
Loading