@voltro/cli 0.30.1 → 0.31.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 (124) hide show
  1. package/CHANGELOG.md +163 -0
  2. package/dist/apiBuild-BOqL1dlg.js +2 -0
  3. package/dist/{apiBuild-DmkzRyv7.js → apiBuild-CLPt-pX6.js} +2 -2
  4. package/dist/appGraph-CvQCte0z.js +2 -0
  5. package/dist/appGraph-gQ_6GkQQ.js +110 -0
  6. package/dist/bin.js +3 -3
  7. package/dist/checkCommand-ClRvH_SN.js +2 -0
  8. package/dist/{checkCommand-C4konUy9.js → checkCommand-D7r6_pk7.js} +439 -530
  9. package/dist/{commands-BkJft9K2.js → commands-CNVVv03h.js} +1941 -1880
  10. package/dist/{dbCommand-qn__kLEt.js → dbCommand-BH8GAYuf.js} +76 -19
  11. package/dist/dbCommand-BwQ_Jl98.js +2 -0
  12. package/dist/{dev-DXhhZ7-f.js → dev-DOZVMVfi.js} +1 -1
  13. package/dist/{dev-C_NPcLDp.js → dev-DdQEn2Ia.js} +1986 -1967
  14. package/dist/{frameworkTableAssembly-Cpgn2e88.js → frameworkTableAssembly-BwIrO5nv.js} +122 -103
  15. package/dist/frameworkTableAssembly-D-EebUQX.js +2 -0
  16. package/dist/index.js +1 -1
  17. package/dist/{inspectMetrics-CkB2J0Zn.js → inspectMetrics-BeEAnjqw.js} +774 -527
  18. package/dist/{sdkgen-wsWLrq4l.js → sdkgen-v9WV8zRi.js} +1 -1
  19. package/dist/{serveCommand-HtI4X5kj.js → serveCommand-KsKXXWn4.js} +294 -293
  20. package/dist/serveEntry.js +2 -2
  21. package/dist/{start-egkbpugc.js → start-CI2QdKy9.js} +351 -346
  22. package/dist/startEntry.js +2 -2
  23. package/package.json +17 -17
  24. package/templates/AGENTS.md +43 -43
  25. package/templates/agent-docs/_index.md +43 -43
  26. package/templates/agent-docs/_manifest.json +84 -42
  27. package/templates/agent-docs/cli.md +4 -2
  28. package/templates/agent-docs/database/migrations.md +14 -1
  29. package/templates/agent-docs/internationalization.md +54 -3
  30. package/templates/agent-docs/plugins/ai-flows.md +148 -0
  31. package/templates/agent-docs/plugins/analytics-postgres.md +90 -0
  32. package/templates/agent-docs/plugins/atlassian.md +378 -0
  33. package/templates/agent-docs/plugins/audit.md +324 -0
  34. package/templates/agent-docs/plugins/auth-auth0.md +92 -0
  35. package/templates/agent-docs/plugins/auth-clerk.md +90 -0
  36. package/templates/agent-docs/plugins/auth-kinde.md +88 -0
  37. package/templates/agent-docs/plugins/auth-oidc.md +95 -0
  38. package/templates/agent-docs/plugins/auth-supabase.md +103 -0
  39. package/templates/agent-docs/plugins/auth-workos.md +105 -0
  40. package/templates/agent-docs/plugins/auth.md +227 -0
  41. package/templates/agent-docs/plugins/billing.md +324 -0
  42. package/templates/agent-docs/plugins/broadcast.md +144 -0
  43. package/templates/agent-docs/plugins/cdc-out.md +116 -0
  44. package/templates/agent-docs/plugins/clickhouse.md +91 -0
  45. package/templates/agent-docs/plugins/datadog.md +105 -0
  46. package/templates/agent-docs/plugins/deactivation.md +114 -0
  47. package/templates/agent-docs/plugins/duckdb.md +82 -0
  48. package/templates/agent-docs/plugins/flags.md +146 -0
  49. package/templates/agent-docs/plugins/governance.md +143 -0
  50. package/templates/agent-docs/plugins/licensing.md +74 -0
  51. package/templates/agent-docs/plugins/logship.md +56 -0
  52. package/templates/agent-docs/plugins/mail.md +334 -0
  53. package/templates/agent-docs/plugins/moderation.md +65 -0
  54. package/templates/agent-docs/plugins/multitenancy.md +99 -0
  55. package/templates/agent-docs/plugins/notifications.md +252 -0
  56. package/templates/agent-docs/plugins/openapi.md +94 -0
  57. package/templates/agent-docs/plugins/postgis.md +140 -0
  58. package/templates/agent-docs/plugins/posthog.md +91 -0
  59. package/templates/agent-docs/plugins/presence.md +115 -0
  60. package/templates/agent-docs/plugins/prometheus.md +124 -0
  61. package/templates/agent-docs/plugins/ratelimit.md +274 -0
  62. package/templates/agent-docs/plugins/rbac.md +270 -0
  63. package/templates/agent-docs/plugins/scim.md +63 -0
  64. package/templates/agent-docs/plugins/search.md +116 -0
  65. package/templates/agent-docs/plugins/sentry.md +192 -0
  66. package/templates/agent-docs/plugins/soft-delete.md +72 -0
  67. package/templates/agent-docs/plugins/sso-saml.md +132 -0
  68. package/templates/agent-docs/plugins/storage.md +709 -0
  69. package/templates/agent-docs/plugins/tinybird.md +92 -0
  70. package/templates/agent-docs/plugins/versioning.md +226 -0
  71. package/templates/agent-docs/plugins/webhooks.md +585 -0
  72. package/templates/agent-docs/security.md +12 -1
  73. package/templates/agent-docs/whats-new.md +81 -37
  74. package/templates/apps/api-ai/package.json +7 -7
  75. package/templates/apps/api-auth/package.json +8 -8
  76. package/templates/apps/api-backend/package.json +7 -7
  77. package/templates/apps/api-backend-deactivation/package.json +7 -7
  78. package/templates/apps/api-backend-mail/package.json +8 -8
  79. package/templates/apps/api-backend-mariadb/package.json +9 -9
  80. package/templates/apps/api-backend-sqlite/package.json +8 -8
  81. package/templates/apps/api-backend-storage/package.json +8 -8
  82. package/templates/apps/api-cms/package.json +10 -10
  83. package/templates/apps/api-collab/package.json +8 -8
  84. package/templates/apps/api-data-advanced/package.json +8 -8
  85. package/templates/apps/api-durable/package.json +8 -8
  86. package/templates/apps/api-feature-flags/package.json +9 -9
  87. package/templates/apps/api-governance/package.json +8 -8
  88. package/templates/apps/api-kv/package.json +8 -8
  89. package/templates/apps/api-moderation/package.json +8 -8
  90. package/templates/apps/api-observability/package.json +8 -8
  91. package/templates/apps/api-ratelimit/package.json +8 -8
  92. package/templates/apps/api-rbac/package.json +8 -8
  93. package/templates/apps/api-rest/package.json +7 -7
  94. package/templates/apps/api-saas/package.json +11 -11
  95. package/templates/apps/api-saas-starter/package.json +10 -10
  96. package/templates/apps/api-search/package.json +8 -8
  97. package/templates/apps/api-status/package.json +8 -8
  98. package/templates/apps/api-versioning/package.json +8 -8
  99. package/templates/apps/api-webhooks/package.json +9 -9
  100. package/templates/apps/changelog/package.json +6 -6
  101. package/templates/apps/edge-functions/package.json +2 -2
  102. package/templates/apps/frontend-admin/package.json +8 -8
  103. package/templates/apps/frontend-app/package.json +8 -8
  104. package/templates/apps/frontend-auth/package.json +8 -8
  105. package/templates/apps/frontend-blank/package.json +7 -7
  106. package/templates/apps/frontend-cms/package.json +9 -9
  107. package/templates/apps/frontend-collab/package.json +9 -9
  108. package/templates/apps/frontend-contact/package.json +7 -7
  109. package/templates/apps/frontend-dashboard/package.json +7 -7
  110. package/templates/apps/frontend-docs/package.json +7 -7
  111. package/templates/apps/frontend-i18n/package.json +6 -6
  112. package/templates/apps/frontend-landing/package.json +7 -7
  113. package/templates/apps/frontend-portal/package.json +8 -8
  114. package/templates/apps/frontend-saas/package.json +8 -8
  115. package/templates/apps/frontend-spa/package.json +7 -7
  116. package/templates/apps/frontend-ssr/package.json +7 -7
  117. package/templates/apps/frontend-ssr-api/package.json +8 -8
  118. package/templates/apps/frontend-static-blog/package.json +6 -6
  119. package/templates/apps/frontend-status/package.json +8 -8
  120. package/templates/apps/mobile-app/package.json +2 -2
  121. package/dist/apiBuild-Ca6Sq5jy.js +0 -2
  122. package/dist/checkCommand-DHD0aBeR.js +0 -2
  123. package/dist/dbCommand-wfGi3FgG.js +0 -2
  124. package/dist/frameworkTableAssembly-Bn_c4Mnl.js +0 -2
@@ -1,4 +1,4 @@
1
- # What's new in 0.30.1
1
+ # What's new in 0.31.0
2
2
 
3
3
  Read this FIRST when a task touches an area you have not worked in recently.
4
4
  It is the cheapest way to notice that the framework grew the thing you were
@@ -7,69 +7,113 @@ workaround for something that shipped two versions ago.
7
7
 
8
8
  BREAKING entries name a codemod; run `voltro update` to apply it.
9
9
 
10
+ ### Added
11
+
12
+ - **@voltro/i18n, @voltro/cli** — **`LOCALE_COOKIE` and `THEME_COOKIE` are exported from `@voltro/i18n`.**
13
+
14
+ `voltro doctor` flags a hand-written `'voltro:locale'` and tells you to "import the constant … from `@voltro/ui-shadcn`" — which was the only package exporting one. An app on the framework's i18n and not on the shadcn kit could not follow that advice without adopting a UI kit for two strings. Reported by a consumer, who added that the rule "does not fire for us, and we think that is correct-by-accident".
15
+
16
+ The names live in `@voltro/i18n` now (the package that resolves the locale from a request already hardcoded the literal), doctor's remedy names it, and `cookieNameParity.test.ts` asserts every declaration in the repo agrees AND that the remedy names a package which actually exports what it names.
17
+
18
+ That second assertion is one `scripts/check-message-apis.mjs` structurally cannot make: it verifies a member EXISTS in the published surface, and `LOCALE_COOKIE` always did — just not anywhere the reader could import it from. A reachability claim needs its own check.
19
+ - **@voltro/cli** — **`voltro doctor` reports two things that were decidable and unreported: dead endpoints and never-fired events.**
20
+
21
+ **A procedure requiring a scope no declared role grants.** A consumer shipped `webhooks.test` guarded by `webhooks:test` while their roles granted `webhooks:read` and `webhooks:write` and nothing else — uncallable by every user in every team, with nothing failing at boot to say so — and asked us to build the rule. The rule already existed: `rbac/unknown-scope`, in `voltro check`. It was in the wrong PLACE for them. `check` is the CI gate; `doctor` is what someone runs when something feels wrong, and a rule that only fires where you already suspect the problem fires for the people who did not need it. Doctor now surfaces the same finding from the same function — reused, not re-derived, because two answers to "which scope is ungranted" would diverge on the day it mattered.
22
+
23
+ **A declared event with no emit call site.** Asked for as a dashboard column, with the number that motivated it: seven of eleven advertised events had no emit anywhere, a week of work to remove. From a partner's side that is the expensive failure — they write a subscriber, test it, see nothing, and cannot tell "not implemented" from "my endpoint is broken". It is source-decidable, so it lands before deploy for every app rather than for whoever opens a panel afterwards. ADVISORY, and it says so: an emit through a variable reads as missing here.
24
+
25
+ Both reach `--json` and the human report. `serverOnly` and `authz` were each in one and absent from the other, twice, and "absent" read as "nothing to report".
26
+ - **@voltro/cli** — **`voltro dev` and `voltro doctor` report `@voltro/*` packages that are not on the same release.**
27
+
28
+ A consumer bumped 34 packages to 0.30.2 and `@voltro/i18n` stayed on 0.30.0 — their bump script's pattern was `@voltro/[a-z-]+`, and `i18n` contains digits. Their point was not the typo:
29
+
30
+ > *"Der erwähnenswerte Teil ist, dass eine Versionsschiefe innerhalb einer > Release-Familie nirgends auffällt: tsc, Tests, doctor und drei Builds waren > mit dem 0.30.0-Paket im Baum alle grün. Wenn ihr eine Stelle habt, an der das > billig zu prüfen wäre, wäre eine Warnung dort mehr wert als eine perfekte > Fehlermeldung anderswo."*
31
+
32
+ `tsc` in four apps, 19 317 tests, `voltro doctor` exit 0, three production builds — all green with a package two releases behind. None of those checks is ABOUT version agreement, so none of them could have caught it.
33
+
34
+ The framework ships in LOCKSTEP (`prepare-publish.mjs` stamps one version across every package), which is what makes this exact rather than a compatibility guess: two versions in one tree is a state the release process cannot produce. Reported at dev boot — where they asked for it, because that is where it is cheap — and in doctor's human report and `--json`. WARN, never fatal: we have no evidence a skewed tree cannot work, only that the combination was never released as a set.
35
+
36
+ Distinct from the duplicate-instance check, which asks a different question ("is one package resolved at two versions?") and has a different fix.
37
+
10
38
  ### Fixed
11
39
 
12
- - **@voltro/testing, @voltro/sql-mysql** — **One integration suite was never skip-guarded, and the guard it called silently ran it anyway.** `describeIfAvailable(label, dependency, probe, suite)` was called with three arguments in `sql-mysql`'s `fileMigrationLedger.mariadb` suite, so `probe` bound to the SUITE body: `await probe()` executed it at file scope, its `beforeAll` and `test`s registered outside any `describe` and ran unconditionally, and the `describe.skipIf` underneath registered an empty shell. The file therefore passed when MariaDB happened to be up and hard-failed with `SqlError: MysqlClient: Failed to connect` when it was not the exact opposite of the clean skip it was written to have, and a red `pnpm test` for anyone without the docker stack.
40
+ - **@voltro/cli** — **`voltro db scan-credentials` on 0.30.0–0.30.2 did not look at the column credentials are in, and exited 0.**
41
+
42
+ 0.30.0 fixed a crash — the scan asked every table for a column called `subject`, `_voltro_row_history` has none, and the command died on postgres with `code=42703`. The fix replaced `subject` with `subjectId` on BOTH tables. That is right for one table and wrong for the other: `_voltro_audit_log.subject` is a `json()` blob and is the exact column the 0.28.0 upgrade note named — the one a reporting team found 117 rows of `jiraToken` in. `subjectId` is a flat opaque id that cannot hold a credential.
43
+
44
+ So for three releases a security command ran cleanly, printed a scanned count beside a hit count, and had never looked where credentials are. **A clean answer from a scan that searched the wrong place is worse than the crash it replaced.**
45
+
46
+ The default targets are derived from where a credential can physically land now: every `json()` column on `_voltro_audit_log` (`subject`, `actor`, `scope`, `metadata`, plus `input` / `outcome` — a procedure's arguments and result, the likeliest accidental home for a token), and `data` on `_voltro_row_history` — the full-row snapshot, which carries a credential column from ANY user table and outlives deleting the source row. The test that signed off on the narrowing is derived from the table declarations now, so it fails in both directions: a target naming a column that does not exist, and a column that exists and goes unscanned.
47
+
48
+ A manual codemod under 0.31.0 tells anyone who ran the command on 0.30.x to run it again — a codemod note is delivered once at a version boundary and cannot be revised, so a correction has to be re-issued under a version nobody has reached.
49
+ - **@voltro/cli** — **`voltro dev` announced `ready` while a different process served its port.**
50
+
51
+ Reported as an aside — "it fails with `Port 5190 is already in use` and the OLD process keeps answering" — and measured to be worse than that. With a squatter on IPv4 `127.0.0.1:5299`, vite's `host: true` bound IPv6 `*:5299` SUCCESSFULLY and the boot printed `listening on http://localhost:5299` and `ready in 56 ms`. Two listeners, one port, different stacks; every request went to the old process, with the old module graph. Not a failed boot — a boot that reports ready while your edits do nothing.
52
+
53
+ `strictPort: true` was set and working: it asks "can I bind?", and the failure is "is somebody already serving this?", which on a dual-stack host is a different question with a different answer. Both dev boot paths (api and web) now CONNECT to `127.0.0.1` and `::1` before creating a server and refuse with a `bootRefusal` naming the port, the stack, and `lsof -nP -iTCP:<port> -sTCP:LISTEN`. Exit 1, no `ready` line. Deliberately dev-only: in production the ambiguous cases are real (a sidecar, a health proxy, a rolling restart sharing a namespace) and refusing a legitimate boot is the worse failure — `serve` keeps failing on the bind alone.
54
+ - **@voltro/cli** — **`voltro doctor`'s duplicate-version check could not see the tree the consumer who asked for it actually had.**
13
55
 
14
- `tsc` could not catch it: every dialect package's tsconfig `include` lists the src glob only, so `__tests__/` is not typechecked at all the same gap that lets an incomplete parity fixture compile. So the arity is checked at runtime now, and `describeIfAvailable` throws a `TypeError` naming what it got instead of quietly running the suite. One of roughly twenty call sites was wrong; nineteen were right, which is why nothing looked off.
15
- - **@voltro/cli** — **Four things `voltro doctor` knew and would not tell you.** All reported by a consumer, all measured rather than guessed.
56
+ They shipped the app on `@voltro/i18n@0.30.1` while `packages/ui-admin` and `ui-admin-shared` which depend on it themselves were left on 0.30.0. Two physical copies of a package carrying a React context; nothing failed at boot, no test caught it, and the framework's own dev-SSR diagnosis names that condition as a cause. They asked us to build the check. **It existed, and it was blind to their case.**
16
57
 
17
- **The authz list was reachable by no route at all.** The human view truncated at 20 (`… and 14 more`) and `--json` had no `authz` section — measured, its keys were `root · scannedFiles · … · serverOnly`. Reading findings 21..n meant allowlisting the first 20, re-running, and resetting the file: a loop to read a list the tool already had. `--json` carries `authz` now (`counts`, `guardVocabulary`, `allowlist`, and every `unchecked` finding, never truncated), and the elision line names both the command and the field. The same defect, one section over, is recorded in `serverOnly`'s own comment — "the field was MISSING from `--json` entirely" so this is that lesson applied rather than re-learned. Both surfaces read ONE scan (`scanAuthzForRoot`), because two derivations of one scan is how two views come to disagree about what was found.
58
+ It walked the app's `node_modules` plus every ancestor's, on the reasoning that the pnpm virtual store is reached through the symlinks those contain. True for one copy: an ancestor's `node_modules/@voltro/i18n` is ONE symlink to ONE version. A second version pulled in by a SIBLING workspace package is linked only from that sibling's own `node_modules`, which is neither the app root nor an ancestor of it so it was structurally invisible from the directory doctor is run in.
18
59
 
19
- **The allowlist could not tell "reviewed and safe" from "debt".** Its header says `This is DEBT, not approval` — which is right, and which made it the wrong place for the other thing people legitimately need to record: an executor a human has read and found genuinely open, constrained by something the scanner cannot see. It was also the ONLY place, so the reporter resorted to comment blocks around groups of lines a convention inside a file parsed line by line, which the next `--write-authz-allowlist` would have flattened without a word. A line is now either `<tag>` (debt, unchanged) or `<tag> reviewed=<why>`, the reason REQUIRED `reviewed=` with no why is the claim without the evidence and is refused, since a bare tag is the honest alternative and always available. Doctor counts and prints the two apart, and `--write-authz-allowlist` preserves reviewed lines instead of downgrading them.
60
+ The pnpm store is read directly now, from its directory NAMES (`@voltro+i18n@0.30.0`), which is one `readdir` rather than a descent into thousands of inner `node_modules`. The peer-hash suffix pnpm appends is not read as a versionone package linked twice for two peer sets is normal, and reporting it would train people to ignore the rule.
61
+ - **@voltro/database, @voltro/sql-mysql** — **`json().default([])` emitted MySQL-only DDL and died mid-plan on MariaDB.**
20
62
 
21
- **A hint that named 41% of the files was not a hint.** One hand-roll finding listed 2 641 of 6 374 files, and the reporter skipped the whole section because of it — including the lines pointing at 5 and 13 files, which were worth acting on that day. Findings now print FEWEST files first, and a finding above both a share (20%) and a floor (50 files) prints its ADVICE without the enumeration, marked as a codebase-wide pattern. Both bounds matter: the share is what makes it a pattern, the floor keeps a small app — where "3 of 8 files" is a large share and a perfectly readable list — out of it. The paths stay in `--json`.
63
+ The emitter had one branch for both servers, under a comment asserting MariaDB 10.2.7+ accepts the MySQL form. It does not. Measured against the real servers:
22
64
 
23
- **A translation catalog that is never loaded said nothing.** `src/locales/{code}.ts` is imported by the web codegen only when the app declares `locales:`. Without that line the files are inert no import, no provider, no error — and from the inside a catalog that is never loaded looks exactly like one that works. The reporter carried `de.ts` + `en.ts` in TWO apps for months, never wired, and measured that neither boot nor doctor mentioned it. Doctor now names the orphaned codes and offers both ways out: the exact `locales: [...]` line to paste, or delete the files (which is what they did). It deliberately does NOT report the reverse — a declared locale with no file already fails loudly at codegen, and a second, weaker voice for a problem that has a loud one is noise.
24
- - **@voltro/cli** — **`encryptSteps` was derived twice, once per boot path.** Six hand-mirrored lines in `dev.ts` and in `serveApi.ts` — read the flow control off the definition, compare `=== true`, build the cipher, spread the result or nothing. They agreed today and nothing kept them agreeing, which is the shape that produced the `_voltro_outbox` error loop and every dev/serve scar in `packages/cli/CLAUDE.md`. The asymmetry a drift would produce here is the bad direction: step payloads encrypted under `voltro dev` and plaintext under `voltro serve`, with the declaration reading as protection in both.
65
+ | | statement | result | |---|---|---| | MariaDB 11.8.8 | `SET DEFAULT (CAST('[]' AS JSON))` | `ERROR 1064 near 'JSON))'` | | MariaDB 11.8.8 | `SET DEFAULT ('[]')` | OK | | MySQL 8.4.10 | `SET DEFAULT ('[]')` | `ERROR 1101 can't have a default value` | | MySQL 8.4.10 | `SET DEFAULT (CAST('[]' AS JSON))` | OK | | BOTH | `SET DEFAULT (CONVERT('[]' USING utf8mb4))` | OK |
25
66
 
26
- `stepPayloadCipherOptions(definition)` is the one derivation now, and it is slightly better than either copy it replaced: the workflow NAME in the boot-refusal message comes from the resolved control rather than from a second argument, so the flag and the name it is reported under are the same object. `flowControlParity.test.ts` pins that both paths call it AND that neither re-derives `encryptSteps === true` inline.
27
- - **@voltro/runtime, @voltro/cli, @voltro/workflow** — **`debounce` never ran. Neither did a `batch` that flushed on its timeout — and `batch` could not be started at all.** Three defects, one boundary, all found by a consumer who adopted flow control against a live API and measured `attempts: 13, collapsed: 14, runs: 0` on a debounced workflow that never produced a run.
67
+ MariaDB has no JSON *type* the column is `LONGTEXT` with `CHECK (json_valid(...))` so `AS JSON` is not a cast target it has; MySQL treats a parenthesised literal as a literal and demands a real expression. The failure was not graceful: the plan died mid-apply, leaving a boot migration part-applied.
28
68
 
29
- **1 the drainer re-entered the admission boundary it had just cleared.** A deferred start is judged twice on purpose: once on arrival, once when the drainer reconsiders the pending row. The second judgement is the one that ADMITS, and the drainer then started the workflow *through the facade* deliberately, so a queued run takes exactly the code path an immediate one does. But the facade's start IS the arrival path, and arrival is where a deferring control defers. So the admitted start was deferred straight back into the row it came from: `collapsed` up by one, the row still pending, the engine never reached, one wasted pass per second, forever. `debounce` was 100% broken; `batch` was broken whenever it flushed on the timeout rather than by filling. `throttle` and `concurrency` survived only by an ordering accident — the re-entrant arrival happened to re-admit because the ledger row and lease are written *after* the start returns. The drainer's start now carries an internal `admitted` marker that skips the gate: it is the APPLICATION of a decision already made, and everything the arrival path would have done (pause, singleton eviction, the ledger row and lease, consuming the intents) the drainer does around it.
69
+ `CONVERT(… USING utf8mb4)` is emitted for both, chosen over splitting the branch because the declarative applier cannot tell the two servers apart`sql.onDialectOrElse` collapses the family to one token so a per-server answer would have meant plumbing the real dialect through three call sites. Both forms introspect back to something `normalizeDefault` unwraps, so the next plan is EMPTY instead of re-emitting the same op forever.
30
70
 
31
- **2 — a `batch:` workflow rejected every caller's start.** The declaration contract is explicit and enforced: the workflow's own `payload` is `{ items: Schema.Array(Item) }` while callers `start()` it with a SINGLE item, declared as `batch.item`. `batch.item` was required, asserted at declaration time — and then dropped during resolution and read by nothing. So the facade validated the caller's single item against the batch shape and threw `WorkflowPayloadError: missing required field(s): items` before the gate was ever reached. `batch:` was unusable end to end. The item schema is now carried through and is what an arriving start is judged by; a drained batch is judged by the workflow's own schema.
71
+ `sql-mysql/src/jsonColumnDefault.integration.test.ts` boots BOTH servers, applies the schema and asserts the inserted row carries the default verified red against the old emitter (`ER_PARSE_ERROR 1064`) before it was made green.
72
+ - **@voltro/cli** — **`locales:` declared the app's languages in `voltro dev` and demanded catalogs in `voltro build` — so an app on its own i18n stack got the right language in development and `lang="en"` in production.**
32
73
 
33
- **3 the two halves of that boundary could be wired half-right, in both boot paths.** `startPayloadSchema` is pinned beside `admitStart` in `flowControlParity.test.ts` as a separate assertion, because passing one and not the other fails silently and differently.
74
+ `voltro dev` already separates the two: the catalogs decide the CATALOG wiring, `locales:` decides the language facts (`<html lang>`, the resolved locale, `meta.locale`). The build did not, which is this repo's dev/build drift in its worse direction — the environment nobody watches, on the day of the first deploy.
34
75
 
35
- **Why no unit suite could see any of this.** `admissionDrainer.test.ts` fakes `startAdmitted`; `workflowRuntime.test.ts` fakes `admitStart`. Each is a complete test of its own half, and the defect lived strictly between them the same shape as this repo's dev/serve parity scars, one level down. `flowControlDrainRoundTrip.test.ts` wires a real gate to a real facade over a real in-memory store and drives all four deferring controls from arrival to run. It was written red: debounce and batch-timeout failed, throttle and concurrency passed, which is exactly the diagnosis. It asserts the pending row is CONSUMED rather than merely that a run eventually happened — a debounce that re-collapses twice on the way is still broken, and `admitted: 1` alone would not say so.
36
- - **@voltro/cli** — **`_voltro_outbox` was polled every five seconds by apps that never had it created.** Reported by a consumer as a permanent `Table doesn't exist` loop — and, they noted, "a permanent error loop that buries the real ones". The table appeared zero times in `voltro db plan`, which was correct for the gate as written and wrong for what the boot actually does.
76
+ Reported by a consumer on react-i18next, who left `locales:` out because it demanded `src/locales/<lang>.ts` they do not have, and got `<html lang="en">` plus `locale: 'en'` handed to every page's `meta` in a German app:
37
77
 
38
- The two predicates had drifted. The table was created when the app declared at least one `*.outbox.ts` handler; the delivery worker was STARTED when at least one handler existed *including the framework's own* `voltro.webhook.emit`, which is registered whenever the app has a webhook surface. So an app with webhooks and no handler file got the worker, got `ctx.outbox`, and got a `ctx.webhooks.emit` inside a mutation writing through a table that was never planned. The 0.30.0 note claiming such an app "keeps the in-memory callback" described the intent, not the code.
78
+ > *"Der Parameter `locale` ist damit für uns nicht nur nutzlos, sondern > gefährlich: hätten wir ihm vertraut, wäre nach der Hydration jeder deutsche > Tab englisch geworden."*
39
79
 
40
- Widening the table's gate to match could not work: the webhook surface includes outgoing webhooks declared on EVENTS, and the migration path detects features by walking filenames, so it cannot see them without loading the app's modules. **`_voltro_outbox` and `_voltro_outbox_attempts` are therefore created for every sql app now** — small, dialect-neutral, empty unless something enqueues, the same trade `_voltro_wakeups` and the storage tables already take. Two empty tables against a class of divergence that has no symptom until production.
80
+ A value the framework hands you that is confidently wrong is worse than one it withholds.
41
81
 
42
- It also fixes `voltro migrate`, which never passed the flag at all and, in the same sweep, `voltro migrate` never detected `*.connection.ts` either, so the credential-vault tables were created by `voltro dev` / `voltro db apply` and silently not by `voltro migrate`. Migrate carried its own copy of the feature-detection walk; it calls the shared `detectFeatureMix` now, so there is one walk and one answer.
82
+ The build now emits a resolver-only i18n runtime when `locales:` is declared with no catalogs: `resolveLocale` (cookie > `Accept-Language` > default, negotiated against the declared set) with an identity `outerWrap`. No provider, no React, no catalog imports and `voltro start` sets `<html lang>` and `meta.locale` from the real negotiation instead of falling back to `'en'`.
83
+ - **@voltro/cli** — **A plugin's depth was addressed as a 1 KB README that says "read the website" — a dead end for an agent working inside a repo.**
43
84
 
44
- **And the delivery worker no longer prints a wall.** An identical drain failure is reported once at `warn`, escalated ONCE to `error` after ~a minute of consecutive identical failures ("this is not transient. Enqueued effects are NOT being delivered"), and then suppressed until the cause CHANGES or it recovers recovery says so, with how many passes it was broken for, because a failure that stopped being logged and one that got fixed must not read alike.
85
+ We spent a round correcting a documented recommendation (`resolveSubjectId`) that the one team who had lived it had retracted. That consumer went looking for the correction in the channel our own `AGENTS.md` advertises as authoritative:
45
86
 
46
- **The 0.30.0 codemod note said the opposite, and it is corrected in place.** It told users that an app declaring no `*.outbox.ts` "falls back to the in-memory callback" — the intent, not the code. Normally a note under a published version cannot be revised (`selectCodemods` filters `from < version <= to`, so anyone who has already crossed 0.30.0 will never see a correction, which is why corrections are re-issued under a version nobody has reached). That rule is about a changed *instruction*, where someone who acted on the old one has to hear the new one. This is a false statement of fact with nothing attached for a reader to undo — the table is created by the declarative differ on the next `voltro dev` boot or `voltro db apply` — so the alternative was leaving every future 0.29 → 0.31 upgrader a sentence that is simply untrue.
47
- - **@voltro/web** — **The second half of the SSR `useId` divergence: the client boot rendered a sibling to the app that the server did not.** `VoltroRuntimeProvider` renders `{children}` alongside a chrome slot (`chromeMounted ? <>…overlays…</> : null`), while the server rendered the page tree with no boot wrapper at all. A parent with two children forks React's tree-id path; a parent with one does not — so this shifted every `useId` in the app exactly as the router provider did, one level further up.
87
+ ```
88
+ resolveSubjectId → 0 Treffer
89
+ | notifications | node_modules/@voltro/plugin-notifications/README.md |
90
+ ```
48
91
 
49
- It is filed separately from the router fix because the two are independent and **each is independently fatal**: measured on a pristine tree, fixing only the router still fails and fixing only this still fails. Both paths now render `RootChromeSlot`, one component owning the arity, with `chrome: null` on the server.
92
+ > *"Diese Datei ist 1 039 Byte Für einen Menschen ist das ein Klick. Für einen > Agenten, der im Repo arbeitet, ist es eine Sackgasse."*
50
93
 
51
- The irony is worth keeping, because it is what made the defect invisible: the `chromeMounted` gate was added so the first client render matches the server DOM. It does and that is exactly why hydration SUCCEEDS, React keeps the server markup, nothing throws, and the only casualty is the ids. The gate did not cause the fork; the slot forks whether or not it renders anything.
94
+ Their measurement was slightly off the correction WAS in `agent-docs/`, in `whats-new.md` and the truth is worse than their reading. `whats-new.md` is regenerated from the LATEST release section only, so the lesson would have vanished at 0.31.0 regardless. Same structure as a codemod note: delivered once, at a boundary, unrevisable. **A durable lesson needs a durable address.**
52
95
 
53
- **What must not change without re-measuring:** the number of forks above the page on each side. Nesting DEPTH is free measured, any number of single-child providers above the router keeps ids aligned but adding a sibling to the app on one path only (an overlay, a portal host, a second root element) reintroduces this. `ssrTreeIdParity.test.tsx` holds it in jsdom; `scripts/browser-ssr-hydration-ids.mjs` holds it in a real chromium against a real `voltro dev`.
54
- - **@voltro/web** — **Every `useId` in an SSR app mismatched on hydration, on every page, since the route announcer was added.** Reported by a consumer against 0.30.0 and 0.29.0 with the two `dist` bundles read side by side — not a regression, and not something any of our tests could see.
96
+ Each plugin's docs page is now compiled into `agent-docs/plugins/<slug>.md` and the index points there first, README secondin the generated template AND in the per-project file the seeder writes, which is the one users actually read. The per-plugin modules stay out of the TOPIC table on purpose: 42 rows all titled "Plugins" would be a worse index than the dead end it replaces.
97
+ - **@voltro/database, @voltro/plugin-webhooks, @voltro/runtime** — **A `QueryDescriptor` without `order` took the SELECT compiler down, and the framework reported it as a database failure.**
55
98
 
56
- The router provider took ONE child on the server (`createElement(RouterContext.Provider, { value }, tree)`) and TWO on the client (JSX with `{content}` and the announcer, which compiles to `jsxs` with a 2-element array). React derives `useId` from the path of ARRAY SLOTS down to a fiber: a single child does not fork, a 2-element array forks and places the subtree at index 0. So the entire tree below the router sat at a different tree id on the two sides, and every id generated beneath it differed.
99
+ {"msg":"mutation.webhooks.test failed: e.order is not iterable", "dbCauseChain":"TypeError: e.order is not iterable"}
57
100
 
58
- **The failure is unusually quiet, which is why it lasted.** The second child is `announcerReady ? <RouteAnnouncer/> : null`, and `announcerReady` starts `false` so the first client pass renders `null`, the DOM matches, hydration SUCCEEDS, and React keeps the server markup and merely warns about the attributes. Nothing breaks visibly; the console fills with `A tree hydrated but some attributes didn't match` for every component that calls `useId`. With Radix that is every tooltip, dialog, accordion, collapsible, select and label.
101
+ `dbCauseChain` sent the reporter to the connection, the driver and the dialect. The database was never involved the SELECT was never built. Nothing they could write in app code reached it either: the descriptor is constructed inside `@voltro/plugin-webhooks`, so `ctx.webhooks.testTarget(...)` was unusable and the outgoing-webhook path could not be exercised end to end.
59
102
 
60
- **There were TWO such divergences, not one, and each is independently fatal.** The router provider is the one the reporter found by reading the bundles; one level further up, the client's `VoltroRuntimeProvider` rendered the app ALONGSIDE a chrome slot (`{children}{chromeMounted ? … : null}`) while the server rendered no boot wrapper at all. Measured on a pristine tree: fixing only the router still fails, fixing only the chrome slot still fails, fixing both passes. So a report that names one of them is not a partial diagnosis to be discounted — it is half of the answer, and the half nobody had.
103
+ The field is DECLARED required, which is why this looked impossible. A descriptor is hand-built at ~130 sites and nearly all of them cast (`as never`) past the generic row type and a cast switches the required-field check off for the whole literal. Four sites shipped `order: undefined`.
61
104
 
62
- Both paths now render ONE shared component at each level — `RouterProviderTree` for the router, `RootChromeSlot` for the boot whose second slot is always present and `null` where there is nothing to put in it. The arity is identical by construction rather than by two call sites agreeing. `ssrTreeIdParity.test.tsx` renders one page through both paths and compares a `useId`, so a future change to the shape fails at the point of change instead of in a consumer's browser. It was written red first. Its FIRST version was the cautionary tale, though: it compared the server render against a bare `<Router>` and passed while the app was still broken, because the boot-level fork it did not model is the one that was left. It hydrates through the real `VoltroRuntimeProvider` now — every hydrating path in `mount.tsx` goes through it, so a bare router is not a shape that exists. A parity test that models less than the real boot proves only that the part it models agrees.
105
+ Fixed as ONE read path (`orderClausesOf`) rather than a guard at the reported line: `order` was dereferenced bare in TWELVE places across two compilers (three in `sqlCompiler.ts`, nine in `jsonEagerCompiler.ts`), so patching the crash site would have moved it rather than removed it. The four lying call sites are corrected, and a source scan fails on a fifth.
106
+ - **@voltro/cli, @voltro/i18n** — **Dev SSR could build an `<I18nProvider>` the app's own `useT()` could not see, and the diagnosis we shipped pointed at a check that cannot observe the cause.**
63
107
 
64
- **The methodological trap is carried in the test, because it cost the reporter an hour and would cost the next person one:** reading the id back from the DOM shows the SERVER's value on both sides hydration deliberately does not patch ids, which is the very thing the warning says. A harness built that way reports the bug as absent. The id has to be captured from the render that computed it, and a second test proves the harness would still catch a fork.
108
+ `ssr.noExternal: ['react-intl']` without `@voltro/i18n` is itself an instance splitter: Vite externalizes a node_modules dependency in SSR, so Node not Vite resolves everything IT imports. An externalized `@voltro/i18n` therefore got Node's react-intl while every Vite-transformed module got the bundled one. Two instances, two contexts, and a provider invisible to a `useT()` with an error byte-identical to having no provider at all. Both are now bundled and deduped together in `voltro dev`, `voltro build` and `voltro start`, pinned by `i18nSingleInstance.test.ts` across all three configs.
65
109
 
66
- **Verified in a real browser, not only in jsdom.** `scripts/browser-ssr-hydration-ids.mjs` boots `voltro dev` on the SSR fixture from SOURCE, loads a `renderMode: 'ssr'` page, and asserts the client computes the same `useId` the server wrote AND that react-dom logs no mismatch. Removing either half of the fix makes it print the reporter's exact string `A tree hydrated but some attributes of the server rendered HTML didn't match the client properties` which is the only place that message can be observed at all: the DOM is identical, hydration succeeds, nothing throws, and there is no server-side signal.
67
- - **@voltro/web, @voltro/cli** — **The server render discarded the request's query string.** `RenderPageOptions` had no `search`, and the SSR router context hardcoded `search: ''` with a comment noting that the client reads `window.location.search` on hydration. That is true, and it is precisely why the hardcoding was wrong: the client reading the real value is what turns a discarded query string into a divergence in an exported context value. The value was already computed in both per-request boot paths — the loaders receive it — and simply never reached the renderer.
110
+ The framework's diagnosis told readers to check with `pnpm ls -r --depth 10 @voltro/i18n react-intl`, and to report a framework bug if that showed one version of each. A consumer did exactly that one version, one directory in the store, four fresh boots — and was still at a 500 on every SSR page. **The criterion was the defect: `pnpm ls` enumerates versions ON DISK and the failure is module INSTANCES in a process.** One file reached down two paths is two instances, and no package manager can see it. `@voltro/i18n` now registers each of its evaluations with the identity of the react-intl it is bound to, and the diagnosis reports the counts and the paths from the process where the render failed. When it counts one of each, it says the framework is at fault instead of making that conditional on a check that could not come back false.
68
111
 
69
- `renderPageToHtml` / `renderPageToStream` take `search` now, and `voltro start` and `voltro dev` both pass it. `build.ts` deliberately does not: a static prerender has no request and one artefact serves every visitor, so `''` is the truthful value there rather than a missing wire and `ssrI18nParity.test.ts` encodes that difference, asserting the two per-request renderers pass it while leaving the prerender out on purpose.
112
+ The transferable half: an instruction to VERIFY has to be able to return false for the cause you are diagnosing. A check that cannot turns "I don't know" into "the framework is at fault", and the reader stops looking.
113
+ - **@voltro/plugin-webhooks** — **A webhook routing filter's operators were ANDed in the documentation and first-match-wins in the matcher, so the documented range OVER-matched.**
70
114
 
71
- **Scope, stated rather than assumed:** `useSearchParams()` was ALREADY correct on the server. It reads `requestContext.url`, which both per-request paths populate with the full request url including the query. So this fixes `RouterContext.search` exported, and readable by an app directly and does not on its own explain a mismatch in a page that reaches the query through that hook. Reported alongside the `useId` defect by the same consumer.
115
+ `{ gte: 100, lt: 1000 }` the second example on the plugin's docs page — evaluated `gte` and returned, ignoring `lt`. A `total` of 5000 satisfied a filter declared as 100–1000. That is the worse direction of wrong: an under-matching filter delivers nothing and gets noticed, an over-matching one posts a partner data their own filter says they must not receive, and nothing anywhere reports it. Every present operator must now hold, and an operator object with no recognised key (`{ gtE: 5 }`, `{}`) matches nothing rather than everything.
72
116
 
73
- ### Internal (no consumer-facing effect)
117
+ `gt` / `gte` / `lt` / `lte` have always been TYPED `number | string` and compared only when both sides were numbers — so a string bound type-checked, subscribed, stored and matched nothing, which reads exactly like an event that never fired. Strings now compare lexicographically, which is what makes `{ 'payload.at': { lt: '2026-01-01' } }` work on an ISO timestamp. Mixed types still match nothing, deliberately: `'10' < 9` depends on which side JavaScript converts.
74
118
 
75
- - **@voltro/database** `pendingAttribution`'s boundedness test no longer scores its property on the wall clock. It asserts that 12 000 registrations leave at most 10 000 entries and says nothing about how long 12 000 iterations take but under the default 5 s timeout it had quietly become an assertion about the machine as well, and went red inside a 24-task parallel run while the whole file finishes in 480 ms on its own. That is the "a test that measures the machine" producer recorded in `packages/cli/CLAUDE.md`, and the fix is to decouple the property from the clock (an explicit generous timeout) rather than to shrink the loop 12 000 is chosen to overrun the 10 000 cap, so a smaller burst would weaken the only thing under test. A non-vacuity assertion came with it: a cap of zero satisfies `<= 10 000` while proving nothing.
119
+ And the doc comment above the matcher called the equality form "v1" with operators as a future possibility, while `compareValue` implemented all six twenty lines below it. A consumer read that, refused a `resourceIds` filter for the whole life of the feature, and shipped a typed `ValidationError` telling their own users it was impossible. A comment describing an intention rather than the code under it is not a smaller doc it is a wrong one, and more expensive than none.
@@ -12,16 +12,16 @@
12
12
  "dependencies": {
13
13
  "@effect/platform": "^0.97.0",
14
14
  "@effect/rpc": "^0.76.0",
15
- "@voltro/ai": "0.30.1",
16
- "@voltro/cli": "0.30.1",
17
- "@voltro/database": "0.30.1",
18
- "@voltro/env": "0.30.1",
19
- "@voltro/protocol": "0.30.1",
20
- "@voltro/runtime": "0.30.1",
15
+ "@voltro/ai": "0.31.0",
16
+ "@voltro/cli": "0.31.0",
17
+ "@voltro/database": "0.31.0",
18
+ "@voltro/env": "0.31.0",
19
+ "@voltro/protocol": "0.31.0",
20
+ "@voltro/runtime": "0.31.0",
21
21
  "effect": "^3.22.0"
22
22
  },
23
23
  "devDependencies": {
24
- "@voltro/testing": "0.30.1",
24
+ "@voltro/testing": "0.31.0",
25
25
  "typescript": "^6.0.3",
26
26
  "vitest": "^4.1.10"
27
27
  }
@@ -13,17 +13,17 @@
13
13
  "dependencies": {
14
14
  "@effect/platform": "^0.97.0",
15
15
  "@effect/rpc": "^0.76.0",
16
- "@voltro/cli": "0.30.1",
17
- "@voltro/database": "0.30.1",
18
- "@voltro/env": "0.30.1",
19
- "@voltro/plugin-auth": "0.30.1",
20
- "@voltro/protocol": "0.30.1",
21
- "@voltro/runtime": "0.30.1",
22
- "@voltro/sql-postgres": "0.30.1",
16
+ "@voltro/cli": "0.31.0",
17
+ "@voltro/database": "0.31.0",
18
+ "@voltro/env": "0.31.0",
19
+ "@voltro/plugin-auth": "0.31.0",
20
+ "@voltro/protocol": "0.31.0",
21
+ "@voltro/runtime": "0.31.0",
22
+ "@voltro/sql-postgres": "0.31.0",
23
23
  "effect": "^3.22.0"
24
24
  },
25
25
  "devDependencies": {
26
- "@voltro/testing": "0.30.1",
26
+ "@voltro/testing": "0.31.0",
27
27
  "typescript": "^6.0.3",
28
28
  "vitest": "^4.1.10"
29
29
  }
@@ -13,16 +13,16 @@
13
13
  "dependencies": {
14
14
  "@effect/platform": "^0.97.0",
15
15
  "@effect/rpc": "^0.76.0",
16
- "@voltro/cli": "0.30.1",
17
- "@voltro/database": "0.30.1",
18
- "@voltro/env": "0.30.1",
19
- "@voltro/plugin-multitenancy": "0.30.1",
20
- "@voltro/protocol": "0.30.1",
21
- "@voltro/runtime": "0.30.1",
16
+ "@voltro/cli": "0.31.0",
17
+ "@voltro/database": "0.31.0",
18
+ "@voltro/env": "0.31.0",
19
+ "@voltro/plugin-multitenancy": "0.31.0",
20
+ "@voltro/protocol": "0.31.0",
21
+ "@voltro/runtime": "0.31.0",
22
22
  "effect": "^3.22.0"
23
23
  },
24
24
  "devDependencies": {
25
- "@voltro/testing": "0.30.1",
25
+ "@voltro/testing": "0.31.0",
26
26
  "typescript": "^6.0.3",
27
27
  "vitest": "^4.1.10"
28
28
  }
@@ -13,16 +13,16 @@
13
13
  "dependencies": {
14
14
  "@effect/platform": "^0.97.0",
15
15
  "@effect/rpc": "^0.76.0",
16
- "@voltro/cli": "0.30.1",
17
- "@voltro/database": "0.30.1",
18
- "@voltro/env": "0.30.1",
19
- "@voltro/plugin-deactivation": "0.30.1",
20
- "@voltro/protocol": "0.30.1",
21
- "@voltro/runtime": "0.30.1",
16
+ "@voltro/cli": "0.31.0",
17
+ "@voltro/database": "0.31.0",
18
+ "@voltro/env": "0.31.0",
19
+ "@voltro/plugin-deactivation": "0.31.0",
20
+ "@voltro/protocol": "0.31.0",
21
+ "@voltro/runtime": "0.31.0",
22
22
  "effect": "^3.22.0"
23
23
  },
24
24
  "devDependencies": {
25
- "@voltro/testing": "0.30.1",
25
+ "@voltro/testing": "0.31.0",
26
26
  "typescript": "^6.0.3",
27
27
  "vitest": "^4.1.10"
28
28
  }
@@ -13,18 +13,18 @@
13
13
  "dependencies": {
14
14
  "@react-email/components": "^1.0.12",
15
15
  "@react-email/render": "^1.4.0",
16
- "@voltro/cli": "0.30.1",
17
- "@voltro/database": "0.30.1",
18
- "@voltro/env": "0.30.1",
19
- "@voltro/plugin-mail": "0.30.1",
20
- "@voltro/plugin-multitenancy": "0.30.1",
21
- "@voltro/protocol": "0.30.1",
22
- "@voltro/runtime": "0.30.1",
16
+ "@voltro/cli": "0.31.0",
17
+ "@voltro/database": "0.31.0",
18
+ "@voltro/env": "0.31.0",
19
+ "@voltro/plugin-mail": "0.31.0",
20
+ "@voltro/plugin-multitenancy": "0.31.0",
21
+ "@voltro/protocol": "0.31.0",
22
+ "@voltro/runtime": "0.31.0",
23
23
  "effect": "^3.22.0",
24
24
  "react": "^19.0.0"
25
25
  },
26
26
  "devDependencies": {
27
- "@voltro/testing": "0.30.1",
27
+ "@voltro/testing": "0.31.0",
28
28
  "typescript": "^6.0.3",
29
29
  "vitest": "^4.1.10"
30
30
  }
@@ -13,18 +13,18 @@
13
13
  "dependencies": {
14
14
  "@effect/platform": "^0.97.0",
15
15
  "@effect/rpc": "^0.76.0",
16
- "@voltro/cli": "0.30.1",
17
- "@voltro/database": "0.30.1",
18
- "@voltro/env": "0.30.1",
19
- "@voltro/plugin-multitenancy": "0.30.1",
20
- "@voltro/plugin-storage": "0.30.1",
21
- "@voltro/protocol": "0.30.1",
22
- "@voltro/runtime": "0.30.1",
23
- "@voltro/sql-mysql": "0.30.1",
16
+ "@voltro/cli": "0.31.0",
17
+ "@voltro/database": "0.31.0",
18
+ "@voltro/env": "0.31.0",
19
+ "@voltro/plugin-multitenancy": "0.31.0",
20
+ "@voltro/plugin-storage": "0.31.0",
21
+ "@voltro/protocol": "0.31.0",
22
+ "@voltro/runtime": "0.31.0",
23
+ "@voltro/sql-mysql": "0.31.0",
24
24
  "effect": "^3.22.0"
25
25
  },
26
26
  "devDependencies": {
27
- "@voltro/testing": "0.30.1",
27
+ "@voltro/testing": "0.31.0",
28
28
  "typescript": "^6.0.3",
29
29
  "vitest": "^4.1.10"
30
30
  }
@@ -13,17 +13,17 @@
13
13
  "dependencies": {
14
14
  "@effect/platform": "^0.97.0",
15
15
  "@effect/rpc": "^0.76.0",
16
- "@voltro/cli": "0.30.1",
17
- "@voltro/database": "0.30.1",
18
- "@voltro/env": "0.30.1",
19
- "@voltro/plugin-multitenancy": "0.30.1",
20
- "@voltro/protocol": "0.30.1",
21
- "@voltro/runtime": "0.30.1",
22
- "@voltro/sql-sqlite": "0.30.1",
16
+ "@voltro/cli": "0.31.0",
17
+ "@voltro/database": "0.31.0",
18
+ "@voltro/env": "0.31.0",
19
+ "@voltro/plugin-multitenancy": "0.31.0",
20
+ "@voltro/protocol": "0.31.0",
21
+ "@voltro/runtime": "0.31.0",
22
+ "@voltro/sql-sqlite": "0.31.0",
23
23
  "effect": "^3.22.0"
24
24
  },
25
25
  "devDependencies": {
26
- "@voltro/testing": "0.30.1",
26
+ "@voltro/testing": "0.31.0",
27
27
  "typescript": "^6.0.3",
28
28
  "vitest": "^4.1.10"
29
29
  }
@@ -11,17 +11,17 @@
11
11
  "test": "voltro test"
12
12
  },
13
13
  "dependencies": {
14
- "@voltro/cli": "0.30.1",
15
- "@voltro/database": "0.30.1",
16
- "@voltro/env": "0.30.1",
17
- "@voltro/plugin-multitenancy": "0.30.1",
18
- "@voltro/plugin-storage": "0.30.1",
19
- "@voltro/protocol": "0.30.1",
20
- "@voltro/runtime": "0.30.1",
14
+ "@voltro/cli": "0.31.0",
15
+ "@voltro/database": "0.31.0",
16
+ "@voltro/env": "0.31.0",
17
+ "@voltro/plugin-multitenancy": "0.31.0",
18
+ "@voltro/plugin-storage": "0.31.0",
19
+ "@voltro/protocol": "0.31.0",
20
+ "@voltro/runtime": "0.31.0",
21
21
  "effect": "^3.22.0"
22
22
  },
23
23
  "devDependencies": {
24
- "@voltro/testing": "0.30.1",
24
+ "@voltro/testing": "0.31.0",
25
25
  "typescript": "^6.0.3",
26
26
  "vitest": "^4.1.10"
27
27
  }
@@ -13,19 +13,19 @@
13
13
  "dependencies": {
14
14
  "@effect/platform": "^0.97.0",
15
15
  "@effect/rpc": "^0.76.0",
16
- "@voltro/cli": "0.30.1",
17
- "@voltro/cms": "0.30.1",
18
- "@voltro/database": "0.30.1",
19
- "@voltro/env": "0.30.1",
20
- "@voltro/plugin-auth": "0.30.1",
21
- "@voltro/plugin-multitenancy": "0.30.1",
22
- "@voltro/protocol": "0.30.1",
23
- "@voltro/runtime": "0.30.1",
24
- "@voltro/sql-postgres": "0.30.1",
16
+ "@voltro/cli": "0.31.0",
17
+ "@voltro/cms": "0.31.0",
18
+ "@voltro/database": "0.31.0",
19
+ "@voltro/env": "0.31.0",
20
+ "@voltro/plugin-auth": "0.31.0",
21
+ "@voltro/plugin-multitenancy": "0.31.0",
22
+ "@voltro/protocol": "0.31.0",
23
+ "@voltro/runtime": "0.31.0",
24
+ "@voltro/sql-postgres": "0.31.0",
25
25
  "effect": "^3.22.0"
26
26
  },
27
27
  "devDependencies": {
28
- "@voltro/testing": "0.30.1",
28
+ "@voltro/testing": "0.31.0",
29
29
  "typescript": "^6.0.3",
30
30
  "vitest": "^4.1.10"
31
31
  }
@@ -13,17 +13,17 @@
13
13
  "dependencies": {
14
14
  "@effect/platform": "^0.97.0",
15
15
  "@effect/rpc": "^0.76.0",
16
- "@voltro/cli": "0.30.1",
17
- "@voltro/database": "0.30.1",
18
- "@voltro/env": "0.30.1",
19
- "@voltro/local-first": "0.30.1",
20
- "@voltro/plugin-multitenancy": "0.30.1",
21
- "@voltro/protocol": "0.30.1",
22
- "@voltro/runtime": "0.30.1",
16
+ "@voltro/cli": "0.31.0",
17
+ "@voltro/database": "0.31.0",
18
+ "@voltro/env": "0.31.0",
19
+ "@voltro/local-first": "0.31.0",
20
+ "@voltro/plugin-multitenancy": "0.31.0",
21
+ "@voltro/protocol": "0.31.0",
22
+ "@voltro/runtime": "0.31.0",
23
23
  "effect": "^3.22.0"
24
24
  },
25
25
  "devDependencies": {
26
- "@voltro/testing": "0.30.1",
26
+ "@voltro/testing": "0.31.0",
27
27
  "typescript": "^6.0.3",
28
28
  "vitest": "^4.1.10"
29
29
  }
@@ -12,17 +12,17 @@
12
12
  "dependencies": {
13
13
  "@effect/platform": "^0.97.0",
14
14
  "@effect/rpc": "^0.76.0",
15
- "@voltro/cli": "0.30.1",
16
- "@voltro/database": "0.30.1",
17
- "@voltro/env": "0.30.1",
18
- "@voltro/plugin-governance": "0.30.1",
19
- "@voltro/plugin-multitenancy": "0.30.1",
20
- "@voltro/protocol": "0.30.1",
21
- "@voltro/runtime": "0.30.1",
15
+ "@voltro/cli": "0.31.0",
16
+ "@voltro/database": "0.31.0",
17
+ "@voltro/env": "0.31.0",
18
+ "@voltro/plugin-governance": "0.31.0",
19
+ "@voltro/plugin-multitenancy": "0.31.0",
20
+ "@voltro/protocol": "0.31.0",
21
+ "@voltro/runtime": "0.31.0",
22
22
  "effect": "^3.22.0"
23
23
  },
24
24
  "devDependencies": {
25
- "@voltro/testing": "0.30.1",
25
+ "@voltro/testing": "0.31.0",
26
26
  "typescript": "^6.0.3",
27
27
  "vitest": "^4.1.10"
28
28
  }
@@ -12,17 +12,17 @@
12
12
  "dependencies": {
13
13
  "@effect/platform": "^0.97.0",
14
14
  "@effect/rpc": "^0.76.0",
15
- "@voltro/cli": "0.30.1",
16
- "@voltro/database": "0.30.1",
17
- "@voltro/env": "0.30.1",
18
- "@voltro/plugin-multitenancy": "0.30.1",
19
- "@voltro/protocol": "0.30.1",
20
- "@voltro/runtime": "0.30.1",
21
- "@voltro/workflow": "0.30.1",
15
+ "@voltro/cli": "0.31.0",
16
+ "@voltro/database": "0.31.0",
17
+ "@voltro/env": "0.31.0",
18
+ "@voltro/plugin-multitenancy": "0.31.0",
19
+ "@voltro/protocol": "0.31.0",
20
+ "@voltro/runtime": "0.31.0",
21
+ "@voltro/workflow": "0.31.0",
22
22
  "effect": "^3.22.0"
23
23
  },
24
24
  "devDependencies": {
25
- "@voltro/testing": "0.30.1",
25
+ "@voltro/testing": "0.31.0",
26
26
  "typescript": "^6.0.3",
27
27
  "vitest": "^4.1.10"
28
28
  }