@voltro/cli 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +127 -0
- package/dist/{apiBuild-370ITNRk.js → apiBuild-CHItlwPO.js} +2 -2
- package/dist/apiBuild-D8juhYsS.js +2 -0
- package/dist/bin.js +3 -3
- package/dist/{commands-D-teL_TM.js → commands-CPQuQRXh.js} +1779 -1563
- package/dist/{dbCommand-Dmi-vHfA.js → dbCommand-B8F29zV0.js} +2 -2
- package/dist/dbCommand-Dt7BtdMd.js +2 -0
- package/dist/{dev-CPKbckaN.js → dev-BHLM3RPX.js} +1 -1
- package/dist/{dev-CKyW_LAv.js → dev-C2lCUhYI.js} +1101 -1081
- package/dist/{fileConventions-COg0ZytD.js → fileConventions-Cu0tM-Bl.js} +22 -2
- package/dist/{frameworkTableAssembly-DCLhpHsF.js → frameworkTableAssembly-BA2bAmYN.js} +1 -1
- package/dist/frameworkTableAssembly-D1zJSgOU.js +2 -0
- package/dist/index.js +1 -1
- package/dist/{inspectMetrics-CyVMeofr.js → inspectMetrics-CYDSO3za.js} +1 -1
- package/dist/{serveCommand-CU3Sw4ZM.js → serveCommand-DBzQcCuv.js} +5 -5
- package/dist/serveEntry.js +2 -2
- package/dist/{start-D8ATvTzo.js → start-BtgatJN3.js} +1 -1
- package/dist/startEntry.js +2 -2
- package/package.json +17 -17
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/authentication.md +29 -0
- package/templates/agent-docs/cli.md +80 -0
- package/templates/agent-docs/data.md +2 -2
- package/templates/agent-docs/database/migrations.md +21 -0
- package/templates/agent-docs/schema-driven-ui.md +2 -1
- package/templates/agent-docs/whats-new.md +240 -48
- package/templates/apps/api-ai/package.json +7 -7
- package/templates/apps/api-auth/package.json +8 -8
- package/templates/apps/api-backend/package.json +7 -7
- package/templates/apps/api-backend-deactivation/package.json +7 -7
- package/templates/apps/api-backend-mail/package.json +8 -8
- package/templates/apps/api-backend-mariadb/package.json +9 -9
- package/templates/apps/api-backend-storage/package.json +8 -8
- package/templates/apps/api-data-advanced/package.json +8 -8
- package/templates/apps/api-durable/package.json +8 -8
- package/templates/apps/api-feature-flags/package.json +9 -9
- package/templates/apps/api-governance/package.json +8 -8
- package/templates/apps/api-kv/package.json +8 -8
- package/templates/apps/api-moderation/package.json +8 -8
- package/templates/apps/api-observability/package.json +8 -8
- package/templates/apps/api-ratelimit/package.json +8 -8
- package/templates/apps/api-rbac/package.json +8 -8
- package/templates/apps/api-rest/package.json +7 -7
- package/templates/apps/api-saas/package.json +11 -11
- package/templates/apps/api-search/package.json +8 -8
- package/templates/apps/api-versioning/package.json +8 -8
- package/templates/apps/api-webhooks/package.json +9 -9
- package/templates/apps/changelog/package.json +6 -6
- package/templates/apps/edge-functions/package.json +2 -2
- package/templates/apps/frontend-admin/package.json +8 -8
- package/templates/apps/frontend-app/package.json +8 -8
- package/templates/apps/frontend-blank/package.json +7 -7
- package/templates/apps/frontend-contact/package.json +7 -7
- package/templates/apps/frontend-dashboard/package.json +7 -7
- package/templates/apps/frontend-docs/package.json +7 -7
- package/templates/apps/frontend-i18n/package.json +6 -6
- package/templates/apps/frontend-landing/package.json +7 -7
- package/templates/apps/frontend-spa/package.json +7 -7
- package/templates/apps/frontend-ssr/package.json +7 -7
- package/templates/apps/frontend-ssr-api/package.json +8 -8
- package/templates/apps/frontend-static-blog/package.json +6 -6
- package/dist/apiBuild-DatWP5hh.js +0 -2
- package/dist/dbCommand-B3CeMU3u.js +0 -2
- package/dist/frameworkTableAssembly-DYzb2elg.js +0 -2
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
//#region src/fileConventions.ts
|
|
2
|
-
var e = /\.(query|mutation|action|stream)\.ts$/, t = /\.(query|mutation|action|stream)\.server\.ts$/, n = /\.workflow\.tsx$/, r = /\.workflow\.server\.tsx$/, i = /\.workflow\.tsx?$/, a = /\.trigger\.tsx?$/, o = /\.cron\.tsx?$/, s = /\.webhook\.tsx?$/, c = /\.outbox\.tsx?$/, l = /\.subscribe\.tsx?$/, u = /\.reaction\.tsx?$/, d = /\.aggregate\.tsx?$/, f = /\.startup\.tsx?$/, p = /\.seed\.ts$/, m = /\.relations\.ts$/, h = /\.entity\.ts$|\.schema\.ts$|^schema\.ts$/, g = (e) => i.test(e) && !n.test(e) && !r.test(e), _ = /\.page\.tsx$/, v = /\.island\.tsx?$/, y = /\.component\.tsx$/, b = /\.component\.ui\.tsx$/, x = /\.hook\.tsx?$/, S = /\.internal\.tsx?$/, C = /\.types\.tsx?$/, w = /\.fixture\.tsx?$/, T = /\.tracking\.tsx?$/, E = /\.store\.tsx?$/, D = /\.(test|spec)\.tsx?$/,
|
|
2
|
+
var e = /\.(query|mutation|action|stream)\.ts$/, t = /\.(query|mutation|action|stream)\.server\.ts$/, n = /\.workflow\.tsx$/, r = /\.workflow\.server\.tsx$/, i = /\.workflow\.tsx?$/, a = /\.trigger\.tsx?$/, o = /\.cron\.tsx?$/, s = /\.webhook\.tsx?$/, c = /\.outbox\.tsx?$/, l = /\.subscribe\.tsx?$/, u = /\.reaction\.tsx?$/, d = /\.aggregate\.tsx?$/, f = /\.startup\.tsx?$/, p = /\.seed\.ts$/, m = /\.relations\.ts$/, h = /\.entity\.ts$|\.schema\.ts$|^schema\.ts$/, g = (e) => i.test(e) && !n.test(e) && !r.test(e), _ = /\.page\.tsx$/, v = /\.island\.tsx?$/, y = /\.component\.tsx$/, b = /\.component\.ui\.tsx$/, x = /\.hook\.tsx?$/, S = /\.internal\.tsx?$/, C = /\.types\.tsx?$/, w = /\.fixture\.tsx?$/, T = /\.tracking\.tsx?$/, E = /\.store\.tsx?$/, D = /\.client\.tsx?$/, O = /\.(test|spec)\.tsx?$/, k = [
|
|
3
|
+
e,
|
|
4
|
+
t,
|
|
5
|
+
i,
|
|
6
|
+
r,
|
|
7
|
+
a,
|
|
8
|
+
o,
|
|
9
|
+
s,
|
|
10
|
+
c,
|
|
11
|
+
l,
|
|
12
|
+
u,
|
|
13
|
+
d,
|
|
14
|
+
f,
|
|
15
|
+
p,
|
|
16
|
+
m,
|
|
17
|
+
h,
|
|
18
|
+
/\.route\.tsx?$/,
|
|
19
|
+
E,
|
|
20
|
+
D,
|
|
21
|
+
/\.(agent|tool|email|connection|serverless|server|config|generated)\.tsx?$/
|
|
22
|
+
], A = (e) => k.some((t) => t.test(e)), j = /* @__PURE__ */ new Set([
|
|
3
23
|
"layout.tsx",
|
|
4
24
|
"error.tsx",
|
|
5
25
|
"loading.tsx",
|
|
6
26
|
"not-found.tsx"
|
|
7
27
|
]);
|
|
8
28
|
//#endregion
|
|
9
|
-
export { a as C, i as D, n as E, r as O, T as S, s as T, p as _, w as a, l as b, v as c,
|
|
29
|
+
export { g as A, a as C, i as D, n as E, r as O, T as S, s as T, p as _, w as a, l as b, v as c, j as d, e as f, h as g, m as h, o as i, A as k, c as l, u as m, y as n, x as o, t as p, b as r, S as s, d as t, _ as u, f as v, C as w, O as x, E as y };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as e } from "./appModuleLoader-C9r9mxZt.js";
|
|
2
|
-
import { C as t, D as n, T as r, i, l as a } from "./fileConventions-
|
|
2
|
+
import { C as t, D as n, T as r, i, l as a } from "./fileConventions-Cu0tM-Bl.js";
|
|
3
3
|
import { basename as o, join as s } from "node:path";
|
|
4
4
|
import { pathToFileURL as c } from "node:url";
|
|
5
5
|
import { Effect as l } from "effect";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as e, u as t, x as n } from "./fileConventions-
|
|
1
|
+
import { d as e, u as t, x as n } from "./fileConventions-Cu0tM-Bl.js";
|
|
2
2
|
import { D as r, E as i, T as a, a as o, p as s, w as c } from "./inspect-Dwx0_tUj.js";
|
|
3
3
|
import { basename as l, dirname as u, isAbsolute as d, join as f, relative as p, resolve as m } from "node:path";
|
|
4
4
|
import { fileURLToPath as h, pathToFileURL as g } from "node:url";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { ct as e, t } from "./inspectMetrics-
|
|
1
|
+
import { ct as e, t } from "./inspectMetrics-CYDSO3za.js";
|
|
2
2
|
import { s as n } from "./seedRunner-D6eu-u5U.js";
|
|
3
3
|
import { r, t as i } from "./appModuleLoader-C9r9mxZt.js";
|
|
4
|
-
import { f as a, m as o, n as s, p as c, u as l } from "./frameworkTableAssembly-
|
|
5
|
-
import { l as u } from "./fileConventions-
|
|
6
|
-
import { $ as d, A as ee, B as f, C as te, D as ne, E as re, F as p, H as ie, I as m, J as h, K as ae, L as oe, M as g, N as _, O as se, P as v, Q as y, S as ce, T as le, V as ue, X as de, Y as b, Z as x, _ as fe, a as S, b as C, c as pe, et as me, f as w, g as he, h as ge, j as _e, k as ve, n as ye, p as T, q as be, r as xe, s as Se, v as Ce, w as we, x as Te, y as E, z as Ee } from "./dev-
|
|
7
|
-
import { c as D, r as De } from "./apiBuild-
|
|
4
|
+
import { f as a, m as o, n as s, p as c, u as l } from "./frameworkTableAssembly-BA2bAmYN.js";
|
|
5
|
+
import { l as u } from "./fileConventions-Cu0tM-Bl.js";
|
|
6
|
+
import { $ as d, A as ee, B as f, C as te, D as ne, E as re, F as p, H as ie, I as m, J as h, K as ae, L as oe, M as g, N as _, O as se, P as v, Q as y, S as ce, T as le, V as ue, X as de, Y as b, Z as x, _ as fe, a as S, b as C, c as pe, et as me, f as w, g as he, h as ge, j as _e, k as ve, n as ye, p as T, q as be, r as xe, s as Se, v as Ce, w as we, x as Te, y as E, z as Ee } from "./dev-C2lCUhYI.js";
|
|
7
|
+
import { c as D, r as De } from "./apiBuild-CHItlwPO.js";
|
|
8
8
|
import { t as Oe } from "./bootTiming-BdyP9nYw.js";
|
|
9
9
|
import { n as ke } from "./cliArgs-qdZSElM3.js";
|
|
10
10
|
import { join as Ae } from "node:path";
|
package/dist/serveEntry.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $ as e } from "./inspectMetrics-
|
|
1
|
+
import { $ as e } from "./inspectMetrics-CYDSO3za.js";
|
|
2
2
|
import { c as t } from "./seedRunner-D6eu-u5U.js";
|
|
3
3
|
import { r as n } from "./appModuleLoader-C9r9mxZt.js";
|
|
4
|
-
import { t as r } from "./serveCommand-
|
|
4
|
+
import { t as r } from "./serveCommand-DBzQcCuv.js";
|
|
5
5
|
export { e as loadDotEnv, n as registerAppModules, t as registerDriver, r as runServe };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as e, C as t, E as n, G as r, I as i, J as a, K as o, N as s, O as c, V as l, W as u, X as d, Z as f, _ as ee, a as p, at as m, b as h, c as g, ct as _, dt as v, f as te, g as y, h as b, i as x, it as ne, j as S, k as C, m as w, nt as T, o as re, p as ie, q as E, r as D, rt as O, s as k, t as A, tt as j, v as M, w as ae, y as N } from "./inspectMetrics-
|
|
1
|
+
import { A as e, C as t, E as n, G as r, I as i, J as a, K as o, N as s, O as c, V as l, W as u, X as d, Z as f, _ as ee, a as p, at as m, b as h, c as g, ct as _, dt as v, f as te, g as y, h as b, i as x, it as ne, j as S, k as C, m as w, nt as T, o as re, p as ie, q as E, r as D, rt as O, s as k, t as A, tt as j, v as M, w as ae, y as N } from "./inspectMetrics-CYDSO3za.js";
|
|
2
2
|
import { D as oe, E as se, T as ce, a as P, p as le, w as ue } from "./inspect-Dwx0_tUj.js";
|
|
3
3
|
import { t as de } from "./bootTiming-BdyP9nYw.js";
|
|
4
4
|
import { dirname as fe, extname as F, join as I, resolve as L } from "node:path";
|
package/dist/startEntry.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { $ as e } from "./inspectMetrics-
|
|
2
|
-
import { t } from "./start-
|
|
1
|
+
import { $ as e } from "./inspectMetrics-CYDSO3za.js";
|
|
2
|
+
import { t } from "./start-BtgatJN3.js";
|
|
3
3
|
export { e as loadDotEnv, t as runStartCommand };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "The `voltro` CLI — dev server, codegen, migrations, project scaffolding, agent-docs seeding, and production serve.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -62,22 +62,22 @@
|
|
|
62
62
|
"@effect/platform-node": "^0.107.0",
|
|
63
63
|
"@effect/sql": "^0.51.1",
|
|
64
64
|
"@effect/workflow": "^0.18.2",
|
|
65
|
-
"@voltro/ai": "0.
|
|
66
|
-
"@voltro/cache": "0.
|
|
67
|
-
"@voltro/data-transfer": "0.
|
|
68
|
-
"@voltro/database": "0.
|
|
69
|
-
"@voltro/env": "0.
|
|
70
|
-
"@voltro/kv": "0.
|
|
71
|
-
"@voltro/logger": "0.
|
|
72
|
-
"@voltro/plugin-auth": "0.
|
|
73
|
-
"@voltro/plugin-broadcast": "0.
|
|
74
|
-
"@voltro/plugin-mail": "0.
|
|
75
|
-
"@voltro/plugin-storage": "0.
|
|
76
|
-
"@voltro/plugin-webhooks": "0.
|
|
77
|
-
"@voltro/protocol": "0.
|
|
78
|
-
"@voltro/runtime": "0.
|
|
79
|
-
"@voltro/serverless": "0.
|
|
80
|
-
"@voltro/workflow": "0.
|
|
65
|
+
"@voltro/ai": "0.15.0",
|
|
66
|
+
"@voltro/cache": "0.15.0",
|
|
67
|
+
"@voltro/data-transfer": "0.15.0",
|
|
68
|
+
"@voltro/database": "0.15.0",
|
|
69
|
+
"@voltro/env": "0.15.0",
|
|
70
|
+
"@voltro/kv": "0.15.0",
|
|
71
|
+
"@voltro/logger": "0.15.0",
|
|
72
|
+
"@voltro/plugin-auth": "0.15.0",
|
|
73
|
+
"@voltro/plugin-broadcast": "0.15.0",
|
|
74
|
+
"@voltro/plugin-mail": "0.15.0",
|
|
75
|
+
"@voltro/plugin-storage": "0.15.0",
|
|
76
|
+
"@voltro/plugin-webhooks": "0.15.0",
|
|
77
|
+
"@voltro/protocol": "0.15.0",
|
|
78
|
+
"@voltro/runtime": "0.15.0",
|
|
79
|
+
"@voltro/serverless": "0.15.0",
|
|
80
|
+
"@voltro/workflow": "0.15.0",
|
|
81
81
|
"chokidar": "^5.0.0",
|
|
82
82
|
"ioredis": "^5.11.1",
|
|
83
83
|
"tinyglobby": "^0.2.17",
|
package/templates/AGENTS.md
CHANGED
|
@@ -526,7 +526,7 @@ each plugin's own README.
|
|
|
526
526
|
|
|
527
527
|
| Topic | Open | Summary |
|
|
528
528
|
|---|---|---|
|
|
529
|
-
| **What's new in 0.
|
|
529
|
+
| **What's new in 0.14.0** | `node_modules/@voltro/cli/templates/agent-docs/whats-new.md` | Everything that changed in this version. Read it before hand-rolling something the framework may now ship. |
|
|
530
530
|
| AI | `node_modules/@voltro/cli/templates/agent-docs/ai.md` | How Voltro treats AI — agents, tools, streaming, RAG — all primitives over the same WebSocket as the rest of the framework. |
|
|
531
531
|
| Authentication | `node_modules/@voltro/cli/templates/agent-docs/authentication.md` | How @voltro/plugin-auth wires password + session-cookie auth across api + web, plus the pluggable identity-strategy protocol. |
|
|
532
532
|
| Caching | `node_modules/@voltro/cli/templates/agent-docs/caching.md` | Voltro's caching layer (@voltro/cache) — an always-on memory default, swappable Redis-compatible backends, a low-level wrap primitive, and automatic query-result invalidation. |
|
|
@@ -9,7 +9,7 @@ each plugin's own README.
|
|
|
9
9
|
|
|
10
10
|
| Topic | Open | Summary |
|
|
11
11
|
|---|---|---|
|
|
12
|
-
| **What's new in 0.
|
|
12
|
+
| **What's new in 0.14.0** | `node_modules/@voltro/cli/templates/agent-docs/whats-new.md` | Everything that changed in this version. Read it before hand-rolling something the framework may now ship. |
|
|
13
13
|
| AI | `node_modules/@voltro/cli/templates/agent-docs/ai.md` | How Voltro treats AI — agents, tools, streaming, RAG — all primitives over the same WebSocket as the rest of the framework. |
|
|
14
14
|
| Authentication | `node_modules/@voltro/cli/templates/agent-docs/authentication.md` | How @voltro/plugin-auth wires password + session-cookie auth across api + web, plus the pluggable identity-strategy protocol. |
|
|
15
15
|
| Caching | `node_modules/@voltro/cli/templates/agent-docs/caching.md` | Voltro's caching layer (@voltro/cache) — an always-on memory default, swappable Redis-compatible backends, a low-level wrap primitive, and automatic query-result invalidation. |
|
|
@@ -525,6 +525,7 @@ interface AuthStrategy {
|
|
|
525
525
|
interface AuthStrategyInput {
|
|
526
526
|
readonly headers: Readonly<Record<string, string | undefined>>
|
|
527
527
|
readonly clientId: number // per-connection id (for soft re-auth)
|
|
528
|
+
readonly store?: DataStore // the app's store, for a DB-backed strategy
|
|
528
529
|
}
|
|
529
530
|
```
|
|
530
531
|
|
|
@@ -540,6 +541,34 @@ The `failed`-stops-the-chain rule is a **security** decision, not an ergonomic o
|
|
|
540
541
|
|
|
541
542
|
> Strategies must be **fast on the no-match path** — a cookie-name substring check, no IO — because every strategy runs on every request until one matches. Do JWKS fetches / DB lookups only *after* you've confirmed the request is yours, and cache them.
|
|
542
543
|
|
|
544
|
+
### Reading your database — `input.store`
|
|
545
|
+
|
|
546
|
+
A strategy that identifies the caller from a row — a session, an API key, a PAT
|
|
547
|
+
— gets the app's `DataStore` on its input:
|
|
548
|
+
|
|
549
|
+
```ts
|
|
550
|
+
const dbSession: AuthStrategy = {
|
|
551
|
+
id: 'db-session',
|
|
552
|
+
resolve: async ({ headers, store }) => {
|
|
553
|
+
const token = headers.authorization?.slice('Bearer '.length)
|
|
554
|
+
if (token === undefined) return { kind: 'skip' }
|
|
555
|
+
if (store === undefined) return { kind: 'skip' }
|
|
556
|
+
const [row] = await store.query(sessions.byToken(token))
|
|
557
|
+
return row ? { kind: 'matched', subject: toSubject(row) } : { kind: 'failed', reason: 'unknown token' }
|
|
558
|
+
},
|
|
559
|
+
}
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
It is the **boot** store, not a request-scoped one — strategies resolve before a
|
|
563
|
+
request store exists — and the same value `auth.resolveScopes` receives.
|
|
564
|
+
`undefined` only while the store is still being built (`voltro dev` builds it
|
|
565
|
+
after the auth chain) and on an app with no store, so a strategy should `skip`
|
|
566
|
+
rather than throw.
|
|
567
|
+
|
|
568
|
+
Read users, sessions, keys. A strategy that runs domain writes while deciding
|
|
569
|
+
who the caller is has the two jobs the wrong way round; nothing in the type
|
|
570
|
+
stops you, and it is still wrong.
|
|
571
|
+
|
|
543
572
|
## Composing the chain
|
|
544
573
|
|
|
545
574
|
`composeAuthStrategies` turns an ordered list of strategies into a single resolver. First `matched` wins; first `failed` short-circuits to anonymous.
|
|
@@ -718,6 +718,45 @@ The restart is a full re-exec — there is no in-process hot-reload of a
|
|
|
718
718
|
handler body; editing a query's executor respawns the child (debounced
|
|
719
719
|
80ms, so a burst of saves collapses into one restart).
|
|
720
720
|
|
|
721
|
+
## When the dev server stops
|
|
722
|
+
|
|
723
|
+
A restart replaces the child; the supervisor keeps watching. When the dev
|
|
724
|
+
server exits **on its own** — an aborted boot, or you stopping it — what
|
|
725
|
+
happens next depends on whether anyone is there to react.
|
|
726
|
+
|
|
727
|
+
**In a terminal**, a crashed boot is something you are about to fix, so
|
|
728
|
+
the supervisor keeps watching and tells you:
|
|
729
|
+
|
|
730
|
+
```text
|
|
731
|
+
dev server crashed — waiting for a file change exitCode=1
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
Fix the cause and save. The watcher restarts the server exactly as it
|
|
735
|
+
would for any other edit; you don't retype the command.
|
|
736
|
+
|
|
737
|
+
**Piped, backgrounded or in CI** — anywhere stdout is not a TTY — nobody
|
|
738
|
+
is going to fix anything, so `voltro dev` exits with the child's code:
|
|
739
|
+
|
|
740
|
+
```text
|
|
741
|
+
dev server exited — supervisor stopping exitCode=1
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
That half matters because the supervisor used to keep watching in *both*
|
|
745
|
+
cases: a shell that had long since closed still had a `voltro dev` behind
|
|
746
|
+
it holding a watcher, and a CI job that had "finished" kept its runner
|
|
747
|
+
busy. A failed boot is now a failed command wherever no one is looking.
|
|
748
|
+
|
|
749
|
+
A **clean** exit always stops the supervisor, watched or not — a dev
|
|
750
|
+
server ending on purpose is not something to wait out.
|
|
751
|
+
|
|
752
|
+
| Env | Effect |
|
|
753
|
+
|---|---|
|
|
754
|
+
| `VOLTRO_DEV_KEEP_ALIVE=1` | Wait for a fix even without a TTY — a CI runner with a TTY allocated, or a wrapper that pipes output while you watch it. |
|
|
755
|
+
| `VOLTRO_DEV_KEEP_ALIVE=0` | Exit on a crash even in a terminal. |
|
|
756
|
+
|
|
757
|
+
Neither can keep a clean exit alive; that would turn a deliberate
|
|
758
|
+
shutdown into a hang.
|
|
759
|
+
|
|
721
760
|
The `.env` trigger applies to **both api and web** apps — `process.env` is
|
|
722
761
|
parsed once at boot, so editing a `.env` (or re-pulling secrets, e.g.
|
|
723
762
|
`doppler secrets download > .env`) needs a full re-exec. `voltro dev` watches
|
|
@@ -2255,6 +2294,7 @@ voltro update # bump to the latest published version, install, r
|
|
|
2255
2294
|
voltro update --to 0.4.0 # pin an explicit target version
|
|
2256
2295
|
voltro update --dry-run # preview the bump + which codemods would run — writes nothing
|
|
2257
2296
|
voltro update --force # allow a dirty working tree (not recommended)
|
|
2297
|
+
voltro update --only 0.14.0/03_pages-suffix # run just these codemod(s), comma-separated
|
|
2258
2298
|
voltro update --exact # pin exact versions (drop the ^ / ~ range prefix)
|
|
2259
2299
|
voltro update --help # every flag — always answered, even on a dirty tree
|
|
2260
2300
|
|
|
@@ -2263,6 +2303,26 @@ voltro update --codemods-only --from 0.3.0 # re-run codemods 0.3.0
|
|
|
2263
2303
|
voltro update --codemods-only --from 0.3.0 --to 0.4.0 # explicit delta
|
|
2264
2304
|
```
|
|
2265
2305
|
|
|
2306
|
+
### Taking only part of the jump — `--only`
|
|
2307
|
+
|
|
2308
|
+
Ids are what `--dry-run` prints:
|
|
2309
|
+
|
|
2310
|
+
```bash
|
|
2311
|
+
voltro update --dry-run
|
|
2312
|
+
voltro update --codemods-only --from 0.13.0 --only 0.14.0/03_pages-suffix,0.14.0/02_reactive-by-default
|
|
2313
|
+
```
|
|
2314
|
+
|
|
2315
|
+
Useful when part of a jump is load-bearing (without it the app does not build or
|
|
2316
|
+
its routes 404) and part is elective: take the necessary ones, get back to a
|
|
2317
|
+
committable tree, then run the rest. An id that matches nothing in the jump is an
|
|
2318
|
+
error listing the ids that do — "it did nothing" and "you typed it wrong" would
|
|
2319
|
+
otherwise look identical.
|
|
2320
|
+
|
|
2321
|
+
There is no `--required` flag, deliberately. "Required" would have to mean *this
|
|
2322
|
+
app does not run without it*, and that is a property of your app rather than of
|
|
2323
|
+
the codemod: the pages rename is unavoidable for a project with pages and
|
|
2324
|
+
irrelevant to an api-only one. You know which ones you need; we would be guessing.
|
|
2325
|
+
|
|
2266
2326
|
## In a workspace, the whole workspace moves
|
|
2267
2327
|
|
|
2268
2328
|
Run `voltro update` anywhere inside a workspace — a `pnpm-workspace.yaml`, or a
|
|
@@ -2333,6 +2393,26 @@ voltro update --codemods-only --from 0.5.0 --to 0.6.0
|
|
|
2333
2393
|
|
|
2334
2394
|
Every `@voltro/*` entry in `dependencies` and `devDependencies` — in every workspace member, see above — with the range style preserved (`^0.3.0` stays caret, `~0.3.0` stays tilde) unless you pass `--exact`. Non-registry specs (`workspace:*`, `catalog:`, `link:`, …) are left untouched — they're already resolved by your monorepo or catalog.
|
|
2335
2395
|
|
|
2396
|
+
## When the install cannot run on this host
|
|
2397
|
+
|
|
2398
|
+
Some projects install in a container with their own store, from an offline
|
|
2399
|
+
mirror, or in a locked-down CI image. `voltro update` runs your package manager
|
|
2400
|
+
on the machine you invoke it from, so on those hosts the install step fails —
|
|
2401
|
+
and it fails *after* the version bump is written, which leaves the tree
|
|
2402
|
+
half-upgraded.
|
|
2403
|
+
|
|
2404
|
+
`--no-install` splits the command where those projects need it split:
|
|
2405
|
+
|
|
2406
|
+
```bash
|
|
2407
|
+
voltro update --no-install --to 0.14.0 # writes the bump, stops, says what is left
|
|
2408
|
+
# ...install however this project installs...
|
|
2409
|
+
voltro update --codemods-only --from 0.13.0 --to 0.14.0
|
|
2410
|
+
```
|
|
2411
|
+
|
|
2412
|
+
Step two is not optional and the command says so: the codemods for a jump ship
|
|
2413
|
+
**inside** the target version, so nothing can run them until the install has put
|
|
2414
|
+
that version on disk.
|
|
2415
|
+
|
|
2336
2416
|
## Which package manager
|
|
2337
2417
|
|
|
2338
2418
|
`voltro update` never assumes npm. It resolves your project's package manager in this order, starting in the app directory and walking **up to the repo root**:
|
|
@@ -911,10 +911,10 @@ Throw a matching error from the server file; the client can narrow on `_tag`.
|
|
|
911
911
|
|
|
912
912
|
Tagged errors **round-trip structurally** over the wire — the caught value carries `_tag` plus every declared field as real properties (and `instanceof` works, same Schema class both ends). You do **not** need to parse the error message string.
|
|
913
913
|
|
|
914
|
-
Inside Effect, use `Effect.catchTag('NoteQuotaExceeded', …)`. In a React `try/catch` (outside Effect, where `catchTag` isn't available and the decoded value may be a plain object, not a class instance), match with **`errorTag(err)`** — the dependency-free tag reader `@voltro/
|
|
914
|
+
Inside Effect, use `Effect.catchTag('NoteQuotaExceeded', …)`. In a React `try/catch` (outside Effect, where `catchTag` isn't available and the decoded value may be a plain object, not a class instance), match with **`errorTag(err)`** — the dependency-free tag reader `@voltro/protocol` ships (it reads what `toRpc` writes):
|
|
915
915
|
|
|
916
916
|
```ts
|
|
917
|
-
import { errorTag } from '@voltro/
|
|
917
|
+
import { errorTag } from '@voltro/protocol'
|
|
918
918
|
|
|
919
919
|
try {
|
|
920
920
|
await createNote(input)
|
|
@@ -435,6 +435,27 @@ VOLTRO_DESTRUCTIVE_OK=1 voltro db apply --note 'retiring users table after migra
|
|
|
435
435
|
|
|
436
436
|
For complex multi-table retirements (move data out, then drop), use a [file-based migration](./file-based.md) — explicit ordering + a transaction wrapped around the data move.
|
|
437
437
|
|
|
438
|
+
### Name the tables, not the whole run
|
|
439
|
+
|
|
440
|
+
`VOLTRO_DESTRUCTIVE_OK=1` acknowledges **every** lossy op in the plan. That is
|
|
441
|
+
rarely what you mean — a plan with one intended drop and three other lossy ops
|
|
442
|
+
would have all four approved by a single `1`. Give it a comma-separated list
|
|
443
|
+
instead:
|
|
444
|
+
|
|
445
|
+
```sh
|
|
446
|
+
# Only these tables — every other lossy op in the plan stays refused.
|
|
447
|
+
VOLTRO_DESTRUCTIVE_OK=users,legacy_notes voltro db apply --note 'retiring the pre-migration tables'
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
An op the list does not name stays blocked, and a plan with anything still
|
|
451
|
+
blocked is refused as a whole. Half a plan applied is how a schema ends up in a
|
|
452
|
+
state neither the declaration nor the database describes.
|
|
453
|
+
|
|
454
|
+
There is deliberately **no `.dropped()` marker for a table**, unlike for a
|
|
455
|
+
column. A dropped column leaves a slot worth documenting in the declaration; a
|
|
456
|
+
dropped table leaves nothing, so the marker would be a dead entry you have to
|
|
457
|
+
remember to delete.
|
|
458
|
+
|
|
438
459
|
## `.narrowedFrom()` for type changes
|
|
439
460
|
|
|
440
461
|
A bare column type change is **refuse-to-plan** — the planner blocks it
|
|
@@ -1017,7 +1017,8 @@ be on. Rather than repeat that check in every `useMutation` call site, each api'
|
|
|
1017
1017
|
runtime carries an error bus; this hook subscribes to it with React lifecycle.
|
|
1018
1018
|
|
|
1019
1019
|
```tsx
|
|
1020
|
-
import { useOnRpcError
|
|
1020
|
+
import { useOnRpcError } from '@voltro/client'
|
|
1021
|
+
import { errorTag } from '@voltro/protocol'
|
|
1021
1022
|
|
|
1022
1023
|
useOnRpcError('app', useCallback((e) => {
|
|
1023
1024
|
if (errorTag(e.error) === 'Unauthenticated') redirectToSignIn()
|