@voltro/cli 0.33.0 → 0.35.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 (343) hide show
  1. package/CHANGELOG.md +1968 -0
  2. package/bin/nodeEnvironment.d.mts +30 -0
  3. package/bin/nodeEnvironment.mjs +158 -0
  4. package/bin/voltro.mjs +69 -5
  5. package/dist/addCommand-BNeoeSxe.js +124 -0
  6. package/dist/addCommand-aXSQveak.js +2 -0
  7. package/dist/agentsMd-BTchIZku.js +2 -0
  8. package/dist/agentsMd-mhQMF1bx.js +254 -0
  9. package/dist/apiBuild-B8aoJvuw.js +2 -0
  10. package/dist/{apiBuild-h9VHtnlw.js → apiBuild-DYD_ONLD.js} +46 -46
  11. package/dist/{appGraph-gQ_6GkQQ.js → appGraph-KGDPTuTy.js} +1 -1
  12. package/dist/appGraph-zuMGKVYX.js +2 -0
  13. package/dist/appPort-B_HpJ_ck.js +48 -0
  14. package/dist/baselineCommand-C2ClWZN3.js +2 -0
  15. package/dist/baselineCommand-DIttzO8A.js +227 -0
  16. package/dist/bin.js +71 -28
  17. package/dist/build-CD8K4XOr.js +711 -0
  18. package/dist/cacheCommand-DA4OH9xt.js +42 -0
  19. package/dist/capabilitiesCommand-nq_pz5xd.js +123 -0
  20. package/dist/checkCommand-Ct9xkTrS.js +232 -0
  21. package/dist/checkCommand-DKpDLlqu.js +2 -0
  22. package/dist/{cliArgs-qdZSElM3.js → cliArgs-D4p8n7EE.js} +12 -1
  23. package/dist/cliError-BmdYnghb.js +10 -0
  24. package/dist/cliOutput-D1tSBoRM.js +15 -0
  25. package/dist/{cliRuntime-Oh517vCV.js → cliRuntime-Dh7UDinH.js} +20 -20
  26. package/dist/cloudClient-DWL-Hw_T.js +67 -0
  27. package/dist/cloudCmd-Cvv5HGaZ.js +364 -0
  28. package/dist/clusterCmd-D5wsCmA_.js +54 -0
  29. package/dist/codegen-CYM3Zqrf.js +605 -0
  30. package/dist/codegen-ChBi_hVa.js +2 -0
  31. package/dist/codegenCommand-C4YoQIc2.js +30 -0
  32. package/dist/codemodRunner-BnFq3Fgu.js +5384 -0
  33. package/dist/commandRunner-BLAEFLjp.js +47 -0
  34. package/dist/commands-BE8E7zF3.js +816 -0
  35. package/dist/connectionConfig-UFlIEiys.js +66 -0
  36. package/dist/dashboardCommand-D7SgZGaN.js +25 -0
  37. package/dist/dataCommand-BhYwDgg-.js +537 -0
  38. package/dist/dataProfile-dW-PsfLB.js +15 -0
  39. package/dist/dbCommand-DS4b97Is.js +2 -0
  40. package/dist/{dbCommand-DTLKAfbA.js → dbCommand-O8HA63s2.js} +552 -402
  41. package/dist/{dev-C_P8FLSx.js → dev-C7sFZq3m.js} +3670 -3169
  42. package/dist/dev-D2BikO7a.js +3 -0
  43. package/dist/devActivity-Dx_3nnGv.js +100 -0
  44. package/dist/devActivity.js +1 -1
  45. package/dist/dialectDriver-CgXnDfec.js +39 -0
  46. package/dist/discover-C9XKJDco.js +25 -0
  47. package/dist/doctorCommand-CM4Ch9C7.js +2 -0
  48. package/dist/{checkCommand-xGhRFFg2.js → doctorCommand-DnimF5IM.js} +523 -1278
  49. package/dist/dormancyCommand-QewYug_s.js +69 -0
  50. package/dist/e2eCmd-BRabZww-.js +147 -0
  51. package/dist/embeddingsCommand-BfiLS_QI.js +73 -0
  52. package/dist/envCommand-CCGPRQY1.js +60 -0
  53. package/dist/evalCommand-6RUfPen4.js +118 -0
  54. package/dist/evolveCommand-CHsLCtDf.js +281 -0
  55. package/dist/fileTaxonomy-CJfgOllU.js +457 -0
  56. package/dist/frameworkTableAssembly-YyVe32Cb.js +2 -0
  57. package/dist/frameworkTableAssembly-oMPBKqlE.js +511 -0
  58. package/dist/generateCommand-DbgcUpGw.js +147 -0
  59. package/dist/index.d.ts +45 -0
  60. package/dist/index.js +4 -3
  61. package/dist/infoCommand-DwOgK1t6.js +60 -0
  62. package/dist/{inspect-BUUjt773.js → inspect-CjTYzAs_.js} +113 -41
  63. package/dist/inspect-P4pxoMaV.js +2 -0
  64. package/dist/inspectCmd-EHFZ9yYu.js +224 -0
  65. package/dist/inspectFetch-EMuhTG_9.js +151 -0
  66. package/dist/inspectMetrics-CfdKLh6t.js +72 -0
  67. package/dist/loadEnv-D9nEOClM.js +44 -0
  68. package/dist/logFileSink-C_D2wRN1.js +105 -0
  69. package/dist/logsCmd-D36xK7Zu.js +260 -0
  70. package/dist/manifestBuild-COkJoyAr.js +2 -0
  71. package/dist/{manifestBuild-BLrVuSlM.js → manifestBuild-hpPLaGxV.js} +1 -1
  72. package/dist/metaCommands-7MJfZ5cf.js +196 -0
  73. package/dist/migrate-BV7I-ZHZ.js +83 -0
  74. package/dist/mssqlClusterPatch-_4cE_nun.js +44 -0
  75. package/dist/newCommand-COWOJ1_E.js +156 -0
  76. package/dist/nodeEnvironment-cGFAj1J8.js +28 -0
  77. package/dist/packageCommand-Cug_3Ogl.js +271 -0
  78. package/dist/pageConvention-cEiRxdab.js +5 -0
  79. package/dist/privacyCommand-C-Df56U_.js +146 -0
  80. package/dist/probeCommand-CZfaaUOZ.js +122 -0
  81. package/dist/projectScaffold-DmzEKHib.js +2 -0
  82. package/dist/projectScaffold-LMMtaavR.js +814 -0
  83. package/dist/renderModeScan-D7J1B7Kw.js +105 -0
  84. package/dist/renderProfile-1OWWAAtx.js +81 -0
  85. package/dist/runtimeRegistry-DMeKfTHP.js +81 -0
  86. package/dist/runtimeTrace-CH3eUiMw.js +91 -0
  87. package/dist/scheduleCmd-DQRu6BZC.js +149 -0
  88. package/dist/scheduleManifestCmd-D2x0CTTY.js +249 -0
  89. package/dist/schemaIr-UJybUUZW.js +103 -0
  90. package/dist/{sdkgen-C81QIkiL.js → sdkgen-BLkvGRfX.js} +111 -209
  91. package/dist/seedRunner-ZmLSqNe2.js +333 -0
  92. package/dist/serveCommand-CbDHU6l-.js +2 -0
  93. package/dist/serveCommand-iwlUBNS1.js +1766 -0
  94. package/dist/serveEntry.js +5 -5
  95. package/dist/serverlessCommand-CfJZy6dS.js +482 -0
  96. package/dist/start-BgN62boB.js +3 -0
  97. package/dist/start-T4VesWiM.js +1087 -0
  98. package/dist/startEntry.js +2 -2
  99. package/dist/staticCommand-Dr2M6tpU.js +304 -0
  100. package/dist/storageCommand-Co6NfLqN.js +42 -0
  101. package/dist/templates-De8IR5-c.js +102 -0
  102. package/dist/test-CI6iDsYc.js +115 -0
  103. package/dist/tracesCmd-DStmCJPi.js +232 -0
  104. package/dist/tsconfigPaths-BWXBWgcl.js +107 -0
  105. package/dist/tsxLoader-EuXmSJ1K.js +51 -0
  106. package/dist/typecheckCommand-BlsWiCNq.js +61 -0
  107. package/dist/updateCommand-BlMZhWgO.js +2 -0
  108. package/dist/updateCommand-x0pI_x-B.js +585 -0
  109. package/dist/webDev-BcykISYQ2.js +2 -0
  110. package/dist/{inspectMetrics-1xzTKAFx.js → webDev-Dybxew86.js} +988 -1560
  111. package/dist/webhookDiscovery-CrGAfhIG.js +2 -0
  112. package/dist/webhookDiscovery-D7VaeMlz.js +51 -0
  113. package/dist/webhooksCommand-DlAgS2Iw.js +267 -0
  114. package/dist/workflowsCmd-BGF-mRZ5.js +608 -0
  115. package/package.json +209 -17
  116. package/templates/AGENTS.core.md +58 -3
  117. package/templates/AGENTS.md +64 -7
  118. package/templates/agent-docs/_index.md +6 -4
  119. package/templates/agent-docs/_manifest.json +23 -6
  120. package/templates/agent-docs/ai.md +370 -0
  121. package/templates/agent-docs/authentication.md +313 -31
  122. package/templates/agent-docs/caching.md +6 -0
  123. package/templates/agent-docs/cli.md +853 -50
  124. package/templates/agent-docs/data.md +608 -12
  125. package/templates/agent-docs/database/migrations.md +223 -25
  126. package/templates/agent-docs/database/misc.md +156 -40
  127. package/templates/agent-docs/database/querying.md +19 -1
  128. package/templates/agent-docs/database/scaling.md +60 -0
  129. package/templates/agent-docs/database/schema.md +1 -0
  130. package/templates/agent-docs/database/seedsdialects.md +208 -19
  131. package/templates/agent-docs/database/transactions.md +68 -0
  132. package/templates/agent-docs/deployment.md +284 -25
  133. package/templates/agent-docs/introduction.md +88 -17
  134. package/templates/agent-docs/local-first-mobile.md +79 -4
  135. package/templates/agent-docs/multi-tenancy.md +188 -42
  136. package/templates/agent-docs/observability.md +58 -3
  137. package/templates/agent-docs/plugins/ai-flows.md +247 -2
  138. package/templates/agent-docs/plugins/analytics-postgres.md +1 -1
  139. package/templates/agent-docs/plugins/audit.md +37 -1
  140. package/templates/agent-docs/plugins/auth-social.md +143 -0
  141. package/templates/agent-docs/plugins/auth-workos.md +4 -2
  142. package/templates/agent-docs/plugins/auth.md +131 -6
  143. package/templates/agent-docs/plugins/billing.md +132 -15
  144. package/templates/agent-docs/plugins/cdc-out.md +46 -7
  145. package/templates/agent-docs/plugins/clickhouse.md +32 -1
  146. package/templates/agent-docs/plugins/duckdb.md +1 -1
  147. package/templates/agent-docs/plugins/flags.md +132 -0
  148. package/templates/agent-docs/plugins/governance.md +105 -7
  149. package/templates/agent-docs/plugins/multitenancy.md +9 -4
  150. package/templates/agent-docs/plugins/presence.md +13 -2
  151. package/templates/agent-docs/plugins/ratelimit.md +9 -0
  152. package/templates/agent-docs/plugins/search.md +162 -8
  153. package/templates/agent-docs/plugins/sso-saml.md +47 -8
  154. package/templates/agent-docs/plugins/storage.md +11 -0
  155. package/templates/agent-docs/plugins/webhooks.md +105 -0
  156. package/templates/agent-docs/plugins.md +152 -18
  157. package/templates/agent-docs/reference.md +60 -3
  158. package/templates/agent-docs/releases.md +1117 -0
  159. package/templates/agent-docs/routing.md +43 -25
  160. package/templates/agent-docs/scheduling.md +27 -0
  161. package/templates/agent-docs/schema-driven-ui.md +92 -12
  162. package/templates/agent-docs/security.md +426 -0
  163. package/templates/agent-docs/templates/apibackends.md +87 -18
  164. package/templates/agent-docs/templates/appshells.md +32 -14
  165. package/templates/agent-docs/templates/overview.md +13 -8
  166. package/templates/agent-docs/testing.md +211 -14
  167. package/templates/agent-docs/whats-new.md +98 -136
  168. package/templates/agent-docs/workflows.md +231 -14
  169. package/templates/apps/api-ai/actions/summarize.action.ts +11 -0
  170. package/templates/apps/api-ai/package.json +8 -7
  171. package/templates/apps/api-auth/actions/me.action.ts +13 -0
  172. package/templates/apps/api-auth/package.json +9 -8
  173. package/templates/apps/api-backend/mutations/notes.create.mutation.ts +9 -0
  174. package/templates/apps/api-backend/package.json +12 -8
  175. package/templates/apps/api-backend/queries/notes.query.ts +30 -8
  176. package/templates/apps/api-backend-deactivation/actions/users.get.action.ts +14 -0
  177. package/templates/apps/api-backend-deactivation/mutations/users.create.mutation.ts +8 -0
  178. package/templates/apps/api-backend-deactivation/mutations/users.deactivate.mutation.ts +10 -0
  179. package/templates/apps/api-backend-deactivation/package.json +8 -7
  180. package/templates/apps/api-backend-mail/actions/sendWelcome.action.ts +17 -0
  181. package/templates/apps/api-backend-mail/mutations/notes.create.mutation.ts +9 -0
  182. package/templates/apps/api-backend-mail/package.json +9 -8
  183. package/templates/apps/api-backend-mail/queries/notes.query.ts +30 -8
  184. package/templates/apps/api-backend-mariadb/.env.example +14 -0
  185. package/templates/apps/api-backend-mariadb/mutations/notes.create.mutation.ts +9 -0
  186. package/templates/apps/api-backend-mariadb/package.json +10 -9
  187. package/templates/apps/api-backend-mariadb/queries/notes.query.ts +30 -8
  188. package/templates/apps/api-backend-sqlite/.env.example +14 -0
  189. package/templates/apps/api-backend-sqlite/mutations/notes.create.mutation.ts +9 -0
  190. package/templates/apps/api-backend-sqlite/package.json +9 -8
  191. package/templates/apps/api-backend-sqlite/queries/notes.query.ts +30 -8
  192. package/templates/apps/api-backend-storage/actions/uploadAvatar.action.ts +13 -0
  193. package/templates/apps/api-backend-storage/actions/uploadDocument.action.ts +12 -0
  194. package/templates/apps/api-backend-storage/mutations/notes.create.mutation.ts +9 -0
  195. package/templates/apps/api-backend-storage/package.json +9 -8
  196. package/templates/apps/api-backend-storage/queries/notes.query.ts +30 -8
  197. package/templates/apps/api-cms/actions/content.get.action.ts +7 -0
  198. package/templates/apps/api-cms/actions/content.types.action.ts +6 -0
  199. package/templates/apps/api-cms/actions/me.action.ts +13 -0
  200. package/templates/apps/api-cms/app.config.ts +19 -0
  201. package/templates/apps/api-cms/authz.ts +63 -0
  202. package/templates/apps/api-cms/mutations/content.publish.mutation.ts +10 -0
  203. package/templates/apps/api-cms/mutations/content.saveDraft.mutation.ts +10 -0
  204. package/templates/apps/api-cms/mutations/content.unpublish.mutation.ts +5 -0
  205. package/templates/apps/api-cms/package.json +11 -10
  206. package/templates/apps/api-cms/queries/content.list.query.ts +23 -7
  207. package/templates/apps/api-cms/tests/accessDecisions.test.ts +121 -0
  208. package/templates/apps/api-cms/tests/content.descriptors.test.ts +8 -4
  209. package/templates/apps/api-collab/mutations/documents.create.mutation.ts +8 -0
  210. package/templates/apps/api-collab/mutations/documents.setBody.mutation.ts +13 -0
  211. package/templates/apps/api-collab/package.json +9 -8
  212. package/templates/apps/api-collab/queries/documents.query.ts +19 -7
  213. package/templates/apps/api-data-advanced/package.json +9 -8
  214. package/templates/apps/api-data-advanced/queries/authors.withBooks.query.ts +12 -0
  215. package/templates/apps/api-data-advanced/queries/books.search.query.ts +9 -0
  216. package/templates/apps/api-durable/mutations/orders.approve.mutation.ts +17 -0
  217. package/templates/apps/api-durable/mutations/orders.place.mutation.ts +9 -0
  218. package/templates/apps/api-durable/package.json +9 -8
  219. package/templates/apps/api-feature-flags/actions/notes.export.action.ts +16 -0
  220. package/templates/apps/api-feature-flags/mutations/notes.create.mutation.ts +12 -0
  221. package/templates/apps/api-feature-flags/package.json +10 -9
  222. package/templates/apps/api-governance/README.md +30 -8
  223. package/templates/apps/api-governance/actions/profiles.get.action.server.ts +17 -1
  224. package/templates/apps/api-governance/actions/profiles.get.action.ts +29 -4
  225. package/templates/apps/api-governance/database/schema.ts +16 -4
  226. package/templates/apps/api-governance/mutations/profiles.create.mutation.ts +12 -0
  227. package/templates/apps/api-governance/package.json +9 -8
  228. package/templates/apps/api-kv/actions/sync.pull.action.ts +15 -0
  229. package/templates/apps/api-kv/actions/sync.reset.action.ts +13 -0
  230. package/templates/apps/api-kv/actions/sync.status.action.ts +7 -0
  231. package/templates/apps/api-kv/package.json +9 -8
  232. package/templates/apps/api-kv/queries/events.list.query.ts +19 -8
  233. package/templates/apps/api-moderation/mutations/comments.create.mutation.ts +11 -0
  234. package/templates/apps/api-moderation/mutations/posts.create.mutation.ts +13 -0
  235. package/templates/apps/api-moderation/package.json +9 -8
  236. package/templates/apps/api-observability/mutations/notes.create.mutation.ts +8 -0
  237. package/templates/apps/api-observability/package.json +9 -8
  238. package/templates/apps/api-observability/queries/notes.list.query.ts +13 -0
  239. package/templates/apps/api-ratelimit/mutations/notes.create.mutation.ts +14 -0
  240. package/templates/apps/api-ratelimit/package.json +9 -8
  241. package/templates/apps/api-rbac/package.json +9 -8
  242. package/templates/apps/api-rest/package.json +8 -7
  243. package/templates/apps/api-saas/mutations/projects.create.mutation.ts +13 -0
  244. package/templates/apps/api-saas/package.json +12 -11
  245. package/templates/apps/api-saas/queries/projects.list.query.ts +11 -0
  246. package/templates/apps/api-saas-starter/actions/me.action.ts +13 -0
  247. package/templates/apps/api-saas-starter/app.config.ts +19 -0
  248. package/templates/apps/api-saas-starter/authz.ts +75 -0
  249. package/templates/apps/api-saas-starter/mutations/invites.create.mutation.ts +10 -0
  250. package/templates/apps/api-saas-starter/mutations/projects.create.mutation.ts +9 -0
  251. package/templates/apps/api-saas-starter/package.json +15 -11
  252. package/templates/apps/api-saas-starter/queries/invites.list.query.ts +19 -8
  253. package/templates/apps/api-saas-starter/queries/projects.list.query.ts +18 -7
  254. package/templates/apps/api-saas-starter/tests/accessDecisions.test.ts +135 -0
  255. package/templates/apps/api-search/mutations/articles.create.mutation.ts +14 -0
  256. package/templates/apps/api-search/package.json +9 -8
  257. package/templates/apps/api-search/queries/articles.list.query.ts +21 -8
  258. package/templates/apps/api-status/README.md +10 -3
  259. package/templates/apps/api-status/app.config.ts +8 -3
  260. package/templates/apps/api-status/authz.ts +5 -3
  261. package/templates/apps/api-status/package.json +9 -8
  262. package/templates/apps/api-status/queries/components.list.query.ts +14 -6
  263. package/templates/apps/api-status/queries/incidents.live.query.ts +23 -10
  264. package/templates/apps/api-status/queries/updates.list.query.ts +16 -9
  265. package/templates/apps/api-status/tests/status.test.ts +9 -1
  266. package/templates/apps/api-versioning/actions/documents.asOf.action.ts +12 -0
  267. package/templates/apps/api-versioning/actions/documents.history.action.ts +13 -0
  268. package/templates/apps/api-versioning/mutations/documents.create.mutation.ts +9 -0
  269. package/templates/apps/api-versioning/mutations/documents.update.mutation.ts +12 -0
  270. package/templates/apps/api-versioning/package.json +9 -8
  271. package/templates/apps/api-webhooks/mutations/orders.fulfill.mutation.ts +16 -0
  272. package/templates/apps/api-webhooks/package.json +10 -9
  273. package/templates/apps/api-webhooks/queries/orders.list.query.ts +10 -0
  274. package/templates/apps/changelog/package.json +8 -6
  275. package/templates/apps/edge-functions/package.json +2 -2
  276. package/templates/apps/frontend-admin/package.json +10 -8
  277. package/templates/apps/frontend-admin/src/lib/admin.ts +20 -9
  278. package/templates/apps/frontend-admin/src/locales/de.ts +11 -1
  279. package/templates/apps/frontend-admin/src/locales/en.ts +13 -1
  280. package/templates/apps/frontend-admin/src/pages/admin/[entity]/page.tsx +65 -22
  281. package/templates/apps/frontend-admin/src/pages/admin/entity.test.tsx +130 -23
  282. package/templates/apps/frontend-admin/src/pages/admin/layout.tsx +3 -2
  283. package/templates/apps/frontend-admin/src/pages/admin/page.test.tsx +19 -2
  284. package/templates/apps/frontend-admin/src/pages/admin/page.tsx +9 -4
  285. package/templates/apps/frontend-app/app.config.ts +4 -3
  286. package/templates/apps/frontend-app/package.json +11 -8
  287. package/templates/apps/frontend-app/src/lib/api.ts +25 -0
  288. package/templates/apps/frontend-app/src/pages/page.test.tsx +130 -82
  289. package/templates/apps/frontend-app/src/pages/page.tsx +14 -18
  290. package/templates/apps/frontend-auth/package.json +10 -8
  291. package/templates/apps/frontend-blank/package.json +9 -7
  292. package/templates/apps/frontend-cms/package.json +11 -9
  293. package/templates/apps/frontend-collab/package.json +12 -9
  294. package/templates/apps/frontend-collab/src/pages/page.test.tsx +122 -78
  295. package/templates/apps/frontend-contact/package.json +9 -7
  296. package/templates/apps/frontend-dashboard/package.json +9 -7
  297. package/templates/apps/frontend-docs/package.json +9 -7
  298. package/templates/apps/frontend-i18n/package.json +8 -6
  299. package/templates/apps/frontend-landing/package.json +9 -7
  300. package/templates/apps/frontend-portal/package.json +10 -8
  301. package/templates/apps/frontend-saas/app.config.ts +10 -6
  302. package/templates/apps/frontend-saas/package.json +10 -8
  303. package/templates/apps/frontend-saas/src/lib/api.ts +27 -32
  304. package/templates/apps/frontend-saas/src/pages/dashboard/billing/page.tsx +7 -8
  305. package/templates/apps/frontend-saas/src/pages/dashboard/page.test.tsx +27 -3
  306. package/templates/apps/frontend-saas/src/pages/dashboard/page.tsx +4 -4
  307. package/templates/apps/frontend-saas/src/pages/dashboard/team/page.tsx +3 -4
  308. package/templates/apps/frontend-spa/package.json +9 -7
  309. package/templates/apps/frontend-ssr/package.json +9 -7
  310. package/templates/apps/frontend-ssr-api/package.json +10 -8
  311. package/templates/apps/frontend-static-blog/package.json +8 -6
  312. package/templates/apps/frontend-status/package.json +10 -8
  313. package/templates/apps/mobile-app/README.md +1 -0
  314. package/templates/apps/mobile-app/package.json +4 -2
  315. package/templates/apps/mobile-app/src/app/index.tsx +22 -12
  316. package/templates/apps/mobile-app/src/app/orders/[id].tsx +1 -1
  317. package/templates/apps/mobile-app/src/lib/api.ts +34 -0
  318. package/templates/apps/mobile-app/voltro.mobile.ts +4 -2
  319. package/templates/baselines/bare/.env.example +14 -0
  320. package/templates/baselines/bare/baseline.json +4 -4
  321. package/templates/baselines/compose/.env.example +14 -0
  322. package/templates/baselines/compose/README.md +1 -1
  323. package/templates/baselines/compose/baseline.json +5 -5
  324. package/templates/baselines/compose-mariadb/.env.example +14 -0
  325. package/templates/baselines/compose-mariadb/README.md +1 -1
  326. package/templates/baselines/compose-mariadb/baseline.json +5 -5
  327. package/templates/baselines/helm/.env.example +14 -0
  328. package/templates/baselines/helm/baseline.json +4 -4
  329. package/dist/apiBuild-C-x9YacA.js +0 -2
  330. package/dist/appGraph-CvQCte0z.js +0 -2
  331. package/dist/checkCommand-DRovTKza.js +0 -2
  332. package/dist/commands-CJfepbm4.js +0 -11541
  333. package/dist/dbCommand-b1gum4td.js +0 -2
  334. package/dist/dev-iiMtlkfs.js +0 -3
  335. package/dist/devActivity-BhIu6ncs.js +0 -159
  336. package/dist/frameworkTableAssembly-BwIrO5nv.js +0 -638
  337. package/dist/frameworkTableAssembly-D-EebUQX.js +0 -2
  338. package/dist/inspect-mmBuRXmy.js +0 -2
  339. package/dist/manifestBuild-Dj8Jjoto.js +0 -2
  340. package/dist/seedRunner-Bqxgp7HZ.js +0 -230
  341. package/dist/serveCommand-DdaM4Hup.js +0 -1608
  342. package/dist/start-C0koT0UO.js +0 -1084
  343. /package/templates/apps/api-ai/actions/{summarize.action.server.tsx → summarize.action.server.ts} +0 -0
@@ -707,11 +707,13 @@ What still cannot defer on this path:
707
707
 
708
708
  `interactive` is **orthogonal** to `renderMode` — it controls how much JS runs in the browser. See [Islands](/docs/routing/islands).
709
709
 
710
- | `interactive` | What's hydrated |
711
- |---|---|
712
- | `'none'` | Nothing — pure HTML. |
713
- | `'islands'` | Only `*.island.tsx` files. |
714
- | `'full'` *(default)* | Whole page. |
710
+ | `interactive` | What's hydrated | JS shipped |
711
+ |---|---|---|
712
+ | `'none'` | Nothing — pure HTML. | None — the script tags are stripped. |
713
+ | `'islands'` | Only `*.island.tsx` files. | The full app bundle, same as `'full'`. |
714
+ | `'full'` *(default)* | Whole page. | The full app bundle. |
715
+
716
+ The third column is the one people get wrong: `'islands'` buys back hydration CPU, not download. Only `'none'` removes bytes. See [Islands](/docs/routing/islands) for the measured numbers.
715
717
 
716
718
  Combinations:
717
719
 
@@ -745,7 +747,7 @@ That last case is how dynamic `static` routes work in dev / when `getStaticPaths
745
747
  ## Where to read next
746
748
 
747
749
  - [Loaders & meta](/docs/routing/loaders-and-meta) — fetch data before render, inject `<head>` tags
748
- - [Islands](/docs/routing/islands) — pages that ship 0 JS except for explicit islands
750
+ - [Islands](/docs/routing/islands) — scope hydration to explicit islands (note: this reduces hydration work, not the JS payload `'none'` is the mode that removes bytes)
749
751
 
750
752
 
751
753
 
@@ -1659,7 +1661,7 @@ Useful when the prefetch trigger isn't a `<Link>` (e.g. an entire card area, whe
1659
1661
 
1660
1662
  _interactive: 'islands' — ship pure HTML with selectively-hydrated interactive components._
1661
1663
 
1662
- The **islands** model: serve the page as pure HTML, then hydrate only the bits that need interactivity. The rest of the page is just text + CSS — no React runtime, no JS bundle, no hydration cost.
1664
+ The **islands** model: serve the page as pure HTML, then hydrate only the bits that need interactivity. The rest of the page stays inert — no React lifecycle runs through it.
1663
1665
 
1664
1666
  Voltro implements islands per-page via the `interactive` export:
1665
1667
 
@@ -1668,7 +1670,15 @@ export const renderMode = 'static' as const
1668
1670
  export const interactive = 'islands' as const
1669
1671
  ```
1670
1672
 
1671
- With `interactive: 'islands'`, the framework strips the page's React runtime from the HTML, but loads `*.island.tsx` files as separate chunks + hydrates them in place.
1673
+ > **Islands cut hydration WORK, not DOWNLOAD read this before you pick the mode.**
1674
+ >
1675
+ > `interactive: 'islands'` ships **exactly the same JavaScript** as `interactive: 'full'`. Measured on the framework's reference fixture, the same page: `full` = 195,229 bytes gzipped of first-load JS, `islands` = 195,231 bytes. That is the whole difference — two bytes of noise.
1676
+ >
1677
+ > The reason is structural, not a missing optimisation pass: the generated browser entry imports `mount` and your `App` at value level, so the browser has already downloaded, parsed and evaluated the entire app bundle before the islands branch is even reached. Only `interactive: 'none'` removes bytes today — it strips every `<script type="module">` and `<link rel="modulepreload">` from the page's HTML.
1678
+ >
1679
+ > So islands are the right choice when the cost you want back is **CPU on the main thread** (hydration walking a large tree, effects firing across a page of prose). They are the wrong choice if you adopted them to make the download smaller — for that, use `interactive: 'none'` and put the interactive bits behind a separate page, or accept the full payload.
1680
+
1681
+ With `interactive: 'islands'`, the page's HTML keeps its script tags and the app bundle still loads; what changes is that `mount()` skips hydrating the page tree and instead scans for island markers, hydrating each one on its own schedule.
1672
1682
 
1673
1683
  ## When to use islands
1674
1684
 
@@ -1676,7 +1686,7 @@ With `interactive: 'islands'`, the framework strips the page's React runtime fro
1676
1686
  - **Docs** that are mostly text but have a search modal + theme toggle.
1677
1687
  - **Blog posts** with an embedded poll or comment widget.
1678
1688
 
1679
- The split lets you ship near-zero JS for the body + JS only for the islands. Lighthouse scores stay high; React's overhead applies only to the interactive parts.
1689
+ In each case what you get back is hydration time, not bytes: React's *runtime* overhead applies only to the interactive parts, while the *download* is unchanged. If the page has no interactive part at all, `interactive: 'none'` is strictly better it ships no JavaScript.
1680
1690
 
1681
1691
  ## Writing an island
1682
1692
 
@@ -1750,17 +1760,29 @@ Each island declares WHEN it hydrates via the `hydrate` option (default `'visibl
1750
1760
 
1751
1761
  Mix freely inside one page: a `load` search box, a `visible` comment widget, and a `never` build banner can all coexist.
1752
1762
 
1753
- ## Bundle savings
1763
+ ## What each mode actually costs
1754
1764
 
1755
- For a typical Voltro page:
1765
+ Measured on the framework's reference web fixture — the same page, three values of `interactive`, first-load JavaScript read out of the page's own built HTML (entry script + every `modulepreload`) and gzipped:
1756
1766
 
1757
- | Mode | JS shipped |
1758
- |---|---|
1759
- | `interactive: 'full'` | Full React + page bundle (~80-150 KB gzipped) |
1760
- | `interactive: 'islands'` | Island boot loader + island chunks (typically 10-30 KB gzipped) |
1761
- | `interactive: 'none'` | Zero |
1767
+ | Mode | JS shipped | Hydration |
1768
+ |---|---|---|
1769
+ | `interactive: 'full'` | 195,229 B gz | The whole page tree |
1770
+ | `interactive: 'islands'` | 195,231 B gz | Only the marked islands, each on its own strategy |
1771
+ | `interactive: 'none'` | 0 B — every module script and modulepreload is stripped from the HTML | None |
1772
+
1773
+ Two things to take from that table. **`islands` is not a download optimisation** — it is level with `full` to within two bytes, and the numbers above are the whole story, not a "before we finish the work" snapshot. And **`none` is the one that removes bytes**, because it is the only mode that removes the script tags.
1774
+
1775
+ The floor those first two numbers sit on is the framework's browser runtime — React plus the Effect-based RPC client — and it is pinned in CI so it cannot drift silently. Reproduce it yourself:
1776
+
1777
+ ```sh
1778
+ node packages/web/scripts/bundle-budget.mjs
1779
+ ```
1780
+
1781
+ ## Making islands reduce bytes too
1762
1782
 
1763
- For pages where the body never moves, the savings are dramatic.
1783
+ It is a real gap, and it is a build-pipeline change rather than a runtime one: the browser entry would have to be emitted *per page*, so an islands page's entry imports the island runtime and its own islands instead of the whole app. Nothing in the page's own code can shortcut it — the bytes are pulled in above `mount()`, by the entry that imports it.
1784
+
1785
+ Until then, if download size is what you are optimising, reach for `interactive: 'none'`.
1764
1786
 
1765
1787
  ## Island boundaries
1766
1788
 
@@ -1816,17 +1838,13 @@ If you need to pass a function reference, define it INSIDE the island.
1816
1838
 
1817
1839
  ## Inspecting
1818
1840
 
1819
- The build pipeline reports which chunks are islands:
1841
+ Each `*.island.tsx` becomes its own chunk, so `.framework/dist/assets/` carries an `island-<Name>-<hash>.js` per island alongside the app chunks. Listing that directory is the whole report:
1820
1842
 
1821
- ```
1822
- [voltro build] vite build…
1823
- chunks emitted:
1824
- main.abc.js 145 KB ← page runtime (full pages only)
1825
- island-LikeButton.def.js 3.4 KB ← per-island bundle
1826
- island-Search.ghi.js 8.1 KB
1843
+ ```sh
1844
+ ls -l .framework/dist/assets
1827
1845
  ```
1828
1846
 
1829
- Inspect dashboard's "Bundles" panel shows the per-island size + hydration timings.
1847
+ Per-island chunks are cached independently across deploys and fetched in parallel — but note they are *additional* files reachable from the app bundle, not a replacement for it. See the mode table above for what actually reaches the browser.
1830
1848
 
1831
1849
  ## Anti-patterns
1832
1850
 
@@ -355,6 +355,16 @@ replica C ─┘ └─ PK conflict → stands down (no
355
355
 
356
356
  Losers don't write a run row — at scale that would be N−1 noise rows per firing. Only the winner's run appears in the dashboard, tagged `wonLock`.
357
357
 
358
+ **If your app registers its own bound for a framework table, yours wins.** `registerRetention({ table, timeColumn, ttlMs })` from a startup outranks the framework's default for the same table — app > plugin > framework, and `source` defaults to `'app'` so you do not have to pass anything. A real disagreement is reported at boot, on the line beside the policy that survived:
359
+
360
+ ```
361
+ ! _voltro_schedule_claims: two registrations — kept the app's 1h,
362
+ dropped the framework's 24h. An app registration wins over a plugin's,
363
+ and a plugin's over a framework default.
364
+ ```
365
+
366
+ Through 0.32.0 this was a silent last-write-wins: a consumer's 1-hour bound was replaced one second later by the framework's default, their startup went on logging `bounded to 1h` at every boot, and they found it by counting rows. Note the direction — the loser is chosen by WHO registered, not by which TTL is narrower. "Narrower wins" would let a framework default we tighten in a later release silently start deleting your data faster than you asked for.
367
+
358
368
  ## `cluster`
359
369
 
360
370
  If you already run `@effect/cluster` (for [workflows](/docs/workflows/cluster)), schedules can ride the same sharding fabric. Each schedule becomes a `ClusterCron` singleton; the cluster assigns it to exactly one shard owner, and only that runner fires. The in-app `self` timer is **not** armed in this mode — the cluster owns the clock, so arming it too would double-fire.
@@ -559,6 +569,23 @@ Backfill runs **before** the live timer is armed, so a caught-up firing never ra
559
569
 
560
570
  Missed slots recorded under `latest` show up in the dashboard with the `missed` status — visible evidence of the gap, not a silent hole.
561
571
 
572
+ ## Backfilling an explicit range — `voltro schedule backfill`
573
+
574
+ Boot backfill only walks forward from the **last recorded run**, and cluster-cron coordination caps its own catch-up at one day. A longer outage — or a schedule added after the fact that should have "always existed" — needs an explicit operator instruction naming the range:
575
+
576
+ ```sh
577
+ voltro schedule backfill hourly-sync --from 2026-08-10T00:00:00Z --to 2026-08-12T00:00:00Z
578
+ ```
579
+
580
+ Every cron occurrence in `(from, to]` fires **sequentially, in order, each against its own cron-derived `scheduledAt`** — a handler (or a `workflow:` payload function) reading `ctx.scheduledAt` computes against its slot, not "now". Firings record as `trigger: 'manual'` in `_voltro_schedule_runs`, so the catch-up is a legible ledger; a failed slot records its failure and the next slot still fires.
581
+
582
+ The verb is **bounded and confirmable**, because a range verb that can enqueue 100k runs is an outage generator:
583
+
584
+ - Above **25** occurrences it refuses and prints the count — re-run with `--yes` after reading the number.
585
+ - Above the per-request cap (default **1,000**, raisable with `--limit` up to a hard ceiling of 10,000) it refuses outright, firing **nothing** — never a silent prefix that reports completeness. Run bigger catch-ups in slices.
586
+
587
+ The same verb is `POST /_voltro/inspect/schedules/:name/backfill` with `{ "from", "to", "confirm", "limit" }` (a refusal answers `409` with the count and reason), on `voltro dev` and `voltro serve` alike — it needs the inspect surface open (`VOLTRO_INSPECT_TOKEN`).
588
+
562
589
 
563
590
 
564
591
  ---
@@ -583,8 +583,23 @@ stack lives on the server, it survives a page reload.
583
583
  Capture has a per-mutation cost (a read-before-write on update/delete + a
584
584
  log-row insert), so it's **on outside production, off in production** by default;
585
585
  set `VOLTRO_UNDO=on|off` to override (the same environment-aware default the
586
- durable trace persistence uses). When off, the table isn't created, nothing is
587
- captured, and the built-ins aren't served or codegen'd.
586
+ durable trace persistence uses). When capture is off, `_voltro_undo_log` isn't
587
+ created and nothing is recorded.
588
+
589
+ **The WIRE SURFACE is a separate question, and it reads only the explicit
590
+ declaration.** The three `__voltro.undo.*` procedures are generated into the
591
+ client's rpc group and bound on the server unless `VOLTRO_UNDO=off` — regardless
592
+ of `NODE_ENV`. The reason is that `rpcGroup.generated.ts` is written by `voltro
593
+ dev` and `voltro build` never regenerates it: an environment-derived answer baked
594
+ there is the developer machine's answer shipped to a production process that
595
+ binds none of it, and the failure appears only when someone presses undo after a
596
+ deploy.
597
+
598
+ So with capture off, the procedures exist and answer honestly rather than 404:
599
+ `useUndoLog` returns an empty list (nothing was captured) and apply/redo answer
600
+ `UndoNotFound`. Both boot paths log a line at startup saying so, so a
601
+ permanently empty undo list is not a mystery. `VOLTRO_UNDO=off` removes the
602
+ procedures from the server AND from the client bundle.
588
603
 
589
604
  ## Boundaries
590
605
 
@@ -887,17 +902,18 @@ The manifest carries:
887
902
 
888
903
  | Field | Contents |
889
904
  |---|---|
890
- | `procedures` | Every procedure's `tag`, `kind`, `input`/`output` Schema, plus the `source` table a query reads and the `targets` (`{ table, op }`) a mutation writes. |
891
- | `tables` | The user tables — `name`, `columns` (`type`, `nullable`, `refersTo`, `enum`), and whether the table is `reactive`. Framework `_voltro_*` tables are flagged `framework`. |
905
+ | `procedures` | Every procedure's `tag`, `kind`, `input`/`output` Schema, the `source` table a query reads, the `targets` (`{ table, op }`) a mutation writes, and the `guards` it declares. |
906
+ | `tables` | The user tables — `name`, `columns` (`type`, `nullable`, `refersTo`, `enum`, and the three exposure axes), `pkColumn`, `editable`, and whether the table is `reactive`. Framework `_voltro_*` tables are flagged `framework`. |
892
907
  | `workflows` | The discovered workflow names. |
893
908
  | `widgets` | The registered widget ids. |
909
+ | `scopes` | Every scope the installed plugins declare. Empty means "not declared" — never "no scopes exist". |
894
910
  | `version` | The manifest format version. |
895
911
 
896
912
  ## Deriving an admin surface
897
913
 
898
914
  `deriveEntityAdmins(manifest)` is the pure projection the [admin
899
915
  template](/docs/templates/admin) is built on. It joins each user table to the
900
- procedures that read and write it, so a generated back-office binds to tags that
916
+ procedures that read and write it, so a back-office binds to tags that
901
917
  **actually exist** instead of guessing them from a naming convention:
902
918
 
903
919
  ```tsx
@@ -905,15 +921,71 @@ import { useCapabilityManifest, deriveEntityAdmins } from '@voltro/client'
905
921
 
906
922
  const { manifest } = useCapabilityManifest('app')
907
923
  const entities = manifest ? deriveEntityAdmins(manifest) : []
908
- // each: { table, columns, reactive, listTag?, createTag?, updateTag?, deleteTag?,
909
- // createScope, writeScope, deleteScope }
924
+ // each: { table, columns, serverOnlyColumns, sensitiveColumns, reactive,
925
+ // pkColumn?, editable,
926
+ // list, create, update, delete } // each an { tag?, guards? }
910
927
  ```
911
928
 
912
- A tag is `undefined` when the app exposes no procedure for that operation — render
913
- that affordance read-only rather than binding to a tag that does not resolve. The
914
- `*Scope` strings are the conventional names the UI gates writes on via
915
- [`useCan`](/docs/ui/client-utilities/use-can); map them to your app's real RBAC
916
- scopes.
929
+ An action's `tag` is `undefined` when the app exposes no procedure for that
930
+ operation — render that affordance read-only rather than binding to a tag that
931
+ does not resolve.
932
+
933
+ ### Why derive at runtime instead of generating an admin
934
+
935
+ A generated back-office snapshots the answer at codegen time. The moment you edit
936
+ `guards:` on a mutation the generated gate is stale — and stale in the silent
937
+ direction: it renders a control the server now refuses, or hides one that would
938
+ work. The manifest is served by the **running** app, so a derived surface cannot
939
+ drift from it. Customisation is not the tradeoff it looks like: the derived spec
940
+ is plain data, and the component that maps over it is your own template code.
941
+
942
+ ## Gating on the access the api declares
943
+
944
+ Each action carries `guards` — the procedure's own `guards:` / `openAccess:`
945
+ declaration, the same data the server enforces. `useAccessDecision` turns it into
946
+ a decision against the scopes you fed
947
+ [`<PermissionProvider>`](/docs/ui/client-utilities/use-can):
948
+
949
+ ```tsx
950
+ import { useAccessDecision, requiredScopes } from '@voltro/client'
951
+
952
+ const decision = useAccessDecision(entity.create.guards) // 'allowed' | 'denied' | 'unknown'
953
+ {entity.create.tag && decision !== 'denied' ? <AutoForm … /> : null}
954
+ {decision === 'denied' ? <p>Requires {requiredScopes(entity.create.guards).join(', ')}</p> : null}
955
+ ```
956
+
957
+ **The decision is three-valued, and `unknown` is the important one.** A guard that
958
+ carries a `resource` extractor is answered per **row** by the server, and a browser
959
+ holding only the subject's global scopes cannot pre-compute it. Both ways of
960
+ collapsing that gap are bugs:
961
+
962
+ | Collapse | What ships |
963
+ |---|---|
964
+ | `unknown` → `denied` | Every affordance disappears for callers whose authority is per-resource — the multi-tenant case, where subjects are minted with no global scopes. A total outage wearing a permission check's clothes. |
965
+ | `unknown` → `allowed` | A control that always errors. |
966
+
967
+ So show it and let the server answer: it is the authorization boundary, and it
968
+ replies with a typed `ScopeError`. `decideAccess(guards, scopes)` is the pure form
969
+ if you need it outside React.
970
+
971
+ `guards: undefined` means the procedure declared **neither** `guards:` nor
972
+ `openAccess:` — undecided, not open. That is refused outright under
973
+ `security.defaultDeny`, so it is reported as `unknown` rather than guessed.
974
+
975
+ ## The three exposure axes in a derived UI
976
+
977
+ The manifest's columns carry all three schema markers, and they are **orthogonal** —
978
+ `deriveEntityAdmins` treats each one differently, and so must you:
979
+
980
+ | Marker | What it says | What the admin does |
981
+ |---|---|---|
982
+ | `.serverOnly()` | Never crosses **any** wire; the runtime refuses a mutation input that sets it | **Excluded** from `columns`; listed in `serverOnlyColumns` so the UI can say why it is absent |
983
+ | `.encrypted()` | Ciphertext **at rest** | **Kept.** Your procedures read it decrypted — hiding it is a category error |
984
+ | `.sensitive(class)` | Personal data; the **export**-masking axis | **Kept**, and listed in `sensitiveColumns` so a bulk export masks it |
985
+
986
+ `pkColumn` is the column row-keyed actions must target — do not hard-code `id`. When
987
+ a table has no single primary key, `editable` is `false` and no row can be addressed
988
+ for update or delete.
917
989
 
918
990
  The manifest GET is bearer-gated wherever it runs — `/_voltro/inspect/*` is
919
991
  fail-closed, so no configured `VOLTRO_INSPECT_TOKEN` means `401`, not "everyone".
@@ -1088,6 +1160,14 @@ middleware again and resolves the new subject.
1088
1160
  Optimistic patches survive the refresh: they are tied to mutation lifecycles, not
1089
1161
  subscription lifecycles, and the new snapshots land underneath them.
1090
1162
 
1163
+ The **data does not** — each entry's rows are cleared and the components go back
1164
+ to `loading` until their new snapshot arrives. That is deliberate: the whole
1165
+ reason to call this is that the identity changed, and the new subject may be
1166
+ entitled to strictly less than the old one. It is the same boundary that stops a
1167
+ [reconnect](/docs/data/subscriptions#reconnect) from seeding across a
1168
+ `useReconnect()` — a dropped connection keeps your screen, a change of identity
1169
+ clears it.
1170
+
1091
1171
  This is not a cache-invalidation tool. Subscriptions are already live, so a
1092
1172
  normal write needs no refresh — reach for this only when the *connection's
1093
1173
  identity* changed underneath them.