@voltro/cli 0.47.0 → 0.49.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.
- package/CHANGELOG.md +147 -0
- package/dist/{apiBuild-FpHCWiv6.js → apiBuild-QmYHaCF4.js} +1 -1
- package/dist/apiBuild-dZbHdqMg.js +2 -0
- package/dist/bin.js +1 -1
- package/dist/{build-zVygXxGB.js → build-Bi4O_g7T.js} +6 -6
- package/dist/{checkCommand-D0dAKciE.js → checkCommand-D8vjQXQt.js} +3 -3
- package/dist/{checkCommand-B2Fw73lu.js → checkCommand-udbQpphy.js} +1 -1
- package/dist/{codegenCommand-BTtsnRus.js → codegenCommand-DApSH7hK.js} +39 -46
- package/dist/{codemodRunner-DSZjgyCL.js → codemodRunner-De1_316I.js} +562 -492
- package/dist/{commands-BrFKxnYW.js → commands-a5PxCaIg.js} +68 -60
- package/dist/{dashboardCommand-D9SjDc8E.js → dashboardCommand-DaoUUqJS.js} +1 -1
- package/dist/dataCommand-CJv_OMoS.js +1156 -0
- package/dist/dataProfile-Du3ztYxv.js +51 -0
- package/dist/{dbCommand-jbrmzwW_.js → dbCommand-Bf7Cy0mn.js} +5 -5
- package/dist/dbCommand-Bnl7MSGC.js +2 -0
- package/dist/declaredSchemaGates-BlcwObhb.js +25 -0
- package/dist/{dev-RjB7eE_B.js → dev-C31Nvlbv.js} +31 -30
- package/dist/{dev-CaIfZnw5.js → dev-DFVuzOj7.js} +1 -1
- package/dist/{doctorCommand-D7X29cw6.js → doctorCommand-B3uraeAe.js} +32 -14
- package/dist/doctorCommand-CPL6EhrW.js +2 -0
- package/dist/doctorDecidedSchema-BlbWgCD_.js +23 -0
- package/dist/{dormancyCommand-BGOP27fz.js → dormancyCommand-QUXQ9yoz.js} +1 -1
- package/dist/{embeddingsCommand-D72E22bw.js → embeddingsCommand-Zw1-rYSF.js} +1 -1
- package/dist/{envCommand-BHSxz6wC.js → envCommand-DtaJ4xEf.js} +1 -1
- package/dist/{evolveCommand-C2ofGGlz.js → evolveCommand-JDD3hE1i.js} +2 -2
- package/dist/{frameworkTableAssembly-BvZ0Lil_.js → frameworkTableAssembly-BwJVEKLr.js} +96 -119
- package/dist/frameworkTableAssembly-CVDB2hCq.js +2 -0
- package/dist/index.js +1 -1
- package/dist/{infoCommand-CuNl9cbh.js → infoCommand-COsUC1DB.js} +1 -1
- package/dist/{migrate-odCPGHPq.js → migrate-D3MK9BpK.js} +4 -4
- package/dist/{runtimeTrace-C_OKr0jY.js → runtimeTrace-Di6fcndp.js} +1 -1
- package/dist/{sdkgen-D9trW7sl.js → sdkgen-CIi5gM17.js} +1 -1
- package/dist/serveCommand-CzSDngKm.js +2 -0
- package/dist/serveCommand-N3udT49p.js +2362 -0
- package/dist/serveEntry.js +5 -5
- package/dist/{subcommandNames-CKG5Dz3a.js → subcommandNames-DpYs3DXr.js} +12 -2
- package/dist/{updateCommand-BlyXavoG.js → updateCommand-2BfbeMvp.js} +1 -1
- package/dist/updateCommand-CtYm7aKH.js +2 -0
- package/dist/{webhooksCommand-BqcWcbuW.js → webhooksCommand-CwX9IzvJ.js} +1 -1
- package/package.json +29 -17
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/cli.md +117 -4
- package/templates/agent-docs/database/migrations.md +19 -5
- package/templates/agent-docs/whats-new.md +51 -14
- package/templates/apps/api-ai/package.json +7 -7
- package/templates/apps/api-auth/package.json +8 -8
- package/templates/apps/api-backend/package.json +7 -7
- package/templates/apps/api-backend-deactivation/package.json +7 -7
- package/templates/apps/api-backend-mail/package.json +8 -8
- package/templates/apps/api-backend-mariadb/package.json +9 -9
- package/templates/apps/api-backend-sqlite/package.json +8 -8
- package/templates/apps/api-backend-storage/package.json +8 -8
- package/templates/apps/api-cms/package.json +10 -10
- package/templates/apps/api-collab/package.json +8 -8
- package/templates/apps/api-data-advanced/package.json +8 -8
- package/templates/apps/api-durable/package.json +8 -8
- package/templates/apps/api-feature-flags/package.json +9 -9
- package/templates/apps/api-governance/package.json +8 -8
- package/templates/apps/api-kv/package.json +8 -8
- package/templates/apps/api-moderation/package.json +8 -8
- package/templates/apps/api-observability/package.json +8 -8
- package/templates/apps/api-ratelimit/package.json +8 -8
- package/templates/apps/api-rbac/package.json +8 -8
- package/templates/apps/api-rest/package.json +7 -7
- package/templates/apps/api-saas/package.json +11 -11
- package/templates/apps/api-saas-starter/package.json +10 -10
- package/templates/apps/api-search/package.json +8 -8
- package/templates/apps/api-status/package.json +8 -8
- package/templates/apps/api-versioning/package.json +8 -8
- package/templates/apps/api-webhooks/package.json +9 -9
- package/templates/apps/changelog/package.json +6 -6
- package/templates/apps/edge-functions/package.json +2 -2
- package/templates/apps/frontend-admin/package.json +8 -8
- package/templates/apps/frontend-app/package.json +9 -9
- package/templates/apps/frontend-auth/package.json +8 -8
- package/templates/apps/frontend-blank/package.json +7 -7
- package/templates/apps/frontend-cms/package.json +9 -9
- package/templates/apps/frontend-collab/package.json +10 -10
- package/templates/apps/frontend-contact/package.json +7 -7
- package/templates/apps/frontend-dashboard/package.json +7 -7
- package/templates/apps/frontend-docs/package.json +7 -7
- package/templates/apps/frontend-i18n/package.json +6 -6
- package/templates/apps/frontend-landing/package.json +7 -7
- package/templates/apps/frontend-portal/package.json +8 -8
- package/templates/apps/frontend-saas/package.json +8 -8
- package/templates/apps/frontend-spa/package.json +7 -7
- package/templates/apps/frontend-ssr/package.json +7 -7
- package/templates/apps/frontend-ssr-api/package.json +8 -8
- package/templates/apps/frontend-static-blog/package.json +6 -6
- package/templates/apps/frontend-status/package.json +8 -8
- package/templates/apps/mobile-app/package.json +4 -4
- package/dist/apiBuild-BsooZpw2.js +0 -2
- package/dist/dataCommand-Dl11q14e.js +0 -975
- package/dist/dataProfile-Cm0YVKSy.js +0 -18
- package/dist/dbCommand-BUD4Fd8v.js +0 -2
- package/dist/doctorCommand-5zv6PN-G.js +0 -2
- package/dist/frameworkTableAssembly-DDKtwsy2.js +0 -2
- package/dist/serveCommand-BU0wfV6V.js +0 -1931
- package/dist/serveCommand-Bwrn_9Fn.js +0 -2
- package/dist/updateCommand-CT5AvVg7.js +0 -2
package/dist/serveEntry.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as e } from "./
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
export {
|
|
1
|
+
import { t as e } from "./serveCommand-N3udT49p.js";
|
|
2
|
+
import { t } from "./loadEnv-D9nEOClM.js";
|
|
3
|
+
import { r as n } from "./appModuleLoader-C9r9mxZt.js";
|
|
4
|
+
import { i as r } from "./dialectDriver-czCHYpeH.js";
|
|
5
|
+
export { t as loadDotEnv, n as registerAppModules, r as registerDriver, e as runServe };
|
|
@@ -19,9 +19,19 @@ var e = [
|
|
|
19
19
|
"scan-credentials",
|
|
20
20
|
"encrypt-column"
|
|
21
21
|
], t = [
|
|
22
|
+
"export",
|
|
23
|
+
"import",
|
|
24
|
+
"transfers",
|
|
25
|
+
"inspect",
|
|
26
|
+
"unpack",
|
|
27
|
+
"backup",
|
|
28
|
+
"restore",
|
|
29
|
+
"clear-replace-marker",
|
|
30
|
+
"clear-staging"
|
|
31
|
+
], n = [
|
|
22
32
|
"scope",
|
|
23
33
|
"export",
|
|
24
34
|
"erase"
|
|
25
|
-
],
|
|
35
|
+
], r = (e) => `<${e.join("|")}>`;
|
|
26
36
|
//#endregion
|
|
27
|
-
export {
|
|
37
|
+
export { r as i, e as n, n as r, t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as e, r as t, t as n } from "./codemodRunner-
|
|
1
|
+
import { n as e, r as t, t as n } from "./codemodRunner-De1_316I.js";
|
|
2
2
|
import { basename as r, dirname as i, join as a, relative as o, resolve as s } from "node:path";
|
|
3
3
|
import { existsSync as c, readFileSync as l, readdirSync as u, statSync as d, writeFileSync as f } from "node:fs";
|
|
4
4
|
import { totalmem as p } from "node:os";
|
|
@@ -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-
|
|
225
|
+
let { walk: t, loadDiscovered: n } = await import("./dev-DFVuzOj7.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.
|
|
3
|
+
"version": "0.49.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",
|
|
@@ -652,6 +652,18 @@
|
|
|
652
652
|
"title": "an aggregate’s `incremental.source` is typechecked against the app’s tables",
|
|
653
653
|
"kind": "manual"
|
|
654
654
|
},
|
|
655
|
+
{
|
|
656
|
+
"version": "0.49.0",
|
|
657
|
+
"id": "0.49.0/01_data-imports-to-transfers",
|
|
658
|
+
"title": "`voltro data imports` → `voltro data transfers`",
|
|
659
|
+
"kind": "manual"
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
"version": "0.49.0",
|
|
663
|
+
"id": "0.49.0/02_import-run-symbols",
|
|
664
|
+
"title": "`ImportRun` / `describeImportRun` / `IMPORT_RUNS_TABLE` → their `…TransferRun` names",
|
|
665
|
+
"kind": "transform"
|
|
666
|
+
},
|
|
655
667
|
{
|
|
656
668
|
"version": "0.5.0",
|
|
657
669
|
"id": "0.5.0/01_one-terminal-exactly-one",
|
|
@@ -739,22 +751,22 @@
|
|
|
739
751
|
"@effect/platform-node": "^0.108.0",
|
|
740
752
|
"@effect/sql": "^0.52.0",
|
|
741
753
|
"@effect/workflow": "^0.19.0",
|
|
742
|
-
"@voltro/ai": "0.
|
|
743
|
-
"@voltro/cache": "0.
|
|
744
|
-
"@voltro/data-transfer": "0.
|
|
745
|
-
"@voltro/database": "0.
|
|
746
|
-
"@voltro/env": "0.
|
|
747
|
-
"@voltro/kv": "0.
|
|
748
|
-
"@voltro/logger": "0.
|
|
749
|
-
"@voltro/plugin-auth": "0.
|
|
750
|
-
"@voltro/plugin-broadcast": "0.
|
|
751
|
-
"@voltro/plugin-mail": "0.
|
|
752
|
-
"@voltro/plugin-storage": "0.
|
|
753
|
-
"@voltro/plugin-webhooks": "0.
|
|
754
|
-
"@voltro/protocol": "0.
|
|
755
|
-
"@voltro/runtime": "0.
|
|
756
|
-
"@voltro/serverless": "0.
|
|
757
|
-
"@voltro/workflow": "0.
|
|
754
|
+
"@voltro/ai": "0.49.0",
|
|
755
|
+
"@voltro/cache": "0.49.0",
|
|
756
|
+
"@voltro/data-transfer": "0.49.0",
|
|
757
|
+
"@voltro/database": "0.49.0",
|
|
758
|
+
"@voltro/env": "0.49.0",
|
|
759
|
+
"@voltro/kv": "0.49.0",
|
|
760
|
+
"@voltro/logger": "0.49.0",
|
|
761
|
+
"@voltro/plugin-auth": "0.49.0",
|
|
762
|
+
"@voltro/plugin-broadcast": "0.49.0",
|
|
763
|
+
"@voltro/plugin-mail": "0.49.0",
|
|
764
|
+
"@voltro/plugin-storage": "0.49.0",
|
|
765
|
+
"@voltro/plugin-webhooks": "0.49.0",
|
|
766
|
+
"@voltro/protocol": "0.49.0",
|
|
767
|
+
"@voltro/runtime": "0.49.0",
|
|
768
|
+
"@voltro/serverless": "0.49.0",
|
|
769
|
+
"@voltro/workflow": "0.49.0",
|
|
758
770
|
"chokidar": "^5.0.0",
|
|
759
771
|
"ioredis": "^5.11.1",
|
|
760
772
|
"tinyglobby": "^0.2.17",
|
package/templates/AGENTS.md
CHANGED
|
@@ -707,7 +707,7 @@ each plugin's own README.
|
|
|
707
707
|
|
|
708
708
|
| Topic | Open | Summary |
|
|
709
709
|
|---|---|---|
|
|
710
|
-
| **What's new in 0.
|
|
710
|
+
| **What's new in 0.49.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. |
|
|
711
711
|
| 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. |
|
|
712
712
|
| 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. |
|
|
713
713
|
| 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.
|
|
12
|
+
| **What's new in 0.49.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. |
|
|
@@ -2613,11 +2613,13 @@ Rows are written as newline-delimited JSON — streamable, resumable by line, an
|
|
|
2613
2613
|
| *(none)* | Every table the app has DATA in (the default) — see the note below on the handful that describe a deployment rather than filling it. |
|
|
2614
2614
|
| `--tenant <id>` | Every `tenant()`-scoped table filtered to that tenant, **plus** the FK closure in BOTH directions: (1) the transitive **FK-parent** closure of those rows — closure-pulled shared tables (a global `users` / reference table) are **row-subset to the ids the tenant's rows actually reference**, never exported in full; and (2) the **child** closure — rows that *reference* the tenant's rows (the comments on the tenant's projects) come along too, each scoped to the ids that actually point into the tenant set. The child walk is anchored on the `tenant()` tables, so a row that references **only a shared parent** (a global `users` another tenant also references) is **not** pulled — that would be a cross-tenant leak. A `--tenant` bundle therefore carries the tenant's parents AND children and **no other tenant's rows** — that's what makes it safe as a GDPR / per-tenant takeout. |
|
|
2615
2615
|
| `--tables a,b` | An explicit set (you own referential integrity; the importer's deferred-FK resolution covers load-order dangles, see below). |
|
|
2616
|
-
| `--exclude a,b` | Everything EXCEPT these
|
|
2616
|
+
| `--exclude a,b` | Everything EXCEPT these. The scope stays `all` and records what was left out — so the deployment-describing tables are still filtered, and `replace` still accepts the bundle. Works on both targets (the instance resolves it against its own live list). Cannot be combined with `--tables` or `--tenant`; a name that does not exist is refused, because an exclusion that excludes nothing leaves the run looking like it worked. |
|
|
2617
2617
|
|
|
2618
2618
|
#### What `all` deliberately leaves out
|
|
2619
2619
|
|
|
2620
|
-
A
|
|
2620
|
+
A number of framework tables hold rows **about a deployment** rather than an app's data. The test is: would a row from elsewhere make this target *act* — send, run, admit, refuse, skip a delivery — or assert something untrue about its own history? That covers its migration ledger, file-migration and seed records, CDC offsets and change log, schedule claims, wakeups and firing history, workflow watermarks / pending starts / admissions / pauses / delivered events, its outbox and delivery attempts, its idempotency keys, its storage grants, its spend and usage accounting, and its own traces and undo log. They are dropped from `all`, skipped on import, and never emptied by a `replace`, and the run says which ones and why.
|
|
2621
|
+
|
|
2622
|
+
Every framework table is classified one way or the other, and a new one fails the build until somebody decides — the classification used to live in two places, the module and a hand-kept copy in its test, and the two disagreed about exactly the tables that later caused trouble.
|
|
2621
2623
|
|
|
2622
2624
|
The reason is worth one paragraph, because it cost a real environment ninety minutes. A `scope: all` bundle carried `_voltro_migration_plans`, `replace` wrote it, and the target's next boot refused:
|
|
2623
2625
|
|
|
@@ -2625,7 +2627,7 @@ The reason is worth one paragraph, because it cost a real environment ninety min
|
|
|
2625
2627
|
auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=6e2c61081a9ed80c live=28af9a54414f22f1
|
|
2626
2628
|
```
|
|
2627
2629
|
|
|
2628
|
-
The refusal was right. That fingerprint is computed over the **declared table set**,
|
|
2630
|
+
The refusal was right. That fingerprint is computed over the **declared table set**, so the imported row was not out of date, it was **foreign**: it stated a schema decision made somewhere else. (The declared set could also differ per environment then, because `NODE_ENV` decided two of the tables. It no longer does — but that removes one *way* for two deployments to differ, not the reason a foreign ledger row is wrong.) Two of the others would have made the target *act* — a pending workflow start runs a workflow somebody queued elsewhere, a pause silently stops one here.
|
|
2629
2631
|
|
|
2630
2632
|
`all` is the only scope filtered. **Name one of these in `--tables` and you get it** — an explicit name is an expectation, and this command refuses to drop those silently.
|
|
2631
2633
|
|
|
@@ -2883,7 +2885,7 @@ recorder is for. Every suspended run says so, and the suspension is scoped to th
|
|
|
2883
2885
|
run rather than the process, so requests served alongside it keep recording.
|
|
2884
2886
|
|
|
2885
2887
|
Instead of per-row history, the operation records **itself**. One row in
|
|
2886
|
-
`
|
|
2888
|
+
`_voltro_data_transfers` per run — in either direction: the mode, the transport, the bundle, the source
|
|
2887
2889
|
deployment's schema fingerprint, the counts — and the failure, for the run you
|
|
2888
2890
|
are usually looking for. A trail that only records successes goes quiet exactly
|
|
2889
2891
|
when it is needed.
|
|
@@ -2893,6 +2895,117 @@ interlock and a run which cannot write it must not proceed, while this is
|
|
|
2893
2895
|
history. A target whose schema is not migrated yet still imports, and says the
|
|
2894
2896
|
trace could not be written.
|
|
2895
2897
|
|
|
2898
|
+
### Every request fits a budget
|
|
2899
|
+
|
|
2900
|
+
Some environments cap a single request: a job runner that kills a client after
|
|
2901
|
+
ten minutes, an ingress with a 30-second ceiling, a CI step with a deadline. A
|
|
2902
|
+
whole transfer may still take an hour — it just has to do so as a series of short
|
|
2903
|
+
requests, each individually abandonable and individually retryable.
|
|
2904
|
+
|
|
2905
|
+
The rule the endpoints follow:
|
|
2906
|
+
|
|
2907
|
+
> **A request that carries bytes never runs a transfer. A request that starts a
|
|
2908
|
+
> transfer never carries bytes.**
|
|
2909
|
+
|
|
2910
|
+
```bash
|
|
2911
|
+
# Nothing here may take longer than 30 seconds per request.
|
|
2912
|
+
voltro data import ./bundle --target api --api-url https://app.example \
|
|
2913
|
+
--mode replace --max-request-seconds 30
|
|
2914
|
+
|
|
2915
|
+
# Or: start it and walk away. The outcome is NOT known when this returns.
|
|
2916
|
+
voltro data import ./bundle --target api --api-url https://app.example --detach
|
|
2917
|
+
```
|
|
2918
|
+
|
|
2919
|
+
Both staging areas — the uploaded bundle on its way in, the produced one on its
|
|
2920
|
+
way out — sit in the system temp directory by default and move with
|
|
2921
|
+
`VOLTRO_IMPORT_UPLOAD_DIR` / `VOLTRO_EXPORT_ARTIFACT_DIR`. Worth setting on a
|
|
2922
|
+
container: a bundle is the size your database is, and a default `/tmp` is
|
|
2923
|
+
frequently a small tmpfs.
|
|
2924
|
+
|
|
2925
|
+
`--max-request-seconds` is DECLARED rather than probed. The thing that kills a
|
|
2926
|
+
request is a policy on your side, and only you know it — in the one environment
|
|
2927
|
+
this was measured against, the ingress would happily hold a connection for an
|
|
2928
|
+
hour and the caller's own toolchain killed the client at ten minutes.
|
|
2929
|
+
|
|
2930
|
+
**An import is three steps.** The bundle goes up (in 16 MiB chunks when it is
|
|
2931
|
+
big, resumable, one plain request when it is small); `import/start` begins the
|
|
2932
|
+
run and answers as soon as the run is recorded; then the client watches the
|
|
2933
|
+
record. `start` is idempotent — retrying it under a budget returns the run that
|
|
2934
|
+
is already going rather than beginning a second destructive one.
|
|
2935
|
+
|
|
2936
|
+
**An export is three steps too.** Ask, wait for the record, then fetch the bytes
|
|
2937
|
+
in ranges from `GET /_voltro/admin/export/download`. The archive used to arrive
|
|
2938
|
+
in the response body, which made the request last as long as reading your whole
|
|
2939
|
+
database.
|
|
2940
|
+
|
|
2941
|
+
**`--detach` returns once the run has started** and says so plainly: exit `0`
|
|
2942
|
+
there means "it started", not "it worked". Attached, the exit code comes from the
|
|
2943
|
+
run's record — `0` finished, `1` failed, `2` still going when you stopped
|
|
2944
|
+
watching. Ctrl-C loses the watching and never the run.
|
|
2945
|
+
|
|
2946
|
+
### Watching a transfer you cannot see
|
|
2947
|
+
|
|
2948
|
+
Over `--target api` the run happens INSIDE the instance. Everything it decides
|
|
2949
|
+
— whether it stages, whether recorders are suspended, how far it has got — is
|
|
2950
|
+
printed in the pod's log, and someone reaching for `--target api` is by
|
|
2951
|
+
construction someone who cannot reach the database directly and usually cannot
|
|
2952
|
+
read that log either. The run is also deliberately decoupled from the caller:
|
|
2953
|
+
killing the client does not stop it, which is what keeps a dead client from
|
|
2954
|
+
leaving a half-emptied target. Both properties are right, and together they used
|
|
2955
|
+
to mean an operator could neither see the run nor learn how it ended.
|
|
2956
|
+
|
|
2957
|
+
Two things close that, and neither is a streamed response on the upload
|
|
2958
|
+
connection. That connection is the thing an operator is most likely to lose: a
|
|
2959
|
+
client killed by a job timeout while the import runs on inside the instance is
|
|
2960
|
+
the ordinary case, and a stream would go quiet at exactly the moment somebody
|
|
2961
|
+
needs to know what happened. A poll can be run from a different machine than
|
|
2962
|
+
the one that started the import.
|
|
2963
|
+
|
|
2964
|
+
**Ask before you upload.** A `replace` over the api asks the instance what it is
|
|
2965
|
+
going to do, before a byte of the bundle goes up. The instance answers from the
|
|
2966
|
+
same function the run itself calls, so the answer cannot drift from the run:
|
|
2967
|
+
|
|
2968
|
+
```
|
|
2969
|
+
$ voltro data import ./bundle --target api --api-url https://app.example --mode replace
|
|
2970
|
+
api replace: the instance WILL stage — 104 table(s) load into copies and the
|
|
2971
|
+
target keeps its rows until one short swap at the end. Interrupting the load leaves the target intact.
|
|
2972
|
+
importing — 41200 row(s) across 18 table(s) (staged; the target still holds its own rows)
|
|
2973
|
+
done — 228866 row(s) across 104 table(s)
|
|
2974
|
+
```
|
|
2975
|
+
|
|
2976
|
+
With `--bundle-key` the client never holds the bundle, so it sends the key and
|
|
2977
|
+
the instance reads the table list out of the archive itself — the caller about to
|
|
2978
|
+
have an instance empty its own database is the last one who should be told to
|
|
2979
|
+
check a log they cannot read.
|
|
2980
|
+
|
|
2981
|
+
If it will not stage, the line says so and names the reason — a bundle table the
|
|
2982
|
+
target does not have, a foreign-key cycle, a dialect this build cannot stage on.
|
|
2983
|
+
That is the difference between "interrupting this is safe" and "interrupting
|
|
2984
|
+
this empties the target", which is exactly the decision an operator is making
|
|
2985
|
+
while they watch.
|
|
2986
|
+
|
|
2987
|
+
**Read the run from anywhere.** `_voltro_data_transfers` carries one row per run
|
|
2988
|
+
in EITHER direction: opened before the first table, advanced every couple of
|
|
2989
|
+
seconds as tables land, closed with the outcome — so polling it IS the progress
|
|
2990
|
+
feed:
|
|
2991
|
+
|
|
2992
|
+
```
|
|
2993
|
+
$ voltro data transfers --target api --api-url https://app.example
|
|
2994
|
+
1 import(s) IN FLIGHT — re-run this to watch the counters move
|
|
2995
|
+
2026-08-23T09:04:01.000Z · replace — started and never reported finishing · via api · staged (target untouched until the swap) · from /tmp/b
|
|
2996
|
+
2026-08-23T08:00:00.000Z · export all — 228866 row(s) across 104 table(s) · via api · from backups/nightly.vbundle
|
|
2997
|
+
```
|
|
2998
|
+
|
|
2999
|
+
Same data over `GET /_voltro/admin/imports?limit=20`, behind the same
|
|
3000
|
+
data-transfer secret (the row names bundles and schema fingerprints). It works
|
|
3001
|
+
from a different machine than the one that started the import, and through
|
|
3002
|
+
anything that forwards a GET.
|
|
3003
|
+
|
|
3004
|
+
The `staged` part is a separate claim from the preflight's, and both are needed.
|
|
3005
|
+
The preflight says what the instance WILL do; this says what it did. Without it
|
|
3006
|
+
the two could only be closed by reading the pod's log, which is the one place a
|
|
3007
|
+
`--target api` caller cannot reach.
|
|
3008
|
+
|
|
2896
3009
|
### An interrupted `replace` cannot be silent
|
|
2897
3010
|
|
|
2898
3011
|
The capture only helps if somebody knows to reach for it. A half-replaced database is indistinguishable from an empty one **from the inside** — every table exists, every constraint holds, every query returns nothing without erroring — so a run that emptied a target and disappeared can be served over for hours before anyone asks the right question.
|
|
@@ -3179,14 +3179,28 @@ flag flipped alone:
|
|
|
3179
3179
|
|
|
3180
3180
|
**From 0.35.0 none of them does.** `_voltro_cdc_offsets` follows the DIALECT, so
|
|
3181
3181
|
a mariadb/mssql app declares it either way; the other two are declared in
|
|
3182
|
-
`app.config.ts` and the env vars only choose what a process captures
|
|
3182
|
+
`app.config.ts` and the env vars only choose what a process captures.
|
|
3183
|
+
|
|
3184
|
+
**And from 0.48.0 `NODE_ENV` does not either.** Until then, `_voltro_traces` and
|
|
3185
|
+
`_voltro_undo_log` defaulted to on outside production — safe for the
|
|
3186
|
+
fingerprint, which only ever compares processes inside ONE deployment, and
|
|
3187
|
+
unsafe for the reader that spans two. `voltro data` is that reader: a bundle
|
|
3188
|
+
exported from a development database carries the tables that database has, and
|
|
3189
|
+
a staged (non-destructive) `replace` needs every bundle table to exist in the
|
|
3190
|
+
target. One source tree therefore produced a bundle a production target could
|
|
3191
|
+
not stage, and the run fell back to truncating it — with nothing red anywhere.
|
|
3192
|
+
|
|
3193
|
+
Both are declared in every environment now. An unused declared table is an empty
|
|
3194
|
+
table; a schema that differs per environment is a class of failure. Declare them
|
|
3195
|
+
only to leave one OUT:
|
|
3183
3196
|
|
|
3184
3197
|
```ts
|
|
3185
3198
|
export default {
|
|
3186
|
-
//
|
|
3187
|
-
//
|
|
3188
|
-
//
|
|
3189
|
-
|
|
3199
|
+
// Declared in EVERY environment by default. Set `false` to keep a table out —
|
|
3200
|
+
// and then set it in every environment, or two deployments of one source tree
|
|
3201
|
+
// declare different schemas again. `VOLTRO_UNDO` / `VOLTRO_TRACING_PERSIST`
|
|
3202
|
+
// still decide what a process WRITES; they no longer decide what exists.
|
|
3203
|
+
schema: { undo: false, traces: false },
|
|
3190
3204
|
}
|
|
3191
3205
|
```
|
|
3192
3206
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# What's new in 0.
|
|
1
|
+
# What's new in 0.49.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,28 +7,65 @@ 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
|
-
###
|
|
10
|
+
### ⚠ BREAKING
|
|
11
11
|
|
|
12
|
-
- **@voltro/
|
|
12
|
+
- **@voltro/cli, @voltro/data-transfer, @voltro/database, @voltro/sql-sqlite, @voltro/voltro** — A data transfer is a series of short requests now — no single one may outlive a caller's budget.
|
|
13
13
|
|
|
14
|
-
**
|
|
14
|
+
**The rule:** *a request that carries bytes never runs a transfer; a request that starts a transfer never carries bytes.* It was broken in the worst available place. The upload was already chunked and resumable — many short requests, each abandonable — and then the FINAL chunk fell through and ran the whole import. So the longest request of the flow arrived AFTER the entire upload had succeeded, and a caller under a policy that caps a single request (a job runner that kills a client at ten minutes; a 30 s ingress ceiling) lost the most expensive thing they had already paid for. A single-request upload had the same shape without the excuse, and the export had no protocol at all: one request that read the whole database and streamed it back.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
**Import.** `POST /_voltro/admin/import` accumulates and answers `202`. `POST /_voltro/admin/import/start` begins the run and answers `202 { runId }` as soon as the run's first row exists. `start` is idempotent per upload — it is a short request and therefore a retryable one, and without a claim a retry would begin a second destructive run from the same bytes. A claim whose run has ENDED is taken over rather than honoured forever, so a process that dies holding one cannot poison a bundle.
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
**Export.** `POST /_voltro/admin/export` answers `202 { runId }` and produces in the background; the bytes come back from `GET /_voltro/admin/export/download?runId=&offset=&length=` in ranges, resumable, with the total in a header. Object storage (`--bundle-key`) remains for a bundle you want to KEEP — it is no longer the only way to get one out, because requiring it would leave an instance without storage unable to export at all.
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
**The client.** `--max-request-seconds` (or `VOLTRO_MAX_REQUEST_SECONDS`) declares the budget — declared rather than probed, because the thing that kills a request is a policy on the caller's side and only they know it. `--detach` returns once the run has started and says the outcome is NOT known. Attached, the CLI polls the record and prints per-table progress; Ctrl-C then loses the watching and never the run.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
**The trap, stated because it is the one way to get this wrong:** a failure used to arrive in the response (409 on drift, 409 on a refused mode, 500 otherwise). After the split the response is a `202`, so **a client deriving its exit code from the status line reports a failed import as a success.** The exit code comes from the polled record, in one shared function, and the drift check moved into `start` where it can still be a refusal that leaves no history.
|
|
23
23
|
|
|
24
|
-
**
|
|
24
|
+
**Two knobs that were constants.** `VOLTRO_IMPORT_UPLOAD_DIR` and `VOLTRO_EXPORT_ARTIFACT_DIR` move the staging areas off the default temp filesystem — which on a container is frequently a small tmpfs, so an instance simply could not accept a bundle the size a grown database produces, and the failure arrived as a write error halfway through an upload somebody had been waiting on.
|
|
25
25
|
|
|
26
|
-
**
|
|
26
|
+
**Renamed:** `voltro data imports` → `voltro data transfers`, and `_voltro_data_imports` → `_voltro_data_transfers` with a `direction` column. The command showed one direction and now shows both; the table rename carries its rows via the declarative differ on every dialect and needs nothing from you. The CLI rename ships a `manual` codemod — the command lives in scripts, CI jobs and runbooks, which `voltro update` cannot see or rewrite. The four PUBLIC exports that named the same record were renamed with it (`ImportRun`, `describeImportRun`, `IMPORT_RUNS_TABLE`, `_voltroImportRunsTable`); those are application source, they ship their own `transform` codemod, and they have their own entry.
|
|
27
|
+
- **@voltro/database, @voltro/voltro** — The run-history exports say `transfer`, not `import`.
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
`@voltro/database` (and `voltro/database`) renamed four public exports along with the table behind them:
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
| was | is | |---|---| | `ImportRun` | `DataTransferRun` | | `describeImportRun` | `describeTransferRun` | | `IMPORT_RUNS_TABLE` | `DATA_TRANSFERS_TABLE` | | `_voltroImportRunsTable` | `_voltroDataTransfersTable` |
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
An EXPORT writes to this record now — the row carries a `direction` — so every one of those names described half of what it holds.
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
A `transform` codemod rewrites all four, alias-aware, from either module spelling. It also rewrites a hand-spelled `_voltro_data_imports` in a string, template or raw-SQL fragment, and that is the half worth stating: the four identifiers announce themselves as compile errors, while a query that addresses the table by name has nothing to fail on. The table itself moves with its rows via the declarative differ on every dialect.
|
|
36
|
+
|
|
37
|
+
This is filed apart from the transfer-protocol entry beside it deliberately. That one's codemod is `manual` and is about a CLI invocation living in scripts and CI jobs; this one is application source and is rewritten for you. Reading the first as covering both is what would leave a build broken with a note saying nothing in your source was affected.
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- **@voltro/database, @voltro/data-transfer, @voltro/cli** — An import records WHETHER it staged, and a soft-dropped column says so in a drift refusal.
|
|
42
|
+
|
|
43
|
+
**`_voltro_data_imports.staged`.** The pre-upload preflight says what the instance WILL do; the run's own line says what it did — and that line is printed inside the instance, which is exactly where an operator using `--target api` cannot read it. So "we were told it would stage" and "it staged" were two claims with no way to close the gap between them from outside. The column is `null` for a mode where the question does not arise; `voltro data imports` and `GET /_voltro/admin/imports` both carry it.
|
|
44
|
+
|
|
45
|
+
**A soft-dropped column is named as one.** `<original>__dropped_<stamp>` is what the differ leaves behind when an app stops declaring a column — only the database that did the drop has it, so it drifts against every target. The refusal reported it as an ordinary missing column ("the value has nowhere to go"), which points at the TARGET's schema: the one place the fix does not lie. It now says where the column lives and how to reclaim it.
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- **@voltro/data-transfer, @voltro/sql-sqlite, @voltro/database** — A successful `--mode replace --no-atomic` left a marker that refused the next boot.
|
|
50
|
+
|
|
51
|
+
Two defects, one visible symptom, and both were silent by construction.
|
|
52
|
+
|
|
53
|
+
**The clear was gated on the WRITE's condition.** `!(useLedger && ledger.truncated)` means "an earlier attempt already recorded this destructive run, do not write a second row" — correct on the write. Copied down to the clear its meaning inverts: `ledger.truncated` is set by the emptying step of THIS run, so on `--no-atomic` (the only mode where `useLedger` is true) the clear was skipped by the very run that wrote the marker.
|
|
54
|
+
|
|
55
|
+
**And a `Date` in a predicate is not bindable on sqlite.** `better-sqlite3` binds numbers, strings, bigints, buffers and null; the row path has coerced Dates since that store was written, and the eager-join compiler carried its own private copy of the fix, but `query` / `updateMany` / `deleteMany` bound the raw value. So every comparison of a timestamp column against a `Date` failed with `Failed to execute statement` — including the marker's clear, which swallows its errors ON PURPOSE (a store with no marker table must not fail an import over a bookkeeping row) and therefore said nothing. The retention sweep compares `lt(column, cutoff)` the same way.
|
|
56
|
+
|
|
57
|
+
Together: a fully successful replace left the marker standing, and the next boot REFUSED with "a destructive import did not finish" over a database that was completely fine. The one recovery is a command the operator has no reason to think they need. It stayed invisible because `atomic` defaults to true for `replace`, and because a staged replace writes no marker at all — two defaults hiding the one mode that exists for large, interruptible loads.
|
|
58
|
+
|
|
59
|
+
The coercion is shared now and applied at all three predicate sites, with a guard that fails on a fourth that forgets. A dry run also closes its trace row: a preview that finished instantly used to leave the record open, so a polling caller waited out its whole budget over a run that was long done.
|
|
60
|
+
- **@voltro/cli** — `voltro codegen` declared twenty framework tables fewer than a boot.
|
|
61
|
+
|
|
62
|
+
The app half of this was fixed last release and looked like the whole thing. It was not: `codegen` derived the FEATURE MIX from the file list it had just walked, and that list is the entity/relations set — which contains no `*.workflow.tsx`, no `*.agent.ts`, no `*.cron.tsx`. So every feature flag came back false, and the dialect was never passed at all, taking `_voltro_cdc_offsets` with it. Measured on an app with two workflow files: 18 framework tables where the shared assembly produces 33.
|
|
63
|
+
|
|
64
|
+
It calls `assembleFrameworkTables({ root })` now — the same entry `voltro db plan/apply` uses, which detects the mix from the root rather than being handed one.
|
|
65
|
+
|
|
66
|
+
The parity guard moved with it. Comparing the two WALKS could not see this: both walks were right about files, and the divergence was introduced one layer past them. It compares the assembled SETS now, and runs codegen's own table function on a tree whose only feature signals are a workflow file and an agent file — a source assertion that the right function is CALLED cannot see a wrong argument handed to it, and a wrong argument is what this was.
|
|
67
|
+
- **@voltro/cli** — `voltro data --help` advertised four subcommands out of nine.
|
|
68
|
+
|
|
69
|
+
It printed `<export|import|backup|restore>` while the command dispatched those four plus `imports`, `inspect`, `unpack`, `clear-replace-marker` and `clear-staging`. A quoted enumeration is read as exhaustive — the same failure `subcommandNames.ts` was written for after a `db` list cost two wrong conclusions — and the missing entry here is the one that answers "what is my import doing right now" for somebody who cannot reach the pod.
|
|
70
|
+
|
|
71
|
+
`subcommandHelpParity.test.ts` had listed `data` among the commands it could not check, loudly and correctly: there was no name list to check against. There is one now (`DATA_SUBCOMMANDS`), the dispatch is a keyed `Record`, so a subcommand with no name and a name with no handler are both compile errors, and the usage line is generated from the same array. `data` is out of the unchecked list.
|
|
@@ -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.
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/database": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/protocol": "0.
|
|
20
|
-
"@voltro/runtime": "0.
|
|
15
|
+
"@voltro/ai": "0.49.0",
|
|
16
|
+
"@voltro/cli": "0.49.0",
|
|
17
|
+
"@voltro/database": "0.49.0",
|
|
18
|
+
"@voltro/env": "0.49.0",
|
|
19
|
+
"@voltro/protocol": "0.49.0",
|
|
20
|
+
"@voltro/runtime": "0.49.0",
|
|
21
21
|
"effect": "^3.22.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@voltro/testing": "0.
|
|
24
|
+
"@voltro/testing": "0.49.0",
|
|
25
25
|
"typescript": "^6.0.3",
|
|
26
26
|
"@vitest/coverage-v8": "^4.1.10",
|
|
27
27
|
"vitest": "^4.1.10"
|
|
@@ -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.
|
|
17
|
-
"@voltro/database": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/plugin-auth": "0.
|
|
20
|
-
"@voltro/protocol": "0.
|
|
21
|
-
"@voltro/runtime": "0.
|
|
22
|
-
"@voltro/sql-postgres": "0.
|
|
16
|
+
"@voltro/cli": "0.49.0",
|
|
17
|
+
"@voltro/database": "0.49.0",
|
|
18
|
+
"@voltro/env": "0.49.0",
|
|
19
|
+
"@voltro/plugin-auth": "0.49.0",
|
|
20
|
+
"@voltro/protocol": "0.49.0",
|
|
21
|
+
"@voltro/runtime": "0.49.0",
|
|
22
|
+
"@voltro/sql-postgres": "0.49.0",
|
|
23
23
|
"effect": "^3.22.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@voltro/testing": "0.
|
|
26
|
+
"@voltro/testing": "0.49.0",
|
|
27
27
|
"typescript": "^6.0.3",
|
|
28
28
|
"@vitest/coverage-v8": "^4.1.10",
|
|
29
29
|
"vitest": "^4.1.10"
|
|
@@ -16,16 +16,16 @@
|
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@effect/platform": "^0.97.0",
|
|
18
18
|
"@effect/rpc": "^0.76.0",
|
|
19
|
-
"@voltro/cli": "0.
|
|
20
|
-
"@voltro/database": "0.
|
|
21
|
-
"@voltro/env": "0.
|
|
22
|
-
"@voltro/plugin-multitenancy": "0.
|
|
23
|
-
"@voltro/protocol": "0.
|
|
24
|
-
"@voltro/runtime": "0.
|
|
19
|
+
"@voltro/cli": "0.49.0",
|
|
20
|
+
"@voltro/database": "0.49.0",
|
|
21
|
+
"@voltro/env": "0.49.0",
|
|
22
|
+
"@voltro/plugin-multitenancy": "0.49.0",
|
|
23
|
+
"@voltro/protocol": "0.49.0",
|
|
24
|
+
"@voltro/runtime": "0.49.0",
|
|
25
25
|
"effect": "^3.22.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@voltro/testing": "0.
|
|
28
|
+
"@voltro/testing": "0.49.0",
|
|
29
29
|
"typescript": "^6.0.3",
|
|
30
30
|
"@vitest/coverage-v8": "^4.1.10",
|
|
31
31
|
"vitest": "^4.1.10"
|
|
@@ -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.
|
|
17
|
-
"@voltro/database": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/plugin-deactivation": "0.
|
|
20
|
-
"@voltro/protocol": "0.
|
|
21
|
-
"@voltro/runtime": "0.
|
|
16
|
+
"@voltro/cli": "0.49.0",
|
|
17
|
+
"@voltro/database": "0.49.0",
|
|
18
|
+
"@voltro/env": "0.49.0",
|
|
19
|
+
"@voltro/plugin-deactivation": "0.49.0",
|
|
20
|
+
"@voltro/protocol": "0.49.0",
|
|
21
|
+
"@voltro/runtime": "0.49.0",
|
|
22
22
|
"effect": "^3.22.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@voltro/testing": "0.
|
|
25
|
+
"@voltro/testing": "0.49.0",
|
|
26
26
|
"typescript": "^6.0.3",
|
|
27
27
|
"@vitest/coverage-v8": "^4.1.10",
|
|
28
28
|
"vitest": "^4.1.10"
|
|
@@ -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.
|
|
17
|
-
"@voltro/database": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/plugin-mail": "0.
|
|
20
|
-
"@voltro/plugin-multitenancy": "0.
|
|
21
|
-
"@voltro/protocol": "0.
|
|
22
|
-
"@voltro/runtime": "0.
|
|
16
|
+
"@voltro/cli": "0.49.0",
|
|
17
|
+
"@voltro/database": "0.49.0",
|
|
18
|
+
"@voltro/env": "0.49.0",
|
|
19
|
+
"@voltro/plugin-mail": "0.49.0",
|
|
20
|
+
"@voltro/plugin-multitenancy": "0.49.0",
|
|
21
|
+
"@voltro/protocol": "0.49.0",
|
|
22
|
+
"@voltro/runtime": "0.49.0",
|
|
23
23
|
"effect": "^3.22.0",
|
|
24
24
|
"react": "^19.0.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@voltro/testing": "0.
|
|
27
|
+
"@voltro/testing": "0.49.0",
|
|
28
28
|
"typescript": "^6.0.3",
|
|
29
29
|
"@vitest/coverage-v8": "^4.1.10",
|
|
30
30
|
"vitest": "^4.1.10"
|