4.4 KiB
Fix storage-uri-plugin-bundle so the ./node-fetch subpath emits its .js
Package: @suaveplan/storage-uri-plugin-bundle
Status: PROPOSED
Type: bug-fix
Why
The shipped storage-uri-plugin-bundle package declares a ./node-fetch subpath export in its package.json:
"./node-fetch": {
"import": {
"types": "./dist/node-fetch/node-fetch.d.ts",
"default": "./dist/node-fetch/node-fetch.js"
}
}
…and the existing spec (openspec/specs/storage-uri-plugin-bundle/spec.md, requirement "Server-tier ./node-fetch subpath for file:// roots on Node") requires this entry point to exist and behave correctly. The build, however, only emits dist/node-fetch/node-fetch.d.ts — the .js is never written. Cause:
vite.config.tsdeclareslib: { entry: "src/index.ts" }(single entry).src/index.tsdoes NOT re-exportnodeFileFetch(correctly — the package contract is universal-tier at the root barrel; the node-fetch surface is server-tier and lives behind the subpath).- Rollup, walking only from
src/index.ts, never seessrc/node-fetch/node-fetch.tsand tree-shakes it.vite-plugin-dtswalks the source tree independently, so the.d.tssurvives — masking the defect from type-only consumers.
Node-tier consumers that import @suaveplan/storage-uri-plugin-bundle/node-fetch get MODULE_NOT_FOUND at runtime. Both Stage-3 audio-ir room packages (club, pool) hit this and worked around it by inlining a local nodeFileFetch adapter. The fix is mechanical: add src/node-fetch/node-fetch.ts as a second rollup entry so it's emitted as a top-level chunk.
What changes
- MODIFIED:
vite.config.ts— replacelib: { entry: "src/index.ts" }with a multi-entry build that produces bothdist/index.jsanddist/node-fetch/node-fetch.js. Uselib: { entry: { index: "src/index.ts", "node-fetch/node-fetch": "src/node-fetch/node-fetch.ts" }, formats: ["es"] }.preserveModules: trueis already set, so per-file chunking continues to work. - ADDED requirement: a build-time invariant in the package's capability spec. The runtime contract requirement already exists; this one explicitly mandates that the build artifact ships, so the same regression cannot recur silently.
Out of scope
- Any runtime behavior change.
nodeFileFetch's implementation undersrc/node-fetch/node-fetch.tsis unchanged. - Any change to the root barrel (
src/index.ts) — it stays universal-tier with nonode:*imports. - Audio-IR consumer cleanups. Removing the inline shims in
audio-ir-room-plugin-clubandaudio-ir-room-plugin-poolis a separate, follow-up change once this fix lands. Not bundled here per AGENTS §193 (one change per package).
Source mapping
In-repo fix. No upstream reference. The capability spec already documents the desired behavior; this change adds an additional ADDED requirement covering the build artifact.
Requirements with no source line
| Requirement | Justification |
|---|---|
| Build-time emission invariant | Caught only by Stage-3 consumers; not previously stated as a spec requirement |
Verification approach
tests/build/node-fetch-emit.test.ts— afterbunx turbo build --filter=@suaveplan/storage-uri-plugin-bundle, the test reads<package-root>/dist/node-fetch/node-fetch.jsvianode:fs.statSync, asserts the file exists, is non-empty, and is a.jsfile (not a.d.ts).tests/build/node-fetch-runtime-import.test.ts— dynamicallyimport()s<package-root>/dist/node-fetch/node-fetch.jsdirectly and asserts the exportnodeFileFetchis a function — proves the emitted file is actually runnable, not just present.- Re-runs of all existing node-fetch source-level tests (
src/node-fetch/node-fetch.test.ts) — must remain green; this change does not modify the runtime.
Impact
Affected dependents
Run bunx turbo ls --filter=...@suaveplan/storage-uri-plugin-bundle. Today:
@suaveplan/audio-ir-room-plugin-club— [x] no action needed (reason: inline shim under integration tests does not depend on the subpath emit; the follow-up cleanup change will adopt the shipped subpath)@suaveplan/audio-ir-room-plugin-pool— [x] no action needed (same reason)@suaveplan/audio-ir-loader— [x] no action needed (consumer doesn't import the subpath)
All three remain green at 100/100/100/100 after this fix. The shipped subpath becomes usable for new consumers immediately.