@voltro/cli 0.43.0 → 0.43.2
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 +100 -0
- package/dist/{apiBuild-DF0f69Gf.js → apiBuild-BWuw8ZXS.js} +1 -1
- package/dist/apiBuild-Cw2-TEXW.js +2 -0
- package/dist/bin.js +1 -1
- package/dist/{build-LC_IJaHL.js → build-CGBs4ZOv.js} +6 -6
- package/dist/{checkCommand-DDxwJCja.js → checkCommand-BFtFBsqL.js} +2 -2
- package/dist/{checkCommand-DBpTSK8d.js → checkCommand-lTPSN3EQ.js} +1 -1
- package/dist/{codegenCommand-LjxfK4Am.js → codegenCommand-BJeyFlip.js} +1 -1
- package/dist/{commands-CbQcuWsE.js → commands-pEDOcOo2.js} +15 -15
- package/dist/{dashboardCommand-CAHjCe_9.js → dashboardCommand-Bt2hHMro.js} +1 -1
- package/dist/{dataCommand-CrqvbVOv.js → dataCommand-DD2bRHCu.js} +377 -208
- package/dist/{dev-D0E5x2Ue.js → dev-DMx-MF2s.js} +1 -1
- package/dist/{dev-B2rZfqxw.js → dev-wumUfDm1.js} +922 -912
- package/dist/doctorCommand-FOXTTaGp.js +2 -0
- package/dist/{doctorCommand-Ct_3BHgd.js → doctorCommand-RFKpnLih.js} +9 -9
- package/dist/{dormancyCommand-D1DKnYce.js → dormancyCommand-EFDQWiUw.js} +1 -1
- package/dist/{embeddingsCommand-1sZRBKlM.js → embeddingsCommand-OeYp3qSq.js} +1 -1
- package/dist/{envCommand-7qjlQgLD.js → envCommand-CKgBZK7x.js} +1 -1
- package/dist/{evolveCommand-D5opB48I.js → evolveCommand-ClQlAH0j.js} +1 -1
- package/dist/index.js +1 -1
- package/dist/{runtimeTrace-Wmi7V-wN.js → runtimeTrace-CgpAD9wL.js} +1 -1
- package/dist/{sdkgen-DbTFGCjg.js → sdkgen-Ca2zj4cd.js} +1 -1
- package/dist/{serveCommand-C8xzYCwa.js → serveCommand-CgK7Kj6j.js} +472 -368
- package/dist/serveCommand-DUm2-ikx.js +2 -0
- package/dist/serveEntry.js +1 -1
- package/dist/{webhooksCommand-BXUP5YjW.js → webhooksCommand-BVNtNsI0.js} +1 -1
- package/package.json +17 -17
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/cli.md +126 -2
- package/templates/agent-docs/database/seedsdialects.md +12 -0
- package/templates/agent-docs/whats-new.md +14 -74
- 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-B7NgSMhX.js +0 -2
- package/dist/doctorCommand-CdsctSwg.js +0 -2
- package/dist/serveCommand-CGNTXafv.js +0 -2
package/dist/serveEntry.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as e } from "./loadEnv-D9nEOClM.js";
|
|
2
2
|
import { r as t } from "./appModuleLoader-C9r9mxZt.js";
|
|
3
3
|
import { i as n } from "./dialectDriver-czCHYpeH.js";
|
|
4
|
-
import { t as r } from "./serveCommand-
|
|
4
|
+
import { t as r } from "./serveCommand-CgK7Kj6j.js";
|
|
5
5
|
export { e as loadDotEnv, t as registerAppModules, n as registerDriver, r as runServe };
|
|
@@ -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-DMx-MF2s.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.43.
|
|
3
|
+
"version": "0.43.2",
|
|
4
4
|
"description": "The `voltro` CLI — dev server, codegen, migrations, project scaffolding, agent-docs seeding, and production serve.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -721,22 +721,22 @@
|
|
|
721
721
|
"@effect/platform-node": "^0.108.0",
|
|
722
722
|
"@effect/sql": "^0.52.0",
|
|
723
723
|
"@effect/workflow": "^0.19.0",
|
|
724
|
-
"@voltro/ai": "0.43.
|
|
725
|
-
"@voltro/cache": "0.43.
|
|
726
|
-
"@voltro/data-transfer": "0.43.
|
|
727
|
-
"@voltro/database": "0.43.
|
|
728
|
-
"@voltro/env": "0.43.
|
|
729
|
-
"@voltro/kv": "0.43.
|
|
730
|
-
"@voltro/logger": "0.43.
|
|
731
|
-
"@voltro/plugin-auth": "0.43.
|
|
732
|
-
"@voltro/plugin-broadcast": "0.43.
|
|
733
|
-
"@voltro/plugin-mail": "0.43.
|
|
734
|
-
"@voltro/plugin-storage": "0.43.
|
|
735
|
-
"@voltro/plugin-webhooks": "0.43.
|
|
736
|
-
"@voltro/protocol": "0.43.
|
|
737
|
-
"@voltro/runtime": "0.43.
|
|
738
|
-
"@voltro/serverless": "0.43.
|
|
739
|
-
"@voltro/workflow": "0.43.
|
|
724
|
+
"@voltro/ai": "0.43.2",
|
|
725
|
+
"@voltro/cache": "0.43.2",
|
|
726
|
+
"@voltro/data-transfer": "0.43.2",
|
|
727
|
+
"@voltro/database": "0.43.2",
|
|
728
|
+
"@voltro/env": "0.43.2",
|
|
729
|
+
"@voltro/kv": "0.43.2",
|
|
730
|
+
"@voltro/logger": "0.43.2",
|
|
731
|
+
"@voltro/plugin-auth": "0.43.2",
|
|
732
|
+
"@voltro/plugin-broadcast": "0.43.2",
|
|
733
|
+
"@voltro/plugin-mail": "0.43.2",
|
|
734
|
+
"@voltro/plugin-storage": "0.43.2",
|
|
735
|
+
"@voltro/plugin-webhooks": "0.43.2",
|
|
736
|
+
"@voltro/protocol": "0.43.2",
|
|
737
|
+
"@voltro/runtime": "0.43.2",
|
|
738
|
+
"@voltro/serverless": "0.43.2",
|
|
739
|
+
"@voltro/workflow": "0.43.2",
|
|
740
740
|
"chokidar": "^5.0.0",
|
|
741
741
|
"ioredis": "^5.11.1",
|
|
742
742
|
"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.43.
|
|
710
|
+
| **What's new in 0.43.2** | `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.43.
|
|
12
|
+
| **What's new in 0.43.2** | `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. |
|
|
@@ -2643,6 +2643,29 @@ over-read is worse than no preview.
|
|
|
2643
2643
|
what it does — a silently-ignored table name is how a run scoped to one table writes the
|
|
2644
2644
|
whole bundle.
|
|
2645
2645
|
|
|
2646
|
+
### Every `import` option, in one place
|
|
2647
|
+
|
|
2648
|
+
| Option | Default | What it does |
|
|
2649
|
+
|---|---|---|
|
|
2650
|
+
| `--mode upsert\|append\|replace` | `upsert` | How rows are written. See the table below. |
|
|
2651
|
+
| `--on-conflict skip\|fail` | `skip` | `append` only: what to do when the primary key already exists. |
|
|
2652
|
+
| `--atomic` | off | Wrap the whole table phase in ONE transaction — live readers see the import all-or-nothing. The live-safe `replace`. |
|
|
2653
|
+
| `--tables a,b` | every table | Import only these tables from the bundle. |
|
|
2654
|
+
| `--dry-run` | off | Run every pre-flight and report what WOULD move; write nothing. |
|
|
2655
|
+
| `--force` | off | Proceed despite schema drift AND cross-dialect warnings. |
|
|
2656
|
+
| `--no-verify` | off | Skip per-table checksum verification (direct target only). |
|
|
2657
|
+
| `--allow-live` | off | Override the refusal to write directly into a database a live instance is serving (direct target only). |
|
|
2658
|
+
| `--assets` | off | Restore blobs as well as rows. |
|
|
2659
|
+
| `--passphrase <s>` | — | Decrypt an `--encrypt`ed bundle (direct target only; over the api the CLI decrypts before sending). |
|
|
2660
|
+
| `--target direct\|api` | `direct` | Write straight to the database, or through a running instance's admin endpoint. |
|
|
2661
|
+
| `--api-url <url>` / `--token <secret>` | — | Required by `--target api`. The token must equal the instance's data-transfer secret. |
|
|
2662
|
+
| `--bundle-key <key>` | — | `--target api`: have the instance PULL the archive from object storage instead of uploading it. |
|
|
2663
|
+
| `--chunk-size <mb>` | 16 | `--target api`: bytes per upload chunk. Chunking engages automatically above one chunk. |
|
|
2664
|
+
| `--timeout <seconds>` | none | `--target api`: give up waiting for the instance. Default is to wait as long as the import takes. |
|
|
2665
|
+
| `--json` | off | Machine-readable result. |
|
|
2666
|
+
|
|
2667
|
+
A flag this subcommand does not read is refused, not ignored — see below.
|
|
2668
|
+
|
|
2646
2669
|
### A flag this command does not read is an ERROR
|
|
2647
2670
|
|
|
2648
2671
|
Every `voltro data` subcommand declares the flags it reads, per target, and refuses anything
|
|
@@ -2729,9 +2752,63 @@ Anything still unresolvable — the parent row exists in **neither the bundle no
|
|
|
2729
2752
|
|---|---|---|---|
|
|
2730
2753
|
| `upsert` (default) | INSERT-or-UPDATE by primary key | sync / idempotent re-import | overwrites per row |
|
|
2731
2754
|
| `append` | INSERT only | additive data (event log, new seed) | `--on-conflict skip` (default) or `fail` |
|
|
2732
|
-
| `replace` |
|
|
2755
|
+
| `replace` | empty the target tables, then INSERT | full refresh — target ends up **exactly** the bundle | — |
|
|
2756
|
+
|
|
2757
|
+
`replace` **refuses a partial bundle** (a subset / tenant / table scope): emptying would delete rows the bundle never carried. Re-export with full scope, or use `upsert`. (`append --on-conflict fail` throws on a duplicate primary key only where the store enforces the constraint — every SQL dialect does; the in-memory dev store overwrites.)
|
|
2758
|
+
|
|
2759
|
+
#### How `replace` empties the target, and what it refuses
|
|
2760
|
+
|
|
2761
|
+
The bundle's tables are emptied **as one unit, in one transaction, with referential integrity suspended for the duration** — not table by table. Both halves matter:
|
|
2762
|
+
|
|
2763
|
+
- **All or nothing.** A run that cannot finish leaves the target exactly as it found it. Emptying table by table and stopping at the first refusal leaves the target in neither state — and makes a second attempt destroy *more* than the first.
|
|
2764
|
+
- **No ordering can replace the suspension.** MySQL, MariaDB and SQL Server check a foreign key as each *row* is deleted, so a table that references **itself** cannot be emptied at all by ordering tables — the conflict is between two rows of one of them. `createdBy → actors` on the `actors` table is exactly that shape, and it is what an audit mixin on an actor table produces. (Postgres needs no suspension: a multi-table `TRUNCATE` covers the whole set at once.)
|
|
2765
|
+
|
|
2766
|
+
What it will **not** do is reach outside the bundle. If a table the bundle does **not** carry holds rows that reference one it does, `replace` refuses **before deleting anything** and names them:
|
|
2767
|
+
|
|
2768
|
+
```
|
|
2769
|
+
replace cannot empty this target: 1 table(s) OUTSIDE the bundle hold rows that reference
|
|
2770
|
+
tables INSIDE it. Emptying the bundle's tables would leave those rows pointing at nothing,
|
|
2771
|
+
and the bundle cannot restore them.
|
|
2772
|
+
webhookDeliveries (4021 rows): createdBy → actors, updatedBy → actors
|
|
2773
|
+
Nothing has been deleted. Either re-export with a scope that includes those tables, or use
|
|
2774
|
+
--mode upsert if those rows are meant to survive.
|
|
2775
|
+
```
|
|
2776
|
+
|
|
2777
|
+
An **empty** table outside the bundle blocks nothing — a schema always carries tables an environment has never written to.
|
|
2778
|
+
|
|
2779
|
+
One consequence of emptying in bulk: the delete itself emits **no change events** (one per row is not affordable at bundle scale). Over `--target api` that is covered — an import through the instance's own process asks every live subscription to re-read once it lands, the same coarse refresh the framework uses after a broadcast gap. Over `--target direct` there is no live instance to tell, which is the whole reason that path is guarded.
|
|
2780
|
+
|
|
2781
|
+
#### Which mode for which job
|
|
2782
|
+
|
|
2783
|
+
| You want | Mode | Why |
|
|
2784
|
+
|---|---|---|
|
|
2785
|
+
| Keep a staging database in step with a production export, re-runnable | `upsert` | Idempotent per row: run it as often as you like, the result is the same. |
|
|
2786
|
+
| Add an event log / new seed data without touching what is there | `append --on-conflict skip` | Insert-only, and a row that already exists is left alone rather than overwritten. |
|
|
2787
|
+
| Catch a duplicate instead of silently skipping it | `append --on-conflict fail` | The import stops and names the row. Use when a duplicate means the bundle is wrong. |
|
|
2788
|
+
| Make a target become **exactly** a bundle — replace an environment | `replace` (full-scope bundle) | Empties the bundle's tables first, so rows the bundle does not carry are gone. |
|
|
2789
|
+
| The same, against a database that is being served right now | `replace --atomic` | One transaction: readers see the old state until commit, the new one after. Never a half-loaded table. |
|
|
2790
|
+
| The same, against a live instance, honouring app invariants | `replace --target api` | Runs in the instance's process: validation, mixins, field encryption, hooks, and live subscriptions re-read afterwards. |
|
|
2791
|
+
|
|
2792
|
+
Two things `replace` will refuse, both before writing anything: a **partial bundle** (subset / tenant / table scope), because emptying would delete rows the bundle never carried; and a target where a table **outside** the bundle holds rows referencing one inside it, because those rows cannot be put back. Both refusals name what to do instead.
|
|
2793
|
+
|
|
2794
|
+
#### Recipe: replace a dev environment from your local database
|
|
2795
|
+
|
|
2796
|
+
```sh
|
|
2797
|
+
# 1. Full-scope export of the source, locally.
|
|
2798
|
+
voltro data export ./dev-refresh
|
|
2799
|
+
|
|
2800
|
+
# 2. Preview against the target first — every pre-flight runs, nothing is written.
|
|
2801
|
+
voltro data import ./dev-refresh --target api \
|
|
2802
|
+
--api-url https://dev.example --token "$VOLTRO_DATA_TRANSFER_SECRET" \
|
|
2803
|
+
--mode replace --dry-run
|
|
2804
|
+
|
|
2805
|
+
# 3. Do it. A big bundle chunks itself; a failed run can be re-run and resumes.
|
|
2806
|
+
voltro data import ./dev-refresh --target api \
|
|
2807
|
+
--api-url https://dev.example --token "$VOLTRO_DATA_TRANSFER_SECRET" \
|
|
2808
|
+
--mode replace --atomic
|
|
2809
|
+
```
|
|
2733
2810
|
|
|
2734
|
-
|
|
2811
|
+
If step 3 dies halfway — a dropped connection, a laptop closing — run **exactly the same command again**. The upload continues where it stopped, and the import is a single all-or-nothing step, so the target is either the old state or the new one.
|
|
2735
2812
|
|
|
2736
2813
|
### Importing into a LIVE instance
|
|
2737
2814
|
|
|
@@ -2753,6 +2830,49 @@ A plain import connects **straight to the database** (not through the running ap
|
|
|
2753
2830
|
- **Secret gate, constant-time.** Every request must present that secret as a **Bearer token** (`Authorization: Bearer <secret>`), compared in constant time over SHA-256 digests (neither length nor content leaks via timing). The gate is a framework-owned secret **independent of app RBAC** — enabling data transfer can never accidentally ride on a user role. The CLI sends it via `--token` / `VOLTRO_DATA_TRANSFER_SECRET` (it must equal the server's secret). Wrong/absent token → `401`.
|
|
2754
2831
|
- **One secret, both directions.** The same secret gates export (read) and import (write). If you need to grant export without import (e.g. a backup job that must never overwrite), split it into a per-operation credential deliberately — the default is one credential for the whole surface.
|
|
2755
2832
|
|
|
2833
|
+
#### A big bundle goes up in chunks, and resumes (`--chunk-size`)
|
|
2834
|
+
|
|
2835
|
+
A bundle bigger than one chunk is uploaded as a **series of short requests** instead of one long one, and the switch is automatic: the packer's stream is buffered one chunk ahead, so a bundle that fits inside that buffer is sent exactly as before — one request, no protocol — and a bigger one chunks itself. **You never have to know in advance which table is the big one.**
|
|
2836
|
+
|
|
2837
|
+
Each chunk is its own request, so a proxy body cap or an ingress read timeout has nothing large to choke on. The **import still runs once**, at the end, over the whole bundle — same modes, same deferred-FK repair, same all-or-nothing emptying. Only the transport changes.
|
|
2838
|
+
|
|
2839
|
+
**Resume is real.** The upload id is derived from the bundle itself, so re-running the same command after a failure asks the instance how far it got and continues from there:
|
|
2840
|
+
|
|
2841
|
+
```
|
|
2842
|
+
api import: resuming a chunked upload the instance already holds { bytes: 50331648 }
|
|
2843
|
+
api import: uploaded in chunks { chunks: 7, bytes: 62914560, resumedFrom: 50331648 }
|
|
2844
|
+
```
|
|
2845
|
+
|
|
2846
|
+
That is safe because `packBundle` over a bundle directory is byte-identical across runs, and because each chunk carries the bundle's **key** (the hash of its manifest). Uploading a *different* bundle under the same id is refused rather than spliced into the partial one, and a chunk that does not start exactly where the instance left off is refused with the offset it does expect.
|
|
2847
|
+
|
|
2848
|
+
`--chunk-size <mb>` overrides the default of 16 MiB. Unfinished uploads are discarded by the instance after 24 hours.
|
|
2849
|
+
|
|
2850
|
+
##### The chunk protocol, for when you are reading proxy logs
|
|
2851
|
+
|
|
2852
|
+
Worth knowing if an ingress sits in the way, because these requests are what it will show you. All of them are `POST` to the same `/_voltro/admin/import` path, gated by the same Bearer secret:
|
|
2853
|
+
|
|
2854
|
+
| Request | Headers | Answer |
|
|
2855
|
+
|---|---|---|
|
|
2856
|
+
| probe | `x-import-upload-id`, `x-import-probe: 1`, empty body | `200 {uploadId, bytes}` — how much the instance already holds |
|
|
2857
|
+
| chunk | `x-import-upload-id`, `x-import-upload-key`, `x-import-chunk-offset` | `202 {uploadId, bytes}` — accepted, nothing imported yet |
|
|
2858
|
+
| final chunk | the same plus `x-import-chunk-final: 1` | `200` with the import's own result — this is the long one |
|
|
2859
|
+
|
|
2860
|
+
A `409` means the instance refused the chunk and says which of three things happened: `offset-mismatch` (with the `expectedOffset` to continue from), `key-mismatch` (a different bundle under this upload id — use a new id), or `bad-id`. None of them is retryable by simply repeating the request, which is why each one names the fix.
|
|
2861
|
+
|
|
2862
|
+
Only the FINAL request runs the import, so only that one is long. If it is the request your proxy times out on, that is the one to raise `proxy_read_timeout` for — or use `--bundle-key` and have the instance pull the archive from object storage instead of receiving it.
|
|
2863
|
+
|
|
2864
|
+
#### How long an `--target api` call may take (`--timeout`)
|
|
2865
|
+
|
|
2866
|
+
Both api-target calls **wait as long as the instance needs**. There is no default deadline, and that is deliberate: the response arrives only when the *import* (or export) has finished, so any fixed bound is really a bound on the size of your database. A full bundle of a grown database routinely takes longer than five minutes to apply.
|
|
2867
|
+
|
|
2868
|
+
Pass `--timeout <seconds>` when you want one. If it is hit, the message says what it means — the upload finished long ago and **the instance is very probably still importing**:
|
|
2869
|
+
|
|
2870
|
+
```
|
|
2871
|
+
voltro data import ./out --target api --api-url https://api.example --token $SECRET --timeout 900
|
|
2872
|
+
```
|
|
2873
|
+
|
|
2874
|
+
Note the asymmetry when a deadline *is* hit: re-running an `upsert` after the first run has finished is safe (it is idempotent); re-running a **`replace`** while the first is still mid-flight would empty the target under it. Check the instance's log before deciding — the message says so too.
|
|
2875
|
+
|
|
2756
2876
|
**Import** (`POST /_voltro/admin/import`) applies a bundle **in the instance's own process** through its store — full app pipeline (validation, mixins, **field encryption**, hooks) AND automatic reactivity. Two transports, neither needs a server-readable path:
|
|
2757
2877
|
- **upload** (default) — the CLI **packs the bundle and uploads the bytes**; the server unpacks to its own temp dir, imports in-process, cleans up. Buffered → small/moderate bundles.
|
|
2758
2878
|
- **storage-pull** (`--bundle-key <key>`) — the CLI sends only `{ "bundleKey": "<key>" }`; the instance **streams that archive from its configured object storage** (S3 / Azure / MinIO / filesystem, resolved from the storage env — `STORAGE_PROVIDER`, `S3_*`, `AZURE_*`, …), no body buffering → arbitrarily large bundles.
|
|
@@ -3128,6 +3248,10 @@ flag is the one-off override.
|
|
|
3128
3248
|
| GDPR / per-tenant takeout | `voltro data export --tenant <id> --assets` |
|
|
3129
3249
|
| A small self-consistent slice of the data | `voltro data export --profile <env>` with a `subset` |
|
|
3130
3250
|
| Move Postgres → MySQL | `voltro data export` then `import` (cross-dialect lint applies) |
|
|
3251
|
+
| Replace a dev/staging environment with your local state | `voltro data import <dir> --target api --mode replace --atomic` |
|
|
3252
|
+
| Seed a fresh cluster through the running app (invariants + encryption) | `voltro data import <dir> --target api` (default `upsert`) |
|
|
3253
|
+
| Move a bundle too big for one request | nothing extra — the upload chunks itself; `--chunk-size` only if you need a different size |
|
|
3254
|
+
| Resume an upload that died | re-run the identical command |
|
|
3131
3255
|
|
|
3132
3256
|
|
|
3133
3257
|
|
|
@@ -1004,6 +1004,18 @@ The usual cause on MariaDB is a **UNIQUE constraint on an unbounded text column*
|
|
|
1004
1004
|
|
|
1005
1005
|
The reader finds such tables when CDC starts, reports each once, and **excludes** it — so there is no reconnect loop. Cross-instance change events for that table are lost; own-node reactivity is unaffected, because writes still emit inline.
|
|
1006
1006
|
|
|
1007
|
+
**How long that verdict lasts.** It is a reading of the schema at the moment the reader attached, and applying the remedy does not lift it by itself. `voltro dev` builds its store before it migrates — kv, cross-replica broadcast and the analytics mirror all need one — so on a boot whose own migration bounds the column, the finding is a second older than the fix. That boot therefore **re-checks the exclusion set once all its schema work is done and re-admits the table in the same run**:
|
|
1008
|
+
|
|
1009
|
+
```
|
|
1010
|
+
cdc: table 'sessions' looks undecodable … Not a verdict yet; the definitive line follows.
|
|
1011
|
+
auto-migrate: applied 74 op(s) in 1157ms
|
|
1012
|
+
cdc: table 'sessions' re-admitted to binlog capture — the hidden-column condition is gone.
|
|
1013
|
+
```
|
|
1014
|
+
|
|
1015
|
+
The re-check runs in both directions: schema work that *creates* an unbounded unique on a captured table excludes it there and then, rather than after the reader has failed on three writes.
|
|
1016
|
+
|
|
1017
|
+
`voltro serve` has no equivalent step and needs none — it builds its store *after* every schema step and never applies DDL itself, so its reading at attach is already the final one. Everywhere else the exclusion holds until the process restarts.
|
|
1018
|
+
|
|
1007
1019
|
**The remedy is to bound the column:**
|
|
1008
1020
|
|
|
1009
1021
|
```ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# What's new in 0.43.
|
|
1
|
+
# What's new in 0.43.2
|
|
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,89 +7,29 @@ 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
|
-
### ⚠ BREAKING
|
|
11
|
-
|
|
12
|
-
- **@voltro/data-transfer, @voltro/cli** — `DanglingReferenceError` is now `RowsRefusedError`, and it separates the rows that failed from the rows that failed because those rows did.
|
|
13
|
-
|
|
14
|
-
**The name.** The import raised it for EVERY row still refused after deferred-FK resolution, whatever the reason — a NOT NULL violation, a duplicate key, a value the database computes for itself. The tag named ONE possible cause and put it where a reader looks first, so any other refusal arrived mislabelled. The new name states the outcome; each row's `reason` states the cause, which is where a cause can honestly be claimed.
|
|
15
|
-
|
|
16
|
-
**The split.** A row is `derived` when one of its reference columns holds the primary key of another row that also failed in this run: it could not have landed whatever it contained, so its reason describes the parent's problem. The relation is transitive, decided from the DATA (the failed ids against the reference-typed values), so no schema knowledge is needed. `primaryCount` is the number an operator acts on, `rows` lists primary failures FIRST so the cap never spends its budget on consequences, and the CLI leads with both numbers:
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
import refused 300 row(s), of which 1 are the actual failures — the rest could
|
|
20
|
-
not land because a row they reference did not.
|
|
21
|
-
teams t1 foreign key teams_ibfk_1: the referenced row does not exist [1452]
|
|
22
|
-
… and 299 row(s) behind them. Fix the 1 above and re-run; they resolve with
|
|
23
|
-
their parents.
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
In an FK-dense bundle one refused parent takes its whole subtree with it, so the length of a flat list says how connected the data is, not how many problems there are — and the single row that explains all of them sits somewhere in the middle of it.
|
|
27
|
-
|
|
28
|
-
The codemod rewrites the import and every use of the symbol. It does NOT rewrite a tag STRING (`Effect.catchTag('DanglingReferenceError', …)`, `err._tag === '…'`) — change those to `'RowsRefusedError'` — and the payload gained `primaryCount` plus a `derived` flag per row.
|
|
29
|
-
|
|
30
10
|
### Fixed
|
|
31
11
|
|
|
32
|
-
- **@voltro/cli** —
|
|
33
|
-
|
|
34
|
-
Every form of access decision the framework has — `internal: true`, `guards: [...]`, `openAccess:` — is declared on the DESCRIPTOR. So an app that declares them properly got a finding for each one, and on a codebase whose procedures are mostly `internal: true` the rule fires on essentially all of them and is wrong essentially every time.
|
|
35
|
-
|
|
36
|
-
That is worse than a rule that finds nothing: it is the longest line in the report and it reads like a security finding, so it teaches the reader to skim the place a real finding would have appeared.
|
|
37
|
-
|
|
38
|
-
The premise was structurally impossible for most of them, and the framework says so itself: `security.defaultDeny` refuses at boot any wire-exposed procedure declaring neither `guards:` nor `openAccess:`. So "an anonymous caller reaches the write" can only be true of an `openAccess` procedure. That is what the rule looks for now — plus the handler check it always honoured, plus an ownership comparison against `subject.id`, which is the refusal the rule says is missing. Where no descriptor can be read, it says nothing: the claim is about a declaration, and a finding whose evidence was never opened is the failure mode this fixes.
|
|
39
|
-
|
|
40
|
-
The `use:` line changed with it. It recommended `.guard(requireScope('…'))`; the shipped guide teaches declarative `guards:` and calls a hand-written per-executor scope check the thing `guards:` exists to delete. A rule may not recommend the shape the guide argues against.
|
|
41
|
-
- **@voltro/database, @voltro/data-transfer** — A `voltro data` transfer no longer carries GENERATED column values, and no longer loses every row that has one.
|
|
42
|
-
|
|
43
|
-
The export wrote the computed values into the bundle and the import sent them back in the `INSERT` column list. MariaDB refuses that for any value except NULL (`1906: The value specified for generated column 'x' in table 't' has been ignored`); postgres refuses a non-DEFAULT value outright. So the transfer failed per ROW, not per table, and only for the rows whose generated value was non-NULL.
|
|
44
|
-
|
|
45
|
-
That selectivity is the dangerous part. `.uniqueActive()` lowers to exactly such a column on mysql/mariadb — a STORED generated column holding the key while the row is live and NULL once it is soft-deleted — so the refused rows are the LIVE ones and the accepted ones are the tombstones. A table can come out looking like "a few rows failed" or empty, depending only on how many of its rows are deleted, and any table with a foreign key into it fails behind it.
|
|
46
|
-
|
|
47
|
-
Both ends are fixed from one source of truth: **introspection now reports generated columns on every dialect** (`generatedAs`, from `information_schema.generation_expression` on mysql/mariadb, `is_generated` on postgres, `PRAGMA table_xinfo`'s hidden flag on sqlite, `sys.computed_columns` on mssql). It was declared-side only before — invisible to the planner, which does not compare it, and load-bearing for anything that writes rows back.
|
|
48
|
-
|
|
49
|
-
The exporter omits those columns, values and all. The importer strips them from every incoming row using the TARGET's snapshot, because a bundle already written still carries them and a file on disk is data, read where it is.
|
|
50
|
-
|
|
51
|
-
**`voltro serve`'s admin export/import needed a second fix, and without it this one reached only the direct transport.** The running instance hands those handlers `declaredSnapshot(tables)` — no dialect — and `.uniqueActive()` lowers to a generated column only when the snapshot knows the engine. So over `--target api` the snapshot described a schema with no generated columns while the database had several, and the export wrote their values back into the bundle exactly as before. It passes the dialect now (the variable was already on the next line).
|
|
52
|
-
|
|
53
|
-
`generatedAs` is also kept OUT of the schema fingerprint. Introspection can read the fact back but not a comparable value — the engine returns its own normalisation of the expression, never the declared spelling — so hashing it would make declared and live disagree permanently: a schema nobody touched reporting a changed declaration on every boot, and a transfer target that matches its bundle exactly refused as drifted.
|
|
54
|
-
|
|
55
|
-
Covered by a live mariadb→mariadb and mysql→mysql round trip over a `.uniqueActive()` table with live and soft-deleted rows, asserting the target recomputed the value rather than that the row merely arrived.
|
|
56
|
-
- **@voltro/sql-mysql** — On mysql/mariadb, a write REJECTED by the database through `insertIgnore` was reported as a conflict when the caller was not inside a transaction — and never reached the caller as a typed `ConstraintViolation` at all.
|
|
57
|
-
|
|
58
|
-
Two causes, both measured against live MySQL 8.4 and MariaDB 11.
|
|
59
|
-
|
|
60
|
-
**The connection.** `INSERT IGNORE` demotes every error to a warning, so the store reads `SHOW WARNINGS` to tell a rejection from a conflict. That describes the last statement on a CONNECTION, and outside a transaction every statement acquires its own from the pool — so the read was unattributable and came back empty. The rejected write then surfaced as "the insert was skipped as a conflict, but no existing row matches conflictColumns […] the constraint that fired is unknown", whose enumeration lists only conflict causes. A rejection described as a conflict is the exact sentence this path was fixed once already for producing; it survived on the path that had no transaction to read on. The store now pins one connection for the whole decision — the same pinning `insertRecoverAutoId` does for `LAST_INSERT_ID()`.
|
|
61
|
-
|
|
62
|
-
**The classification.** The store swallowed the driver's error and raised a prose one of its own, so `classifyConstraintViolation` had nothing to read: this was the one write path where the typed error could not fire, while every other one produced it. The warning IS the driver's payload — `INSERT IGNORE` only changed how it was delivered — so it is handed on in the shape the driver would have thrown. A rejection now arrives as the same `ConstraintViolation { kind: 'foreignKey', … }` a plain `insert` produces. Nothing new crosses the wire: the classifier extracts the constraint NAME as a delimited group, never the sentence.
|
|
63
|
-
|
|
64
|
-
This is the default `voltro data import` path (`--mode append`, `--on-conflict skip`, without `--atomic`), so a row rejected by a foreign key was reported to the operator as a conflict with an unknown cause.
|
|
65
|
-
|
|
66
|
-
`constraintViolation.integration.test.ts` now asserts the `insertIgnore` seam per dialect against live postgres 17, MySQL 8.4, MariaDB 11 and SQL Server 2022. It was the missing assertion behind a claim derived from the wiring — the classification does sit on all ten write paths, which is not the same as a classifiable error arriving on all ten.
|
|
67
|
-
- **@voltro/protocol, @voltro/runtime** — The framework's store errors — `ConstraintViolation`, `TenantScopeViolation`, `TenantRowNotFound`, `ServerOnlyColumnWrite`, `TableValidationFailed`, `StoreOperationFailed` — are exported from `@voltro/protocol` and can therefore be declared in a descriptor's `error:` union. They could not be.
|
|
68
|
-
|
|
69
|
-
They lived in `@voltro/runtime`, which reaches `node:child_process`, `node:http` and `node:crypto`. A descriptor is loaded VALUE-LEVEL by the web client (the `RpcClient` needs every procedure's Schema), so a descriptor importing from there is refused at boot by the browser-safety guard — correctly. The typed half of these errors was therefore unreachable: the docs told you to declare them, and the boot said no.
|
|
12
|
+
- **@voltro/sql-mysql, @voltro/database, @voltro/cli** — The mysql-family binlog reader no longer keeps a table excluded after the very migration that fixed it.
|
|
70
13
|
|
|
71
|
-
|
|
14
|
+
A UNIQUE on an unbounded text column is a MariaDB hash long-unique, whose hidden `DB_ROW_HASH_n` column the reader can never account for — so the table is held out of binlog capture and the exclusion is reported. `voltro dev` builds its store BEFORE it migrates (kv, cross-replica broadcast and the analytics mirror all need one), so on a boot whose own auto-migration bounds the column, that finding was drawn from a schema that stopped existing about a second later. The exclusion then outlived its cause for the life of the process, and the message — correct when written, and typically the only error line in the boot log — went on describing the pre-migration database.
|
|
72
15
|
|
|
73
|
-
|
|
74
|
-
- **@voltro/database, @voltro/sql-mysql** — A blocked `alter-column-type` told every dialect to write a postgres cast.
|
|
16
|
+
Three changes:
|
|
75
17
|
|
|
76
|
-
The
|
|
18
|
+
- `DataStore.refreshChangeCaptureExclusions()` (optional; implemented by the mysql-family store) re-runs the probe and re-points the LIVE reader, in both directions — schema work that CREATES the condition now excludes the table immediately instead of after three failed writes. `voltro dev` calls it once, after all its schema work. `voltro serve` needs no equivalent: it builds its store after every schema step and never applies DDL itself. - The definitive message now states its own durability — that it is the schema as read at reader attach, and that applying the remedy does not by itself lift the exclusion. - On a boot that will re-check, the finding is reported as a provisional note rather than as a verdict, so a boot that fixes the condition leaves no error line about it. The note escalates to the full verdict on its own if the re-check never runs. - Two reader fixes the re-check depended on: applying a new exclusion set now WAITS for a reconnect already in flight (it is what applies the set, so resolving before it landed meant the caller's next write hit the old filter), and the reconnect loop no longer keeps resuming from an offset it has just jumped away from — that turned one purged offset into a reconnect every watchdog interval, forever, delivering nothing.
|
|
19
|
+
- **@voltro/data-transfer, @voltro/database, @voltro/sql-mysql, @voltro/sql-postgres, @voltro/sql-sqlite, @voltro/sql-mssql, @voltro/cli** — `voltro data import --mode replace` no longer leaves a target in neither state, and now works against schemas that have foreign keys.
|
|
77
20
|
|
|
78
|
-
|
|
79
|
-
acknowledge it on the column: `.narrowedFrom('json', { using: 'meta::text' })`
|
|
80
|
-
```
|
|
21
|
+
The delete step ran table by table and stopped at the first refusal, so a run that could not finish left dozens of tables emptied and nothing loaded — and a second attempt destroyed more than the first, because it got further before hitting the same wall. The wall itself was not exotic: MySQL, MariaDB and SQL Server check a foreign key as each ROW is deleted, so a table that references ITSELF cannot be emptied by any ordering of the tables. `createdBy → actors` on the `actors` table is exactly that shape, and it is what an audit mixin on an actor table produces.
|
|
81
22
|
|
|
82
|
-
`
|
|
23
|
+
- `DataStore.emptyTables()` (per dialect) empties the whole set as one unit, in one transaction, with referential integrity suspended for the duration — `FOREIGN_KEY_CHECKS` on the mysql family, a multi-table `TRUNCATE` on postgres, `defer_foreign_keys` on sqlite, per-table `NOCHECK`/`WITH CHECK CHECK` on mssql. All-or-nothing on every engine, including under `--atomic`, where it runs on the transaction the import already holds. - A **pre-flight refusal**: if a table OUTSIDE the bundle holds rows referencing one inside it, the import refuses before deleting anything and names the tables, the columns and the row counts. Those rows cannot be restored from the bundle, so forcing it is not an option. An EMPTY outside table blocks nothing. - Table-level failures carry the driver's own reason and code, the way row-level failures already did. `truncate <table> failed: Failed to execute statement` fits every plausible cause equally; the classification that produced `foreign key <name>: … [ER_NO_REFERENCED_ROW_2/1452]` one level down now applies one level up. The word "truncate" is gone from the message too — the step issues DELETE, and naming a statement it does not run sends whoever reads it to reproduce the wrong thing. - A typed refusal reaching the `--target api` transport keeps its text: the admin import endpoint answers `409` with the reason instead of flattening it to `import failed`, on the one transport where the operator has no other way to see it.
|
|
83
24
|
|
|
84
|
-
The
|
|
25
|
+
The bulk empty emits no change events, where the per-table loop emitted one per row. An import through `--target api` now asks every live subscription to re-read once it lands — the coarse refresh the framework already uses after a broadcast gap — so neither the missing deletes nor a table the bundle carries EMPTY leaves a subscriber holding rows that are gone. Wired where the route is mounted, which is the one place both boot paths share.
|
|
85
26
|
|
|
86
|
-
|
|
27
|
+
On postgres the emptying is a `DELETE` per table, not a `TRUNCATE`, and the difference is not performance: postgres refuses `TRUNCATE` on a table with ANY incoming foreign key, rows or not, while the mysql family refuses a DELETE only when rows actually reference the doomed ones. A `TRUNCATE` version made an EMPTY table outside the bundle block a replace on postgres and not on mariadb — one import, refused on one engine and accepted on the other, over a table holding nothing.
|
|
87
28
|
|
|
88
|
-
|
|
89
|
-
- **@voltro/sql-mysql** — On MariaDB, `upsert` could write a DIFFERENT row than the one it was given and report success.
|
|
29
|
+
`--target api` also no longer times out on a full bundle. Both api-target calls went through `fetch`, whose undici default gives up after 300 s — a bound on the caller's database size, on a call whose response arrives only when the import does. They wait as long as the instance needs now, stream the body instead of buffering the whole bundle, and take `--timeout <seconds>` when a deadline is wanted. If one is hit, the message says the instance is probably still importing — and gives different advice for `replace` than for the idempotent modes, since re-running the first while it is mid-flight would empty the target under it.
|
|
90
30
|
|
|
91
|
-
|
|
31
|
+
Two more, found by measuring rather than by reading:
|
|
92
32
|
|
|
93
|
-
|
|
33
|
+
- **`--atomic` on postgres could not import a bundle that needed the deferred-FK repair at all.** A failed statement aborts the transaction there, and that repair depends on a row whose parent has not loaded yet failing, being held, and being retried — so the first such row poisoned every write after it. Every tolerated write now runs inside a savepoint. Per-row savepoints measured 2.40x the time of none on 5 000 rows, so they are amortised: one savepoint per batch of 200, and a batch that fails rolls back whole and replays row by row. The mysql family and sqlite leave a transaction usable after a failed statement and pay nothing for any of this. - **The replace pre-flight asked the caller's snapshot.** Over `--target api` that is the app's DECLARED schema, which cannot show a table the app stopped declaring but the database still has — and rows in a table nobody declares are exactly the rows nobody is watching. `DataStore.incomingForeignKeys()` reads the live catalog per dialect; the snapshot remains the fallback for stores without one.
|
|
94
34
|
|
|
95
|
-
|
|
35
|
+
A bundle bigger than one chunk is now uploaded as a series of short requests, so a proxy body cap or an ingress read timeout has nothing large to choke on, and the switch is automatic — the packer's stream is buffered one chunk ahead, so a small bundle is sent exactly as before and nobody has to know in advance which table is the big one. The import still runs ONCE, at the end, over the whole bundle. Resume is byte-exact (`packBundle` is deterministic over a directory, which this package now asserts), guarded by a bundle key so a different bundle under the same upload id is refused rather than spliced into the partial one, and by a contiguity check so a mis-ordered append cannot produce an archive that only fails later during decode. `--chunk-size <mb>` overrides the 16 MiB default.
|
|
@@ -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.43.
|
|
16
|
-
"@voltro/cli": "0.43.
|
|
17
|
-
"@voltro/database": "0.43.
|
|
18
|
-
"@voltro/env": "0.43.
|
|
19
|
-
"@voltro/protocol": "0.43.
|
|
20
|
-
"@voltro/runtime": "0.43.
|
|
15
|
+
"@voltro/ai": "0.43.2",
|
|
16
|
+
"@voltro/cli": "0.43.2",
|
|
17
|
+
"@voltro/database": "0.43.2",
|
|
18
|
+
"@voltro/env": "0.43.2",
|
|
19
|
+
"@voltro/protocol": "0.43.2",
|
|
20
|
+
"@voltro/runtime": "0.43.2",
|
|
21
21
|
"effect": "^3.22.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@voltro/testing": "0.43.
|
|
24
|
+
"@voltro/testing": "0.43.2",
|
|
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.43.
|
|
17
|
-
"@voltro/database": "0.43.
|
|
18
|
-
"@voltro/env": "0.43.
|
|
19
|
-
"@voltro/plugin-auth": "0.43.
|
|
20
|
-
"@voltro/protocol": "0.43.
|
|
21
|
-
"@voltro/runtime": "0.43.
|
|
22
|
-
"@voltro/sql-postgres": "0.43.
|
|
16
|
+
"@voltro/cli": "0.43.2",
|
|
17
|
+
"@voltro/database": "0.43.2",
|
|
18
|
+
"@voltro/env": "0.43.2",
|
|
19
|
+
"@voltro/plugin-auth": "0.43.2",
|
|
20
|
+
"@voltro/protocol": "0.43.2",
|
|
21
|
+
"@voltro/runtime": "0.43.2",
|
|
22
|
+
"@voltro/sql-postgres": "0.43.2",
|
|
23
23
|
"effect": "^3.22.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@voltro/testing": "0.43.
|
|
26
|
+
"@voltro/testing": "0.43.2",
|
|
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.43.
|
|
20
|
-
"@voltro/database": "0.43.
|
|
21
|
-
"@voltro/env": "0.43.
|
|
22
|
-
"@voltro/plugin-multitenancy": "0.43.
|
|
23
|
-
"@voltro/protocol": "0.43.
|
|
24
|
-
"@voltro/runtime": "0.43.
|
|
19
|
+
"@voltro/cli": "0.43.2",
|
|
20
|
+
"@voltro/database": "0.43.2",
|
|
21
|
+
"@voltro/env": "0.43.2",
|
|
22
|
+
"@voltro/plugin-multitenancy": "0.43.2",
|
|
23
|
+
"@voltro/protocol": "0.43.2",
|
|
24
|
+
"@voltro/runtime": "0.43.2",
|
|
25
25
|
"effect": "^3.22.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@voltro/testing": "0.43.
|
|
28
|
+
"@voltro/testing": "0.43.2",
|
|
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.43.
|
|
17
|
-
"@voltro/database": "0.43.
|
|
18
|
-
"@voltro/env": "0.43.
|
|
19
|
-
"@voltro/plugin-deactivation": "0.43.
|
|
20
|
-
"@voltro/protocol": "0.43.
|
|
21
|
-
"@voltro/runtime": "0.43.
|
|
16
|
+
"@voltro/cli": "0.43.2",
|
|
17
|
+
"@voltro/database": "0.43.2",
|
|
18
|
+
"@voltro/env": "0.43.2",
|
|
19
|
+
"@voltro/plugin-deactivation": "0.43.2",
|
|
20
|
+
"@voltro/protocol": "0.43.2",
|
|
21
|
+
"@voltro/runtime": "0.43.2",
|
|
22
22
|
"effect": "^3.22.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@voltro/testing": "0.43.
|
|
25
|
+
"@voltro/testing": "0.43.2",
|
|
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.43.
|
|
17
|
-
"@voltro/database": "0.43.
|
|
18
|
-
"@voltro/env": "0.43.
|
|
19
|
-
"@voltro/plugin-mail": "0.43.
|
|
20
|
-
"@voltro/plugin-multitenancy": "0.43.
|
|
21
|
-
"@voltro/protocol": "0.43.
|
|
22
|
-
"@voltro/runtime": "0.43.
|
|
16
|
+
"@voltro/cli": "0.43.2",
|
|
17
|
+
"@voltro/database": "0.43.2",
|
|
18
|
+
"@voltro/env": "0.43.2",
|
|
19
|
+
"@voltro/plugin-mail": "0.43.2",
|
|
20
|
+
"@voltro/plugin-multitenancy": "0.43.2",
|
|
21
|
+
"@voltro/protocol": "0.43.2",
|
|
22
|
+
"@voltro/runtime": "0.43.2",
|
|
23
23
|
"effect": "^3.22.0",
|
|
24
24
|
"react": "^19.0.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@voltro/testing": "0.43.
|
|
27
|
+
"@voltro/testing": "0.43.2",
|
|
28
28
|
"typescript": "^6.0.3",
|
|
29
29
|
"@vitest/coverage-v8": "^4.1.10",
|
|
30
30
|
"vitest": "^4.1.10"
|
|
@@ -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.43.
|
|
17
|
-
"@voltro/database": "0.43.
|
|
18
|
-
"@voltro/env": "0.43.
|
|
19
|
-
"@voltro/plugin-multitenancy": "0.43.
|
|
20
|
-
"@voltro/plugin-storage": "0.43.
|
|
21
|
-
"@voltro/protocol": "0.43.
|
|
22
|
-
"@voltro/runtime": "0.43.
|
|
23
|
-
"@voltro/sql-mysql": "0.43.
|
|
16
|
+
"@voltro/cli": "0.43.2",
|
|
17
|
+
"@voltro/database": "0.43.2",
|
|
18
|
+
"@voltro/env": "0.43.2",
|
|
19
|
+
"@voltro/plugin-multitenancy": "0.43.2",
|
|
20
|
+
"@voltro/plugin-storage": "0.43.2",
|
|
21
|
+
"@voltro/protocol": "0.43.2",
|
|
22
|
+
"@voltro/runtime": "0.43.2",
|
|
23
|
+
"@voltro/sql-mysql": "0.43.2",
|
|
24
24
|
"effect": "^3.22.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@voltro/testing": "0.43.
|
|
27
|
+
"@voltro/testing": "0.43.2",
|
|
28
28
|
"typescript": "^6.0.3",
|
|
29
29
|
"@vitest/coverage-v8": "^4.1.10",
|
|
30
30
|
"vitest": "^4.1.10"
|