@voltro/cli 0.43.1 → 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.
Files changed (90) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/dist/{apiBuild-DF0f69Gf.js → apiBuild-DvWreIQP.js} +1 -1
  3. package/dist/apiBuild-XaW40W8x.js +2 -0
  4. package/dist/bin.js +1 -1
  5. package/dist/{build-LC_IJaHL.js → build-Ckc-FA7d.js} +6 -6
  6. package/dist/{checkCommand-DBpTSK8d.js → checkCommand-AlbawIal.js} +1 -1
  7. package/dist/{checkCommand-DDxwJCja.js → checkCommand-BNfEs4KG.js} +2 -2
  8. package/dist/{codegenCommand-LjxfK4Am.js → codegenCommand-iClXoRCW.js} +1 -1
  9. package/dist/{codemodRunner-Cnnz4-I7.js → codemodRunner-BKTnaGOz.js} +22 -0
  10. package/dist/{commands-CbQcuWsE.js → commands-fsnezHLH.js} +18 -18
  11. package/dist/{dashboardCommand-CAHjCe_9.js → dashboardCommand-DHDmlo9A.js} +1 -1
  12. package/dist/dataCommand-sfpGV694.js +867 -0
  13. package/dist/{dev-D0E5x2Ue.js → dev-BZO5aLdr.js} +1 -1
  14. package/dist/{dev-B2rZfqxw.js → dev-D-JZ6CGQ.js} +930 -916
  15. package/dist/doctorCommand-BeLOwq7S.js +2 -0
  16. package/dist/{doctorCommand-Ct_3BHgd.js → doctorCommand-BlUyESpD.js} +9 -9
  17. package/dist/{dormancyCommand-D1DKnYce.js → dormancyCommand-lQxdrU8C.js} +1 -1
  18. package/dist/{embeddingsCommand-1sZRBKlM.js → embeddingsCommand-ByBTju6X.js} +1 -1
  19. package/dist/{envCommand-7qjlQgLD.js → envCommand-CpCbYAgR.js} +1 -1
  20. package/dist/{evolveCommand-D5opB48I.js → evolveCommand-CBV3-TtK.js} +2 -2
  21. package/dist/index.js +1 -1
  22. package/dist/{infoCommand-Bs_8RU22.js → infoCommand-DJoA9cKD.js} +1 -1
  23. package/dist/{runtimeTrace-Wmi7V-wN.js → runtimeTrace-DJ9tPhrc.js} +1 -1
  24. package/dist/{sdkgen-DbTFGCjg.js → sdkgen-7dr8-Onw.js} +1 -1
  25. package/dist/serveCommand-BlnAlNQg.js +1891 -0
  26. package/dist/serveCommand-Dg_E1ev4.js +2 -0
  27. package/dist/serveEntry.js +1 -1
  28. package/dist/{updateCommand-CrI9B4d7.js → updateCommand-BvRidHp6.js} +1 -1
  29. package/dist/updateCommand-DcKVmLVN.js +2 -0
  30. package/dist/{webhooksCommand-BXUP5YjW.js → webhooksCommand-BfO_JF2b.js} +1 -1
  31. package/package.json +23 -17
  32. package/templates/AGENTS.md +1 -1
  33. package/templates/agent-docs/_index.md +1 -1
  34. package/templates/agent-docs/cli.md +144 -4
  35. package/templates/agent-docs/database/seedsdialects.md +12 -0
  36. package/templates/agent-docs/plugins/versioning.md +2 -0
  37. package/templates/agent-docs/whats-new.md +16 -51
  38. package/templates/apps/api-ai/package.json +7 -7
  39. package/templates/apps/api-auth/package.json +8 -8
  40. package/templates/apps/api-backend/package.json +7 -7
  41. package/templates/apps/api-backend-deactivation/package.json +7 -7
  42. package/templates/apps/api-backend-mail/package.json +8 -8
  43. package/templates/apps/api-backend-mariadb/package.json +9 -9
  44. package/templates/apps/api-backend-sqlite/package.json +8 -8
  45. package/templates/apps/api-backend-storage/package.json +8 -8
  46. package/templates/apps/api-cms/package.json +10 -10
  47. package/templates/apps/api-collab/package.json +8 -8
  48. package/templates/apps/api-data-advanced/package.json +8 -8
  49. package/templates/apps/api-durable/package.json +8 -8
  50. package/templates/apps/api-feature-flags/package.json +9 -9
  51. package/templates/apps/api-governance/package.json +8 -8
  52. package/templates/apps/api-kv/package.json +8 -8
  53. package/templates/apps/api-moderation/package.json +8 -8
  54. package/templates/apps/api-observability/package.json +8 -8
  55. package/templates/apps/api-ratelimit/package.json +8 -8
  56. package/templates/apps/api-rbac/package.json +8 -8
  57. package/templates/apps/api-rest/package.json +7 -7
  58. package/templates/apps/api-saas/package.json +11 -11
  59. package/templates/apps/api-saas-starter/package.json +10 -10
  60. package/templates/apps/api-search/package.json +8 -8
  61. package/templates/apps/api-status/package.json +8 -8
  62. package/templates/apps/api-versioning/package.json +8 -8
  63. package/templates/apps/api-webhooks/package.json +9 -9
  64. package/templates/apps/changelog/package.json +6 -6
  65. package/templates/apps/edge-functions/package.json +2 -2
  66. package/templates/apps/frontend-admin/package.json +8 -8
  67. package/templates/apps/frontend-app/package.json +9 -9
  68. package/templates/apps/frontend-auth/package.json +8 -8
  69. package/templates/apps/frontend-blank/package.json +7 -7
  70. package/templates/apps/frontend-cms/package.json +9 -9
  71. package/templates/apps/frontend-collab/package.json +10 -10
  72. package/templates/apps/frontend-contact/package.json +7 -7
  73. package/templates/apps/frontend-dashboard/package.json +7 -7
  74. package/templates/apps/frontend-docs/package.json +7 -7
  75. package/templates/apps/frontend-i18n/package.json +6 -6
  76. package/templates/apps/frontend-landing/package.json +7 -7
  77. package/templates/apps/frontend-portal/package.json +8 -8
  78. package/templates/apps/frontend-saas/package.json +8 -8
  79. package/templates/apps/frontend-spa/package.json +7 -7
  80. package/templates/apps/frontend-ssr/package.json +7 -7
  81. package/templates/apps/frontend-ssr-api/package.json +8 -8
  82. package/templates/apps/frontend-static-blog/package.json +6 -6
  83. package/templates/apps/frontend-status/package.json +8 -8
  84. package/templates/apps/mobile-app/package.json +4 -4
  85. package/dist/apiBuild-B7NgSMhX.js +0 -2
  86. package/dist/dataCommand-CrqvbVOv.js +0 -679
  87. package/dist/doctorCommand-CdsctSwg.js +0 -2
  88. package/dist/serveCommand-C8xzYCwa.js +0 -1776
  89. package/dist/serveCommand-CGNTXafv.js +0 -2
  90. package/dist/updateCommand-BvkKlV7D.js +0 -2
package/CHANGELOG.md CHANGED
@@ -39,6 +39,71 @@ _Changes staged for the next release accumulate here (rolled up from
39
39
 
40
40
  ---
41
41
 
42
+ ## [0.44.0] — 2026-08-19
43
+
44
+ ### ⚠ BREAKING
45
+
46
+ - **@voltro/data-transfer, @voltro/cli** — `runImport` returns an `ImportOutcome` instead of the bundle's `Manifest`, and `--mode replace` runs as ONE transaction by default.
47
+
48
+ **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.
49
+
50
+ Migration: `runImport(...)` now resolves to `{ manifest, tablesWritten, rowsWritten, tablesSkipped, rowsSkipped, fullyResumed }`. Read `.manifest` where you read the manifest before.
51
+
52
+ **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.
53
+
54
+ `--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.
55
+
56
+ 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.
57
+
58
+ **`voltro update` carries you across this** — codemod `0.44.0/01_import-outcome`.
59
+
60
+ ### Fixed
61
+
62
+ - **@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.
63
+
64
+ 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.
65
+
66
+ 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.
67
+
68
+ Both ends are closed, and they are independent on purpose:
69
+
70
+ - **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.
71
+
72
+ 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.
73
+
74
+ ---
75
+
76
+ ## [0.43.2] — 2026-08-18
77
+
78
+ ### Fixed
79
+
80
+ - **@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.
81
+
82
+ 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.
83
+
84
+ Three changes:
85
+
86
+ - `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.
87
+ - **@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.
88
+
89
+ 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.
90
+
91
+ - `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.
92
+
93
+ 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.
94
+
95
+ 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.
96
+
97
+ `--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.
98
+
99
+ Two more, found by measuring rather than by reading:
100
+
101
+ - **`--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.
102
+
103
+ 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.
104
+
105
+ ---
106
+
42
107
  ## [0.43.1] — 2026-08-18
43
108
 
44
109
  ### Fixed
@@ -1,4 +1,4 @@
1
- import { f as e } from "./dev-B2rZfqxw.js";
1
+ import { f as e } from "./dev-D-JZ6CGQ.js";
2
2
  import { vt as t } from "./webDev-101csg6Q.js";
3
3
  import { t as n } from "./dialectDriver-czCHYpeH.js";
4
4
  import { dirname as r, isAbsolute as i, join as a, relative as o, resolve as s } from "node:path";
@@ -0,0 +1,2 @@
1
+ import { c as e, l as t } from "./apiBuild-DvWreIQP.js";
2
+ export { e as runApiBuild, t as runServeBundleBuild };
package/dist/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { r as e } from "./commands-CbQcuWsE.js";
2
+ import { r as e } from "./commands-fsnezHLH.js";
3
3
  import { a as t } from "./nodeEnvironment-cGFAj1J8.js";
4
4
  import { t as n } from "./loadEnv-D9nEOClM.js";
5
5
  import { n as r } from "./cliError-BmdYnghb.js";
@@ -1,8 +1,8 @@
1
- import { hn as e } from "./dev-B2rZfqxw.js";
1
+ import { hn as e } from "./dev-D-JZ6CGQ.js";
2
2
  import { $ as t, A as n, F as r, I as i, L as a, Q as o, a as s, b as c, d as l, et as u, f as d, ht as f, k as p, rt as m, s as h, v as g, vt as _, y as v } from "./webDev-101csg6Q.js";
3
3
  import { t as y } from "./cliRuntime-Dh7UDinH.js";
4
4
  import { a as b } from "./renderModeScan-D7J1B7Kw.js";
5
- import { i as x, o as S, s as C } from "./apiBuild-DF0f69Gf.js";
5
+ import { i as x, o as S, s as C } from "./apiBuild-DvWreIQP.js";
6
6
  import { n as w } from "./renderProfile-1OWWAAtx.js";
7
7
  import { dirname as T, join as E, resolve as D } from "node:path";
8
8
  import { existsSync as O, promises as k } from "node:fs";
@@ -477,7 +477,7 @@ var N = A({ scope: "voltro:build" }), P = async (e) => {
477
477
  file: n.file,
478
478
  reason: n.reason
479
479
  });
480
- let { regenerateRpcGroup: r } = await import("./codegenCommand-LjxfK4Am.js"), i = await r(e);
480
+ let { regenerateRpcGroup: r } = await import("./codegenCommand-iClXoRCW.js"), i = await r(e);
481
481
  if (i.kind === "refused") {
482
482
  F.warn("could not regenerate the rpc group — building against what is on disk", { reason: i.reason });
483
483
  return;
@@ -489,10 +489,10 @@ var N = A({ scope: "voltro:build" }), P = async (e) => {
489
489
  }, K = async (e) => {
490
490
  let n = await l(e);
491
491
  if (!n) {
492
- let { loadApiConfig: t } = await import("./dev-D0E5x2Ue.js"), n = await t(e);
492
+ let { loadApiConfig: t } = await import("./dev-BZO5aLdr.js"), n = await t(e);
493
493
  if (n) {
494
494
  F.info("building api app", { app: n.name ?? "(unnamed)" }), await G(e);
495
- let { runApiBuild: t, runServeBundleBuild: r } = await import("./apiBuild-B7NgSMhX.js");
495
+ let { runApiBuild: t, runServeBundleBuild: r } = await import("./apiBuild-XaW40W8x.js");
496
496
  await t(e);
497
497
  try {
498
498
  await r(e);
@@ -711,7 +711,7 @@ var N = A({ scope: "voltro:build" }), P = async (e) => {
711
711
  return t.ran ? t.exitCode : (yield* j.logError("no web app found at this path", { hint: "looked for app.config.ts with `type: 'web'`" }), 1);
712
712
  }), J = async (t) => {
713
713
  if (t.includes("--target")) {
714
- let { runSdkBuildCommand: e } = await import("./sdkgen-DbTFGCjg.js");
714
+ let { runSdkBuildCommand: e } = await import("./sdkgen-7dr8-Onw.js");
715
715
  return e(t);
716
716
  }
717
717
  let n = t.find((e) => !e.startsWith("-")) ?? process.cwd(), r = await y(q(n), { scope: "voltro:build" }), i = e(n);
@@ -1,2 +1,2 @@
1
- import { n as e, r as t, t as n } from "./checkCommand-DDxwJCja.js";
1
+ import { n as e, r as t, t as n } from "./checkCommand-BNfEs4KG.js";
2
2
  export { n as offlineManifest, e as runCheckCommand, t as toInput };
@@ -4,7 +4,7 @@ import { r } from "./appGraph-KGDPTuTy.js";
4
4
  import { n as i } from "./cliOutput-D1tSBoRM.js";
5
5
  import { n as a, o, r as s, t as c } from "./inspectFetch-EMuhTG_9.js";
6
6
  import { r as l } from "./fileTaxonomy-CJfgOllU.js";
7
- import { x as u } from "./doctorCommand-Ct_3BHgd.js";
7
+ import { x as u } from "./doctorCommand-BlUyESpD.js";
8
8
  import { resolve as d } from "node:path";
9
9
  import { readdirSync as f, statSync as p } from "node:fs";
10
10
  //#region src/observedDiff.ts
@@ -141,7 +141,7 @@ var m = (e) => e === void 0 ? [] : typeof e == "string" ? [e] : e, h = /* @__PUR
141
141
  let t = e.severity === "error" ? "✗ error" : "⚠ warn", n = e.file ? ` (${e.file})` : "";
142
142
  return `${t} ${e.rule} ${e.node}${n}\n ${e.breaks.join("; ")}\n fix: ${e.fix}`;
143
143
  }).join("\n"), C = async (e) => {
144
- let { walk: t, loadDiscovered: n, loadApiConfig: r } = await import("./dev-D0E5x2Ue.js"), { buildRpcEntry: i } = await import("./manifestBuild-j0n109tt.js"), { buildCapabilityManifest: a } = await import("./inspect-DUze25t0.js"), { relative: o } = await import("node:path"), s = await n(await t(e)), c = (t, n, r) => i(t, n, o(e, r)), l = [
144
+ let { walk: t, loadDiscovered: n, loadApiConfig: r } = await import("./dev-BZO5aLdr.js"), { buildRpcEntry: i } = await import("./manifestBuild-j0n109tt.js"), { buildCapabilityManifest: a } = await import("./inspect-DUze25t0.js"), { relative: o } = await import("node:path"), s = await n(await t(e)), c = (t, n, r) => i(t, n, o(e, r)), l = [
145
145
  ...s.queries.map((e) => c(e.descriptor, "query", e.file)),
146
146
  ...s.mutations.map((e) => c(e.descriptor, "mutation", e.file)),
147
147
  ...s.actions.map((e) => c(e.descriptor, "action", e.file)),
@@ -1,4 +1,4 @@
1
- import { l as e, z as t } from "./dev-B2rZfqxw.js";
1
+ import { l as e, z as t } from "./dev-D-JZ6CGQ.js";
2
2
  import { dt as n } from "./webDev-101csg6Q.js";
3
3
  import { r } from "./codegen-CbpGCWLG.js";
4
4
  import { basename as i, join as a, relative as o, resolve as s } from "node:path";
@@ -5618,6 +5618,28 @@ var b = (e, t, n) => {
5618
5618
  });
5619
5619
  return r > 0 && n(`renamed ${r} import(s) of DanglingReferenceError → RowsRefusedError. A tag STRING (Effect.catchTag('DanglingReferenceError', …) or err._tag === '…') is NOT rewritten — change it to 'RowsRefusedError'. The payload also gained primaryCount, and each row a boolean derived.`), r;
5620
5620
  }
5621
+ }),
5622
+ S({
5623
+ version: "0.44.0",
5624
+ id: "0.44.0/01_import-outcome",
5625
+ title: "`runImport` returns an ImportOutcome — read `.manifest` for the bundle",
5626
+ kind: "manual",
5627
+ appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getImportDeclarations().some((e) => e.getModuleSpecifierValue().startsWith("@voltro/data-transfer") && e.getNamedImports().some((e) => e.getName() === "runImport"))),
5628
+ note: [
5629
+ "`runImport(...)` now resolves to `{ manifest, tablesWritten, rowsWritten, tablesSkipped, rowsSkipped, fullyResumed }`",
5630
+ "instead of the bundle's `Manifest`.",
5631
+ "",
5632
+ " 1. Where you read the bundle — `.tables`, `.assets`, `.scope`, `.source` — read `.manifest.tables` and so on.",
5633
+ " 2. Where you REPORTED a row count, prefer `rowsWritten`. The manifest total is what the bundle CARRIES:",
5634
+ " a run that skipped every table (an earlier run of the same bundle directory had already applied them)",
5635
+ " carries the full count while writing nothing, which is exactly how a no-op used to read as a success.",
5636
+ " 3. `fullyResumed` is true precisely in that case.",
5637
+ "",
5638
+ "Same release, unrelated to the return type: `--mode replace` now runs in ONE transaction unless you pass",
5639
+ "`--no-atomic` (CLI) or `atomic: false` (API) — a replace that failed mid-load used to leave the target",
5640
+ "emptied of its old rows and holding part of the new ones. If you relied on per-table resume for a replace,",
5641
+ "that is the non-atomic path."
5642
+ ].join("\n")
5621
5643
  })
5622
5644
  ], Y = /* @__PURE__ */ new Set([
5623
5645
  "node_modules",
@@ -91,7 +91,7 @@ var c = () => {
91
91
  name: "dev",
92
92
  summary: "Start the local development server (auto-discovers routes / mutations).",
93
93
  status: "wired",
94
- run: (e) => import("./dev-D0E5x2Ue.js").then((t) => t.runDev(e)),
94
+ run: (e) => import("./dev-BZO5aLdr.js").then((t) => t.runDev(e)),
95
95
  help: {
96
96
  usage: "[app]",
97
97
  examples: [["voltro dev", "boot the app in the current directory"], ["voltro dev apps/acme/api", "boot a specific app"]],
@@ -109,7 +109,7 @@ var c = () => {
109
109
  name: "dashboard",
110
110
  summary: "Serve the DevTools dashboard standalone (from @voltro/dashboard). Targets via VOLTRO_DASHBOARD_APPS; --port to override.",
111
111
  status: "wired",
112
- run: (e) => import("./dashboardCommand-CAHjCe_9.js").then((t) => t.runDashboardCommand(e)),
112
+ run: (e) => import("./dashboardCommand-DHDmlo9A.js").then((t) => t.runDashboardCommand(e)),
113
113
  help: {
114
114
  usage: "[--port <n>]",
115
115
  flags: [["--port <n>", "port to serve the dashboard on"]],
@@ -121,7 +121,7 @@ var c = () => {
121
121
  name: "check",
122
122
  summary: "Verify the app graph (blast-radius checks) against a running api; LLM-shaped --json diagnostics. Flags: --json, --process <p>, --diff removeTable:<name>.",
123
123
  status: "wired",
124
- run: (e) => import("./checkCommand-DBpTSK8d.js").then((t) => t.runCheckCommand(e)),
124
+ run: (e) => import("./checkCommand-AlbawIal.js").then((t) => t.runCheckCommand(e)),
125
125
  help: {
126
126
  usage: "[--json] [--offline] [--process <name>] [--diff removeTable:<name>]",
127
127
  flags: [
@@ -155,7 +155,7 @@ var c = () => {
155
155
  name: "webhooks",
156
156
  summary: "Outbound-webhook artefacts. `consumer` generates the ZERO-DEPENDENCY Standard-Webhooks verification package a subscriber installs, from this app's own declared events; `events` lists the events a subscriber can register for. Usage: voltro webhooks <consumer|events> [path] [--out <dir>] [--name <pkg>] [--json].",
157
157
  status: "wired",
158
- run: (e) => import("./webhooksCommand-BXUP5YjW.js").then((t) => t.runWebhooksCommand(e)),
158
+ run: (e) => import("./webhooksCommand-BfO_JF2b.js").then((t) => t.runWebhooksCommand(e)),
159
159
  help: {
160
160
  usage: "<consumer|events> [path] [--out <dir>] [--name <pkg>] [--json]",
161
161
  flags: [
@@ -171,7 +171,7 @@ var c = () => {
171
171
  name: "evolve",
172
172
  summary: "Schema-evolution copilot: propose an observed-graph-driven codemod + a branch-verified backfill for a schema change (rename/retype/split/drop a column, rename a table). Dry-run by default; --write applies. Usage: voltro evolve rename-column <table>.<col> --to <newName> [--write] [--json].",
173
173
  status: "wired",
174
- run: (e) => import("./evolveCommand-D5opB48I.js").then((t) => t.runEvolveCommand(e)),
174
+ run: (e) => import("./evolveCommand-CBV3-TtK.js").then((t) => t.runEvolveCommand(e)),
175
175
  help: {
176
176
  usage: "<rename-column|rename-table|retype-column|split-column|drop-column> <target> [--to <new>] [--write]",
177
177
  flags: [
@@ -188,7 +188,7 @@ var c = () => {
188
188
  name: "codegen",
189
189
  summary: "Emit rpcGroup.generated.ts from discovered route / mutation descriptors.",
190
190
  status: "wired",
191
- run: (e) => import("./codegenCommand-LjxfK4Am.js").then((t) => t.runCodegenCommand(e)),
191
+ run: (e) => import("./codegenCommand-iClXoRCW.js").then((t) => t.runCodegenCommand(e)),
192
192
  help: {
193
193
  usage: "[app]",
194
194
  examples: [["voltro codegen", "regenerate rpcGroup.generated.ts for the app in the cwd"]],
@@ -259,7 +259,7 @@ var c = () => {
259
259
  name: "info",
260
260
  summary: "Report versions (CLI, node, every installed @voltro/* — flags lockstep skew), package manager, and dialect. --json for CI. Exits 1 on version skew.",
261
261
  status: "wired",
262
- run: (e) => import("./infoCommand-Bs_8RU22.js").then((t) => t.runInfoCommand(e)),
262
+ run: (e) => import("./infoCommand-DJoA9cKD.js").then((t) => t.runInfoCommand(e)),
263
263
  help: {
264
264
  usage: "[--json]",
265
265
  flags: [["--json", "machine-readable report"]],
@@ -280,7 +280,7 @@ var c = () => {
280
280
  name: "env",
281
281
  summary: "Inspect/sync the typed-env manifest. Subcommands: check (default), sync (.env.example), types (env.generated.d.ts for CI tsc), turbo.",
282
282
  status: "wired",
283
- run: (e) => import("./envCommand-7qjlQgLD.js").then((t) => t.runEnvCommand(e)),
283
+ run: (e) => import("./envCommand-CpCbYAgR.js").then((t) => t.runEnvCommand(e)),
284
284
  help: {
285
285
  usage: "[check|sync|types|turbo] [--force]",
286
286
  flags: [["--force", "overwrite the generated file instead of refusing on a conflict"]],
@@ -309,12 +309,12 @@ var c = () => {
309
309
  run: async (e) => {
310
310
  let t = e.find((e) => !e.startsWith("-")) ?? process.cwd();
311
311
  if (e.includes("--preflight")) {
312
- let { runServePreflight: e } = await import("./doctorCommand-CdsctSwg.js");
312
+ let { runServePreflight: e } = await import("./doctorCommand-BeLOwq7S.js");
313
313
  return e(a(t), !0);
314
314
  }
315
315
  let { tryRunWebServe: n } = await import("./webDev-BLKBO34K.js"), r = await n(a(t));
316
316
  if (!r.ran) {
317
- let { runServeDispatch: t } = await import("./serveCommand-CGNTXafv.js");
317
+ let { runServeDispatch: t } = await import("./serveCommand-Dg_E1ev4.js");
318
318
  return t(e);
319
319
  }
320
320
  return r.exitCode;
@@ -342,13 +342,13 @@ var c = () => {
342
342
  handlesHelp: !0,
343
343
  summary: "Preflight an app for production: the precompiled serve bundle, hand-rolled primitives (naming the shipped one), @voltro/* version skew, executors with no access check, `.serverOnly()` leaks, and junction-FK gaps.",
344
344
  status: "wired",
345
- run: (e) => import("./doctorCommand-CdsctSwg.js").then((t) => t.runDoctorCommand(e))
345
+ run: (e) => import("./doctorCommand-BeLOwq7S.js").then((t) => t.runDoctorCommand(e))
346
346
  },
347
347
  {
348
348
  name: "build",
349
349
  summary: "Production build for a web app (vite build + per-page SSG pre-render).",
350
350
  status: "wired",
351
- run: (e) => import("./build-LC_IJaHL.js").then((t) => t.runBuildCommand(e)),
351
+ run: (e) => import("./build-Ckc-FA7d.js").then((t) => t.runBuildCommand(e)),
352
352
  help: {
353
353
  usage: "[app] [--target <t>]",
354
354
  flags: [["--target <t>", "build target"]],
@@ -364,7 +364,7 @@ var c = () => {
364
364
  name: "prune-runtime",
365
365
  summary: "Trim a deployed web tree’s node_modules to the reachable runtime set (standalone image slimming).",
366
366
  status: "wired",
367
- run: (e) => import("./runtimeTrace-Wmi7V-wN.js").then((t) => t.runPruneRuntimeCommand(e)),
367
+ run: (e) => import("./runtimeTrace-DJ9tPhrc.js").then((t) => t.runPruneRuntimeCommand(e)),
368
368
  hidden: !0
369
369
  },
370
370
  {
@@ -382,7 +382,7 @@ var c = () => {
382
382
  name: "dormancy",
383
383
  summary: "Single-node scale-to-zero: front the API with a wake-orchestrator that stops the app when idle and brings it back on a request or a due wakeup (cron/workflow). Needs a SQL store. Flags: --port, --app-port, --idle-grace-ms, --tick-ms.",
384
384
  status: "wired",
385
- run: (e) => import("./dormancyCommand-D1DKnYce.js").then((t) => t.runDormancyCommand(e)),
385
+ run: (e) => import("./dormancyCommand-lQxdrU8C.js").then((t) => t.runDormancyCommand(e)),
386
386
  help: {
387
387
  usage: "[app] [--port <n>] [--app-port <n>] [--idle-grace-ms <n>] [--tick-ms <n>]",
388
388
  flags: [
@@ -469,7 +469,7 @@ var c = () => {
469
469
  name: "data",
470
470
  summary: "Export/import + backup/restore of app data. Logical (rows + optional assets): export <dir> [--tenant <id>|--tables a,b] [--assets] [--compression zstd|gzip|none] [--consistency live|snapshot]; import <dir> [--assets] [--no-verify]. Native (rows ONLY — no blobs): backup <dir> / restore <dir> (pg_dump/mariadb-dump/…). Resumable; typed-NDJSON; content-addressed assets on the logical path.",
471
471
  status: "wired",
472
- run: (e) => import("./dataCommand-CrqvbVOv.js").then((t) => t.runDataCommand(e)),
472
+ run: (e) => import("./dataCommand-sfpGV694.js").then((t) => t.runDataCommand(e)),
473
473
  help: {
474
474
  usage: "<export|import|backup|restore> <dir> [options]",
475
475
  flags: [
@@ -524,20 +524,20 @@ var c = () => {
524
524
  handlesHelp: !0,
525
525
  summary: "Upgrade the app to the latest framework: bump every @voltro/* dependency (across ALL workspace members, install once at the workspace root), then run the codemods shipped with the target version. Flags: --to <version>, --from <version>, --codemods-only, --dry-run, --force, --exact, --help. After: run `voltro db apply`.",
526
526
  status: "wired",
527
- run: (e) => import("./updateCommand-BvkKlV7D.js").then((t) => t.runUpdateCommand(e))
527
+ run: (e) => import("./updateCommand-DcKVmLVN.js").then((t) => t.runUpdateCommand(e))
528
528
  },
529
529
  {
530
530
  name: "_apply-codemods",
531
531
  summary: "Internal: apply shipped codemods for a framework version jump (re-exec target of `voltro update`).",
532
532
  status: "wired",
533
533
  hidden: !0,
534
- run: (e) => import("./updateCommand-BvkKlV7D.js").then((t) => t.runApplyCodemods(e))
534
+ run: (e) => import("./updateCommand-DcKVmLVN.js").then((t) => t.runApplyCodemods(e))
535
535
  },
536
536
  {
537
537
  name: "embeddings",
538
538
  summary: "Embeddings tooling. Subcommand: backfill <table> --text <field> --vector <field> [--model <m>] [--model-field <f>] [--batch <n>] [--dry-run] — (re)embed rows the vectorEmbedding() mixin missed.",
539
539
  status: "wired",
540
- run: (e) => import("./embeddingsCommand-1sZRBKlM.js").then((t) => t.runEmbeddingsCommand(e)),
540
+ run: (e) => import("./embeddingsCommand-ByBTju6X.js").then((t) => t.runEmbeddingsCommand(e)),
541
541
  help: {
542
542
  usage: "backfill <table> --text <field> --vector <field> [--model <m>] [--batch <n>] [--dry-run]",
543
543
  flags: [
@@ -1,4 +1,4 @@
1
- import { d as e } from "./dev-B2rZfqxw.js";
1
+ import { d as e } from "./dev-D-JZ6CGQ.js";
2
2
  import { H as t, z as n } from "./webDev-101csg6Q.js";
3
3
  import { t as r } from "./start-Ds3xyn8R.js";
4
4
  import { join as i } from "node:path";