Problem
Found while doing #700. isInlineableVersion in packages/server/src/bun-pin-rewrite.js (added in #698) ACCEPTS a caret/tilde/comparator range that carries a PRERELEASE suffix, e.g. ^1.0.0-rc.3. Its regex is /^(?:>=|<=|>|<|=|\^|~)?\d+(?:\.\d+){0,2}(?:[-+][0-9A-Za-z.-]+)?$/, and ^1.0.0-rc.3 matches.
But Bun zero-install ENOENTs on a caret-prerelease inline specifier (verified on Bun 1.3.14):
drizzle-orm@^1.0.0-rc.3 -> error: ENOENT while resolving package
drizzle-orm@1.0.0-rc.3 (exact) -> resolves fine
ms@^2.0.0 (normal caret) -> resolves fine
So an app that declares a dep as a caret-prerelease range (e.g. "drizzle-orm": "^1.0.0-rc.3") would have its bare import rewritten by buildBunPinTransform to drizzle-orm@^1.0.0-rc.3, which then ENOENTs at runtime under Bun zero-install. The rewrite makes it WORSE than leaving it bare (bare resolves to latest, which at least loads). #700 sidesteps this by keeping the scaffold's drizzle pin EXACT, but a user could still hit it directly.
Design / approach
Tighten isInlineableVersion to REJECT a range operator (^ ~ >= <= > < =) combined with a prerelease suffix, so a caret-prerelease is left BARE (resolves to latest, the safe pre-feature behavior) instead of being forwarded to a broken specifier. An EXACT prerelease (1.0.0-rc.3, no range operator) must still be accepted (bun resolves it). A normal range with no prerelease stays accepted.
Implementation notes
- Where:
isInlineableVersion in packages/server/src/bun-pin-rewrite.js (regex), plus a unit case in packages/server/test/bun-pin-rewrite/bun-pin-rewrite.test.js (accept 1.0.0-rc.3 exact, reject ^1.0.0-rc.3 / ~1.0.0-beta.1).
- Verify against the real bun behavior (the ENOENT above) in
test/bun/pin-rewrite.mjs if practical.
- Landmine: do not reject an exact prerelease; only the range-operator-plus-prerelease combination is unresolvable.
Acceptance criteria
Relates to #698, #700.
Problem
Found while doing #700.
isInlineableVersioninpackages/server/src/bun-pin-rewrite.js(added in #698) ACCEPTS a caret/tilde/comparator range that carries a PRERELEASE suffix, e.g.^1.0.0-rc.3. Its regex is/^(?:>=|<=|>|<|=|\^|~)?\d+(?:\.\d+){0,2}(?:[-+][0-9A-Za-z.-]+)?$/, and^1.0.0-rc.3matches.But Bun zero-install ENOENTs on a caret-prerelease inline specifier (verified on Bun 1.3.14):
drizzle-orm@^1.0.0-rc.3->error: ENOENT while resolving packagedrizzle-orm@1.0.0-rc.3(exact) -> resolves finems@^2.0.0(normal caret) -> resolves fineSo an app that declares a dep as a caret-prerelease range (e.g.
"drizzle-orm": "^1.0.0-rc.3") would have its bare import rewritten bybuildBunPinTransformtodrizzle-orm@^1.0.0-rc.3, which then ENOENTs at runtime under Bun zero-install. The rewrite makes it WORSE than leaving it bare (bare resolves to latest, which at least loads). #700 sidesteps this by keeping the scaffold's drizzle pin EXACT, but a user could still hit it directly.Design / approach
Tighten
isInlineableVersionto REJECT a range operator (^ ~ >= <= > < =) combined with a prerelease suffix, so a caret-prerelease is left BARE (resolves to latest, the safe pre-feature behavior) instead of being forwarded to a broken specifier. An EXACT prerelease (1.0.0-rc.3, no range operator) must still be accepted (bun resolves it). A normal range with no prerelease stays accepted.Implementation notes
isInlineableVersioninpackages/server/src/bun-pin-rewrite.js(regex), plus a unit case inpackages/server/test/bun-pin-rewrite/bun-pin-rewrite.test.js(accept1.0.0-rc.3exact, reject^1.0.0-rc.3/~1.0.0-beta.1).test/bun/pin-rewrite.mjsif practical.Acceptance criteria
Relates to #698, #700.