@voltro/cli 0.43.2 → 0.44.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 +34 -0
- package/dist/{apiBuild-BWuw8ZXS.js → apiBuild-DvWreIQP.js} +1 -1
- package/dist/apiBuild-XaW40W8x.js +2 -0
- package/dist/bin.js +1 -1
- package/dist/{build-CGBs4ZOv.js → build-Ckc-FA7d.js} +6 -6
- package/dist/{checkCommand-lTPSN3EQ.js → checkCommand-AlbawIal.js} +1 -1
- package/dist/{checkCommand-BFtFBsqL.js → checkCommand-BNfEs4KG.js} +2 -2
- package/dist/{codegenCommand-BJeyFlip.js → codegenCommand-iClXoRCW.js} +1 -1
- package/dist/{codemodRunner-Cnnz4-I7.js → codemodRunner-BKTnaGOz.js} +22 -0
- package/dist/{commands-pEDOcOo2.js → commands-fsnezHLH.js} +18 -18
- package/dist/{dashboardCommand-Bt2hHMro.js → dashboardCommand-DHDmlo9A.js} +1 -1
- package/dist/{dataCommand-DD2bRHCu.js → dataCommand-sfpGV694.js} +254 -235
- package/dist/{dev-DMx-MF2s.js → dev-BZO5aLdr.js} +1 -1
- package/dist/{dev-wumUfDm1.js → dev-D-JZ6CGQ.js} +8 -4
- package/dist/doctorCommand-BeLOwq7S.js +2 -0
- package/dist/{doctorCommand-RFKpnLih.js → doctorCommand-BlUyESpD.js} +9 -9
- package/dist/{dormancyCommand-EFDQWiUw.js → dormancyCommand-lQxdrU8C.js} +1 -1
- package/dist/{embeddingsCommand-OeYp3qSq.js → embeddingsCommand-ByBTju6X.js} +1 -1
- package/dist/{envCommand-CKgBZK7x.js → envCommand-CpCbYAgR.js} +1 -1
- package/dist/{evolveCommand-ClQlAH0j.js → evolveCommand-CBV3-TtK.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/{infoCommand-Bs_8RU22.js → infoCommand-DJoA9cKD.js} +1 -1
- package/dist/{runtimeTrace-CgpAD9wL.js → runtimeTrace-DJ9tPhrc.js} +1 -1
- package/dist/{sdkgen-Ca2zj4cd.js → sdkgen-7dr8-Onw.js} +1 -1
- package/dist/{serveCommand-CgK7Kj6j.js → serveCommand-BlnAlNQg.js} +632 -621
- package/dist/serveCommand-Dg_E1ev4.js +2 -0
- package/dist/serveEntry.js +1 -1
- package/dist/{updateCommand-CrI9B4d7.js → updateCommand-BvRidHp6.js} +1 -1
- package/dist/updateCommand-DcKVmLVN.js +2 -0
- package/dist/{webhooksCommand-BVNtNsI0.js → webhooksCommand-BfO_JF2b.js} +1 -1
- package/package.json +23 -17
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/cli.md +20 -4
- package/templates/agent-docs/plugins/versioning.md +2 -0
- package/templates/agent-docs/whats-new.md +18 -15
- 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-Cw2-TEXW.js +0 -2
- package/dist/doctorCommand-FOXTTaGp.js +0 -2
- package/dist/serveCommand-DUm2-ikx.js +0 -2
- package/dist/updateCommand-BvkKlV7D.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-BlnAlNQg.js";
|
|
5
5
|
export { e as loadDotEnv, t as registerAppModules, n as registerDriver, r as runServe };
|
|
@@ -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-BKTnaGOz.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-BZO5aLdr.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.44.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",
|
|
@@ -634,6 +634,12 @@
|
|
|
634
634
|
"title": "`DanglingReferenceError` → `RowsRefusedError` (named for the outcome, not a guessed cause)",
|
|
635
635
|
"kind": "transform"
|
|
636
636
|
},
|
|
637
|
+
{
|
|
638
|
+
"version": "0.44.0",
|
|
639
|
+
"id": "0.44.0/01_import-outcome",
|
|
640
|
+
"title": "`runImport` returns an ImportOutcome — read `.manifest` for the bundle",
|
|
641
|
+
"kind": "manual"
|
|
642
|
+
},
|
|
637
643
|
{
|
|
638
644
|
"version": "0.5.0",
|
|
639
645
|
"id": "0.5.0/01_one-terminal-exactly-one",
|
|
@@ -721,22 +727,22 @@
|
|
|
721
727
|
"@effect/platform-node": "^0.108.0",
|
|
722
728
|
"@effect/sql": "^0.52.0",
|
|
723
729
|
"@effect/workflow": "^0.19.0",
|
|
724
|
-
"@voltro/ai": "0.
|
|
725
|
-
"@voltro/cache": "0.
|
|
726
|
-
"@voltro/data-transfer": "0.
|
|
727
|
-
"@voltro/database": "0.
|
|
728
|
-
"@voltro/env": "0.
|
|
729
|
-
"@voltro/kv": "0.
|
|
730
|
-
"@voltro/logger": "0.
|
|
731
|
-
"@voltro/plugin-auth": "0.
|
|
732
|
-
"@voltro/plugin-broadcast": "0.
|
|
733
|
-
"@voltro/plugin-mail": "0.
|
|
734
|
-
"@voltro/plugin-storage": "0.
|
|
735
|
-
"@voltro/plugin-webhooks": "0.
|
|
736
|
-
"@voltro/protocol": "0.
|
|
737
|
-
"@voltro/runtime": "0.
|
|
738
|
-
"@voltro/serverless": "0.
|
|
739
|
-
"@voltro/workflow": "0.
|
|
730
|
+
"@voltro/ai": "0.44.0",
|
|
731
|
+
"@voltro/cache": "0.44.0",
|
|
732
|
+
"@voltro/data-transfer": "0.44.0",
|
|
733
|
+
"@voltro/database": "0.44.0",
|
|
734
|
+
"@voltro/env": "0.44.0",
|
|
735
|
+
"@voltro/kv": "0.44.0",
|
|
736
|
+
"@voltro/logger": "0.44.0",
|
|
737
|
+
"@voltro/plugin-auth": "0.44.0",
|
|
738
|
+
"@voltro/plugin-broadcast": "0.44.0",
|
|
739
|
+
"@voltro/plugin-mail": "0.44.0",
|
|
740
|
+
"@voltro/plugin-storage": "0.44.0",
|
|
741
|
+
"@voltro/plugin-webhooks": "0.44.0",
|
|
742
|
+
"@voltro/protocol": "0.44.0",
|
|
743
|
+
"@voltro/runtime": "0.44.0",
|
|
744
|
+
"@voltro/serverless": "0.44.0",
|
|
745
|
+
"@voltro/workflow": "0.44.0",
|
|
740
746
|
"chokidar": "^5.0.0",
|
|
741
747
|
"ioredis": "^5.11.1",
|
|
742
748
|
"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.44.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.44.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. |
|
|
@@ -2649,7 +2649,8 @@ whole bundle.
|
|
|
2649
2649
|
|---|---|---|
|
|
2650
2650
|
| `--mode upsert\|append\|replace` | `upsert` | How rows are written. See the table below. |
|
|
2651
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 —
|
|
2652
|
+
| `--atomic` | **on for `replace`**, off otherwise | Wrap the whole table phase in ONE transaction — readers see the import all-or-nothing. |
|
|
2653
|
+
| `--no-atomic` | — | Opt out of that. See the trade below. |
|
|
2653
2654
|
| `--tables a,b` | every table | Import only these tables from the bundle. |
|
|
2654
2655
|
| `--dry-run` | off | Run every pre-flight and report what WOULD move; write nothing. |
|
|
2655
2656
|
| `--force` | off | Proceed despite schema drift AND cross-dialect warnings. |
|
|
@@ -2760,7 +2761,11 @@ Anything still unresolvable — the parent row exists in **neither the bundle no
|
|
|
2760
2761
|
|
|
2761
2762
|
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
|
|
|
2763
|
-
- **All or nothing.**
|
|
2764
|
+
- **All or nothing — the emptying AND the load.** `--mode replace` runs the whole table phase in ONE transaction by default, so a run that cannot finish leaves the target exactly as it found it. That default is a correction: the guarantee used to cover only the emptying, and a replace that died partway through the *load* left the target emptied of its old rows and holding part of the new ones. There is no useful state for a replace to stop in, which is why it is the default rather than a flag you have to know about.
|
|
2765
|
+
|
|
2766
|
+
One transaction also closes a window that is easy to miss. Between the delete and the load the target is empty, and if the database is being served, the application writes into that gap — a row it creates on demand is then a primary-key conflict against the same row arriving from the bundle. With one transaction the concurrent writer waits instead of racing.
|
|
2767
|
+
|
|
2768
|
+
`--no-atomic` opts out, and the trade is real: every write to those tables waits for the load, so on a bundle that takes minutes, so does the wait. On postgres it also re-enables the bulk `COPY` loader, which cannot join a transaction it does not own — an atomic run says so once rather than being quietly slower.
|
|
2764
2769
|
- **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
2770
|
|
|
2766
2771
|
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:
|
|
@@ -2817,10 +2822,10 @@ A plain import connects **straight to the database** (not through the running ap
|
|
|
2817
2822
|
| Target | How | Guarantees | Use for |
|
|
2818
2823
|
|---|---|---|---|
|
|
2819
2824
|
| **direct** (default) | writes straight to the DB | none while live — **guarded**; pass `--allow-live` to override | a stopped target, a replica, a dev/staging DB not serving traffic |
|
|
2820
|
-
| **direct + `--atomic`** | wraps
|
|
2825
|
+
| **direct + `--atomic`** (the default for `replace`) | wraps empty+load in ONE transaction | MVCC readers see the import **all-or-nothing** (old until commit, new after) — the live-safe `replace` | replacing a live target's data with no partial-state window |
|
|
2821
2826
|
| **in-process (`--target api`)** | `voltro data import <dir> --target api --api-url <url> --token <secret>` **uploads** the packed bundle (or, with `--bundle-key`, has the instance **pull it from storage**) to the instance's secret-gated admin endpoint, which imports it **in its own process** through its store | full app pipeline — validation, mixins, **field encryption**, hooks — AND automatic reactivity (in-process writes emit change events, so subscriptions update; no separate resync) | a live merge (incl. PROD) that must honour app invariants |
|
|
2822
2827
|
|
|
2823
|
-
`--atomic` is
|
|
2828
|
+
`--atomic` is what `replace` does by default (see above): one transaction, so live reads never see a half-loaded table. (It holds a write transaction for the load duration — writes to those tables block, readers don't. A shadow-table rename would shorten that lock window, but for a full replace concurrent writes are discarded on swap anyway, so it isn't the default.)
|
|
2824
2829
|
|
|
2825
2830
|
### The `--target api` data-transfer endpoints (prod-safe)
|
|
2826
2831
|
|
|
@@ -2937,6 +2942,17 @@ Net: interrupt an export or import at any point — network drop, `Ctrl-C`, OOM-
|
|
|
2937
2942
|
|
|
2938
2943
|
The `--target api` path is unaffected: the instance unpacks each upload into a fresh temp directory, so it never carries a ledger between runs.
|
|
2939
2944
|
|
|
2945
|
+
### What the summary line counts
|
|
2946
|
+
|
|
2947
|
+
`import complete … rows: N` counts the rows **this run wrote**, not the rows the bundle carries. The two differ more often than you would think, and the case where they differ most used to read as a success:
|
|
2948
|
+
|
|
2949
|
+
```
|
|
2950
|
+
import complete — 0 rows written, every table was already applied by an earlier run
|
|
2951
|
+
of this bundle directory { rows: 0, carried: 242950, skippedTables: 114, skippedRows: 242950 }
|
|
2952
|
+
```
|
|
2953
|
+
|
|
2954
|
+
The resume ledger lives **inside the bundle directory**, so copying a bundle copies its ledger, and the copy then imports nothing — correctly, and with a warning that says so and names the file to delete. But the warning is not the last line, and an operator piping the output through `tail -1` sees only the last line. So the last line now tells the truth on its own: `rows` is what was written, `carried` is what the bundle holds, and `skippedRows` is what an earlier run had already applied.
|
|
2955
|
+
|
|
2940
2956
|
### Progress & observability
|
|
2941
2957
|
|
|
2942
2958
|
A multi-hour job is not a black box. Both pipelines signal per **table** — never per row, so the reporting never slows the hot path:
|
|
@@ -134,6 +134,8 @@ Version numbers are 1-based in **both** timings, so switching `timing` does not
|
|
|
134
134
|
|
|
135
135
|
**The price is not optional.** That guarantee is only obtainable by being willing to REFUSE. When the history insert fails — disk, lock timeout, constraint, dropped connection — a transaction offers exactly two outcomes: the mutation fails with it, or the error is swallowed and the change commits without its entry, which is post-commit's hole with the cost already paid. There is no third option, so a rare, explained rejection is the shape of the guarantee rather than a defect.
|
|
136
136
|
|
|
137
|
+
**The refusal takes the row with it.** When the trail's insert fails, the write it covers is rolled back — including a write made OUTSIDE any transaction of your own. That has not always been true: the row's statement committed on its own and the trail ran as a second statement afterwards, so a failing trail left a committed row behind a write that reported failure. Anything that retried that write then met its own row and reported a duplicate key for a row nobody wrote twice. A table with recorders is written inside a transaction now, on every SQL dialect, so "the mutation fails with it" means what it says.
|
|
138
|
+
|
|
137
139
|
**Why the default is still `'post-commit'`.** In-transaction makes `_voltro_row_history` a hard dependency of every write path it covers: its availability becomes your write path's availability, and every covered write holds its locks longer. Post-commit loses at worst *one entry*; in-transaction can, at worst, stop writes to the covered tables entirely. For a compliance trail the second trade is the right one — for the undo / time-travel use this plugin also serves, it is not.
|
|
138
140
|
|
|
139
141
|
### Under CDC, and inside a transaction
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# What's new in 0.
|
|
1
|
+
# What's new in 0.44.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,29 +7,32 @@ 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
|
+
|
|
12
|
+
- **@voltro/data-transfer, @voltro/cli** — `runImport` returns an `ImportOutcome` instead of the bundle's `Manifest`, and `--mode replace` runs as ONE transaction by default.
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
**Why the return type changed.** The summary line counted the rows the BUNDLE carries, not the rows the run wrote. Those differ most exactly where it matters: a bundle directory carries its own resume ledger, so a copied directory imports nothing — correctly, with a warning naming the file to delete — and the run then printed `import complete … rows: 242950` over a target it had not touched. The warning was one line above, which is one line too far for anyone piping the output through `tail -1`. The outcome carries `rowsWritten`, `rowsSkipped` and `fullyResumed`, the CLI reports written-vs-carried, and a fully-skipped run says so on its LAST line.
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
Migration: `runImport(...)` now resolves to `{ manifest, tablesWritten, rowsWritten, tablesSkipped, rowsSkipped, fullyResumed }`. Read `.manifest` where you read the manifest before.
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
**Why replace is atomic now.** The all-or-nothing guarantee was written for the emptying step, and read — reasonably — as covering the run. A replace that died partway through the LOAD left the target emptied of its old rows and holding part of the new ones, measured on a live instance over sixteen minutes. There is no useful state for a replace to stop in, so it is a default rather than a flag you have to know about. It also closes the window that produced that failure: with the tables emptied and the load uncommitted, a concurrent writer in the application waits instead of inserting a row the bundle is about to insert too.
|
|
17
19
|
|
|
18
|
-
-
|
|
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.
|
|
20
|
+
`--no-atomic` (CLI) / `atomic: false` (API) opts out. The trade is stated where it bites: every write to those tables waits for the load, and on postgres the bulk `COPY` loader cannot join a transaction it does not own — an atomic run now says that once rather than being quietly slower.
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
Two smaller things from the same report: `--mode replace` against a running instance warns about the empty-target window when it is NOT atomic, and the `--target api` upload reports progress per chunk plus a line explaining that the final request stays open for the whole import — sixteen minutes of silence is indistinguishable from a hang, and one operator killed a run that had finished.
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
**`voltro update` carries you across this** — codemod `0.44.0/01_import-outcome`.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
24
27
|
|
|
25
|
-
|
|
28
|
+
- **@voltro/sql-mysql, @voltro/sql-postgres, @voltro/sql-sqlite, @voltro/sql-mssql, @voltro/data-transfer** — A write and its write-recorders now succeed or fail together on every SQL dialect, and the data importer's retry is idempotent.
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
A recorder (a versioning trail, an audit log) runs on the caller's connection and is ALLOWED to fail — a recorder that throws must take the write down with it, that is its contract. Outside a caller transaction the two were not one unit: the row's statement committed on its own, and the recorder's INSERT ran afterwards as a second autocommit statement. So a recorder that threw left a COMMITTED row behind a write that reported failure. Measured directly: `insert` throws, the row is in the table, and a second attempt at the same row is `ER_DUP_ENTRY` on PRIMARY.
|
|
28
31
|
|
|
29
|
-
|
|
32
|
+
Anything that retries a failed write then meets its own row. The data importer retries by design — it holds a row whose write failed and tries again once the remaining tables have streamed — so a `--mode replace` that had just emptied a table failed on a duplicate key IN that table. From outside, that is the impossible-looking thing: an import that emptied a table and then failed because something was already in it. Reproduced verbatim, including the table name and `[ER_DUP_ENTRY/1062]`, by putting the old retry back.
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
Both ends are closed, and they are independent on purpose:
|
|
32
35
|
|
|
33
|
-
-
|
|
36
|
+
- **The cause.** A table that HAS recorders writes inside a transaction now, so the row and the trail commit together or not at all — on mysql, mariadb, postgres, sqlite and mssql, verified by one suite that asks all five the same question. A table with no recorders — the default — takes the direct path unchanged; `recordsTable` is a Map-size check first, so it costs one comparison. - **The defence.** The importer's retry upserts instead of inserting in `replace` mode. That covers every OTHER way a write can land while reporting failure: a driver timeout on a write the server applied, a connection lost after the commit, a concurrent writer inserting the same key. It is sound precisely because the table was emptied by this same run — there is nothing in it that is not ours.
|
|
34
37
|
|
|
35
|
-
|
|
38
|
+
The test that pinned the divergence went red when the fix landed, exactly as its own note said it would, and is inverted with that note kept.
|
|
@@ -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.44.0",
|
|
16
|
+
"@voltro/cli": "0.44.0",
|
|
17
|
+
"@voltro/database": "0.44.0",
|
|
18
|
+
"@voltro/env": "0.44.0",
|
|
19
|
+
"@voltro/protocol": "0.44.0",
|
|
20
|
+
"@voltro/runtime": "0.44.0",
|
|
21
21
|
"effect": "^3.22.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@voltro/testing": "0.
|
|
24
|
+
"@voltro/testing": "0.44.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.44.0",
|
|
17
|
+
"@voltro/database": "0.44.0",
|
|
18
|
+
"@voltro/env": "0.44.0",
|
|
19
|
+
"@voltro/plugin-auth": "0.44.0",
|
|
20
|
+
"@voltro/protocol": "0.44.0",
|
|
21
|
+
"@voltro/runtime": "0.44.0",
|
|
22
|
+
"@voltro/sql-postgres": "0.44.0",
|
|
23
23
|
"effect": "^3.22.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@voltro/testing": "0.
|
|
26
|
+
"@voltro/testing": "0.44.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.44.0",
|
|
20
|
+
"@voltro/database": "0.44.0",
|
|
21
|
+
"@voltro/env": "0.44.0",
|
|
22
|
+
"@voltro/plugin-multitenancy": "0.44.0",
|
|
23
|
+
"@voltro/protocol": "0.44.0",
|
|
24
|
+
"@voltro/runtime": "0.44.0",
|
|
25
25
|
"effect": "^3.22.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@voltro/testing": "0.
|
|
28
|
+
"@voltro/testing": "0.44.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.44.0",
|
|
17
|
+
"@voltro/database": "0.44.0",
|
|
18
|
+
"@voltro/env": "0.44.0",
|
|
19
|
+
"@voltro/plugin-deactivation": "0.44.0",
|
|
20
|
+
"@voltro/protocol": "0.44.0",
|
|
21
|
+
"@voltro/runtime": "0.44.0",
|
|
22
22
|
"effect": "^3.22.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@voltro/testing": "0.
|
|
25
|
+
"@voltro/testing": "0.44.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.44.0",
|
|
17
|
+
"@voltro/database": "0.44.0",
|
|
18
|
+
"@voltro/env": "0.44.0",
|
|
19
|
+
"@voltro/plugin-mail": "0.44.0",
|
|
20
|
+
"@voltro/plugin-multitenancy": "0.44.0",
|
|
21
|
+
"@voltro/protocol": "0.44.0",
|
|
22
|
+
"@voltro/runtime": "0.44.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.44.0",
|
|
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.
|
|
17
|
-
"@voltro/database": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/plugin-multitenancy": "0.
|
|
20
|
-
"@voltro/plugin-storage": "0.
|
|
21
|
-
"@voltro/protocol": "0.
|
|
22
|
-
"@voltro/runtime": "0.
|
|
23
|
-
"@voltro/sql-mysql": "0.
|
|
16
|
+
"@voltro/cli": "0.44.0",
|
|
17
|
+
"@voltro/database": "0.44.0",
|
|
18
|
+
"@voltro/env": "0.44.0",
|
|
19
|
+
"@voltro/plugin-multitenancy": "0.44.0",
|
|
20
|
+
"@voltro/plugin-storage": "0.44.0",
|
|
21
|
+
"@voltro/protocol": "0.44.0",
|
|
22
|
+
"@voltro/runtime": "0.44.0",
|
|
23
|
+
"@voltro/sql-mysql": "0.44.0",
|
|
24
24
|
"effect": "^3.22.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@voltro/testing": "0.
|
|
27
|
+
"@voltro/testing": "0.44.0",
|
|
28
28
|
"typescript": "^6.0.3",
|
|
29
29
|
"@vitest/coverage-v8": "^4.1.10",
|
|
30
30
|
"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-multitenancy": "0.
|
|
20
|
-
"@voltro/protocol": "0.
|
|
21
|
-
"@voltro/runtime": "0.
|
|
22
|
-
"@voltro/sql-sqlite": "0.
|
|
16
|
+
"@voltro/cli": "0.44.0",
|
|
17
|
+
"@voltro/database": "0.44.0",
|
|
18
|
+
"@voltro/env": "0.44.0",
|
|
19
|
+
"@voltro/plugin-multitenancy": "0.44.0",
|
|
20
|
+
"@voltro/protocol": "0.44.0",
|
|
21
|
+
"@voltro/runtime": "0.44.0",
|
|
22
|
+
"@voltro/sql-sqlite": "0.44.0",
|
|
23
23
|
"effect": "^3.22.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@voltro/testing": "0.
|
|
26
|
+
"@voltro/testing": "0.44.0",
|
|
27
27
|
"typescript": "^6.0.3",
|
|
28
28
|
"@vitest/coverage-v8": "^4.1.10",
|
|
29
29
|
"vitest": "^4.1.10"
|
|
@@ -11,17 +11,17 @@
|
|
|
11
11
|
"test": "voltro test"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@voltro/cli": "0.
|
|
15
|
-
"@voltro/database": "0.
|
|
16
|
-
"@voltro/env": "0.
|
|
17
|
-
"@voltro/plugin-multitenancy": "0.
|
|
18
|
-
"@voltro/plugin-storage": "0.
|
|
19
|
-
"@voltro/protocol": "0.
|
|
20
|
-
"@voltro/runtime": "0.
|
|
14
|
+
"@voltro/cli": "0.44.0",
|
|
15
|
+
"@voltro/database": "0.44.0",
|
|
16
|
+
"@voltro/env": "0.44.0",
|
|
17
|
+
"@voltro/plugin-multitenancy": "0.44.0",
|
|
18
|
+
"@voltro/plugin-storage": "0.44.0",
|
|
19
|
+
"@voltro/protocol": "0.44.0",
|
|
20
|
+
"@voltro/runtime": "0.44.0",
|
|
21
21
|
"effect": "^3.22.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@voltro/testing": "0.
|
|
24
|
+
"@voltro/testing": "0.44.0",
|
|
25
25
|
"typescript": "^6.0.3",
|
|
26
26
|
"@vitest/coverage-v8": "^4.1.10",
|
|
27
27
|
"vitest": "^4.1.10"
|
|
@@ -13,19 +13,19 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@effect/platform": "^0.97.0",
|
|
15
15
|
"@effect/rpc": "^0.76.0",
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/cms": "0.
|
|
18
|
-
"@voltro/database": "0.
|
|
19
|
-
"@voltro/env": "0.
|
|
20
|
-
"@voltro/plugin-auth": "0.
|
|
21
|
-
"@voltro/plugin-multitenancy": "0.
|
|
22
|
-
"@voltro/protocol": "0.
|
|
23
|
-
"@voltro/runtime": "0.
|
|
24
|
-
"@voltro/sql-postgres": "0.
|
|
16
|
+
"@voltro/cli": "0.44.0",
|
|
17
|
+
"@voltro/cms": "0.44.0",
|
|
18
|
+
"@voltro/database": "0.44.0",
|
|
19
|
+
"@voltro/env": "0.44.0",
|
|
20
|
+
"@voltro/plugin-auth": "0.44.0",
|
|
21
|
+
"@voltro/plugin-multitenancy": "0.44.0",
|
|
22
|
+
"@voltro/protocol": "0.44.0",
|
|
23
|
+
"@voltro/runtime": "0.44.0",
|
|
24
|
+
"@voltro/sql-postgres": "0.44.0",
|
|
25
25
|
"effect": "^3.22.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@voltro/testing": "0.
|
|
28
|
+
"@voltro/testing": "0.44.0",
|
|
29
29
|
"typescript": "^6.0.3",
|
|
30
30
|
"@vitest/coverage-v8": "^4.1.10",
|
|
31
31
|
"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/local-first": "0.
|
|
20
|
-
"@voltro/plugin-multitenancy": "0.
|
|
21
|
-
"@voltro/protocol": "0.
|
|
22
|
-
"@voltro/runtime": "0.
|
|
16
|
+
"@voltro/cli": "0.44.0",
|
|
17
|
+
"@voltro/database": "0.44.0",
|
|
18
|
+
"@voltro/env": "0.44.0",
|
|
19
|
+
"@voltro/local-first": "0.44.0",
|
|
20
|
+
"@voltro/plugin-multitenancy": "0.44.0",
|
|
21
|
+
"@voltro/protocol": "0.44.0",
|
|
22
|
+
"@voltro/runtime": "0.44.0",
|
|
23
23
|
"effect": "^3.22.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@voltro/testing": "0.
|
|
26
|
+
"@voltro/testing": "0.44.0",
|
|
27
27
|
"typescript": "^6.0.3",
|
|
28
28
|
"@vitest/coverage-v8": "^4.1.10",
|
|
29
29
|
"vitest": "^4.1.10"
|
|
@@ -12,17 +12,17 @@
|
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@effect/platform": "^0.97.0",
|
|
14
14
|
"@effect/rpc": "^0.76.0",
|
|
15
|
-
"@voltro/cli": "0.
|
|
16
|
-
"@voltro/database": "0.
|
|
17
|
-
"@voltro/env": "0.
|
|
18
|
-
"@voltro/plugin-governance": "0.
|
|
19
|
-
"@voltro/plugin-multitenancy": "0.
|
|
20
|
-
"@voltro/protocol": "0.
|
|
21
|
-
"@voltro/runtime": "0.
|
|
15
|
+
"@voltro/cli": "0.44.0",
|
|
16
|
+
"@voltro/database": "0.44.0",
|
|
17
|
+
"@voltro/env": "0.44.0",
|
|
18
|
+
"@voltro/plugin-governance": "0.44.0",
|
|
19
|
+
"@voltro/plugin-multitenancy": "0.44.0",
|
|
20
|
+
"@voltro/protocol": "0.44.0",
|
|
21
|
+
"@voltro/runtime": "0.44.0",
|
|
22
22
|
"effect": "^3.22.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@voltro/testing": "0.
|
|
25
|
+
"@voltro/testing": "0.44.0",
|
|
26
26
|
"typescript": "^6.0.3",
|
|
27
27
|
"@vitest/coverage-v8": "^4.1.10",
|
|
28
28
|
"vitest": "^4.1.10"
|