@voltro/cli 0.31.0 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +368 -0
  2. package/THIRD-PARTY-NOTICES.md +1 -29
  3. package/dist/apiBuild-C-x9YacA.js +2 -0
  4. package/dist/{apiBuild-CLPt-pX6.js → apiBuild-h9VHtnlw.js} +2 -2
  5. package/dist/bin.js +3 -3
  6. package/dist/checkCommand-DRovTKza.js +2 -0
  7. package/dist/{checkCommand-D7r6_pk7.js → checkCommand-xGhRFFg2.js} +330 -290
  8. package/dist/{commands-CNVVv03h.js → commands-CJfepbm4.js} +139 -13
  9. package/dist/{dbCommand-BH8GAYuf.js → dbCommand-DTLKAfbA.js} +431 -263
  10. package/dist/dbCommand-b1gum4td.js +2 -0
  11. package/dist/{dev-DdQEn2Ia.js → dev-C_P8FLSx.js} +2141 -2081
  12. package/dist/{dev-DOZVMVfi.js → dev-iiMtlkfs.js} +1 -1
  13. package/dist/index.js +1 -1
  14. package/dist/{inspectMetrics-BeEAnjqw.js → inspectMetrics-1xzTKAFx.js} +750 -685
  15. package/dist/{sdkgen-v9WV8zRi.js → sdkgen-C81QIkiL.js} +1 -1
  16. package/dist/serveCommand-DdaM4Hup.js +1608 -0
  17. package/dist/serveEntry.js +2 -2
  18. package/dist/{start-CI2QdKy9.js → start-C0koT0UO.js} +1 -1
  19. package/dist/startEntry.js +2 -2
  20. package/package.json +431 -18
  21. package/templates/AGENTS.md +1 -1
  22. package/templates/agent-docs/_index.md +1 -1
  23. package/templates/agent-docs/database/misc.md +37 -0
  24. package/templates/agent-docs/database/schema.md +4 -2
  25. package/templates/agent-docs/deployment.md +87 -1
  26. package/templates/agent-docs/plugins/audit.md +24 -0
  27. package/templates/agent-docs/plugins.md +50 -0
  28. package/templates/agent-docs/scheduling.md +4 -1
  29. package/templates/agent-docs/security.md +31 -1
  30. package/templates/agent-docs/whats-new.md +149 -59
  31. package/templates/apps/api-ai/package.json +7 -7
  32. package/templates/apps/api-auth/package.json +8 -8
  33. package/templates/apps/api-backend/package.json +7 -7
  34. package/templates/apps/api-backend-deactivation/package.json +7 -7
  35. package/templates/apps/api-backend-mail/package.json +8 -8
  36. package/templates/apps/api-backend-mariadb/package.json +9 -9
  37. package/templates/apps/api-backend-sqlite/package.json +8 -8
  38. package/templates/apps/api-backend-storage/package.json +8 -8
  39. package/templates/apps/api-cms/package.json +10 -10
  40. package/templates/apps/api-collab/package.json +8 -8
  41. package/templates/apps/api-data-advanced/package.json +8 -8
  42. package/templates/apps/api-durable/package.json +8 -8
  43. package/templates/apps/api-feature-flags/package.json +9 -9
  44. package/templates/apps/api-governance/package.json +8 -8
  45. package/templates/apps/api-kv/package.json +8 -8
  46. package/templates/apps/api-moderation/package.json +8 -8
  47. package/templates/apps/api-observability/package.json +8 -8
  48. package/templates/apps/api-ratelimit/package.json +8 -8
  49. package/templates/apps/api-rbac/package.json +8 -8
  50. package/templates/apps/api-rest/package.json +7 -7
  51. package/templates/apps/api-saas/package.json +11 -11
  52. package/templates/apps/api-saas-starter/package.json +10 -10
  53. package/templates/apps/api-search/package.json +8 -8
  54. package/templates/apps/api-status/package.json +8 -8
  55. package/templates/apps/api-versioning/package.json +8 -8
  56. package/templates/apps/api-webhooks/package.json +9 -9
  57. package/templates/apps/changelog/package.json +6 -6
  58. package/templates/apps/edge-functions/package.json +2 -2
  59. package/templates/apps/frontend-admin/package.json +8 -8
  60. package/templates/apps/frontend-app/package.json +8 -8
  61. package/templates/apps/frontend-auth/package.json +8 -8
  62. package/templates/apps/frontend-blank/package.json +7 -7
  63. package/templates/apps/frontend-cms/package.json +9 -9
  64. package/templates/apps/frontend-collab/package.json +9 -9
  65. package/templates/apps/frontend-contact/package.json +7 -7
  66. package/templates/apps/frontend-dashboard/package.json +7 -7
  67. package/templates/apps/frontend-docs/package.json +7 -7
  68. package/templates/apps/frontend-i18n/package.json +6 -6
  69. package/templates/apps/frontend-landing/package.json +7 -7
  70. package/templates/apps/frontend-portal/package.json +8 -8
  71. package/templates/apps/frontend-saas/package.json +8 -8
  72. package/templates/apps/frontend-spa/package.json +7 -7
  73. package/templates/apps/frontend-ssr/package.json +7 -7
  74. package/templates/apps/frontend-ssr-api/package.json +8 -8
  75. package/templates/apps/frontend-static-blog/package.json +6 -6
  76. package/templates/apps/frontend-status/package.json +8 -8
  77. package/templates/apps/mobile-app/package.json +2 -2
  78. package/dist/apiBuild-BOqL1dlg.js +0 -2
  79. package/dist/checkCommand-ClRvH_SN.js +0 -2
  80. package/dist/dbCommand-BwQ_Jl98.js +0 -2
  81. package/dist/serveCommand-KsKXXWn4.js +0 -1578
@@ -1,5 +1,5 @@
1
- import { ct as e } from "./inspectMetrics-BeEAnjqw.js";
1
+ import { ct as e } from "./inspectMetrics-1xzTKAFx.js";
2
2
  import { c as t } from "./seedRunner-Bqxgp7HZ.js";
3
3
  import { r as n } from "./appModuleLoader-C9r9mxZt.js";
4
- import { t as r } from "./serveCommand-KsKXXWn4.js";
4
+ import { t as r } from "./serveCommand-DdaM4Hup.js";
5
5
  export { e as loadDotEnv, n as registerAppModules, t as registerDriver, r as runServe };
@@ -1,4 +1,4 @@
1
- import { $ as e, C as t, Ct as n, D as r, E as i, G as a, J as o, K as s, L as c, P as l, Q as u, S as d, St as ee, Tt as f, V as p, W as m, _ as h, _t as g, a as _, b as v, bt as y, c as b, dt as te, f as x, ft as S, g as C, h as w, i as T, k as E, m as D, mt as O, o as ne, p as re, pt as k, q as ie, r as A, s as j, t as M, ut as N, v as ae, wt as oe, x as P, y as F } from "./inspectMetrics-BeEAnjqw.js";
1
+ import { $ as e, C as t, Ct as n, D as r, E as i, G as a, J as o, K as s, L as c, P as l, Q as u, S as d, St as ee, Tt as f, V as p, W as m, _ as h, _t as g, a as _, b as v, bt as y, c as b, dt as te, f as x, ft as S, g as C, h as w, i as T, k as E, m as D, mt as O, o as ne, p as re, pt as k, q as ie, r as A, s as j, t as M, ut as N, v as ae, wt as oe, x as P, y as F } from "./inspectMetrics-1xzTKAFx.js";
2
2
  import { A as se, E as I, O as ce, a as le, k as L, m as ue } from "./inspect-BUUjt773.js";
3
3
  import { t as de } from "./bootTiming-BdyP9nYw.js";
4
4
  import { dirname as fe, extname as pe, join as R, resolve as z } from "node:path";
@@ -1,3 +1,3 @@
1
- import { ct as e } from "./inspectMetrics-BeEAnjqw.js";
2
- import { t } from "./start-CI2QdKy9.js";
1
+ import { ct as e } from "./inspectMetrics-1xzTKAFx.js";
2
+ import { t } from "./start-C0koT0UO.js";
3
3
  export { e as loadDotEnv, t as runStartCommand };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/cli",
3
- "version": "0.31.0",
3
+ "version": "0.33.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",
@@ -50,11 +50,424 @@
50
50
  "types": "./dist/startEntry.d.ts",
51
51
  "import": "./dist/startEntry.js",
52
52
  "default": "./dist/startEntry.js"
53
- }
53
+ },
54
+ "./package.json": "./package.json"
54
55
  },
55
56
  "main": "./dist/index.js",
56
57
  "module": "./dist/index.js",
57
58
  "types": "./dist/index.d.ts",
59
+ "voltro": {
60
+ "codemods": [
61
+ {
62
+ "version": "0.10.0",
63
+ "id": "0.10.0/01_render-mode-client-to-spa",
64
+ "title": "renderMode is a closed set — `'client'` becomes `'spa'`",
65
+ "kind": "transform"
66
+ },
67
+ {
68
+ "version": "0.10.0",
69
+ "id": "0.10.0/02_router-state-carries-its-path",
70
+ "title": "`renderRouterStateScript` now requires the `path` it rendered",
71
+ "kind": "manual"
72
+ },
73
+ {
74
+ "version": "0.10.0",
75
+ "id": "0.10.0/03_workflow-caller-context-resolved",
76
+ "title": "workflow `buildContext` receives a RESOLVED caller context",
77
+ "kind": "manual"
78
+ },
79
+ {
80
+ "version": "0.10.0",
81
+ "id": "0.10.0/04_seed-run-status-skipped",
82
+ "title": "seed run status gained `skipped`",
83
+ "kind": "manual"
84
+ },
85
+ {
86
+ "version": "0.10.0",
87
+ "id": "0.10.0/05_subscription-idle-state",
88
+ "title": "`useSubscription` gained an idle state for `skip`",
89
+ "kind": "manual"
90
+ },
91
+ {
92
+ "version": "0.11.0",
93
+ "id": "0.11.0/01_step-options-type-params",
94
+ "title": "`StepOptions` takes the context type first",
95
+ "kind": "manual"
96
+ },
97
+ {
98
+ "version": "0.12.0",
99
+ "id": "0.12.0/01_outbound-http-ssrf-guard",
100
+ "title": "Outbound HttpClient blocks internal targets by default (add `http.allowHosts` if you call one)",
101
+ "kind": "manual"
102
+ },
103
+ {
104
+ "version": "0.12.0",
105
+ "id": "0.12.0/02_api-key-revoke-tenant-scope",
106
+ "title": "apiKeyService.revoke/rotate now require the caller's tenantId",
107
+ "kind": "manual"
108
+ },
109
+ {
110
+ "version": "0.12.0",
111
+ "id": "0.12.0/03_api-key-on-behalf-of",
112
+ "title": "API keys: createdBy is provenance, onBehalfOf is ownership",
113
+ "kind": "manual"
114
+ },
115
+ {
116
+ "version": "0.12.0",
117
+ "id": "0.12.0/04_inspect-fail-closed",
118
+ "title": "The inspect surface requires VOLTRO_INSPECT_TOKEN (previously open when unset)",
119
+ "kind": "manual"
120
+ },
121
+ {
122
+ "version": "0.13.0",
123
+ "id": "0.13.0/01_bearer-gates-fail-closed",
124
+ "title": "checkBearer is fail-closed; scimPlugin refuses an empty token",
125
+ "kind": "manual"
126
+ },
127
+ {
128
+ "version": "0.13.0",
129
+ "id": "0.13.0/02_storage-grants-owner-only",
130
+ "title": "storage.share / revoke / listGrants require ownership",
131
+ "kind": "manual"
132
+ },
133
+ {
134
+ "version": "0.13.0",
135
+ "id": "0.13.0/03_apply-plan-convergence-proof",
136
+ "title": "applyPlan requires a `replan` convergence proof",
137
+ "kind": "manual"
138
+ },
139
+ {
140
+ "version": "0.14.0",
141
+ "id": "0.14.0/01_resolve-scopes-store",
142
+ "title": "auth.resolveScopes receives the app DataStore",
143
+ "kind": "manual"
144
+ },
145
+ {
146
+ "version": "0.14.0",
147
+ "id": "0.14.0/02_reactive-by-default",
148
+ "title": "Reactivity is the default; .reactive() is removed",
149
+ "kind": "transform"
150
+ },
151
+ {
152
+ "version": "0.14.0",
153
+ "id": "0.14.0/03_pages-suffix",
154
+ "title": "Pages are declared with a .page.tsx suffix",
155
+ "kind": "transform"
156
+ },
157
+ {
158
+ "version": "0.14.0",
159
+ "id": "0.14.0/04_file-taxonomy",
160
+ "title": "Web files declare their contract (*.component.tsx / *.hook.ts / *.types.ts)",
161
+ "kind": "transform"
162
+ },
163
+ {
164
+ "version": "0.14.0",
165
+ "id": "0.14.0/05_typed-tracking",
166
+ "title": "Tracking catalogues are typed against the component props",
167
+ "kind": "manual"
168
+ },
169
+ {
170
+ "version": "0.14.0",
171
+ "id": "0.14.0/06_voltro-test-skips-e2e",
172
+ "title": "`voltro test` leaves `e2e/` to `voltro e2e`",
173
+ "kind": "manual"
174
+ },
175
+ {
176
+ "version": "0.14.0",
177
+ "id": "0.14.0/07_dev-remote-file-migrations",
178
+ "title": "voltro dev refuses unattended file migrations against a remote database",
179
+ "kind": "manual"
180
+ },
181
+ {
182
+ "version": "0.15.0",
183
+ "id": "0.15.0/01_undo-mistaken-taxonomy-renames",
184
+ "title": "Undo the two file renames 0.14.0 got wrong (framework primitives, side-effect modules)",
185
+ "kind": "transform"
186
+ },
187
+ {
188
+ "version": "0.15.0",
189
+ "id": "0.15.0/02_error-tag-in-protocol",
190
+ "title": "`errorTag` is imported from @voltro/protocol",
191
+ "kind": "transform"
192
+ },
193
+ {
194
+ "version": "0.17.0",
195
+ "id": "0.17.0/01_pages-are-directories",
196
+ "title": "A directory is a route segment; its route is page.tsx",
197
+ "kind": "transform"
198
+ },
199
+ {
200
+ "version": "0.18.0",
201
+ "id": "0.18.0/01_where-like-removed",
202
+ "title": "the `'like'` where-operator is removed — pick `contains` or `startsWith`",
203
+ "kind": "manual"
204
+ },
205
+ {
206
+ "version": "0.19.0",
207
+ "id": "0.19.0/01_server-only-gates-the-boot",
208
+ "title": "`.serverOnly()` now FAILS the boot under `voltro serve` — it used to only warn",
209
+ "kind": "manual"
210
+ },
211
+ {
212
+ "version": "0.19.0",
213
+ "id": "0.19.0/02_audit-redact-input-default",
214
+ "title": "`auditPlugin` now redacts mutation input by default (`redactInput: 'all'`)",
215
+ "kind": "manual"
216
+ },
217
+ {
218
+ "version": "0.20.0",
219
+ "id": "0.20.0/01_write-recorder-port",
220
+ "title": "`WriteRecorder` takes a port (`{ append, maxOf }`) instead of a bare `append`",
221
+ "kind": "manual"
222
+ },
223
+ {
224
+ "version": "0.21.0",
225
+ "id": "0.21.0/01_maxlength-now-migrates",
226
+ "title": "`text().maxLength(n)` now migrates EXISTING columns — plan before you apply",
227
+ "kind": "manual"
228
+ },
229
+ {
230
+ "version": "0.22.0",
231
+ "id": "0.22.0/01_rename-index-op",
232
+ "title": "`MigrationOperation` gained a `rename-index` kind",
233
+ "kind": "manual"
234
+ },
235
+ {
236
+ "version": "0.22.0",
237
+ "id": "0.22.0/02_plugin-tables-voltro-prefixed",
238
+ "title": "plugin-owned tables are `_voltro_`-prefixed (the rows move themselves)",
239
+ "kind": "manual"
240
+ },
241
+ {
242
+ "version": "0.22.0",
243
+ "id": "0.22.0/03_cache-scope-gained-tenant",
244
+ "title": "`cache.scope` gained 'tenant' — an exhaustive switch over it needs a branch",
245
+ "kind": "manual"
246
+ },
247
+ {
248
+ "version": "0.22.0",
249
+ "id": "0.22.0/04_inspect-write-credential",
250
+ "title": "Mutating `/_voltro/inspect/*` endpoints need VOLTRO_INSPECT_WRITE_TOKEN",
251
+ "kind": "manual"
252
+ },
253
+ {
254
+ "version": "0.23.0",
255
+ "id": "0.23.0/01_versioning-is-opt-out",
256
+ "title": "versioningPlugin: `tables: string[]` → opt-out by default, `include` / `exclude` by value",
257
+ "kind": "manual"
258
+ },
259
+ {
260
+ "version": "0.24.0",
261
+ "id": "0.24.0/01_agent-tables-voltro-prefixed",
262
+ "title": "the two agent tables are `_voltro_`-prefixed (the rows move themselves)",
263
+ "kind": "manual"
264
+ },
265
+ {
266
+ "version": "0.25.0",
267
+ "id": "0.25.0/01_events-emit-to-publish",
268
+ "title": "`ctx.events.emit(name, data)` → `ctx.events.publish(descriptor, key, payload)`",
269
+ "kind": "manual"
270
+ },
271
+ {
272
+ "version": "0.25.0",
273
+ "id": "0.25.0/02_outgoing-event-to-define-event",
274
+ "title": "`defineOutgoingEvent` → `defineEvent({ …, webhook: { … } })`",
275
+ "kind": "transform"
276
+ },
277
+ {
278
+ "version": "0.25.0",
279
+ "id": "0.25.0/03_broadcast-channel-to-namespace",
280
+ "title": "`broadcast({ channel })` → `broadcast({ namespace })`",
281
+ "kind": "transform"
282
+ },
283
+ {
284
+ "version": "0.26.0",
285
+ "id": "0.26.0/01_event-webhook-retry-removed",
286
+ "title": "`defineEvent({ webhook: { retry } })` is gone — it never did anything",
287
+ "kind": "manual"
288
+ },
289
+ {
290
+ "version": "0.26.0",
291
+ "id": "0.26.0/02_step-retry-enforced",
292
+ "title": "workflow step `retry:` is now ENFORCED (was metadata) — drop any redundant manual retry",
293
+ "kind": "manual"
294
+ },
295
+ {
296
+ "version": "0.28.0",
297
+ "id": "0.28.0/01_notifications-resolve-subject-id-async",
298
+ "title": "`makeSubjectId` returns a Promise; `resolveSubjectId` may be async",
299
+ "kind": "manual"
300
+ },
301
+ {
302
+ "version": "0.28.0",
303
+ "id": "0.28.0/02_plugin-ref-change-event",
304
+ "title": "`PluginRefChange` is removed — the change channel's `ChangeEvent` is the one shape",
305
+ "kind": "manual"
306
+ },
307
+ {
308
+ "version": "0.28.0",
309
+ "id": "0.28.0/03_atlassian-credentials-context",
310
+ "title": "`credentialsResolver` receives `{ subject, store }` instead of a bare Subject",
311
+ "kind": "manual"
312
+ },
313
+ {
314
+ "version": "0.28.0",
315
+ "id": "0.28.0/04_audit-redacts-subject-metadata",
316
+ "title": "`auditPlugin` redacts `subject.metadata` by default",
317
+ "kind": "manual"
318
+ },
319
+ {
320
+ "version": "0.29.0",
321
+ "id": "0.29.0/01_loader-data-absence",
322
+ "title": "`useLoaderData()` throws at a level that declares no `loader`",
323
+ "kind": "manual"
324
+ },
325
+ {
326
+ "version": "0.3.0",
327
+ "id": "0.3.0/01_prod-serve-requires-build",
328
+ "title": "Production `voltro serve` requires a precompiled bundle (build before serve)",
329
+ "kind": "manual"
330
+ },
331
+ {
332
+ "version": "0.30.0",
333
+ "id": "0.30.0/01_locale-cookie-rename",
334
+ "title": "the language-preference cookie is `voltro:locale` (was `voltro:lang`)",
335
+ "kind": "transform"
336
+ },
337
+ {
338
+ "version": "0.30.0",
339
+ "id": "0.30.0/02_audit-purge-query-recheck",
340
+ "title": "re-run the credential-purge query — the 0.28.0 spelling under-reported on MySQL/MariaDB",
341
+ "kind": "manual"
342
+ },
343
+ {
344
+ "version": "0.30.0",
345
+ "id": "0.30.0/03_webhook-emit-durable-deferral",
346
+ "title": "a deferred `webhooks.emit` rides the transactional outbox; `{ immediate: true }` opts out",
347
+ "kind": "manual"
348
+ },
349
+ {
350
+ "version": "0.30.0",
351
+ "id": "0.30.0/04_workflow-run-handle-nullable-execution",
352
+ "title": "`WorkflowRunHandle.executionId` is `string | null`; `status` gains queued/dropped/skipped",
353
+ "kind": "manual"
354
+ },
355
+ {
356
+ "version": "0.31.0",
357
+ "id": "0.31.0/01_rerun-credential-scan",
358
+ "title": "re-run `voltro db scan-credentials` — on 0.30.0–0.30.2 it skipped the column credentials land in",
359
+ "kind": "manual"
360
+ },
361
+ {
362
+ "version": "0.32.0",
363
+ "id": "0.32.0/01_audit-redacts-outcome",
364
+ "title": "`auditPlugin` now redacts `outcome` by default — opt out if your trail reads it",
365
+ "kind": "manual"
366
+ },
367
+ {
368
+ "version": "0.33.0",
369
+ "id": "0.33.0/01_opentelemetry-optional-peer",
370
+ "title": "`@effect/opentelemetry` is now an optional peer — install it if you use tracing",
371
+ "kind": "manual"
372
+ },
373
+ {
374
+ "version": "0.33.0",
375
+ "id": "0.33.0/02_coordinated-handle-gained-wake",
376
+ "title": "`CoordinatedScheduleHandle` gained `wake()`, `currentIntervalMs()` and `isArmed()` — update hand-written test doubles",
377
+ "kind": "manual"
378
+ },
379
+ {
380
+ "version": "0.4.0",
381
+ "id": "0.4.0/01_rbac-forbidden-to-scopeerror",
382
+ "title": "@voltro/plugin-rbac: `Forbidden` → protocol `ScopeError` (one denial tag)",
383
+ "kind": "transform"
384
+ },
385
+ {
386
+ "version": "0.4.0",
387
+ "id": "0.4.0/02_rbac-web-to-client-permissions",
388
+ "title": "@voltro/plugin-rbac/web removed — the UI gate lives in @voltro/client",
389
+ "kind": "transform"
390
+ },
391
+ {
392
+ "version": "0.5.0",
393
+ "id": "0.5.0/01_one-terminal-exactly-one",
394
+ "title": ".one() now fails on MORE than one row; NoRowFound is a declarable typed error",
395
+ "kind": "manual"
396
+ },
397
+ {
398
+ "version": "0.5.0",
399
+ "id": "0.5.0/02_typed-store-rows",
400
+ "title": "store.query() now returns the row type — casts on row fields may stop compiling",
401
+ "kind": "manual"
402
+ },
403
+ {
404
+ "version": "0.6.0",
405
+ "id": "0.6.0/01_no-dev-session-secret",
406
+ "title": "The built-in dev session secret is removed; VOLTRO_SESSION_SECRET is required",
407
+ "kind": "manual"
408
+ },
409
+ {
410
+ "version": "0.6.0",
411
+ "id": "0.6.0/02_subscription-state-union",
412
+ "title": "SubscriptionState is a discriminated union — `loading` now narrows `data`",
413
+ "kind": "manual"
414
+ },
415
+ {
416
+ "version": "0.6.0",
417
+ "id": "0.6.0/03_billing-on-stripe-sdk",
418
+ "title": "Billing moved onto the Stripe SDK; proration + dunning are now Stripe’s",
419
+ "kind": "manual"
420
+ },
421
+ {
422
+ "version": "0.6.0",
423
+ "id": "0.6.0/04_relation-key-validation",
424
+ "title": "relation key options are validated at boot; `one` now fails on more than one match",
425
+ "kind": "manual"
426
+ },
427
+ {
428
+ "version": "0.6.0",
429
+ "id": "0.6.0/05_atlassian-avatar-mode",
430
+ "title": "atlassianPlugin's `avatar` config requires an explicit `mode: 'service' | 'perUser'`",
431
+ "kind": "transform"
432
+ },
433
+ {
434
+ "version": "0.6.0",
435
+ "id": "0.6.0/06_ui-strings-connect-account",
436
+ "title": "UiStrings gained a required `connectAccount` section",
437
+ "kind": "manual"
438
+ },
439
+ {
440
+ "version": "0.7.0",
441
+ "id": "0.7.0/01_row-filter-load-failure",
442
+ "title": "A row filter that fails to load now errors instead of returning zero rows",
443
+ "kind": "manual"
444
+ },
445
+ {
446
+ "version": "0.7.0",
447
+ "id": "0.7.0/02_testing-invoke-effect-handlers",
448
+ "title": "@voltro/testing: invoke() runs Effect handlers; executor types widened",
449
+ "kind": "manual"
450
+ },
451
+ {
452
+ "version": "0.8.0",
453
+ "id": "0.8.0/01_optional-password-hash",
454
+ "title": "`UserRecord.passwordHash` is optional — password-less identities are now first-class",
455
+ "kind": "manual"
456
+ },
457
+ {
458
+ "version": "0.8.0",
459
+ "id": "0.8.0/02_ssr-streams-and-loaderdata",
460
+ "title": "`ssr` pages stream; `useLoaderData<T>()` returns `LoaderData<T>`",
461
+ "kind": "manual"
462
+ },
463
+ {
464
+ "version": "0.9.0",
465
+ "id": "0.9.0/01_ssr-layout-shell-for-spa",
466
+ "title": "A `renderMode:'spa'` page under a layout now server-renders that layout",
467
+ "kind": "manual"
468
+ }
469
+ ]
470
+ },
58
471
  "engines": {
59
472
  "node": ">=24.0.0"
60
473
  },
@@ -62,22 +475,22 @@
62
475
  "@effect/platform-node": "^0.108.0",
63
476
  "@effect/sql": "^0.52.0",
64
477
  "@effect/workflow": "^0.19.0",
65
- "@voltro/ai": "0.31.0",
66
- "@voltro/cache": "0.31.0",
67
- "@voltro/data-transfer": "0.31.0",
68
- "@voltro/database": "0.31.0",
69
- "@voltro/env": "0.31.0",
70
- "@voltro/kv": "0.31.0",
71
- "@voltro/logger": "0.31.0",
72
- "@voltro/plugin-auth": "0.31.0",
73
- "@voltro/plugin-broadcast": "0.31.0",
74
- "@voltro/plugin-mail": "0.31.0",
75
- "@voltro/plugin-storage": "0.31.0",
76
- "@voltro/plugin-webhooks": "0.31.0",
77
- "@voltro/protocol": "0.31.0",
78
- "@voltro/runtime": "0.31.0",
79
- "@voltro/serverless": "0.31.0",
80
- "@voltro/workflow": "0.31.0",
478
+ "@voltro/ai": "0.33.0",
479
+ "@voltro/cache": "0.33.0",
480
+ "@voltro/data-transfer": "0.33.0",
481
+ "@voltro/database": "0.33.0",
482
+ "@voltro/env": "0.33.0",
483
+ "@voltro/kv": "0.33.0",
484
+ "@voltro/logger": "0.33.0",
485
+ "@voltro/plugin-auth": "0.33.0",
486
+ "@voltro/plugin-broadcast": "0.33.0",
487
+ "@voltro/plugin-mail": "0.33.0",
488
+ "@voltro/plugin-storage": "0.33.0",
489
+ "@voltro/plugin-webhooks": "0.33.0",
490
+ "@voltro/protocol": "0.33.0",
491
+ "@voltro/runtime": "0.33.0",
492
+ "@voltro/serverless": "0.33.0",
493
+ "@voltro/workflow": "0.33.0",
81
494
  "chokidar": "^5.0.0",
82
495
  "ioredis": "^5.11.1",
83
496
  "tinyglobby": "^0.2.17",
@@ -652,7 +652,7 @@ each plugin's own README.
652
652
 
653
653
  | Topic | Open | Summary |
654
654
  |---|---|---|
655
- | **What's new in 0.31.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. |
655
+ | **What's new in 0.33.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. |
656
656
  | 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. |
657
657
  | 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. |
658
658
  | 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. |
@@ -9,7 +9,7 @@ each plugin's own README.
9
9
 
10
10
  | Topic | Open | Summary |
11
11
  |---|---|---|
12
- | **What's new in 0.31.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.33.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. |
@@ -225,6 +225,43 @@ Precedence, exactly:
225
225
  3. **`.safe()`** on an encrypted column suppresses the implied secret and copies
226
226
  it verbatim — say this only when you have genuinely reviewed the plaintext.
227
227
 
228
+ ## Encrypting a column that already has rows
229
+
230
+ `.encrypted()` encrypts on **write**. Adding it to a populated column converts
231
+ nothing that is already stored — those rows stay plaintext until something
232
+ rewrites them, which for a credential column may be never.
233
+
234
+ ```sh
235
+ voltro db encrypt-column integrations.webhookSecret --dry-run
236
+ voltro db encrypt-column integrations.webhookSecret employees.meilisearchKey --yes
237
+ ```
238
+
239
+ It reads `FIELD_ENCRYPTION_KEY` (or `--key-env NAME`) and must be **the same key
240
+ your app runs with** — the one you pass to
241
+ `governancePlugin({ fieldEncryption: { key } })`.
242
+
243
+ **Order does not matter.** A read returns a non-ciphertext value unchanged, so
244
+ the column may hold a mix while you deploy: run the command before or after the
245
+ release that adds `.encrypted()`, and run it again afterwards to catch anything
246
+ written in between. It skips what is already encrypted, which also means an
247
+ interrupted run is resumed by running it again.
248
+
249
+ Five things it refuses to do, each of them a way a hand-written `UPDATE` goes
250
+ wrong quietly:
251
+
252
+ | It checks | Because |
253
+ |---|---|
254
+ | already-ciphertext values are skipped | double encryption cannot be undone without the key history |
255
+ | the value decrypts back before the write | a broken cipher otherwise fails on the first *read*, when the plaintext is gone |
256
+ | the key matches what the column already holds | a *different* key round-trips fine; resuming with one leaves a column readable with neither key alone |
257
+ | the column is wide enough | ciphertext is `49 + 4×ceil(bytes/3)` characters — a 64-char key needs 137, and a `varchar(100)` fails partway through |
258
+ | `--yes` is present | it rewrites a column in place |
259
+
260
+ The width figure is in **bytes**, not characters: `'ä'.repeat(10)` is 10
261
+ characters and 20 bytes, and encrypts to 77.
262
+
263
+ No value — plaintext or ciphertext — is ever printed. The report is counts.
264
+
228
265
  ## `.serverOnly()` — never to a client
229
266
 
230
267
  A THIRD, independent axis. `.sensitive()` / `.safe()` are about **data export
@@ -748,9 +748,11 @@ ctx.store.select('inviteLinks').includeExpired()
748
748
  | | where | when |
749
749
  | --- | --- | --- |
750
750
  | **Invisible to reads** | every dialect | immediately, the instant it passes |
751
- | **Physically deleted** | postgres only | eventually, by the retention sweep |
751
+ | **Physically deleted** | every dialect | eventually, by the retention sweep |
752
752
 
753
- So an expired row is **invisible everywhere and still present in the database on four of five dialects**. That is the right trade — making visibility depend on the sweep would mean a row that vanished on postgres and kept serving on MariaDB — but it is a surprising one, and it matters: *do not treat an expired row as unreachable*. If the value must actually be gone, delete it, or do not store it in a row at all.
753
+ So an expired row is **invisible immediately and still present in the database for a while**. That is the right trade — making visibility depend on the sweep would mean a row that vanished on postgres and kept serving on MariaDB — but it matters: *do not treat an expired row as unreachable*. If the value must actually be gone, delete it, or do not store it in a row at all.
754
+
755
+ The second row of that table used to say **postgres only**, and it was accurate: the sweep was registered behind a `dialect !== 'postgres'` early return, so on mariadb, mysql, mssql and sqlite nothing was ever deleted and the boot printed no armed-policies line to say so. What is postgres-specific is the fast set-based DELETE, not the policy — the sweep falls back to a bounded read plus one set-based delete per batch elsewhere. Fixed in 0.33.0; on those dialects the first boot after upgrading will have a backlog to work through.
754
756
 
755
757
  ## See also
756
758