@voltro/cli 0.31.0 → 0.33.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 (81) hide show
  1. package/CHANGELOG.md +368 -0
  2. package/THIRD-PARTY-NOTICES.md +1 -29
  3. package/dist/apiBuild-C-x9YacA.js +2 -0
  4. package/dist/{apiBuild-CLPt-pX6.js → apiBuild-h9VHtnlw.js} +2 -2
  5. package/dist/bin.js +3 -3
  6. package/dist/checkCommand-DRovTKza.js +2 -0
  7. package/dist/{checkCommand-D7r6_pk7.js → checkCommand-xGhRFFg2.js} +330 -290
  8. package/dist/{commands-CNVVv03h.js → commands-CJfepbm4.js} +139 -13
  9. package/dist/{dbCommand-BH8GAYuf.js → dbCommand-DTLKAfbA.js} +431 -263
  10. package/dist/dbCommand-b1gum4td.js +2 -0
  11. package/dist/{dev-DdQEn2Ia.js → dev-C_P8FLSx.js} +2141 -2081
  12. package/dist/{dev-DOZVMVfi.js → dev-iiMtlkfs.js} +1 -1
  13. package/dist/index.js +1 -1
  14. package/dist/{inspectMetrics-BeEAnjqw.js → inspectMetrics-1xzTKAFx.js} +750 -685
  15. package/dist/{sdkgen-v9WV8zRi.js → sdkgen-C81QIkiL.js} +1 -1
  16. package/dist/serveCommand-DdaM4Hup.js +1608 -0
  17. package/dist/serveEntry.js +2 -2
  18. package/dist/{start-CI2QdKy9.js → start-C0koT0UO.js} +1 -1
  19. package/dist/startEntry.js +2 -2
  20. package/package.json +431 -18
  21. package/templates/AGENTS.md +1 -1
  22. package/templates/agent-docs/_index.md +1 -1
  23. package/templates/agent-docs/database/misc.md +37 -0
  24. package/templates/agent-docs/database/schema.md +4 -2
  25. package/templates/agent-docs/deployment.md +87 -1
  26. package/templates/agent-docs/plugins/audit.md +24 -0
  27. package/templates/agent-docs/plugins.md +50 -0
  28. package/templates/agent-docs/scheduling.md +4 -1
  29. package/templates/agent-docs/security.md +31 -1
  30. package/templates/agent-docs/whats-new.md +149 -59
  31. package/templates/apps/api-ai/package.json +7 -7
  32. package/templates/apps/api-auth/package.json +8 -8
  33. package/templates/apps/api-backend/package.json +7 -7
  34. package/templates/apps/api-backend-deactivation/package.json +7 -7
  35. package/templates/apps/api-backend-mail/package.json +8 -8
  36. package/templates/apps/api-backend-mariadb/package.json +9 -9
  37. package/templates/apps/api-backend-sqlite/package.json +8 -8
  38. package/templates/apps/api-backend-storage/package.json +8 -8
  39. package/templates/apps/api-cms/package.json +10 -10
  40. package/templates/apps/api-collab/package.json +8 -8
  41. package/templates/apps/api-data-advanced/package.json +8 -8
  42. package/templates/apps/api-durable/package.json +8 -8
  43. package/templates/apps/api-feature-flags/package.json +9 -9
  44. package/templates/apps/api-governance/package.json +8 -8
  45. package/templates/apps/api-kv/package.json +8 -8
  46. package/templates/apps/api-moderation/package.json +8 -8
  47. package/templates/apps/api-observability/package.json +8 -8
  48. package/templates/apps/api-ratelimit/package.json +8 -8
  49. package/templates/apps/api-rbac/package.json +8 -8
  50. package/templates/apps/api-rest/package.json +7 -7
  51. package/templates/apps/api-saas/package.json +11 -11
  52. package/templates/apps/api-saas-starter/package.json +10 -10
  53. package/templates/apps/api-search/package.json +8 -8
  54. package/templates/apps/api-status/package.json +8 -8
  55. package/templates/apps/api-versioning/package.json +8 -8
  56. package/templates/apps/api-webhooks/package.json +9 -9
  57. package/templates/apps/changelog/package.json +6 -6
  58. package/templates/apps/edge-functions/package.json +2 -2
  59. package/templates/apps/frontend-admin/package.json +8 -8
  60. package/templates/apps/frontend-app/package.json +8 -8
  61. package/templates/apps/frontend-auth/package.json +8 -8
  62. package/templates/apps/frontend-blank/package.json +7 -7
  63. package/templates/apps/frontend-cms/package.json +9 -9
  64. package/templates/apps/frontend-collab/package.json +9 -9
  65. package/templates/apps/frontend-contact/package.json +7 -7
  66. package/templates/apps/frontend-dashboard/package.json +7 -7
  67. package/templates/apps/frontend-docs/package.json +7 -7
  68. package/templates/apps/frontend-i18n/package.json +6 -6
  69. package/templates/apps/frontend-landing/package.json +7 -7
  70. package/templates/apps/frontend-portal/package.json +8 -8
  71. package/templates/apps/frontend-saas/package.json +8 -8
  72. package/templates/apps/frontend-spa/package.json +7 -7
  73. package/templates/apps/frontend-ssr/package.json +7 -7
  74. package/templates/apps/frontend-ssr-api/package.json +8 -8
  75. package/templates/apps/frontend-static-blog/package.json +6 -6
  76. package/templates/apps/frontend-status/package.json +8 -8
  77. package/templates/apps/mobile-app/package.json +2 -2
  78. package/dist/apiBuild-BOqL1dlg.js +0 -2
  79. package/dist/checkCommand-ClRvH_SN.js +0 -2
  80. package/dist/dbCommand-BwQ_Jl98.js +0 -2
  81. package/dist/serveCommand-KsKXXWn4.js +0 -1578
@@ -1,31 +1,32 @@
1
- import { Ct as e, et as t, f as n, n as r, nt as i, o as a, rt as o, tt as s, z as c } from "./inspectMetrics-BeEAnjqw.js";
2
- import { Ht as l, Ut as u } from "./dev-DdQEn2Ia.js";
1
+ import { Ct as e, et as t, f as n, n as r, nt as i, o as a, rt as o, tt as s, z as c } from "./inspectMetrics-1xzTKAFx.js";
2
+ import { Gt as l, Wt as u } from "./dev-C_P8FLSx.js";
3
3
  import { C as d, E as f, O as p, T as m, d as h, h as g, i as _, l as v, m as y, r as ee, u as te } from "./fileConventions-Cof68_BL.js";
4
- import { r as ne, u as re } from "./apiBuild-CLPt-pX6.js";
4
+ import { r as ne, u as re } from "./apiBuild-h9VHtnlw.js";
5
5
  import { r as ie } from "./appGraph-gQ_6GkQQ.js";
6
6
  import { dirname as b, isAbsolute as ae, join as x, relative as S, resolve as C, sep as w } from "node:path";
7
- import { routeDiagnosticsToStderr as oe } from "@voltro/logger";
8
- import { existsSync as T, readFileSync as E, readdirSync as D, statSync as O, writeFileSync as se } from "node:fs";
7
+ import { pathToFileURL as oe } from "node:url";
8
+ import { routeDiagnosticsToStderr as se } from "@voltro/logger";
9
+ import { existsSync as T, readFileSync as E, readdirSync as D, statSync as O, writeFileSync as ce } from "node:fs";
9
10
  import { Node as k, Project as A, SyntaxKind as j } from "ts-morph";
10
11
  //#region src/cliOutput.ts
11
- var ce = () => {
12
- oe();
12
+ var le = () => {
13
+ se();
13
14
  }, M = (e, t = {}) => {
14
15
  console.log(JSON.stringify(e, null, t.pretty === !1 ? 0 : 2));
15
- }, le = (e) => {
16
+ }, ue = (e) => {
16
17
  for (let t = 0; t < e.length; t++) {
17
18
  let n = e[t];
18
19
  if (n === "--json" || n === "--format=json" || n === "--format" && e[t + 1] === "json") return !0;
19
20
  }
20
21
  return !1;
21
- }, ue = (e, t, n = !1) => {
22
+ }, de = (e, t, n = !1) => {
22
23
  let r = { ...e ?? {} }, i = t ?? process.env.VOLTRO_INSPECT_TOKEN;
23
24
  if (i !== void 0 && i !== "" && (r.authorization = `Bearer ${i}`), n) {
24
25
  let e = process.env.VOLTRO_INSPECT_WRITE_TOKEN;
25
26
  e !== void 0 && e !== "" && (r["x-voltro-inspect-write"] = e);
26
27
  }
27
28
  return r;
28
- }, de = /* @__PURE__ */ new Set([
29
+ }, fe = /* @__PURE__ */ new Set([
29
30
  "POST",
30
31
  "PUT",
31
32
  "PATCH",
@@ -35,7 +36,7 @@ var ce = () => {
35
36
  try {
36
37
  let t = await fetch(r, {
37
38
  method: i,
38
- headers: ue(a ? { "content-type": "application/json" } : void 0, e.inspectToken, de.has(i)),
39
+ headers: de(a ? { "content-type": "application/json" } : void 0, e.inspectToken, fe.has(i)),
39
40
  ...a ? { body: JSON.stringify(n.body) } : {}
40
41
  }), o = await t.text(), s;
41
42
  if (o.length > 0) try {
@@ -44,7 +45,7 @@ var ce = () => {
44
45
  s = o;
45
46
  }
46
47
  if (!t.ok) {
47
- let n = s, r = typeof n == "object" && n ? String(n.message ?? n.reason ?? n.error ?? `HTTP ${t.status}`) : `HTTP ${t.status}`, a = de.has(i) && (process.env.VOLTRO_INSPECT_WRITE_TOKEN ?? "") === "" && /write/i.test(r);
48
+ let n = s, r = typeof n == "object" && n ? String(n.message ?? n.reason ?? n.error ?? `HTTP ${t.status}`) : `HTTP ${t.status}`, a = fe.has(i) && (process.env.VOLTRO_INSPECT_WRITE_TOKEN ?? "") === "" && /write/i.test(r);
48
49
  return {
49
50
  kind: "err",
50
51
  name: e.name,
@@ -109,7 +110,7 @@ var ce = () => {
109
110
  },
110
111
  rest: n
111
112
  };
112
- }, fe = (e) => ({
113
+ }, pe = (e) => ({
113
114
  id: `remote:${e.url}`,
114
115
  name: e.name,
115
116
  kind: "api",
@@ -120,7 +121,7 @@ var ce = () => {
120
121
  status: "live",
121
122
  logFile: "",
122
123
  ...e.token === void 0 ? {} : { inspectToken: e.token }
123
- }), pe = async (t, n) => n === void 0 ? (await e()).apps.filter((e) => e.kind === "api" && e.status === "live" && e.url.length > 0 && (t === void 0 || e.name === t)) : [fe(n)], me = (e) => {
124
+ }), me = async (t, n) => n === void 0 ? (await e()).apps.filter((e) => e.kind === "api" && e.status === "live" && e.url.length > 0 && (t === void 0 || e.name === t)) : [pe(n)], he = (e) => {
124
125
  let t = "pretty", n = [];
125
126
  for (let r = 0; r < e.length; r++) {
126
127
  let i = e[r];
@@ -144,7 +145,7 @@ var ce = () => {
144
145
  format: t,
145
146
  rest: n
146
147
  };
147
- }, he = (e, t = process.env) => {
148
+ }, ge = (e, t = process.env) => {
148
149
  let { target: n, rest: r, error: i } = P(e, t), a, o = [];
149
150
  for (let e = 0; e < r.length; e++) {
150
151
  let t = r[e];
@@ -164,7 +165,7 @@ var ce = () => {
164
165
  rest: o,
165
166
  ...i === void 0 ? {} : { error: i }
166
167
  };
167
- }, ge = (e) => {
168
+ }, _e = (e) => {
168
169
  let t = "", n = !1;
169
170
  for (let r = 0; r < e.length; r++) {
170
171
  let i = e[r];
@@ -192,8 +193,8 @@ var ce = () => {
192
193
  }
193
194
  t += i;
194
195
  }
195
- return JSON.parse(_e(t));
196
- }, _e = (e) => {
196
+ return JSON.parse(ve(t));
197
+ }, ve = (e) => {
197
198
  let t = "", n = !1;
198
199
  for (let r = 0; r < e.length; r++) {
199
200
  let i = e[r];
@@ -221,7 +222,7 @@ var ce = () => {
221
222
  t.add(e);
222
223
  let n;
223
224
  try {
224
- n = ge(E(e, "utf8"));
225
+ n = _e(E(e, "utf8"));
225
226
  } catch {
226
227
  return;
227
228
  }
@@ -237,7 +238,7 @@ var ce = () => {
237
238
  ...n.compilerOptions?.paths
238
239
  }
239
240
  } };
240
- }, ve = (e, t = "tsconfig.json") => {
241
+ }, ye = (e, t = "tsconfig.json") => {
241
242
  let n = ae(t) ? t : C(e, t), r = F(n, /* @__PURE__ */ new Set()), i = r?.compilerOptions?.paths;
242
243
  if (i === void 0) return;
243
244
  let a = {};
@@ -261,11 +262,11 @@ var ce = () => {
261
262
  });
262
263
  }
263
264
  return o.sort((e, t) => t.prefix.length - e.prefix.length);
264
- }, ye = (e, t) => {
265
+ }, be = (e, t) => {
265
266
  for (let n of t) if (n.wildcard) {
266
267
  if (e.startsWith(n.prefix)) return x(n.target, e.slice(n.prefix.length));
267
268
  } else if (e === n.prefix) return n.target;
268
- }, L = ".voltro-vendored", be = (e, t) => {
269
+ }, L = ".voltro-vendored", xe = (e, t) => {
269
270
  let n = [], r = /* @__PURE__ */ new Set(), i = (e, t) => {
270
271
  let i = C(e);
271
272
  r.has(i) || !T(i) || (r.add(i), n.push({
@@ -296,7 +297,7 @@ var ce = () => {
296
297
  }
297
298
  }
298
299
  return n;
299
- }, xe = (e, t) => t.some((t) => e === t.dir || e.startsWith(`${t.dir}${w}`)), Se = (e, t) => t.map((t) => `${S(e, t.dir) || "."} (${t.source})`), Ce = [
300
+ }, Se = (e, t) => t.some((t) => e === t.dir || e.startsWith(`${t.dir}${w}`)), Ce = (e, t) => t.map((t) => `${S(e, t.dir) || "."} (${t.source})`), we = [
300
301
  {
301
302
  id: "component.ui",
302
303
  re: _,
@@ -337,7 +338,7 @@ var ce = () => {
337
338
  re: p,
338
339
  needsTest: !1
339
340
  }
340
- ], R = (e) => Ce.find((t) => t.re.test(e))?.id ?? null, we = (e) => m.test(e), Te = /* @__PURE__ */ new Set([
341
+ ], R = (e) => we.find((t) => t.re.test(e))?.id ?? null, Te = (e) => m.test(e), Ee = /* @__PURE__ */ new Set([
341
342
  "useMutation",
342
343
  "useAction",
343
344
  "useUpload",
@@ -347,12 +348,12 @@ var ce = () => {
347
348
  "useAgentStream",
348
349
  "useResumableAgentStream",
349
350
  "useWorkflow"
350
- ]), Ee = /* @__PURE__ */ new Set(["defineTracking"]), De = /* @__PURE__ */ new Set([
351
+ ]), De = /* @__PURE__ */ new Set(["defineTracking"]), Oe = /* @__PURE__ */ new Set([
351
352
  "useSubscription",
352
353
  "useWindowedSubscription",
353
354
  "useRecord",
354
355
  "useQuery"
355
- ]), Oe = /* @__PURE__ */ new Set([
356
+ ]), ke = /* @__PURE__ */ new Set([
356
357
  "node_modules",
357
358
  "dist",
358
359
  "build",
@@ -363,7 +364,7 @@ var ce = () => {
363
364
  ".git",
364
365
  "coverage",
365
366
  ".publish"
366
- ]), ke = /\.tsx?$/, Ae = (e, t = [], n = 0) => {
367
+ ]), Ae = /\.tsx?$/, je = (e, t = [], n = 0) => {
367
368
  if (n > 12) return t;
368
369
  let r;
369
370
  try {
@@ -372,27 +373,27 @@ var ce = () => {
372
373
  return t;
373
374
  }
374
375
  for (let i of r) {
375
- if (Oe.has(i)) continue;
376
+ if (ke.has(i)) continue;
376
377
  let r = x(e, i), a;
377
378
  try {
378
379
  a = O(r);
379
380
  } catch {
380
381
  continue;
381
382
  }
382
- a.isDirectory() ? Ae(r, t, n + 1) : a.isFile() && ke.test(i) && !i.endsWith(".d.ts") && t.push(r);
383
+ a.isDirectory() ? je(r, t, n + 1) : a.isFile() && Ae.test(i) && !i.endsWith(".d.ts") && t.push(r);
383
384
  }
384
385
  return t;
385
- }, je = /\b(?:FC|FunctionComponent|ComponentType|ForwardRefExoticComponent|MemoExoticComponent)\b/, Me = /\b(?:memo|forwardRef|observer|styled)\b/, Ne = (e) => k.isArrowFunction(e) || k.isFunctionExpression(e) || k.isFunctionDeclaration(e) || k.isClassDeclaration(e) || k.isClassExpression(e), z = (e) => {
386
- if (Ne(e)) return !0;
386
+ }, Me = /\b(?:FC|FunctionComponent|ComponentType|ForwardRefExoticComponent|MemoExoticComponent)\b/, Ne = /\b(?:memo|forwardRef|observer|styled)\b/, Pe = (e) => k.isArrowFunction(e) || k.isFunctionExpression(e) || k.isFunctionDeclaration(e) || k.isClassDeclaration(e) || k.isClassExpression(e), z = (e) => {
387
+ if (Pe(e)) return !0;
387
388
  if (k.isExportAssignment(e) || k.isAsExpression(e) || k.isSatisfiesExpression(e) || k.isParenthesizedExpression(e)) return z(e.getExpression());
388
389
  if (k.isVariableDeclaration(e)) {
389
390
  let t = e.getTypeNode();
390
- if (t !== void 0 && je.test(t.getText())) return !0;
391
+ if (t !== void 0 && Me.test(t.getText())) return !0;
391
392
  let n = e.getInitializer();
392
393
  return n === void 0 || z(n);
393
394
  }
394
- return k.isCallExpression(e) ? Me.test(e.getExpression().getText()) ? !0 : e.getArguments().some((e) => Ne(e) || k.isIdentifier(e)) : k.isTaggedTemplateExpression(e) ? !0 : !(k.isObjectLiteralExpression(e) || k.isArrayLiteralExpression(e) || k.isStringLiteral(e) || k.isNoSubstitutionTemplateLiteral(e) || k.isNumericLiteral(e) || k.isTemplateExpression(e) || k.isNewExpression(e) || k.isPropertyAccessExpression(e) || e.getKind() === j.TrueKeyword || e.getKind() === j.FalseKeyword || e.getKind() === j.NullKeyword);
395
- }, Pe = (e) => {
395
+ return k.isCallExpression(e) ? Ne.test(e.getExpression().getText()) ? !0 : e.getArguments().some((e) => Pe(e) || k.isIdentifier(e)) : k.isTaggedTemplateExpression(e) ? !0 : !(k.isObjectLiteralExpression(e) || k.isArrayLiteralExpression(e) || k.isStringLiteral(e) || k.isNoSubstitutionTemplateLiteral(e) || k.isNumericLiteral(e) || k.isTemplateExpression(e) || k.isNewExpression(e) || k.isPropertyAccessExpression(e) || e.getKind() === j.TrueKeyword || e.getKind() === j.FalseKeyword || e.getKind() === j.NullKeyword);
396
+ }, Fe = (e) => {
396
397
  let t = [], n = [], r = [], i = /* @__PURE__ */ new Set();
397
398
  for (let [a, o] of e.getExportedDeclarations()) {
398
399
  let e = o[0];
@@ -415,7 +416,7 @@ var ce = () => {
415
416
  others: r,
416
417
  hasRuntimeExport: t.length + n.length + r.length > 0
417
418
  };
418
- }, B = [], Fe = (e, t, n) => {
419
+ }, B = [], Ie = (e, t, n) => {
419
420
  let r = b(e), i = [];
420
421
  for (let e = r;; e = b(e)) {
421
422
  let r = n.get(e);
@@ -434,8 +435,8 @@ var ce = () => {
434
435
  }
435
436
  for (let e of i) n.set(e, B);
436
437
  return B;
437
- }, Ie = (e, t, n) => {
438
- let r = t.startsWith(".") ? C(b(e), t) : ye(t, n);
438
+ }, Le = (e, t, n) => {
439
+ let r = t.startsWith(".") ? C(b(e), t) : be(t, n);
439
440
  if (r === void 0) return null;
440
441
  for (let e of [
441
442
  r,
@@ -447,9 +448,9 @@ var ce = () => {
447
448
  if (O(e).isFile()) return e;
448
449
  } catch {}
449
450
  return null;
450
- }, Le = (e, t, n) => {
451
+ }, Re = (e, t, n) => {
451
452
  let r = [], i = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new Map(), o = (e) => {
452
- let i = Ie(t, e, n);
453
+ let i = Le(t, e, n);
453
454
  return i !== null && r.push(i), i;
454
455
  };
455
456
  for (let t of e.getImportDeclarations()) if (o(t.getModuleSpecifierValue()), !t.isTypeOnly()) for (let e of t.getNamedImports()) e.isTypeOnly() || i.add(e.getName());
@@ -476,29 +477,29 @@ var ce = () => {
476
477
  namedBindings: i,
477
478
  reExports: a
478
479
  };
479
- }, Re = (e) => {
480
+ }, ze = (e) => {
480
481
  let t = /* @__PURE__ */ new Map();
481
482
  for (let n of e.getDescendantsOfKind(j.CallExpression)) {
482
483
  let e = n.getExpression(), r = k.isPropertyAccessExpression(e) ? e.getName() : e.getText();
483
484
  t.set(r, (t.get(r) ?? 0) + 1);
484
485
  }
485
486
  return t;
486
- }, ze = (e) => {
487
+ }, Be = (e) => {
487
488
  if (e.length <= 1) return e.length === 1;
488
489
  let t = [...e].sort((e, t) => e.length - t.length)[0];
489
490
  return e.every((e) => e.startsWith(t));
490
- }, Be = (e, t) => {
491
+ }, Ve = (e, t) => {
491
492
  let n = b(t);
492
493
  return e.startsWith(`${n}${w}`) || b(e) === n;
493
494
  }, V = (e) => {
494
- let t = Ae(e);
495
+ let t = je(e);
495
496
  if (t.length === 0) return {
496
497
  findings: [],
497
498
  declared: 0,
498
499
  scanned: 0,
499
500
  vendored: []
500
501
  };
501
- let n = be(e, t), r = t.filter((e) => !xe(e, n));
502
+ let n = xe(e, t), r = t.filter((e) => !Se(e, n));
502
503
  if (r.length === 0) return {
503
504
  findings: [],
504
505
  declared: 0,
@@ -522,7 +523,7 @@ var ce = () => {
522
523
  } catch {
523
524
  continue;
524
525
  }
525
- s.set(t, Pe(r)), c.set(t, Le(r, t, Fe(t, e, u))), l.set(t, Re(r));
526
+ s.set(t, Fe(r)), c.set(t, Re(r, t, Ie(t, e, u))), l.set(t, ze(r));
526
527
  }
527
528
  let d = /* @__PURE__ */ new Map();
528
529
  for (let [e, t] of c) for (let n of t.localTargets) {
@@ -554,11 +555,11 @@ var ce = () => {
554
555
  for (let e of r) {
555
556
  let t = R(e), n = s.get(e), r = c.get(e);
556
557
  if (n === void 0 || r === void 0) continue;
557
- let i = we(e);
558
+ let i = Te(e);
558
559
  t !== null && !i && (p += 1);
559
560
  let u = d.get(e) ?? [];
560
561
  if ((t === "component" || t === "component.ui") && !i) {
561
- let t = ze(n.components);
562
+ let t = Be(n.components);
562
563
  (n.components.length === 0 || !t) && a.push({
563
564
  rule: "component/one-per-file",
564
565
  file: o(e),
@@ -596,7 +597,7 @@ var ce = () => {
596
597
  ].join(", ")}`,
597
598
  fix: "a *.types.ts has NO runtime export. That is what makes importing it provably free AND makes it impossible for it to sit in a runtime import cycle — the guarantee is the point, so move the value to a sibling module"
598
599
  }), t === "internal") {
599
- let t = u.filter((t) => !Be(t, e));
600
+ let t = u.filter((t) => !Ve(t, e));
600
601
  t.length > 0 && a.push({
601
602
  rule: "internal/foreign-import",
602
603
  file: o(e),
@@ -606,7 +607,7 @@ var ce = () => {
606
607
  });
607
608
  }
608
609
  if (t === "fixture") {
609
- let t = u.filter((e) => !we(e) && R(e) !== "fixture");
610
+ let t = u.filter((e) => !Te(e) && R(e) !== "fixture");
610
611
  t.length > 0 && a.push({
611
612
  rule: "fixture/production-import",
612
613
  file: o(e),
@@ -616,7 +617,7 @@ var ce = () => {
616
617
  });
617
618
  }
618
619
  if (t === "component.ui" && !i) {
619
- let t = [...r.namedBindings].filter((e) => Te.has(e)).sort();
620
+ let t = [...r.namedBindings].filter((e) => Ee.has(e)).sort();
620
621
  t.length > 0 && a.push({
621
622
  rule: "ui/no-write",
622
623
  file: o(e),
@@ -651,7 +652,7 @@ var ce = () => {
651
652
  detail: t === 0 ? "declares a store file but calls no defineStore()" : `declares ${t} stores`,
652
653
  fix: "a store file defines exactly ONE store — the SSR seed pass and devtools address stores by name, so two in a file makes both harder to find and neither easier to reason about"
653
654
  });
654
- let n = [...l.get(e)?.keys() ?? []].filter((e) => De.has(e)).sort();
655
+ let n = [...l.get(e)?.keys() ?? []].filter((e) => Oe.has(e)).sort();
655
656
  n.length > 0 && a.push({
656
657
  rule: "store/mirrors-server-state",
657
658
  file: o(e),
@@ -661,7 +662,7 @@ var ce = () => {
661
662
  });
662
663
  }
663
664
  if (t !== "tracking" && !i) {
664
- let t = [...l.get(e)?.keys() ?? []].filter((e) => Ee.has(e)).sort();
665
+ let t = [...l.get(e)?.keys() ?? []].filter((e) => De.has(e)).sort();
665
666
  t.length > 0 && a.push({
666
667
  rule: "tracking/outside-tracking-file",
667
668
  file: o(e),
@@ -670,7 +671,7 @@ var ce = () => {
670
671
  fix: "move the defineTracking(...) spec into a *.tracking.ts and import it here. The event catalogue — names, property bags, the decisions about what personal data goes out — belongs in one place you can list; calling useTracking with a spec from there is fine"
671
672
  });
672
673
  }
673
- if (Ce.find((e) => e.id === t)?.needsTest === !0 && !i) {
674
+ if (we.find((e) => e.id === t)?.needsTest === !0 && !i) {
674
675
  let t = e.replace(/\.tsx?$/, ""), n = e.endsWith("x") ? "tsx" : "ts";
675
676
  ["test", "spec"].flatMap((e) => [`${t}.${e}.ts`, `${t}.${e}.tsx`]).some((e) => {
676
677
  try {
@@ -693,10 +694,10 @@ var ce = () => {
693
694
  scanned: r.length,
694
695
  vendored: n
695
696
  };
696
- }, Ve = 10, He = (e) => {
697
+ }, He = 10, Ue = (e) => {
697
698
  let { findings: t, declared: n, scanned: r, vendored: i } = V(e);
698
699
  console.log("");
699
- for (let t of Se(e, i)) console.log(`· not ours, exempt: ${t}`);
700
+ for (let t of Ce(e, i)) console.log(`· not ours, exempt: ${t}`);
700
701
  if (r === 0) return console.log("• file-taxonomy scan: no sources here — nothing to check."), 0;
701
702
  if (t.length === 0) return console.log(`✓ file-taxonomy scan: ${n} declared file(s) keep their contract (${r} scanned).`), 0;
702
703
  let a = /* @__PURE__ */ new Map();
@@ -708,12 +709,12 @@ var ce = () => {
708
709
  console.log(`• file taxonomy: ${t.length} finding(s) — ${o} error, ${t.length - o} advisory (${n} declared / ${r} scanned):`);
709
710
  for (let [e, t] of [...a].sort()) {
710
711
  console.log(` ${t[0].severity === "error" ? "✗" : "·"} ${e} (${t.length})`);
711
- for (let e of t.slice(0, Ve)) console.log(` ${e.file} — ${e.detail}`);
712
- let n = t.length - Ve;
712
+ for (let e of t.slice(0, He)) console.log(` ${e.file} — ${e.detail}`);
713
+ let n = t.length - He;
713
714
  n > 0 && console.log(` (+${n} more — \`voltro doctor --json\` prints every one.)`), console.log(` → ${t[0].fix}`);
714
715
  }
715
716
  return t.length;
716
- }, Ue = /* @__PURE__ */ new Set([
717
+ }, We = /* @__PURE__ */ new Set([
717
718
  "eq",
718
719
  "ne",
719
720
  "gt",
@@ -731,10 +732,10 @@ var ce = () => {
731
732
  "endsWith",
732
733
  "between",
733
734
  "jsonField"
734
- ]), We = (e) => {
735
+ ]), Ge = (e) => {
735
736
  if (k.isPropertyAccessExpression(e)) return e.getName();
736
737
  if (k.isIdentifier(e)) return e.getText();
737
- }, Ge = (e) => {
738
+ }, Ke = (e) => {
738
739
  let t = e;
739
740
  for (; k.isCallExpression(t);) {
740
741
  let e = t.getExpression();
@@ -742,7 +743,7 @@ var ce = () => {
742
743
  t = e.getExpression();
743
744
  }
744
745
  return t;
745
- }, Ke = (e, t, n) => {
746
+ }, qe = (e, t, n) => {
746
747
  let r = new Map(t.map((e) => [e.name, new Set(e.columns)])), i = new Map(t.map((e) => [e.name, e.columns])), a = [], o = 0, s = new A({
747
748
  useInMemoryFileSystem: !0,
748
749
  skipAddingFilesFromTsConfig: !0
@@ -760,7 +761,7 @@ var ce = () => {
760
761
  for (let t of e.getDescendantsOfKind(j.CallExpression)) {
761
762
  let e = t.getExpression();
762
763
  if (!k.isPropertyAccessExpression(e) || e.getName() !== "where") continue;
763
- let n = We(Ge(e.getExpression()));
764
+ let n = Ge(Ke(e.getExpression()));
764
765
  if (n === void 0 || !r.has(n)) {
765
766
  let t = e.getExpression();
766
767
  if (k.isCallExpression(t)) {
@@ -783,7 +784,7 @@ var ce = () => {
783
784
  else for (let e of [u, ...u.getDescendantsOfKind(j.CallExpression)]) {
784
785
  if (!k.isCallExpression(e)) continue;
785
786
  let t = e.getExpression(), n = k.isIdentifier(t) ? t.getText() : k.isPropertyAccessExpression(t) ? t.getName() : void 0;
786
- if (n === void 0 || !Ue.has(n)) continue;
787
+ if (n === void 0 || !We.has(n)) continue;
787
788
  let r = e.getArguments()[0];
788
789
  r !== void 0 && k.isStringLiteral(r) && l.push({
789
790
  column: r.getLiteralValue(),
@@ -804,7 +805,7 @@ var ce = () => {
804
805
  issues: a,
805
806
  checked: o
806
807
  };
807
- }, H = 12, qe = (e) => {
808
+ }, H = 12, Je = (e) => {
808
809
  if (e.checked === 0) return null;
809
810
  if (e.issues.length === 0) return `predicate columns: ${e.checked} checked — every filtered column exists on its table`;
810
811
  let t = [`predicate columns: ${e.issues.length} filter${e.issues.length, "s"} on a column that does not exist (${e.checked} checked)`];
@@ -813,7 +814,7 @@ var ce = () => {
813
814
  t.push(` ${n.file}:${n.line} '${n.table}' has no column '${n.column}'`), t.push(` columns: ${e}${r}`);
814
815
  }
815
816
  return t.push(" This type-checks today and fails at runtime as a bare SQL error."), t.join("\n");
816
- }, Je = /* @__PURE__ */ new Set([
817
+ }, Ye = /* @__PURE__ */ new Set([
817
818
  "id",
818
819
  "tenantId",
819
820
  "tenant_id",
@@ -833,7 +834,7 @@ var ce = () => {
833
834
  "idempotency_id",
834
835
  "idempotencyKey",
835
836
  "idempotency_key"
836
- ]), Ye = /* @__PURE__ */ new Set([
837
+ ]), Xe = /* @__PURE__ */ new Set([
837
838
  "id",
838
839
  "createdAt",
839
840
  "created_at",
@@ -843,10 +844,10 @@ var ce = () => {
843
844
  "deleted_at",
844
845
  "tenantId",
845
846
  "tenant_id"
846
- ]), Xe = (e) => Je.has(e) ? !1 : /[a-z0-9]Id$/.test(e) || /_id$/.test(e), Ze = (e) => e.type === "reference", Qe = (e) => {
847
+ ]), Ze = (e) => Ye.has(e) ? !1 : /[a-z0-9]Id$/.test(e) || /_id$/.test(e), Qe = (e) => e.type === "reference", $e = (e) => {
847
848
  let t = [];
848
849
  for (let n of e) {
849
- let e = n.columns.filter((e) => Xe(e.name)), r = e.filter((e) => !Ze(e)).map((e) => e.name);
850
+ let e = n.columns.filter((e) => Ze(e.name)), r = e.filter((e) => !Qe(e)).map((e) => e.name);
850
851
  if (r.length === 0) continue;
851
852
  let i = new Set(n.primaryKey), a = r.filter((e) => i.has(e));
852
853
  if (n.primaryKey.length >= 2 && a.length > 0) {
@@ -857,7 +858,7 @@ var ce = () => {
857
858
  });
858
859
  continue;
859
860
  }
860
- if (e.some(Ze) && e.length >= 2) {
861
+ if (e.some(Qe) && e.length >= 2) {
861
862
  t.push({
862
863
  table: n.name,
863
864
  columns: r,
@@ -865,7 +866,7 @@ var ce = () => {
865
866
  });
866
867
  continue;
867
868
  }
868
- e.length >= 2 && n.columns.filter((e) => !Xe(e.name) && !Ye.has(e.name)).length === 0 && t.push({
869
+ e.length >= 2 && n.columns.filter((e) => !Ze(e.name) && !Xe.has(e.name)).length === 0 && t.push({
869
870
  table: n.name,
870
871
  columns: r,
871
872
  signal: "link-only"
@@ -875,20 +876,20 @@ var ce = () => {
875
876
  issues: t,
876
877
  tablesChecked: e.length
877
878
  };
878
- }, $e = {
879
+ }, et = {
879
880
  "composite-pk": "part of a composite primary key",
880
881
  "reference-sibling": "sits beside a wired reference() on this table",
881
882
  "link-only": "this table is nothing but link columns"
882
- }, et = (e) => {
883
+ }, tt = (e) => {
883
884
  if (e.tablesChecked === 0) return null;
884
885
  if (e.issues.length === 0) return `junction FKs: ${e.tablesChecked} table${e.tablesChecked === 1 ? "" : "s"} checked — every link column is a wired reference()`;
885
886
  let t = e.issues.length, n = [`junction FKs: ${t} junction table${t === 1 ? "" : "s"} with an id column that is a plain text() and not a reference()`];
886
887
  for (let t of e.issues) {
887
888
  let e = t.columns.map((e) => `'${e}'`).join(", ");
888
- n.push(` '${t.table}': ${e} (${$e[t.signal]})`);
889
+ n.push(` '${t.table}': ${e} (${et[t.signal]})`);
889
890
  }
890
891
  return n.push(" Declare each as reference(() => <table>): the FK is enforced, the column is auto-indexed,"), n.push(" and the relationship becomes walkable (a plain text() id column is an invisible edge)."), n.join("\n");
891
- }, tt = /* @__PURE__ */ new Set(/* @__PURE__ */ "position.positions.move.moved.moving.cursor.pointer.mouse.drag.dragging.hover.frame.frames.tick.ticks.ping.heartbeat.typing.scroll.scrolling.zoom.pan.coord.coords.coordinate.coordinates.telemetry.sensor.sample.samples.viewport".split(".")), nt = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[^A-Za-z0-9]+/).filter((e) => e.length > 0).map((e) => e.toLowerCase()), rt = (e) => nt(e).some((e) => tt.has(e)), it = (e) => {
892
+ }, nt = /* @__PURE__ */ new Set(/* @__PURE__ */ "position.positions.move.moved.moving.cursor.pointer.mouse.drag.dragging.hover.frame.frames.tick.ticks.ping.heartbeat.typing.scroll.scrolling.zoom.pan.coord.coords.coordinate.coordinates.telemetry.sensor.sample.samples.viewport".split(".")), rt = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[^A-Za-z0-9]+/).filter((e) => e.length > 0).map((e) => e.toLowerCase()), it = (e) => rt(e).some((e) => nt.has(e)), at = (e) => {
892
893
  let t = [], n = [];
893
894
  for (let r of e) t.push({
894
895
  event: r.name,
@@ -897,7 +898,7 @@ var ce = () => {
897
898
  event: r.name,
898
899
  kind: "wide-key",
899
900
  keyFieldCount: r.keyFieldCount
900
- }), r.hasWebhook && rt(r.name) && n.push({
901
+ }), r.hasWebhook && it(r.name) && n.push({
901
902
  event: r.name,
902
903
  kind: "webhook-high-rate"
903
904
  });
@@ -906,26 +907,26 @@ var ce = () => {
906
907
  modes: t,
907
908
  warnings: n
908
909
  };
909
- }, at = (e) => {
910
+ }, ot = (e) => {
910
911
  if (e.eventsChecked === 0) return null;
911
912
  let t = e.eventsChecked, n = [`event delivery: ${t} declared event${t === 1 ? "" : "s"} — the mode decides what a MISSING message means`];
912
913
  for (let t of e.modes) n.push(` '${t.event}': ${t.delivery}`);
913
914
  return n.push(" each — every delivery matters; a slow subscriber loses the oldest and is TOLD how many (the default)."), n.push(" latest — a newer delivery supersedes a pending one; a slow subscriber gets the current value, told nothing."), n.push(" Two events with identical route/subscriber/buffer numbers mean OPPOSITE things about a drop — the mode is the difference."), n.join("\n");
914
- }, ot = (e) => {
915
+ }, st = (e) => {
915
916
  if (e.warnings.length === 0) return null;
916
917
  let t = e.warnings.length, n = [`events that may not scale as declared: ${t} finding${t === 1 ? "" : "s"}`];
917
918
  for (let t of e.warnings) t.kind === "wide-key" ? (n.push(` '${t.event}': routing key has ${t.keyFieldCount ?? 0} fields — every field FRAGMENTS the subscriber set (distinct routes are the PRODUCT of the fields’ value spaces).`), n.push(" Check each is an ADDRESS the delivery is decided by (arenaId), not a discriminator the handler reads (gameType) — the latter is payload, not key.")) : (n.push(` '${t.event}': a webhook block on a per-frame-looking event — every publish is N HTTP deliveries per second per subscribed target.`), n.push(" The webhook rate limit DEFERS the excess as pending rows rather than failing, so the symptom is a growing table. Publish a coarser event (a summary / state change) for the outside world."));
918
919
  return n.push(" WARNING, not a fault — a producer may intend the fan-out. `voltro doctor --json` prints every finding."), n.join("\n");
919
- }, st = /* @__PURE__ */ new Set([
920
+ }, ct = /* @__PURE__ */ new Set([
920
921
  "start",
921
922
  "run",
922
923
  "child"
923
- ]), ct = (e) => k.isCallExpression(e) && (() => {
924
+ ]), lt = (e) => k.isCallExpression(e) && (() => {
924
925
  let t = e.getExpression();
925
- if (!k.isPropertyAccessExpression(t) || !st.has(t.getName())) return !1;
926
+ if (!k.isPropertyAccessExpression(t) || !ct.has(t.getName())) return !1;
926
927
  let n = t.getExpression();
927
928
  return k.isPropertyAccessExpression(n) ? n.getName() === "workflows" : k.isIdentifier(n) && n.getText() === "workflows";
928
- })(), lt = (e, t, n) => {
929
+ })(), ut = (e, t, n) => {
929
930
  let r = new Map(t.map((e) => [e.name, e])), i = [...r.keys()].sort(), a = [], o = [], s = 0, c = 0, l = new A({
930
931
  useInMemoryFileSystem: !0,
931
932
  skipAddingFilesFromTsConfig: !0
@@ -941,7 +942,7 @@ var ce = () => {
941
942
  }
942
943
  let u = S(n, t);
943
944
  for (let t of e.getDescendantsOfKind(j.CallExpression)) {
944
- if (!ct(t)) continue;
945
+ if (!lt(t)) continue;
945
946
  c++;
946
947
  let e = t.getStartLineNumber(), [n, l] = t.getArguments();
947
948
  if (n === void 0 || !k.isStringLiteral(n)) {
@@ -1025,7 +1026,7 @@ var ce = () => {
1025
1026
  checked: s,
1026
1027
  callSites: c
1027
1028
  };
1028
- }, ut = (e) => {
1029
+ }, dt = (e) => {
1029
1030
  if (e.callSites === 0) return null;
1030
1031
  let t = [];
1031
1032
  t.push(`workflow starts: ${e.checked}/${e.callSites} call sites checked`);
@@ -1038,7 +1039,7 @@ var ce = () => {
1038
1039
  for (let n of e.unchecked) t.push(` ${n.file}:${n.line} — ${n.reason}`);
1039
1040
  }
1040
1041
  return e.issues.length === 0 && e.unchecked.length === 0 && t.push(" every call site matches its workflow"), t.join("\n");
1041
- }, dt = /(^|[/\\])(\.env(\.[\w.-]+)?|.*\.ya?ml|Dockerfile|.*\.tf|.*\.toml|Procfile)$/i, U = "VOLTRO_FIELD_ENCRYPTION_KEY", ft = (e) => {
1042
+ }, ft = /(^|[/\\])(\.env(\.[\w.-]+)?|.*\.ya?ml|Dockerfile|.*\.tf|.*\.toml|Procfile)$/i, U = "VOLTRO_FIELD_ENCRYPTION_KEY", pt = (e) => {
1042
1043
  let t;
1043
1044
  for (let [n, r] of e.sources) if (t === void 0 && /\bfieldEncryption\b/.test(r) && (t = {
1044
1045
  reason: "fieldEncryption",
@@ -1051,7 +1052,7 @@ var ce = () => {
1051
1052
  for (let [, t] of e.envFiles) if (t.includes(U)) return;
1052
1053
  return t;
1053
1054
  }
1054
- }, pt = (e) => [
1055
+ }, mt = (e) => [
1055
1056
  `✗ ${U} is named nowhere under this app root, and the app encrypts columns at rest`,
1056
1057
  e.reason === "fieldEncryption" ? ` (\`fieldEncryption\` in ${e.file})` : ` (an \`.encrypted()\` column in ${e.file})`,
1057
1058
  "",
@@ -1068,14 +1069,14 @@ var ce = () => {
1068
1069
  " reaches your deploy target is not knowable from here — a secret manager",
1069
1070
  " or a CI variable is not a file. Naming it nowhere is conclusive; naming",
1070
1071
  " it somewhere is not a guarantee."
1071
- ].join("\n"), mt = (e) => {
1072
+ ].join("\n"), ht = (e) => {
1072
1073
  if (e.catalogCodes.length === 0) return;
1073
1074
  let t = new Set(e.declaredLocales), n = e.catalogCodes.filter((e) => !t.has(e)).sort();
1074
1075
  if (n.length !== 0) return {
1075
1076
  orphaned: n,
1076
1077
  noneDeclared: t.size === 0
1077
1078
  };
1078
- }, ht = (e, t) => {
1079
+ }, gt = (e, t) => {
1079
1080
  let n = e.orphaned.join(", ");
1080
1081
  return e.noneDeclared ? [
1081
1082
  `⚠ ${t} has ${e.orphaned.length} catalog(s) — ${n} — and the app declares no \`locales:\`.`,
@@ -1087,33 +1088,33 @@ var ce = () => {
1087
1088
  " …or delete the files. A catalog that is never loaded looks from the inside",
1088
1089
  " exactly like one that works, which is why this is worth a line."
1089
1090
  ] : [`⚠ ${t} has catalog(s) not in \`locales:\` — ${n} — so they are never imported.`, " Add the code(s) to `locales:` in your app config, or delete the file(s)."];
1090
- }, gt = (e) => e.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/[^\n]*/g, "$1"), _t = /* @__PURE__ */ new Set([
1091
+ }, _t = (e) => e.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/[^\n]*/g, "$1"), vt = /* @__PURE__ */ new Set([
1091
1092
  "requireScope",
1092
1093
  "requireAnyScope",
1093
1094
  "requireAuth",
1094
1095
  "assertScope",
1095
1096
  "assertCan",
1096
1097
  "can"
1097
- ]), vt = (e) => {
1098
+ ]), yt = (e) => {
1098
1099
  let t = /* @__PURE__ */ new Set();
1099
- for (let n of e) for (let e of gt(n).matchAll(/\bexport\s+(?:const|function|async\s+function)\s+((?:require|assert)[A-Z]\w*)/g)) t.add(e[1]);
1100
+ for (let n of e) for (let e of _t(n).matchAll(/\bexport\s+(?:const|function|async\s+function)\s+((?:require|assert)[A-Z]\w*)/g)) t.add(e[1]);
1100
1101
  return t;
1101
- }, yt = (e, t) => {
1102
+ }, bt = (e, t) => {
1102
1103
  for (let n of t) if (RegExp(`\\b${n}\\s*\\(`).test(e)) return n;
1103
- }, bt = (e) => {
1104
+ }, xt = (e) => {
1104
1105
  let t = /\bsubject\s*\.\s*id\b[^\n]*?(?:!==|===|!=|==)|(?:!==|===|!=|==)[^\n]*?\bsubject\s*\.\s*id\b/.test(e), n = /(?:Error|Denied|Forbidden|Unauthorized)\b|\b(?:fail|die|throw)\b/.test(e);
1105
1106
  return t && n;
1106
- }, xt = (e, t, n) => {
1107
+ }, St = (e, t, n) => {
1107
1108
  if (e.hasDeclaredGuards) return { kind: "declared-guard" };
1108
- let r = gt(e.src), i = yt(r, t);
1109
- return i === void 0 ? bt(r) ? { kind: "inline-ownership" } : n.has(e.tag) ? { kind: "allowlisted" } : { kind: "unchecked" } : {
1109
+ let r = _t(e.src), i = bt(r, t);
1110
+ return i === void 0 ? xt(r) ? { kind: "inline-ownership" } : n.has(e.tag) ? { kind: "allowlisted" } : { kind: "unchecked" } : {
1110
1111
  kind: "vocabulary-guard",
1111
1112
  name: i
1112
1113
  };
1113
- }, St = (e, t, n) => {
1114
+ }, Ct = (e, t, n) => {
1114
1115
  let r = e.op === "delete" ? 3 : e.op === "update" ? 2 : 1;
1115
1116
  return e.table !== void 0 && (t.has(e.table) && (r += 2), n.has(e.table) && e.op === "delete" && (r += 2)), r;
1116
- }, Ct = (e, t, n) => {
1117
+ }, wt = (e, t, n) => {
1117
1118
  switch (t.kind) {
1118
1119
  case "declared-guard": return "guards: on the descriptor";
1119
1120
  case "vocabulary-guard": return `calls ${t.name}()`;
@@ -1121,15 +1122,15 @@ var ce = () => {
1121
1122
  case "allowlisted": return "accepted by a previous run";
1122
1123
  case "unchecked": return n ? e.op === "read" ? "no check in this file — this app registers a row filter; VERIFY it covers this table, then record it as reviewed= rather than debt" : `${e.op}s${e.table ? ` ${e.table}` : ""} with no check in this file — this app registers a row filter; VERIFY it covers this table, then record it as reviewed= rather than debt` : e.op === "read" ? "returns a row the client selected, with nothing compared to the caller" : `${e.op}s${e.table ? ` ${e.table}` : ""} with nothing constraining WHICH row`;
1123
1124
  }
1124
- }, wt = (e) => {
1125
+ }, Tt = (e) => {
1125
1126
  let t = e.executors.map((t) => {
1126
- let n = xt(t, e.guardVocabulary, e.allowlist);
1127
+ let n = St(t, e.guardVocabulary, e.allowlist);
1127
1128
  return {
1128
1129
  tag: t.tag,
1129
1130
  path: t.path,
1130
1131
  verdict: n,
1131
- severity: St(t, e.tenantScopedTables, e.referencedTables),
1132
- why: Ct(t, n, e.rowFilterRegistered === !0)
1132
+ severity: Ct(t, e.tenantScopedTables, e.referencedTables),
1133
+ why: wt(t, n, e.rowFilterRegistered === !0)
1133
1134
  };
1134
1135
  }), n = (e) => t.filter((t) => t.verdict.kind === e).length;
1135
1136
  return {
@@ -1143,7 +1144,7 @@ var ce = () => {
1143
1144
  },
1144
1145
  unchecked: t.filter((e) => e.verdict.kind === "unchecked").sort((e, t) => t.severity - e.severity || e.tag.localeCompare(t.tag))
1145
1146
  };
1146
- }, Tt = [
1147
+ }, Et = [
1147
1148
  "# voltro doctor — authz allowlist",
1148
1149
  "#",
1149
1150
  "# Two KINDS of line, and the difference is the point:",
@@ -1168,18 +1169,18 @@ var ce = () => {
1168
1169
  "# `--write-authz-allowlist` PRESERVES reviewed= lines. It only ever adds debt",
1169
1170
  "# lines for executors that are newly unchecked.",
1170
1171
  ""
1171
- ], Et = (e) => {
1172
+ ], Dt = (e) => {
1172
1173
  let t = [...e].map((e) => typeof e == "string" ? { tag: e } : e), n = t.filter((e) => e.reviewed === void 0).map((e) => e.tag).sort(), r = t.filter((e) => e.reviewed !== void 0).sort((e, t) => e.tag.localeCompare(t.tag));
1173
1174
  return [
1174
- ...Tt,
1175
+ ...Et,
1175
1176
  ...n,
1176
1177
  ...r.length > 0 ? ["", "# reviewed — read by a human, open on purpose"] : [],
1177
1178
  ...r.map((e) => `${e.tag} reviewed=${e.reviewed}`),
1178
1179
  ""
1179
1180
  ].join("\n");
1180
- }, Dt = (e, t) => {
1181
+ }, Ot = (e, t) => {
1181
1182
  let n = [...new Set(t)].sort();
1182
- if (e === void 0) return Et(n.map((e) => ({ tag: e })));
1183
+ if (e === void 0) return Dt(n.map((e) => ({ tag: e })));
1183
1184
  let r = W(e).tags, i = n.filter((e) => !r.has(e));
1184
1185
  return i.length === 0 ? e : [
1185
1186
  e.replace(/\n+$/, ""),
@@ -1189,7 +1190,7 @@ var ce = () => {
1189
1190
  ...i,
1190
1191
  ""
1191
1192
  ].join("\n");
1192
- }, Ot = (e, t) => {
1193
+ }, kt = (e, t) => {
1193
1194
  let n = [...new Set(t)];
1194
1195
  if (e === void 0) return {
1195
1196
  added: n.length,
@@ -1202,7 +1203,7 @@ var ce = () => {
1202
1203
  kept: r.size,
1203
1204
  removed: 0
1204
1205
  };
1205
- }, kt = class extends Error {
1206
+ }, At = class extends Error {
1206
1207
  tag;
1207
1208
  constructor(e) {
1208
1209
  super(`authz allowlist: '${e}' is marked reviewed with no reason. Write \`${e} reviewed=<why it is genuinely open>\`. A bare tag is the other, honest option — it records the executor as DEBT, which is what an unexplained exemption is.`), this.tag = e, this.name = "AllowlistReasonMissingError";
@@ -1220,7 +1221,7 @@ var ce = () => {
1220
1221
  continue;
1221
1222
  }
1222
1223
  let a = r[2].trim();
1223
- if (a.length === 0) throw new kt(i);
1224
+ if (a.length === 0) throw new At(i);
1224
1225
  t.push({
1225
1226
  tag: i,
1226
1227
  reviewed: a
@@ -1230,13 +1231,13 @@ var ce = () => {
1230
1231
  tags: new Set(t.map((e) => e.tag)),
1231
1232
  entries: t
1232
1233
  };
1233
- }, At = (e) => {
1234
+ }, jt = (e) => {
1234
1235
  let t = e.indexOf(".");
1235
1236
  return t <= 0 ? void 0 : e.slice(0, t);
1236
- }, jt = (e, t) => {
1237
+ }, Mt = (e, t) => {
1237
1238
  let n = new Set(t.tables), r = new Set(t.rpcTags), i = /* @__PURE__ */ new Map();
1238
1239
  for (let e of t.rpcTags) {
1239
- let t = At(e);
1240
+ let t = jt(e);
1240
1241
  if (t === void 0) continue;
1241
1242
  let n = i.get(t);
1242
1243
  n ? n.push(e) : i.set(t, [e]);
@@ -1265,7 +1266,7 @@ var ce = () => {
1265
1266
  });
1266
1267
  continue;
1267
1268
  }
1268
- let s = new Set(o.rpcTags.map(At).filter((e) => e !== void 0));
1269
+ let s = new Set(o.rpcTags.map(jt).filter((e) => e !== void 0));
1269
1270
  for (let e of s) {
1270
1271
  let t = i.get(e);
1271
1272
  t !== void 0 && a.push({
@@ -1278,12 +1279,12 @@ var ce = () => {
1278
1279
  }
1279
1280
  }
1280
1281
  return a;
1281
- }, Mt = (e, t) => {
1282
+ }, Nt = (e, t) => {
1282
1283
  let n = e.reduce((e, t) => e + t.tables.length, 0), r = [`plugin surface · ${e.length} plugin(s) contribute ${n} table(s)`];
1283
1284
  if (t.length === 0) return r.push(" ✓ no overlap with your own tables or rpc namespaces"), r;
1284
1285
  for (let e of t) r.push(` ${e.fatal ? "✗" : "⚠"} ${e.plugin} — ${e.detail}`), r.push(` ${e.fix}`);
1285
1286
  return r;
1286
- }, Nt = (e) => T(C(e, "app.config.ts")) || T(C(e, "app.config.js")), Pt = (e) => {
1287
+ }, Pt = (e) => T(C(e, "app.config.ts")) || T(C(e, "app.config.js")), Ft = (e) => {
1287
1288
  let t = re(e), n = ne(e);
1288
1289
  return {
1289
1290
  root: e,
@@ -1292,19 +1293,19 @@ var ce = () => {
1292
1293
  apiBundle: n,
1293
1294
  apiBundlePresent: T(n)
1294
1295
  };
1295
- }, Ft = [
1296
+ }, It = [
1296
1297
  "Production `voltro serve` requires a precompiled serve bundle and never transpiles on demand.",
1297
1298
  "Add a `voltro build .` step BEFORE `voltro serve .` in your Dockerfile / start script.",
1298
1299
  "(Generated Dockerfiles from `voltro create-project` already do this.)"
1299
- ].join("\n "), It = (e, t = !1) => {
1300
- let n = Pt(e);
1301
- if (console.log(`voltro doctor — serve preflight for ${n.root}`), !Nt(e)) return console.log("• no app.config found here — nothing to check (run against an app root)."), 0;
1300
+ ].join("\n "), Lt = (e, t = !1) => {
1301
+ let n = Ft(e);
1302
+ if (console.log(`voltro doctor — serve preflight for ${n.root}`), !Pt(e)) return console.log("• no app.config found here — nothing to check (run against an app root)."), 0;
1302
1303
  console.log(`${n.serveBundlePresent ? "✓" : "✗"} serve bundle: ${n.serveBundlePresent ? "present" : "MISSING"} (${n.serveBundle})`), console.log(`${n.apiBundlePresent ? "✓" : "•"} api bundle: ${n.apiBundlePresent ? "present" : "absent"} (${n.apiBundle})`);
1303
1304
  let r = process.env.NODE_ENV === "production";
1304
1305
  if (n.serveBundlePresent) return console.log("✓ serve preflight: ready for `voltro serve`."), 0;
1305
1306
  let i = t || r;
1306
- return console.error(`${i ? "✗" : "•"} serve bundle missing — ${i ? "production `voltro serve` will FAIL." : "a non-production `voltro serve` still runs via tsx."}`), console.error(` ${Ft}`), +!!i;
1307
- }, Lt = (e, t, n) => {
1307
+ return console.error(`${i ? "✗" : "•"} serve bundle missing — ${i ? "production `voltro serve` will FAIL." : "a non-production `voltro serve` still runs via tsx."}`), console.error(` ${It}`), +!!i;
1308
+ }, Rt = (e, t, n) => {
1308
1309
  let r = new Set(e), i = I(n), a = (e) => (/\.(tsx?|jsx?)$/.test(e) ? [e] : [
1309
1310
  `${e}.ts`,
1310
1311
  `${e}.tsx`,
@@ -1324,13 +1325,13 @@ var ce = () => {
1324
1325
  }
1325
1326
  let o = [];
1326
1327
  for (let t of r) {
1327
- let n = t.startsWith(".") ? C(b(e), t) : ye(t, i);
1328
+ let n = t.startsWith(".") ? C(b(e), t) : be(t, i);
1328
1329
  if (n === void 0) continue;
1329
1330
  let r = a(n);
1330
1331
  r !== void 0 && o.push(r);
1331
1332
  }
1332
1333
  return o;
1333
- }, s = /* @__PURE__ */ new Set(), c = e.filter((e) => Ut.test(S(n, e))), l = new Set(c);
1334
+ }, s = /* @__PURE__ */ new Set(), c = e.filter((e) => Wt.test(S(n, e))), l = new Set(c);
1334
1335
  for (; c.length > 0;) {
1335
1336
  let e = c.shift();
1336
1337
  if (!s.has(e)) {
@@ -1343,11 +1344,11 @@ var ce = () => {
1343
1344
  let d = /* @__PURE__ */ new Set();
1344
1345
  for (let e of s) l.has(e) || u.has(e) || d.add(e);
1345
1346
  return d;
1346
- }, Rt = (e) => e.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/(^|[^:])\/\/[^\n]*/g, "$1").replace(/'(?:[^'\\\n]|\\.)*'/g, "''").replace(/"(?:[^"\\\n]|\\.)*"/g, "\"\""), zt = (e, t) => (e.match(t) ?? []).length, G = (e, t) => e.getDescendantsOfKind(j.CallExpression).filter((e) => t.test(e.getExpression().getText())).length, Bt = (e, t) => {
1347
+ }, zt = (e) => e.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/(^|[^:])\/\/[^\n]*/g, "$1").replace(/'(?:[^'\\\n]|\\.)*'/g, "''").replace(/"(?:[^"\\\n]|\\.)*"/g, "\"\""), Bt = (e, t) => (e.match(t) ?? []).length, G = (e, t) => e.getDescendantsOfKind(j.CallExpression).filter((e) => t.test(e.getExpression().getText())).length, Vt = (e, t) => {
1347
1348
  if (e.src.includes(t)) return !0;
1348
1349
  let n = t.replace(/^@voltro\/plugin-/, "");
1349
1350
  return n !== t && G(e.file, RegExp(`^${n}Plugin$`)) > 0;
1350
- }, Vt = (e, t) => {
1351
+ }, Ht = (e, t) => {
1351
1352
  let n = [], r = RegExp(`\\b${t}\\s*(?:<[^()]*>)?\\s*\\(`, "g"), i;
1352
1353
  for (; (i = r.exec(e)) !== null;) {
1353
1354
  let t = i.index + i[0].length, r = 1, a = t;
@@ -1355,10 +1356,10 @@ var ce = () => {
1355
1356
  n.push(e.slice(t, a - 1));
1356
1357
  }
1357
1358
  return n;
1358
- }, Ht = (e, t) => {
1359
+ }, Ut = (e, t) => {
1359
1360
  let n = t.getSymbol()?.getDeclarations()?.[0];
1360
1361
  return n === void 0 ? [] : e.getDescendantsOfKind(j.Identifier).filter((e) => e.getSymbol()?.getDeclarations()?.[0] === n);
1361
- }, Ut = /\.(server|cron|workflow\.server|subscribe|reaction|outbox|startup|trigger|webhook|migration|seed)\.tsx?$/, Wt = /\.(query|mutation|action|stream)\.server\.tsx?$/, Gt = [
1362
+ }, Wt = /\.(server|cron|workflow\.server|subscribe|reaction|outbox|startup|trigger|webhook|migration|seed)\.tsx?$/, Gt = /\.(query|mutation|action|stream)\.server\.tsx?$/, Kt = [
1362
1363
  "Id",
1363
1364
  "ID",
1364
1365
  "Hash",
@@ -1384,7 +1385,7 @@ var ce = () => {
1384
1385
  "Comment",
1385
1386
  "Provider",
1386
1387
  "Format"
1387
- ], Kt = RegExp(`(?:${Gt.join("|")})$|_(?:${Gt.map((e) => e.toLowerCase()).join("|")})$`), qt = [
1388
+ ], qt = RegExp(`(?:${Kt.join("|")})$|_(?:${Kt.map((e) => e.toLowerCase()).join("|")})$`), Jt = [
1388
1389
  {
1389
1390
  id: "hardcoded-framework-cookie",
1390
1391
  scope: "client",
@@ -1397,7 +1398,7 @@ var ce = () => {
1397
1398
  scope: "server",
1398
1399
  smell: "an executor that never names its own descriptor — its input type is hand-written, so it can drift from the contract it implements",
1399
1400
  use: "import the descriptor and type the input as `ExecutorInput<typeof descriptor>`, so the wire contract and the handler cannot disagree",
1400
- match: ({ src: e, path: t }) => Wt.test(t) && !/\bimport\s[^;]*\bfrom\s*['"][^'"]*['"]/.test((e.match(/^\s*import\s[^;]*from\s*['"]\.[^'"]*['"]/gm) ?? []).join("\n"))
1401
+ match: ({ src: e, path: t }) => Gt.test(t) && !/\bimport\s[^;]*\bfrom\s*['"][^'"]*['"]/.test((e.match(/^\s*import\s[^;]*from\s*['"]\.[^'"]*['"]/gm) ?? []).join("\n"))
1401
1402
  },
1402
1403
  {
1403
1404
  id: "subject-write-no-guard",
@@ -1405,8 +1406,8 @@ var ce = () => {
1405
1406
  smell: "writes ctx.request.subject.id into the database with no guard on the descriptor — an anonymous caller reaches the write and gets a raw statement failure instead of a typed refusal",
1406
1407
  use: "add a guard (e.g. `.guard(requireScope('…'))`) or an explicit auth check, so an unauthenticated caller is refused BEFORE the write",
1407
1408
  match: ({ src: e, path: t }) => {
1408
- if (!Wt.test(t)) return !1;
1409
- let n = Rt(e);
1409
+ if (!Gt.test(t)) return !1;
1410
+ let n = zt(e);
1410
1411
  return /\bsubject\s*\.\s*id\b/.test(n) && /\b(?:insert|update|upsert|insertMany|updateMany|insertRow|upsertRow|updateManyRow)\s*\(/.test(n) && !/\b(?:guard|guards|requireScope|requireAnyScope|assertCan|assertScope|requireAuth|Unauthenticated)\b/.test(n);
1411
1412
  }
1412
1413
  },
@@ -1415,7 +1416,7 @@ var ce = () => {
1415
1416
  scope: "server",
1416
1417
  smell: "raw fetch() for outbound HTTP on the server (no traceparent, no retry, and no SSRF guard where the URL is not a constant)",
1417
1418
  use: "yield* HttpClient — the framework client. It injects traceparent, retries, and honours `http.allowHosts`. Where the URL is built from anything a caller supplied it ALSO blocks loopback / RFC-1918 / link-local targets (incl. 169.254.169.254) on the initial request AND every redirect hop — for a hard-coded host that half is redundant, and the first three are still the reason to switch",
1418
- match: ({ file: e, path: t, serverOnly: n }) => (Ut.test(t) || n) && G(e, /^(?:globalThis\.|window\.|self\.)?fetch$/) > 0
1419
+ match: ({ file: e, path: t, serverOnly: n }) => (Wt.test(t) || n) && G(e, /^(?:globalThis\.|window\.|self\.)?fetch$/) > 0
1419
1420
  },
1420
1421
  {
1421
1422
  id: "form",
@@ -1450,7 +1451,7 @@ var ce = () => {
1450
1451
  scope: "client",
1451
1452
  smell: "useMemo fanning in multiple subscriptions (hand-maintained dep array)",
1452
1453
  use: "useDerived — dependency-tracked, referentially stable",
1453
- match: ({ src: e }) => zt(e, /\buseSubscription\s*[(<]/g) >= 3 && zt(e, /\buseMemo\s*\(/g) >= 3
1454
+ match: ({ src: e }) => Bt(e, /\buseSubscription\s*[(<]/g) >= 3 && Bt(e, /\buseMemo\s*\(/g) >= 3
1454
1455
  },
1455
1456
  {
1456
1457
  id: "next-shim",
@@ -1475,7 +1476,7 @@ var ce = () => {
1475
1476
  match: ({ file: e }) => e.getDescendantsOfKind(j.CallExpression).filter((e) => /(^|\.)useSubscription$/.test(e.getExpression().getText())).flatMap((e) => {
1476
1477
  let t = e.getFirstAncestorByKind(j.VariableDeclaration)?.getNameNode();
1477
1478
  return t === void 0 ? [] : k.isObjectBindingPattern(t) ? t.getElements().filter((e) => (e.getPropertyNameNode() ?? e.getNameNode()).getText() === "data").map((e) => e.getNameNode()) : [];
1478
- }).some((t) => Ht(e, t).some((e) => {
1479
+ }).some((t) => Ut(e, t).some((e) => {
1479
1480
  let t = e.getParent();
1480
1481
  if (k.isBinaryExpression(t)) {
1481
1482
  let n = t.getOperatorToken().getText(), r = t.getLeft() === e ? t.getRight() : t.getLeft();
@@ -1526,7 +1527,7 @@ var ce = () => {
1526
1527
  use: ".encrypted() on the column — boot fails loudly if no cipher is configured, so it can never silently persist plaintext (a *Hash column and a vault* handle are NOT plaintext secrets: the hash IS the protection — often a unique lookup key — and the handle only names a secret held elsewhere, so both are skipped)",
1527
1528
  match: ({ src: e }) => e.split("\n").some((e) => [...e.matchAll(/\b([A-Za-z_$][\w$]*)\s*:\s*(?:text|varchar|string|longtext)\s*\(/g)].some((t) => {
1528
1529
  let n = t[1];
1529
- return !/token|secret|credential|password|apikey|accesskey/i.test(n) || Kt.test(n) || /^vault/i.test(n) || /\.unique\s*\(/.test(e) ? !1 : !/\.encrypted\s*\(/.test(e);
1530
+ return !/token|secret|credential|password|apikey|accesskey/i.test(n) || qt.test(n) || /^vault/i.test(n) || /\.unique\s*\(/.test(e) ? !1 : !/\.encrypted\s*\(/.test(e);
1530
1531
  }))
1531
1532
  },
1532
1533
  {
@@ -1536,7 +1537,7 @@ var ce = () => {
1536
1537
  use: "you cannot look a value up by equality AND encrypt it non-deterministically — `.encrypted()` would make this column unfindable. Store the HASH as the unique lookup key and keep the secret itself either `.encrypted()` in a second column or nowhere (the framework's own `_voltro_api_keys.hashedKey` is the shape: the presented value is hashed and compared, never read back). A deterministic cipher is the other option and buys equality lookup at the cost of leaking which rows share a value",
1537
1538
  match: ({ src: e }) => e.split("\n").some((e) => [...e.matchAll(/\b([A-Za-z_$][\w$]*)\s*:\s*(?:text|varchar|string|longtext)\s*\(/g)].some((t) => {
1538
1539
  let n = t[1];
1539
- return !/token|secret|credential|password|apikey|accesskey/i.test(n) || Kt.test(n) || /^vault/i.test(n) ? !1 : /\.unique\s*\(/.test(e) && !/\.encrypted\s*\(/.test(e);
1540
+ return !/token|secret|credential|password|apikey|accesskey/i.test(n) || qt.test(n) || /^vault/i.test(n) ? !1 : /\.unique\s*\(/.test(e) && !/\.encrypted\s*\(/.test(e);
1540
1541
  }))
1541
1542
  },
1542
1543
  {
@@ -1601,8 +1602,8 @@ var ce = () => {
1601
1602
  smell: "setRowFilter is registered, but no test passes `rowFilter:` to makeTestContext",
1602
1603
  use: "wire the filter into at least one test (`makeTestContext({ subject, store, rowFilter })`) and sabotage the predicate once to watch it go red — an untested row filter is a visibility rule nothing verifies",
1603
1604
  match: ({ file: e, testSources: t }) => G(e, /^setRowFilter$/) > 0 && ![...t.values()].some((e) => {
1604
- let t = Rt(e);
1605
- return Vt(t, "makeTestContext").length > 0 && /\browFilter\b/.test(t);
1605
+ let t = zt(e);
1606
+ return Ht(t, "makeTestContext").length > 0 && /\browFilter\b/.test(t);
1606
1607
  })
1607
1608
  },
1608
1609
  {
@@ -1612,14 +1613,14 @@ var ce = () => {
1612
1613
  use: "timestampMs / timestampMsOrNull from @voltro/database/wire in the descriptor's output struct — `output` IS the serializer (it is the rpc success schema), so a Date field declared as timestampMs crosses as epoch ms on its own; declaring Schema.Number describes the WIRE type and leaves nothing to convert",
1613
1614
  match: ({ src: e }) => /\.(getTime|toISOString)\s*\(\s*\)/.test(e) && /\.map\s*\(|=>\s*\(\{/.test(e) && /\bexport\s+default\b/.test(e)
1614
1615
  }
1615
- ], Jt = (e) => q(e), Yt = (e, t) => {
1616
+ ], Yt = (e) => q(e), Xt = (e, t) => {
1616
1617
  let n = /* @__PURE__ */ new Set();
1617
1618
  for (let r of t) {
1618
1619
  let t = S(e, r), i = t.split(/[\\/]/)[0];
1619
1620
  n.add(i !== void 0 && i !== t ? i : ".");
1620
1621
  }
1621
1622
  return [...n].sort();
1622
- }, Xt = /\.(tsx?|jsx?)$/, K = /(^|\/)(node_modules|dist|build|\.framework|\.next|coverage)(\/|$)/, Zt = /(^|[\\/])[^\\/]*\.generated\.[cm]?[jt]sx?$|\.d\.[cm]?ts$/, Qt = (e, t = [], n = 0) => {
1623
+ }, Zt = /\.(tsx?|jsx?)$/, K = /(^|\/)(node_modules|dist|build|\.framework|\.next|coverage)(\/|$)/, Qt = /(^|[\\/])[^\\/]*\.generated\.[cm]?[jt]sx?$|\.d\.[cm]?ts$/, $t = (e, t = [], n = 0) => {
1623
1624
  if (n > 12 || K.test(e)) return t;
1624
1625
  let r;
1625
1626
  try {
@@ -1631,8 +1632,8 @@ var ce = () => {
1631
1632
  let r = x(e, i.name);
1632
1633
  if (i.isDirectory()) {
1633
1634
  if (i.name.startsWith(".")) continue;
1634
- Qt(r, t, n + 1);
1635
- } else dt.test(i.name) && t.push(r);
1635
+ $t(r, t, n + 1);
1636
+ } else ft.test(i.name) && t.push(r);
1636
1637
  }
1637
1638
  return t;
1638
1639
  }, q = (e, t = [], n = 0) => {
@@ -1650,10 +1651,10 @@ var ce = () => {
1650
1651
  } catch {
1651
1652
  continue;
1652
1653
  }
1653
- a.isDirectory() ? q(r, t, n + 1) : Xt.test(i) && !/\.(test|spec)\./.test(i) && !Zt.test(i) && t.push(r);
1654
+ a.isDirectory() ? q(r, t, n + 1) : Zt.test(i) && !/\.(test|spec)\./.test(i) && !Qt.test(i) && t.push(r);
1654
1655
  }
1655
1656
  return t;
1656
- }, $t = (e, t = [], n = 0) => {
1657
+ }, en = (e, t = [], n = 0) => {
1657
1658
  if (n > 12 || K.test(e)) return t;
1658
1659
  let r;
1659
1660
  try {
@@ -1668,17 +1669,17 @@ var ce = () => {
1668
1669
  } catch {
1669
1670
  continue;
1670
1671
  }
1671
- a.isDirectory() ? $t(r, t, n + 1) : Xt.test(i) && /\.(test|spec)\./.test(i) && t.push(r);
1672
+ a.isDirectory() ? en(r, t, n + 1) : Zt.test(i) && /\.(test|spec)\./.test(i) && t.push(r);
1672
1673
  }
1673
1674
  return t;
1674
- }, en = (e) => {
1675
- let t = Jt(e);
1675
+ }, tn = (e) => {
1676
+ let t = Yt(e);
1676
1677
  return {
1677
- dirs: Yt(e, t),
1678
+ dirs: Xt(e, t),
1678
1679
  fileCount: t.length
1679
1680
  };
1680
- }, tn = (e) => {
1681
- let t = Jt(e);
1681
+ }, nn = (e) => {
1682
+ let t = Yt(e);
1682
1683
  if (t.length === 0) return [];
1683
1684
  let n = new A({
1684
1685
  useInMemoryFileSystem: !0,
@@ -1687,8 +1688,8 @@ var ce = () => {
1687
1688
  for (let e of t) try {
1688
1689
  i.set(e, E(e, "utf8"));
1689
1690
  } catch {}
1690
- let a = Lt([...i.keys()], i, e), o = /* @__PURE__ */ new Map();
1691
- for (let t of $t(e)) try {
1691
+ let a = Rt([...i.keys()], i, e), o = /* @__PURE__ */ new Map();
1692
+ for (let t of en(e)) try {
1692
1693
  o.set(t, E(t, "utf8"));
1693
1694
  } catch {}
1694
1695
  for (let s of t) {
@@ -1706,23 +1707,23 @@ var ce = () => {
1706
1707
  } catch {
1707
1708
  continue;
1708
1709
  }
1709
- for (let t of qt) {
1710
- if (t.plugin !== void 0 && Bt(c, t.plugin) || !t.match(c)) continue;
1710
+ for (let t of Jt) {
1711
+ if (t.plugin !== void 0 && Vt(c, t.plugin) || !t.match(c)) continue;
1711
1712
  let n = r.get(t.id) ?? [];
1712
1713
  n.push(S(e, s)), r.set(t.id, n);
1713
1714
  }
1714
1715
  }
1715
- return qt.filter((e) => r.has(e.id)).map((e) => ({
1716
+ return Jt.filter((e) => r.has(e.id)).map((e) => ({
1716
1717
  rule: e,
1717
1718
  files: r.get(e.id)
1718
1719
  })).sort((e, t) => t.files.length - e.files.length || e.rule.id.localeCompare(t.rule.id));
1719
- }, nn = (e) => {
1720
- let t = en(e);
1720
+ }, rn = (e) => {
1721
+ let t = tn(e);
1721
1722
  return {
1722
1723
  root: e,
1723
1724
  scannedFiles: t.fileCount,
1724
1725
  scannedDirs: t.dirs,
1725
- findings: tn(e).map(({ rule: e, files: t }) => ({
1726
+ findings: nn(e).map(({ rule: e, files: t }) => ({
1726
1727
  id: e.id,
1727
1728
  scope: e.scope,
1728
1729
  smell: e.smell,
@@ -1730,22 +1731,22 @@ var ce = () => {
1730
1731
  files: t
1731
1732
  }))
1732
1733
  };
1733
- }, rn = 3, an = .2, on = 50, sn = (e, t) => e >= on && t > 0 && e / t >= an, cn = (e) => {
1734
+ }, an = 3, on = .2, sn = 50, cn = (e, t) => e >= sn && t > 0 && e / t >= on, ln = (e) => {
1734
1735
  let t = /* @__PURE__ */ new Map();
1735
1736
  for (let n of q(e)) try {
1736
1737
  t.set(S(e, n), E(n, "utf8"));
1737
1738
  } catch {}
1738
1739
  let n = /* @__PURE__ */ new Map();
1739
- for (let t of Qt(e)) try {
1740
+ for (let t of $t(e)) try {
1740
1741
  n.set(S(e, t), E(t, "utf8"));
1741
1742
  } catch {}
1742
- let r = ft({
1743
+ let r = pt({
1743
1744
  sources: t,
1744
1745
  envFiles: n
1745
1746
  });
1746
- r !== void 0 && (console.log(""), console.log(pt(r)));
1747
- }, ln = (e) => {
1748
- let t = nn(e);
1747
+ r !== void 0 && (console.log(""), console.log(mt(r)));
1748
+ }, un = (e) => {
1749
+ let t = rn(e);
1749
1750
  if (console.log(""), t.scannedFiles === 0) return console.log(`\u2022 hand-roll scan: no source directories found under ${e}.`), console.log(" Walked the app root recursively (node_modules / dist / .framework pruned). Run `voltro doctor <app>` against an app root."), 0;
1750
1751
  if (t.findings.length === 0) return console.log(`\u2713 hand-roll scan: ${t.scannedFiles} file${t.scannedFiles === 1 ? "" : "s"} across ${t.scannedDirs.join(", ")} \u2014 no hand-rolled primitives found.`), 0;
1751
1752
  console.log(`\u2022 Shipped primitives you may be hand-rolling (scanned ${t.scannedFiles} files across ${t.scannedDirs.join(", ")}):`);
@@ -1756,24 +1757,24 @@ var ce = () => {
1756
1757
  console.log(` [${e}]`);
1757
1758
  let i = [...r].sort((e, t) => e.files.length - t.files.length);
1758
1759
  for (let e of i) {
1759
- if (sn(e.files.length, t.scannedFiles)) {
1760
+ if (cn(e.files.length, t.scannedFiles)) {
1760
1761
  let n = Math.round(e.files.length / t.scannedFiles * 100);
1761
1762
  console.log(` ${e.smell} \u2014 ${e.files.length} file(s), ${n}% of those scanned: a codebase-wide pattern rather than a work list`), console.log(` \u2192 ${e.use}`), console.log(" (paths omitted on purpose at this scale — `voltro doctor --json` has every one.)");
1762
1763
  continue;
1763
1764
  }
1764
- let r = e.files.slice(0, rn).join(", "), i = e.files.length - rn;
1765
+ let r = e.files.slice(0, an).join(", "), i = e.files.length - an;
1765
1766
  i > 0 && (n += i);
1766
1767
  let a = i > 0 ? `, +${i} more` : "";
1767
1768
  console.log(` ${e.smell} \u2014 ${e.files.length} file(s): ${r}${a}`), console.log(` \u2192 ${e.use}`);
1768
1769
  }
1769
1770
  }
1770
1771
  return n > 0 && console.log(` (${n} more file path${n === 1 ? "" : "s"} not shown \u2014 \`voltro doctor --json\` prints every one.)`), console.log(" (See the \"Pick the SERVER primitive\" / \"Pick the CLIENT primitive\" rubrics in AGENTS.md / CLAUDE.md.)"), t.findings.length;
1771
- }, un = "renderMode:'spa' skips this page's SSR compile while its layout shell still renders server-side — adopt it if the page BODY does not need SSR (internal/authenticated pages); keep 'ssr' if the page content needs SEO or server first-paint.", dn = /export\s+const\s+renderMode\s*(?::[^=]+)?=\s*['"]([^'"]*)['"]/, fn = /export\s+const\s+dynamic\s*=\s*['"]force-(dynamic|static)['"]/, pn = (e) => {
1772
- let t = dn.exec(e)?.[1];
1772
+ }, dn = "renderMode:'spa' skips this page's SSR compile while its layout shell still renders server-side — adopt it if the page BODY does not need SSR (internal/authenticated pages); keep 'ssr' if the page content needs SEO or server first-paint.", fn = /export\s+const\s+renderMode\s*(?::[^=]+)?=\s*['"]([^'"]*)['"]/, pn = /export\s+const\s+dynamic\s*=\s*['"]force-(dynamic|static)['"]/, mn = (e) => {
1773
+ let t = fn.exec(e)?.[1];
1773
1774
  if (t !== void 0) return t === "ssr" ? "ssr" : null;
1774
- let n = fn.exec(e)?.[1];
1775
+ let n = pn.exec(e)?.[1];
1775
1776
  return n === "dynamic" ? "ssr" : n === "static" ? null : "default";
1776
- }, mn = async (e) => {
1777
+ }, hn = async (e) => {
1777
1778
  let t = x(e, "src", "pages");
1778
1779
  if (!T(t)) return [];
1779
1780
  let { pages: i, dirs: o } = await n(t), s = [];
@@ -1786,7 +1787,7 @@ var ce = () => {
1786
1787
  continue;
1787
1788
  }
1788
1789
  if (r.test(i)) continue;
1789
- let c = pn(i);
1790
+ let c = mn(i);
1790
1791
  c !== null && s.push({
1791
1792
  file: S(e, x(t, n.file)),
1792
1793
  pattern: n.pattern,
@@ -1794,18 +1795,18 @@ var ce = () => {
1794
1795
  });
1795
1796
  }
1796
1797
  return s;
1797
- }, hn = 10, gn = async (e) => {
1798
+ }, gn = 10, _n = async (e) => {
1798
1799
  if (console.log(""), !T(x(e, "src", "pages"))) return console.log("• spa-candidate scan: no src/pages here — nothing to check (web apps only)."), 0;
1799
- let t = await mn(e);
1800
+ let t = await hn(e);
1800
1801
  if (t.length === 0) return console.log("✓ spa-candidate scan: no loader-free, layout-backed pages to flag."), 0;
1801
1802
  console.log(`• renderMode:'spa' candidates (${t.length} page${t.length === 1 ? "" : "s"} — loader-free, under a layout, currently ssr/default):`);
1802
- for (let e of t.slice(0, hn)) {
1803
+ for (let e of t.slice(0, gn)) {
1803
1804
  let t = e.currentMode === "ssr" ? "renderMode:'ssr'" : "default renderMode";
1804
1805
  console.log(` ${e.file} (${e.pattern}) — ${t}`);
1805
1806
  }
1806
- let n = t.length - hn;
1807
- return n > 0 && console.log(` (+${n} more page${n === 1 ? "" : "s"} not shown — \`voltro doctor --json\` prints every one.)`), console.log(` → ${un}`), t.length;
1808
- }, _n = /* @__PURE__ */ new Set([
1807
+ let n = t.length - gn;
1808
+ return n > 0 && console.log(` (+${n} more page${n === 1 ? "" : "s"} not shown — \`voltro doctor --json\` prints every one.)`), console.log(` → ${dn}`), t.length;
1809
+ }, vn = /* @__PURE__ */ new Set([
1809
1810
  "node_modules",
1810
1811
  "dist",
1811
1812
  "build",
@@ -1813,7 +1814,7 @@ var ce = () => {
1813
1814
  ".vite",
1814
1815
  ".framework",
1815
1816
  ".git"
1816
- ]), vn = (e, t, n) => {
1817
+ ]), yn = (e, t, n) => {
1817
1818
  let r;
1818
1819
  try {
1819
1820
  r = D(e, { withFileTypes: !0 });
@@ -1821,11 +1822,11 @@ var ce = () => {
1821
1822
  return;
1822
1823
  }
1823
1824
  for (let i of r) {
1824
- if (_n.has(i.name)) continue;
1825
+ if (vn.has(i.name)) continue;
1825
1826
  let r = x(e, i.name);
1826
- i.isDirectory() ? vn(r, t, n) : i.isFile() && i.name.endsWith(".tsx") && n.push(S(t, r));
1827
+ i.isDirectory() ? yn(r, t, n) : i.isFile() && i.name.endsWith(".tsx") && n.push(S(t, r));
1827
1828
  }
1828
- }, yn = (e, t) => {
1829
+ }, bn = (e, t) => {
1829
1830
  let n = /* @__PURE__ */ new Set(), r = /(?:from|import)\s*\(?\s*['"](\.[^'"]*)['"]/g;
1830
1831
  for (let i of t) {
1831
1832
  let t;
@@ -1850,16 +1851,16 @@ var ce = () => {
1850
1851
  }
1851
1852
  }
1852
1853
  return n;
1853
- }, bn = (e, t) => {
1854
+ }, xn = (e, t) => {
1854
1855
  let n = e.slice(t.length).split(w).slice(0, -1)[0];
1855
1856
  return n !== void 0 && n.startsWith("[");
1856
1857
  }, J = (e) => {
1857
1858
  let t = [], n = x(e, "src", "pages"), r = x(e, "src");
1858
1859
  if (!T(r)) return t;
1859
1860
  let i = [];
1860
- vn(r, e, i), i.sort();
1861
+ yn(r, e, i), i.sort();
1861
1862
  let a = `${S(e, n)}${w}`;
1862
- yn(e, i);
1863
+ bn(e, i);
1863
1864
  for (let n of i) {
1864
1865
  let r = n.slice(n.lastIndexOf(w) + 1);
1865
1866
  if (n.startsWith(a)) {
@@ -1875,7 +1876,7 @@ var ce = () => {
1875
1876
  file: n
1876
1877
  });
1877
1878
  } catch {}
1878
- bn(n, a) && t.push({
1879
+ xn(n, a) && t.push({
1879
1880
  kind: "top-level-dynamic-route",
1880
1881
  file: n
1881
1882
  });
@@ -1887,30 +1888,30 @@ var ce = () => {
1887
1888
  });
1888
1889
  }
1889
1890
  return t;
1890
- }, xn = 10, Y = (e, t, n) => {
1891
+ }, Sn = 10, Y = (e, t, n) => {
1891
1892
  if (t.length === 0) return;
1892
1893
  console.log(`• ${e} (${t.length}):`);
1893
- for (let e of t.slice(0, xn)) console.log(` ${e}`);
1894
- let r = t.length - xn;
1894
+ for (let e of t.slice(0, Sn)) console.log(` ${e}`);
1895
+ let r = t.length - Sn;
1895
1896
  r > 0 && console.log(` (+${r} more not shown — \`voltro doctor --json\` prints every one.)`), console.log(` → ${n}`);
1896
- }, Sn = (e) => {
1897
+ }, Cn = (e) => {
1897
1898
  if (console.log(""), !T(x(e, "src", "pages"))) return console.log("• page-convention scan: no src/pages here — nothing to check (web apps only)."), 0;
1898
1899
  let t = J(e);
1899
1900
  if (t.length === 0) return console.log("✓ page-convention scan: every route is a page.tsx in its own directory, with a test beside it."), 0;
1900
1901
  let n = (e) => t.filter((t) => t.kind === e).map((e) => e.file);
1901
1902
  return Y("will NEVER route — page.tsx outside src/pages/", n("suffixed-outside-pages"), "the name says \"route\", the location says otherwise, and the location wins: the URL comes from the directory chain under src/pages/. Move it into the directory whose route it serves, or rename it."), Y("pages with no test beside them", n("page-without-test"), "a page and its test belong together — `users/[id].page.tsx` → `users/[id].page.test.tsx`. Advisory only; a missing test is a gap, not a defect."), Y("routes whose FIRST segment is dynamic — they claim every URL of that depth", n("top-level-dynamic-route"), "a route like `[id]/[code]` answers `/api/health`, `/internal/readiness` and anything else with that many segments on this origin. That is what the pattern means, so it is not a bug — but it is invisible until something requests such a URL, and then the page renders, its loader runs, and the failure reads as an application error rather than as a route claiming a path nobody meant it to. Give the route a literal first segment (`scan/[id]/[code]`) if you did not intend to own the whole origin at that depth. Advisory."), Y("pages with no `meta` export — they serve the APP name as their title", n("page-without-meta"), "a page with no `meta` sets no title, so the response carries `<title>{your app.config name}</title>` — the same string on every such page, to every reader that does not run JavaScript: link previews, crawlers, a bookmark taken before hydration, a screen reader announcing the document. The client router fixes the tab after hydration, which is exactly why this is easy to miss. Add `export const meta = { title: \"…\" }` (or a function of params/loaderData). If such a page also has no real body — it redirects from an effect, say — the missing title is the symptom rather than the bug: on an `ssr` route the server answers 200 with an empty document and the redirect happens only once JavaScript runs. Move it into the loader (`redirect(...)`, a real 303). Advisory."), t.length;
1902
- }, Cn = "voltro doctor [app] [flags]\n\nPreflight an app root: verify it can boot under production `voltro serve`,\nreport shipped primitives the source looks to be hand-rolling, and flag pages\nthat are safe `renderMode:'spa'` candidates.\n\nArguments:\n [app] App directory to check (default: the current directory).\n\nFlags:\n --strict Treat a missing serve bundle as blocking regardless of NODE_ENV\n (the `voltro serve --preflight` behavior). Without it, a missing\n bundle only fails when NODE_ENV=production.\n --json Print the complete scan as JSON — hand-roll findings AND spa\n candidates, every file path, nothing elided. Skips the preflight output.\n --write-authz-allowlist\n Record today's executors that reference NO access check into\n voltro-authz-allowlist.txt, so every later run fails only on\n ADDITIONS. The list is DEBT, not approval — an entry stops\n mattering as soon as its executor gains a guard.\n -h, --help Print this help.", wn = /* @__PURE__ */ new Map(), X = (e) => {
1903
- let t = wn.get(e);
1903
+ }, wn = "voltro doctor [app] [flags]\n\nPreflight an app root: verify it can boot under production `voltro serve`,\nreport shipped primitives the source looks to be hand-rolling, and flag pages\nthat are safe `renderMode:'spa'` candidates.\n\nArguments:\n [app] App directory to check (default: the current directory).\n\nFlags:\n --strict Treat a missing serve bundle as blocking regardless of NODE_ENV\n (the `voltro serve --preflight` behavior). Without it, a missing\n bundle only fails when NODE_ENV=production.\n --json Print the complete scan as JSON — hand-roll findings AND spa\n candidates, every file path, nothing elided. Skips the preflight output.\n --write-authz-allowlist\n Record today's executors that reference NO access check into\n voltro-authz-allowlist.txt, so every later run fails only on\n ADDITIONS. The list is DEBT, not approval — an entry stops\n mattering as soon as its executor gains a guard.\n -h, --help Print this help.", Tn = /* @__PURE__ */ new Map(), X = (e) => {
1904
+ let t = Tn.get(e);
1904
1905
  if (t !== void 0) return t;
1905
1906
  let n = (async () => {
1906
- let { walk: t, loadDiscovered: n } = await import("./dev-DOZVMVfi.js"), r = await t(e);
1907
+ let { walk: t, loadDiscovered: n } = await import("./dev-iiMtlkfs.js"), r = await t(e);
1907
1908
  return {
1908
1909
  files: r,
1909
1910
  discovered: await n(r)
1910
1911
  };
1911
1912
  })();
1912
- return wn.set(e, n), n;
1913
- }, Tn = async (e) => {
1913
+ return Tn.set(e, n), n;
1914
+ }, En = async (e) => {
1914
1915
  let t;
1915
1916
  try {
1916
1917
  let { files: n, discovered: r } = await X(e), i = r.tables.map((e) => {
@@ -1921,12 +1922,12 @@ var ce = () => {
1921
1922
  };
1922
1923
  });
1923
1924
  if (i.length === 0) return;
1924
- t = qe(Ke(n, i, e));
1925
+ t = Je(qe(n, i, e));
1925
1926
  } catch {
1926
1927
  return;
1927
1928
  }
1928
1929
  t !== null && (console.log(""), console.log(`${t.includes("does not exist") ? "✗" : "✓"} ${t}`));
1929
- }, En = (e) => e.map((e) => {
1930
+ }, Dn = (e) => e.map((e) => {
1930
1931
  let t = e, n = Object.entries(t.fields ?? {}).map(([e, t]) => ({
1931
1932
  name: e,
1932
1933
  type: typeof t?.type == "string" ? t.type : ""
@@ -1939,19 +1940,19 @@ var ce = () => {
1939
1940
  }), Z = async (e) => {
1940
1941
  try {
1941
1942
  let { discovered: t } = await X(e);
1942
- return Qe(En(t.tables));
1943
+ return $e(Dn(t.tables));
1943
1944
  } catch {
1944
1945
  return null;
1945
1946
  }
1946
- }, Dn = async (e) => {
1947
+ }, On = async (e) => {
1947
1948
  let t = await Z(e);
1948
1949
  if (t === null || t.tablesChecked === 0) return;
1949
- let n = et(t);
1950
+ let n = tt(t);
1950
1951
  n !== null && (console.log(""), console.log(`${t.issues.length > 0 ? "✗" : "✓"} ${n}`));
1951
- }, On = async (e) => {
1952
+ }, kn = async (e) => {
1952
1953
  try {
1953
1954
  let { payloadPropertyNames: t } = await import("@voltro/runtime"), { discovered: n } = await X(e);
1954
- return it(n.events.map((e) => {
1955
+ return at(n.events.map((e) => {
1955
1956
  let n = e.descriptor, r = t(n.key);
1956
1957
  return {
1957
1958
  name: n.name,
@@ -1963,17 +1964,17 @@ var ce = () => {
1963
1964
  } catch {
1964
1965
  return null;
1965
1966
  }
1966
- }, kn = async (e) => {
1967
- let t = await On(e);
1967
+ }, An = async (e) => {
1968
+ let t = await kn(e);
1968
1969
  if (t === null || t.eventsChecked === 0) return;
1969
- let n = at(t);
1970
+ let n = ot(t);
1970
1971
  n !== null && (console.log(""), console.log(`• ${n}`));
1971
- let r = ot(t);
1972
+ let r = st(t);
1972
1973
  r !== null && (console.log(""), console.log(`⚠️ ${r}`));
1973
- }, An = (e) => {
1974
+ }, jn = (e) => {
1974
1975
  let t = e, n = typeof t?.message == "string" && t.message !== "" ? t.message : String(e), r = typeof t?.code == "string" ? t.code : void 0;
1975
1976
  return r === void 0 ? n : `${r}: ${n}`;
1976
- }, jn = async (e) => {
1977
+ }, Mn = async (e) => {
1977
1978
  try {
1978
1979
  let { formatServerOnlyLeaks: t } = await import("@voltro/runtime"), n = (await X(e)).discovered.serverOnlyLeaks, r = t(n);
1979
1980
  return {
@@ -1986,17 +1987,17 @@ var ce = () => {
1986
1987
  } catch (e) {
1987
1988
  return { status: {
1988
1989
  checked: !1,
1989
- reason: An(e)
1990
+ reason: jn(e)
1990
1991
  } };
1991
1992
  }
1992
- }, Mn = async (e) => {
1993
- let { status: t, message: n } = await jn(e);
1994
- return t.checked ? n === void 0 ? !1 : (console.log(""), console.log(`✗ [serverOnly] ${n}`), !0) : (console.log(""), console.log("• serverOnly: NOT CHECKED — the app's descriptors could not be loaded (not a pass)"), console.log(` reason: ${t.reason ?? "unknown"}`), console.log(" This audit is the automated check that a hash or a token cannot reach the wire, so"), console.log(" an app that leans on `.serverOnly()` should treat a persistent skip as a failure."), console.log(" `voltro doctor --json` reports it as `serverOnly.checked: false` for a CI gate."), !1);
1995
1993
  }, Nn = async (e) => {
1994
+ let { status: t, message: n } = await Mn(e);
1995
+ return t.checked ? n === void 0 ? !1 : (console.log(""), console.log(`✗ [serverOnly] ${n}`), !0) : (console.log(""), console.log("• serverOnly: NOT CHECKED — the app's descriptors could not be loaded (not a pass)"), console.log(` reason: ${t.reason ?? "unknown"}`), console.log(" This audit is the automated check that a hash or a token cannot reach the wire, so"), console.log(" an app that leans on `.serverOnly()` should treat a persistent skip as a failure."), console.log(" `voltro doctor --json` reports it as `serverOnly.checked: false` for a CI gate."), !1);
1996
+ }, Pn = async (e) => {
1996
1997
  let t;
1997
1998
  try {
1998
1999
  let { payloadPropertyNames: n } = await import("@voltro/runtime"), { files: r, discovered: i } = await X(e);
1999
- t = lt(r, i.workflows.map((e) => {
2000
+ t = ut(r, i.workflows.map((e) => {
2000
2001
  let t = e.definition, r = t.payloadSchema === void 0 ? {
2001
2002
  required: [],
2002
2003
  optional: []
@@ -2010,59 +2011,98 @@ var ce = () => {
2010
2011
  } catch {
2011
2012
  return;
2012
2013
  }
2013
- let n = ut(t);
2014
+ let n = dt(t);
2014
2015
  if (n === null) return;
2015
2016
  console.log("");
2016
2017
  let r = t.issues.length > 0 ? "✗" : t.unchecked.length > 0 ? "•" : "✓";
2017
2018
  console.log(`${r} ${n}`);
2018
- }, Q = "voltro-authz-allowlist.txt", Pn = (e, t = (e) => {
2019
+ }, Q = "voltro-authz-allowlist.txt", Fn = (e, t = (e) => {
2019
2020
  try {
2020
2021
  return E(e, "utf8");
2021
2022
  } catch {
2022
2023
  return "";
2023
2024
  }
2024
- }) => /* @__PURE__ */ new Set([..._t, ...vt(q(e).map(t))]), Fn = async (e) => {
2025
+ }) => /* @__PURE__ */ new Set([...vt, ...yt(q(e).map(t))]), In = (e, t) => {
2026
+ let n = t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2027
+ return new RegExp(String.raw`(?:export\s+)?const\s+([A-Za-z_$][\w$]*)\s*=\s*define[A-Za-z]*Event\s*\(\s*\{[^}]*?name\s*:\s*['"\`]${n}['"\`]`, "s").exec(e)?.[1];
2028
+ }, Ln = async (e) => {
2025
2029
  try {
2026
- let { discovered: t } = await X(e), n = t.events.map((e) => e.descriptor.name).filter((e) => typeof e == "string");
2030
+ let { discovered: t } = await X(e), n = t.events.map((e) => ({
2031
+ name: e.descriptor.name,
2032
+ file: e.file
2033
+ })).filter((e) => typeof e.name == "string");
2027
2034
  if (n.length === 0) return [];
2028
- let r = new Set(t.events.map((e) => e.file)), i = q(e).filter((e) => !r.has(e)).map((e) => {
2035
+ let r = new Set(t.events.map((e) => e.file)), i = (e) => {
2029
2036
  try {
2030
2037
  return E(e, "utf8");
2031
2038
  } catch {
2032
2039
  return "";
2033
2040
  }
2034
- }).join("\n");
2035
- return n.filter((e) => !i.includes(e)).sort();
2041
+ }, a = q(e).filter((e) => !r.has(e)).map(i).join("\n");
2042
+ return n.filter(({ name: e, file: t }) => {
2043
+ if (a.includes(e)) return !1;
2044
+ let n = In(i(t), e);
2045
+ return n === void 0 || !new RegExp(String.raw`\b${n}\b`).test(a);
2046
+ }).map((e) => e.name).sort();
2036
2047
  } catch {
2037
2048
  return [];
2038
2049
  }
2039
- }, In = async (e) => {
2040
- let t = await Fn(e);
2050
+ }, Rn = async (e) => {
2051
+ let t = await Ln(e);
2041
2052
  if (t.length !== 0) {
2042
2053
  console.log(""), console.log(`• ${t.length} declared event(s) with no emit call site found:`);
2043
2054
  for (let e of t) console.log(` ${e}`);
2044
- console.log(""), console.log(" An event you declare is an event partners can subscribe to. One that"), console.log(" never fires is indistinguishable, from their side, from a broken"), console.log(" endpoint of their own — so they debug your contract instead of"), console.log(" reading it."), console.log(" ADVISORY: this looks for the event NAME in your sources. An emit"), console.log(" through a variable or an assembled name will read as missing here.");
2055
+ console.log(""), console.log(" An event you declare is an event partners can subscribe to. One that"), console.log(" never fires is indistinguishable, from their side, from a broken"), console.log(" endpoint of their own — so they debug your contract instead of"), console.log(" reading it."), console.log(" ADVISORY: this looks for the event name AND the identifier its"), console.log(" declaration binds it to, so `emit(ctx, apiKeyCreated, …)` counts. An"), console.log(" emit through an ASSEMBLED name still reads as missing here.");
2045
2056
  }
2046
- }, Ln = async (e) => {
2057
+ }, zn = async (e) => {
2047
2058
  try {
2048
- let { offlineManifest: t, toInput: n } = await import("./checkCommand-ClRvH_SN.js"), { buildAppGraph: r, checkAppGraph: i } = await import("./appGraph-CvQCte0z.js"), a = await t(e);
2049
- return i(r(n(a.manifest, a.tables))).filter((e) => e.rule === "rbac/unknown-scope").map((e) => ({
2050
- node: e.node,
2051
- ...e.file === void 0 ? {} : { file: e.file },
2052
- detail: e.breaks.join("; "),
2053
- fix: e.fix
2054
- }));
2059
+ let { loadApiConfig: t } = await import("./dev-iiMtlkfs.js"), n = (await t(e))?.doctor?.scopeVocabulary;
2060
+ if (typeof n != "string") return [];
2061
+ let [r, i] = n.split("#");
2062
+ if (r === void 0 || i === void 0) return [];
2063
+ let a = (await import(oe(C(e, r)).href))[i];
2064
+ return Array.isArray(a) ? a.filter((e) => typeof e == "string") : [];
2055
2065
  } catch {
2056
2066
  return [];
2057
2067
  }
2058
- }, Rn = async (e) => {
2059
- let t = await Ln(e);
2068
+ }, Bn = async (e) => {
2069
+ let t = {
2070
+ evaluated: !1,
2071
+ vocabularySize: 0,
2072
+ findings: []
2073
+ };
2074
+ try {
2075
+ let { offlineManifest: n, toInput: r } = await import("./checkCommand-DRovTKza.js"), { buildAppGraph: i, checkAppGraph: a } = await import("./appGraph-CvQCte0z.js"), o = await n(e), s = r(o.manifest, o.tables), c = await zn(e), l = [.../* @__PURE__ */ new Set([...s.scopes ?? [], ...c])];
2076
+ if (l.length === 0) return t;
2077
+ let u = i({
2078
+ ...s,
2079
+ scopes: l
2080
+ });
2081
+ return {
2082
+ evaluated: !0,
2083
+ vocabularySize: l.length,
2084
+ findings: a(u).filter((e) => e.rule === "rbac/unknown-scope").map((e) => ({
2085
+ node: e.node,
2086
+ ...e.file === void 0 ? {} : { file: e.file },
2087
+ detail: e.breaks.join("; "),
2088
+ fix: e.fix
2089
+ }))
2090
+ };
2091
+ } catch {
2092
+ return t;
2093
+ }
2094
+ }, Vn = async (e) => {
2095
+ let { findings: t, evaluated: n } = await Bn(e);
2096
+ if (!n) {
2097
+ console.log(""), console.log("• scope vocabulary: none found — the unknown-scope rule did NOT run."), console.log(" It compares each procedure's required scopes against the scopes your"), console.log(" roles actually grant, and needs somewhere to read that set from."), console.log(" `@voltro/plugin-rbac` publishes it from its `roles` map; an app doing"), console.log(" RBAC without the plugin can point at its own:"), console.log(""), console.log(" // app.config.ts"), console.log(" doctor: { scopeVocabulary: './lib/teamRoles.ts#ALL_TEAM_SCOPES' }"), console.log(""), console.log(" Until then this section is NOT a clean bill of health — a procedure"), console.log(" requiring a scope no role grants is uncallable by everyone, and"), console.log(" nothing here would have told you.");
2098
+ return;
2099
+ }
2060
2100
  if (t.length !== 0) {
2061
2101
  console.log(""), console.log(`• ${t.length} procedure(s) require a scope no declared role grants:`);
2062
2102
  for (let e of t) console.log(` ${e.node}${e.file === void 0 ? "" : ` ${e.file}`}`), console.log(` ${e.detail}`);
2063
2103
  console.log(""), console.log(" Each of these is uncallable by every user in every role — not"), console.log(" misconfigured, DEAD — and nothing fails at boot to say so. The"), console.log(" usual cause is a typo or a rename that moved one side only."), console.log(` ${t[0].fix}`);
2064
2104
  }
2065
- }, zn = async (e) => {
2105
+ }, Hn = async (e) => {
2066
2106
  let t = ["src/locales", "locales"], n, r = [];
2067
2107
  for (let i of t) {
2068
2108
  let t = x(e, i);
@@ -2074,23 +2114,23 @@ var ce = () => {
2074
2114
  if (n === void 0 || r.length === 0) return;
2075
2115
  let i = [];
2076
2116
  try {
2077
- let { loadApiConfig: t } = await import("./dev-DOZVMVfi.js");
2117
+ let { loadApiConfig: t } = await import("./dev-iiMtlkfs.js");
2078
2118
  i = (await t(e))?.locales ?? [];
2079
2119
  } catch {
2080
2120
  return;
2081
2121
  }
2082
- let a = mt({
2122
+ let a = ht({
2083
2123
  catalogCodes: r,
2084
2124
  declaredLocales: i
2085
2125
  });
2086
2126
  if (a !== void 0) {
2087
2127
  console.log("");
2088
- for (let e of ht(a, n)) console.log(e);
2128
+ for (let e of gt(a, n)) console.log(e);
2089
2129
  }
2090
- }, Bn = async (e) => {
2130
+ }, Un = async (e) => {
2091
2131
  let { discovered: t } = await X(e), n = [];
2092
2132
  try {
2093
- let { loadApiConfig: t } = await import("./dev-DOZVMVfi.js");
2133
+ let { loadApiConfig: t } = await import("./dev-iiMtlkfs.js");
2094
2134
  n = ((await t(e))?.plugins ?? []).map((e) => {
2095
2135
  let t = (e.extendSchema?.tables ?? []).map((e) => {
2096
2136
  let t = e;
@@ -2106,8 +2146,8 @@ var ce = () => {
2106
2146
  plugin: e.name,
2107
2147
  tables: t,
2108
2148
  rpcTags: n,
2109
- canDisableTables: Vn.has(e.name),
2110
- canAlias: Hn.has(e.name)
2149
+ canDisableTables: Wn.has(e.name),
2150
+ canAlias: Gn.has(e.name)
2111
2151
  };
2112
2152
  });
2113
2153
  } catch {
@@ -2119,14 +2159,14 @@ var ce = () => {
2119
2159
  ...t.mutations,
2120
2160
  ...t.actions,
2121
2161
  ...t.streams ?? []
2122
- ].map((e) => String(e.descriptor.name)), i = jt(n, {
2162
+ ].map((e) => String(e.descriptor.name)), i = Mt(n, {
2123
2163
  tables: t.tables.map((e) => e.tableName),
2124
2164
  rpcTags: r
2125
2165
  });
2126
2166
  console.log();
2127
- for (let e of Mt(n, i)) console.log(e);
2128
- }, Vn = /* @__PURE__ */ new Set(["@voltro/plugin-rbac"]), Hn = /* @__PURE__ */ new Set(["@voltro/plugin-ai-flows"]), $ = 20, Un = async (e) => {
2129
- let t = await Wn(e), n = new Set(t.reviewed.map((e) => e.tag)), r = t.result.findings.filter((e) => e.verdict.kind === "allowlisted" && !n.has(e.tag)).length;
2167
+ for (let e of Nt(n, i)) console.log(e);
2168
+ }, Wn = /* @__PURE__ */ new Set(["@voltro/plugin-rbac"]), Gn = /* @__PURE__ */ new Set(["@voltro/plugin-ai-flows"]), $ = 20, Kn = async (e) => {
2169
+ let t = await qn(e), n = new Set(t.reviewed.map((e) => e.tag)), r = t.result.findings.filter((e) => e.verdict.kind === "allowlisted" && !n.has(e.tag)).length;
2130
2170
  return {
2131
2171
  executors: t.executorCount,
2132
2172
  guardVocabulary: [...t.vocabulary].sort(),
@@ -2138,7 +2178,7 @@ var ce = () => {
2138
2178
  },
2139
2179
  unchecked: t.result.unchecked
2140
2180
  };
2141
- }, Wn = async (e) => {
2181
+ }, qn = async (e) => {
2142
2182
  let { discovered: t } = await X(e), n = /* @__PURE__ */ new Map(), r = (e) => {
2143
2183
  if (!n.has(e)) try {
2144
2184
  n.set(e, E(e, "utf8"));
@@ -2146,7 +2186,7 @@ var ce = () => {
2146
2186
  n.set(e, "");
2147
2187
  }
2148
2188
  return n.get(e);
2149
- }, i = Pn(e, r), a = /* @__PURE__ */ new Set();
2189
+ }, i = Fn(e, r), a = /* @__PURE__ */ new Set();
2150
2190
  for (let e of t.tables) for (let t of Object.values(e.fields ?? {})) try {
2151
2191
  let e = t.references?.();
2152
2192
  e && a.add(e.tableName);
@@ -2183,7 +2223,7 @@ var ce = () => {
2183
2223
  l = !0;
2184
2224
  break;
2185
2225
  }
2186
- let u = wt({
2226
+ let u = Tt({
2187
2227
  executors: o,
2188
2228
  guardVocabulary: i,
2189
2229
  tenantScopedTables: t.tenantScopedTables,
@@ -2200,49 +2240,49 @@ var ce = () => {
2200
2240
  executorCount: o.length,
2201
2241
  allowPath: s
2202
2242
  };
2203
- }, Gn = async (e, t) => {
2204
- let { result: n, vocabulary: r, existing: i, reviewed: a, executorCount: o, allowPath: s, rowFilterRegistered: c } = await Wn(e), l = n.counts;
2243
+ }, Jn = async (e, t) => {
2244
+ let { result: n, vocabulary: r, existing: i, reviewed: a, executorCount: o, allowPath: s, rowFilterRegistered: c } = await qn(e), l = n.counts;
2205
2245
  console.log(`\nauthz scan · ${o} executor(s)`);
2206
- let u = [...r].filter((e) => !_t.has(e)).sort();
2246
+ let u = [...r].filter((e) => !vt.has(e)).sort();
2207
2247
  console.log(u.length === 0 ? " guard vocabulary: framework names only — no exported require*/assert* found in this app" : ` guard vocabulary: ${u.length} from your source (${u.slice(0, 6).join(", ")}${u.length > 6 ? ", …" : ""})`), console.log(` ✗ no access check ${String(l.unchecked).padStart(4)}`), console.log(` ⚠ inline ownership check, no named guard${String(l.inlineOwnership).padStart(4)} (informational)`), console.log(` ✓ guards: on the descriptor ${String(l.declaredGuard).padStart(4)}`), console.log(` ✓ calls a guard from the vocabulary ${String(l.vocabularyGuard).padStart(4)}`);
2208
2248
  let d = new Set(a.map((e) => e.tag)), f = n.findings.filter((e) => e.verdict.kind === "allowlisted" && !d.has(e.tag)).length, p = l.allowlisted - f;
2209
2249
  if (console.log(` – accepted as recorded debt ${String(f).padStart(4)} (${Q})`), console.log(` ✓ reviewed, open on purpose ${String(p).padStart(4)} (\`reviewed=<why>\` in that file)`), c && console.log(" ⓘ this app registers setRowFilter — the scan CANNOT see through it. A finding below may\n already be constrained; verify the filter covers that table and record it as `reviewed=`."), t) {
2210
- let e = T(s) ? E(s, "utf8") : void 0, t = n.unchecked.map((e) => e.tag), r = Ot(e, t);
2211
- return se(s, Dt(e, t), "utf8"), console.log(`\n${Q}: +${r.added} new, ${r.kept} kept, ${r.removed} removed. Doctor now fails on ADDITIONS only.`), r.added === 0 && console.log(" (nothing new was unchecked — the file is unchanged.)"), !1;
2250
+ let e = T(s) ? E(s, "utf8") : void 0, t = n.unchecked.map((e) => e.tag), r = kt(e, t);
2251
+ return ce(s, Ot(e, t), "utf8"), console.log(`\n${Q}: +${r.added} new, ${r.kept} kept, ${r.removed} removed. Doctor now fails on ADDITIONS only.`), r.added === 0 && console.log(" (nothing new was unchecked — the file is unchanged.)"), !1;
2212
2252
  }
2213
2253
  if (n.unchecked.length === 0) return !1;
2214
2254
  console.log("");
2215
2255
  for (let e of n.unchecked.slice(0, $)) console.log(` ✗ ${e.tag} — ${e.why}\n ${e.path}`);
2216
2256
  return n.unchecked.length > $ && console.log(` … and ${n.unchecked.length - $} more — \`voltro doctor --json\` prints every one (\`authz.unchecked\`).`), i === void 0 ? (console.log(`\nNo ${Q} yet, so this run is advisory. To start the ratchet:`), console.log("\n voltro doctor --write-authz-allowlist\n"), console.log("That records today's unchecked handlers as DEBT and fails every run after on"), console.log("anything NEW. Fix a handler and its line stops mattering — the scan reports it as"), console.log("guarded whether or not the line is still there."), !1) : (console.log(`\n${n.unchecked.length} executor(s) with no access check are not in ${Q}.`), console.log("Add a guard, or add the tag to that file if it is genuinely open."), console.log("\nBefore hand-rolling another check: `guards: [{ action, resourceType, resource }]`"), console.log("answers \"may this subject act on THIS row\" declaratively, and an app whose"), console.log("relationships live in its own tables registers its own tuple source rather than"), console.log("copying data into a framework table. See the authorization docs."), !0);
2217
- }, Kn = async (e) => {
2218
- if (e.includes("--help") || e.includes("-h")) return console.log(Cn), 0;
2257
+ }, Yn = async (e) => {
2258
+ if (e.includes("--help") || e.includes("-h")) return console.log(wn), 0;
2219
2259
  let n = e.includes("--strict"), r = C(e.find((e) => !e.startsWith("-")) ?? process.cwd());
2220
- if (le(e)) return ce(), M({
2221
- ...nn(r),
2222
- spaCandidates: await mn(r),
2260
+ if (ue(e)) return le(), M({
2261
+ ...rn(r),
2262
+ spaCandidates: await hn(r),
2223
2263
  pageConvention: J(r),
2224
2264
  fileTaxonomy: V(r).findings,
2225
2265
  junctionFks: (await Z(r))?.issues ?? [],
2226
- eventDelivery: await On(r),
2266
+ eventDelivery: await kn(r),
2227
2267
  duplicateInstances: t(r),
2228
2268
  versionSkew: s(r) ?? null,
2229
- serverOnly: (await jn(r)).status,
2230
- authz: await Un(r),
2231
- ungrantedScopes: await Ln(r),
2232
- neverEmittedEvents: await Fn(r)
2269
+ serverOnly: (await Mn(r)).status,
2270
+ authz: await Kn(r),
2271
+ ungrantedScopes: await Bn(r),
2272
+ neverEmittedEvents: await Ln(r)
2233
2273
  }), 0;
2234
- let a = It(r, n);
2235
- ln(r), cn(r), Sn(r), He(r), await gn(r), await Nn(r), await Tn(r), await Dn(r), await kn(r), await Bn(r), await Rn(r), await In(r), await zn(r);
2236
- let c = await Mn(r), l = await Gn(r, e.includes("--write-authz-allowlist")), u = o(s(r));
2274
+ let a = Lt(r, n);
2275
+ un(r), ln(r), Cn(r), Ue(r), await _n(r), await Pn(r), await En(r), await On(r), await An(r), await Un(r), await Vn(r), await Rn(r), await Hn(r);
2276
+ let c = await Nn(r), l = await Jn(r, e.includes("--write-authz-allowlist")), u = o(s(r));
2237
2277
  u !== void 0 && (console.log(""), console.log(u));
2238
2278
  let d = i(t(r));
2239
2279
  return d !== void 0 && console.log(`\n${d}`), c || l ? Math.max(a, 1) : a;
2240
- }, qn = (e) => e === void 0 ? [] : typeof e == "string" ? [e] : e, Jn = /* @__PURE__ */ new Set([
2280
+ }, Xn = (e) => e === void 0 ? [] : typeof e == "string" ? [e] : e, Zn = /* @__PURE__ */ new Set([
2241
2281
  "insert",
2242
2282
  "update",
2243
2283
  "delete",
2244
2284
  "upsert"
2245
- ]), Yn = (e, t) => {
2285
+ ]), Qn = (e, t) => {
2246
2286
  let n = [], r = new Set(t.exercised), i = /* @__PURE__ */ new Map();
2247
2287
  for (let e of t.edges) {
2248
2288
  let t = i.get(e.tag);
@@ -2254,8 +2294,8 @@ var ce = () => {
2254
2294
  a.push(t.tag);
2255
2295
  continue;
2256
2296
  }
2257
- let e = `${t.kind}(${t.tag})`, s = t.file, c = i.get(t.tag) ?? [], l = new Set(qn(t.source)), u = new Map((t.targets ?? []).map((e) => [e.table, e.op]));
2258
- for (let t of c) if (Jn.has(t.op)) {
2297
+ let e = `${t.kind}(${t.tag})`, s = t.file, c = i.get(t.tag) ?? [], l = new Set(Xn(t.source)), u = new Map((t.targets ?? []).map((e) => [e.table, e.op]));
2298
+ for (let t of c) if (Zn.has(t.op)) {
2259
2299
  let r = u.get(t.table);
2260
2300
  r === void 0 ? n.push({
2261
2301
  rule: "observed/undeclared-write",
@@ -2311,7 +2351,7 @@ var ce = () => {
2311
2351
  total: e.length
2312
2352
  }
2313
2353
  };
2314
- }, Xn = (e, t = [], n = 0) => {
2354
+ }, $n = (e, t = [], n = 0) => {
2315
2355
  if (n > 12) return t;
2316
2356
  let r;
2317
2357
  try {
@@ -2335,24 +2375,24 @@ var ce = () => {
2335
2375
  } catch {
2336
2376
  continue;
2337
2377
  }
2338
- a.isDirectory() ? Xn(r, t, n + 1) : a.isFile() && l.test(i) && t.push(r);
2378
+ a.isDirectory() ? $n(r, t, n + 1) : a.isFile() && u.test(i) && t.push(r);
2339
2379
  }
2340
2380
  return t;
2341
- }, Zn = /* @__PURE__ */ new Set(["actors", "tenants"]), Qn = async (e) => {
2381
+ }, er = /* @__PURE__ */ new Set(["actors", "tenants"]), tr = async (e) => {
2342
2382
  try {
2343
2383
  let { readFile: t } = await import("node:fs/promises"), { join: n } = await import("node:path"), r = await t(n(e, "app.graph.observed.generated.json"), "utf8"), i = JSON.parse(r);
2344
2384
  return i?.version !== 1 || !Array.isArray(i.edges) || !Array.isArray(i.exercised) ? null : i;
2345
2385
  } catch {
2346
2386
  return null;
2347
2387
  }
2348
- }, $n = (e) => {
2388
+ }, nr = (e) => {
2349
2389
  let { exercised: t, total: n } = e.coverage, r = `\nobserved: ${t}/${n} procedures exercised (${n === 0 ? 0 : Math.round(t / n * 100)}%)`;
2350
2390
  if (e.diagnostics.length === 0) return `${r}\n no declared/observed mismatches${e.unexercised.length > 0 ? `\n ${e.unexercised.length} unexercised — no recording, so nothing is claimed about them` : ""}`;
2351
2391
  let i = e.diagnostics.map((e) => ` ${e.node}${e.file === void 0 ? "" : ` (${e.file})`}\n` + e.breaks.map((e) => ` ${e}`).join("\n") + `\n fix: ${e.fix}`), a = e.unexercised.length > 0 ? `\n ${e.unexercised.length} unexercised — no recording, so nothing is claimed about them` : "";
2352
2392
  return `${r}\n${i.join("\n")}${a}`;
2353
- }, er = (e, t) => ({
2393
+ }, rr = (e, t) => ({
2354
2394
  tables: (t.tables ?? []).map((e) => e.name),
2355
- frameworkOwnedTables: (t.tables ?? []).filter((e) => e.framework === !0 || e.name.startsWith("_voltro_") || Zn.has(e.name)).map((e) => e.name),
2395
+ frameworkOwnedTables: (t.tables ?? []).filter((e) => e.framework === !0 || e.name.startsWith("_voltro_") || er.has(e.name)).map((e) => e.name),
2356
2396
  scopes: e.scopes ?? [],
2357
2397
  procedures: (e.procedures ?? []).map((e) => {
2358
2398
  let t = (e.guards ?? []).flatMap((e) => e.kind === "scope" ? e.scope ?? [] : []);
@@ -2365,11 +2405,11 @@ var ce = () => {
2365
2405
  ...e.guards === void 0 ? {} : { hasGuards: e.guards.length > 0 }
2366
2406
  };
2367
2407
  })
2368
- }), tr = (e) => e.length === 0 ? "✓ voltro check: no issues" : e.map((e) => {
2408
+ }), ir = (e) => e.length === 0 ? "✓ voltro check: no issues" : e.map((e) => {
2369
2409
  let t = e.severity === "error" ? "✗ error" : "⚠ warn", n = e.file ? ` (${e.file})` : "";
2370
2410
  return `${t} ${e.rule} ${e.node}${n}\n ${e.breaks.join("; ")}\n fix: ${e.fix}`;
2371
- }).join("\n"), nr = async (e) => {
2372
- let { walk: t, loadDiscovered: n, loadApiConfig: r } = await import("./dev-DOZVMVfi.js"), { buildRpcEntry: i } = await import("./manifestBuild-Dj8Jjoto.js"), { buildCapabilityManifest: a } = await import("./inspect-mmBuRXmy.js"), { relative: o } = await import("node:path"), s = await n(await t(e)), c = (t, n, r) => i(t, n, o(e, r)), l = [
2411
+ }).join("\n"), ar = async (e) => {
2412
+ let { walk: t, loadDiscovered: n, loadApiConfig: r } = await import("./dev-iiMtlkfs.js"), { buildRpcEntry: i } = await import("./manifestBuild-Dj8Jjoto.js"), { buildCapabilityManifest: a } = await import("./inspect-mmBuRXmy.js"), { relative: o } = await import("node:path"), s = await n(await t(e)), c = (t, n, r) => i(t, n, o(e, r)), l = [
2373
2413
  ...s.queries.map((e) => c(e.descriptor, "query", e.file)),
2374
2414
  ...s.mutations.map((e) => c(e.descriptor, "mutation", e.file)),
2375
2415
  ...s.actions.map((e) => c(e.descriptor, "action", e.file)),
@@ -2385,10 +2425,10 @@ var ce = () => {
2385
2425
  })), [], m),
2386
2426
  tables: { tables: p }
2387
2427
  };
2388
- }, rr = async (e) => {
2389
- let t = me(e.flatMap((e) => e === "--json" ? ["--format", "json"] : [e]));
2428
+ }, or = async (e) => {
2429
+ let t = he(e.flatMap((e) => e === "--json" ? ["--format", "json"] : [e]));
2390
2430
  if ("error" in t) return console.error(`voltro check: ${t.error}`), 1;
2391
- let { process: n, target: r, rest: i } = he(t.rest), a;
2431
+ let { process: n, target: r, rest: i } = ge(t.rest), a;
2392
2432
  for (let e = 0; e < i.length; e++) if (i[e] === "--diff") {
2393
2433
  let [t, n] = (i[++e] ?? "").split(":");
2394
2434
  if (t === "removeTable" && n) a = {
@@ -2405,21 +2445,21 @@ var ce = () => {
2405
2445
  };
2406
2446
  else return console.error("voltro check --diff: expected removeTable:<name> | removeProcedure:<tag> | removeScope:<name>"), 1;
2407
2447
  }
2408
- let o = i.find((e) => !e.startsWith("-")) ?? process.cwd(), s = i.includes("--offline"), c = s ? [] : await pe(n, r), l, d;
2448
+ let o = i.find((e) => !e.startsWith("-")) ?? process.cwd(), s = i.includes("--offline"), c = s ? [] : await me(n, r), u, d;
2409
2449
  if (c.length === 0) {
2410
2450
  if (!s && r !== void 0) return console.error("voltro check: --url given but no api reachable there."), 1;
2411
2451
  try {
2412
- let e = await nr(C(o));
2413
- l = e.manifest, d = e.tables;
2452
+ let e = await ar(C(o));
2453
+ u = e.manifest, d = e.tables;
2414
2454
  } catch (e) {
2415
2455
  return console.error(`voltro check: could not assemble the graph from source: ${e.message}`), console.error(" Start `voltro dev` to check against a running api instead."), 1;
2416
2456
  }
2417
2457
  } else {
2418
2458
  let e = c[0], [t, n] = await Promise.all([N(e, "/_voltro/inspect/manifest"), N(e, "/_voltro/inspect/data/tables")]);
2419
2459
  if (t.kind === "err") return console.error(`voltro check: manifest fetch failed: ${t.error}`), 1;
2420
- l = t.data, d = n.kind === "ok" ? n.data : { tables: [] };
2460
+ u = t.data, d = n.kind === "ok" ? n.data : { tables: [] };
2421
2461
  }
2422
- let f = er(l, d), p = ie(f, a), m = [...V(o).findings.map((e) => ({
2462
+ let f = rr(u, d), p = ie(f, a), m = [...V(o).findings.map((e) => ({
2423
2463
  rule: e.rule,
2424
2464
  node: e.file,
2425
2465
  file: e.file,
@@ -2433,7 +2473,7 @@ var ce = () => {
2433
2473
  breaks: [e.kind === "suffixed-outside-pages" ? "a page.tsx outside src/pages/ never routes" : "no test beside it"],
2434
2474
  fix: e.kind === "suffixed-outside-pages" ? "move it under src/pages/ into the directory whose route it serves, or rename it — page.tsx is reserved" : "write the test with the file — the name is derivable",
2435
2475
  severity: e.kind === "suffixed-outside-pages" ? "error" : "warn"
2436
- }))], h = (await u(o, Xn(o))).map((e) => ({
2476
+ }))], h = (await l(o, $n(o))).map((e) => ({
2437
2477
  rule: "client/not-browser-safe",
2438
2478
  node: e.file,
2439
2479
  file: e.file,
@@ -2444,7 +2484,7 @@ var ce = () => {
2444
2484
  ...p.diagnostics,
2445
2485
  ...m,
2446
2486
  ...h
2447
- ], _ = p.ok && !m.some((e) => e.severity === "error") && h.length === 0, v = await Qn(C(o)), y = v === null ? null : Yn(f.procedures, v);
2487
+ ], _ = p.ok && !m.some((e) => e.severity === "error") && h.length === 0, v = await tr(C(o)), y = v === null ? null : Qn(f.procedures, v);
2448
2488
  return t.format === "json" ? M(y === null ? {
2449
2489
  ...p,
2450
2490
  ok: _,
@@ -2454,7 +2494,7 @@ var ce = () => {
2454
2494
  ok: _,
2455
2495
  diagnostics: g,
2456
2496
  observed: y
2457
- }) : (console.log(tr(g)), y !== null && console.log($n(y)), console.log(_ ? "\nvoltro check: OK" : "\nvoltro check: FAILED (errors above)")), +!_;
2497
+ }) : (console.log(ir(g)), y !== null && console.log(nr(y)), console.log(_ ? "\nvoltro check: OK" : "\nvoltro check: FAILED (errors above)")), +!_;
2458
2498
  };
2459
2499
  //#endregion
2460
- export { ce as _, It as a, xe as c, N as d, me as f, pe as g, fe as h, Kn as i, I as l, P as m, rr as n, ze as o, he as p, er as r, be as s, nr as t, ve as u, M as v, le as y };
2500
+ export { le as _, Lt as a, Se as c, N as d, he as f, me as g, pe as h, Yn as i, I as l, P as m, or as n, Be as o, ge as p, rr as r, xe as s, ar as t, ye as u, M as v, ue as y };