Skip to content

bun-pin-rewrite: don't forward a caret-prerelease range (bun ENOENTs on it) #703

Description

@vivek7405

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

  • A caret/tilde/comparator range with a prerelease suffix is left bare (not forwarded).
  • An exact prerelease pin still forwards.
  • Unit test with the accept/reject cases (counterfactual on the regex tweak).

Relates to #698, #700.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type
No fields configured for issues without a type.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions