@voltro/cli 0.35.0 → 0.36.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.
Files changed (87) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/dist/{apiBuild-DYD_ONLD.js → apiBuild-DiE9zcj6.js} +1 -1
  3. package/dist/apiBuild-ZEZnCXn2.js +2 -0
  4. package/dist/bin.js +1 -1
  5. package/dist/{build-CD8K4XOr.js → build-DBe6c7qC.js} +6 -6
  6. package/dist/{checkCommand-DKpDLlqu.js → checkCommand-BTA6P3Yr.js} +1 -1
  7. package/dist/{checkCommand-Ct9xkTrS.js → checkCommand-BhG0gmUD.js} +2 -2
  8. package/dist/{codegenCommand-C4YoQIc2.js → codegenCommand-DH-8ZXzR.js} +1 -1
  9. package/dist/{codemodRunner-BnFq3Fgu.js → codemodRunner-DjQGrdmg.js} +64 -47
  10. package/dist/{commands-BE8E7zF3.js → commands-Bp7utV-7.js} +18 -18
  11. package/dist/{dashboardCommand-D7SgZGaN.js → dashboardCommand-D5Jwjmr1.js} +1 -1
  12. package/dist/{dataCommand-BhYwDgg-.js → dataCommand-DnCm0B2C.js} +1 -1
  13. package/dist/{dev-D2BikO7a.js → dev-BSFTgCQ5.js} +1 -1
  14. package/dist/{dev-C7sFZq3m.js → dev-Dc4cpmRl.js} +2000 -2000
  15. package/dist/doctorCommand-BYffQc0s.js +2 -0
  16. package/dist/{doctorCommand-DnimF5IM.js → doctorCommand-CNFtt3nR.js} +9 -9
  17. package/dist/{dormancyCommand-QewYug_s.js → dormancyCommand-6F6NsJKf.js} +1 -1
  18. package/dist/{embeddingsCommand-BfiLS_QI.js → embeddingsCommand-DRRdneJD.js} +1 -1
  19. package/dist/{envCommand-CCGPRQY1.js → envCommand-TZzcyqZ-.js} +1 -1
  20. package/dist/{evolveCommand-CHsLCtDf.js → evolveCommand-iU35TPjT.js} +2 -2
  21. package/dist/index.js +1 -1
  22. package/dist/{infoCommand-DwOgK1t6.js → infoCommand-unqisJGp.js} +1 -1
  23. package/dist/{runtimeTrace-CH3eUiMw.js → runtimeTrace-D5LJ_N55.js} +1 -1
  24. package/dist/{sdkgen-BLkvGRfX.js → sdkgen-82xVuvbt.js} +1 -1
  25. package/dist/serveCommand-CEBVP36A.js +2 -0
  26. package/dist/{serveCommand-iwlUBNS1.js → serveCommand-VVGcIMIw.js} +487 -487
  27. package/dist/serveEntry.js +1 -1
  28. package/dist/updateCommand-CSBXVsYq.js +2 -0
  29. package/dist/{updateCommand-x0pI_x-B.js → updateCommand-CwnUK_mf.js} +1 -1
  30. package/dist/{webhooksCommand-DlAgS2Iw.js → webhooksCommand-di1CJVzu.js} +1 -1
  31. package/package.json +23 -17
  32. package/templates/AGENTS.md +1 -1
  33. package/templates/agent-docs/_index.md +1 -1
  34. package/templates/agent-docs/cli.md +22 -0
  35. package/templates/agent-docs/database/misc.md +33 -0
  36. package/templates/agent-docs/whats-new.md +31 -130
  37. package/templates/apps/api-ai/package.json +7 -7
  38. package/templates/apps/api-auth/package.json +8 -8
  39. package/templates/apps/api-backend/package.json +7 -7
  40. package/templates/apps/api-backend-deactivation/package.json +7 -7
  41. package/templates/apps/api-backend-mail/package.json +8 -8
  42. package/templates/apps/api-backend-mariadb/package.json +9 -9
  43. package/templates/apps/api-backend-sqlite/package.json +8 -8
  44. package/templates/apps/api-backend-storage/package.json +8 -8
  45. package/templates/apps/api-cms/package.json +10 -10
  46. package/templates/apps/api-collab/package.json +8 -8
  47. package/templates/apps/api-data-advanced/package.json +8 -8
  48. package/templates/apps/api-durable/package.json +8 -8
  49. package/templates/apps/api-feature-flags/package.json +9 -9
  50. package/templates/apps/api-governance/package.json +8 -8
  51. package/templates/apps/api-kv/package.json +8 -8
  52. package/templates/apps/api-moderation/package.json +8 -8
  53. package/templates/apps/api-observability/package.json +8 -8
  54. package/templates/apps/api-ratelimit/package.json +8 -8
  55. package/templates/apps/api-rbac/package.json +8 -8
  56. package/templates/apps/api-rest/package.json +7 -7
  57. package/templates/apps/api-saas/package.json +11 -11
  58. package/templates/apps/api-saas-starter/package.json +10 -10
  59. package/templates/apps/api-search/package.json +8 -8
  60. package/templates/apps/api-status/package.json +8 -8
  61. package/templates/apps/api-versioning/package.json +8 -8
  62. package/templates/apps/api-webhooks/package.json +9 -9
  63. package/templates/apps/changelog/package.json +6 -6
  64. package/templates/apps/edge-functions/package.json +2 -2
  65. package/templates/apps/frontend-admin/package.json +8 -8
  66. package/templates/apps/frontend-app/package.json +9 -9
  67. package/templates/apps/frontend-auth/package.json +8 -8
  68. package/templates/apps/frontend-blank/package.json +7 -7
  69. package/templates/apps/frontend-cms/package.json +9 -9
  70. package/templates/apps/frontend-collab/package.json +10 -10
  71. package/templates/apps/frontend-contact/package.json +7 -7
  72. package/templates/apps/frontend-dashboard/package.json +7 -7
  73. package/templates/apps/frontend-docs/package.json +7 -7
  74. package/templates/apps/frontend-i18n/package.json +6 -6
  75. package/templates/apps/frontend-landing/package.json +7 -7
  76. package/templates/apps/frontend-portal/package.json +8 -8
  77. package/templates/apps/frontend-saas/package.json +8 -8
  78. package/templates/apps/frontend-spa/package.json +7 -7
  79. package/templates/apps/frontend-ssr/package.json +7 -7
  80. package/templates/apps/frontend-ssr-api/package.json +8 -8
  81. package/templates/apps/frontend-static-blog/package.json +6 -6
  82. package/templates/apps/frontend-status/package.json +8 -8
  83. package/templates/apps/mobile-app/package.json +3 -3
  84. package/dist/apiBuild-B8aoJvuw.js +0 -2
  85. package/dist/doctorCommand-CM4Ch9C7.js +0 -2
  86. package/dist/serveCommand-CbDHU6l-.js +0 -2
  87. package/dist/updateCommand-BlMZhWgO.js +0 -2
package/CHANGELOG.md CHANGED
@@ -39,6 +39,74 @@ _Changes staged for the next release accumulate here (rolled up from
39
39
 
40
40
  ---
41
41
 
42
+ ## [0.36.0] — 2026-08-13
43
+
44
+ ### ⚠ BREAKING
45
+
46
+ - **@voltro/integration-http, @voltro/plugin-atlassian** — A 401 from an upstream now produces `code: 'unauthorized'`, not `code: 'session_expired'`. The connection vault's own failure — where we DO know the credential is unusable — becomes `code: 'credential_unusable'`.
47
+
48
+ `session_expired` asserted a cause the status cannot support. A 401 says the credential was not accepted and says nothing about why: expired, revoked, insufficient scope and MALFORMED all produce it. A consumer's plugin sent ciphertext as a bearer token (a separate defect, fixed in the same release), the upstream answered 401, this name called it an expired session, and their health check acted on the name and deleted a valid session. Login loop, with every symptom pointing at a revoked credential.
49
+
50
+ Names get acted on, which is the whole reason to split them:
51
+
52
+ - `'unauthorized'` — the upstream refused. Non-transient, so still never retried; `status` rides along so a caller that knows more about its own upstream can decide for itself. Deciding for them is what this gives up. - `'credential_unusable'` — the connection vault could not produce a credential (no grant, revoked grant, refresh failed). Here the claim is ours to make, because the failure is ours rather than the far end's.
53
+
54
+ The 401 message stopped saying "session expired" too. It now says the credential was refused and that the reason is not in the response — which is the honest sentence and the one that would have saved the day this cost.
55
+
56
+ Its test asserts the CLAIM rather than banning the word: the first version forbade `/expired/i` and went red against the corrected message, which lists expiry as one of several things a 401 can mean. That distinction is the point of the change, so the assertion had to be about `session expired` specifically.
57
+
58
+ **`voltro update` carries you across this** — codemod `0.35.1/01_unauthorized-replaces-session-expired`.
59
+
60
+ ### Added
61
+
62
+ - **@voltro/web** — **`apiSurface: compatible` — why the three altered golden lines cannot break a caller.** `LoaderContext` and `LoaderFn` each gained a type parameter WITH a default, so an unparameterised reference still resolves. The one that needed proving is `query?`, which went from a written-out signature to `LoaderQuery<Procedures>` — and `LoaderQuery` is a conditional whose false branch is character-for-character the previous signature. `unknown` does not extend `ProcedureTypeMap`, so the defaulted instantiation takes that branch.
63
+
64
+ Proved with `tsc` rather than by reading it: a probe asserting mutual assignability between `LoaderQuery<unknown>` and the old signature compiles, and inverting the probe fails — with tsc printing the resolved type as `<T = unknown>(tag: string, input?: Record<string, unknown> | undefined) => Promise<T>`, which is the old signature verbatim.
65
+
66
+ `LoaderContext` takes the app's procedure map, so a loader's `query` infers its input and output from the descriptor instead of returning `unknown`.
67
+
68
+ ```ts
69
+ import type { AppProcedures } from '<your-api>/rpcGroup'
70
+
71
+ export const loader = async ({ query }: LoaderContext<AppProcedures>) => {
72
+ const rows = await query?.('bookmarks.list', { limit: 100 })
73
+ // ^ inferred; an unknown tag or a wrong input shape is a compile error
74
+ }
75
+ ```
76
+
77
+ `AppProcedures` is generated already and has been for a while — it was wired to `createHooks` on the CLIENT and to nothing on the server, so every loader call site spelled its own output type by hand and a typo in a tag compiled. A consumer reported it twice.
78
+
79
+ The extraction reuses `ProcedureInput` / `ProcedureOutput` from `@voltro/client` rather than re-deriving them: a second answer to "what does this tag return" drifts the first time a descriptor field is renamed, and both answers look right in isolation.
80
+
81
+ Opt-in, and non-breaking: with no map named, the signature is the previous `<T = unknown>(tag: string, …)`. The framework cannot import an app's generated file, which is the same reason `createHooks<AppProcedures>` takes it explicitly.
82
+
83
+ Covered by a `.test-d.ts`, because the failure mode is "it compiles when it should not" and no runtime assertion can observe that. Two of its cases exist because the first version was vacuous: an `interface` fixture does not satisfy the map constraint (no implicit index signature — the codegen emits an alias for exactly this reason), so the typed branch fell back silently and every `@ts-expect-error` came back unused.
84
+
85
+ ### Fixed
86
+
87
+ - **@voltro/cli** — The store a plugin receives through `bindDataStore` now carries the storage codec, so an `.encrypted()` column read through it decrypts.
88
+
89
+ A consumer measured both stores inside one request: `ctx.store` gave a 44-character plaintext PAT, and the store their plugin's `credentialsResolver` received gave 113 characters of `enc:v1:…`. Ciphertext is a syntactically valid bearer token, so nothing threw. Jira answered 401, `@voltro/integration-http` named that `session_expired`, their PAT health check did the reasonable thing with that name and deleted the session, and the user got login → dashboard → login forever. A configuration error in the costume of an authentication refusal, where every symptom pointed at the one explanation that was wrong.
90
+
91
+ The part worth recording is that `bootStoreCodec.ts` was written for exactly this, after it happened at two other seams, and its header predicts this consumer's symptom verbatim: "a route reading an `.encrypted()` column got the literal string `enc:v1:…` back … the failure reads as 'wrong credential'". The fix was applied per-seam. `bindDataStore` was not one of the seams anybody listed, so it happened a third time — and a per-seam test stayed green throughout, because it covered the two seams somebody remembered.
92
+
93
+ `bootStoreHandouts.test.ts` asserts the rule instead: no boot path hands a plugin the raw driver, on either boot path, with the wrapper applied before the handout. The codec needs no Subject — it is how a column is spelled on disk versus in JS — so there was never anything a boot-level store could not carry.
94
+
95
+ Also relevant to anyone who followed the 0.28.0 codemod: that codemod told apps to stop carrying a credential on the Subject and look it up in the resolver instead. Doing exactly that is what put an app on this seam, so the instruction and `.encrypted()` were not simultaneously satisfiable through it.
96
+ - **@voltro/runtime, @voltro/cli** — The rpc/WebSocket query and stream arms now resolve row visibility before the executor sees a context. Fixes a 0.35.0 regression that made every read throw for an app with a registered row filter, and the older leak underneath it.
97
+
98
+ 0.35.0 shipped two things for the row filter: the registration moved to `globalThis` (so a duplicate `@voltro/runtime` instance cannot hide it), and a scoped store built without a resolved scope started throwing instead of silently serving unfiltered rows. The first was a real fix for a real hazard. The second was correct in principle and immediately fatal in practice, because the framework itself had a path that did exactly what it now refuses.
99
+
100
+ The consumer who reported the original leak ran the two-line check we asked for and `getRowFilter()` was visible from their request path — so the instance split was NOT their cause, and our hypothesis was wrong. Their measurement is what found the real one: the refusal fired, meaning the registration was FOUND and `ctx.rowFilter` was still undefined at the store. Nothing was missing; a step was.
101
+
102
+ Four arms reach a request context. `makeOneShotQueryRunner` (REST) and `makeQuerySubscriber` (SSE) both `await withRowFilter(...)` and say so in a comment. The rpc query handler and the stream handler — each hand-copied into both boot paths — handed the raw request straight through. So a user's executor received a context whose `ctx.store` applied no row filter, on the two arms that carry the most traffic. It survived because subscriptions are refiltered per DELIVERY, which made a descriptor-returning query look correct end to end while the executor's own reads were not.
103
+
104
+ `withScopedRequest` is the seam that fixes it once: a request that already carries a scope passes through untouched (resolving twice would run the app's `load` twice per request), an app with NO filter stays fully synchronous, and an app with one gets an Effect — which every one of these call sites already accepts. A boot-path parity test pins both stream arms and the shared producer.
105
+
106
+ The refusal also stopped firing for a SYSTEM subject. That is not a softening: `resolveRowFilterScopeFor` returns `NO_ROW_FILTER` for a system subject, so the only correct value was already determined, and several legitimate paths (schedules, resumed workflows, the webhook trigger context) build a context directly with no scope. Demanding a decision there is what took the api down.
107
+
108
+ ---
109
+
42
110
  ## [0.35.0] — 2026-08-13
43
111
 
44
112
  ### ⚠ BREAKING
@@ -1,4 +1,4 @@
1
- import { f as e } from "./dev-C7sFZq3m.js";
1
+ import { f as e } from "./dev-Dc4cpmRl.js";
2
2
  import { ut as t } from "./webDev-Dybxew86.js";
3
3
  import { t as n } from "./dialectDriver-CgXnDfec.js";
4
4
  import { dirname as r, isAbsolute as i, join as a, relative as o, resolve as s } from "node:path";
@@ -0,0 +1,2 @@
1
+ import { c as e, l as t } from "./apiBuild-DiE9zcj6.js";
2
+ export { e as runApiBuild, t as runServeBundleBuild };
package/dist/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { r as e } from "./commands-BE8E7zF3.js";
2
+ import { r as e } from "./commands-Bp7utV-7.js";
3
3
  import { a as t } from "./nodeEnvironment-cGFAj1J8.js";
4
4
  import { t as n } from "./loadEnv-D9nEOClM.js";
5
5
  import { n as r } from "./cliError-BmdYnghb.js";
@@ -1,8 +1,8 @@
1
- import { pn as e } from "./dev-C7sFZq3m.js";
1
+ import { pn as e } from "./dev-Dc4cpmRl.js";
2
2
  import { D as t, G as n, K as r, O as i, S as a, W as o, Y as s, a as c, b as l, d as u, f as d, k as f, s as p, st as m, ut as h, v as g, x as _, y as v } from "./webDev-Dybxew86.js";
3
3
  import { t as y } from "./cliRuntime-Dh7UDinH.js";
4
4
  import { a as b } from "./renderModeScan-D7J1B7Kw.js";
5
- import { i as x, o as S, s as C } from "./apiBuild-DYD_ONLD.js";
5
+ import { i as x, o as S, s as C } from "./apiBuild-DiE9zcj6.js";
6
6
  import { n as w } from "./renderProfile-1OWWAAtx.js";
7
7
  import { dirname as T, join as E, resolve as D } from "node:path";
8
8
  import { existsSync as O, promises as k } from "node:fs";
@@ -467,7 +467,7 @@ var N = A({ scope: "voltro:build" }), P = async (e) => {
467
467
  file: n.file,
468
468
  reason: n.reason
469
469
  });
470
- let { regenerateRpcGroup: r } = await import("./codegenCommand-C4YoQIc2.js"), i = await r(e);
470
+ let { regenerateRpcGroup: r } = await import("./codegenCommand-DH-8ZXzR.js"), i = await r(e);
471
471
  if (i.kind === "refused") {
472
472
  F.warn("could not regenerate the rpc group — building against what is on disk", { reason: i.reason });
473
473
  return;
@@ -479,10 +479,10 @@ var N = A({ scope: "voltro:build" }), P = async (e) => {
479
479
  }, K = async (e) => {
480
480
  let t = await u(e);
481
481
  if (!t) {
482
- let { loadApiConfig: t } = await import("./dev-D2BikO7a.js"), n = await t(e);
482
+ let { loadApiConfig: t } = await import("./dev-BSFTgCQ5.js"), n = await t(e);
483
483
  if (n) {
484
484
  F.info("building api app", { app: n.name ?? "(unnamed)" }), await G(e);
485
- let { runApiBuild: t, runServeBundleBuild: r } = await import("./apiBuild-B8aoJvuw.js");
485
+ let { runApiBuild: t, runServeBundleBuild: r } = await import("./apiBuild-ZEZnCXn2.js");
486
486
  await t(e);
487
487
  try {
488
488
  await r(e);
@@ -701,7 +701,7 @@ var N = A({ scope: "voltro:build" }), P = async (e) => {
701
701
  return t.ran ? t.exitCode : (yield* j.logError("no web app found at this path", { hint: "looked for app.config.ts with `type: 'web'`" }), 1);
702
702
  }), J = async (t) => {
703
703
  if (t.includes("--target")) {
704
- let { runSdkBuildCommand: e } = await import("./sdkgen-BLkvGRfX.js");
704
+ let { runSdkBuildCommand: e } = await import("./sdkgen-82xVuvbt.js");
705
705
  return e(t);
706
706
  }
707
707
  let n = t.find((e) => !e.startsWith("-")) ?? process.cwd(), r = await y(q(n), { scope: "voltro:build" }), i = e(n);
@@ -1,2 +1,2 @@
1
- import { n as e, r as t, t as n } from "./checkCommand-Ct9xkTrS.js";
1
+ import { n as e, r as t, t as n } from "./checkCommand-BhG0gmUD.js";
2
2
  export { n as offlineManifest, e as runCheckCommand, t as toInput };
@@ -4,7 +4,7 @@ import { r } from "./appGraph-KGDPTuTy.js";
4
4
  import { n as i } from "./cliOutput-D1tSBoRM.js";
5
5
  import { n as a, o, r as s, t as c } from "./inspectFetch-EMuhTG_9.js";
6
6
  import { r as l } from "./fileTaxonomy-CJfgOllU.js";
7
- import { x as u } from "./doctorCommand-DnimF5IM.js";
7
+ import { x as u } from "./doctorCommand-CNFtt3nR.js";
8
8
  import { resolve as d } from "node:path";
9
9
  import { readdirSync as f, statSync as p } from "node:fs";
10
10
  //#region src/observedDiff.ts
@@ -141,7 +141,7 @@ var m = (e) => e === void 0 ? [] : typeof e == "string" ? [e] : e, h = /* @__PUR
141
141
  let t = e.severity === "error" ? "✗ error" : "⚠ warn", n = e.file ? ` (${e.file})` : "";
142
142
  return `${t} ${e.rule} ${e.node}${n}\n ${e.breaks.join("; ")}\n fix: ${e.fix}`;
143
143
  }).join("\n"), C = async (e) => {
144
- let { walk: t, loadDiscovered: n, loadApiConfig: r } = await import("./dev-D2BikO7a.js"), { buildRpcEntry: i } = await import("./manifestBuild-COkJoyAr.js"), { buildCapabilityManifest: a } = await import("./inspect-P4pxoMaV.js"), { relative: o } = await import("node:path"), s = await n(await t(e)), c = (t, n, r) => i(t, n, o(e, r)), l = [
144
+ let { walk: t, loadDiscovered: n, loadApiConfig: r } = await import("./dev-BSFTgCQ5.js"), { buildRpcEntry: i } = await import("./manifestBuild-COkJoyAr.js"), { buildCapabilityManifest: a } = await import("./inspect-P4pxoMaV.js"), { relative: o } = await import("node:path"), s = await n(await t(e)), c = (t, n, r) => i(t, n, o(e, r)), l = [
145
145
  ...s.queries.map((e) => c(e.descriptor, "query", e.file)),
146
146
  ...s.mutations.map((e) => c(e.descriptor, "mutation", e.file)),
147
147
  ...s.actions.map((e) => c(e.descriptor, "action", e.file)),
@@ -1,4 +1,4 @@
1
- import { l as e, z as t } from "./dev-C7sFZq3m.js";
1
+ import { l as e, z as t } from "./dev-Dc4cpmRl.js";
2
2
  import { r as n } from "./codegen-CYM3Zqrf.js";
3
3
  import { basename as r, relative as i, resolve as a } from "node:path";
4
4
  //#region src/codegenCommand.ts
@@ -5066,7 +5066,21 @@ var x = (e, t, n) => {
5066
5066
  "",
5067
5067
  "The read is issued at most once per key per process, off the commit path."
5068
5068
  ].join("\n")
5069
- }), Gr = (e) => /RunStepStatus/.test(e) || /['"]succeeded['"]/.test(e) && /['"]waiting['"]/.test(e) && /RunStep|runStep|flow/i.test(e), q = [
5069
+ }), Gr = (e) => /RunStepStatus/.test(e) || /['"]succeeded['"]/.test(e) && /['"]waiting['"]/.test(e) && /RunStep|runStep|flow/i.test(e), Kr = C({
5070
+ version: "0.35.0",
5071
+ id: "0.35.0/04_flow-run-step-skipped",
5072
+ title: "A flow run step can now be 'skipped' — handle it where you render a run timeline",
5073
+ kind: "manual",
5074
+ appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Gr(e.getFullText())),
5075
+ note: (/* @__PURE__ */ "A FLOW RUN STEP CAN NOW BE 'skipped'.((`when:` on a flow step gates it on a prior value, and a step whose condition(is false is SKIPPED rather than run. That is a sixth member of(`RunStepStatus`, so an exhaustive switch over it no longer compiles, and a(lookup keyed by status now has a hole.((WHAT TO DO:((1) FIND IT. Anywhere you render or branch on a run step status — a timeline( component, a status badge map, a progress calculation.((2) DECIDE WHAT A SKIPPED STEP LOOKS LIKE. It is NOT a failure and NOT a( success: it did not run, on purpose, and it produced no output. The( step carries `skipReason` — the rendered condition, e.g.( `{{mode}} equals \"full\"` — so the timeline can say WHY.((3) DO NOT DEFAULT IT TO INVISIBLE. Dropping the row compiles and reads fine( in review, and it reproduces exactly the problem `skipReason` exists to( prevent: a step that vanished is indistinguishable from a step nobody( declared, which is the first thing a user reports as a bug.((A PROGRESS COUNT probably needs a second look too: `succeeded / total` now(under-reports a completed run that skipped a step. Counting(`succeeded + skipped` against the total is usually what was meant.((If your app does not render a flow timeline, there is nothing to do — this(note fires on any file that names the status type or its literals.".split("(")).join("\n")
5076
+ }), qr = C({
5077
+ version: "0.35.0",
5078
+ id: "0.35.0/05_declared-schema-drops-runtime-flags",
5079
+ title: "The declared schema no longer reads `CDC` / `VOLTRO_UNDO` / `VOLTRO_TRACING_PERSIST`",
5080
+ kind: "manual",
5081
+ appliesTo: () => !0,
5082
+ note: (/* @__PURE__ */ "The set of framework tables your app DECLARES is hashed into the schema(fingerprint. A pre-deploy `voltro db apply` records that hash; every serving(container recomputes it and refuses to boot if it differs. Until this release(three RUNTIME flags fed into that set:(( CDC=0 removed `_voltro_cdc_offsets`( VOLTRO_UNDO=on added `_voltro_undo_log`( VOLTRO_TRACING_PERSIST=all added `_voltro_traces`((All three read as pure runtime knobs, so they tend to live on the PODS and(not on the pre-upgrade migrate Job — which is a green migrate followed by(every pod in CrashLoopBackOff. This was reported against a Helm deployment(where `CDC: \"0\"` was in all three overlays' pod blocks and none of their(jobs; it had been latent for months and would have fired on the next deploy.((WHAT YOU MUST DO — only if you set one of these to turn a table ON in(production:(( * `VOLTRO_UNDO=on` in production → add to app.config.ts:( export default { schema: { undo: true }, … }( * `VOLTRO_TRACING_PERSIST` keeping trace history in production → add:( export default { schema: { traces: true }, … }(( Without the declaration, `voltro serve` now REFUSES to boot and names the( field. That refusal is the point: before, the same configuration either( wrote to a table nobody created or produced a fingerprint the migrate job( could not reproduce.(( Turning capture OFF still needs no declaration and never will — a declared( table nobody writes to is harmless. Only turning it ON is a schema claim.((WHAT HAPPENS WITHOUT ANY ACTION:(( * On mariadb or mssql you will see ONE additive `create-table` in your next( plan: `_voltro_cdc_offsets` is now declared by the DIALECT rather than by( `CDC`, so it exists whether or not that process drives CDC. It is an( offsets table — a handful of rows — and the alternative was leaving a( runtime flag able to split your fleet.( * On postgres/sqlite nothing changes: those dialects have no offsets table.((AND ONE THING WORTH DOING ANYWAY: if you are upgrading a deployment that has(a separate migrate job, diff that job's `env:` against your pods' once. The(framework can now guarantee its OWN tables do not depend on a runtime flag;(it cannot make the same guarantee for a plugin's `extendSchema.tables`, which(is app code and may read anything. A `prod-mismatch` refusal now prints which(tables this process decided and from which input, so the comparison is quick.".split("(")).join("\n")
5083
+ }), q = "session_expired", J = [
5070
5084
  ge,
5071
5085
  _e,
5072
5086
  ye,
@@ -5165,23 +5179,26 @@ var x = (e, t, n) => {
5165
5179
  Ir,
5166
5180
  Hr,
5167
5181
  Wr,
5182
+ Kr,
5183
+ qr,
5168
5184
  C({
5169
- version: "0.35.0",
5170
- id: "0.35.0/04_flow-run-step-skipped",
5171
- title: "A flow run step can now be 'skipped' handle it where you render a run timeline",
5172
- kind: "manual",
5173
- appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Gr(e.getFullText())),
5174
- note: (/* @__PURE__ */ "A FLOW RUN STEP CAN NOW BE 'skipped'.((`when:` on a flow step gates it on a prior value, and a step whose condition(is false is SKIPPED rather than run. That is a sixth member of(`RunStepStatus`, so an exhaustive switch over it no longer compiles, and a(lookup keyed by status now has a hole.((WHAT TO DO:((1) FIND IT. Anywhere you render or branch on a run step status — a timeline( component, a status badge map, a progress calculation.((2) DECIDE WHAT A SKIPPED STEP LOOKS LIKE. It is NOT a failure and NOT a( success: it did not run, on purpose, and it produced no output. The( step carries `skipReason` — the rendered condition, e.g.( `{{mode}} equals \"full\"` — so the timeline can say WHY.((3) DO NOT DEFAULT IT TO INVISIBLE. Dropping the row compiles and reads fine( in review, and it reproduces exactly the problem `skipReason` exists to( prevent: a step that vanished is indistinguishable from a step nobody( declared, which is the first thing a user reports as a bug.((A PROGRESS COUNT probably needs a second look too: `succeeded / total` now(under-reports a completed run that skipped a step. Counting(`succeeded + skipped` against the total is usually what was meant.((If your app does not render a flow timeline, there is nothing to do — this(note fires on any file that names the status type or its literals.".split("(")).join("\n")
5175
- }),
5176
- C({
5177
- version: "0.35.0",
5178
- id: "0.35.0/05_declared-schema-drops-runtime-flags",
5179
- title: "The declared schema no longer reads `CDC` / `VOLTRO_UNDO` / `VOLTRO_TRACING_PERSIST`",
5180
- kind: "manual",
5181
- appliesTo: () => !0,
5182
- note: (/* @__PURE__ */ "The set of framework tables your app DECLARES is hashed into the schema(fingerprint. A pre-deploy `voltro db apply` records that hash; every serving(container recomputes it and refuses to boot if it differs. Until this release(three RUNTIME flags fed into that set:(( CDC=0 removed `_voltro_cdc_offsets`( VOLTRO_UNDO=on added `_voltro_undo_log`( VOLTRO_TRACING_PERSIST=all added `_voltro_traces`((All three read as pure runtime knobs, so they tend to live on the PODS and(not on the pre-upgrade migrate Job which is a green migrate followed by(every pod in CrashLoopBackOff. This was reported against a Helm deployment(where `CDC: \"0\"` was in all three overlays' pod blocks and none of their(jobs; it had been latent for months and would have fired on the next deploy.((WHAT YOU MUST DO only if you set one of these to turn a table ON in(production:(( * `VOLTRO_UNDO=on` in production → add to app.config.ts:( export default { schema: { undo: true }, }( * `VOLTRO_TRACING_PERSIST` keeping trace history in production → add:( export default { schema: { traces: true }, … }(( Without the declaration, `voltro serve` now REFUSES to boot and names the( field. That refusal is the point: before, the same configuration either( wrote to a table nobody created or produced a fingerprint the migrate job( could not reproduce.(( Turning capture OFF still needs no declaration and never will — a declared( table nobody writes to is harmless. Only turning it ON is a schema claim.((WHAT HAPPENS WITHOUT ANY ACTION:(( * On mariadb or mssql you will see ONE additive `create-table` in your next( plan: `_voltro_cdc_offsets` is now declared by the DIALECT rather than by( `CDC`, so it exists whether or not that process drives CDC. It is an( offsets table — a handful of rows — and the alternative was leaving a( runtime flag able to split your fleet.( * On postgres/sqlite nothing changes: those dialects have no offsets table.((AND ONE THING WORTH DOING ANYWAY: if you are upgrading a deployment that has(a separate migrate job, diff that job's `env:` against your pods' once. The(framework can now guarantee its OWN tables do not depend on a runtime flag;(it cannot make the same guarantee for a plugin's `extendSchema.tables`, which(is app code and may read anything. A `prod-mismatch` refusal now prints which(tables this process decided and from which input, so the comparison is quick.".split("(")).join("\n")
5185
+ version: "0.35.1",
5186
+ id: "0.35.1/01_unauthorized-replaces-session-expired",
5187
+ title: "A 401 is `code: 'unauthorized'`; the vault's own failure is `'credential_unusable'`",
5188
+ kind: "transform",
5189
+ appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getFullText().includes(q)),
5190
+ transform: ({ project: e, log: t }) => {
5191
+ let n = [];
5192
+ for (let t of e.getSourceFiles()) {
5193
+ if (!t.getFullText().includes(q)) continue;
5194
+ let e = !1;
5195
+ for (let n of t.getDescendantsOfKind(11)) n.getLiteralValue() === q && (n.setLiteralValue("unauthorized"), e = !0);
5196
+ e && n.push(t.getFilePath());
5197
+ }
5198
+ n.length !== 0 && t(`rewrote '${q}' to 'unauthorized' in ${n.length} file(s).\n A 401 now means only "the credential was refused"expired, revoked, wrong\n scope and MALFORMED all produce that status, and the old name asserted the\n first one. If a rewritten branch was meant to catch a credential your\n CONNECTION VAULT could not produce (no grant, revoked grant, failed refresh),\n change it to 'credential_unusable' that is the code the vault raises, and it\n is the one where re-auth is genuinely the right action.\n A health check that logs the user out on this code should read 'unauthorized'\n as "ask again", not as "the session is gone".\n` + n.map((e) => ` ${e}`).join("\n"));
5199
+ }
5183
5200
  })
5184
- ], J = /* @__PURE__ */ new Set([
5201
+ ], Y = /* @__PURE__ */ new Set([
5185
5202
  "node_modules",
5186
5203
  ".git",
5187
5204
  "dist",
@@ -5193,12 +5210,12 @@ var x = (e, t, n) => {
5193
5210
  ".turbo",
5194
5211
  ".cache",
5195
5212
  ".output"
5196
- ]), Kr = () => [...[...J].map((e) => `**/${e}/**`), "**/.voltro-*/**"], Y = /(?:from|import)\s*\(?\s*['"]([^'"]+)['"]|require\s*\(\s*['"]([^'"]+)['"]\s*\)/g, X = /\.(?:tsx?|jsx?|mjs|cjs)$/, qr = (e) => m(e).replace(X, ""), Jr = (e) => {
5213
+ ]), Jr = () => [...[...Y].map((e) => `**/${e}/**`), "**/.voltro-*/**"], X = /(?:from|import)\s*\(?\s*['"]([^'"]+)['"]|require\s*\(\s*['"]([^'"]+)['"]\s*\)/g, Z = /\.(?:tsx?|jsx?|mjs|cjs)$/, Yr = (e) => m(e).replace(Z, ""), Xr = (e) => {
5197
5214
  let t = e.split("/").filter((e) => e.length > 0).pop();
5198
5215
  if (t === void 0 || t === "." || t === "..") return;
5199
- let n = t.replace(X, "");
5216
+ let n = t.replace(Z, "");
5200
5217
  return n.length > 0 ? n : void 0;
5201
- }, Yr = (e) => {
5218
+ }, Zr = (e) => {
5202
5219
  let t = /* @__PURE__ */ new Map();
5203
5220
  for (let n of e) {
5204
5221
  let e;
@@ -5207,57 +5224,57 @@ var x = (e, t, n) => {
5207
5224
  } catch {
5208
5225
  continue;
5209
5226
  }
5210
- Y.lastIndex = 0;
5211
- for (let r = Y.exec(e); r !== null; r = Y.exec(e)) {
5212
- let e = Jr(r[1] ?? r[2] ?? "");
5227
+ X.lastIndex = 0;
5228
+ for (let r = X.exec(e); r !== null; r = X.exec(e)) {
5229
+ let e = Xr(r[1] ?? r[2] ?? "");
5213
5230
  if (e === void 0) continue;
5214
5231
  let i = t.get(e);
5215
5232
  i === void 0 ? t.set(e, /* @__PURE__ */ new Set([n])) : i.add(n);
5216
5233
  }
5217
5234
  }
5218
5235
  return t;
5219
- }, Xr = (e, t) => {
5236
+ }, Qr = (e, t) => {
5220
5237
  let n = new Set(e);
5221
- for (let r of e) for (let e of [qr(r), m(h(r))]) {
5238
+ for (let r of e) for (let e of [Yr(r), m(h(r))]) {
5222
5239
  let r = t.get(e);
5223
5240
  if (r !== void 0) for (let e of r) n.add(e);
5224
5241
  }
5225
5242
  return n;
5226
- }, Zr = [
5243
+ }, $r = [
5227
5244
  "**/*.ts",
5228
5245
  "**/*.tsx",
5229
5246
  "!**/node_modules/**",
5230
5247
  "!**/dist/**",
5231
5248
  "!**/.framework/**",
5232
5249
  "!**/*.d.ts"
5233
- ], Z = (e, t, n = ei) => {
5250
+ ], Q = (e, t, n = ni) => {
5234
5251
  let r = /* @__PURE__ */ new Set();
5235
- for (let e of t) for (let t of e.scope ?? Zr) r.add(t);
5252
+ for (let e of t) for (let t of e.scope ?? $r) r.add(t);
5236
5253
  let i = n(e);
5237
5254
  if (i !== void 0) {
5238
- let t = [...r].filter((e) => !e.startsWith("!")).map((e) => $r(e)), n = [...r].filter((e) => e.startsWith("!")).map((e) => $r(e.slice(1))), a = [...J], o = [];
5255
+ let t = [...r].filter((e) => !e.startsWith("!")).map((e) => ti(e)), n = [...r].filter((e) => e.startsWith("!")).map((e) => ti(e.slice(1))), a = [...Y], o = [];
5239
5256
  for (let r of i) {
5240
5257
  if (a.some((e) => r === e || r.startsWith(`${e}/`) || r.includes(`/${e}/`)) || !t.some((e) => e(r)) || n.some((e) => e(r))) continue;
5241
5258
  let i = g(e, r);
5242
5259
  v(i) && o.push(i);
5243
5260
  }
5244
- return Qr(o.length, e), o;
5261
+ return ei(o.length, e), o;
5245
5262
  }
5246
5263
  let a = oe([...r], {
5247
5264
  cwd: e,
5248
5265
  absolute: !0,
5249
5266
  expandDirectories: !1,
5250
5267
  followSymbolicLinks: !1,
5251
- ignore: [...Kr()]
5268
+ ignore: [...Jr()]
5252
5269
  });
5253
- return Qr(a.length, e), a;
5254
- }, Qr = (e, t) => {
5255
- let n = ti();
5270
+ return ei(a.length, e), a;
5271
+ }, ei = (e, t) => {
5272
+ let n = ri();
5256
5273
  if (!(e <= n)) throw Error(`voltro update: the codemod scan matched ${e} files under ${t}, past the ${n} ceiling.\n Every matched file is parsed into one ts-morph project, so the heap needed grows with\n this number — past the ceiling it runs out of memory, and V8 aborts without naming a\n limit, which is why this stops here instead. Three ways out, in order:\n • put non-source directories in .gitignore (inside a git repo the scan then never\n sees them at all — a build cache, a data dump, a virtualenv),\n • run \`voltro update\` from the app directory rather than the workspace root, or\n • take one codemod at a time: \`voltro update --dry-run\` lists the ids, then\n \`voltro update --codemods-only --only <id>\` runs a single one.\n If every one of those files really is source this pass must rewrite, raise the ceiling\n with VOLTRO_CODEMOD_MAX_FILES and give node room: NODE_OPTIONS=--max-old-space-size=8192.`);
5257
- }, $r = (e) => {
5274
+ }, ti = (e) => {
5258
5275
  let t = e.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*\//g, "\0").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\u0000/g, "(?:.*/)?").replace(/\\\{([^}]*)\\\}/g, (e, t) => `(?:${t.split(",").join("|")})`);
5259
5276
  return (e) => RegExp(`^${t}$`).test(e);
5260
- }, ei = (e) => {
5277
+ }, ni = (e) => {
5261
5278
  try {
5262
5279
  let t = re("git", [
5263
5280
  "ls-files",
@@ -5278,17 +5295,17 @@ var x = (e, t, n) => {
5278
5295
  } catch {
5279
5296
  return;
5280
5297
  }
5281
- }, ti = () => {
5298
+ }, ri = () => {
5282
5299
  let e = Number(process.env.VOLTRO_CODEMOD_MAX_FILES);
5283
5300
  return Number.isInteger(e) && e > 0 ? e : 2e4;
5284
- }, Q = (e, t) => {
5301
+ }, $ = (e, t) => {
5285
5302
  let n = e.split(".").map(Number), r = t.split(".").map(Number);
5286
5303
  for (let e = 0; e < 3; e++) {
5287
5304
  let t = (n[e] ?? 0) - (r[e] ?? 0);
5288
5305
  if (t !== 0) return t;
5289
5306
  }
5290
5307
  return 0;
5291
- }, ni = (e, t, n = q) => n.filter((n) => Q(e, n.version) < 0 && Q(n.version, t) <= 0).slice().sort(he), $ = (e, t, n = () => {}) => {
5308
+ }, ii = (e, t, n = J) => n.filter((n) => $(e, n.version) < 0 && $(n.version, t) <= 0).slice().sort(he), ai = (e, t, n = () => {}) => {
5292
5309
  let r = [], i = [], a = [];
5293
5310
  for (let o of t) {
5294
5311
  if (!(!o.appliesTo || o.appliesTo({ project: e }))) {
@@ -5334,8 +5351,8 @@ var x = (e, t, n) => {
5334
5351
  manual: i,
5335
5352
  skipped: a
5336
5353
  };
5337
- }, ri = async (e) => {
5338
- let t = e.log ?? (() => {}), n = ni(e.from, e.to, e.codemods ?? q), r = e.only === void 0 || e.only.length === 0 ? n : (() => {
5354
+ }, oi = async (e) => {
5355
+ let t = e.log ?? (() => {}), n = ii(e.from, e.to, e.codemods ?? J), r = e.only === void 0 || e.only.length === 0 ? n : (() => {
5339
5356
  let t = n.filter((t) => e.only.includes(t.id)), r = e.only.filter((e) => !n.some((t) => t.id === e));
5340
5357
  if (r.length > 0) throw Error(`voltro update --only: no codemod in ${e.from} → ${e.to} has id ${r.map((e) => `"${e}"`).join(", ")}.\n Available for this jump:\n${n.map((e) => ` ${e.id}`).join("\n")}`);
5341
5358
  return t;
@@ -5354,15 +5371,15 @@ var x = (e, t, n) => {
5354
5371
  baseUrl: i.baseUrl,
5355
5372
  paths: i.paths
5356
5373
  } }
5357
- }), o, s = Z(e.root, r), c = r.filter((e) => e.needsImporters === !0 && e.scope !== void 0), l = [], u = [], d = [], p = c.length > 0 ? Yr(Z(e.root, [{
5374
+ }), o, s = Q(e.root, r), c = r.filter((e) => e.needsImporters === !0 && e.scope !== void 0), l = [], u = [], d = [], p = c.length > 0 ? Zr(Q(e.root, [{
5358
5375
  ...c[0],
5359
- scope: Zr
5376
+ scope: $r
5360
5377
  }])) : void 0;
5361
5378
  for (let n of r) {
5362
5379
  if (c.includes(n)) {
5363
- let r = a(), i = Z(e.root, [n]);
5364
- for (let e of Xr(i, p)) v(e) && r.addSourceFileAtPath(e);
5365
- let s = $(r, [n], t);
5380
+ let r = a(), i = Q(e.root, [n]);
5381
+ for (let e of Qr(i, p)) v(e) && r.addSourceFileAtPath(e);
5382
+ let s = ai(r, [n], t);
5366
5383
  e.dryRun || await r.save(), l.push(...s.applied), u.push(...s.manual), d.push(...s.skipped), o = void 0;
5367
5384
  continue;
5368
5385
  }
@@ -5371,7 +5388,7 @@ var x = (e, t, n) => {
5371
5388
  for (let t of s) v(t) && e.addSourceFileAtPath(t);
5372
5389
  return e;
5373
5390
  })();
5374
- let r = $(o, [n], t);
5391
+ let r = ai(o, [n], t);
5375
5392
  e.dryRun || await o.save(), l.push(...r.applied), u.push(...r.manual), d.push(...r.skipped);
5376
5393
  }
5377
5394
  return {
@@ -5381,4 +5398,4 @@ var x = (e, t, n) => {
5381
5398
  };
5382
5399
  };
5383
5400
  //#endregion
5384
- export { C as i, ri as n, J as r, Q as t };
5401
+ export { C as i, oi as n, Y as r, $ as t };
@@ -90,7 +90,7 @@ var a = () => {
90
90
  name: "dev",
91
91
  summary: "Start the local development server (auto-discovers routes / mutations).",
92
92
  status: "wired",
93
- run: (e) => import("./dev-D2BikO7a.js").then((t) => t.runDev(e)),
93
+ run: (e) => import("./dev-BSFTgCQ5.js").then((t) => t.runDev(e)),
94
94
  help: {
95
95
  usage: "[app]",
96
96
  examples: [["voltro dev", "boot the app in the current directory"], ["voltro dev apps/acme/api", "boot a specific app"]],
@@ -108,7 +108,7 @@ var a = () => {
108
108
  name: "dashboard",
109
109
  summary: "Serve the DevTools dashboard standalone (from @voltro/dashboard). Targets via VOLTRO_DASHBOARD_APPS; --port to override.",
110
110
  status: "wired",
111
- run: (e) => import("./dashboardCommand-D7SgZGaN.js").then((t) => t.runDashboardCommand(e)),
111
+ run: (e) => import("./dashboardCommand-D5Jwjmr1.js").then((t) => t.runDashboardCommand(e)),
112
112
  help: {
113
113
  usage: "[--port <n>]",
114
114
  flags: [["--port <n>", "port to serve the dashboard on"]],
@@ -120,7 +120,7 @@ var a = () => {
120
120
  name: "check",
121
121
  summary: "Verify the app graph (blast-radius checks) against a running api; LLM-shaped --json diagnostics. Flags: --json, --process <p>, --diff removeTable:<name>.",
122
122
  status: "wired",
123
- run: (e) => import("./checkCommand-DKpDLlqu.js").then((t) => t.runCheckCommand(e)),
123
+ run: (e) => import("./checkCommand-BTA6P3Yr.js").then((t) => t.runCheckCommand(e)),
124
124
  help: {
125
125
  usage: "[--json] [--offline] [--process <name>] [--diff removeTable:<name>]",
126
126
  flags: [
@@ -154,7 +154,7 @@ var a = () => {
154
154
  name: "webhooks",
155
155
  summary: "Outbound-webhook artefacts. `consumer` generates the ZERO-DEPENDENCY Standard-Webhooks verification package a subscriber installs, from this app's own declared events; `events` lists the events a subscriber can register for. Usage: voltro webhooks <consumer|events> [path] [--out <dir>] [--name <pkg>] [--json].",
156
156
  status: "wired",
157
- run: (e) => import("./webhooksCommand-DlAgS2Iw.js").then((t) => t.runWebhooksCommand(e)),
157
+ run: (e) => import("./webhooksCommand-di1CJVzu.js").then((t) => t.runWebhooksCommand(e)),
158
158
  help: {
159
159
  usage: "<consumer|events> [path] [--out <dir>] [--name <pkg>] [--json]",
160
160
  flags: [
@@ -170,7 +170,7 @@ var a = () => {
170
170
  name: "evolve",
171
171
  summary: "Schema-evolution copilot: propose an observed-graph-driven codemod + a branch-verified backfill for a schema change (rename/retype/split/drop a column, rename a table). Dry-run by default; --write applies. Usage: voltro evolve rename-column <table>.<col> --to <newName> [--write] [--json].",
172
172
  status: "wired",
173
- run: (e) => import("./evolveCommand-CHsLCtDf.js").then((t) => t.runEvolveCommand(e)),
173
+ run: (e) => import("./evolveCommand-iU35TPjT.js").then((t) => t.runEvolveCommand(e)),
174
174
  help: {
175
175
  usage: "<rename-column|rename-table|retype-column|split-column|drop-column> <target> [--to <new>] [--write]",
176
176
  flags: [
@@ -187,7 +187,7 @@ var a = () => {
187
187
  name: "codegen",
188
188
  summary: "Emit rpcGroup.generated.ts from discovered route / mutation descriptors.",
189
189
  status: "wired",
190
- run: (e) => import("./codegenCommand-C4YoQIc2.js").then((t) => t.runCodegenCommand(e)),
190
+ run: (e) => import("./codegenCommand-DH-8ZXzR.js").then((t) => t.runCodegenCommand(e)),
191
191
  help: {
192
192
  usage: "[app]",
193
193
  examples: [["voltro codegen", "regenerate rpcGroup.generated.ts for the app in the cwd"]],
@@ -258,7 +258,7 @@ var a = () => {
258
258
  name: "info",
259
259
  summary: "Report versions (CLI, node, every installed @voltro/* — flags lockstep skew), package manager, and dialect. --json for CI. Exits 1 on version skew.",
260
260
  status: "wired",
261
- run: (e) => import("./infoCommand-DwOgK1t6.js").then((t) => t.runInfoCommand(e)),
261
+ run: (e) => import("./infoCommand-unqisJGp.js").then((t) => t.runInfoCommand(e)),
262
262
  help: {
263
263
  usage: "[--json]",
264
264
  flags: [["--json", "machine-readable report"]],
@@ -279,7 +279,7 @@ var a = () => {
279
279
  name: "env",
280
280
  summary: "Inspect/sync the typed-env manifest. Subcommands: check (default), sync (.env.example), types (env.generated.d.ts for CI tsc), turbo.",
281
281
  status: "wired",
282
- run: (e) => import("./envCommand-CCGPRQY1.js").then((t) => t.runEnvCommand(e)),
282
+ run: (e) => import("./envCommand-TZzcyqZ-.js").then((t) => t.runEnvCommand(e)),
283
283
  help: {
284
284
  usage: "[check|sync|types|turbo] [--force]",
285
285
  flags: [["--force", "overwrite the generated file instead of refusing on a conflict"]],
@@ -308,12 +308,12 @@ var a = () => {
308
308
  run: async (e) => {
309
309
  let t = e.find((e) => !e.startsWith("-")) ?? process.cwd();
310
310
  if (e.includes("--preflight")) {
311
- let { runServePreflight: e } = await import("./doctorCommand-CM4Ch9C7.js");
311
+ let { runServePreflight: e } = await import("./doctorCommand-BYffQc0s.js");
312
312
  return e(n(t), !0);
313
313
  }
314
314
  let { tryRunWebServe: r } = await import("./webDev-BcykISYQ2.js"), i = await r(n(t));
315
315
  if (!i.ran) {
316
- let { runServeDispatch: t } = await import("./serveCommand-CbDHU6l-.js");
316
+ let { runServeDispatch: t } = await import("./serveCommand-CEBVP36A.js");
317
317
  return t(e);
318
318
  }
319
319
  return i.exitCode;
@@ -341,13 +341,13 @@ var a = () => {
341
341
  handlesHelp: !0,
342
342
  summary: "Preflight an app for production: the precompiled serve bundle, hand-rolled primitives (naming the shipped one), @voltro/* version skew, executors with no access check, `.serverOnly()` leaks, and junction-FK gaps.",
343
343
  status: "wired",
344
- run: (e) => import("./doctorCommand-CM4Ch9C7.js").then((t) => t.runDoctorCommand(e))
344
+ run: (e) => import("./doctorCommand-BYffQc0s.js").then((t) => t.runDoctorCommand(e))
345
345
  },
346
346
  {
347
347
  name: "build",
348
348
  summary: "Production build for a web app (vite build + per-page SSG pre-render).",
349
349
  status: "wired",
350
- run: (e) => import("./build-CD8K4XOr.js").then((t) => t.runBuildCommand(e)),
350
+ run: (e) => import("./build-DBe6c7qC.js").then((t) => t.runBuildCommand(e)),
351
351
  help: {
352
352
  usage: "[app] [--target <t>]",
353
353
  flags: [["--target <t>", "build target"]],
@@ -363,7 +363,7 @@ var a = () => {
363
363
  name: "prune-runtime",
364
364
  summary: "Trim a deployed web tree’s node_modules to the reachable runtime set (standalone image slimming).",
365
365
  status: "wired",
366
- run: (e) => import("./runtimeTrace-CH3eUiMw.js").then((t) => t.runPruneRuntimeCommand(e)),
366
+ run: (e) => import("./runtimeTrace-D5LJ_N55.js").then((t) => t.runPruneRuntimeCommand(e)),
367
367
  hidden: !0
368
368
  },
369
369
  {
@@ -381,7 +381,7 @@ var a = () => {
381
381
  name: "dormancy",
382
382
  summary: "Single-node scale-to-zero: front the API with a wake-orchestrator that stops the app when idle and brings it back on a request or a due wakeup (cron/workflow). Needs a SQL store. Flags: --port, --app-port, --idle-grace-ms, --tick-ms.",
383
383
  status: "wired",
384
- run: (e) => import("./dormancyCommand-QewYug_s.js").then((t) => t.runDormancyCommand(e)),
384
+ run: (e) => import("./dormancyCommand-6F6NsJKf.js").then((t) => t.runDormancyCommand(e)),
385
385
  help: {
386
386
  usage: "[app] [--port <n>] [--app-port <n>] [--idle-grace-ms <n>] [--tick-ms <n>]",
387
387
  flags: [
@@ -468,7 +468,7 @@ var a = () => {
468
468
  name: "data",
469
469
  summary: "Export/import + backup/restore of app data. Logical (rows + optional assets): export <dir> [--tenant <id>|--tables a,b] [--assets] [--compression zstd|gzip|none] [--consistency live|snapshot]; import <dir> [--assets] [--no-verify]. Native (rows ONLY — no blobs): backup <dir> / restore <dir> (pg_dump/mariadb-dump/…). Resumable; typed-NDJSON; content-addressed assets on the logical path.",
470
470
  status: "wired",
471
- run: (e) => import("./dataCommand-BhYwDgg-.js").then((t) => t.runDataCommand(e)),
471
+ run: (e) => import("./dataCommand-DnCm0B2C.js").then((t) => t.runDataCommand(e)),
472
472
  help: {
473
473
  usage: "<export|import|backup|restore> <dir> [options]",
474
474
  flags: [
@@ -523,20 +523,20 @@ var a = () => {
523
523
  handlesHelp: !0,
524
524
  summary: "Upgrade the app to the latest framework: bump every @voltro/* dependency (across ALL workspace members, install once at the workspace root), then run the codemods shipped with the target version. Flags: --to <version>, --from <version>, --codemods-only, --dry-run, --force, --exact, --help. After: run `voltro db apply`.",
525
525
  status: "wired",
526
- run: (e) => import("./updateCommand-BlMZhWgO.js").then((t) => t.runUpdateCommand(e))
526
+ run: (e) => import("./updateCommand-CSBXVsYq.js").then((t) => t.runUpdateCommand(e))
527
527
  },
528
528
  {
529
529
  name: "_apply-codemods",
530
530
  summary: "Internal: apply shipped codemods for a framework version jump (re-exec target of `voltro update`).",
531
531
  status: "wired",
532
532
  hidden: !0,
533
- run: (e) => import("./updateCommand-BlMZhWgO.js").then((t) => t.runApplyCodemods(e))
533
+ run: (e) => import("./updateCommand-CSBXVsYq.js").then((t) => t.runApplyCodemods(e))
534
534
  },
535
535
  {
536
536
  name: "embeddings",
537
537
  summary: "Embeddings tooling. Subcommand: backfill <table> --text <field> --vector <field> [--model <m>] [--model-field <f>] [--batch <n>] [--dry-run] — (re)embed rows the vectorEmbedding() mixin missed.",
538
538
  status: "wired",
539
- run: (e) => import("./embeddingsCommand-BfiLS_QI.js").then((t) => t.runEmbeddingsCommand(e)),
539
+ run: (e) => import("./embeddingsCommand-DRRdneJD.js").then((t) => t.runEmbeddingsCommand(e)),
540
540
  help: {
541
541
  usage: "backfill <table> --text <field> --vector <field> [--model <m>] [--batch <n>] [--dry-run]",
542
542
  flags: [
@@ -1,4 +1,4 @@
1
- import { d as e } from "./dev-C7sFZq3m.js";
1
+ import { d as e } from "./dev-Dc4cpmRl.js";
2
2
  import { P as t, j as n } from "./webDev-Dybxew86.js";
3
3
  import { t as r } from "./start-T4VesWiM.js";
4
4
  import { join as i } from "node:path";
@@ -1,5 +1,5 @@
1
1
  import { t as e } from "./cliError-BmdYnghb.js";
2
- import { c as t, i as n, o as r } from "./dev-C7sFZq3m.js";
2
+ import { c as t, i as n, o as r } from "./dev-Dc4cpmRl.js";
3
3
  import { n as i, t as a } from "./cliArgs-D4p8n7EE.js";
4
4
  import { r as o } from "./dialectDriver-CgXnDfec.js";
5
5
  import { t as s } from "./dataProfile-dW-PsfLB.js";
@@ -1,3 +1,3 @@
1
- import { c as e, d as t, f as n, i as r, u as i } from "./dev-C7sFZq3m.js";
1
+ import { c as e, d as t, f as n, i as r, u as i } from "./dev-Dc4cpmRl.js";
2
2
  import "./dialectDriver-CgXnDfec.js";
3
3
  export { r as buildStore, e as loadApiConfig, i as loadDiscovered, t as runDev, n as walk };