@voltro/cli 0.52.0 → 0.53.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 (195) hide show
  1. package/CHANGELOG.md +229 -0
  2. package/THIRD-PARTY-NOTICES.md +8311 -3318
  3. package/dist/{apiBuild-CSFI8QGq.js → apiBuild-CaPfoWku.js} +11 -5
  4. package/dist/apiBuild-DHtLXYx9.js +2 -0
  5. package/dist/bin.js +1 -1
  6. package/dist/build-D-OnvNMf.js +843 -0
  7. package/dist/{checkCommand-COmqc2cB.js → checkCommand-C5elt0tW.js} +6 -6
  8. package/dist/{checkCommand-2SbqzukH.js → checkCommand-D2ZduVlh.js} +1 -1
  9. package/dist/codegen-BWpt3VgF.js +2 -0
  10. package/dist/{codegen-VF479Cnb.js → codegen-FEk8AZHb.js} +2 -2
  11. package/dist/{codegenCommand-DCdG2JN-.js → codegenCommand-BOiWQ5hz.js} +4 -4
  12. package/dist/{codemodRunner-r7J9lIa7.js → codemodRunner-BjtB2lq6.js} +109 -11
  13. package/dist/{commands-Cc_nV8WI.js → commands-DyxAmhP0.js} +30 -30
  14. package/dist/{dashboardCommand-C-gKvwqh.js → dashboardCommand-BdKTyT13.js} +5 -5
  15. package/dist/{dataCommand-BgpBHnlB.js → dataCommand-Bab9X7s8.js} +2 -2
  16. package/dist/{dbCommand-sHedr-NJ.js → dbCommand-06O2finM.js} +277 -236
  17. package/dist/dbCommand-B1EXBC6f.js +2 -0
  18. package/dist/{dev-CRHoCEiy.js → dev-C6LGF4iY.js} +3006 -2426
  19. package/dist/{dev--A3nsxA3.js → dev-GjJWAYo2.js} +1 -1
  20. package/dist/doctorCommand-B0hX0tdz.js +2 -0
  21. package/dist/{doctorCommand-DtfJ3FA6.js → doctorCommand-etMkflRc.js} +101 -69
  22. package/dist/{dormancyCommand-Drn7o0No.js → dormancyCommand-UwZ1AZzB.js} +1 -1
  23. package/dist/{embeddingsCommand-Z-jO1fWN.js → embeddingsCommand-C70zWHwo.js} +1 -1
  24. package/dist/{envCommand-D4gCrrTZ.js → envCommand-dSyKvRkM.js} +18 -18
  25. package/dist/{evolveCommand-CMROeKeA.js → evolveCommand-CG0_ebO5.js} +2 -2
  26. package/dist/fileConventions-DASGEmj-.js +35 -0
  27. package/dist/{fileTaxonomy-DvDUV9wq.js → fileTaxonomy-B7uxipWS.js} +55 -55
  28. package/dist/fontPipeline-LxIHa1vo.js +2 -0
  29. package/dist/fontPipeline-Tsh8kZfA.js +152 -0
  30. package/dist/frameworkTableAssembly-C_7Z-rMs.js +2 -0
  31. package/dist/{frameworkTableAssembly-w-XnLa3q.js → frameworkTableAssembly-DKx3ba3S.js} +5 -5
  32. package/dist/imagePipeline-B_GVJgm6.js +2 -0
  33. package/dist/imagePipeline-CBZmjT4i.js +127 -0
  34. package/dist/index.js +1 -1
  35. package/dist/{infoCommand-DXM868o_.js → infoCommand-_53iOc_j.js} +1 -1
  36. package/dist/{inspect-CtL_xTbu.js → inspect-Bd8-9wsi.js} +1 -1
  37. package/dist/inspect-CuoDInfZ.js +2 -0
  38. package/dist/{inspectGateHint-BjnFubmH.js → inspectGateHint-4LxkNtrz.js} +1 -1
  39. package/dist/manifestBuild-C4-J1-m_.js +2 -0
  40. package/dist/{manifestBuild-CuU1VrSm.js → manifestBuild-Cqgsx2bM.js} +1 -1
  41. package/dist/{metaCommands-C6RFmF1r.js → metaCommands-Cn2oboG4.js} +8 -2
  42. package/dist/{migrate-D0F-eTlK.js → migrate-Cko9rswM.js} +2 -2
  43. package/dist/{pageConvention-CzUiSbtU.js → pageConvention-C938S8oC.js} +1 -1
  44. package/dist/{privacyCommand-DGdopOI6.js → privacyCommand-DWTQMC6R.js} +2 -2
  45. package/dist/{probeCommand-C9gazU0H.js → probeCommand-DkGGLknv.js} +83 -24
  46. package/dist/{renderModeScan-CcH2X1_D.js → renderModeScan-CUbOeOAg.js} +3 -1
  47. package/dist/{renderProfile-Ck32Fzxr.js → renderProfile-CskIgAfn.js} +2 -2
  48. package/dist/{runtimeTrace-BPQyCmC5.js → runtimeTrace-c0APJz7E.js} +1 -1
  49. package/dist/{sdkgen-Se88ifTd.js → sdkgen-BiQCgIEr.js} +1 -1
  50. package/dist/{serveCommand-DkP3OT0W.js → serveCommand-CueKQgzl.js} +869 -805
  51. package/dist/serveCommand-DsnrVN3U.js +2 -0
  52. package/dist/serveEntry.js +1 -1
  53. package/dist/start-BJzZLbt8.js +3 -0
  54. package/dist/start-ekPan8BT.js +1510 -0
  55. package/dist/startEntry.js +1 -1
  56. package/dist/{staticCommand-BwNEDlSU.js → staticCommand-xlSL-IWk.js} +1 -1
  57. package/dist/{test-f3amja6a.js → test-BWPQcRoB.js} +1 -1
  58. package/dist/updateCommand-Bqql_rsQ.js +2 -0
  59. package/dist/{updateCommand-BMk2e4ky.js → updateCommand-C_8I8Rzo.js} +139 -115
  60. package/dist/webDev-C7jWJ5dX.js +2 -0
  61. package/dist/{webDev-BgWL9gKV.js → webDev-oczpugbx.js} +1455 -922
  62. package/dist/{webhooksCommand-CoIO3jbj.js → webhooksCommand-4SVPDjKg.js} +1 -1
  63. package/package.json +60 -19
  64. package/templates/AGENTS.md +5 -3
  65. package/templates/agent-docs/_index.md +5 -3
  66. package/templates/agent-docs/_manifest.json +20 -4
  67. package/templates/agent-docs/ai.md +2 -2
  68. package/templates/agent-docs/authentication.md +1 -1
  69. package/templates/agent-docs/cli.md +2 -2
  70. package/templates/agent-docs/configuration.md +17 -0
  71. package/templates/agent-docs/data.md +470 -26
  72. package/templates/agent-docs/database/advancedqueries.md +7 -7
  73. package/templates/agent-docs/database/columntypes.md +2 -2
  74. package/templates/agent-docs/database/querying.md +1 -1
  75. package/templates/agent-docs/database/schema.md +1 -1
  76. package/templates/agent-docs/database/seedsdialects.md +1 -1
  77. package/templates/agent-docs/database/transactions.md +3 -3
  78. package/templates/agent-docs/deployment.md +8 -0
  79. package/templates/agent-docs/internationalization.md +2 -2
  80. package/templates/agent-docs/introduction.md +7 -1
  81. package/templates/agent-docs/local-first-mobile.md +102 -4
  82. package/templates/agent-docs/observability.md +2 -0
  83. package/templates/agent-docs/plugins/auth.md +1 -1
  84. package/templates/agent-docs/plugins/comments.md +142 -0
  85. package/templates/agent-docs/plugins/notifications.md +47 -4
  86. package/templates/agent-docs/plugins/presence.md +16 -3
  87. package/templates/agent-docs/plugins/prometheus.md +1 -1
  88. package/templates/agent-docs/plugins/queue.md +129 -0
  89. package/templates/agent-docs/plugins.md +11 -7
  90. package/templates/agent-docs/reference.md +16 -4
  91. package/templates/agent-docs/routing.md +527 -3
  92. package/templates/agent-docs/schema-driven-ui.md +214 -3
  93. package/templates/agent-docs/security.md +3 -3
  94. package/templates/agent-docs/whats-new.md +160 -66
  95. package/templates/apps/api-ai/package.json +6 -6
  96. package/templates/apps/api-auth/package.json +8 -8
  97. package/templates/apps/api-backend/package.json +7 -7
  98. package/templates/apps/api-backend-deactivation/package.json +7 -7
  99. package/templates/apps/api-backend-mail/package.json +8 -8
  100. package/templates/apps/api-backend-mariadb/package.json +9 -9
  101. package/templates/apps/api-backend-sqlite/package.json +8 -8
  102. package/templates/apps/api-backend-storage/package.json +8 -8
  103. package/templates/apps/api-cms/package.json +9 -9
  104. package/templates/apps/api-collab/package.json +8 -8
  105. package/templates/apps/api-data-advanced/package.json +8 -8
  106. package/templates/apps/api-durable/package.json +8 -8
  107. package/templates/apps/api-feature-flags/package.json +9 -9
  108. package/templates/apps/api-governance/package.json +8 -8
  109. package/templates/apps/api-kv/package.json +8 -8
  110. package/templates/apps/api-moderation/package.json +8 -8
  111. package/templates/apps/api-observability/package.json +8 -8
  112. package/templates/apps/api-ratelimit/package.json +8 -8
  113. package/templates/apps/api-rbac/package.json +8 -8
  114. package/templates/apps/api-rest/package.json +7 -7
  115. package/templates/apps/api-row-history/package.json +8 -8
  116. package/templates/apps/api-saas/package.json +10 -10
  117. package/templates/apps/api-saas-starter/package.json +10 -10
  118. package/templates/apps/api-search/package.json +8 -8
  119. package/templates/apps/api-status/package.json +8 -8
  120. package/templates/apps/api-webhooks/package.json +9 -9
  121. package/templates/apps/changelog/app.config.ts +26 -2
  122. package/templates/apps/changelog/content/releases/{0.1.0.mdx → v0-1-0.mdx} +0 -1
  123. package/templates/apps/changelog/content/releases/{0.2.0.mdx → v0-2-0.mdx} +0 -1
  124. package/templates/apps/changelog/package.json +8 -8
  125. package/templates/apps/changelog/src/collections/releases.collection.ts +48 -0
  126. package/templates/apps/changelog/src/globals.d.ts +1 -1
  127. package/templates/apps/changelog/src/locales/de.ts +1 -1
  128. package/templates/apps/changelog/src/locales/en.ts +1 -1
  129. package/templates/apps/changelog/src/pages/[locale]/[slug]/page.tsx +7 -4
  130. package/templates/apps/changelog/src/pages/[locale]/mirrors.test.tsx +13 -41
  131. package/templates/apps/changelog/src/pages/[slug]/page.test.tsx +26 -51
  132. package/templates/apps/changelog/src/pages/[slug]/page.tsx +21 -19
  133. package/templates/apps/changelog/src/pages/page.test.tsx +14 -37
  134. package/templates/apps/changelog/src/pages/page.tsx +18 -12
  135. package/templates/apps/edge-functions/package.json +2 -2
  136. package/templates/apps/frontend-admin/package.json +8 -8
  137. package/templates/apps/frontend-app/package.json +9 -9
  138. package/templates/apps/frontend-auth/package.json +8 -8
  139. package/templates/apps/frontend-blank/package.json +7 -7
  140. package/templates/apps/frontend-cms/package.json +9 -9
  141. package/templates/apps/frontend-collab/package.json +10 -10
  142. package/templates/apps/frontend-contact/package.json +7 -7
  143. package/templates/apps/frontend-dashboard/package.json +7 -7
  144. package/templates/apps/frontend-docs/content/docs/de/guides/first-page.md +4 -0
  145. package/templates/apps/frontend-docs/content/docs/de/intro/getting-started.md +4 -0
  146. package/templates/apps/frontend-docs/content/docs/en/guides/first-page.md +4 -0
  147. package/templates/apps/frontend-docs/content/docs/en/intro/getting-started.md +4 -0
  148. package/templates/apps/frontend-docs/package.json +8 -6
  149. package/templates/apps/frontend-docs/src/collections/docs.collection.ts +21 -0
  150. package/templates/apps/frontend-docs/src/locales/de.ts +0 -5
  151. package/templates/apps/frontend-docs/src/locales/en.ts +0 -5
  152. package/templates/apps/frontend-docs/src/pages/[locale]/docs/[...slug]/page.tsx +17 -9
  153. package/templates/apps/frontend-docs/src/pages/[locale]/mirrors.test.tsx +10 -5
  154. package/templates/apps/frontend-docs/src/pages/[locale]/page.tsx +8 -0
  155. package/templates/apps/frontend-docs/src/pages/docs/[...slug]/page.test.tsx +53 -15
  156. package/templates/apps/frontend-docs/src/pages/docs/[...slug]/page.tsx +27 -33
  157. package/templates/apps/frontend-docs/src/pages/page.test.tsx +17 -3
  158. package/templates/apps/frontend-docs/src/pages/page.tsx +16 -12
  159. package/templates/apps/frontend-i18n/package.json +6 -6
  160. package/templates/apps/frontend-landing/package.json +6 -6
  161. package/templates/apps/frontend-portal/package.json +8 -8
  162. package/templates/apps/frontend-saas/package.json +8 -8
  163. package/templates/apps/frontend-spa/package.json +7 -7
  164. package/templates/apps/frontend-ssr/package.json +7 -7
  165. package/templates/apps/frontend-ssr-api/package.json +8 -8
  166. package/templates/apps/frontend-static-blog/content/posts/cms-to-ssg.md +12 -0
  167. package/templates/apps/frontend-static-blog/content/posts/hello-static.md +12 -0
  168. package/templates/apps/frontend-static-blog/content/posts/islands-not-hydration.md +14 -0
  169. package/templates/apps/frontend-static-blog/package.json +8 -6
  170. package/templates/apps/frontend-static-blog/src/collections/posts.collection.ts +27 -0
  171. package/templates/apps/frontend-static-blog/src/pages/[locale]/blog/[slug]/page.tsx +7 -4
  172. package/templates/apps/frontend-static-blog/src/pages/[locale]/mirrors.test.tsx +7 -1
  173. package/templates/apps/frontend-static-blog/src/pages/blog/[slug]/page.test.tsx +19 -9
  174. package/templates/apps/frontend-static-blog/src/pages/blog/[slug]/page.tsx +19 -21
  175. package/templates/apps/frontend-static-blog/src/pages/page.test.tsx +18 -5
  176. package/templates/apps/frontend-static-blog/src/pages/page.tsx +21 -14
  177. package/templates/apps/frontend-status/package.json +8 -8
  178. package/templates/apps/mobile-app/package.json +4 -4
  179. package/dist/apiBuild-BYBpL7Pz.js +0 -2
  180. package/dist/build-CPgcMQug.js +0 -793
  181. package/dist/codegen-CctkDO-1.js +0 -2
  182. package/dist/dbCommand-DNb6yeOG.js +0 -2
  183. package/dist/doctorCommand-CqoWA2p5.js +0 -2
  184. package/dist/fileConventions-DOqD3lPS.js +0 -34
  185. package/dist/frameworkTableAssembly-C6ETawPR.js +0 -2
  186. package/dist/inspect-CuGDYES0.js +0 -2
  187. package/dist/manifestBuild-CPjhvM62.js +0 -2
  188. package/dist/serveCommand-DLc-BznW.js +0 -2
  189. package/dist/start-DfL3fOiN.js +0 -3
  190. package/dist/start-jw89Xbqy.js +0 -1339
  191. package/dist/updateCommand-5gFVfK5q.js +0 -2
  192. package/dist/webDev-CZbTsDcH.js +0 -2
  193. package/templates/apps/changelog/scripts/generate-rss.mjs +0 -38
  194. package/templates/apps/changelog/src/lib/releases.ts +0 -21
  195. package/templates/apps/frontend-static-blog/src/content/posts.ts +0 -64
@@ -1,4 +1,4 @@
1
- import { C as e, E as t, O as n, T as r, d as i, h as a, i as o, l as s, m as c, r as l, u } from "./fileConventions-DOqD3lPS.js";
1
+ import { D as e, E as t, d as n, f as r, g as i, h as a, i as o, k as s, r as c, u as l, w as u } from "./fileConventions-DASGEmj-.js";
2
2
  import { n as d, t as f } from "./tsconfigPaths-BWXBWgcl.js";
3
3
  import { dirname as p, join as m, relative as h, resolve as g, sep as _ } from "node:path";
4
4
  import { existsSync as v, readFileSync as y, readdirSync as b, statSync as x } from "node:fs";
@@ -43,40 +43,40 @@ var T = ".voltro-vendored", E = (e, t) => {
43
43
  },
44
44
  {
45
45
  id: "component",
46
- re: l,
46
+ re: c,
47
47
  needsTest: !0
48
48
  },
49
49
  {
50
50
  id: "hook",
51
- re: u,
51
+ re: n,
52
52
  needsTest: !0
53
53
  },
54
54
  {
55
55
  id: "tracking",
56
- re: t,
56
+ re: e,
57
57
  needsTest: !0
58
58
  },
59
59
  {
60
60
  id: "store",
61
- re: e,
61
+ re: u,
62
62
  needsTest: !0
63
63
  },
64
64
  {
65
65
  id: "internal",
66
- re: i,
66
+ re: r,
67
67
  needsTest: !0
68
68
  },
69
69
  {
70
70
  id: "fixture",
71
- re: s,
71
+ re: l,
72
72
  needsTest: !1
73
73
  },
74
74
  {
75
75
  id: "types",
76
- re: n,
76
+ re: s,
77
77
  needsTest: !1
78
78
  }
79
- ], A = (e) => k.find((t) => t.re.test(e))?.id ?? null, j = (e) => r.test(e), M = /* @__PURE__ */ new Set([
79
+ ], A = (e) => k.find((t) => t.re.test(e))?.id ?? null, j = (e) => t.test(e), M = /* @__PURE__ */ new Set([
80
80
  "useMutation",
81
81
  "useAction",
82
82
  "useUpload",
@@ -244,10 +244,10 @@ var T = ".voltro-vendored", E = (e, t) => {
244
244
  scanned: 0,
245
245
  vendored: n
246
246
  };
247
- let i = new C({
247
+ let o = new C({
248
248
  useInMemoryFileSystem: !0,
249
249
  skipAddingFilesFromTsConfig: !0
250
- }), o = [], s = (t) => h(e, t), l = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map();
250
+ }), s = [], c = (t) => h(e, t), l = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map();
251
251
  for (let t of r) {
252
252
  let n;
253
253
  try {
@@ -257,7 +257,7 @@ var T = ".voltro-vendored", E = (e, t) => {
257
257
  }
258
258
  let r;
259
259
  try {
260
- r = i.createSourceFile(t.endsWith("x") ? "/scan.tsx" : "/scan.ts", n, { overwrite: !0 });
260
+ r = o.createSourceFile(t.endsWith("x") ? "/scan.tsx" : "/scan.ts", n, { overwrite: !0 });
261
261
  } catch {
262
262
  continue;
263
263
  }
@@ -293,40 +293,40 @@ var T = ".voltro-vendored", E = (e, t) => {
293
293
  for (let e of r) {
294
294
  let t = A(e), n = l.get(e), r = u.get(e);
295
295
  if (n === void 0 || r === void 0) continue;
296
- let i = j(e);
297
- t !== null && !i && (g += 1);
296
+ let o = j(e);
297
+ t !== null && !o && (g += 1);
298
298
  let f = p.get(e) ?? [];
299
- if ((t === "component" || t === "component.ui") && !i) {
299
+ if ((t === "component" || t === "component.ui") && !o) {
300
300
  let t = J(n.components);
301
- (n.components.length === 0 || !t) && o.push({
301
+ (n.components.length === 0 || !t) && s.push({
302
302
  rule: "component/one-per-file",
303
- file: s(e),
303
+ file: c(e),
304
304
  severity: "error",
305
305
  detail: n.components.length === 0 ? "declares a component file but exports no component" : `exports ${n.components.length} unrelated components: ${n.components.join(", ")}`,
306
306
  fix: "a component file exports ONE component — or one NAMESPACED family sharing its name (`Card`, `CardHeader`, `CardTitle`), which is one component with parts. Types alongside are fine. Unrelated components belong in their own files"
307
- }), n.hooks.length > 0 && o.push({
307
+ }), n.hooks.length > 0 && s.push({
308
308
  rule: "component/no-hook-export",
309
- file: s(e),
309
+ file: c(e),
310
310
  severity: "error",
311
311
  detail: `also exports hook(s): ${n.hooks.join(", ")}`,
312
312
  fix: "move the hook into its own *.hook.ts — a file exporting both is two files wearing one name, and neither can be reused without dragging the other"
313
313
  });
314
314
  }
315
- if (t === "hook" && !i && (n.hooks.length !== 1 && o.push({
315
+ if (t === "hook" && !o && (n.hooks.length !== 1 && s.push({
316
316
  rule: "hook/one-per-file",
317
- file: s(e),
317
+ file: c(e),
318
318
  severity: "error",
319
319
  detail: n.hooks.length === 0 ? "declares a hook file but exports no use* hook" : `exports ${n.hooks.length} hooks: ${n.hooks.join(", ")}`,
320
320
  fix: "a hook file exports exactly ONE use* hook (types alongside are fine)"
321
- }), n.components.length > 0 && o.push({
321
+ }), n.components.length > 0 && s.push({
322
322
  rule: "hook/no-component-export",
323
- file: s(e),
323
+ file: c(e),
324
324
  severity: "error",
325
325
  detail: `also exports component(s): ${n.components.join(", ")}`,
326
326
  fix: "move the component into its own *.component.tsx"
327
- })), t === "types" && n.hasRuntimeExport && o.push({
327
+ })), t === "types" && n.hasRuntimeExport && s.push({
328
328
  rule: "types/runtime-export",
329
- file: s(e),
329
+ file: c(e),
330
330
  severity: "error",
331
331
  detail: `exports runtime value(s): ${[
332
332
  ...n.components,
@@ -336,80 +336,80 @@ var T = ".voltro-vendored", E = (e, t) => {
336
336
  fix: "a *.types.ts has NO runtime export. That is what makes importing it provably free AND makes it impossible for it to sit in a runtime import cycle — the guarantee is the point, so move the value to a sibling module"
337
337
  }), t === "internal") {
338
338
  let t = f.filter((t) => !Y(t, e));
339
- t.length > 0 && o.push({
339
+ t.length > 0 && s.push({
340
340
  rule: "internal/foreign-import",
341
- file: s(e),
341
+ file: c(e),
342
342
  severity: "error",
343
- detail: `imported from outside its own directory by: ${t.slice(0, 5).map(s).join(", ")}${t.length > 5 ? ` (+${t.length - 5})` : ""}`,
343
+ detail: `imported from outside its own directory by: ${t.slice(0, 5).map(c).join(", ")}${t.length > 5 ? ` (+${t.length - 5})` : ""}`,
344
344
  fix: "export it through the feature's public module, or move the importer inside. `.internal` is the promise that refactoring within this directory breaks nobody — a foreign import revokes it silently, which is how a feature boundary rots without a single review comment"
345
345
  });
346
346
  }
347
347
  if (t === "fixture") {
348
348
  let t = f.filter((e) => !j(e) && A(e) !== "fixture");
349
- t.length > 0 && o.push({
349
+ t.length > 0 && s.push({
350
350
  rule: "fixture/production-import",
351
- file: s(e),
351
+ file: c(e),
352
352
  severity: "error",
353
- detail: `imported by non-test file(s): ${t.slice(0, 5).map(s).join(", ")}`,
353
+ detail: `imported by non-test file(s): ${t.slice(0, 5).map(c).join(", ")}`,
354
354
  fix: "test material must not be reachable from a production path — it ships in the bundle, and it is written to be convenient rather than correct"
355
355
  });
356
356
  }
357
- if (t === "component.ui" && !i) {
357
+ if (t === "component.ui" && !o) {
358
358
  let t = [...r.namedBindings].filter((e) => M.has(e)).sort();
359
- t.length > 0 && o.push({
359
+ t.length > 0 && s.push({
360
360
  rule: "ui/no-write",
361
- file: s(e),
361
+ file: c(e),
362
362
  severity: "error",
363
363
  detail: `imports write hook(s): ${t.join(", ")}`,
364
364
  fix: "a *.component.ui.tsx renders; it does not write. Lift the mutation into the *.component.tsx that owns it and pass a handler down. Reading (useT / useCan / usePermissions) stays allowed — threading those through props is prop-drilling, not reusability"
365
365
  });
366
- let n = m(e), i = n.filter((e) => {
366
+ let n = m(e), o = n.filter((e) => {
367
367
  let t = A(e);
368
- return t === "component" || t === "component.ui" || c.test(e) || a.has(e.slice(e.lastIndexOf(_) + 1));
368
+ return t === "component" || t === "component.ui" || a.test(e) || i.has(e.slice(e.lastIndexOf(_) + 1));
369
369
  });
370
- n.length === 0 ? o.push({
370
+ n.length === 0 ? s.push({
371
371
  rule: "ui/orphaned",
372
- file: s(e),
372
+ file: c(e),
373
373
  severity: "warn",
374
374
  detail: "nothing imports it",
375
375
  fix: "render it from a *.component.tsx or a page, or delete it — an unrendered presentational component is carried, reviewed and refactored forever without reaching a user"
376
- }) : i.length === 0 && o.push({
376
+ }) : o.length === 0 && s.push({
377
377
  rule: "ui/unlinked",
378
- file: s(e),
378
+ file: c(e),
379
379
  severity: "warn",
380
- detail: `reached only by: ${n.slice(0, 5).map(s).join(", ")}${n.length > 5 ? ` (+${n.length - 5})` : ""} — barrels resolved through`,
380
+ detail: `reached only by: ${n.slice(0, 5).map(c).join(", ")}${n.length > 5 ? ` (+${n.length - 5})` : ""} — barrels resolved through`,
381
381
  fix: "a presentational component should be reached from a *.component.tsx, another *.component.ui.tsx, or a page"
382
382
  });
383
383
  }
384
- if (t === "store" && !i) {
384
+ if (t === "store" && !o) {
385
385
  let t = d.get(e)?.get("defineStore") ?? 0;
386
- t !== 1 && o.push({
386
+ t !== 1 && s.push({
387
387
  rule: "store/one-per-file",
388
- file: s(e),
388
+ file: c(e),
389
389
  severity: "error",
390
390
  detail: t === 0 ? "declares a store file but calls no defineStore()" : `declares ${t} stores`,
391
391
  fix: "a store file defines exactly ONE store — the SSR seed pass and devtools address stores by name, so two in a file makes both harder to find and neither easier to reason about"
392
392
  });
393
393
  let n = [...d.get(e)?.keys() ?? []].filter((e) => P.has(e)).sort();
394
- n.length > 0 && o.push({
394
+ n.length > 0 && s.push({
395
395
  rule: "store/mirrors-server-state",
396
- file: s(e),
396
+ file: c(e),
397
397
  severity: "error",
398
398
  detail: `reads server state here: ${n.join(", ")}`,
399
399
  fix: "a store holds CLIENT state. A subscription is already live server state; copying it into a store gives you a second copy that does not live, and the page then shows the stale one — a bug that reads as \"reactivity is broken\". Read the subscription where you render it"
400
400
  });
401
401
  }
402
- if (t !== "tracking" && !i) {
402
+ if (t !== "tracking" && !o) {
403
403
  let t = [...d.get(e)?.keys() ?? []].filter((e) => N.has(e)).sort();
404
- t.length > 0 && o.push({
404
+ t.length > 0 && s.push({
405
405
  rule: "tracking/outside-tracking-file",
406
- file: s(e),
406
+ file: c(e),
407
407
  severity: "error",
408
408
  detail: `calls ${t.join(", ")} outside a *.tracking.ts`,
409
409
  fix: "move the defineTracking(...) spec into a *.tracking.ts and import it here. The event catalogue — names, property bags, the decisions about what personal data goes out — belongs in one place you can list; calling useTracking with a spec from there is fine"
410
410
  });
411
411
  }
412
- if (k.find((e) => e.id === t)?.needsTest === !0 && !i) {
412
+ if (k.find((e) => e.id === t)?.needsTest === !0 && !o) {
413
413
  let t = e.replace(/\.tsx?$/, ""), n = e.endsWith("x") ? "tsx" : "ts";
414
414
  ["test", "spec"].flatMap((e) => [`${t}.${e}.ts`, `${t}.${e}.tsx`]).some((e) => {
415
415
  try {
@@ -417,17 +417,17 @@ var T = ".voltro-vendored", E = (e, t) => {
417
417
  } catch {
418
418
  return !1;
419
419
  }
420
- }) || o.push({
420
+ }) || s.push({
421
421
  rule: "convention/missing-test",
422
- file: s(e),
422
+ file: c(e),
423
423
  severity: "warn",
424
424
  detail: "no test beside it",
425
- fix: `add ${s(t)}.test.${n} — the name is derivable, so write it with the file. A shallow test earns its place: what it buys is that something MOUNTS the component, and a render loop, a crashing effect or a missing provider is invisible until then. One app wrote 251 of these and the first run found a render loop that made a page take 423 s and exhaust the heap — in a browser it had looked usable`
425
+ fix: `add ${c(t)}.test.${n} — the name is derivable, so write it with the file. A shallow test earns its place: what it buys is that something MOUNTS the component, and a render loop, a crashing effect or a missing provider is invisible until then. One app wrote 251 of these and the first run found a render loop that made a page take 423 s and exhaust the heap — in a browser it had looked usable`
426
426
  });
427
427
  }
428
428
  }
429
- return o.sort((e, t) => e.file === t.file ? e.rule.localeCompare(t.rule) : e.file.localeCompare(t.file)), {
430
- findings: o,
429
+ return s.sort((e, t) => e.file === t.file ? e.rule.localeCompare(t.rule) : e.file.localeCompare(t.file)), {
430
+ findings: s,
431
431
  declared: g,
432
432
  scanned: r.length,
433
433
  vendored: n
@@ -0,0 +1,2 @@
1
+ import { o as e, s as t } from "./fontPipeline-Tsh8kZfA.js";
2
+ export { e as loadFontkit, t as loadSubsetFont };
@@ -0,0 +1,152 @@
1
+ import { createHash as e } from "node:crypto";
2
+ //#region src/fontPipeline.ts
3
+ var t = (e) => e.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, ""), n, r = !1, i = async () => {
4
+ if (n !== void 0) return n;
5
+ try {
6
+ let e = await import("fontkit");
7
+ n = e.default ?? e;
8
+ } catch {
9
+ n = null;
10
+ }
11
+ return n;
12
+ }, a, o = !1, s = async () => {
13
+ if (a !== void 0) return a;
14
+ try {
15
+ let e = await import("subset-font");
16
+ a = e.default ?? e;
17
+ } catch {
18
+ a = null;
19
+ }
20
+ return a;
21
+ }, c = (e, t) => {
22
+ if (e === "fontkit") {
23
+ if (r) return;
24
+ r = !0, t.warn("font pipeline: fontkit is not loadable — fonts still self-host with @font-face + preload, but the size-adjusted fallback metrics (the CLS guard) are SKIPPED. It ships as an optional dependency of @voltro/cli; if your installer omitted optional deps, run `pnpm add -D fontkit`.");
25
+ } else {
26
+ if (o) return;
27
+ o = !0, t.warn("font pipeline: subset-font is not loadable — declared `subsets:` are SKIPPED and the full font files ship. Run `pnpm add -D subset-font` (optional dependency of @voltro/cli that your installer omitted).");
28
+ }
29
+ }, l = {
30
+ Arial: {
31
+ unitsPerEm: 2048,
32
+ ascent: 1854,
33
+ descent: 434,
34
+ lineGap: 67,
35
+ xWidthAvg: 913
36
+ },
37
+ "Times New Roman": {
38
+ unitsPerEm: 2048,
39
+ ascent: 1825,
40
+ descent: 443,
41
+ lineGap: 87,
42
+ xWidthAvg: 832
43
+ }
44
+ }, u = "etaoin shrdlu cmfwyp vbgkqj xz", d = async (e) => {
45
+ let t = await i();
46
+ if (t === null) return null;
47
+ try {
48
+ let n = t.create(Buffer.from(e)), r = n.layout(u).glyphs.map((e) => e.advanceWidth).filter((e) => Number.isFinite(e) && e > 0), i = r.length > 0 ? r.reduce((e, t) => e + t, 0) / r.length : 0;
49
+ return {
50
+ unitsPerEm: n.unitsPerEm,
51
+ ascent: Math.abs(n.ascent),
52
+ descent: Math.abs(n.descent),
53
+ lineGap: Math.abs(n.lineGap ?? 0),
54
+ xWidthAvg: i
55
+ };
56
+ } catch {
57
+ return null;
58
+ }
59
+ }, f = (e) => `${(e * 100).toFixed(4).replace(/\.?0+$/, "")}%`, p = (e, t, n) => {
60
+ let r = l[n];
61
+ if (t.xWidthAvg <= 0 || t.unitsPerEm <= 0) return null;
62
+ let i = t.xWidthAvg / t.unitsPerEm / (r.xWidthAvg / r.unitsPerEm);
63
+ if (!Number.isFinite(i) || i <= 0) return null;
64
+ let a = t.ascent / t.unitsPerEm / i, o = t.descent / t.unitsPerEm / i, s = t.lineGap / t.unitsPerEm / i;
65
+ return [
66
+ "@font-face {",
67
+ ` font-family: '${e} Fallback';`,
68
+ ` src: local('${n}');`,
69
+ ` size-adjust: ${f(i)};`,
70
+ ` ascent-override: ${f(a)};`,
71
+ ` descent-override: ${f(o)};`,
72
+ ` line-gap-override: ${f(s)};`,
73
+ "}"
74
+ ].join("\n");
75
+ }, m = {
76
+ latin: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
77
+ "latin-ext": "U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF"
78
+ }, h = (e) => {
79
+ let t = [];
80
+ for (let n of e.split(",")) {
81
+ let e = /U\+([0-9A-F]{1,6})(?:-([0-9A-F]{1,6}))?/i.exec(n.trim());
82
+ if (!e) continue;
83
+ let r = parseInt(e[1], 16), i = e[2] === void 0 ? r : parseInt(e[2], 16);
84
+ for (let e = r; e <= i && e <= 65535; e += 1) t.push(String.fromCharCode(e));
85
+ }
86
+ return t.join("");
87
+ }, g = async (e, t) => {
88
+ let n = await s();
89
+ if (n === null) return null;
90
+ try {
91
+ let r = await n(Buffer.from(e), h(m[t]), { targetFormat: "woff2" });
92
+ return new Uint8Array(r);
93
+ } catch {
94
+ return null;
95
+ }
96
+ }, _ = (t) => e("sha256").update(t).digest("hex").slice(0, 12), v = (e) => e.endsWith(".woff2") ? "woff2" : e.endsWith(".woff") ? "woff" : e.endsWith(".otf") ? "opentype" : "truetype", y = async (e, n, r = {}) => {
97
+ let a = r.baseUrl ?? "/", o = [], s = [], c = [], l = [], u = /* @__PURE__ */ new Set();
98
+ for (let r of e) {
99
+ let e = r.display ?? "swap", f = r.fallback ?? "Arial", h = null, y = !0;
100
+ for (let t of r.src) {
101
+ let l = await n(t.path);
102
+ h === null && (h = await d(l), h === null && await i() === null && u.add("fontkit"));
103
+ let f = t.weight ?? 400, p = t.style ?? "normal", b = (t, n, i) => {
104
+ let l = n === "woff2" ? "woff2" : n === "woff" ? "woff" : n === "opentype" ? "otf" : "ttf", u = `assets/fonts/${_(t)}.${l}`;
105
+ s.push({
106
+ fileName: u,
107
+ bytes: t,
108
+ preload: y
109
+ }), y && c.push(`${a}${u}`), y = !1, o.push([
110
+ "@font-face {",
111
+ ` font-family: '${r.family}';`,
112
+ ` font-style: ${p};`,
113
+ ` font-weight: ${f};`,
114
+ ` font-display: ${e};`,
115
+ ` src: url('${a}${u}') format('${n}');`,
116
+ ...i === void 0 ? [] : [` unicode-range: ${i};`],
117
+ "}"
118
+ ].join("\n"));
119
+ };
120
+ if (r.subsets !== void 0 && r.subsets.length > 0) {
121
+ let e = !1;
122
+ for (let t of r.subsets) {
123
+ let n = await g(l, t);
124
+ if (n === null) {
125
+ u.add("subset-font");
126
+ break;
127
+ }
128
+ e = !0, b(n, "woff2", m[t]);
129
+ }
130
+ e || b(l, v(t.path));
131
+ } else b(l, v(t.path));
132
+ }
133
+ if (h !== null) {
134
+ let e = p(r.family, h, f);
135
+ e !== null && o.push(e);
136
+ }
137
+ let b = `--font-${t(r.family)}`;
138
+ l.push({
139
+ family: r.family,
140
+ variable: b
141
+ }), o.push(`:root { ${b}: '${r.family}', '${r.family} Fallback', ${f === "Arial" ? "Arial, sans-serif" : "'Times New Roman', serif"}; }`);
142
+ }
143
+ return {
144
+ css: o.join("\n"),
145
+ files: s,
146
+ preloads: c,
147
+ variables: l,
148
+ warnings: [...u]
149
+ };
150
+ };
151
+ //#endregion
152
+ export { _ as a, h as c, c as d, t as i, d as l, y as n, i as o, p as r, s, m as t, g as u };
@@ -0,0 +1,2 @@
1
+ import { c as e, n as t } from "./frameworkTableAssembly-DKx3ba3S.js";
2
+ export { t as assembleFrameworkTables, e as loadAppSchemaInputs };
@@ -1,6 +1,6 @@
1
1
  import { n as e } from "./appModuleLoader-C9r9mxZt.js";
2
2
  import { n as t } from "./declaredSchemaGates-BlcwObhb.js";
3
- import { D as n, a as r, j as i, k as a, x as o } from "./fileConventions-DOqD3lPS.js";
3
+ import { A as n, M as r, O as i, S as a, o } from "./fileConventions-DASGEmj-.js";
4
4
  import { basename as s, join as c } from "node:path";
5
5
  import { existsSync as l, promises as u } from "node:fs";
6
6
  import { pathToFileURL as d } from "node:url";
@@ -407,20 +407,20 @@ var we = [
407
407
  connections: r.map((e) => `${e.definition.id} (${e.definition.kind})`),
408
408
  files: r.map((e) => He(s(e.file)))
409
409
  }), r;
410
- }, J = (e) => r.test(e) || o.test(e), Y = async (e) => {
411
- let t = !1, r = !1, o = !1, s = !1, l = !1, d = async (e) => {
410
+ }, J = (e) => o.test(e) || a.test(e), Y = async (e) => {
411
+ let t = !1, a = !1, o = !1, s = !1, l = !1, d = async (e) => {
412
412
  let f = await u.readdir(e, { withFileTypes: !0 }).catch(() => []);
413
413
  for (let u of f) if (u.isDirectory()) {
414
414
  if (u.name === "node_modules" || u.name === "dist" || u.name === ".framework" || u.name.startsWith(".")) continue;
415
415
  await d(c(e, u.name));
416
416
  } else {
417
417
  let e = u.name;
418
- (i.test(e) || n.test(e)) && (t = !0), J(e) && (r = !0), a.test(e) && (o = !0), W.test(e) && (s = !0), q.test(e) && (l = !0);
418
+ (r.test(e) || i.test(e)) && (t = !0), J(e) && (a = !0), n.test(e) && (o = !0), W.test(e) && (s = !0), q.test(e) && (l = !0);
419
419
  }
420
420
  };
421
421
  return await d(e), {
422
422
  workflows: t,
423
- schedules: r,
423
+ schedules: a,
424
424
  webhooks: o,
425
425
  agents: s,
426
426
  connections: l
@@ -0,0 +1,2 @@
1
+ import { c as e, u as t } from "./imagePipeline-CBZmjT4i.js";
2
+ export { e as loadSharp, t as sharpUnavailableReason };
@@ -0,0 +1,127 @@
1
+ import { join as e } from "node:path";
2
+ import { mkdir as t, readFile as n, stat as r, writeFile as i } from "node:fs/promises";
3
+ import { createHash as a } from "node:crypto";
4
+ //#region src/imagePipeline.ts
5
+ var o = [
6
+ 640,
7
+ 750,
8
+ 828,
9
+ 1080,
10
+ 1200,
11
+ 1920,
12
+ 2048,
13
+ 3840
14
+ ], s = {
15
+ formats: ["avif", "webp"],
16
+ quality: 75
17
+ }, c = (e) => ({
18
+ formats: e?.formats !== void 0 && e.formats.length > 0 ? e.formats.filter((e) => e === "avif" || e === "webp") : s.formats,
19
+ quality: e?.quality !== void 0 && Number.isFinite(e.quality) && e.quality >= 1 && e.quality <= 100 ? Math.round(e.quality) : s.quality
20
+ }), l, u = !1, d, f = async () => {
21
+ if (l !== void 0) return l;
22
+ try {
23
+ let e = await import("sharp");
24
+ l = e.default ?? e;
25
+ } catch (e) {
26
+ let t = e instanceof Error ? e.message : String(e);
27
+ d = t.includes("Could not load the sharp module") ? {
28
+ reason: "binary-missing",
29
+ detail: t
30
+ } : {
31
+ reason: "not-installed",
32
+ detail: t
33
+ }, l = null;
34
+ }
35
+ return l;
36
+ }, p = () => d, m = (e) => {
37
+ if (u) return;
38
+ u = !0;
39
+ let t = d?.reason === "binary-missing" ? "sharp is installed but its platform binary is missing (an install that omitted optional dependencies drops the @img/* prebuilds). Reinstall without omitting optional deps, or run `pnpm add -D sharp` in this app to pin it directly." : "sharp is not installed. It ships as an optional dependency of @voltro/cli; if your installer skipped optional dependencies, run `pnpm add -D sharp` in this app.";
40
+ e.warn(`image pipeline: serving ORIGINAL images without srcSet variants or blur placeholders — ${t} Until then <Image> falls back to the passthrough loader.`);
41
+ }, h = (e, t, n, r) => `${e}-w${t}-q${r}.${n}`, g = (t) => e(t, ".framework", "image-cache"), _ = (e) => a("sha256").update(e).digest("hex").slice(0, 16), v = 4, y = 0, b = [], x = async (e) => {
42
+ y >= v && await new Promise((e) => b.push(e)), y += 1;
43
+ try {
44
+ return await e();
45
+ } finally {
46
+ --y, b.shift()?.();
47
+ }
48
+ }, S = async (r) => {
49
+ let a = await f();
50
+ if (!a) return null;
51
+ let o = e(r.cacheDir, h(r.sourceHash, r.width, r.format, r.quality));
52
+ try {
53
+ let e = await n(o);
54
+ return r.onCache?.("hit"), new Uint8Array(e);
55
+ } catch {}
56
+ r.onCache?.("miss");
57
+ let s = await x(async () => {
58
+ let e = await a(Buffer.from(r.sourceBytes), { failOn: "none" }).resize({
59
+ width: r.width,
60
+ withoutEnlargement: !0
61
+ }).toFormat(r.format, { quality: r.quality }).toBuffer();
62
+ return new Uint8Array(e);
63
+ });
64
+ return await t(r.cacheDir, { recursive: !0 }), await i(o, s), s;
65
+ }, C = async (e) => {
66
+ let t = await f();
67
+ if (!t) return null;
68
+ try {
69
+ let n = await t(Buffer.from(e), { failOn: "none" }).metadata();
70
+ return n.width === void 0 || n.height === void 0 || n.format === void 0 ? null : {
71
+ width: n.width,
72
+ height: n.height,
73
+ format: n.format
74
+ };
75
+ } catch {
76
+ return null;
77
+ }
78
+ }, w = async (e, t, n) => {
79
+ let r = await S({
80
+ sourceBytes: e,
81
+ sourceHash: t,
82
+ width: 16,
83
+ format: "webp",
84
+ quality: 40,
85
+ cacheDir: n
86
+ });
87
+ return r === null ? null : `data:image/webp;base64,${Buffer.from(r).toString("base64")}`;
88
+ }, T = (e) => [...o.filter((t) => t < e), e], E = async (e) => {
89
+ let t = await C(e.sourceBytes);
90
+ if (t === null) return null;
91
+ let n = _(e.sourceBytes), r = T(t.width), i = t.format === "png" ? "png" : "jpeg", a = [...e.config.formats, i], o = [];
92
+ for (let t of a) for (let i of r) {
93
+ let r = await S({
94
+ sourceBytes: e.sourceBytes,
95
+ sourceHash: n,
96
+ width: i,
97
+ format: t,
98
+ quality: e.config.quality,
99
+ cacheDir: e.cacheDir,
100
+ ...e.onCache === void 0 ? {} : { onCache: e.onCache }
101
+ });
102
+ if (r === null) return null;
103
+ o.push({
104
+ width: i,
105
+ format: t,
106
+ bytes: r,
107
+ hash: _(r)
108
+ });
109
+ }
110
+ let s = await w(e.sourceBytes, n, e.cacheDir);
111
+ return s === null ? null : {
112
+ width: t.width,
113
+ height: t.height,
114
+ blurDataURL: s,
115
+ widths: r,
116
+ variants: o,
117
+ fallbackFormat: i
118
+ };
119
+ }, D = async (e) => {
120
+ try {
121
+ return (await r(e)).isFile() ? new Uint8Array(await n(e)) : null;
122
+ } catch {
123
+ return null;
124
+ }
125
+ };
126
+ //#endregion
127
+ export { g as a, f as c, S as d, m as f, E as i, D as l, o as n, c as o, T as p, w as r, C as s, s as t, p as u };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as e, i as t, n, o as r, r as i, t as a } from "./commands-Cc_nV8WI.js";
1
+ import { a as e, i as t, n, o as r, r as i, t as a } from "./commands-DyxAmhP0.js";
2
2
  import { r as o } from "./templates-BR-fb4SP.js";
3
3
  //#region src/index.ts
4
4
  var s = "framework";
@@ -1,5 +1,5 @@
1
1
  import { n as e, r as t, t as n } from "./cliOutput-D1tSBoRM.js";
2
- import { o as r } from "./updateCommand-BMk2e4ky.js";
2
+ import { o as r } from "./updateCommand-C_8I8Rzo.js";
3
3
  import { join as i, resolve as a } from "node:path";
4
4
  import { readFileSync as o, readdirSync as s, statSync as c } from "node:fs";
5
5
  //#region src/infoCommand.ts
@@ -1,4 +1,4 @@
1
- import { n as e } from "./inspectGateHint-BjnFubmH.js";
1
+ import { n as e } from "./inspectGateHint-4LxkNtrz.js";
2
2
  import { lastWriteProvenance as t } from "@voltro/runtime";
3
3
  import { timingSafeStringEqual as n } from "@voltro/protocol/session";
4
4
  //#region src/inspect.ts
@@ -0,0 +1,2 @@
1
+ import { r as e } from "./inspect-Bd8-9wsi.js";
2
+ export { e as buildCapabilityManifest };
@@ -1,5 +1,5 @@
1
1
  //#region src/inspectGateHint.ts
2
- var e = (e) => e === 401 || e === 403, t = (e) => e === 403 ? "The inspect surface rejected the credential. VOLTRO_INSPECT_TOKEN must be set on the SERVER and in this shell, and the two values must match. (This is a framework gate, not a database permission.)" : "The inspect surface is gated and this request carried no credential. Set VOLTRO_INSPECT_TOKEN on the server and in this shell (same value), or pass --token.", n = "`voltro dev` mints VOLTRO_INSPECT_WRITE_TOKEN into the project's gitignored .env.local, so read the value from there and send it in this shell; outside dev nothing mints it and you set it explicitly on both sides.", r = (e, t) => {
2
+ var e = (e) => e === 401 || e === 403, t = (e) => e === 403 ? "The inspect surface rejected the credential. VOLTRO_INSPECT_TOKEN must be set on the SERVER and in this shell, and the two values must match. (This is a framework gate, not a database permission.)" : "The inspect surface is gated and this request carried no credential. Set VOLTRO_INSPECT_TOKEN on the server and in this shell (same value), or pass --token.", n = "`voltro dev` mints VOLTRO_INSPECT_WRITE_TOKEN into the project's gitignored .env.local, so read the value from there and send it in this shell; outside dev nothing mints it — generate one with `voltro secret generate inspect-write` and set it explicitly on both sides.", r = (e, t) => {
3
3
  let r = `inspect: ${(t || "unknown-method").toUpperCase()} is a mutating request and needs the WRITE credential — VOLTRO_INSPECT_WRITE_TOKEN, sent as the \`x-voltro-inspect-write\` header alongside the bearer. The read token authorises reads only.`;
4
4
  return e === "unset" ? `${r} The SERVER has none configured, so no header can satisfy this. Mutating inspect endpoints (GDPR erase/export, storage share/revoke, schedule fire) need their own secret. ${n}` : e === "mismatch" ? `${r} The header was sent and does not match the server's value — so this is the two values disagreeing, not a missing setting. ${n}` : `${r} This request carried no such header. ${n}`;
5
5
  };
@@ -0,0 +1,2 @@
1
+ import { t as e } from "./manifestBuild-Cqgsx2bM.js";
2
+ export { e as buildRpcEntry };
@@ -1,4 +1,4 @@
1
- import { P as e } from "./inspect-CtL_xTbu.js";
1
+ import { P as e } from "./inspect-Bd8-9wsi.js";
2
2
  import { JSONSchema as t } from "effect";
3
3
  //#region src/manifestBuild.ts
4
4
  var n = (e) => {
@@ -1,6 +1,6 @@
1
1
  import { i as e, n as t, r as n } from "./cliArgs-D4p8n7EE.js";
2
2
  import { t as r } from "./cliRuntime-Dh7UDinH.js";
3
- import { n as i } from "./renderProfile-Ck32Fzxr.js";
3
+ import { n as i } from "./renderProfile-CskIgAfn.js";
4
4
  import { a, i as o } from "./projectScaffold-B4dmTlwT.js";
5
5
  import { t as s } from "./discover-C9XKJDco.js";
6
6
  import { basename as c, join as l, relative as u, resolve as d } from "node:path";
@@ -141,7 +141,13 @@ var v = /* @__PURE__ */ new Set([
141
141
  env: "VOLTRO_INSPECT_TOKEN",
142
142
  encoding: "base64url",
143
143
  bytes: 32,
144
- note: "bearer token for /_voltro/inspect/*"
144
+ note: "bearer token for /_voltro/inspect/* (reads)"
145
+ },
146
+ "inspect-write": {
147
+ env: "VOLTRO_INSPECT_WRITE_TOKEN",
148
+ encoding: "base64url",
149
+ bytes: 32,
150
+ note: "second factor for MUTATING inspect endpoints (x-voltro-inspect-write header)"
145
151
  },
146
152
  webhook: {
147
153
  env: "VOLTRO_WEBHOOK_SECRET_<ID>",