@voltro/cli 0.57.0 → 0.58.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 (109) hide show
  1. package/CHANGELOG.md +201 -0
  2. package/dist/apiBuild-CDE4NXNi.js +2 -0
  3. package/dist/{apiBuild-DDr2aNFd.js → apiBuild-CkpsCqIu.js} +2 -2
  4. package/dist/bin.js +1 -1
  5. package/dist/build-51qBWfYY.js +981 -0
  6. package/dist/{checkCommand-BISqx1OJ.js → checkCommand-C1EbNmwl.js} +1 -1
  7. package/dist/{checkCommand-DUtMWjcR.js → checkCommand-C30J2F18.js} +3 -3
  8. package/dist/{codegenCommand-DnVuDxwT.js → codegenCommand-kS3Twuc9.js} +7 -7
  9. package/dist/{codemodRunner-BlQPfjzA.js → codemodRunner-BKjCwGiN.js} +1127 -895
  10. package/dist/{commands-CRbxgxv0.js → commands-DowWkYtd.js} +21 -21
  11. package/dist/{dashboardCommand-Bf_-Ne3P.js → dashboardCommand-gG1y4PFG.js} +5 -5
  12. package/dist/{dataCommand-BoBJJ-Gb.js → dataCommand-hNOGKz4K.js} +6 -6
  13. package/dist/{dev-DOEJXicj.js → dev-Ce2gEziv.js} +2422 -2419
  14. package/dist/dev-Dff_pdik.js +3 -0
  15. package/dist/{doctorCommand-BrWu67JZ.js → doctorCommand-5ULMpL10.js} +505 -284
  16. package/dist/doctorCommand-B8H2MYCE.js +2 -0
  17. package/dist/{dormancyCommand-xn2y-pJm.js → dormancyCommand-DYgI0Kf-.js} +3 -3
  18. package/dist/{embeddingsCommand-Cn5MbRDM.js → embeddingsCommand-yJivQSrI.js} +2 -2
  19. package/dist/{envCommand-UJmJIbs9.js → envCommand-ORJUf8r_.js} +8 -8
  20. package/dist/{evolveCommand-Db30twUy.js → evolveCommand-DTawtTxf.js} +2 -2
  21. package/dist/index.js +1 -1
  22. package/dist/{infoCommand-BjVXpMlP.js → infoCommand-BFksHunl.js} +1 -1
  23. package/dist/inspect-CZvsmp8t.js +2 -0
  24. package/dist/{inspect-DZnan87F.js → inspect-PcC5J-Dl.js} +6 -7
  25. package/dist/manifestBuild-AUh31bFU.js +2 -0
  26. package/dist/{manifestBuild-DnbFKF6w.js → manifestBuild-BwiS4iYm.js} +1 -1
  27. package/dist/{probeCommand-C5fuN6Z2.js → probeCommand-BUYzc0CT.js} +1 -1
  28. package/dist/{runtimeTrace-BQL_lfz6.js → runtimeTrace-BUk5zMXY.js} +1 -1
  29. package/dist/{sdkgen-CMUPrDjH.js → sdkgen-CAhmmbjx.js} +1 -1
  30. package/dist/serveCommand-BUXUtSF5.js +2 -0
  31. package/dist/{serveCommand-B_w-Mpb_.js → serveCommand-DhtC7WBq.js} +726 -725
  32. package/dist/serveEntry.js +1 -1
  33. package/dist/{start-s25GAIgn.js → start-C75w6ftA.js} +1 -1
  34. package/dist/{start-YaUehtDV.js → start-DNtIlBcn.js} +641 -609
  35. package/dist/startEntry.js +1 -1
  36. package/dist/{updateCommand-C9n_Z_oG.js → updateCommand-CtuD5r1t.js} +1 -1
  37. package/dist/updateCommand-eVKVHj3N.js +2 -0
  38. package/dist/webDev-Bzb8ZFus.js +2 -0
  39. package/dist/{webDev-BgdkyjP6.js → webDev-CBN9KkyQ.js} +154 -146
  40. package/dist/{webhooksCommand-CYXTNvXq.js → webhooksCommand-BPJQOGTe.js} +1 -1
  41. package/package.json +61 -19
  42. package/templates/AGENTS.md +1 -1
  43. package/templates/agent-docs/_index.md +1 -1
  44. package/templates/agent-docs/_manifest.json +1 -1
  45. package/templates/agent-docs/ai.md +174 -0
  46. package/templates/agent-docs/authentication.md +34 -0
  47. package/templates/agent-docs/data.md +30 -0
  48. package/templates/agent-docs/database/transactions.md +48 -0
  49. package/templates/agent-docs/observability.md +13 -2
  50. package/templates/agent-docs/plugins/auth-supabase.md +21 -0
  51. package/templates/agent-docs/plugins/sentry.md +91 -8
  52. package/templates/agent-docs/schema-driven-ui.md +29 -0
  53. package/templates/agent-docs/whats-new.md +112 -105
  54. package/templates/apps/api-ai/package.json +6 -6
  55. package/templates/apps/api-auth/package.json +8 -8
  56. package/templates/apps/api-backend/package.json +7 -7
  57. package/templates/apps/api-backend-deactivation/package.json +7 -7
  58. package/templates/apps/api-backend-mail/package.json +8 -8
  59. package/templates/apps/api-backend-mariadb/package.json +9 -9
  60. package/templates/apps/api-backend-sqlite/package.json +8 -8
  61. package/templates/apps/api-backend-storage/package.json +8 -8
  62. package/templates/apps/api-cms/package.json +9 -9
  63. package/templates/apps/api-collab/package.json +8 -8
  64. package/templates/apps/api-data-advanced/package.json +8 -8
  65. package/templates/apps/api-durable/package.json +8 -8
  66. package/templates/apps/api-feature-flags/package.json +9 -9
  67. package/templates/apps/api-governance/package.json +8 -8
  68. package/templates/apps/api-kv/package.json +8 -8
  69. package/templates/apps/api-moderation/package.json +8 -8
  70. package/templates/apps/api-observability/package.json +8 -8
  71. package/templates/apps/api-ratelimit/package.json +8 -8
  72. package/templates/apps/api-rbac/package.json +8 -8
  73. package/templates/apps/api-rest/package.json +7 -7
  74. package/templates/apps/api-row-history/package.json +8 -8
  75. package/templates/apps/api-saas/package.json +11 -11
  76. package/templates/apps/api-saas-starter/package.json +10 -10
  77. package/templates/apps/api-search/package.json +8 -8
  78. package/templates/apps/api-status/package.json +8 -8
  79. package/templates/apps/api-webhooks/package.json +9 -9
  80. package/templates/apps/changelog/package.json +7 -7
  81. package/templates/apps/edge-functions/package.json +2 -2
  82. package/templates/apps/frontend-admin/package.json +7 -7
  83. package/templates/apps/frontend-app/package.json +8 -8
  84. package/templates/apps/frontend-auth/package.json +7 -7
  85. package/templates/apps/frontend-blank/package.json +6 -6
  86. package/templates/apps/frontend-cms/package.json +8 -8
  87. package/templates/apps/frontend-collab/package.json +9 -9
  88. package/templates/apps/frontend-contact/package.json +7 -7
  89. package/templates/apps/frontend-dashboard/package.json +6 -6
  90. package/templates/apps/frontend-docs/package.json +8 -8
  91. package/templates/apps/frontend-i18n/package.json +6 -6
  92. package/templates/apps/frontend-landing/package.json +7 -7
  93. package/templates/apps/frontend-portal/package.json +7 -7
  94. package/templates/apps/frontend-saas/package.json +7 -7
  95. package/templates/apps/frontend-spa/package.json +6 -6
  96. package/templates/apps/frontend-ssr/package.json +6 -6
  97. package/templates/apps/frontend-ssr-api/package.json +7 -7
  98. package/templates/apps/frontend-static-blog/package.json +8 -8
  99. package/templates/apps/frontend-status/package.json +7 -7
  100. package/templates/apps/mobile-app/package.json +4 -4
  101. package/dist/apiBuild-B83Cb2Rv.js +0 -2
  102. package/dist/build-QKP6Bm0J.js +0 -872
  103. package/dist/dev-Bl9HqtV7.js +0 -3
  104. package/dist/doctorCommand-DrQv9SL3.js +0 -2
  105. package/dist/inspect-B0hL41s0.js +0 -2
  106. package/dist/manifestBuild-UXrnUcXP.js +0 -2
  107. package/dist/serveCommand-Dtb48ffg.js +0 -2
  108. package/dist/updateCommand-DsXEAHbd.js +0 -2
  109. package/dist/webDev-B6ZMX42w.js +0 -2
@@ -1,6 +1,6 @@
1
- import { Jt as e, Xt as t, Yt as n } from "./dev-DOEJXicj.js";
2
- import { Bt as r, Lt as i, R as a, Rt as o, S as s, t as c, u as l, zt as u } from "./webDev-BgdkyjP6.js";
3
- import { r as d, u as f } from "./apiBuild-DDr2aNFd.js";
1
+ import { Xt as e, Yt as t, Zt as n } from "./dev-Ce2gEziv.js";
2
+ import { Bt as r, Ht as i, T as a, Ut as o, V as s, Vt as c, t as l, u } from "./webDev-CBN9KkyQ.js";
3
+ import { r as d, u as f } from "./apiBuild-CkpsCqIu.js";
4
4
  import { S as p } from "./frameworkTableAssembly-vfkzuzEo.js";
5
5
  import { n as m } from "./pageConvention-CMpfDN6r.js";
6
6
  import { n as h, r as g, t as ee } from "./cliOutput-D1tSBoRM.js";
@@ -11,8 +11,227 @@ import { existsSync as S, readFileSync as C, readdirSync as w, statSync as T, wr
11
11
  import { pathToFileURL as se } from "node:url";
12
12
  import { createLogger as ce } from "@voltro/logger";
13
13
  import { Node as E, Project as D, SyntaxKind as O } from "ts-morph";
14
- //#region src/predicateColumnAudit.ts
15
- var le = /* @__PURE__ */ new Set([
14
+ //#region src/frameworkTableNullability.generated.ts
15
+ var le = {
16
+ _voltro_ai_flow_runs: [
17
+ "cancelledAt",
18
+ "chainPending",
19
+ "chainRefusal",
20
+ "completedAt",
21
+ "durationMs",
22
+ "error",
23
+ "errorMessage",
24
+ "flowName",
25
+ "humanResponse",
26
+ "input",
27
+ "metadata",
28
+ "output",
29
+ "ownerId",
30
+ "sessionId",
31
+ "sessionName",
32
+ "source",
33
+ "startedAt",
34
+ "steps"
35
+ ],
36
+ _voltro_ai_flows: [
37
+ "avatarUrl",
38
+ "cadence",
39
+ "chainTo",
40
+ "color",
41
+ "description",
42
+ "humanTimeoutMs",
43
+ "icon",
44
+ "inputSchema",
45
+ "metadata",
46
+ "orchestratorInstructions",
47
+ "orchestratorModel",
48
+ "ownerId",
49
+ "steps"
50
+ ],
51
+ _voltro_api_keys: [
52
+ "createdBy",
53
+ "expiresAt",
54
+ "lastUsedAt",
55
+ "metadata",
56
+ "onBehalfOf",
57
+ "revokedAt",
58
+ "scopes",
59
+ "tenantId"
60
+ ],
61
+ _voltro_change_claims: [],
62
+ _voltro_comment_reactions: [],
63
+ _voltro_comment_reads: [],
64
+ _voltro_comment_threads: ["tenantId"],
65
+ _voltro_comments: ["editedAt", "tenantId"],
66
+ _voltro_events: ["subjectId", "tenantId"],
67
+ _voltro_idempotency: ["response"],
68
+ _voltro_kv: ["expiresAt", "value"],
69
+ _voltro_migration_plans: [
70
+ "liveFingerprint",
71
+ "notes",
72
+ "onlineStrategy",
73
+ "rollbackPlan",
74
+ "squashedAt"
75
+ ],
76
+ _voltro_migrations: [
77
+ "appliedAt",
78
+ "durationMs",
79
+ "errorMessage",
80
+ "errorStack",
81
+ "workflowRunId"
82
+ ],
83
+ _voltro_notification_deliveries: [
84
+ "clickToken",
85
+ "clickedAt",
86
+ "endpoint",
87
+ "error"
88
+ ],
89
+ _voltro_notification_held: [],
90
+ _voltro_notification_inbox: [
91
+ "archivedAt",
92
+ "readAt",
93
+ "tenantId"
94
+ ],
95
+ _voltro_notification_preferences: [],
96
+ _voltro_notification_push_subscriptions: ["tenantId", "ua"],
97
+ _voltro_notification_quiet_hours: [],
98
+ _voltro_notification_topic_subscriptions: ["tenantId"],
99
+ _voltro_rebac_tuples: ["tenantId"],
100
+ _voltro_replica_observations: [
101
+ "payload",
102
+ "reachableAt",
103
+ "version"
104
+ ],
105
+ _voltro_schedule_claims: [],
106
+ _voltro_schedule_runs: [
107
+ "completedAt",
108
+ "coordinationOutcome",
109
+ "durationMs",
110
+ "errorMessage",
111
+ "errorTag",
112
+ "firedAt",
113
+ "heartbeatAt",
114
+ "replicaId",
115
+ "result"
116
+ ],
117
+ _voltro_scim_groups: ["externalId", "members"],
118
+ _voltro_scim_users: [
119
+ "email",
120
+ "externalId",
121
+ "familyName",
122
+ "givenName"
123
+ ],
124
+ _voltro_seeds: [
125
+ "cronSchedule",
126
+ "lastError",
127
+ "lastRunAt",
128
+ "lastRunDurationMs",
129
+ "lastRunRowsTouched",
130
+ "lastRunStatus",
131
+ "nextRunAt",
132
+ "watchedTables",
133
+ "workflowRunId"
134
+ ],
135
+ _voltro_traces: [
136
+ "attributes",
137
+ "events",
138
+ "parentSpanId",
139
+ "statusMessage"
140
+ ],
141
+ _voltro_undo_log: [
142
+ "label",
143
+ "subjectId",
144
+ "tenantId",
145
+ "traceId"
146
+ ],
147
+ _voltro_wakeups: [],
148
+ _voltro_webhook_deliveries: [
149
+ "errorMessage",
150
+ "eventId",
151
+ "latencyMs",
152
+ "nextAttemptAt",
153
+ "responseBody",
154
+ "responseStatus"
155
+ ],
156
+ _voltro_webhook_event_stats: [],
157
+ _voltro_webhook_rate_windows: [],
158
+ _voltro_webhook_targets: [
159
+ "autoDisableAfter",
160
+ "autoDisableReason",
161
+ "autoDisabledAt",
162
+ "description",
163
+ "filter",
164
+ "headers",
165
+ "rateLimitPerMinute",
166
+ "scope"
167
+ ],
168
+ _voltro_workflow_admissions: [
169
+ "concurrencyKey",
170
+ "executionId",
171
+ "expiresAt",
172
+ "mode",
173
+ "rateKey",
174
+ "reason",
175
+ "releasedAt",
176
+ "runId",
177
+ "singletonKey",
178
+ "tenantId",
179
+ "waitedMs"
180
+ ],
181
+ _voltro_workflow_event_deliveries: [
182
+ "completedAt",
183
+ "errorMessage",
184
+ "executionId"
185
+ ],
186
+ _voltro_workflow_events: ["subject", "traceId"],
187
+ _voltro_workflow_pauses: ["pausedBy", "reason"],
188
+ _voltro_workflow_pending: [
189
+ "callerContext",
190
+ "deadlineAt",
191
+ "lastError",
192
+ "tenantId"
193
+ ],
194
+ _voltro_workflow_run_events: [
195
+ "attempt",
196
+ "payload",
197
+ "stepName"
198
+ ],
199
+ _voltro_workflow_run_steps: [
200
+ "completedAt",
201
+ "durationMs",
202
+ "errorCause",
203
+ "errorMessage",
204
+ "errorTag",
205
+ "input",
206
+ "output",
207
+ "retryPolicy"
208
+ ],
209
+ _voltro_workflow_runs: [
210
+ "completedAt",
211
+ "discardedAt",
212
+ "discardedBy",
213
+ "durationMs",
214
+ "errorMessage",
215
+ "errorTag",
216
+ "output",
217
+ "parentClosePolicy",
218
+ "parentExecutionId",
219
+ "runnerEnteredAt",
220
+ "source",
221
+ "subject",
222
+ "traceId",
223
+ "workflowPatches",
224
+ "workflowVersion"
225
+ ],
226
+ _voltro_workflow_start_contexts: [
227
+ "parentClosePolicy",
228
+ "parentExecutionId",
229
+ "source",
230
+ "subject",
231
+ "traceId"
232
+ ],
233
+ _voltro_workflow_watermarks: []
234
+ }, ue = /* @__PURE__ */ new Set([
16
235
  "eq",
17
236
  "ne",
18
237
  "gt",
@@ -30,10 +249,10 @@ var le = /* @__PURE__ */ new Set([
30
249
  "endsWith",
31
250
  "between",
32
251
  "jsonField"
33
- ]), ue = (e) => {
252
+ ]), de = (e) => {
34
253
  if (E.isPropertyAccessExpression(e)) return e.getName();
35
254
  if (E.isIdentifier(e)) return e.getText();
36
- }, de = (e) => {
255
+ }, fe = (e) => {
37
256
  let t = e;
38
257
  for (; E.isCallExpression(t);) {
39
258
  let e = t.getExpression();
@@ -41,7 +260,7 @@ var le = /* @__PURE__ */ new Set([
41
260
  t = e.getExpression();
42
261
  }
43
262
  return t;
44
- }, fe = (e, t, n) => {
263
+ }, pe = (e, t, n) => {
45
264
  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 D({
46
265
  useInMemoryFileSystem: !0,
47
266
  skipAddingFilesFromTsConfig: !0
@@ -59,7 +278,7 @@ var le = /* @__PURE__ */ new Set([
59
278
  for (let t of e.getDescendantsOfKind(O.CallExpression)) {
60
279
  let e = t.getExpression();
61
280
  if (!E.isPropertyAccessExpression(e) || e.getName() !== "where") continue;
62
- let n = ue(de(e.getExpression()));
281
+ let n = de(fe(e.getExpression()));
63
282
  if (n === void 0 || !r.has(n)) {
64
283
  let t = e.getExpression();
65
284
  if (E.isCallExpression(t)) {
@@ -82,7 +301,7 @@ var le = /* @__PURE__ */ new Set([
82
301
  else for (let e of [u, ...u.getDescendantsOfKind(O.CallExpression)]) {
83
302
  if (!E.isCallExpression(e)) continue;
84
303
  let t = e.getExpression(), n = E.isIdentifier(t) ? t.getText() : E.isPropertyAccessExpression(t) ? t.getName() : void 0;
85
- if (n === void 0 || !le.has(n)) continue;
304
+ if (n === void 0 || !ue.has(n)) continue;
86
305
  let r = e.getArguments()[0];
87
306
  r !== void 0 && E.isStringLiteral(r) && l.push({
88
307
  column: r.getLiteralValue(),
@@ -103,7 +322,7 @@ var le = /* @__PURE__ */ new Set([
103
322
  issues: a,
104
323
  checked: o
105
324
  };
106
- }, k = 12, pe = (e) => {
325
+ }, k = 12, me = (e) => {
107
326
  if (e.checked === 0) return null;
108
327
  if (e.issues.length === 0) return `predicate columns: ${e.checked} checked — every filtered column exists on its table`;
109
328
  let t = [`predicate columns: ${e.issues.length} filter${e.issues.length, "s"} on a column that does not exist (${e.checked} checked)`];
@@ -112,7 +331,7 @@ var le = /* @__PURE__ */ new Set([
112
331
  t.push(` ${n.file}:${n.line} '${n.table}' has no column '${n.column}'`), t.push(` columns: ${e}${r}`);
113
332
  }
114
333
  return t.push(" This type-checks today and fails at runtime as a bare SQL error."), t.join("\n");
115
- }, me = /* @__PURE__ */ new Set([
334
+ }, he = /* @__PURE__ */ new Set([
116
335
  "id",
117
336
  "tenantId",
118
337
  "tenant_id",
@@ -132,7 +351,7 @@ var le = /* @__PURE__ */ new Set([
132
351
  "idempotency_id",
133
352
  "idempotencyKey",
134
353
  "idempotency_key"
135
- ]), he = /* @__PURE__ */ new Set([
354
+ ]), ge = /* @__PURE__ */ new Set([
136
355
  "id",
137
356
  "createdAt",
138
357
  "created_at",
@@ -142,10 +361,10 @@ var le = /* @__PURE__ */ new Set([
142
361
  "deleted_at",
143
362
  "tenantId",
144
363
  "tenant_id"
145
- ]), ge = (e) => me.has(e) ? !1 : /[a-z0-9]Id$/.test(e) || /_id$/.test(e), _e = (e) => e.type === "reference", ve = (e) => {
364
+ ]), _e = (e) => he.has(e) ? !1 : /[a-z0-9]Id$/.test(e) || /_id$/.test(e), ve = (e) => e.type === "reference", ye = (e) => {
146
365
  let t = [];
147
366
  for (let n of e) {
148
- let e = n.columns.filter((e) => ge(e.name)), r = e.filter((e) => !_e(e)).map((e) => e.name);
367
+ let e = n.columns.filter((e) => _e(e.name)), r = e.filter((e) => !ve(e)).map((e) => e.name);
149
368
  if (r.length === 0) continue;
150
369
  let i = new Set(n.primaryKey), a = r.filter((e) => i.has(e));
151
370
  if (n.primaryKey.length >= 2 && a.length > 0) {
@@ -156,7 +375,7 @@ var le = /* @__PURE__ */ new Set([
156
375
  });
157
376
  continue;
158
377
  }
159
- if (e.some(_e) && e.length >= 2) {
378
+ if (e.some(ve) && e.length >= 2) {
160
379
  t.push({
161
380
  table: n.name,
162
381
  columns: r,
@@ -164,7 +383,7 @@ var le = /* @__PURE__ */ new Set([
164
383
  });
165
384
  continue;
166
385
  }
167
- e.length >= 2 && n.columns.filter((e) => !ge(e.name) && !he.has(e.name)).length === 0 && t.push({
386
+ e.length >= 2 && n.columns.filter((e) => !_e(e.name) && !ge.has(e.name)).length === 0 && t.push({
168
387
  table: n.name,
169
388
  columns: r,
170
389
  signal: "link-only"
@@ -174,20 +393,20 @@ var le = /* @__PURE__ */ new Set([
174
393
  issues: t,
175
394
  tablesChecked: e.length
176
395
  };
177
- }, ye = {
396
+ }, be = {
178
397
  "composite-pk": "part of a composite primary key",
179
398
  "reference-sibling": "sits beside a wired reference() on this table",
180
399
  "link-only": "this table is nothing but link columns"
181
- }, be = (e) => {
400
+ }, xe = (e) => {
182
401
  if (e.tablesChecked === 0) return null;
183
402
  if (e.issues.length === 0) return `junction FKs: ${e.tablesChecked} table${e.tablesChecked === 1 ? "" : "s"} checked — every link column is a wired reference()`;
184
403
  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()`];
185
404
  for (let t of e.issues) {
186
405
  let e = t.columns.map((e) => `'${e}'`).join(", ");
187
- n.push(` '${t.table}': ${e} (${ye[t.signal]})`);
406
+ n.push(` '${t.table}': ${e} (${be[t.signal]})`);
188
407
  }
189
408
  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");
190
- }, xe = /* @__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(".")), Se = (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()), Ce = (e) => Se(e).some((e) => xe.has(e)), we = (e) => {
409
+ }, Se = /* @__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(".")), Ce = (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()), we = (e) => Ce(e).some((e) => Se.has(e)), Te = (e) => {
191
410
  let t = [], n = [];
192
411
  for (let r of e) t.push({
193
412
  event: r.name,
@@ -196,7 +415,7 @@ var le = /* @__PURE__ */ new Set([
196
415
  event: r.name,
197
416
  kind: "wide-key",
198
417
  keyFieldCount: r.keyFieldCount
199
- }), r.hasWebhook && Ce(r.name) && n.push({
418
+ }), r.hasWebhook && we(r.name) && n.push({
200
419
  event: r.name,
201
420
  kind: "webhook-high-rate"
202
421
  });
@@ -205,26 +424,26 @@ var le = /* @__PURE__ */ new Set([
205
424
  modes: t,
206
425
  warnings: n
207
426
  };
208
- }, Te = (e) => {
427
+ }, Ee = (e) => {
209
428
  if (e.eventsChecked === 0) return null;
210
429
  let t = e.eventsChecked, n = [`event delivery: ${t} declared event${t === 1 ? "" : "s"} — the mode decides what a MISSING message means`];
211
430
  for (let t of e.modes) n.push(` '${t.event}': ${t.delivery}`);
212
431
  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");
213
- }, Ee = (e) => {
432
+ }, De = (e) => {
214
433
  if (e.warnings.length === 0) return null;
215
434
  let t = e.warnings.length, n = [`events that may not scale as declared: ${t} finding${t === 1 ? "" : "s"}`];
216
435
  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."));
217
436
  return n.push(" WARNING, not a fault — a producer may intend the fan-out. `voltro doctor --json` prints every finding."), n.join("\n");
218
- }, De = /* @__PURE__ */ new Set([
437
+ }, Oe = /* @__PURE__ */ new Set([
219
438
  "start",
220
439
  "run",
221
440
  "child"
222
- ]), Oe = (e) => E.isCallExpression(e) && (() => {
441
+ ]), ke = (e) => E.isCallExpression(e) && (() => {
223
442
  let t = e.getExpression();
224
- if (!E.isPropertyAccessExpression(t) || !De.has(t.getName())) return !1;
443
+ if (!E.isPropertyAccessExpression(t) || !Oe.has(t.getName())) return !1;
225
444
  let n = t.getExpression();
226
445
  return E.isPropertyAccessExpression(n) ? n.getName() === "workflows" : E.isIdentifier(n) && n.getText() === "workflows";
227
- })(), ke = (e, t, n) => {
446
+ })(), Ae = (e, t, n) => {
228
447
  let r = new Map(t.map((e) => [e.name, e])), i = [...r.keys()].sort(), a = [], o = [], s = 0, c = 0, l = new D({
229
448
  useInMemoryFileSystem: !0,
230
449
  skipAddingFilesFromTsConfig: !0
@@ -240,7 +459,7 @@ var le = /* @__PURE__ */ new Set([
240
459
  }
241
460
  let u = y(n, t);
242
461
  for (let t of e.getDescendantsOfKind(O.CallExpression)) {
243
- if (!Oe(t)) continue;
462
+ if (!ke(t)) continue;
244
463
  c++;
245
464
  let e = t.getStartLineNumber(), [n, l] = t.getArguments();
246
465
  if (n === void 0 || !E.isStringLiteral(n)) {
@@ -324,7 +543,7 @@ var le = /* @__PURE__ */ new Set([
324
543
  checked: s,
325
544
  callSites: c
326
545
  };
327
- }, Ae = (e) => {
546
+ }, je = (e) => {
328
547
  if (e.callSites === 0) return null;
329
548
  let t = [];
330
549
  t.push(`workflow starts: ${e.checked}/${e.callSites} call sites checked`);
@@ -337,7 +556,7 @@ var le = /* @__PURE__ */ new Set([
337
556
  for (let n of e.unchecked) t.push(` ${n.file}:${n.line} — ${n.reason}`);
338
557
  }
339
558
  return e.issues.length === 0 && e.unchecked.length === 0 && t.push(" every call site matches its workflow"), t.join("\n");
340
- }, je = /(^|[/\\])(\.env(\.[\w.-]+)?|.*\.ya?ml|Dockerfile|.*\.tf|.*\.toml|Procfile)$/i, A = "VOLTRO_FIELD_ENCRYPTION_KEY", Me = (e) => {
559
+ }, Me = /(^|[/\\])(\.env(\.[\w.-]+)?|.*\.ya?ml|Dockerfile|.*\.tf|.*\.toml|Procfile)$/i, A = "VOLTRO_FIELD_ENCRYPTION_KEY", Ne = (e) => {
341
560
  let t;
342
561
  for (let [n, r] of e.sources) if (t === void 0 && /\bfieldEncryption\b/.test(r) && (t = {
343
562
  reason: "fieldEncryption",
@@ -350,7 +569,7 @@ var le = /* @__PURE__ */ new Set([
350
569
  for (let [, t] of e.envFiles) if (t.includes(A)) return;
351
570
  return t;
352
571
  }
353
- }, Ne = (e) => [
572
+ }, Pe = (e) => [
354
573
  `✗ ${A} is named nowhere under this app root, and the app encrypts columns at rest`,
355
574
  e.reason === "fieldEncryption" ? ` (\`fieldEncryption\` in ${e.file})` : ` (an \`.encrypted()\` column in ${e.file})`,
356
575
  "",
@@ -367,15 +586,15 @@ var le = /* @__PURE__ */ new Set([
367
586
  " reaches your deploy target is not knowable from here — a secret manager",
368
587
  " or a CI variable is not a file. Naming it nowhere is conclusive; naming",
369
588
  " it somewhere is not a guarantee."
370
- ].join("\n"), Pe = {
589
+ ].join("\n"), Fe = {
371
590
  "@voltro/cli": "provides the `voltro` binary; consumed by scripts, never imported",
372
591
  "@voltro/devtools": "mounted by `voltro dev` itself",
373
592
  "@voltro/sql-postgres": "dialect driver, loaded by the framework from config",
374
593
  "@voltro/sql-mysql": "dialect driver, loaded by the framework from config",
375
594
  "@voltro/sql-sqlite": "dialect driver, loaded by the framework from config",
376
595
  "@voltro/sql-mssql": "dialect driver, loaded by the framework from config"
377
- }, Fe = /* @__PURE__ */ new Set(["@voltro/client", "@voltro/web"]), Ie = /(^|\/)(node_modules|dist|build|\.framework|\.next|\.turbo|\.git|coverage|\.publish)(\/|$)/, Le = /\.([cm]?[jt]sx?)$/, Re = /\.generated\.[cm]?[jt]sx?$/, ze = (e, t = [], n = 0) => {
378
- if (n > 12 || Ie.test(e)) return t;
596
+ }, Ie = /* @__PURE__ */ new Set(["@voltro/client", "@voltro/web"]), Le = /(^|\/)(node_modules|dist|build|\.framework|\.next|\.turbo|\.git|coverage|\.publish)(\/|$)/, Re = /\.([cm]?[jt]sx?)$/, ze = /\.generated\.[cm]?[jt]sx?$/, Be = (e, t = [], n = 0) => {
597
+ if (n > 12 || Le.test(e)) return t;
379
598
  let r;
380
599
  try {
381
600
  r = w(e);
@@ -389,10 +608,10 @@ var le = /* @__PURE__ */ new Set([
389
608
  } catch {
390
609
  continue;
391
610
  }
392
- a.isDirectory() ? ze(r, t, n + 1) : Le.test(i) && t.push(r);
611
+ a.isDirectory() ? Be(r, t, n + 1) : Re.test(i) && t.push(r);
393
612
  }
394
613
  return t;
395
- }, Be = /(?:\bfrom\s*|\bimport\s+|\bimport\s*\(\s*|\brequire\s*\(\s*)['"](@voltro\/[a-z0-9-]+)(?:\/[^'"]*)?['"]/g, Ve = (e) => e.split("\n").filter((e) => !/^\s*(\/\/|\*|\/\*)/.test(e)).join("\n"), He = (e) => {
614
+ }, Ve = /(?:\bfrom\s*|\bimport\s+|\bimport\s*\(\s*|\brequire\s*\(\s*)['"](@voltro\/[a-z0-9-]+)(?:\/[^'"]*)?['"]/g, He = (e) => e.split("\n").filter((e) => !/^\s*(\/\/|\*|\/\*)/.test(e)).join("\n"), Ue = (e) => {
396
615
  let t;
397
616
  try {
398
617
  t = JSON.parse(C(v(e, "package.json"), "utf8"));
@@ -402,7 +621,7 @@ var le = /* @__PURE__ */ new Set([
402
621
  let n = (e) => Object.keys(t[e] ?? {}).filter((e) => e.startsWith("@voltro/")).map((t) => ({
403
622
  pkg: t,
404
623
  declaredIn: e
405
- })), r = /* @__PURE__ */ new Set(), i = [...n("dependencies"), ...n("devDependencies")].filter((e) => !r.has(e.pkg) && (r.add(e.pkg), !0)), a = ze(e), o = a.some((e) => Re.test(e)), s = /* @__PURE__ */ new Set();
624
+ })), r = /* @__PURE__ */ new Set(), i = [...n("dependencies"), ...n("devDependencies")].filter((e) => !r.has(e.pkg) && (r.add(e.pkg), !0)), a = Be(e), o = a.some((e) => ze.test(e)), s = /* @__PURE__ */ new Set();
406
625
  for (let e of a) {
407
626
  let t;
408
627
  try {
@@ -410,17 +629,17 @@ var le = /* @__PURE__ */ new Set([
410
629
  } catch {
411
630
  continue;
412
631
  }
413
- for (let e of Ve(t).matchAll(Be)) s.add(e[1]);
632
+ for (let e of He(t).matchAll(Ve)) s.add(e[1]);
414
633
  }
415
- let c = i.filter((e) => !(e.pkg in Pe) && !s.has(e.pkg));
634
+ let c = i.filter((e) => !(e.pkg in Fe) && !s.has(e.pkg));
416
635
  return {
417
636
  declared: i.map((e) => e.pkg).sort(),
418
- unimported: c.filter((e) => o || !Fe.has(e.pkg)).sort((e, t) => e.pkg.localeCompare(t.pkg)),
419
- pendingCodegen: o ? [] : c.map((e) => e.pkg).filter((e) => Fe.has(e)).sort(),
420
- exempt: i.map((e) => e.pkg).filter((e) => e in Pe).sort(),
637
+ unimported: c.filter((e) => o || !Ie.has(e.pkg)).sort((e, t) => e.pkg.localeCompare(t.pkg)),
638
+ pendingCodegen: o ? [] : c.map((e) => e.pkg).filter((e) => Ie.has(e)).sort(),
639
+ exempt: i.map((e) => e.pkg).filter((e) => e in Fe).sort(),
421
640
  scannedFiles: a.length
422
641
  };
423
- }, Ue = (e) => {
642
+ }, We = (e) => {
424
643
  if (e === null) return ["unimported deps · no package.json here — could not check"];
425
644
  let t = `unimported deps · ${e.declared.length} @voltro/* package(s) declared, ${e.scannedFiles} file(s) scanned`;
426
645
  if (e.declared.length === 0) return [t, " no @voltro/* dependencies declared — nothing to check"];
@@ -437,14 +656,14 @@ var le = /* @__PURE__ */ new Set([
437
656
  let i = [t];
438
657
  for (let t of e.unimported) i.push(` ⚠ ${t.pkg} — declared in ${t.declaredIn}, imported nowhere`);
439
658
  return i.push(" a dependency nobody imports still gets installed, updated, and read as"), i.push(" evidence the package is in use — its breaking-change notes included."), i.push(" Remove it, or if it IS imported through an assembled specifier the scan"), i.push(" cannot see, keep it and ignore this line — the rule is advisory."), i.push(...r), n !== "" && i.push(` ·${n.slice(1)}`), i;
440
- }, We = (e) => {
659
+ }, Ge = (e) => {
441
660
  if (e.catalogCodes.length === 0) return;
442
661
  let t = new Set(e.declaredLocales), n = e.catalogCodes.filter((e) => !t.has(e)).sort();
443
662
  if (n.length !== 0) return {
444
663
  orphaned: n,
445
664
  noneDeclared: t.size === 0
446
665
  };
447
- }, Ge = (e, t) => {
666
+ }, Ke = (e, t) => {
448
667
  let n = e.orphaned.join(", ");
449
668
  return e.noneDeclared ? [
450
669
  `⚠ ${t} has ${e.orphaned.length} catalog(s) — ${n} — and the app declares no \`locales:\`.`,
@@ -456,7 +675,7 @@ var le = /* @__PURE__ */ new Set([
456
675
  " …or delete the files. A catalog that is never loaded looks from the inside",
457
676
  " exactly like one that works, which is why this is worth a line."
458
677
  ] : [`⚠ ${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)."];
459
- }, Ke = (e) => {
678
+ }, qe = (e) => {
460
679
  let t = e.getProperty("match");
461
680
  if (t === void 0) return null;
462
681
  let n = (t.asKind(O.PropertyAssignment)?.getInitializer())?.asKind(O.ObjectLiteralExpression);
@@ -493,7 +712,7 @@ var le = /* @__PURE__ */ new Set([
493
712
  else return;
494
713
  }
495
714
  return r;
496
- }, qe = (e, t) => {
715
+ }, Je = (e, t) => {
497
716
  let n = ["middleware.ts", "middleware.tsx"].find((t) => S(v(e, t)));
498
717
  if (n === void 0) return;
499
718
  let r = new D({
@@ -510,22 +729,22 @@ var le = /* @__PURE__ */ new Set([
510
729
  file: n
511
730
  };
512
731
  }
513
- let o = [], s = [], c = 0;
732
+ let a = [], o = [], c = 0;
514
733
  for (let e of i.getVariableDeclarations()) {
515
734
  let t = e.getInitializerIfKind(O.CallExpression);
516
735
  if (t?.getExpression().getText() !== "defineMiddleware") continue;
517
736
  c += 1;
518
737
  let n = e.getName(), r = t.getArguments()[0]?.asKind(O.ObjectLiteralExpression);
519
738
  if (r === void 0) {
520
- s.push(n);
739
+ o.push(n);
521
740
  continue;
522
741
  }
523
- let i = Ke(r);
742
+ let i = qe(r);
524
743
  if (i === void 0) {
525
- s.push(n);
744
+ o.push(n);
526
745
  continue;
527
746
  }
528
- o.push({
747
+ a.push({
529
748
  exportName: n,
530
749
  middleware: {
531
750
  _tag: "VoltroMiddleware",
@@ -535,45 +754,45 @@ var le = /* @__PURE__ */ new Set([
535
754
  });
536
755
  }
537
756
  return {
538
- problems: a(o, t).map((e) => e.message),
539
- unreadable: s,
757
+ problems: s(a, t).map((e) => e.message),
758
+ unreadable: o,
540
759
  seen: c,
541
760
  file: n
542
761
  };
543
- }, Je = (e) => {
762
+ }, Ye = (e) => {
544
763
  let t = [];
545
764
  if (e.problems.length > 0) {
546
765
  t.push(`✗ ${e.file}: ${e.problems.length} matcher problem(s) — this REFUSES the boot`);
547
766
  for (let n of e.problems) t.push(` • ${n}`);
548
767
  }
549
768
  return e.unreadable.length > 0 && t.push(`… ${e.file}: ${e.unreadable.length} matcher(s) not statically readable (${e.unreadable.join(", ")}) — doctor did NOT check them. The boot still does.`), e.seen === 0 && t.push(`… ${e.file}: no \`defineMiddleware(...)\` found — doctor checked nothing here. A middleware assigned through a variable or re-exported from another module is invisible to this rule.`), t.length === 0 && e.seen > 0 && t.push(`✓ ${e.file}: ${e.seen} middleware(s), matchers resolve and do not overlap`), t;
550
- }, Ye = (e) => e.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/[^\n]*/g, "$1"), Xe = /* @__PURE__ */ new Set([
769
+ }, Xe = (e) => e.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/[^\n]*/g, "$1"), Ze = /* @__PURE__ */ new Set([
551
770
  "requireScope",
552
771
  "requireAnyScope",
553
772
  "requireAuth",
554
773
  "assertScope",
555
774
  "assertCan",
556
775
  "can"
557
- ]), Ze = (e) => {
776
+ ]), Qe = (e) => {
558
777
  let t = /* @__PURE__ */ new Set();
559
- for (let n of e) for (let e of Ye(n).matchAll(/\bexport\s+(?:const|function|async\s+function)\s+((?:require|assert)[A-Z]\w*)/g)) t.add(e[1]);
778
+ for (let n of e) for (let e of Xe(n).matchAll(/\bexport\s+(?:const|function|async\s+function)\s+((?:require|assert)[A-Z]\w*)/g)) t.add(e[1]);
560
779
  return t;
561
- }, Qe = (e, t) => {
780
+ }, $e = (e, t) => {
562
781
  for (let n of t) if (RegExp(`\\b${n}\\s*\\(`).test(e)) return n;
563
- }, $e = (e) => {
782
+ }, et = (e) => {
564
783
  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);
565
784
  return t && n;
566
- }, et = (e, t, n) => {
785
+ }, tt = (e, t, n) => {
567
786
  if (e.hasDeclaredGuards) return { kind: "declared-guard" };
568
- let r = Ye(e.src), i = Qe(r, t);
569
- return i === void 0 ? $e(r) ? { kind: "inline-ownership" } : n.has(e.tag) ? { kind: "allowlisted" } : { kind: "unchecked" } : {
787
+ let r = Xe(e.src), i = $e(r, t);
788
+ return i === void 0 ? et(r) ? { kind: "inline-ownership" } : n.has(e.tag) ? { kind: "allowlisted" } : { kind: "unchecked" } : {
570
789
  kind: "vocabulary-guard",
571
790
  name: i
572
791
  };
573
- }, tt = (e, t, n) => {
792
+ }, nt = (e, t, n) => {
574
793
  let r = e.op === "delete" ? 3 : e.op === "update" ? 2 : 1;
575
794
  return e.table !== void 0 && (t.has(e.table) && (r += 2), n.has(e.table) && e.op === "delete" && (r += 2)), r;
576
- }, nt = (e, t, n) => {
795
+ }, rt = (e, t, n) => {
577
796
  switch (t.kind) {
578
797
  case "declared-guard": return "guards: on the descriptor";
579
798
  case "vocabulary-guard": return `calls ${t.name}()`;
@@ -581,15 +800,15 @@ var le = /* @__PURE__ */ new Set([
581
800
  case "allowlisted": return "accepted by a previous run";
582
801
  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`;
583
802
  }
584
- }, rt = (e) => {
803
+ }, it = (e) => {
585
804
  let t = e.executors.map((t) => {
586
- let n = et(t, e.guardVocabulary, e.allowlist);
805
+ let n = tt(t, e.guardVocabulary, e.allowlist);
587
806
  return {
588
807
  tag: t.tag,
589
808
  path: t.path,
590
809
  verdict: n,
591
- severity: tt(t, e.tenantScopedTables, e.referencedTables),
592
- why: nt(t, n, e.rowFilterRegistered === !0)
810
+ severity: nt(t, e.tenantScopedTables, e.referencedTables),
811
+ why: rt(t, n, e.rowFilterRegistered === !0)
593
812
  };
594
813
  }), n = (e) => t.filter((t) => t.verdict.kind === e).length;
595
814
  return {
@@ -603,7 +822,7 @@ var le = /* @__PURE__ */ new Set([
603
822
  },
604
823
  unchecked: t.filter((e) => e.verdict.kind === "unchecked").sort((e, t) => t.severity - e.severity || e.tag.localeCompare(t.tag))
605
824
  };
606
- }, it = [
825
+ }, at = [
607
826
  "# voltro doctor — authz allowlist",
608
827
  "#",
609
828
  "# Two KINDS of line, and the difference is the point:",
@@ -628,18 +847,18 @@ var le = /* @__PURE__ */ new Set([
628
847
  "# `--write-authz-allowlist` PRESERVES reviewed= lines. It only ever adds debt",
629
848
  "# lines for executors that are newly unchecked.",
630
849
  ""
631
- ], at = (e) => {
850
+ ], ot = (e) => {
632
851
  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));
633
852
  return [
634
- ...it,
853
+ ...at,
635
854
  ...n,
636
855
  ...r.length > 0 ? ["", "# reviewed — read by a human, open on purpose"] : [],
637
856
  ...r.map((e) => `${e.tag} reviewed=${e.reviewed}`),
638
857
  ""
639
858
  ].join("\n");
640
- }, ot = (e, t) => {
859
+ }, st = (e, t) => {
641
860
  let n = [...new Set(t)].sort();
642
- if (e === void 0) return at(n.map((e) => ({ tag: e })));
861
+ if (e === void 0) return ot(n.map((e) => ({ tag: e })));
643
862
  let r = j(e).tags, i = n.filter((e) => !r.has(e));
644
863
  return i.length === 0 ? e : [
645
864
  e.replace(/\n+$/, ""),
@@ -649,7 +868,7 @@ var le = /* @__PURE__ */ new Set([
649
868
  ...i,
650
869
  ""
651
870
  ].join("\n");
652
- }, st = (e, t) => {
871
+ }, ct = (e, t) => {
653
872
  let n = [...new Set(t)];
654
873
  if (e === void 0) return {
655
874
  added: n.length,
@@ -662,7 +881,7 @@ var le = /* @__PURE__ */ new Set([
662
881
  kept: r.size,
663
882
  removed: 0
664
883
  };
665
- }, ct = class extends Error {
884
+ }, lt = class extends Error {
666
885
  tag;
667
886
  constructor(e) {
668
887
  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";
@@ -680,7 +899,7 @@ var le = /* @__PURE__ */ new Set([
680
899
  continue;
681
900
  }
682
901
  let a = r[2].trim();
683
- if (a.length === 0) throw new ct(i);
902
+ if (a.length === 0) throw new lt(i);
684
903
  t.push({
685
904
  tag: i,
686
905
  reviewed: a
@@ -690,13 +909,13 @@ var le = /* @__PURE__ */ new Set([
690
909
  tags: new Set(t.map((e) => e.tag)),
691
910
  entries: t
692
911
  };
693
- }, lt = (e) => {
912
+ }, ut = (e) => {
694
913
  let t = e.indexOf(".");
695
914
  return t <= 0 ? void 0 : e.slice(0, t);
696
- }, ut = (e, t) => {
915
+ }, dt = (e, t) => {
697
916
  let n = new Set(t.tables), r = new Set(t.rpcTags), i = /* @__PURE__ */ new Map();
698
917
  for (let e of t.rpcTags) {
699
- let t = lt(e);
918
+ let t = ut(e);
700
919
  if (t === void 0) continue;
701
920
  let n = i.get(t);
702
921
  n ? n.push(e) : i.set(t, [e]);
@@ -725,7 +944,7 @@ var le = /* @__PURE__ */ new Set([
725
944
  });
726
945
  continue;
727
946
  }
728
- let s = new Set(o.rpcTags.map(lt).filter((e) => e !== void 0));
947
+ let s = new Set(o.rpcTags.map(ut).filter((e) => e !== void 0));
729
948
  for (let e of s) {
730
949
  let t = i.get(e);
731
950
  t !== void 0 && a.push({
@@ -738,12 +957,12 @@ var le = /* @__PURE__ */ new Set([
738
957
  }
739
958
  }
740
959
  return a;
741
- }, dt = (e, t) => {
960
+ }, ft = (e, t) => {
742
961
  let n = e.reduce((e, t) => e + t.tables.length, 0), r = [`plugin surface · ${e.length} plugin(s) contribute ${n} table(s)`];
743
962
  if (t.length === 0) return r.push(" ✓ no overlap with your own tables or rpc namespaces"), r;
744
963
  for (let e of t) r.push(` ${e.fatal ? "✗" : "⚠"} ${e.plugin} — ${e.detail}`), r.push(` ${e.fix}`);
745
964
  return r;
746
- }, ft = async (e) => {
965
+ }, pt = async (e) => {
747
966
  if (!await e.hasWorkflows().catch(() => !1)) return { kind: "not-applicable" };
748
967
  let t;
749
968
  try {
@@ -767,12 +986,12 @@ var le = /* @__PURE__ */ new Set([
767
986
  } finally {
768
987
  await t.close().catch(() => {});
769
988
  }
770
- }, pt = (e) => {
989
+ }, mt = (e) => {
771
990
  let t = Math.round(e / 6e4);
772
991
  if (t < 90) return `${t}m`;
773
992
  let n = Math.round(t / 60);
774
993
  return n < 48 ? `${n}h` : `${Math.round(n / 24)}d`;
775
- }, mt = (e) => {
994
+ }, ht = (e) => {
776
995
  if (e.kind === "not-applicable") return null;
777
996
  if (e.kind === "skipped") return `• stuck runs: NOT CHECKED — ${e.reason}\n This is the one doctor rule that reads the database rather than your source.
778
997
  Run it where the app's DB env vars are set, or ignore this line locally.`;
@@ -780,21 +999,21 @@ var le = /* @__PURE__ */ new Set([
780
999
  if (t.stalled.length === 0) n.push(`✓ stuck runs: none (${t.examined} live run(s) old enough to examine${t.waitingOnTimer > 0 ? `, ${t.waitingOnTimer} waiting on a durable timer` : ""}${t.alreadyReported > 0 ? `, ${t.alreadyReported} already reported` : ""})`);
781
1000
  else {
782
1001
  n.push(`✗ stuck runs: ${t.stalled.length} run(s) have made no progress`);
783
- for (let e of t.stalled.slice(0, 20)) n.push(` ${e.tag} ${e.runId} idle ${pt(e.idleMs)} ${e.reason}`);
1002
+ for (let e of t.stalled.slice(0, 20)) n.push(` ${e.tag} ${e.runId} idle ${mt(e.idleMs)} ${e.reason}`);
784
1003
  t.stalled.length > 20 && n.push(` … and ${t.stalled.length - 20} more`), n.push(" Nothing was changed — this is a SUSPICION, not a verdict. `awaiting-signal` usually means the sender never came.");
785
1004
  }
786
1005
  t.sawFullRunPage && n.push(" (the examined page filled up — more old runs exist than were read this pass)");
787
1006
  for (let e of t.failures) n.push(` ! could not examine ${e.subject}: ${e.detail}`);
788
1007
  return n.join("\n");
789
- }, ht = /(?:^|\n)\s*import\s+(?!type\s)[^;'"]*?from\s+['"]@voltro\/ui-shadcn(?:\/(?!tokens\.css)[^'"]+)?['"]/, gt = /@import\s+["']@voltro\/ui-shadcn\/tokens\.css["']|@import\s+["']tailwindcss["']|from\s+['"]@voltro\/ui-shadcn\/tokens\.css['"]|import\s+['"][^'"]*@voltro\/ui-shadcn\/tokens\.css['"]/, _t = (e) => {
1008
+ }, gt = /(?:^|\n)\s*import\s+(?!type\s)[^;'"]*?from\s+['"]@voltro\/ui-shadcn(?:\/(?!tokens\.css)[^'"]+)?['"]/, _t = /@import\s+["']@voltro\/ui-shadcn\/tokens\.css["']|@import\s+["']tailwindcss["']|from\s+['"]@voltro\/ui-shadcn\/tokens\.css['"]|import\s+['"][^'"]*@voltro\/ui-shadcn\/tokens\.css['"]/, vt = (e) => {
790
1009
  let t = [], n = [];
791
- for (let r of e) gt.test(r.source) ? n.push(r.path) : !r.path.endsWith(".css") && ht.test(r.source) && t.push(r.path);
1010
+ for (let r of e) _t.test(r.source) ? n.push(r.path) : !r.path.endsWith(".css") && gt.test(r.source) && t.push(r.path);
792
1011
  return {
793
1012
  kitImporters: t,
794
1013
  styleEntries: n
795
1014
  };
796
- }, vt = (e) => e.kitImporters.length > 0 && e.styleEntries.length === 0, yt = (e) => {
797
- if (!vt(e)) return [];
1015
+ }, yt = (e) => e.kitImporters.length > 0 && e.styleEntries.length === 0, bt = (e) => {
1016
+ if (!yt(e)) return [];
798
1017
  let t = e.kitImporters.slice(0, 5);
799
1018
  return [
800
1019
  `⚠ ui-shadcn: ${e.kitImporters.length} file(s) render kit components, and no CSS entry imports the kit's stylesheet.`,
@@ -813,7 +1032,7 @@ var le = /* @__PURE__ */ new Set([
813
1032
  " Or, if this app is not a kit app, import the unstyled control instead:",
814
1033
  " import { LocaleSwitcher } from '@voltro/i18n'"
815
1034
  ];
816
- }, bt = (e) => S(b(e, "app.config.ts")) || S(b(e, "app.config.js")), xt = (e) => {
1035
+ }, xt = (e) => S(b(e, "app.config.ts")) || S(b(e, "app.config.js")), St = (e) => {
817
1036
  let t = f(e), n = d(e);
818
1037
  return {
819
1038
  root: e,
@@ -822,22 +1041,22 @@ var le = /* @__PURE__ */ new Set([
822
1041
  apiBundle: n,
823
1042
  apiBundlePresent: S(n)
824
1043
  };
825
- }, St = [
1044
+ }, Ct = [
826
1045
  "Production `voltro serve` requires a precompiled serve bundle and never transpiles on demand.",
827
1046
  "Add a `voltro build .` step BEFORE `voltro serve .` in your Dockerfile / start script.",
828
1047
  "(Generated Dockerfiles from `voltro create-project` already do this.)"
829
- ].join("\n "), Ct = (e, t = !1) => {
830
- let n = xt(e);
831
- if (console.log(`voltro doctor — serve preflight for ${n.root}`), !bt(e)) return console.log("• no app.config found here — nothing to check (run against an app root)."), 0;
1048
+ ].join("\n "), wt = (e, t = !1) => {
1049
+ let n = St(e);
1050
+ if (console.log(`voltro doctor — serve preflight for ${n.root}`), !xt(e)) return console.log("• no app.config found here — nothing to check (run against an app root)."), 0;
832
1051
  console.log(`${n.serveBundlePresent ? "✓" : "✗"} serve bundle: ${n.serveBundlePresent ? "present" : "MISSING"} (${n.serveBundle})`), console.log(`${n.apiBundlePresent ? "✓" : "•"} api bundle: ${n.apiBundlePresent ? "present" : "absent"} (${n.apiBundle})`);
833
1052
  let r = process.env.NODE_ENV === "production";
834
1053
  if (n.serveBundlePresent) return console.log("✓ serve preflight: ready for `voltro serve`."), 0;
835
1054
  let i = t || r;
836
- return console.error(`${i ? "✗" : "•"} serve bundle missing — ${i ? "production `voltro serve` will FAIL." : "a non-production `voltro serve` still runs via tsx."}`), console.error(` ${St}`), +!!i;
837
- }, wt = (e) => {
1055
+ return console.error(`${i ? "✗" : "•"} serve bundle missing — ${i ? "production `voltro serve` will FAIL." : "a non-production `voltro serve` still runs via tsx."}`), console.error(` ${Ct}`), +!!i;
1056
+ }, Tt = (e) => {
838
1057
  let t = e.absPath.replace(/\.server\.(tsx?)$/, ".$1");
839
1058
  if (t !== e.absPath) return e.sources.get(t) ?? e.sources.get(t.replace(/\.ts$/, ".tsx"));
840
- }, Tt = (e, t, n) => {
1059
+ }, Et = (e, t, n) => {
841
1060
  let r = new Set(e), i = _(n), a = (e) => (/\.(tsx?|jsx?)$/.test(e) ? [e] : [
842
1061
  `${e}.ts`,
843
1062
  `${e}.tsx`,
@@ -863,7 +1082,7 @@ var le = /* @__PURE__ */ new Set([
863
1082
  r !== void 0 && o.push(r);
864
1083
  }
865
1084
  return o;
866
- }, s = /* @__PURE__ */ new Set(), c = e.filter((e) => zt.test(y(n, e))), l = new Set(c);
1085
+ }, s = /* @__PURE__ */ new Set(), c = e.filter((e) => Bt.test(y(n, e))), l = new Set(c);
867
1086
  for (; c.length > 0;) {
868
1087
  let e = c.shift();
869
1088
  if (!s.has(e)) {
@@ -876,11 +1095,11 @@ var le = /* @__PURE__ */ new Set([
876
1095
  let d = /* @__PURE__ */ new Set();
877
1096
  for (let e of s) l.has(e) || u.has(e) || d.add(e);
878
1097
  return d;
879
- }, M = (e) => e.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/(^|[^:])\/\/[^\n]*/g, "$1").replace(/'(?:[^'\\\n]|\\.)*'/g, "''").replace(/"(?:[^"\\\n]|\\.)*"/g, "\"\""), Et = (e, t) => (e.match(t) ?? []).length, N = (e, t) => e.getDescendantsOfKind(O.CallExpression).filter((e) => t.test(e.getExpression().getText())).length, Dt = (e, t) => {
1098
+ }, M = (e) => e.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/(^|[^:])\/\/[^\n]*/g, "$1").replace(/'(?:[^'\\\n]|\\.)*'/g, "''").replace(/"(?:[^"\\\n]|\\.)*"/g, "\"\""), Dt = (e, t) => (e.match(t) ?? []).length, N = (e, t) => e.getDescendantsOfKind(O.CallExpression).filter((e) => t.test(e.getExpression().getText())).length, Ot = (e, t) => {
880
1099
  if (e.src.includes(t)) return !0;
881
1100
  let n = t.replace(/^@voltro\/plugin-/, "");
882
1101
  return n !== t && N(e.file, RegExp(`^${n}Plugin$`)) > 0;
883
- }, Ot = (e, t) => {
1102
+ }, kt = (e, t) => {
884
1103
  let n = [], r = RegExp(`\\b${t}\\s*(?:<[^()]*>)?\\s*\\(`, "g"), i;
885
1104
  for (; (i = r.exec(e)) !== null;) {
886
1105
  let t = i.index + i[0].length, r = 1, a = t;
@@ -888,10 +1107,10 @@ var le = /* @__PURE__ */ new Set([
888
1107
  n.push(e.slice(t, a - 1));
889
1108
  }
890
1109
  return n;
891
- }, kt = (e, t) => {
1110
+ }, At = (e, t) => {
892
1111
  let n = t.getSymbol()?.getDeclarations()?.[0];
893
1112
  return n === void 0 ? [] : e.getDescendantsOfKind(O.Identifier).filter((e) => e.getSymbol()?.getDeclarations()?.[0] === n);
894
- }, At = /^(insert|insertMany|insertIgnore|update|updateMany|upsert|delete|deleteMany|hardDelete|patchJson)$/, jt = /^(notify|sendNotification|sendWebhook|dispatchWebhook|sendMail|trigger)\w*$/, Mt = (e, t) => {
1113
+ }, jt = /^(insert|insertMany|insertIgnore|update|updateMany|upsert|delete|deleteMany|hardDelete|patchJson)$/, Mt = /^(notify|sendNotification|sendWebhook|dispatchWebhook|sendMail|trigger)\w*$/, Nt = (e, t) => {
895
1114
  if (!E.isObjectLiteralExpression(e)) return;
896
1115
  let n = e.getProperty("handler");
897
1116
  if (n === void 0 || !E.isPropertyAssignment(n)) return;
@@ -903,17 +1122,17 @@ var le = /* @__PURE__ */ new Set([
903
1122
  if (i !== void 0) return i;
904
1123
  let a = t.getVariableDeclaration(r.getText())?.getInitializer();
905
1124
  if (a !== void 0 && (E.isArrowFunction(a) || E.isFunctionExpression(a))) return a;
906
- }, Nt = (e) => {
907
- let t = [jt], n = (E.isArrowFunction(e) || E.isFunctionExpression(e) || E.isFunctionDeclaration(e) ? e.getParameters() : [])[1];
1125
+ }, Pt = (e) => {
1126
+ let t = [Mt], n = (E.isArrowFunction(e) || E.isFunctionExpression(e) || E.isFunctionDeclaration(e) ? e.getParameters() : [])[1];
908
1127
  if (n === void 0) return t;
909
1128
  let r = n.getNameNode();
910
- if (E.isIdentifier(r)) return t.push(RegExp(`^${r.getText()}\\.publish$`)), t.push(RegExp(`^${r.getText()}\\.store\\.${At.source.replace(/^\^|\$$/g, "")}$`)), t;
1129
+ if (E.isIdentifier(r)) return t.push(RegExp(`^${r.getText()}\\.publish$`)), t.push(RegExp(`^${r.getText()}\\.store\\.${jt.source.replace(/^\^|\$$/g, "")}$`)), t;
911
1130
  if (E.isObjectBindingPattern(r)) for (let e of r.getElements()) {
912
1131
  let n = e.getPropertyNameNode()?.getText() ?? e.getName(), r = e.getName();
913
- n === "publish" && t.push(RegExp(`^${r}$`)), n === "store" && t.push(RegExp(`^${r}\\.${At.source.replace(/^\^|\$$/g, "")}$`));
1132
+ n === "publish" && t.push(RegExp(`^${r}$`)), n === "store" && t.push(RegExp(`^${r}\\.${jt.source.replace(/^\^|\$$/g, "")}$`));
914
1133
  }
915
1134
  return t;
916
- }, Pt = (e, t, n, r = 0, i = /* @__PURE__ */ new Set()) => {
1135
+ }, Ft = (e, t, n, r = 0, i = /* @__PURE__ */ new Set()) => {
917
1136
  let a = e.getDescendantsOfKind(O.CallExpression);
918
1137
  for (let e of a) {
919
1138
  let t = e.getExpression().getText();
@@ -928,10 +1147,10 @@ var le = /* @__PURE__ */ new Set([
928
1147
  let e = t.getVariableDeclaration(a)?.getInitializer();
929
1148
  return e !== void 0 && (E.isArrowFunction(e) || E.isFunctionExpression(e)) ? e : void 0;
930
1149
  })();
931
- if (o !== void 0 && Pt(o, t, [...n, ...Nt(o)], r + 1, i)) return !0;
1150
+ if (o !== void 0 && Ft(o, t, [...n, ...Pt(o)], r + 1, i)) return !0;
932
1151
  }
933
1152
  return !1;
934
- }, Ft = (e) => {
1153
+ }, It = (e) => {
935
1154
  let t = /* @__PURE__ */ new Set();
936
1155
  for (let n of e.values()) {
937
1156
  if (!/\bsetRowFilter\s*[<(]/.test(n)) continue;
@@ -939,19 +1158,19 @@ var le = /* @__PURE__ */ new Set([
939
1158
  if (e !== null) for (let n of e[1].matchAll(/['"`]([A-Za-z_][\w]*)['"`]/g)) t.add(n[1]);
940
1159
  }
941
1160
  return t;
942
- }, It = (e) => {
1161
+ }, Lt = (e) => {
943
1162
  if (!/\.(query|stream|mutation|action)\.server\.tsx?$/.test(e.path)) return !1;
944
- let t = Ft(e.sources);
1163
+ let t = It(e.sources);
945
1164
  return t.size === 0 || ![...e.src.matchAll(/\btable\s*:\s*['"`]([A-Za-z_][\w]*)['"`]/g)].map((e) => e[1]).some((e) => t.has(e)) ? !1 : /\b(eq|and|inSet)\s*\(/.test(e.src) || /\bwhere\s*:/.test(e.src);
946
- }, Lt = (e) => e.getDescendantsOfKind(O.CallExpression).filter((e) => e.getExpression().getText() === "defineSubscriber").some((t) => {
1165
+ }, Rt = (e) => e.getDescendantsOfKind(O.CallExpression).filter((e) => e.getExpression().getText() === "defineSubscriber").some((t) => {
947
1166
  let n = t.getArguments()[0];
948
1167
  if (n === void 0 || !E.isObjectLiteralExpression(n) || n.getProperty("once") !== void 0) return !1;
949
- let r = Mt(n, e);
950
- return r !== void 0 && Pt(r, e, Nt(r));
951
- }), Rt = (e) => e.getDescendantsOfKind(O.CallExpression).filter((e) => e.getExpression().getText() === "defineSubscriber").filter((e) => {
1168
+ let r = Nt(n, e);
1169
+ return r !== void 0 && Ft(r, e, Pt(r));
1170
+ }), zt = (e) => e.getDescendantsOfKind(O.CallExpression).filter((e) => e.getExpression().getText() === "defineSubscriber").filter((e) => {
952
1171
  let t = e.getArguments()[0];
953
1172
  return t !== void 0 && E.isObjectLiteralExpression(t) && t.getProperty("once") === void 0;
954
- }).length, zt = /\.(server|cron|workflow\.server|subscribe|reaction|outbox|startup|trigger|webhook|migration|seed)\.tsx?$/, Bt = (e, t) => {
1173
+ }).length, Bt = /\.(server|cron|workflow\.server|subscribe|reaction|outbox|startup|trigger|webhook|migration|seed)\.tsx?$/, Vt = (e, t) => {
955
1174
  let n;
956
1175
  try {
957
1176
  n = t.createSourceFile("/descriptor-scan.ts", e, { overwrite: !0 });
@@ -969,7 +1188,7 @@ var le = /* @__PURE__ */ new Set([
969
1188
  else if (E.isSpreadAssignment(t)) return;
970
1189
  return r;
971
1190
  }
972
- }, Vt = (e, t) => {
1191
+ }, Ht = (e, t) => {
973
1192
  let n = [], r = (e) => {
974
1193
  e !== void 0 && (E.isObjectLiteralExpression(e) ? n.push(e) : E.isParenthesizedExpression(e) && r(e.getExpression()));
975
1194
  };
@@ -983,7 +1202,7 @@ var le = /* @__PURE__ */ new Set([
983
1202
  if (n.some((e) => t.has(e))) for (let e of n) i.add(e);
984
1203
  }
985
1204
  return [...i];
986
- }, Ht = (e, t, n) => {
1205
+ }, Ut = (e, t, n) => {
987
1206
  let r = RegExp(`\\btable\\(\\s*['"\`]${e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}['"\`]`);
988
1207
  for (let [, i] of t) {
989
1208
  if (!r.test(i)) continue;
@@ -1003,7 +1222,9 @@ var le = /* @__PURE__ */ new Set([
1003
1222
  return i;
1004
1223
  }
1005
1224
  }
1006
- }, Ut = (e) => /\bNullOr\b|\bSchema\.Null\b|\bnullable\s*\(/.test(e), P = /\.(query|mutation|action|stream)\.server\.tsx?$/, Wt = [
1225
+ let i = le[e];
1226
+ return i === void 0 ? void 0 : new Set(i);
1227
+ }, Wt = (e) => /\bNullOr\b|\bSchema\.Null\b|\bnullable\s*\(/.test(e), P = /\.(query|mutation|action|stream)\.server\.tsx?$/, Gt = [
1007
1228
  "Id",
1008
1229
  "ID",
1009
1230
  "Hash",
@@ -1029,7 +1250,7 @@ var le = /* @__PURE__ */ new Set([
1029
1250
  "Comment",
1030
1251
  "Provider",
1031
1252
  "Format"
1032
- ], Gt = RegExp(`(?:${Wt.join("|")})$|_(?:${Wt.map((e) => e.toLowerCase()).join("|")})$`), Kt = [
1253
+ ], Kt = RegExp(`(?:${Gt.join("|")})$|_(?:${Gt.map((e) => e.toLowerCase()).join("|")})$`), qt = [
1033
1254
  {
1034
1255
  id: "hardcoded-framework-cookie",
1035
1256
  scope: "client",
@@ -1054,7 +1275,7 @@ var le = /* @__PURE__ */ new Set([
1054
1275
  if (!P.test(n)) return !1;
1055
1276
  let r = M(t);
1056
1277
  if (!(/\bsubject\s*\.\s*id\b/.test(r) && /\b(?:insert|update|upsert|insertMany|updateMany|insertRow|upsertRow|updateManyRow)\s*\(/.test(r)) || /\b(?:guard|guards|requireScope|requireAnyScope|assertCan|assertScope|requireAuth|Unauthenticated)\b/.test(r) || /[=!]==?\s*[^;\n]*\bsubject\s*\.\s*id\b|\bsubject\s*\.\s*id\b\s*[=!]==/.test(r)) return !1;
1057
- let i = wt(e);
1278
+ let i = Tt(e);
1058
1279
  if (i === void 0) return !1;
1059
1280
  let a = M(i);
1060
1281
  return /\binternal\s*:\s*true\b/.test(a) || /\bguards\s*:\s*\[/.test(a) || /\.guard\s*\(/.test(a) ? !1 : /\bopenAccess\s*:/.test(a);
@@ -1065,7 +1286,7 @@ var le = /* @__PURE__ */ new Set([
1065
1286
  scope: "server",
1066
1287
  smell: "raw fetch() for outbound HTTP on the server (no traceparent, no retry, and no SSRF guard where the URL is not a constant)",
1067
1288
  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",
1068
- match: ({ file: e, path: t, serverOnly: n }) => (zt.test(t) || n) && N(e, /^(?:globalThis\.|window\.|self\.)?fetch$/) > 0
1289
+ match: ({ file: e, path: t, serverOnly: n }) => (Bt.test(t) || n) && N(e, /^(?:globalThis\.|window\.|self\.)?fetch$/) > 0
1069
1290
  },
1070
1291
  {
1071
1292
  id: "form",
@@ -1100,7 +1321,7 @@ var le = /* @__PURE__ */ new Set([
1100
1321
  scope: "client",
1101
1322
  smell: "useMemo fanning in multiple subscriptions (hand-maintained dep array)",
1102
1323
  use: "useDerived — dependency-tracked, referentially stable",
1103
- match: ({ src: e }) => Et(e, /\buseSubscription\s*[(<]/g) >= 3 && Et(e, /\buseMemo\s*\(/g) >= 3
1324
+ match: ({ src: e }) => Dt(e, /\buseSubscription\s*[(<]/g) >= 3 && Dt(e, /\buseMemo\s*\(/g) >= 3
1104
1325
  },
1105
1326
  {
1106
1327
  id: "next-shim",
@@ -1132,7 +1353,7 @@ var le = /* @__PURE__ */ new Set([
1132
1353
  match: ({ file: e }) => e.getDescendantsOfKind(O.CallExpression).filter((e) => /(^|\.)useSubscription$/.test(e.getExpression().getText())).flatMap((e) => {
1133
1354
  let t = e.getFirstAncestorByKind(O.VariableDeclaration)?.getNameNode();
1134
1355
  return t === void 0 ? [] : E.isObjectBindingPattern(t) ? t.getElements().filter((e) => (e.getPropertyNameNode() ?? e.getNameNode()).getText() === "data").map((e) => e.getNameNode()) : [];
1135
- }).some((t) => kt(e, t).some((e) => {
1356
+ }).some((t) => At(e, t).some((e) => {
1136
1357
  let t = e.getParent();
1137
1358
  if (E.isBinaryExpression(t)) {
1138
1359
  let n = t.getOperatorToken().getText(), r = t.getLeft() === e ? t.getRight() : t.getLeft();
@@ -1183,7 +1404,7 @@ var le = /* @__PURE__ */ new Set([
1183
1404
  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)",
1184
1405
  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) => {
1185
1406
  let n = t[1];
1186
- return !/token|secret|credential|password|apikey|accesskey/i.test(n) || Gt.test(n) || /^vault/i.test(n) || /\.unique\s*\(/.test(e) ? !1 : !/\.encrypted\s*\(/.test(e);
1407
+ 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);
1187
1408
  }))
1188
1409
  },
1189
1410
  {
@@ -1193,7 +1414,7 @@ var le = /* @__PURE__ */ new Set([
1193
1414
  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",
1194
1415
  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) => {
1195
1416
  let n = t[1];
1196
- return !/token|secret|credential|password|apikey|accesskey/i.test(n) || Gt.test(n) || /^vault/i.test(n) ? !1 : /\.unique\s*\(/.test(e) && !/\.encrypted\s*\(/.test(e);
1417
+ 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);
1197
1418
  }))
1198
1419
  },
1199
1420
  {
@@ -1205,7 +1426,7 @@ var le = /* @__PURE__ */ new Set([
1205
1426
  if (!/\.mutation\.tsx?$/.test(e.path)) return !1;
1206
1427
  let t = /target\s*:\s*\{[^}]*\btable\s*:\s*['"`]([^'"`]+)['"`]/.exec(e.src)?.[1];
1207
1428
  if (t === void 0) return !1;
1208
- let n = Ht(t, e.sources, e.file.getProject());
1429
+ let n = Ut(t, e.sources, e.file.getProject());
1209
1430
  if (n === void 0 || n.size === 0) return !1;
1210
1431
  for (let t of e.file.getDescendantsOfKind(O.PropertyAssignment)) {
1211
1432
  if (t.getName() !== "input") continue;
@@ -1213,7 +1434,7 @@ var le = /* @__PURE__ */ new Set([
1213
1434
  if (e === void 0 || !E.isCallExpression(e) || !/\.Struct$/.test(e.getExpression().getText())) continue;
1214
1435
  let r = e.getArguments()[0];
1215
1436
  if (!(r === void 0 || !E.isObjectLiteralExpression(r))) {
1216
- for (let e of r.getProperties()) if (E.isPropertyAssignment(e) && n.has(e.getName()) && !Ut(e.getText())) return !0;
1437
+ for (let e of r.getProperties()) if (E.isPropertyAssignment(e) && n.has(e.getName()) && !Wt(e.getText())) return !0;
1217
1438
  }
1218
1439
  }
1219
1440
  return !1;
@@ -1226,11 +1447,11 @@ var le = /* @__PURE__ */ new Set([
1226
1447
  use: "add the field to the descriptor's `output` struct, or stop building it — `output` IS the serializer, so an undeclared key never reaches the caller",
1227
1448
  match: (e) => {
1228
1449
  if (!P.test(e.path)) return !1;
1229
- let t = wt(e);
1450
+ let t = Tt(e);
1230
1451
  if (t === void 0) return !1;
1231
- let n = Bt(t, e.file.getProject());
1452
+ let n = Vt(t, e.file.getProject());
1232
1453
  if (n === void 0 || n.length === 0) return !1;
1233
- let r = Vt(e.file, new Set(n));
1454
+ let r = Ht(e.file, new Set(n));
1234
1455
  return r === void 0 || r.length === 0 ? !1 : r.some((e) => !n.includes(e));
1235
1456
  }
1236
1457
  },
@@ -1239,14 +1460,14 @@ var le = /* @__PURE__ */ new Set([
1239
1460
  scope: "server",
1240
1461
  smell: "a *.subscribe.ts handler that WRITES or publishes with no `once:` (it runs on every replica, so the effect repeats once per replica)",
1241
1462
  use: "once: true on defineSubscriber — one INSERT-wins claim per change, fleet-wide (or `once: (event) => key` for a coarser key). A hand-rolled `insertIgnore` dedupe is this, written out.",
1242
- match: ({ file: e }) => Lt(e)
1463
+ match: ({ file: e }) => Rt(e)
1243
1464
  },
1244
1465
  {
1245
1466
  id: "row-filter-duplicated-by-hand",
1246
1467
  scope: "server",
1247
1468
  smell: "a handler that constrains a table your registered `setRowFilter` already constrains",
1248
1469
  use: "drop the hand-written predicate — the filter covers the query, the mutation, the stream AND the subscription delivery. Keep it only if this handler must be NARROWER than the filter, and say so in a comment (two identical predicates ANDed are as tight as one, so this is maintenance, not a leak)",
1249
- match: (e) => It(e)
1470
+ match: (e) => Lt(e)
1250
1471
  },
1251
1472
  {
1252
1473
  id: "mutation-tail-effect",
@@ -1311,7 +1532,7 @@ var le = /* @__PURE__ */ new Set([
1311
1532
  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",
1312
1533
  match: ({ file: e, testSources: t }) => N(e, /^setRowFilter$/) > 0 && ![...t.values()].some((e) => {
1313
1534
  let t = M(e);
1314
- return Ot(t, "makeTestContext").length > 0 && /\browFilter\b/.test(t);
1535
+ return kt(t, "makeTestContext").length > 0 && /\browFilter\b/.test(t);
1315
1536
  })
1316
1537
  },
1317
1538
  {
@@ -1321,14 +1542,14 @@ var le = /* @__PURE__ */ new Set([
1321
1542
  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",
1322
1543
  match: ({ src: e }) => /\.(getTime|toISOString)\s*\(\s*\)/.test(e) && /\.map\s*\(|=>\s*\(\{/.test(e) && /\bexport\s+default\b/.test(e)
1323
1544
  }
1324
- ], F = (e) => L(e), qt = (e, t) => {
1545
+ ], F = (e) => L(e), Jt = (e, t) => {
1325
1546
  let n = /* @__PURE__ */ new Set();
1326
1547
  for (let r of t) {
1327
1548
  let t = y(e, r), i = t.split(/[\\/]/)[0];
1328
1549
  n.add(i !== void 0 && i !== t ? i : ".");
1329
1550
  }
1330
1551
  return [...n].sort();
1331
- }, Jt = /\.(tsx?|jsx?)$/, I = /(^|\/)(node_modules|dist|build|\.framework|\.next|coverage)(\/|$)/, Yt = /(^|[\\/])[^\\/]*\.generated\.[cm]?[jt]sx?$|\.d\.[cm]?ts$/, Xt = (e, t = [], n = 0) => {
1552
+ }, Yt = /\.(tsx?|jsx?)$/, I = /(^|\/)(node_modules|dist|build|\.framework|\.next|coverage)(\/|$)/, Xt = /(^|[\\/])[^\\/]*\.generated\.[cm]?[jt]sx?$|\.d\.[cm]?ts$/, Zt = (e, t = [], n = 0) => {
1332
1553
  if (n > 12 || I.test(e)) return t;
1333
1554
  let r;
1334
1555
  try {
@@ -1340,8 +1561,8 @@ var le = /* @__PURE__ */ new Set([
1340
1561
  let r = v(e, i.name);
1341
1562
  if (i.isDirectory()) {
1342
1563
  if (i.name.startsWith(".")) continue;
1343
- Xt(r, t, n + 1);
1344
- } else je.test(i.name) && t.push(r);
1564
+ Zt(r, t, n + 1);
1565
+ } else Me.test(i.name) && t.push(r);
1345
1566
  }
1346
1567
  return t;
1347
1568
  }, L = (e, t = [], n = 0) => {
@@ -1359,10 +1580,10 @@ var le = /* @__PURE__ */ new Set([
1359
1580
  } catch {
1360
1581
  continue;
1361
1582
  }
1362
- a.isDirectory() ? L(r, t, n + 1) : Jt.test(i) && !/\.(test|spec)\./.test(i) && !Yt.test(i) && t.push(r);
1583
+ a.isDirectory() ? L(r, t, n + 1) : Yt.test(i) && !/\.(test|spec)\./.test(i) && !Xt.test(i) && t.push(r);
1363
1584
  }
1364
1585
  return t;
1365
- }, Zt = (e, t = [], n = 0) => {
1586
+ }, Qt = (e, t = [], n = 0) => {
1366
1587
  if (n > 12 || I.test(e)) return t;
1367
1588
  let r;
1368
1589
  try {
@@ -1377,16 +1598,16 @@ var le = /* @__PURE__ */ new Set([
1377
1598
  } catch {
1378
1599
  continue;
1379
1600
  }
1380
- a.isDirectory() ? Zt(r, t, n + 1) : Jt.test(i) && /\.(test|spec)\./.test(i) && t.push(r);
1601
+ a.isDirectory() ? Qt(r, t, n + 1) : Yt.test(i) && /\.(test|spec)\./.test(i) && t.push(r);
1381
1602
  }
1382
1603
  return t;
1383
- }, Qt = (e) => {
1604
+ }, $t = (e) => {
1384
1605
  let t = F(e);
1385
1606
  return {
1386
- dirs: qt(e, t),
1607
+ dirs: Jt(e, t),
1387
1608
  fileCount: t.length
1388
1609
  };
1389
- }, $t = (e) => {
1610
+ }, en = (e) => {
1390
1611
  let t = F(e);
1391
1612
  if (t.length === 0) return [];
1392
1613
  let n = new D({
@@ -1396,8 +1617,8 @@ var le = /* @__PURE__ */ new Set([
1396
1617
  for (let e of t) try {
1397
1618
  i.set(e, C(e, "utf8"));
1398
1619
  } catch {}
1399
- let a = Tt([...i.keys()], i, e), o = /* @__PURE__ */ new Map();
1400
- for (let t of Zt(e)) try {
1620
+ let a = Et([...i.keys()], i, e), o = /* @__PURE__ */ new Map();
1621
+ for (let t of Qt(e)) try {
1401
1622
  o.set(t, C(t, "utf8"));
1402
1623
  } catch {}
1403
1624
  for (let s of t) {
@@ -1417,34 +1638,34 @@ var le = /* @__PURE__ */ new Set([
1417
1638
  } catch {
1418
1639
  continue;
1419
1640
  }
1420
- for (let t of Kt) {
1421
- if (t.plugin !== void 0 && Dt(c, t.plugin) || !t.match(c)) continue;
1641
+ for (let t of qt) {
1642
+ if (t.plugin !== void 0 && Ot(c, t.plugin) || !t.match(c)) continue;
1422
1643
  let n = r.get(t.id) ?? [];
1423
1644
  n.push(y(e, s)), r.set(t.id, n);
1424
1645
  }
1425
1646
  }
1426
- return Kt.filter((e) => r.has(e.id)).map((e) => ({
1647
+ return qt.filter((e) => r.has(e.id)).map((e) => ({
1427
1648
  rule: e,
1428
1649
  files: r.get(e.id)
1429
1650
  })).sort((e, t) => t.files.length - e.files.length || e.rule.id.localeCompare(t.rule.id));
1430
- }, en = (e) => {
1651
+ }, tn = (e) => {
1431
1652
  let t = new D({
1432
1653
  useInMemoryFileSystem: !0,
1433
1654
  skipAddingFilesFromTsConfig: !0
1434
1655
  }), n = 0;
1435
1656
  for (let r of F(e)) if (/\.subscribe\.tsx?$/.test(r)) try {
1436
1657
  let e = t.createSourceFile(`/count${r.endsWith("x") ? ".tsx" : ".ts"}`, C(r, "utf8"), { overwrite: !0 });
1437
- n += Rt(e);
1658
+ n += zt(e);
1438
1659
  } catch {}
1439
1660
  return n;
1440
1661
  }, R = (e) => {
1441
- let t = Qt(e);
1662
+ let t = $t(e);
1442
1663
  return {
1443
1664
  root: e,
1444
1665
  scannedFiles: t.fileCount,
1445
1666
  scannedDirs: t.dirs,
1446
- subscribersWithoutOnce: en(e),
1447
- findings: $t(e).map(({ rule: e, files: t }) => ({
1667
+ subscribersWithoutOnce: tn(e),
1668
+ findings: en(e).map(({ rule: e, files: t }) => ({
1448
1669
  id: e.id,
1449
1670
  scope: e.scope,
1450
1671
  smell: e.smell,
@@ -1452,21 +1673,21 @@ var le = /* @__PURE__ */ new Set([
1452
1673
  files: t
1453
1674
  }))
1454
1675
  };
1455
- }, tn = 3, nn = .2, rn = 50, an = (e, t) => e >= rn && t > 0 && e / t >= nn, on = (e) => {
1676
+ }, nn = 3, rn = .2, an = 50, on = (e, t) => e >= an && t > 0 && e / t >= rn, sn = (e) => {
1456
1677
  let t = /* @__PURE__ */ new Map();
1457
1678
  for (let n of L(e)) try {
1458
1679
  t.set(y(e, n), C(n, "utf8"));
1459
1680
  } catch {}
1460
1681
  let n = /* @__PURE__ */ new Map();
1461
- for (let t of Xt(e)) try {
1682
+ for (let t of Zt(e)) try {
1462
1683
  n.set(y(e, t), C(t, "utf8"));
1463
1684
  } catch {}
1464
- let r = Me({
1685
+ let r = Ne({
1465
1686
  sources: t,
1466
1687
  envFiles: n
1467
1688
  });
1468
- r !== void 0 && (console.log(""), console.log(Ne(r)));
1469
- }, sn = (e) => {
1689
+ r !== void 0 && (console.log(""), console.log(Pe(r)));
1690
+ }, cn = (e) => {
1470
1691
  let t = R(e);
1471
1692
  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;
1472
1693
  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;
@@ -1478,12 +1699,12 @@ var le = /* @__PURE__ */ new Set([
1478
1699
  console.log(` [${e}]`);
1479
1700
  let i = [...r].sort((e, t) => e.files.length - t.files.length);
1480
1701
  for (let e of i) {
1481
- if (an(e.files.length, t.scannedFiles)) {
1702
+ if (on(e.files.length, t.scannedFiles)) {
1482
1703
  let n = Math.round(e.files.length / t.scannedFiles * 100);
1483
1704
  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.)");
1484
1705
  continue;
1485
1706
  }
1486
- let r = e.files.slice(0, tn).join(", "), i = e.files.length - tn;
1707
+ let r = e.files.slice(0, nn).join(", "), i = e.files.length - nn;
1487
1708
  i > 0 && (n += i);
1488
1709
  let a = i > 0 ? `, +${i} more` : "";
1489
1710
  console.log(` ${e.smell} \u2014 ${e.files.length} file(s): ${r}${a}`), console.log(` \u2192 ${e.use}`);
@@ -1496,25 +1717,25 @@ var le = /* @__PURE__ */ new Set([
1496
1717
  console.log(` \u24d8 ${t.subscribersWithoutOnce} subscriber(s) declare no \`once:\`; an effect was found in ${e}. The rule reads each subscriber's OWN file (its handler and the functions that file declares) and does not resolve imports — a write in another module is unexamined, not absent.`);
1497
1718
  }
1498
1719
  return console.log(" (See the \"Pick the SERVER primitive\" / \"Pick the CLIENT primitive\" rubrics in AGENTS.md / CLAUDE.md.)"), t.findings.length;
1499
- }, cn = "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.", ln = /export\s+const\s+renderMode\s*(?::[^=]+)?=\s*['"]([^'"]*)['"]/, un = /export\s+const\s+dynamic\s*=\s*['"]force-(dynamic|static)['"]/, dn = (e) => {
1500
- let t = ln.exec(e)?.[1];
1720
+ }, ln = "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.", un = /export\s+const\s+renderMode\s*(?::[^=]+)?=\s*['"]([^'"]*)['"]/, dn = /export\s+const\s+dynamic\s*=\s*['"]force-(dynamic|static)['"]/, fn = (e) => {
1721
+ let t = un.exec(e)?.[1];
1501
1722
  if (t !== void 0) return t === "ssr" ? "ssr" : null;
1502
- let n = un.exec(e)?.[1];
1723
+ let n = dn.exec(e)?.[1];
1503
1724
  return n === "dynamic" ? "ssr" : n === "static" ? null : "default";
1504
1725
  }, z = async (e) => {
1505
1726
  let t = v(e, "src", "pages");
1506
1727
  if (!S(t)) return [];
1507
- let { pages: n, dirs: r } = await s(t), i = [];
1728
+ let { pages: n, dirs: r } = await a(t), i = [];
1508
1729
  for (let a of n) {
1509
- if (!l(r, a.dirChain).some((e) => e.hasLayout)) continue;
1730
+ if (!u(r, a.dirChain).some((e) => e.hasLayout)) continue;
1510
1731
  let n;
1511
1732
  try {
1512
1733
  n = C(v(t, a.file), "utf8");
1513
1734
  } catch {
1514
1735
  continue;
1515
1736
  }
1516
- if (c.test(n)) continue;
1517
- let o = dn(n);
1737
+ if (l.test(n)) continue;
1738
+ let o = fn(n);
1518
1739
  o !== null && i.push({
1519
1740
  file: y(e, v(t, a.file)),
1520
1741
  pattern: a.pattern,
@@ -1522,19 +1743,19 @@ var le = /* @__PURE__ */ new Set([
1522
1743
  });
1523
1744
  }
1524
1745
  return i;
1525
- }, fn = 10, pn = async (e) => {
1746
+ }, pn = 10, B = async (e) => {
1526
1747
  console.log("");
1527
1748
  let t = v(e, "src", "pages");
1528
1749
  if (!S(t)) return console.log("• spa-candidate scan: no src/pages here — nothing to check (web apps only)."), 0;
1529
1750
  let n = await z(e);
1530
1751
  if (n.length === 0) return console.log("✓ spa-candidate scan: no loader-free, layout-backed pages to flag."), 0;
1531
1752
  console.log(`• renderMode:'spa' candidates (${n.length} page${n.length === 1 ? "" : "s"} — loader-free, under a layout, currently ssr/default):`);
1532
- for (let e of n.slice(0, fn)) {
1753
+ for (let e of n.slice(0, pn)) {
1533
1754
  let t = e.currentMode === "ssr" ? "renderMode:'ssr'" : "default renderMode";
1534
1755
  console.log(` ${e.file} (${e.pattern}) — ${t}`);
1535
1756
  }
1536
- let r = n.length - fn;
1537
- return r > 0 && console.log(` (+${r} more page${r === 1 ? "" : "s"} not shown — \`voltro doctor --json\` prints every one.)`), console.log(` → ${cn}`), n.length;
1757
+ let r = n.length - pn;
1758
+ return r > 0 && console.log(` (+${r} more page${r === 1 ? "" : "s"} not shown — \`voltro doctor --json\` prints every one.)`), console.log(` → ${ln}`), n.length;
1538
1759
  }, mn = /* @__PURE__ */ new Set([
1539
1760
  "node_modules",
1540
1761
  "dist",
@@ -1583,7 +1804,7 @@ var le = /* @__PURE__ */ new Set([
1583
1804
  }, _n = (e, t) => {
1584
1805
  let n = e.slice(t.length).split(x).slice(0, -1)[0];
1585
1806
  return n !== void 0 && n.startsWith("[");
1586
- }, B = (e) => {
1807
+ }, V = (e) => {
1587
1808
  let t = [], n = v(e, "src", "pages"), r = v(e, "src");
1588
1809
  if (!S(r)) return t;
1589
1810
  let i = [];
@@ -1617,7 +1838,7 @@ var le = /* @__PURE__ */ new Set([
1617
1838
  });
1618
1839
  }
1619
1840
  return t;
1620
- }, vn = 10, V = (e, t, n) => {
1841
+ }, vn = 10, H = (e, t, n) => {
1621
1842
  if (t.length === 0) return;
1622
1843
  console.log(`• ${e} (${t.length}):`);
1623
1844
  for (let e of t.slice(0, vn)) console.log(` ${e}`);
@@ -1627,15 +1848,15 @@ var le = /* @__PURE__ */ new Set([
1627
1848
  console.log("");
1628
1849
  let t = v(e, "src", "pages");
1629
1850
  if (!S(t)) return console.log("• page-convention scan: no src/pages here — nothing to check (web apps only)."), 0;
1630
- let n = B(e);
1851
+ let n = V(e);
1631
1852
  if (n.length === 0) return console.log("✓ page-convention scan: every route is a page.tsx in its own directory, with a test beside it."), 0;
1632
1853
  let r = (e) => n.filter((t) => t.kind === e).map((e) => e.file);
1633
- return V("will NEVER route — page.tsx outside src/pages/", r("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."), V("pages with no test beside them", r("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."), V("routes whose FIRST segment is dynamic — they claim every URL of that depth", r("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."), V("pages with no `meta` export — they serve the APP name as their title", r("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."), n.length;
1634
- }, bn = "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.", xn = /* @__PURE__ */ new Map(), H = (e) => {
1854
+ return H("will NEVER route — page.tsx outside src/pages/", r("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."), H("pages with no test beside them", r("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."), H("routes whose FIRST segment is dynamic — they claim every URL of that depth", r("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."), H("pages with no `meta` export — they serve the APP name as their title", r("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."), n.length;
1855
+ }, bn = "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.", xn = /* @__PURE__ */ new Map(), U = (e) => {
1635
1856
  let t = xn.get(e);
1636
1857
  if (t !== void 0) return t;
1637
1858
  let n = (async () => {
1638
- let { walk: t, loadDiscovered: n } = await import("./dev-Bl9HqtV7.js"), r = await t(e);
1859
+ let { walk: t, loadDiscovered: n } = await import("./dev-Dff_pdik.js"), r = await t(e);
1639
1860
  return {
1640
1861
  files: r,
1641
1862
  discovered: await n(r, { root: e })
@@ -1645,7 +1866,7 @@ var le = /* @__PURE__ */ new Set([
1645
1866
  }, Sn = async (e) => {
1646
1867
  let t;
1647
1868
  try {
1648
- let { files: n, discovered: r } = await H(e), i = r.tables.map((e) => {
1869
+ let { files: n, discovered: r } = await U(e), i = r.tables.map((e) => {
1649
1870
  let t = e;
1650
1871
  return {
1651
1872
  name: t.tableName,
@@ -1653,7 +1874,7 @@ var le = /* @__PURE__ */ new Set([
1653
1874
  };
1654
1875
  });
1655
1876
  if (i.length === 0) return;
1656
- t = pe(fe(n, i, e));
1877
+ t = me(pe(n, i, e));
1657
1878
  } catch {
1658
1879
  return;
1659
1880
  }
@@ -1670,7 +1891,7 @@ var le = /* @__PURE__ */ new Set([
1670
1891
  };
1671
1892
  }), wn = async (e) => {
1672
1893
  try {
1673
- let { missingRelationSources: t } = await import("./doctorSourceRelations-c5mlN5HI.js"), { sourceKeys: n } = await import("@voltro/protocol"), { readFile: r } = await import("node:fs/promises"), { discovered: i } = await H(e), a = [], o = [];
1894
+ let { missingRelationSources: t } = await import("./doctorSourceRelations-c5mlN5HI.js"), { sourceKeys: n } = await import("@voltro/protocol"), { readFile: r } = await import("node:fs/promises"), { discovered: i } = await U(e), a = [], o = [];
1674
1895
  for (let e of i.queries) {
1675
1896
  let i = n(e.descriptor.source);
1676
1897
  if (i.length === 0) continue;
@@ -1705,22 +1926,22 @@ var le = /* @__PURE__ */ new Set([
1705
1926
  for (let e of t.unresolved) console.log(` ${e.procedure}: ${e.relations.map((e) => `\`${e}\``).join(", ")} resolved against no table`);
1706
1927
  console.log(" declare the base table in `source:` and re-run — relations under it are unchecked until then.");
1707
1928
  }
1708
- }, U = async (e) => {
1929
+ }, W = async (e) => {
1709
1930
  try {
1710
- let { discovered: t } = await H(e);
1711
- return ve(Cn(t.tables));
1931
+ let { discovered: t } = await U(e);
1932
+ return ye(Cn(t.tables));
1712
1933
  } catch {
1713
1934
  return null;
1714
1935
  }
1715
1936
  }, Dn = async (e) => {
1716
- let t = await U(e);
1937
+ let t = await W(e);
1717
1938
  if (t === null || t.tablesChecked === 0) return;
1718
- let n = be(t);
1939
+ let n = xe(t);
1719
1940
  n !== null && (console.log(""), console.log(`${t.issues.length > 0 ? "✗" : "✓"} ${n}`));
1720
- }, W = async (e) => {
1941
+ }, G = async (e) => {
1721
1942
  try {
1722
- let { payloadPropertyNames: t } = await import("@voltro/runtime"), { discovered: n } = await H(e);
1723
- return we(n.events.map((e) => {
1943
+ let { payloadPropertyNames: t } = await import("@voltro/runtime"), { discovered: n } = await U(e);
1944
+ return Te(n.events.map((e) => {
1724
1945
  let n = e.descriptor, r = t(n.key);
1725
1946
  return {
1726
1947
  name: n.name,
@@ -1733,18 +1954,18 @@ var le = /* @__PURE__ */ new Set([
1733
1954
  return null;
1734
1955
  }
1735
1956
  }, On = async (e) => {
1736
- let t = await W(e);
1957
+ let t = await G(e);
1737
1958
  if (t === null || t.eventsChecked === 0) return;
1738
- let n = Te(t);
1959
+ let n = Ee(t);
1739
1960
  n !== null && (console.log(""), console.log(`• ${n}`));
1740
- let r = Ee(t);
1961
+ let r = De(t);
1741
1962
  r !== null && (console.log(""), console.log(`⚠️ ${r}`));
1742
- }, G = (e) => {
1963
+ }, K = (e) => {
1743
1964
  let t = e, n = typeof t?.message == "string" && t.message !== "" ? t.message : String(e), r = typeof t?.code == "string" ? t.code : void 0;
1744
1965
  return r === void 0 ? n : `${r}: ${n}`;
1745
- }, K = async (e) => {
1966
+ }, q = async (e) => {
1746
1967
  try {
1747
- let { formatServerOnlyLeaks: t } = await import("@voltro/runtime"), n = (await H(e)).discovered.serverOnlyLeaks, r = t(n);
1968
+ let { formatServerOnlyLeaks: t } = await import("@voltro/runtime"), n = (await U(e)).discovered.serverOnlyLeaks, r = t(n);
1748
1969
  return {
1749
1970
  status: {
1750
1971
  checked: !0,
@@ -1755,12 +1976,12 @@ var le = /* @__PURE__ */ new Set([
1755
1976
  } catch (e) {
1756
1977
  return { status: {
1757
1978
  checked: !1,
1758
- reason: G(e)
1979
+ reason: K(e)
1759
1980
  } };
1760
1981
  }
1761
- }, q = async (r) => {
1982
+ }, J = async (r) => {
1762
1983
  try {
1763
- let { loadApiConfig: i } = await import("./dev-Bl9HqtV7.js"), { discovered: a } = await H(r), o = n(await i(r)), s = {
1984
+ let { loadApiConfig: i } = await import("./dev-Dff_pdik.js"), { discovered: a } = await U(r), o = e(await i(r)), s = {
1764
1985
  queries: a.queries,
1765
1986
  mutations: a.mutations,
1766
1987
  actions: a.actions,
@@ -1770,20 +1991,20 @@ var le = /* @__PURE__ */ new Set([
1770
1991
  return {
1771
1992
  checked: !0,
1772
1993
  defaultDeny: o,
1773
- undecided: t(s),
1774
- openAccess: e(s)
1994
+ undecided: n(s),
1995
+ openAccess: t(s)
1775
1996
  };
1776
1997
  } catch (e) {
1777
1998
  return {
1778
1999
  checked: !1,
1779
- reason: G(e),
2000
+ reason: K(e),
1780
2001
  defaultDeny: !0,
1781
2002
  undecided: [],
1782
2003
  openAccess: []
1783
2004
  };
1784
2005
  }
1785
2006
  }, kn = async (e) => {
1786
- let t = await q(e);
2007
+ let t = await J(e);
1787
2008
  if (!t.checked) return console.log(""), console.log("• access decisions: NOT CHECKED — the app's descriptors could not be loaded (not a pass)"), console.log(` reason: ${t.reason ?? "unknown"}`), !1;
1788
2009
  console.log(""), console.log(`access decisions · security.defaultDeny ${t.defaultDeny ? "ON" : "OFF"}`), console.log(` ✗ no access decision ${String(t.undecided.length).padStart(4)}`), console.log(` ✓ openAccess, declared on purpose ${String(t.openAccess.length).padStart(4)}`);
1789
2010
  for (let e of t.openAccess) console.log(` ${e.tag} — ${e.openAccess ?? ""}`);
@@ -1793,9 +2014,9 @@ var le = /* @__PURE__ */ new Set([
1793
2014
  return console.log(""), t.defaultDeny ? (console.log(" `voltro dev` and `voltro serve` REFUSE to boot on these. Give each a decision:"), An(), !0) : (console.log(" This app sets `security: { defaultDeny: false }`, so these BOOT — and each one is"), console.log(" callable by any authenticated session. Advisory here for that reason only."), An(), !1);
1794
2015
  }, An = () => {
1795
2016
  console.log(" `guards: [{ scope: '…' }]` authority the SUBJECT holds globally"), console.log(" `guards: [{ action, resourceType, resource }]` authority per ROW / per resource"), console.log(" — backed by `defineResourcePolicy` + a tuple source you register. If your"), console.log(" relationships already live in your own tables (a `teamMembers` row), register"), console.log(" a tuple source over them; nothing is copied. Fail-closed without a resolver."), console.log(" Docs: Authentication → Authorization."), console.log(" `openAccess: '<why anyone may call it>'` deliberately unauthenticated");
1796
- }, J = async (e) => {
2017
+ }, Y = async (e) => {
1797
2018
  try {
1798
- let { files: t } = await H(e), { WEBHOOK_PATTERN: n, loadWebhookFiles: r } = await import("./webhookDiscovery-il9ti-HE.js"), { incomingWebhookVerification: i } = await import("@voltro/plugin-webhooks"), a = t.filter((e) => n.test(ie(e)));
2019
+ let { files: t } = await U(e), { WEBHOOK_PATTERN: n, loadWebhookFiles: r } = await import("./webhookDiscovery-il9ti-HE.js"), { incomingWebhookVerification: i } = await import("@voltro/plugin-webhooks"), a = t.filter((e) => n.test(ie(e)));
1799
2020
  if (a.length === 0) return {
1800
2021
  checked: !0,
1801
2022
  unverified: [],
@@ -1822,14 +2043,14 @@ var le = /* @__PURE__ */ new Set([
1822
2043
  } catch (e) {
1823
2044
  return {
1824
2045
  checked: !1,
1825
- reason: G(e),
2046
+ reason: K(e),
1826
2047
  unverified: [],
1827
2048
  open: [],
1828
2049
  verified: 0
1829
2050
  };
1830
2051
  }
1831
2052
  }, jn = async (e) => {
1832
- let t = await J(e);
2053
+ let t = await Y(e);
1833
2054
  if (!t.checked) return console.log(""), console.log("• webhook verification: NOT CHECKED — the app's webhooks could not be loaded (not a pass)"), console.log(` reason: ${t.reason ?? "unknown"}`), !1;
1834
2055
  if (t.verified + t.open.length + t.unverified.length === 0) return !1;
1835
2056
  console.log(""), console.log("incoming webhook verification"), console.log(` ✓ signature / provider verified ${String(t.verified).padStart(4)}`), console.log(` ! deliberately public (none) ${String(t.open.length).padStart(4)}`), console.log(` ✗ nothing verifies the caller ${String(t.unverified.length).padStart(4)}`);
@@ -1839,12 +2060,12 @@ var le = /* @__PURE__ */ new Set([
1839
2060
  for (let e of t.unverified) console.log(` ✗ ${e.id}\n ${e.file}`);
1840
2061
  return console.log(""), console.log(" These are public POSTs that run your application code, and `voltro dev` /"), console.log(" `voltro serve` REFUSE to mount them. Declare one of: `provider:` (a preset),"), console.log(" `signature:` (your own HMAC scheme), `verification: 'provider'` (your handler"), console.log(" verifies), or `verification: 'none'` (deliberately public)."), !0;
1841
2062
  }, Mn = async (e) => {
1842
- let { status: t, message: n } = await K(e);
2063
+ let { status: t, message: n } = await q(e);
1843
2064
  return t.checked ? n !== void 0 && (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);
1844
- }, Nn = async (e) => ft({
1845
- hasWorkflows: async () => (await H(e)).discovered.workflows.length > 0,
2065
+ }, Nn = async (e) => pt({
2066
+ hasWorkflows: async () => (await U(e)).discovered.workflows.length > 0,
1846
2067
  openStore: async () => {
1847
- let { loadApiConfig: t, buildStore: n } = await import("./dev-Bl9HqtV7.js"), r = await t(e);
2068
+ let { loadApiConfig: t, buildStore: n } = await import("./dev-Dff_pdik.js"), r = await t(e);
1848
2069
  if (r === null) throw Error("no app.config.ts in this directory");
1849
2070
  let i = await n(r, void 0);
1850
2071
  return {
@@ -1859,13 +2080,13 @@ var le = /* @__PURE__ */ new Set([
1859
2080
  return t({ store: e });
1860
2081
  }
1861
2082
  }), Pn = async (e) => {
1862
- let t = mt(await Nn(e));
2083
+ let t = ht(await Nn(e));
1863
2084
  t !== null && (console.log(""), console.log(t));
1864
2085
  }, Fn = async (e) => {
1865
2086
  let t;
1866
2087
  try {
1867
- let { payloadPropertyNames: n } = await import("@voltro/runtime"), { files: r, discovered: i } = await H(e);
1868
- t = ke(r, i.workflows.map((e) => {
2088
+ let { payloadPropertyNames: n } = await import("@voltro/runtime"), { files: r, discovered: i } = await U(e);
2089
+ t = Ae(r, i.workflows.map((e) => {
1869
2090
  let t = e.definition, r = t.payloadSchema === void 0 ? {
1870
2091
  required: [],
1871
2092
  optional: []
@@ -1879,23 +2100,23 @@ var le = /* @__PURE__ */ new Set([
1879
2100
  } catch {
1880
2101
  return;
1881
2102
  }
1882
- let n = Ae(t);
2103
+ let n = je(t);
1883
2104
  if (n === null) return;
1884
2105
  console.log("");
1885
2106
  let r = t.issues.length > 0 ? "✗" : t.unchecked.length > 0 ? "•" : "✓";
1886
2107
  console.log(`${r} ${n}`);
1887
- }, Y = "voltro-authz-allowlist.txt", In = (e, t = (e) => {
2108
+ }, X = "voltro-authz-allowlist.txt", In = (e, t = (e) => {
1888
2109
  try {
1889
2110
  return C(e, "utf8");
1890
2111
  } catch {
1891
2112
  return "";
1892
2113
  }
1893
- }) => /* @__PURE__ */ new Set([...Xe, ...Ze(L(e).map(t))]), X = (e, t) => {
2114
+ }) => /* @__PURE__ */ new Set([...Ze, ...Qe(L(e).map(t))]), Ln = (e, t) => {
1894
2115
  let n = t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1895
2116
  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];
1896
2117
  }, Z = async (e) => {
1897
2118
  try {
1898
- let { discovered: t } = await H(e), n = t.events.map((e) => ({
2119
+ let { discovered: t } = await U(e), n = t.events.map((e) => ({
1899
2120
  name: e.descriptor.name,
1900
2121
  file: e.file
1901
2122
  })).filter((e) => typeof e.name == "string");
@@ -1909,22 +2130,22 @@ var le = /* @__PURE__ */ new Set([
1909
2130
  }, a = L(e).filter((e) => !r.has(e)).map(i).join("\n");
1910
2131
  return n.filter(({ name: e, file: t }) => {
1911
2132
  if (a.includes(e)) return !1;
1912
- let n = X(i(t), e);
2133
+ let n = Ln(i(t), e);
1913
2134
  return n === void 0 || !new RegExp(String.raw`\b${n}\b`).test(a);
1914
2135
  }).map((e) => e.name).sort();
1915
2136
  } catch {
1916
2137
  return [];
1917
2138
  }
1918
- }, Ln = async (e) => {
2139
+ }, Rn = async (e) => {
1919
2140
  let t = await Z(e);
1920
2141
  if (t.length !== 0) {
1921
2142
  console.log(""), console.log(`• ${t.length} declared event(s) with no emit call site found:`);
1922
2143
  for (let e of t) console.log(` ${e}`);
1923
2144
  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.");
1924
2145
  }
1925
- }, Rn = async (e) => {
2146
+ }, zn = async (e) => {
1926
2147
  try {
1927
- let { loadApiConfig: t } = await import("./dev-Bl9HqtV7.js"), n = (await t(e))?.doctor?.scopeVocabulary;
2148
+ let { loadApiConfig: t } = await import("./dev-Dff_pdik.js"), n = (await t(e))?.doctor?.scopeVocabulary;
1928
2149
  if (typeof n != "string") return [];
1929
2150
  let [r, i] = n.split("#");
1930
2151
  if (r === void 0 || i === void 0) return [];
@@ -1941,7 +2162,7 @@ var le = /* @__PURE__ */ new Set([
1941
2162
  findings: []
1942
2163
  });
1943
2164
  try {
1944
- let { offlineManifest: n, toInput: r } = await import("./checkCommand-BISqx1OJ.js"), { buildAppGraph: i, checkAppGraph: a } = await import("./appGraph-CFmFKHb2.js"), o = await n(e), s = r(o.manifest, o.tables), c = await Rn(e), l = [.../* @__PURE__ */ new Set([...s.scopes ?? [], ...c])];
2165
+ let { offlineManifest: n, toInput: r } = await import("./checkCommand-C1EbNmwl.js"), { buildAppGraph: i, checkAppGraph: a } = await import("./appGraph-CFmFKHb2.js"), o = await n(e), s = r(o.manifest, o.tables), c = await zn(e), l = [.../* @__PURE__ */ new Set([...s.scopes ?? [], ...c])];
1945
2166
  if (l.length === 0) {
1946
2167
  try {
1947
2168
  let { loadAppSchemaInputs: t } = await import("./frameworkTableAssembly-B96WCNJA.js");
@@ -1968,7 +2189,7 @@ var le = /* @__PURE__ */ new Set([
1968
2189
  } catch {
1969
2190
  return t("app-not-importable");
1970
2191
  }
1971
- }, zn = async (e) => {
2192
+ }, Bn = async (e) => {
1972
2193
  let { findings: t, evaluated: n, notEvaluated: r } = await Q(e);
1973
2194
  if (!n) {
1974
2195
  if (console.log(""), r === "app-not-importable") {
@@ -1983,7 +2204,7 @@ var le = /* @__PURE__ */ new Set([
1983
2204
  for (let e of t) console.log(` ${e.node}${e.file === void 0 ? "" : ` ${e.file}`}`), console.log(` ${e.detail}`);
1984
2205
  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}`);
1985
2206
  }
1986
- }, Bn = (e) => {
2207
+ }, Vn = (e) => {
1987
2208
  let t = v(e, "src");
1988
2209
  if (!S(t)) return;
1989
2210
  let n = [], r = (t, i = 0) => {
@@ -2014,12 +2235,12 @@ var le = /* @__PURE__ */ new Set([
2014
2235
  }
2015
2236
  };
2016
2237
  r(t);
2017
- let i = yt(_t(n));
2238
+ let i = bt(vt(n));
2018
2239
  if (i.length !== 0) {
2019
2240
  console.log("");
2020
2241
  for (let e of i) console.log(e);
2021
2242
  }
2022
- }, Vn = async (e) => {
2243
+ }, Hn = async (e) => {
2023
2244
  let t = ["src/locales", "locales"], n, r = [];
2024
2245
  for (let i of t) {
2025
2246
  let t = v(e, i);
@@ -2031,20 +2252,20 @@ var le = /* @__PURE__ */ new Set([
2031
2252
  if (n === void 0 || r.length === 0) return;
2032
2253
  let i = [];
2033
2254
  try {
2034
- let { loadApiConfig: t } = await import("./dev-Bl9HqtV7.js");
2255
+ let { loadApiConfig: t } = await import("./dev-Dff_pdik.js");
2035
2256
  i = (await t(e))?.locales ?? [];
2036
2257
  } catch {
2037
2258
  return;
2038
2259
  }
2039
- let a = We({
2260
+ let a = Ge({
2040
2261
  catalogCodes: r,
2041
2262
  declaredLocales: i
2042
2263
  });
2043
2264
  if (a !== void 0) {
2044
2265
  console.log("");
2045
- for (let e of Ge(a, n)) console.log(e);
2266
+ for (let e of Ke(a, n)) console.log(e);
2046
2267
  }
2047
- }, Hn = async (e) => {
2268
+ }, Un = async (e) => {
2048
2269
  let t = v(e, "src");
2049
2270
  if (!S(t)) return;
2050
2271
  let n = !1, r = (e) => {
@@ -2063,9 +2284,9 @@ var le = /* @__PURE__ */ new Set([
2063
2284
  return;
2064
2285
  }
2065
2286
  a()?.reason === "binary-missing" ? (console.log("image pipeline: sharp is INSTALLED but its platform binary is missing —"), console.log(" an install that omitted optional dependencies drops the @img/* prebuilds."), console.log(" Fix: reinstall without omitting optional deps, or `pnpm add -D sharp` in this app.")) : (console.log("image pipeline: sharp is NOT installed — ?image imports serve originals (no srcSet, no blur)."), console.log(" Fix: `pnpm add -D sharp` in this app (it is an optional dependency of @voltro/cli;"), console.log(" your installer skipped optional dependencies)."));
2066
- }, Un = async (e) => {
2287
+ }, Wn = async (e) => {
2067
2288
  try {
2068
- let { loadConfig: t } = await import("./webDev-B6ZMX42w.js"), n = (await t(e, { preferSource: !0 }))?.fonts;
2289
+ let { loadConfig: t } = await import("./webDev-Bzb8ZFus.js"), n = (await t(e, { preferSource: !0 }))?.fonts;
2069
2290
  if (n === void 0 || n.length === 0) return;
2070
2291
  let { loadFontkit: r, loadSubsetFont: i } = await import("./fontPipeline-LxIHa1vo.js"), a = [];
2071
2292
  if (await r() === null && a.push("fontkit (size-adjust fallback metrics — the CLS guard — are skipped)"), await i() === null && a.push("subset-font (declared `subsets:` ship the full files)"), console.log(""), a.length === 0) {
@@ -2075,25 +2296,25 @@ var le = /* @__PURE__ */ new Set([
2075
2296
  for (let e of a) console.log(`font pipeline: ${e}`);
2076
2297
  console.log(" Fix: reinstall without omitting optional deps, or `pnpm add -D fontkit subset-font` in this app.");
2077
2298
  } catch {}
2078
- }, Wn = async (e) => {
2299
+ }, Gn = async (e) => {
2079
2300
  let t = v(e, "src", "pages");
2080
2301
  if (!S(t)) return !1;
2081
2302
  let n = [];
2082
2303
  try {
2083
- let { walkPagesTree: e } = await import("./webDev-B6ZMX42w.js");
2304
+ let { walkPagesTree: e } = await import("./webDev-Bzb8ZFus.js");
2084
2305
  n = (await e(t)).pages.map((e) => e.pattern);
2085
2306
  } catch {
2086
2307
  return !1;
2087
2308
  }
2088
- let r = qe(e, n);
2309
+ let r = Je(e, n);
2089
2310
  if (r === void 0) return !1;
2090
2311
  console.log("");
2091
- for (let e of Je(r)) console.log(e);
2312
+ for (let e of Ye(r)) console.log(e);
2092
2313
  return r.problems.length > 0;
2093
- }, Gn = async (e) => {
2094
- let { discovered: t } = await H(e), n = [];
2314
+ }, Kn = async (e) => {
2315
+ let { discovered: t } = await U(e), n = [];
2095
2316
  try {
2096
- let { loadApiConfig: t } = await import("./dev-Bl9HqtV7.js");
2317
+ let { loadApiConfig: t } = await import("./dev-Dff_pdik.js");
2097
2318
  n = ((await t(e))?.plugins ?? []).map((e) => {
2098
2319
  let t = (e.extendSchema?.tables ?? []).map((e) => {
2099
2320
  let t = e;
@@ -2106,8 +2327,8 @@ var le = /* @__PURE__ */ new Set([
2106
2327
  plugin: e.name,
2107
2328
  tables: t,
2108
2329
  rpcTags: n,
2109
- canDisableTables: Kn.has(r),
2110
- canAlias: qn.has(r)
2330
+ canDisableTables: qn.has(r),
2331
+ canAlias: Jn.has(r)
2111
2332
  };
2112
2333
  });
2113
2334
  } catch {
@@ -2119,18 +2340,18 @@ var le = /* @__PURE__ */ new Set([
2119
2340
  ...t.mutations,
2120
2341
  ...t.actions,
2121
2342
  ...t.streams ?? []
2122
- ].map((e) => String(e.descriptor.name)), i = ut(n, {
2343
+ ].map((e) => String(e.descriptor.name)), i = dt(n, {
2123
2344
  tables: t.tables.map((e) => e.tableName),
2124
2345
  rpcTags: r
2125
2346
  });
2126
2347
  console.log();
2127
- for (let e of dt(n, i)) console.log(e);
2128
- }, Kn = /* @__PURE__ */ new Set([
2348
+ for (let e of ft(n, i)) console.log(e);
2349
+ }, qn = /* @__PURE__ */ new Set([
2129
2350
  "@voltro/plugin-rbac",
2130
2351
  "@voltro/plugin-audit",
2131
2352
  "@voltro/plugin-notifications",
2132
2353
  "aiFlows"
2133
- ]), qn = /* @__PURE__ */ new Set([
2354
+ ]), Jn = /* @__PURE__ */ new Set([
2134
2355
  "aiFlows",
2135
2356
  "@voltro/plugin-audit",
2136
2357
  "@voltro/plugin-billing",
@@ -2148,8 +2369,8 @@ var le = /* @__PURE__ */ new Set([
2148
2369
  "@voltro/plugin-sso-saml",
2149
2370
  "@voltro/plugin-storage",
2150
2371
  "@voltro/plugin-row-history"
2151
- ]), $ = 20, Jn = async (e) => {
2152
- let t = await Yn(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;
2372
+ ]), $ = 20, Yn = async (e) => {
2373
+ let t = await Xn(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;
2153
2374
  return {
2154
2375
  executors: t.executorCount,
2155
2376
  guardVocabulary: [...t.vocabulary].sort(),
@@ -2161,8 +2382,8 @@ var le = /* @__PURE__ */ new Set([
2161
2382
  },
2162
2383
  unchecked: t.result.unchecked
2163
2384
  };
2164
- }, Yn = async (e) => {
2165
- let { discovered: t } = await H(e), n = /* @__PURE__ */ new Map(), r = (e) => {
2385
+ }, Xn = async (e) => {
2386
+ let { discovered: t } = await U(e), n = /* @__PURE__ */ new Map(), r = (e) => {
2166
2387
  if (!n.has(e)) try {
2167
2388
  n.set(e, C(e, "utf8"));
2168
2389
  } catch {
@@ -2201,12 +2422,12 @@ var le = /* @__PURE__ */ new Set([
2201
2422
  op: a?.op === "delete" || a?.op === "insert" ? a.op : t,
2202
2423
  ...a?.table === void 0 ? {} : { table: a.table }
2203
2424
  };
2204
- })), s = v(e, Y), c = S(s) ? j(C(s, "utf8")) : void 0, l = !1;
2425
+ })), s = v(e, X), c = S(s) ? j(C(s, "utf8")) : void 0, l = !1;
2205
2426
  for (let t of L(e)) if (/\bsetRowFilter\s*[<(]/.test(r(t))) {
2206
2427
  l = !0;
2207
2428
  break;
2208
2429
  }
2209
- let u = rt({
2430
+ let u = it({
2210
2431
  executors: o,
2211
2432
  guardVocabulary: i,
2212
2433
  tenantScopedTables: t.tenantScopedTables,
@@ -2223,23 +2444,23 @@ var le = /* @__PURE__ */ new Set([
2223
2444
  executorCount: o.length,
2224
2445
  allowPath: s
2225
2446
  };
2226
- }, Xn = async (e, t) => {
2227
- let { result: n, vocabulary: r, existing: i, reviewed: a, executorCount: o, allowPath: s, rowFilterRegistered: c } = await Yn(e), l = n.counts;
2447
+ }, Zn = async (e, t) => {
2448
+ let { result: n, vocabulary: r, existing: i, reviewed: a, executorCount: o, allowPath: s, rowFilterRegistered: c } = await Xn(e), l = n.counts;
2228
2449
  console.log(`\nauthz scan · ${o} executor(s)`);
2229
- let u = [...r].filter((e) => !Xe.has(e)).sort();
2450
+ let u = [...r].filter((e) => !Ze.has(e)).sort();
2230
2451
  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)}`);
2231
2452
  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;
2232
- if (console.log(` – accepted as recorded debt ${String(f).padStart(4)} (${Y})`), 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) {
2233
- let e = S(s) ? C(s, "utf8") : void 0, t = n.unchecked.map((e) => e.tag), r = st(e, t);
2234
- return oe(s, ot(e, t), "utf8"), console.log(`\n${Y}: +${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;
2453
+ if (console.log(` – accepted as recorded debt ${String(f).padStart(4)} (${X})`), 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) {
2454
+ let e = S(s) ? C(s, "utf8") : void 0, t = n.unchecked.map((e) => e.tag), r = ct(e, t);
2455
+ return oe(s, st(e, t), "utf8"), console.log(`\n${X}: +${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;
2235
2456
  }
2236
2457
  if (n.unchecked.length === 0) return !1;
2237
2458
  console.log("");
2238
2459
  for (let e of n.unchecked.slice(0, $)) console.log(` ✗ ${e.tag} — ${e.why}\n ${e.path}`);
2239
- 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 ${Y} 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 ${Y}.`), 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);
2240
- }, Zn = async (e) => {
2460
+ 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 ${X} 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 ${X}.`), 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);
2461
+ }, Qn = async (e) => {
2241
2462
  try {
2242
- let { loadApiConfig: t } = await import("./dev-Bl9HqtV7.js"), { decidedSchemaReport: n } = await import("./doctorDecidedSchema-BlbWgCD_.js"), r = await t(e);
2463
+ let { loadApiConfig: t } = await import("./dev-Dff_pdik.js"), { decidedSchemaReport: n } = await import("./doctorDecidedSchema-BlbWgCD_.js"), r = await t(e);
2243
2464
  return r == null ? null : n({
2244
2465
  ...r.schema ? { declared: r.schema } : {},
2245
2466
  ...r.store === void 0 ? {} : { store: r.store },
@@ -2248,42 +2469,42 @@ var le = /* @__PURE__ */ new Set([
2248
2469
  } catch {
2249
2470
  return null;
2250
2471
  }
2251
- }, Qn = async (e) => {
2252
- let t = await Zn(e);
2472
+ }, $n = async (e) => {
2473
+ let t = await Qn(e);
2253
2474
  if (t !== null) {
2254
2475
  console.log(""), console.log("• framework tables whose presence is DECIDED rather than implied by your source tree:");
2255
2476
  for (let e of t.text.split("\n")) console.log(` ${e}`);
2256
2477
  }
2257
- }, $n = async (e) => {
2478
+ }, er = async (e) => {
2258
2479
  if (e.includes("--help") || e.includes("-h")) return console.log(bn), 0;
2259
2480
  let t = e.includes("--strict"), n = e.find((e) => !e.startsWith("-")), a = b(n ?? process.cwd());
2260
2481
  if (g(e)) return ee(), h({
2261
2482
  ...R(a),
2262
2483
  spaCandidates: await z(a),
2263
- pageConvention: B(a),
2484
+ pageConvention: V(a),
2264
2485
  fileTaxonomy: re(a).findings,
2265
- junctionFks: (await U(a))?.issues ?? [],
2266
- eventDelivery: await W(a),
2267
- duplicateInstances: i(a),
2268
- versionSkew: o(a) ?? null,
2269
- serverOnly: (await K(a)).status,
2270
- accessDecisions: await q(a),
2271
- webhookVerification: await J(a),
2272
- authz: await Jn(a),
2486
+ junctionFks: (await W(a))?.issues ?? [],
2487
+ eventDelivery: await G(a),
2488
+ duplicateInstances: r(a),
2489
+ versionSkew: c(a) ?? null,
2490
+ serverOnly: (await q(a)).status,
2491
+ accessDecisions: await J(a),
2492
+ webhookVerification: await Y(a),
2493
+ authz: await Yn(a),
2273
2494
  ungrantedScopes: await Q(a),
2274
2495
  neverEmittedEvents: await Z(a),
2275
- unimportedDeps: He(a),
2496
+ unimportedDeps: Ue(a),
2276
2497
  stalledRuns: await Nn(a),
2277
- decidedSchema: await Zn(a)
2498
+ decidedSchema: await Qn(a)
2278
2499
  }), 0;
2279
- let s = Ct(a, t);
2280
- sn(a), on(a), yn(a), ne(a), await pn(a), await Fn(a), await Pn(a), await Sn(a), await Dn(a), await En(a), await Qn(a), await On(a), await Gn(a), await zn(a), await Ln(a), console.log("");
2281
- for (let e of Ue(He(a))) console.log(e);
2282
- await Vn(a), Bn(a), await Hn(a), await Un(a);
2283
- let c = await Mn(a), l = await Xn(a, e.includes("--write-authz-allowlist")), d = await kn(a), f = await jn(a), p = await Wn(a), m = r(o(a));
2500
+ let s = wt(a, t);
2501
+ cn(a), sn(a), yn(a), ne(a), await B(a), await Fn(a), await Pn(a), await Sn(a), await Dn(a), await En(a), await $n(a), await On(a), await Kn(a), await Bn(a), await Rn(a), console.log("");
2502
+ for (let e of We(Ue(a))) console.log(e);
2503
+ await Hn(a), Vn(a), await Un(a), await Wn(a);
2504
+ let l = await Mn(a), u = await Zn(a, e.includes("--write-authz-allowlist")), d = await kn(a), f = await jn(a), p = await Gn(a), m = o(c(a));
2284
2505
  m !== void 0 && (console.log(""), console.log(m));
2285
- let _ = u(i(a));
2286
- return _ !== void 0 && console.log(`\n${_}`), c || l || d || p || f ? Math.max(s, 1) : s;
2506
+ let _ = i(r(a));
2507
+ return _ !== void 0 && console.log(`\n${_}`), l || u || d || p || f ? Math.max(s, 1) : s;
2287
2508
  };
2288
2509
  //#endregion
2289
- export { z as C, J as D, Q as E, B as S, Rt as T, yn as _, Jn as a, Ct as b, W as c, Qt as d, xt as f, sn as g, on as h, q as i, In as l, wn as m, St as n, Z as o, U as p, cn as r, X as s, bn as t, R as u, pn as v, K as w, $t as x, $n as y };
2510
+ export { z as C, Y as D, Q as E, V as S, zt as T, yn as _, Yn as a, wt as b, G as c, $t as d, St as f, cn as g, sn as h, J as i, In as l, wn as m, Ct as n, Z as o, W as p, ln as r, Ln as s, bn as t, R as u, B as v, q as w, en as x, er as y };