@voltro/cli 0.51.0 → 0.52.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 (164) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/dist/{agentsMd-D6yD7IQv.js → agentsMd-0l980yhL.js} +4 -1
  3. package/dist/agentsMd-SDDSkyl4.js +2 -0
  4. package/dist/apiBuild-BYBpL7Pz.js +2 -0
  5. package/dist/{apiBuild-CPDHXF72.js → apiBuild-CSFI8QGq.js} +3 -3
  6. package/dist/bin.js +1 -1
  7. package/dist/build-CPgcMQug.js +793 -0
  8. package/dist/checkCommand-2SbqzukH.js +2 -0
  9. package/dist/{checkCommand-DNuPiWMc.js → checkCommand-COmqc2cB.js} +92 -46
  10. package/dist/{cloudCmd-F4YJeqM3.js → cloudCmd-QUXh-b5w.js} +1 -1
  11. package/dist/codegen-CctkDO-1.js +2 -0
  12. package/dist/{codegen-CrMXs4hb.js → codegen-VF479Cnb.js} +1 -1
  13. package/dist/{codegenCommand-BNBHcNNj.js → codegenCommand-DCdG2JN-.js} +12 -12
  14. package/dist/{codemodRunner-BDVixlSw.js → codemodRunner-r7J9lIa7.js} +588 -540
  15. package/dist/{commands-B1OiS9bX.js → commands-Cc_nV8WI.js} +35 -35
  16. package/dist/{dashboardCommand-C-vvPY1B.js → dashboardCommand-C-gKvwqh.js} +5 -5
  17. package/dist/{dataCommand-C1GxXW5q.js → dataCommand-BgpBHnlB.js} +27 -27
  18. package/dist/dbCommand-DNb6yeOG.js +2 -0
  19. package/dist/{dbCommand-If4Y1xQ-.js → dbCommand-sHedr-NJ.js} +2 -2
  20. package/dist/dev--A3nsxA3.js +3 -0
  21. package/dist/{dev-kdAg9Q7l.js → dev-CRHoCEiy.js} +2142 -2103
  22. package/dist/doctorCommand-CqoWA2p5.js +2 -0
  23. package/dist/{doctorCommand-nKmeW78u.js → doctorCommand-DtfJ3FA6.js} +314 -234
  24. package/dist/{dormancyCommand-CY3wa_SW.js → dormancyCommand-Drn7o0No.js} +1 -1
  25. package/dist/{embeddingsCommand-BDLIgje_.js → embeddingsCommand-Z-jO1fWN.js} +1 -1
  26. package/dist/{envCommand-C6V_xVlT.js → envCommand-D4gCrrTZ.js} +8 -8
  27. package/dist/{evolveCommand-D3c4DSfN.js → evolveCommand-CMROeKeA.js} +2 -2
  28. package/dist/fileConventions-DOqD3lPS.js +34 -0
  29. package/dist/{fileTaxonomy-CJfgOllU.js → fileTaxonomy-DvDUV9wq.js} +1 -1
  30. package/dist/frameworkTableAssembly-C6ETawPR.js +2 -0
  31. package/dist/{frameworkTableAssembly-BwJVEKLr.js → frameworkTableAssembly-w-XnLa3q.js} +1 -1
  32. package/dist/index.js +1 -1
  33. package/dist/{infoCommand-BnRFEF1o.js → infoCommand-DXM868o_.js} +1 -1
  34. package/dist/inspectMetrics-CGF94puw.js +143 -0
  35. package/dist/{metaCommands-CfRLra0s.js → metaCommands-C6RFmF1r.js} +2 -2
  36. package/dist/{migrate-DehuBakM.js → migrate-D0F-eTlK.js} +2 -2
  37. package/dist/{pageConvention-cEiRxdab.js → pageConvention-CzUiSbtU.js} +1 -1
  38. package/dist/{privacyCommand-XejDMvmu.js → privacyCommand-DGdopOI6.js} +1 -1
  39. package/dist/{projectScaffold-mIX_DpSe.js → projectScaffold-B4dmTlwT.js} +1 -1
  40. package/dist/{projectScaffold-BIl97_E6.js → projectScaffold-EzlErR4E.js} +1 -1
  41. package/dist/{renderModeScan-D7J1B7Kw.js → renderModeScan-CcH2X1_D.js} +25 -10
  42. package/dist/{renderProfile-1OWWAAtx.js → renderProfile-Ck32Fzxr.js} +2 -2
  43. package/dist/{runtimeTrace-ZsBU7Tkx.js → runtimeTrace-BPQyCmC5.js} +1 -1
  44. package/dist/{sdkgen-O4XqWOjM.js → sdkgen-Se88ifTd.js} +1 -1
  45. package/dist/serveCommand-DLc-BznW.js +2 -0
  46. package/dist/{serveCommand-DdiYNBBu.js → serveCommand-DkP3OT0W.js} +885 -868
  47. package/dist/serveEntry.js +1 -1
  48. package/dist/start-DfL3fOiN.js +3 -0
  49. package/dist/start-jw89Xbqy.js +1339 -0
  50. package/dist/startEntry.js +1 -1
  51. package/dist/{staticCommand-Dr2M6tpU.js → staticCommand-BwNEDlSU.js} +1 -1
  52. package/dist/{test-rXFq4S76.js → test-f3amja6a.js} +1 -1
  53. package/dist/updateCommand-5gFVfK5q.js +2 -0
  54. package/dist/{updateCommand-Bs322Q78.js → updateCommand-BMk2e4ky.js} +1 -1
  55. package/dist/{webDev-B-ubQEMX.js → webDev-BgWL9gKV.js} +1156 -835
  56. package/dist/webDev-CZbTsDcH.js +2 -0
  57. package/dist/{webhooksCommand-FLYY9IXh.js → webhooksCommand-CoIO3jbj.js} +1 -1
  58. package/package.json +30 -17
  59. package/templates/AGENTS.core.md +11 -0
  60. package/templates/AGENTS.md +15 -4
  61. package/templates/agent-docs/_index.md +4 -4
  62. package/templates/agent-docs/_manifest.json +11 -11
  63. package/templates/agent-docs/cli.md +96 -14
  64. package/templates/agent-docs/data.md +210 -7
  65. package/templates/agent-docs/database/schema.md +1 -1
  66. package/templates/agent-docs/database/seedsdialects.md +1 -1
  67. package/templates/agent-docs/deployment.md +22 -3
  68. package/templates/agent-docs/introduction.md +46 -0
  69. package/templates/agent-docs/local-first-mobile.md +34 -7
  70. package/templates/agent-docs/plugins/ai-flows.md +1 -1
  71. package/templates/agent-docs/plugins/audit.md +5 -5
  72. package/templates/agent-docs/plugins/cdc-out.md +2 -2
  73. package/templates/agent-docs/plugins/{versioning.md → row-history.md} +22 -22
  74. package/templates/agent-docs/plugins/storage.md +2 -2
  75. package/templates/agent-docs/plugins.md +29 -7
  76. package/templates/agent-docs/reference.md +39 -2
  77. package/templates/agent-docs/routing.md +341 -47
  78. package/templates/agent-docs/schema-driven-ui.md +78 -2
  79. package/templates/agent-docs/security.md +125 -8
  80. package/templates/agent-docs/templates/apibackends.md +14 -14
  81. package/templates/agent-docs/templates/overview.md +1 -1
  82. package/templates/agent-docs/whats-new.md +76 -53
  83. package/templates/apps/api-ai/package.json +6 -7
  84. package/templates/apps/api-ai/tests/summarize.test.ts +1 -1
  85. package/templates/apps/api-auth/package.json +8 -8
  86. package/templates/apps/api-backend/package.json +7 -7
  87. package/templates/apps/api-backend-deactivation/package.json +7 -7
  88. package/templates/apps/api-backend-mail/package.json +8 -8
  89. package/templates/apps/api-backend-mariadb/package.json +9 -9
  90. package/templates/apps/api-backend-sqlite/package.json +8 -8
  91. package/templates/apps/api-backend-storage/package.json +8 -8
  92. package/templates/apps/api-cms/package.json +9 -10
  93. package/templates/apps/api-collab/package.json +8 -8
  94. package/templates/apps/api-data-advanced/package.json +8 -8
  95. package/templates/apps/api-durable/package.json +8 -8
  96. package/templates/apps/api-feature-flags/package.json +9 -9
  97. package/templates/apps/api-governance/package.json +8 -8
  98. package/templates/apps/api-kv/package.json +8 -8
  99. package/templates/apps/api-moderation/package.json +8 -8
  100. package/templates/apps/api-observability/package.json +8 -8
  101. package/templates/apps/api-ratelimit/package.json +8 -8
  102. package/templates/apps/api-rbac/package.json +8 -8
  103. package/templates/apps/api-rest/package.json +7 -7
  104. package/templates/apps/{api-versioning → api-row-history}/README.md +3 -3
  105. package/templates/apps/{api-versioning → api-row-history}/actions/documents.asOf.action.server.ts +1 -1
  106. package/templates/apps/{api-versioning → api-row-history}/actions/documents.history.action.server.ts +1 -1
  107. package/templates/apps/{api-versioning → api-row-history}/app.config.ts +3 -3
  108. package/templates/apps/{api-versioning → api-row-history}/database/schema.ts +1 -1
  109. package/templates/apps/{api-versioning → api-row-history}/mutations/documents.create.mutation.server.ts +1 -1
  110. package/templates/apps/{api-versioning → api-row-history}/mutations/documents.create.mutation.ts +1 -1
  111. package/templates/apps/{api-versioning → api-row-history}/mutations/documents.update.mutation.ts +1 -1
  112. package/templates/apps/{api-versioning → api-row-history}/package.json +8 -8
  113. package/templates/apps/api-row-history/template.json +6 -0
  114. package/templates/apps/{api-versioning → api-row-history}/tests/documents.create.test.ts +1 -1
  115. package/templates/apps/api-saas/app.config.ts +1 -0
  116. package/templates/apps/api-saas/package.json +10 -11
  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/package.json +6 -6
  122. package/templates/apps/edge-functions/package.json +2 -2
  123. package/templates/apps/frontend-admin/package.json +8 -8
  124. package/templates/apps/frontend-app/package.json +9 -9
  125. package/templates/apps/frontend-auth/package.json +8 -8
  126. package/templates/apps/frontend-blank/package.json +7 -7
  127. package/templates/apps/frontend-cms/package.json +9 -9
  128. package/templates/apps/frontend-collab/package.json +10 -10
  129. package/templates/apps/frontend-collab/src/pages/page.test.tsx +10 -9
  130. package/templates/apps/frontend-collab/src/pages/page.tsx +42 -65
  131. package/templates/apps/frontend-contact/package.json +7 -7
  132. package/templates/apps/frontend-dashboard/package.json +7 -7
  133. package/templates/apps/frontend-docs/package.json +6 -7
  134. package/templates/apps/frontend-i18n/package.json +6 -6
  135. package/templates/apps/frontend-landing/package.json +6 -7
  136. package/templates/apps/frontend-portal/package.json +8 -8
  137. package/templates/apps/frontend-saas/package.json +8 -8
  138. package/templates/apps/frontend-spa/package.json +7 -7
  139. package/templates/apps/frontend-ssr/package.json +7 -7
  140. package/templates/apps/frontend-ssr-api/package.json +8 -8
  141. package/templates/apps/frontend-static-blog/package.json +6 -6
  142. package/templates/apps/frontend-status/package.json +8 -8
  143. package/templates/apps/mobile-app/package.json +4 -4
  144. package/dist/agentsMd-Bu_XQgVf.js +0 -2
  145. package/dist/apiBuild-GDKuGOMV.js +0 -2
  146. package/dist/build-DETLZAFt.js +0 -752
  147. package/dist/checkCommand-CWcnDArJ.js +0 -2
  148. package/dist/codegen-DiMn2KkZ.js +0 -2
  149. package/dist/dbCommand-C27HIsGE.js +0 -2
  150. package/dist/dev-CK522MV5.js +0 -3
  151. package/dist/doctorCommand-BK4l18eG.js +0 -2
  152. package/dist/fileConventions-Cof68_BL.js +0 -33
  153. package/dist/frameworkTableAssembly-CVDB2hCq.js +0 -2
  154. package/dist/inspectMetrics-CfdKLh6t.js +0 -72
  155. package/dist/serveCommand-BRnPCxVd.js +0 -2
  156. package/dist/start-BLNmWkLa.js +0 -1154
  157. package/dist/start-Dzicuyw8.js +0 -3
  158. package/dist/updateCommand-eXB35SEv.js +0 -2
  159. package/dist/webDev-DposiF3j.js +0 -2
  160. package/templates/apps/api-versioning/template.json +0 -6
  161. /package/templates/apps/{api-versioning → api-row-history}/actions/documents.asOf.action.ts +0 -0
  162. /package/templates/apps/{api-versioning → api-row-history}/actions/documents.history.action.ts +0 -0
  163. /package/templates/apps/{api-versioning → api-row-history}/mutations/documents.update.mutation.server.ts +0 -0
  164. /package/templates/apps/{api-versioning → api-row-history}/tsconfig.json +0 -0
@@ -0,0 +1,2 @@
1
+ import { b as e, v as t } from "./webDev-BgWL9gKV.js";
2
+ export { t as tryRunWebServe, e as walkPagesTree };
@@ -222,7 +222,7 @@ createVerifier({ secret: [process.env.WEBHOOK_SECRET, process.env.WEBHOOK_SECRET
222
222
  ...t === void 0 ? {} : { payload: t }
223
223
  };
224
224
  }, S = u({ scope: "voltro:webhooks" }), C = ["--out", "--name"], w = async (e) => {
225
- let { walk: t, loadDiscovered: n } = await import("./dev-CK522MV5.js"), { outgoingFromEvents: r } = await import("./webhookDiscovery-il9ti-HE.js");
225
+ let { walk: t, loadDiscovered: n } = await import("./dev--A3nsxA3.js"), { outgoingFromEvents: r } = await import("./webhookDiscovery-il9ti-HE.js");
226
226
  return r((await n(await t(e))).events.map((e) => ({
227
227
  file: e.file,
228
228
  descriptor: e.descriptor
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/cli",
3
- "version": "0.51.0",
3
+ "version": "0.52.0",
4
4
  "description": "The `voltro` CLI — dev server, codegen, migrations, project scaffolding, agent-docs seeding, and production serve.",
5
5
  "keywords": [
6
6
  "voltro",
@@ -718,6 +718,18 @@
718
718
  "title": "`<I18nProvider>`: `timeZone` is its own prop, not an `intlConfig` member",
719
719
  "kind": "transform"
720
720
  },
721
+ {
722
+ "version": "0.52.0",
723
+ "id": "0.52.0/01_plugin-versioning-to-row-history",
724
+ "title": "@voltro/plugin-versioning → @voltro/plugin-row-history (the name now says what it does)",
725
+ "kind": "transform"
726
+ },
727
+ {
728
+ "version": "0.52.0",
729
+ "id": "0.52.0/02_http-interceptor-fail-closed",
730
+ "title": "A throwing `onHttpRequest` interceptor now refuses the request (500) instead of being ignored",
731
+ "kind": "manual"
732
+ },
721
733
  {
722
734
  "version": "0.6.0",
723
735
  "id": "0.6.0/01_no-dev-session-secret",
@@ -793,22 +805,23 @@
793
805
  "@effect/platform-node": "^0.108.0",
794
806
  "@effect/sql": "^0.52.0",
795
807
  "@effect/workflow": "^0.19.0",
796
- "@voltro/ai": "0.51.0",
797
- "@voltro/cache": "0.51.0",
798
- "@voltro/data-transfer": "0.51.0",
799
- "@voltro/database": "0.51.0",
800
- "@voltro/env": "0.51.0",
801
- "@voltro/kv": "0.51.0",
802
- "@voltro/logger": "0.51.0",
803
- "@voltro/plugin-auth": "0.51.0",
804
- "@voltro/plugin-broadcast": "0.51.0",
805
- "@voltro/plugin-mail": "0.51.0",
806
- "@voltro/plugin-storage": "0.51.0",
807
- "@voltro/plugin-webhooks": "0.51.0",
808
- "@voltro/protocol": "0.51.0",
809
- "@voltro/runtime": "0.51.0",
810
- "@voltro/serverless": "0.51.0",
811
- "@voltro/workflow": "0.51.0",
808
+ "@voltro/ai": "0.52.0",
809
+ "@voltro/cache": "0.52.0",
810
+ "@voltro/client": "0.52.0",
811
+ "@voltro/data-transfer": "0.52.0",
812
+ "@voltro/database": "0.52.0",
813
+ "@voltro/env": "0.52.0",
814
+ "@voltro/kv": "0.52.0",
815
+ "@voltro/logger": "0.52.0",
816
+ "@voltro/plugin-auth": "0.52.0",
817
+ "@voltro/plugin-broadcast": "0.52.0",
818
+ "@voltro/plugin-mail": "0.52.0",
819
+ "@voltro/plugin-storage": "0.52.0",
820
+ "@voltro/plugin-webhooks": "0.52.0",
821
+ "@voltro/protocol": "0.52.0",
822
+ "@voltro/runtime": "0.52.0",
823
+ "@voltro/serverless": "0.52.0",
824
+ "@voltro/workflow": "0.52.0",
812
825
  "chokidar": "^5.0.0",
813
826
  "ioredis": "^5.11.1",
814
827
  "tinyglobby": "^0.2.17",
@@ -696,6 +696,17 @@ primitive → just save; the supervised dev loop respawns and regenerates.
696
696
  - **Don't roll your own session token / ICU/i18n / job runner** — use
697
697
  `signSession`/`verifySession`, `@voltro/i18n`, `@effect/workflow`.
698
698
  - **Don't add `bullmq`/`temporal`/`react-query`/SWR** — see Mental model.
699
+ - **Don't build a GraphQL layer over the stores.** It would bypass the
700
+ reactivity path (source-based invalidation, per-delivery guards) — a second,
701
+ dead read path. External consumers → REST + OpenAPI (`defineRestRoute` +
702
+ `@voltro/plugin-openapi`); internal clients → RPC + live subscriptions.
703
+ - **Don't write `'use server'` / `'use client'` — there is no RSC.** Islands +
704
+ loaders + streaming SSR are the model; those directives mark a boundary this
705
+ framework does not have.
706
+ - **Don't split the app into microservices with service-to-service RPC.** One
707
+ monolith process, scaled by running more replicas (`@effect/cluster` shards
708
+ durable workflows across instances), is the architecture. An external system
709
+ boundary is REST + OpenAPI; a reliable outbound effect is `ctx.outbox`.
699
710
 
700
711
  ## Plugins
701
712
 
@@ -696,6 +696,17 @@ primitive → just save; the supervised dev loop respawns and regenerates.
696
696
  - **Don't roll your own session token / ICU/i18n / job runner** — use
697
697
  `signSession`/`verifySession`, `@voltro/i18n`, `@effect/workflow`.
698
698
  - **Don't add `bullmq`/`temporal`/`react-query`/SWR** — see Mental model.
699
+ - **Don't build a GraphQL layer over the stores.** It would bypass the
700
+ reactivity path (source-based invalidation, per-delivery guards) — a second,
701
+ dead read path. External consumers → REST + OpenAPI (`defineRestRoute` +
702
+ `@voltro/plugin-openapi`); internal clients → RPC + live subscriptions.
703
+ - **Don't write `'use server'` / `'use client'` — there is no RSC.** Islands +
704
+ loaders + streaming SSR are the model; those directives mark a boundary this
705
+ framework does not have.
706
+ - **Don't split the app into microservices with service-to-service RPC.** One
707
+ monolith process, scaled by running more replicas (`@effect/cluster` shards
708
+ durable workflows across instances), is the architecture. An external system
709
+ boundary is REST + OpenAPI; a reliable outbound effect is `ctx.outbox`.
699
710
 
700
711
  ## Plugins
701
712
 
@@ -717,7 +728,7 @@ each plugin's own README.
717
728
 
718
729
  | Topic | Open | Summary |
719
730
  |---|---|---|
720
- | **What's new in 0.51.0** | `node_modules/@voltro/cli/templates/agent-docs/whats-new.md` | Everything that changed in this version. Read it before hand-rolling something the framework may now ship. |
731
+ | **What's new in 0.52.0** | `node_modules/@voltro/cli/templates/agent-docs/whats-new.md` | Everything that changed in this version. Read it before hand-rolling something the framework may now ship. |
721
732
  | AI | `node_modules/@voltro/cli/templates/agent-docs/ai.md` | How Voltro treats AI — agents, tools, streaming, RAG — all primitives over the same WebSocket as the rest of the framework. |
722
733
  | Authentication | `node_modules/@voltro/cli/templates/agent-docs/authentication.md` | How @voltro/plugin-auth wires password + session-cookie auth across api + web, plus the pluggable identity-strategy protocol. |
723
734
  | Caching | `node_modules/@voltro/cli/templates/agent-docs/caching.md` | Voltro's caching layer (@voltro/cache) — an always-on memory default, swappable Redis-compatible backends, a low-level wrap primitive, and automatic query-result invalidation. |
@@ -775,7 +786,7 @@ each plugin's own README.
775
786
  | auth-workos | `node_modules/@voltro/cli/templates/agent-docs/plugins/auth-workos.md` (or `node_modules/@voltro/plugin-auth-workos/README.md`) | WorkOS AuthStrategy — verifies WorkOS AuthKit / SSO JWTs via JWKS (no API key) and maps org_id → tenantId. |
776
787
  | billing | `node_modules/@voltro/cli/templates/agent-docs/plugins/billing.md` (or `node_modules/@voltro/plugin-billing/README.md`) | Subscriptions, plans, entitlements, and usage metering over a pluggable provider (Stripe + mock). Money is integer minor units. |
777
788
  | broadcast | `node_modules/@voltro/cli/templates/agent-docs/plugins/broadcast.md` (or `node_modules/@voltro/plugin-broadcast/README.md`) | Cross-replica reactivity over a pub/sub bus (Redis / NATS) for non-postgres dialects — closes the single-instance gap so a write on one pod surfaces on another. |
778
- | cdc-out | `node_modules/@voltro/cli/templates/agent-docs/plugins/cdc-out.md` (or `node_modules/@voltro/plugin-cdc-out/README.md`) | Declaratively mirror table changes outward to external sinks (webhook / Kafka / Snowflake / BigQuery) through a durable outbox — ordered per pipe, at-least-once from enqueue, retried with backoff, dead-lettered. |
789
+ | cdc-out | `node_modules/@voltro/cli/templates/agent-docs/plugins/cdc-out.md` (or `node_modules/@voltro/plugin-cdc-out/README.md`) | Declaratively mirror table changes outward to external sinks (webhook, plus a CdcSink interface for custom sinks) through a durable outbox — ordered per pipe, at-least-once from enqueue, retried with backoff, dead-lettered. |
779
790
  | clickhouse | `node_modules/@voltro/cli/templates/agent-docs/plugins/clickhouse.md` (or `node_modules/@voltro/plugin-clickhouse/README.md`) | Production-grade OLAP AnalyticsSink over ClickHouse — self-hosted or ClickHouse Cloud — for billions of events with millisecond aggregates. |
780
791
  | datadog | `node_modules/@voltro/cli/templates/agent-docs/plugins/datadog.md` (or `node_modules/@voltro/plugin-datadog/README.md`) | Agentless Datadog metrics exporter — pushes the unified Metrics-API to Datadog's /api/v2/series HTTP intake. |
781
792
  | deactivation | `node_modules/@voltro/cli/templates/agent-docs/plugins/deactivation.md` (or `node_modules/@voltro/plugin-deactivation/README.md`) | A schema mixin that marks a subject as deactivated (can't log in) while keeping its data fully visible — the deliberate opposite of soft-delete. |
@@ -795,14 +806,14 @@ each plugin's own README.
795
806
  | prometheus | `node_modules/@voltro/cli/templates/agent-docs/plugins/prometheus.md` (or `node_modules/@voltro/plugin-prometheus/README.md`) | Prometheus exporter — scrapes the unified Metrics-API at GET /metrics in text exposition format. |
796
807
  | ratelimit | `node_modules/@voltro/cli/templates/agent-docs/plugins/ratelimit.md` (or `node_modules/@voltro/plugin-ratelimit/README.md`) | Per-endpoint, per-subject and per-tenant request limits via the rpc interceptors. Sliding-window / fixed-window / token-bucket, memory / postgres / redis stores. |
797
808
  | rbac | `node_modules/@voltro/cli/templates/agent-docs/plugins/rbac.md` (or `node_modules/@voltro/plugin-rbac/README.md`) | Roles + permissions + the permission() handler guard. Roles compile to scopes. |
809
+ | row-history | `node_modules/@voltro/cli/templates/agent-docs/plugins/row-history.md` (or `node_modules/@voltro/plugin-row-history/README.md`) | Full row history + time-travel. audit() records who/when; row-history records what-changed-to-what — a value snapshot of every row on every write, with as-of queries. |
798
810
  | scim | `node_modules/@voltro/cli/templates/agent-docs/plugins/scim.md` (or `node_modules/@voltro/plugin-scim/README.md`) | SCIM 2.0 provisioning — Users + Groups REST endpoints so an enterprise IdP (Okta, Entra, OneLogin) can create / update / deactivate users in your app. |
799
811
  | search | `node_modules/@voltro/cli/templates/agent-docs/plugins/search.md` (or `node_modules/@voltro/plugin-search/README.md`) | Keep an external search index (Typesense / Meilisearch / Algolia) in sync with your tables via the ChangeEvent tap, query it tenant-scoped through a typed action + hook. |
800
812
  | sentry | `node_modules/@voltro/cli/templates/agent-docs/plugins/sentry.md` (or `node_modules/@voltro/plugin-sentry/README.md`) | Deep Sentry integration — errors correlated to the distributed trace, breadcrumbs from the log sink, and opt-in performance traces. |
801
813
  | soft-delete | `node_modules/@voltro/cli/templates/agent-docs/plugins/soft-delete.md` (or `node_modules/@voltro/plugin-soft-delete/README.md`) | The softDelete() schema mixin — deletedAt / deletedBy columns, delete() redirected to an UPDATE, default reads filtered, hardDelete() bypass. |
802
814
  | sso-saml | `node_modules/@voltro/cli/templates/agent-docs/plugins/sso-saml.md` (or `node_modules/@voltro/plugin-sso-saml/README.md`) | Enterprise SAML 2.0 SSO — SP-initiated login, ACS assertion consumer, SP metadata. Signature verification via @node-saml/node-saml; framework session minting built in. |
803
- | storage | `node_modules/@voltro/cli/templates/agent-docs/plugins/storage.md` (or `node_modules/@voltro/plugin-storage/README.md`) | File storage behind one StorageService — public objects served direct from the bucket/CDN, private objects gated by an access policy + per-object grants. S3 / R2 / GCS / MinIO / filesystem / memory providers, presigned URLs, a dashboard browser. |
815
+ | storage | `node_modules/@voltro/cli/templates/agent-docs/plugins/storage.md` (or `node_modules/@voltro/plugin-storage/README.md`) | File storage behind one StorageService — public objects served direct from the bucket/CDN, private objects gated by an access policy + per-object grants. S3 / MinIO (R2 and GCS via their S3 interop) / Azure / database / filesystem / memory providers, presigned URLs, a dashboard browser. |
804
816
  | tinybird | `node_modules/@voltro/cli/templates/agent-docs/plugins/tinybird.md` (or `node_modules/@voltro/plugin-tinybird/README.md`) | Hosted-ClickHouse AnalyticsSink over Tinybird's Events API + Pipes — pay-as-you-go OLAP without operating a cluster. |
805
- | versioning | `node_modules/@voltro/cli/templates/agent-docs/plugins/versioning.md` (or `node_modules/@voltro/plugin-versioning/README.md`) | Full row history + time-travel. audit() records who/when; versioning records what-changed-to-what — a value snapshot of every row on every write, with as-of queries. |
806
817
  | webhooks | `node_modules/@voltro/cli/templates/agent-docs/plugins/webhooks.md` (or `node_modules/@voltro/plugin-webhooks/README.md`) | First-class outgoing + incoming webhooks — declared events with a webhook: block, defineIncomingWebhook in *.webhook.tsx files, runtime subscriptions, durable delivery via @effect/workflow, HMAC signing, provider presets, and idempotency. |
807
818
 
808
819
 
@@ -9,7 +9,7 @@ each plugin's own README.
9
9
 
10
10
  | Topic | Open | Summary |
11
11
  |---|---|---|
12
- | **What's new in 0.51.0** | `node_modules/@voltro/cli/templates/agent-docs/whats-new.md` | Everything that changed in this version. Read it before hand-rolling something the framework may now ship. |
12
+ | **What's new in 0.52.0** | `node_modules/@voltro/cli/templates/agent-docs/whats-new.md` | Everything that changed in this version. Read it before hand-rolling something the framework may now ship. |
13
13
  | AI | `node_modules/@voltro/cli/templates/agent-docs/ai.md` | How Voltro treats AI — agents, tools, streaming, RAG — all primitives over the same WebSocket as the rest of the framework. |
14
14
  | Authentication | `node_modules/@voltro/cli/templates/agent-docs/authentication.md` | How @voltro/plugin-auth wires password + session-cookie auth across api + web, plus the pluggable identity-strategy protocol. |
15
15
  | Caching | `node_modules/@voltro/cli/templates/agent-docs/caching.md` | Voltro's caching layer (@voltro/cache) — an always-on memory default, swappable Redis-compatible backends, a low-level wrap primitive, and automatic query-result invalidation. |
@@ -67,7 +67,7 @@ each plugin's own README.
67
67
  | auth-workos | `node_modules/@voltro/cli/templates/agent-docs/plugins/auth-workos.md` (or `node_modules/@voltro/plugin-auth-workos/README.md`) | WorkOS AuthStrategy — verifies WorkOS AuthKit / SSO JWTs via JWKS (no API key) and maps org_id → tenantId. |
68
68
  | billing | `node_modules/@voltro/cli/templates/agent-docs/plugins/billing.md` (or `node_modules/@voltro/plugin-billing/README.md`) | Subscriptions, plans, entitlements, and usage metering over a pluggable provider (Stripe + mock). Money is integer minor units. |
69
69
  | broadcast | `node_modules/@voltro/cli/templates/agent-docs/plugins/broadcast.md` (or `node_modules/@voltro/plugin-broadcast/README.md`) | Cross-replica reactivity over a pub/sub bus (Redis / NATS) for non-postgres dialects — closes the single-instance gap so a write on one pod surfaces on another. |
70
- | cdc-out | `node_modules/@voltro/cli/templates/agent-docs/plugins/cdc-out.md` (or `node_modules/@voltro/plugin-cdc-out/README.md`) | Declaratively mirror table changes outward to external sinks (webhook / Kafka / Snowflake / BigQuery) through a durable outbox — ordered per pipe, at-least-once from enqueue, retried with backoff, dead-lettered. |
70
+ | cdc-out | `node_modules/@voltro/cli/templates/agent-docs/plugins/cdc-out.md` (or `node_modules/@voltro/plugin-cdc-out/README.md`) | Declaratively mirror table changes outward to external sinks (webhook, plus a CdcSink interface for custom sinks) through a durable outbox — ordered per pipe, at-least-once from enqueue, retried with backoff, dead-lettered. |
71
71
  | clickhouse | `node_modules/@voltro/cli/templates/agent-docs/plugins/clickhouse.md` (or `node_modules/@voltro/plugin-clickhouse/README.md`) | Production-grade OLAP AnalyticsSink over ClickHouse — self-hosted or ClickHouse Cloud — for billions of events with millisecond aggregates. |
72
72
  | datadog | `node_modules/@voltro/cli/templates/agent-docs/plugins/datadog.md` (or `node_modules/@voltro/plugin-datadog/README.md`) | Agentless Datadog metrics exporter — pushes the unified Metrics-API to Datadog's /api/v2/series HTTP intake. |
73
73
  | deactivation | `node_modules/@voltro/cli/templates/agent-docs/plugins/deactivation.md` (or `node_modules/@voltro/plugin-deactivation/README.md`) | A schema mixin that marks a subject as deactivated (can't log in) while keeping its data fully visible — the deliberate opposite of soft-delete. |
@@ -87,12 +87,12 @@ each plugin's own README.
87
87
  | prometheus | `node_modules/@voltro/cli/templates/agent-docs/plugins/prometheus.md` (or `node_modules/@voltro/plugin-prometheus/README.md`) | Prometheus exporter — scrapes the unified Metrics-API at GET /metrics in text exposition format. |
88
88
  | ratelimit | `node_modules/@voltro/cli/templates/agent-docs/plugins/ratelimit.md` (or `node_modules/@voltro/plugin-ratelimit/README.md`) | Per-endpoint, per-subject and per-tenant request limits via the rpc interceptors. Sliding-window / fixed-window / token-bucket, memory / postgres / redis stores. |
89
89
  | rbac | `node_modules/@voltro/cli/templates/agent-docs/plugins/rbac.md` (or `node_modules/@voltro/plugin-rbac/README.md`) | Roles + permissions + the permission() handler guard. Roles compile to scopes. |
90
+ | row-history | `node_modules/@voltro/cli/templates/agent-docs/plugins/row-history.md` (or `node_modules/@voltro/plugin-row-history/README.md`) | Full row history + time-travel. audit() records who/when; row-history records what-changed-to-what — a value snapshot of every row on every write, with as-of queries. |
90
91
  | scim | `node_modules/@voltro/cli/templates/agent-docs/plugins/scim.md` (or `node_modules/@voltro/plugin-scim/README.md`) | SCIM 2.0 provisioning — Users + Groups REST endpoints so an enterprise IdP (Okta, Entra, OneLogin) can create / update / deactivate users in your app. |
91
92
  | search | `node_modules/@voltro/cli/templates/agent-docs/plugins/search.md` (or `node_modules/@voltro/plugin-search/README.md`) | Keep an external search index (Typesense / Meilisearch / Algolia) in sync with your tables via the ChangeEvent tap, query it tenant-scoped through a typed action + hook. |
92
93
  | sentry | `node_modules/@voltro/cli/templates/agent-docs/plugins/sentry.md` (or `node_modules/@voltro/plugin-sentry/README.md`) | Deep Sentry integration — errors correlated to the distributed trace, breadcrumbs from the log sink, and opt-in performance traces. |
93
94
  | soft-delete | `node_modules/@voltro/cli/templates/agent-docs/plugins/soft-delete.md` (or `node_modules/@voltro/plugin-soft-delete/README.md`) | The softDelete() schema mixin — deletedAt / deletedBy columns, delete() redirected to an UPDATE, default reads filtered, hardDelete() bypass. |
94
95
  | sso-saml | `node_modules/@voltro/cli/templates/agent-docs/plugins/sso-saml.md` (or `node_modules/@voltro/plugin-sso-saml/README.md`) | Enterprise SAML 2.0 SSO — SP-initiated login, ACS assertion consumer, SP metadata. Signature verification via @node-saml/node-saml; framework session minting built in. |
95
- | storage | `node_modules/@voltro/cli/templates/agent-docs/plugins/storage.md` (or `node_modules/@voltro/plugin-storage/README.md`) | File storage behind one StorageService — public objects served direct from the bucket/CDN, private objects gated by an access policy + per-object grants. S3 / R2 / GCS / MinIO / filesystem / memory providers, presigned URLs, a dashboard browser. |
96
+ | storage | `node_modules/@voltro/cli/templates/agent-docs/plugins/storage.md` (or `node_modules/@voltro/plugin-storage/README.md`) | File storage behind one StorageService — public objects served direct from the bucket/CDN, private objects gated by an access policy + per-object grants. S3 / MinIO (R2 and GCS via their S3 interop) / Azure / database / filesystem / memory providers, presigned URLs, a dashboard browser. |
96
97
  | tinybird | `node_modules/@voltro/cli/templates/agent-docs/plugins/tinybird.md` (or `node_modules/@voltro/plugin-tinybird/README.md`) | Hosted-ClickHouse AnalyticsSink over Tinybird's Events API + Pipes — pay-as-you-go OLAP without operating a cluster. |
97
- | versioning | `node_modules/@voltro/cli/templates/agent-docs/plugins/versioning.md` (or `node_modules/@voltro/plugin-versioning/README.md`) | Full row history + time-travel. audit() records who/when; versioning records what-changed-to-what — a value snapshot of every row on every write, with as-of queries. |
98
98
  | webhooks | `node_modules/@voltro/cli/templates/agent-docs/plugins/webhooks.md` (or `node_modules/@voltro/plugin-webhooks/README.md`) | First-class outgoing + incoming webhooks — declared events with a webhook: block, defineIncomingWebhook in *.webhook.tsx files, runtime subscriptions, durable delivery via @effect/workflow, HMAC signing, provider presets, and idempotency. |
@@ -460,7 +460,7 @@
460
460
  {
461
461
  "slug": "cdc-out",
462
462
  "title": "CDC-out (reverse-ETL)",
463
- "description": "Declaratively mirror table changes outward to external sinks (webhook / Kafka / Snowflake / BigQuery) through a durable outbox — ordered per pipe, at-least-once from enqueue, retried with backoff, dead-lettered.",
463
+ "description": "Declaratively mirror table changes outward to external sinks (webhook, plus a CdcSink interface for custom sinks) through a durable outbox — ordered per pipe, at-least-once from enqueue, retried with backoff, dead-lettered.",
464
464
  "pkg": "@voltro/plugin-cdc-out",
465
465
  "doc": "plugins/cdc-out.md",
466
466
  "module": "agent-docs/plugins/cdc-out.md"
@@ -617,6 +617,14 @@
617
617
  "doc": "plugins/rbac.md",
618
618
  "module": "agent-docs/plugins/rbac.md"
619
619
  },
620
+ {
621
+ "slug": "row-history",
622
+ "title": "Row history",
623
+ "description": "Full row history + time-travel. audit() records who/when; row-history records what-changed-to-what — a value snapshot of every row on every write, with as-of queries.",
624
+ "pkg": "@voltro/plugin-row-history",
625
+ "doc": "plugins/row-history.md",
626
+ "module": "agent-docs/plugins/row-history.md"
627
+ },
620
628
  {
621
629
  "slug": "scim",
622
630
  "title": "SCIM",
@@ -660,7 +668,7 @@
660
668
  {
661
669
  "slug": "storage",
662
670
  "title": "Storage",
663
- "description": "File storage behind one StorageService — public objects served direct from the bucket/CDN, private objects gated by an access policy + per-object grants. S3 / R2 / GCS / MinIO / filesystem / memory providers, presigned URLs, a dashboard browser.",
671
+ "description": "File storage behind one StorageService — public objects served direct from the bucket/CDN, private objects gated by an access policy + per-object grants. S3 / MinIO (R2 and GCS via their S3 interop) / Azure / database / filesystem / memory providers, presigned URLs, a dashboard browser.",
664
672
  "pkg": "@voltro/plugin-storage",
665
673
  "doc": "plugins/storage.md",
666
674
  "module": "agent-docs/plugins/storage.md"
@@ -673,14 +681,6 @@
673
681
  "doc": "plugins/tinybird.md",
674
682
  "module": "agent-docs/plugins/tinybird.md"
675
683
  },
676
- {
677
- "slug": "versioning",
678
- "title": "Row versioning",
679
- "description": "Full row history + time-travel. audit() records who/when; versioning records what-changed-to-what — a value snapshot of every row on every write, with as-of queries.",
680
- "pkg": "@voltro/plugin-versioning",
681
- "doc": "plugins/versioning.md",
682
- "module": "agent-docs/plugins/versioning.md"
683
- },
684
684
  {
685
685
  "slug": "webhooks",
686
686
  "title": "Webhooks",
@@ -710,9 +710,9 @@
710
710
  "api-ratelimit": "agent-docs/templates/apibackends.md",
711
711
  "api-rbac": "agent-docs/templates/apibackends.md",
712
712
  "api-rest": "agent-docs/templates/apibackends.md",
713
+ "api-row-history": "agent-docs/templates/apibackends.md",
713
714
  "api-saas": "agent-docs/templates/apibackends.md",
714
715
  "api-search": "agent-docs/templates/apibackends.md",
715
- "api-versioning": "agent-docs/templates/apibackends.md",
716
716
  "api-webhooks": "agent-docs/templates/apibackends.md",
717
717
  "app": "agent-docs/templates/appshells.md",
718
718
  "blank": "agent-docs/templates/appshells.md",
@@ -142,6 +142,12 @@ config value always winning:
142
142
  | `VOLTRO_CSP_HTML` | CSP for HTML responses (under `strict` it defaults to the same policy as `VOLTRO_CSP`). `off` drops just this one. |
143
143
  | `VOLTRO_HSTS` | `Strict-Transport-Security` value. `off` drops just this one. |
144
144
  | `VOLTRO_MAX_RPC_BODY_BYTES` | Cap on the buffered `POST /rpc` JSON body (default 8 MiB) — an oversized body is refused `413` and never buffered past the cap. File uploads ride plugin routes with their own limits. |
145
+ | `VOLTRO_MAX_BODY_BYTES` | Cap on every OTHER body read — plugin HTTP routes, REST routes, incoming webhooks (default 8 MiB, matching the rpc cap). The config-file spelling is `http.maxBodyBytes` in `app.config.ts`; per-route overrides (`defineRestRoute({ maxBodyBytes })`, a webhook handler's `maxBodyBytes`) win over both. Oversize is `413` for `Content-Length` and chunked alike. |
146
+
147
+ Response compression for the buffered non-rpc surfaces (and `voltro start`'s
148
+ HTML) is configured in the same `http:` block — `http.compression.{enabled,minBytes}`
149
+ (default on, 1 KiB threshold; `POST /rpc` is never compressed). Details + the
150
+ BREACH reasoning: [Security → compression](/docs/security/overview#response-compression--and-where-breach-sits).
145
151
 
146
152
  Generate any of the secret vars above with `voltro secret generate <purpose>` (see [`secret`](#command-quick-reference)) — it picks the right length and format. A lower environment's secrets must always differ from production's.
147
153
 
@@ -317,36 +323,48 @@ fails to update.
317
323
 
318
324
  ```
319
325
  observed: 12/34 procedures exercised (35%)
326
+ 1 declared/observed mismatch among the 12 that ran
320
327
  mutation(orders.place) (api/orders/place.mutation.ts)
321
328
  writes 'inventory' (update) but declares no target for it
322
329
  subscriptions on that table are not invalidated by this mutation
323
330
  fix: add { table: 'inventory', op: 'update' } to this procedure's targets
324
- 22 unexercised — no recording, so nothing is claimed about them
331
+ 20 never ran — no observation exists, so nothing is claimed about them
332
+ 2 ran with no table access recorded — indistinguishable from touching nothing, so nothing is claimed about them either
325
333
  ```
326
334
 
327
- Three things about that output are deliberate:
335
+ Four things about that output are deliberate:
328
336
 
329
337
  - **Coverage comes first.** Three findings at 8% coverage and three at 95% are
330
338
  different claims. Hiding the denominator is how a check starts overstating
331
339
  what it knows.
332
- - **`unexercised` is a third state, not a finding.** A procedure no test and no
333
- dev session ever ran has *no observation* which is not the same as "touches
334
- nothing". It is counted and never reported as a problem.
340
+ - **Every result line carries the count it is a result about.** `1 mismatch
341
+ among the 12 that ran` never a bare verdict. A sentence that still reads as
342
+ a conclusion once it is cut out of this block will eventually be cut out of
343
+ it, and quoted as a clean bill of health for a surface nobody measured.
344
+ - **The counts partition the declared set — they add up to the total, always.**
345
+ There are two ways to say nothing about a procedure, and both get a line:
346
+ it never ran, or it ran and no table access was recorded for it. A procedure
347
+ that appeared in no line at all would be indistinguishable from a defect in
348
+ `check` itself, so the two kinds of blindness are named separately and never
349
+ folded into the findings.
335
350
  - **Observed diagnostics never fail the build.** An observation is evidence
336
351
  about the runs that happened, not a proof about the ones that didn't, and
337
352
  `check`'s exit code gates CI. They are always warnings.
338
353
 
339
- A fourth thing is not visible in that output and matters more than any of the
340
- three: **the recorder only knows what ran.** A boot is not a run. An idle dev
354
+ A fifth thing is not visible in that output and matters more than any of the
355
+ four: **the recorder only knows what ran.** A boot is not a run. An idle dev
341
356
  instance that started, served nothing and stopped produces
342
357
 
343
358
  ```
344
- observed: 0/2755 procedures exercised (0%)
345
- 2753 unexercisedno recording, so nothing is claimed about them
359
+ observed: 0/34 procedures exercised (0%)
360
+ nothing was compared a declaration is only checked against a procedure that RAN
361
+ 34 never ran — no observation exists, so nothing is claimed about them
346
362
  ```
347
363
 
348
- which is the honest answer and also a useless one the section says nothing
349
- about 99.9% of the surface. If you want this as a CI gate, the recording pass has
364
+ Note what that is NOT: it is not "no mismatches found". At zero coverage there
365
+ is no result to report, so the section reports the absence of the comparison
366
+ instead. The honest answer is also a useless one — it says nothing about any of
367
+ the surface. If you want this as a CI gate, the recording pass has
350
368
  to be a run that actually *calls* the procedures. `voltro e2e` is one: it spawns
351
369
  `voltro dev` for the api, which turns recording on, and then drives the specs. A
352
370
  harness of your own that boots the app in its own process needs
@@ -365,6 +383,29 @@ handlers: a static pass over code that reaches the store through shared helpers,
365
383
  behind conditionals, has a long tail of both false positives and false negatives
366
384
  — and a check that is *sometimes* wrong is one people stop reading.
367
385
 
386
+ #### Declared vs LIVE — against a running server
387
+
388
+ When `check` runs against a live api (a local `voltro dev`, or a deployed one
389
+ via `--url`), it also diffs the tags your source declares — plugin routes
390
+ included — against the server's actual rpc registry:
391
+
392
+ ```
393
+ declared vs live: 2 of 214 source-declared tags are NOT registered on the server
394
+ ⚠ presence.heartbeat — a generated client calls this and gets "Unknown request tag"
395
+ ⚠ presence.list — a generated client calls this and gets "Unknown request tag"
396
+ fix: if the server runs older code, redeploy; if it is current, plugin route registration was dropped — check the boot line "plugin routes registered"
397
+ ```
398
+
399
+ Only the source→live direction is a finding — a tag the server carries that your
400
+ source does not declare is normal runtime synthesis (agents, undo, approvals).
401
+ This exists because exactly that gap has shipped once: every
402
+ plugin-contributed procedure dead under `voltro serve`, with nothing anywhere
403
+ saying so — the only evidence was a `Defect` frame in the browser console of
404
+ whoever happened to look. (That registration defect is fixed; the diff is the
405
+ runtime backstop for the next one, e.g. a stale deploy.) The server now also
406
+ logs every `Defect` frame it sends (`rpc defect sent to client`), so an unknown
407
+ tag is an operator-visible event rather than a client-only one.
408
+
368
409
  The HTTP surface is reachable directly too — e.g. `curl -s localhost:4000/_voltro/inspect/rpc | jq` (there is no `/_voltro/inspect/queries` endpoint; it's `rpc` for procedures, `routes` for the web page tree, `subscriptions` for active subscribers).
369
410
 
370
411
  ## Where to read next
@@ -1364,7 +1405,7 @@ Point the Kubernetes liveness probe at `/internal/liveness` and the readiness pr
1364
1405
  For WebSocket connections to land on the same backend (required for in-process subscription state):
1365
1406
 
1366
1407
  - Reverse proxy: `lb_policy ip_hash` (Caddy) / `ip_hash` (nginx).
1367
- - Or use `@voltro/plugin-cluster` to share subscription state across instances any-load-balancer-works.
1408
+ - Cross-instance subscription invalidation is built in on Postgres (LISTEN/NOTIFY) and MySQL/MariaDB (binlog CDC); on any other dialect add [`@voltro/plugin-broadcast`](/docs/plugins/broadcast) (Redis/NATS). With that in place a reconnect may land on any replica and still sees every change — sticky sessions then only keep one live connection pinned, they are not a correctness requirement.
1368
1409
 
1369
1410
  ## `voltro build api --target <swift|kotlin>` — native SDK generation
1370
1411
 
@@ -1796,6 +1837,47 @@ matching rule lives inside the CLI, so you cannot re-derive the list with your
1796
1837
  own grep. `--json` prints the complete scan, nothing elided, with no preflight
1797
1838
  output mixed in:
1798
1839
 
1840
+ ### Unimported `@voltro/*` dependencies
1841
+
1842
+ A declared framework dependency nobody imports still gets installed, walked on
1843
+ every `voltro update`, and read as evidence the package is in use — its
1844
+ breaking-change notes included. The usual origin is a migration: the app moves
1845
+ off a framework package to a third-party one, and the `package.json` entry
1846
+ stays. `voltro doctor` checks every `@voltro/*` in `dependencies` and
1847
+ `devDependencies` for an import site:
1848
+
1849
+ ```
1850
+ unimported deps · 8 @voltro/* package(s) declared, 214 file(s) scanned
1851
+ ⚠ @voltro/i18n — declared in dependencies, imported nowhere
1852
+ a dependency nobody imports still gets installed, updated, and read as
1853
+ evidence the package is in use — its breaking-change notes included.
1854
+ Remove it, or if it IS imported through an assembled specifier the scan
1855
+ cannot see, keep it and ignore this line — the rule is advisory.
1856
+ · (2 loaded by the framework itself: @voltro/cli, @voltro/sql-postgres)
1857
+ ```
1858
+
1859
+ Scoped to `@voltro/*` deliberately: for third-party packages the same question
1860
+ has a long tail of legitimate no-import shapes, and a rule that is sometimes
1861
+ wrong is one people stop reading. Three states are distinguished, and each is
1862
+ printed:
1863
+
1864
+ - **Exempt, by name** — packages the framework loads on your declaration
1865
+ (`@voltro/cli` is the binary; `@voltro/devtools` is mounted by `voltro dev`;
1866
+ the `@voltro/sql-*` dialect drivers are loaded from your config). An
1867
+ exemption you cannot see is a finding you cannot question.
1868
+ - **Not measurable yet** — `@voltro/client` / `@voltro/web` are normally
1869
+ imported by *generated* code. On a tree where codegen has never run, their
1870
+ absence is a missing measurement, not a dead dependency; the section says so
1871
+ and tells you to run `voltro dev` once.
1872
+ - **Unimported** — advisory, never fatal. A mention in a comment or an error
1873
+ string does not count as an import (a commented-out import is exactly the
1874
+ residue this looks for), and an import assembled at runtime from string
1875
+ pieces is invisible to the scan — the finding text says both.
1876
+
1877
+ The full report is in `voltro doctor --json` under `unimportedDeps`
1878
+ (`null` when there is no `package.json` to read — "could not check" and
1879
+ "checked, clean" never print the same).
1880
+
1799
1881
  ### Duplicate package instances
1800
1882
 
1801
1883
  `voltro doctor` also reports any identity-sensitive package resolved at more than
@@ -2850,7 +2932,7 @@ Not every run can take it, and a run that cannot **says why** rather than quietl
2850
2932
  taking the slower path:
2851
2933
 
2852
2934
  - a store the framework cannot send DDL to (the in-memory store).
2853
- - a **write recorder** on any table in the set — `versioningPlugin({ timing:
2935
+ - a **write recorder** on any table in the set — `rowHistoryPlugin({ timing:
2854
2936
  'in-transaction' })` and friends. A recorder is keyed by table name, so a
2855
2937
  staged write would find none and the recorder would silently not run. Its
2856
2938
  promise is "if the change committed, the entry is there", so the run keeps the
@@ -2906,7 +2988,7 @@ ITSELF is not a cycle: one statement carries the whole table.
2906
2988
 
2907
2989
  ### A `replace` does not write per-row history
2908
2990
 
2909
- Write recorders — `versioningPlugin({ timing: 'in-transaction' })` and anything
2991
+ Write recorders — `rowHistoryPlugin({ timing: 'in-transaction' })` and anything
2910
2992
  else registered through the same seam — are **suspended for a `replace`**. A
2911
2993
  replace sets a state; it does not change rows, so a per-row history entry would
2912
2994
  describe something that did not happen. On a large bundle that is not a detail: