Skip to content

Commit df2c551

Browse files
fix(metadata-core): drop the optional vitest peer so npm 10 installs it again (#23834)
Fixes #23806 Clause-②: no ## What changes `@objectstack/metadata-core` no longer declares `vitest` in `peerDependencies` / `peerDependenciesMeta`. Both objects became empty and are removed. The `vitest` devDependency stays. One patch changeset is added, `.changeset/23806-metadata-core-vitest-peer.md`. - **`pnpm-lock.yaml` does not move.** The importer entry never recorded the peer. `pnpm install --frozen-lockfile` and `pnpm install --lockfile-only` both exit 0, and the lockfile stays byte-unchanged. - **The built `dist/` is byte-identical** before and after the edit (`diff -r` exit 0). `tsup.config.ts` lists `vitest` in `external` itself, so `dist/testing.js` still imports it and does not bundle it. ## Why: who reads `vitest`? Measured on this branch's build and on the published `18.0.0-next.2` tarball: | entry | file(s) | imports `vitest`? | |---|---|---| | `.` (import) | `dist/index.js` + `dist/chunk-URJ4AGQ3.js` | no. Specifiers: `@objectstack/spec` subpaths, `zod`, `module`, `crypto` | | `.` (require) | `dist/index.cjs` | no | | `./testing` | `dist/testing.js` | yes, line 7: `import { describe, it, expect } from "vitest"` | | `./testing` types | `dist/testing.d.ts` | no import, one mention in a comment | The runtime entry never reads `vitest`. Only the test-only `./testing` entry does, and the docblock in `src/testing.ts` already tells consumers to list `vitest` as a devDependency. That sentence is still true, so the file is unchanged. **In-repo consumers.** Every in-repo consumer of `@objectstack/metadata-core/testing` is a test file, in `metadata-fs`, `metadata-protocol`, `rest` or `runtime`. Each of those packages: - declares `vitest: ^4.1.11` in its own `devDependencies`; - links metadata-core as `workspace:*`. So none of them relied on the peer. `../objectui` (at `63d00da`) has no consumer. Of the 85 tracked `package.json` files, metadata-core's was the only one with `vitest` as a peer, a dependency or an optional dependency. ## Measured: npm 10 (control first), then this branch Each install ran in an empty scratch project on 2026-10-16. Upstream at measurement time: - `vitest` dist-tags: `V4` = 4.1.12, `latest` = 5.0.5. - `vitest@4.1.12` peers `@vitest/browser-webdriverio: ^4.1.11`. - The newest 4.1.x of that package is 4.1.11, which peers `vitest: 4.1.11` exactly. So the upstream peer set is still incoherent. | install | npm | result | |---|---|---| | published `@objectstack/metadata-core@18.0.0-next.2` (control) | 10.9.4 | exit 1, `Cannot read properties of null (reading 'edgesOut')` | | published, same (control) | 10.9.9 | exit 1, same error | | this branch's packed tarball | 10.9.4 | exit 0, 4 packages, no `vitest` in the tree; `import('@objectstack/metadata-core')` loads 121 exports | | this branch's packed tarball | 10.9.9 | exit 0, same | | published tarball with ONLY the two peer keys deleted (isolation leg) | 10.9.9 | exit 0 | | published `@objectstack/objectql@18.0.0-next.2` (a dependent) | 10.9.9 | exit 1, `edgesOut` | | same, with root `overrides` pointing metadata-core at this branch's tarball | 10.9.9 | exit 0 | | project on `vitest@5.0.5` + published metadata-core | 11.21.1 | exit 1, `ERESOLVE`: `peerOptional vitest@"^4.0.0" from @objectstack/metadata-core@18.0.0-next.2` | | project on `vitest@5.0.5` + this branch's tarball | 11.21.1 | exit 0 | 17 published packages declare metadata-core directly, among them `objectql`, `runtime`, `rest`, `cli`, `metadata` and `metadata-protocol`. The peer therefore reached every npm install of any of them. ## What this does not fix `@objectstack/plugin-auth` still exits 1 on npm 10.9.9 with the same error, even with metadata-core overridden to this branch's tarball. The cause is `better-auth@1.7.3`, which declares its own optional `vitest` peer (`^2.0.0 || ^3.0.0 || ^4.0.0`). This PR does not work around it. Both user remedies were measured, and the changeset names both: - npm 11 installs plugin-auth (exit 0); - npm 10.9.9 installs it with a root `"overrides": { "vitest": "~4.0.0" }` (exit 0). Putting that remedy where an installing user reads the docs is the `domain:devx` half of the card, as triage routed it. This PR touches no `content/docs/**`. ## The one reader the peer had, and what replaces it Under one non-default layout, the peer did have a reader that the docblock cannot serve. The probe below runs `await import('@objectstack/metadata-core/testing')` in a consumer that lists `vitest` 4.1.11 as a devDependency: | layout | published (with peer) | this branch | |---|---|---| | pnpm workspace sub-package, `hoist=false` | OK | `ERR_MODULE_NOT_FOUND`: `Cannot find package 'vitest'` | | pnpm workspace sub-package, default hoisting | OK | OK | | pnpm single project, `hoist=false` | not run | OK | | npm 11, hoisted | not run | OK | | npm 10.9.9, `vitest ~4.0.0` plus the same override (blank-scaffold shape) | install OK | install OK, probe OK | | pnpm workspace `hoist=false`, plus `packageExtensions` re-declaring the peer | not applicable | OK | The changeset gives that layout the measured `packageExtensions` remedy. Keeping the peer and narrowing its range was considered and rejected, for two reasons: - it pins against an upstream accident, and the range must be updated again once vitest publishes a coherent 4.x; - it keeps the `ERESOLVE` above for every project on vitest 5, including projects that never import `./testing`. ## Verification (at `a27899a51`) - `pnpm --filter @objectstack/metadata-core exec vitest run --maxWorkers=2`: 18 files, 733 tests passed. - `pnpm --filter @objectstack/metadata-core run typecheck`: exit 0. - **Derived gates.** `node scripts/pm/dispatch-gates.mjs --commands` derived 65 commands. All 65 ran: 64 exit 0, and 1 is NOT MEASURED. That one is `pnpm check:dual-build-cjs-loads`, which reports PREREQUISITE NOT MET because it needs every package's `dist/`; CI runs it. In its place, a direct reading: `require` of `packages/metadata-core/dist/index.cjs` loads 121 keys. The `--ran` reconciliation reads 65 derived, 64 run, 1 NOT MEASURED, 0 UNRUN. - **Two gates rerun after meeting their prerequisite.** `check-plugin-teardown-shape --self-test` first exited 3; it passed after its pinned commit was fetched. `check:lean-entry-closure` first exited 3; it passed after objectql's closure was built. Both exit 0. - **Roster gates under `packages/`.** `check:authz-resolver`, `check:error-code-casing` and `check:filter-alias-parity` each exit 0. - **Wide-population families.** The 11 of them walk non-test `.ts` sources, and this diff contains none. CI runs them. ## Acceptance notes - The docblock in `src/testing.ts` is left as is; its sentence is still true. - `vitest@4.1.11` on its own also fails on npm 10.9.9: `npm install -D vitest@4.1.11` in an empty project exits 1 with `edgesOut`. So on npm 10, consumers of `./testing` are held back by upstream whatever this package declares. The `~4.0.0` shape works. - Whether the contract suite runs on vitest 5 was not measured. The changeset says only that this package runs it on vitest 4. --- _Generated by [Claude Code](https://claude.ai/code/session_01TQLy3Yq6vF4SDpTXdr3Uwi)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 3fed1eb commit df2c551

2 files changed

Lines changed: 22 additions & 8 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
'@objectstack/metadata-core': patch
3+
---
4+
5+
fix(metadata-core): the package installs on npm 10 again, and into projects that use vitest 5, because it no longer declares an optional `vitest` peer
6+
7+
Clause-②: no
8+
9+
On npm 10, the npm that Node 22 bundles, `npm install @objectstack/metadata-core` exited 1 with `Cannot read properties of null (reading 'edgesOut')`. So did installing a package that depends on it, such as `@objectstack/objectql`. The cause was this package's optional peer `vitest: ^4.0.0`. It led npm 10 to vitest 4.1.12, whose own peer declarations contradict each other, and npm 10's resolver crashes on that. The same peer also made npm refuse (`ERESOLVE`) to install the package into a project that already uses vitest 5.
10+
11+
The package's main entry never imports `vitest`. Only the test-only `@objectstack/metadata-core/testing` entry does, so the peer is removed. Nothing the package exports changes.
12+
13+
If you import `@objectstack/metadata-core/testing`, list `vitest` in your own `devDependencies`, as that entry's documentation already says. This package runs that suite on vitest 4. In a pnpm workspace with hoisting turned off (`hoist=false`), that entry can no longer find `vitest` from inside a workspace package. Declare the peer back in your `pnpm-workspace.yaml`:
14+
15+
```yaml
16+
packageExtensions:
17+
'@objectstack/metadata-core':
18+
peerDependencies:
19+
vitest: '*'
20+
```
21+
22+
`@objectstack/plugin-auth` still fails the same way on npm 10, because its `better-auth` dependency declares its own optional `vitest` peer. Install it with npm 11, or add `"overrides": { "vitest": "~4.0.0" }` to your project's `package.json`.

‎packages/metadata-core/package.json‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,6 @@
4545
"@objectstack/spec": "workspace:*",
4646
"zod": "^4.6.5"
4747
},
48-
"peerDependencies": {
49-
"vitest": "^4.0.0"
50-
},
51-
"peerDependenciesMeta": {
52-
"vitest": {
53-
"optional": true
54-
}
55-
},
5648
"devDependencies": {
5749
"@types/node": "^26.6.3",
5850
"fast-check": "^4.10.2",

0 commit comments

Comments
 (0)