You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Make webjs db / test / typecheck work under true Bun zero-install (auto-install), WITHOUT requiring bun install. Supersedes #695 (and reverses its earlier "just run bun install" framing). The dev/start server already runs zero-install and gets its deps pinned via the #685 onLoad rewrite; the spawned tooling should reach the same outcome, not bail to an install.
Why it breaks today
The #685 onLoad pin runs only in the webjs SERVER process. webjs db spawns drizzle-kit as a SEPARATE Bun process (and test/typecheck spawn their own), so:
The spawned tool's own bare imports (drizzle-kit's import 'drizzle-orm', the user's db/schema.server.tsimport 'drizzle-orm') hit raw auto-install and get the wrong version.
Propagate the bun-pin onLoad into the spawned tool process so the tool's AND the schema's bare imports (import 'drizzle-orm') resolve to the pinned version. A spawned bun run picks up the cwd's bunfig.toml preload (verified locally), so the scaffold can ship (or webjs db can inject) a bunfig.tomlpreload that installs the same buildBunPinTransform onLoad plugin. The spawned tool then gets every bare dep inline-versioned, the same as the server.
First task: verify the mechanism end to end (do NOT assume)
This is where #695 option B died, so prove it before building:
Does a bunfig.toml preload onLoad plugin in the spawned process rewrite the bare imports of (a) the tool's own code and (b) the user-authored db/schema.server.ts it loads, not just the entry file? Measure the LOADED version (import the dep's package.json version), never import.meta.resolve(bareName) (that resolves the unrewritten bare specifier and reads latest).
Does bun x drizzle-kit@1.0.0-rc.3 run the pinned bin under an empty cache, and does its transitive drizzle-orm import resolve to the pin once the preload is active?
Confirm on a fresh bun create ... && bun run db:generate (no install) end to end.
If a piece proves infeasible, fall back is a friendly "this command needs bun install" guard (NOT the preferred outcome; the goal is zero-install).
Implementation notes
Where: the case 'db' block (and test / typecheck spawn paths) in packages/cli/bin/webjs.js; the bun-pin onLoad lives in packages/server/src/action-seed-bun.js + bun-pin-rewrite.js (reuse buildBunPinTransform); the scaffold bunfig.toml generation in packages/cli/lib/create.js.
Tests: a cli/scaffold test that a fresh bun zero-install app runs db:generate + db:migrate successfully with NO install (counterfactual: it fails today). Bun-only path, so a test/bun/* assertion.
Docs: update agent-docs/runtime.md, docs/app/docs/runtime/page.ts, packages/cli/AGENTS.md (the current "tooling needs an install" note flips to "tooling works zero-install").
Acceptance criteria
A fresh bun create ... && bun run db:generate && bun run db:migrate works with NO bun install.
The spawned tool resolves drizzle-orm at the pinned version (not the wrong 0.x major).
webjs test / typecheck likewise work zero-install, or are documented as a separate constraint with a reason.
Update (2026-06-25): the bun x approach does NOT work, use bun --preload <runner> (mechanism verified)
Verified this session (recorded on draft PR #708). The body's Approach #1 (spawn bun x drizzle-kit@<pin> and propagate the onLoad into it) is NOT viable as written:
bun x cannot carry the preload.bun --preload P x <pkg> gives Script not found "x"; bun x --preload P treats --preload as a package to install (404 @./P). So the pin onLoad cannot ride bun x.
The working mechanism: spawn bun --preload <server bun-pin-preload.js abspath> <cli runner.mjs> <sub> <args>. bun run honors --preload, and the preload's onLoad reaches the runner's dynamic import('drizzle-kit') (rewriting it to the app-declared pin) AND the user schema's import 'drizzle-orm'. Confirmed with a cowsay repro (a preload rewrote a bare import('cowsay') to cowsay@1.6.0 and it loaded).
Remaining wrinkles to nail in wiring (each needs a check): resolve the server preload abspath from the cli under zero-install (likely a @webjsdev/server/bun-pin-preload subpath export that import.meta.resolve finds in the cache); invoke drizzle-kit programmatically from the runner (set process.argv, import('drizzle-kit/bin.cjs')); generalize to test (node --test) and typecheck (tsc). Builds on #709 (now merged). The cold-cache fetch reliability stays the #705-class caveat (the inline-pinned fetch is far more reliable than bare-latest, not 100%).
Goal
Make
webjs db/test/typecheckwork under true Bun zero-install (auto-install), WITHOUT requiringbun install. Supersedes #695 (and reverses its earlier "just run bun install" framing). The dev/start server already runs zero-install and gets its deps pinned via the #685 onLoad rewrite; the spawned tooling should reach the same outcome, not bail to an install.Why it breaks today
The #685 onLoad pin runs only in the webjs SERVER process.
webjs dbspawns drizzle-kit as a SEPARATE Bun process (and test/typecheck spawn their own), so:import 'drizzle-orm', the user'sdb/schema.server.tsimport 'drizzle-orm') hit raw auto-install and get the wrong version.resolveBin(cwd, 'drizzle-kit')cannot find the tool bin under an empty cache (no node_modules), so even locating the tool fails (fix: bun zero-install breaks every spawned-subprocess command (db/test/seed/typecheck); pin at the spawn layer #695 option B's gap).Approach (zero-install, no bun install)
Two pieces, both leaning on drizzle now being EXACT-pinned (#700), which is exactly what Bun auto-install can resolve inline:
bun x drizzle-kit@<exact-pin-from-package.json>(bunx auto-installs + runs the pinned bin), instead of resolving a bin from a node_modules that does not exist. This closes the fix: bun zero-install breaks every spawned-subprocess command (db/test/seed/typecheck); pin at the spawn layer #695 resolveBin gap.import 'drizzle-orm') resolve to the pinned version. A spawnedbun runpicks up the cwd'sbunfig.toml preload(verified locally), so the scaffold can ship (orwebjs dbcan inject) abunfig.tomlpreloadthat installs the samebuildBunPinTransformonLoad plugin. The spawned tool then gets every bare dep inline-versioned, the same as the server.First task: verify the mechanism end to end (do NOT assume)
This is where #695 option B died, so prove it before building:
bunfig.toml preloadonLoad plugin in the spawned process rewrite the bare imports of (a) the tool's own code and (b) the user-authoreddb/schema.server.tsit loads, not just the entry file? Measure the LOADED version (import the dep's package.json version), neverimport.meta.resolve(bareName)(that resolves the unrewritten bare specifier and reads latest).bun x drizzle-kit@1.0.0-rc.3run the pinned bin under an empty cache, and does its transitivedrizzle-ormimport resolve to the pin once the preload is active?bun create ... && bun run db:generate(no install) end to end.If a piece proves infeasible, fall back is a friendly "this command needs
bun install" guard (NOT the preferred outcome; the goal is zero-install).Implementation notes
case 'db'block (and test / typecheck spawn paths) inpackages/cli/bin/webjs.js; the bun-pin onLoad lives inpackages/server/src/action-seed-bun.js+bun-pin-rewrite.js(reusebuildBunPinTransform); the scaffoldbunfig.tomlgeneration inpackages/cli/lib/create.js.db:generate+db:migratesuccessfully with NO install (counterfactual: it fails today). Bun-only path, so atest/bun/*assertion.agent-docs/runtime.md,docs/app/docs/runtime/page.ts,packages/cli/AGENTS.md(the current "tooling needs an install" note flips to "tooling works zero-install").Acceptance criteria
bun create ... && bun run db:generate && bun run db:migrateworks with NObun install.webjs test/typechecklikewise work zero-install, or are documented as a separate constraint with a reason.Supersedes #695. Relates to #698, #700, #703.
Update (2026-06-25): the
bun xapproach does NOT work, usebun --preload <runner>(mechanism verified)Verified this session (recorded on draft PR #708). The body's Approach #1 (spawn
bun x drizzle-kit@<pin>and propagate the onLoad into it) is NOT viable as written:bun xcannot carry the preload.bun --preload P x <pkg>givesScript not found "x";bun x --preload Ptreats--preloadas a package to install (404 @./P). So the pin onLoad cannot ridebun x.bun --preload <server bun-pin-preload.js abspath> <cli runner.mjs> <sub> <args>.bun runhonors--preload, and the preload's onLoad reaches the runner's dynamicimport('drizzle-kit')(rewriting it to the app-declared pin) AND the user schema'simport 'drizzle-orm'. Confirmed with a cowsay repro (a preload rewrote a bareimport('cowsay')tocowsay@1.6.0and it loaded).packages/server/src/bun-pin-preload.js, on feat: run webjs db/test/typecheck under bun zero-install (no install) #708) is dependency-free (bun-pin-rewrite.jshas zero imports), so loading it by abspath triggers no auto-install (no chicken-and-egg).Remaining wrinkles to nail in wiring (each needs a check): resolve the server preload abspath from the cli under zero-install (likely a
@webjsdev/server/bun-pin-preloadsubpath export thatimport.meta.resolvefinds in the cache); invoke drizzle-kit programmatically from the runner (setprocess.argv,import('drizzle-kit/bin.cjs')); generalize totest(node --test) andtypecheck(tsc). Builds on #709 (now merged). The cold-cache fetch reliability stays the #705-class caveat (the inline-pinned fetch is far more reliable than bare-latest, not 100%).