From 68f8e69204b84075ba85f4d9728b41e17a784c64 Mon Sep 17 00:00:00 2001 From: Vivek Date: Thu, 10 Sep 2026 13:28:05 +0530 Subject: [PATCH 1/4] feat: make webjs db bring-your-own-ORM via a webjs.db verb map Drizzle is the scaffold default, not lock-in: the runtime never imports it and db/connection.server.ts is the app's own file. But the webjs db verbs contradicted that. generate / migrate / push / studio resolved the app's drizzle-kit binary and exited 1 with any other ORM installed, while `webjs db migrate` is the spelling baked into the scaffolded dev.before and start.before tasks, the Dockerfile, CI, and the deployment docs. So an ORM swap meant rewriting all of that instead of one thing. A "webjs": { "db": { "": "" } } block in package.json now maps a verb to the shell command webjs db runs instead, with node_modules/.bin on PATH like a before step and the extra CLI args appended. Any key is a verb, so a block can add subcommands. A verb the block does not name keeps its default, so an app with no block is unchanged and the scaffold emits none. The drizzle-kit-missing error and the unknown-verb error both name the block as the way forward. The schema, the WebjsConfig type, and the reader-key lockstep test all carry the new key. Docs: AGENTS.md, the skill's built-ins reference, the database and configuration docs pages, and the CLI README. Closes #1468 --- .agents/skills/webjs/references/built-ins.md | 18 +++ AGENTS.md | 4 +- packages/cli/README.md | 2 +- packages/cli/bin/webjs.js | 42 ++++++- packages/cli/lib/app-tasks.js | 53 +++++++++ packages/cli/lib/create.js | 6 + .../cli/test/app-tasks/app-tasks.test.mjs | 30 ++++- packages/core/src/webjs-config.d.ts | 11 ++ packages/server/src/webjs-config-validate.js | 6 +- .../test/config/webjs-config-schema.test.js | 6 + packages/server/webjs-config.schema.json | 5 + test/cli/db.test.mjs | 109 ++++++++++++++++++ test/cli/help.test.mjs | 11 ++ website/app/docs/configuration/page.ts | 6 +- website/app/docs/database/page.ts | 16 ++- 15 files changed, 311 insertions(+), 14 deletions(-) create mode 100644 test/cli/db.test.mjs diff --git a/.agents/skills/webjs/references/built-ins.md b/.agents/skills/webjs/references/built-ins.md index 1c48337a5..cde3d9ff3 100644 --- a/.agents/skills/webjs/references/built-ins.md +++ b/.agents/skills/webjs/references/built-ins.md @@ -216,6 +216,24 @@ An over-limit body responds `413` without buffering the whole payload. `before` runs to completion first (a non-zero exit aborts the boot). `parallel` (dev only) runs long-lived watchers alongside the server and tears them down on exit. `watch` (dev only) adds extra live-reload directories outside the app tree. +### Bring your own ORM (`webjs.db`) + +Drizzle is the scaffold DEFAULT, not lock-in. The runtime never imports it, `db/connection.server.ts` is the app's own file, and `webjs db` is adapter-driven: a `db` block maps each verb to the shell command `webjs db ` runs instead of the drizzle-kit default (node_modules/.bin on PATH like a `before` step, extra CLI args appended). + +```jsonc +{ "webjs": { + "db": { + "generate": "prisma migrate dev --create-only", + "migrate": "prisma migrate deploy", + "push": "prisma db push", + "studio": "prisma studio", + "reset": "prisma migrate reset --force" + } +} } +``` + +Any key is a verb (`reset` above adds `webjs db reset`). A verb the block does not name keeps its default (drizzle-kit for `generate` / `migrate` / `push` / `studio`, `db/seed.server.ts` for `seed`), so an app with no block is unchanged and the scaffold emits none. The payoff is that `webjs db migrate` stays one spelling across ORMs, so the scaffolded `dev.before` / `start.before`, the Dockerfile, CI, and the deploy docs all keep working after a swap. Write the bare binary (`prisma migrate deploy`), not `npx prisma ...`, since a pure Bun image has no `npx`. The swap itself is the app's own files: replace `db/connection.server.ts` with the new client, drop `drizzle.config.ts` / `db/columns.server.ts`, and keep server-only imports behind `.server.ts` as before. + ### Doctor severity gate `webjs doctor` reports project health, and by default only a broken toolchain fails the exit. `--strict` makes EVERY warning fatal, which is unusable in CI, because four checks are environment-shaped: `GIT_HOOK` wants a local pre-commit hook a runner has no reason to have, `ENV_DRIFT` compares against a `.env` CI does not carry, `VENDOR_PIN` fetches the network, and `FRAMEWORK_RESOLVE` plus `FRAMEWORK_LINKS` depend on the environment. So per-check severity is CONFIG, keyed by the stable code every result carries. diff --git a/AGENTS.md b/AGENTS.md index 12655a2f6..1c0a333f9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -579,7 +579,7 @@ webjs version # print the installed @webjsdev/cli version ( webjs help [command] # full usage banner, or per-command usage + Options + Examples (e.g. webjs help routes, #975). Flag forms: webjs --help / -h (banner), webjs --help / -h (that command). typecheck/db/ui --help forward to their wrapped tool; an unknown topic exits 1 webjs typecheck [tsc args...] # the project's own tsc --noEmit webjs create [--template api] -webjs db # wraps drizzle-kit (+ runs db/seed.server.ts) +webjs db [args] # wraps drizzle-kit by default (+ runs db/seed.server.ts). Bring your own ORM (#1468): a `"webjs": { "db": { "": "" } }` block in package.json runs that shell command instead (node_modules/.bin on PATH, extra args appended), any key is a verb, an unmapped verb keeps its default, so `webjs db migrate` is one spelling across ORMs and the scaffolded start.before / Dockerfile / CI keep working after a swap webjs ui init | add | list | view webjs vendor pin|unpin|list|audit|outdated|update [--from PROVIDER] # importmap pinning, .webjs/vendor/importmap.json ``` @@ -591,7 +591,7 @@ webjs vendor pin|unpin|list|audit|outdated|update [--from PROVIDER] # importma ## Environment, server config, caching, observability - **Env vars.** `process.env.X` reads are server-only; `WEBJS_PUBLIC_`-prefixed names are exposed in the browser via an inline `