@voltro/cli 0.50.0 → 0.50.1

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 (105) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/apiBuild-BZ-plaQN.js +2 -0
  3. package/dist/{apiBuild-CFYXo06U.js → apiBuild-D3s7lx57.js} +2 -2
  4. package/dist/appGraph-CM9wvUmD.js +2 -0
  5. package/dist/appGraph-Cv2W_wO5.js +111 -0
  6. package/dist/bin.js +1 -1
  7. package/dist/{build-CnSH-zru.js → build-CFmqF39c.js} +7 -7
  8. package/dist/{checkCommand-OL41BMIb.js → checkCommand-DomvYDi1.js} +1 -1
  9. package/dist/{checkCommand-Do3SQbLx.js → checkCommand-DsKIjL6k.js} +54 -45
  10. package/dist/{codegenCommand-BJzaRz6q.js → codegenCommand-C0S27nbB.js} +2 -2
  11. package/dist/{codemodRunner-De3k0pRd.js → codemodRunner-DwY8Rjbl.js} +55 -0
  12. package/dist/{commands-By23Ljny.js → commands-Brp4DI8u.js} +21 -21
  13. package/dist/{dashboardCommand-DN1rAABE.js → dashboardCommand-bbLfc9FW.js} +3 -3
  14. package/dist/{dataCommand-B93TUBIx.js → dataCommand-k9mXTXin.js} +331 -303
  15. package/dist/{dev-1yu42ubu.js → dev-C0cbqysu.js} +3 -3
  16. package/dist/{dev-BWwE0QjK.js → dev-Dz9GqA6P.js} +1 -1
  17. package/dist/doctorCommand-BlciWUJb.js +2 -0
  18. package/dist/{doctorCommand-y-EbP8st.js → doctorCommand-DyViaaCP.js} +38 -22
  19. package/dist/{doctorSourceRelations-Dd48LPvO.js → doctorSourceRelations-c5mlN5HI.js} +66 -34
  20. package/dist/{dormancyCommand-Dc7KRNCG.js → dormancyCommand-DMZPA_HW.js} +1 -1
  21. package/dist/{embeddingsCommand-kPs132bB.js → embeddingsCommand-CMxRPkg6.js} +1 -1
  22. package/dist/{envCommand-E12zSt51.js → envCommand-CDLr-yD4.js} +2 -2
  23. package/dist/{evolveCommand-B3nagPVc.js → evolveCommand-Ct4NesL3.js} +2 -2
  24. package/dist/{generateCommand-CcyvH2ve.js → generateCommand-BDdOxhnv.js} +1 -1
  25. package/dist/index.js +1 -1
  26. package/dist/{infoCommand-Cq0Yz98u.js → infoCommand-orsKJKUy.js} +1 -1
  27. package/dist/{inspect-B7U7Cl_Z.js → inspect-CtL_xTbu.js} +1 -0
  28. package/dist/inspect-CuGDYES0.js +2 -0
  29. package/dist/manifestBuild-CPjhvM62.js +2 -0
  30. package/dist/{manifestBuild-BK42hu0k.js → manifestBuild-CuU1VrSm.js} +2 -2
  31. package/dist/{runtimeTrace-BpLUcrfy.js → runtimeTrace-Bo8jWsNe.js} +1 -1
  32. package/dist/{sdkgen-dl4-WKF6.js → sdkgen-OZhiT2vz.js} +1 -1
  33. package/dist/serveCommand-Bbgg7Paq.js +2 -0
  34. package/dist/{serveCommand-8CTzQCY0.js → serveCommand-YbD5VgfV.js} +4 -4
  35. package/dist/serveEntry.js +1 -1
  36. package/dist/{start-DvlYDyAr.js → start-7b_bL8Uc.js} +1 -1
  37. package/dist/{start-7HcSIKEp.js → start-B1nH9ahf.js} +2 -2
  38. package/dist/startEntry.js +1 -1
  39. package/dist/{updateCommand-i8JbrLAA.js → updateCommand-BgH6vTtq.js} +1 -1
  40. package/dist/updateCommand-BweY17z-.js +2 -0
  41. package/dist/{webDev-B4IEMB0n.js → webDev-BbdkzMbd.js} +1 -1
  42. package/dist/webDev-BcRFTsMA.js +2 -0
  43. package/dist/{webhooksCommand-B0bdyuQ4.js → webhooksCommand-DjE6u0r4.js} +1 -1
  44. package/package.json +23 -17
  45. package/templates/AGENTS.md +1 -1
  46. package/templates/agent-docs/_index.md +1 -1
  47. package/templates/agent-docs/cli.md +63 -3
  48. package/templates/agent-docs/data.md +36 -0
  49. package/templates/agent-docs/whats-new.md +30 -32
  50. package/templates/apps/api-ai/package.json +7 -7
  51. package/templates/apps/api-auth/package.json +8 -8
  52. package/templates/apps/api-backend/package.json +7 -7
  53. package/templates/apps/api-backend-deactivation/package.json +7 -7
  54. package/templates/apps/api-backend-mail/package.json +8 -8
  55. package/templates/apps/api-backend-mariadb/package.json +9 -9
  56. package/templates/apps/api-backend-sqlite/package.json +8 -8
  57. package/templates/apps/api-backend-storage/package.json +8 -8
  58. package/templates/apps/api-cms/package.json +10 -10
  59. package/templates/apps/api-collab/package.json +8 -8
  60. package/templates/apps/api-data-advanced/package.json +8 -8
  61. package/templates/apps/api-durable/package.json +8 -8
  62. package/templates/apps/api-feature-flags/package.json +9 -9
  63. package/templates/apps/api-governance/package.json +8 -8
  64. package/templates/apps/api-kv/package.json +8 -8
  65. package/templates/apps/api-moderation/package.json +8 -8
  66. package/templates/apps/api-observability/package.json +8 -8
  67. package/templates/apps/api-ratelimit/package.json +8 -8
  68. package/templates/apps/api-rbac/package.json +8 -8
  69. package/templates/apps/api-rest/package.json +7 -7
  70. package/templates/apps/api-saas/package.json +11 -11
  71. package/templates/apps/api-saas-starter/package.json +10 -10
  72. package/templates/apps/api-search/package.json +8 -8
  73. package/templates/apps/api-status/package.json +8 -8
  74. package/templates/apps/api-versioning/package.json +8 -8
  75. package/templates/apps/api-webhooks/package.json +9 -9
  76. package/templates/apps/changelog/package.json +6 -6
  77. package/templates/apps/edge-functions/package.json +2 -2
  78. package/templates/apps/frontend-admin/package.json +8 -8
  79. package/templates/apps/frontend-app/package.json +9 -9
  80. package/templates/apps/frontend-auth/package.json +8 -8
  81. package/templates/apps/frontend-blank/package.json +7 -7
  82. package/templates/apps/frontend-cms/package.json +9 -9
  83. package/templates/apps/frontend-collab/package.json +10 -10
  84. package/templates/apps/frontend-contact/package.json +7 -7
  85. package/templates/apps/frontend-dashboard/package.json +7 -7
  86. package/templates/apps/frontend-docs/package.json +7 -7
  87. package/templates/apps/frontend-i18n/package.json +6 -6
  88. package/templates/apps/frontend-landing/package.json +7 -7
  89. package/templates/apps/frontend-portal/package.json +8 -8
  90. package/templates/apps/frontend-saas/package.json +8 -8
  91. package/templates/apps/frontend-spa/package.json +7 -7
  92. package/templates/apps/frontend-ssr/package.json +7 -7
  93. package/templates/apps/frontend-ssr-api/package.json +8 -8
  94. package/templates/apps/frontend-static-blog/package.json +6 -6
  95. package/templates/apps/frontend-status/package.json +8 -8
  96. package/templates/apps/mobile-app/package.json +4 -4
  97. package/dist/apiBuild-BWo8KI6n.js +0 -2
  98. package/dist/appGraph-KGDPTuTy.js +0 -110
  99. package/dist/appGraph-zuMGKVYX.js +0 -2
  100. package/dist/doctorCommand-BmovAwb7.js +0 -2
  101. package/dist/inspect-DUze25t0.js +0 -2
  102. package/dist/manifestBuild-j0n109tt.js +0 -2
  103. package/dist/serveCommand-C_WI4TTG.js +0 -2
  104. package/dist/updateCommand-D91-TZ7E.js +0 -2
  105. package/dist/webDev-B79ji8M5.js +0 -2
@@ -1,6 +1,6 @@
1
1
  import { i as e, t } from "./subcommandNames-DpYs3DXr.js";
2
2
  import { t as n } from "./cliError-BmdYnghb.js";
3
- import { c as r, i, o as a, z as o } from "./dev-1yu42ubu.js";
3
+ import { c as r, i, o as a, z as o } from "./dev-C0cbqysu.js";
4
4
  import { n as s, t as c } from "./cliArgs-D4p8n7EE.js";
5
5
  import { r as l } from "./dialectDriver-czCHYpeH.js";
6
6
  import { i as u, n as d, r as f, t as p } from "./dataProfile-Du3ztYxv.js";
@@ -8,13 +8,13 @@ import { o as m, t as h } from "./inspectFetch-EMuhTG_9.js";
8
8
  import { r as g } from "./dbCommand-Bf7Cy0mn.js";
9
9
  import { resolve as _ } from "node:path";
10
10
  import { createLogger as v } from "@voltro/logger";
11
- import { DATA_TRANSFERS_TABLE as y, REPLACE_IN_PROGRESS_TABLE as b, _voltroDataTransfersTable as x, _voltroReplaceInProgressTable as S, connectionIdentity as C, derivedRowId as ee, ensureTableRegistered as te, normaliseTarget as ne, sameDatabase as re, streamTable as ie } from "@voltro/database";
12
- import { Cause as w, Effect as T, Exit as ae, Option as oe, Stream as se } from "effect";
13
- import { SqlClient as ce } from "@effect/sql";
14
- import { declaredSnapshot as le, fingerprintSchema as ue, introspectSchema as de } from "@voltro/database/sql";
15
- import { STORAGE_REFS_TABLE as fe, resolveStorageProvider as E } from "@voltro/plugin-storage";
11
+ import { DATA_TRANSFERS_TABLE as y, REPLACE_IN_PROGRESS_TABLE as b, _voltroDataTransfersTable as x, _voltroReplaceInProgressTable as S, connectionIdentity as C, derivedRowId as ee, ensureTableRegistered as w, normaliseTarget as te, sameDatabase as ne, streamTable as re } from "@voltro/database";
12
+ import { Cause as T, Effect as E, Exit as ie, Option as ae, Stream as oe } from "effect";
13
+ import { SqlClient as se } from "@effect/sql";
14
+ import { declaredSnapshot as ce, fingerprintSchema as le, introspectSchema as ue } from "@voltro/database/sql";
15
+ import { STORAGE_REFS_TABLE as de, appStorageProvider as fe, configuredStorageProvider as D } from "@voltro/plugin-storage";
16
16
  import { createHash as pe } from "node:crypto";
17
- import { ASSETS_DIR as D, ASSET_INDEX_FILE as O, BundleError as me, asImportError as he, assessLiveImport as ge, backupArtifactName as k, backupCommand as _e, captureAssetsToCas as ve, classificationFromSnapshot as ye, decryptStream as A, encryptStream as be, packBundle as xe, peekBundle as j, previewMasking as Se, restoreAssetsFromCas as Ce, restoreCommand as we, runExport as Te, runImport as Ee, runNativeStep as M, storageAssetSink as De, storageAssetSource as Oe, storageBlobSink as ke, storageBlobSource as Ae, unpackBundle as je, unpackBundleToDir as Me } from "@voltro/data-transfer";
17
+ import { ASSETS_DIR as O, ASSET_INDEX_FILE as k, BundleError as me, asImportError as he, assessLiveImport as ge, backupArtifactName as A, backupCommand as _e, captureAssetsToCas as ve, classificationFromSnapshot as ye, decryptStream as j, encryptStream as be, packBundle as xe, peekBundle as M, previewMasking as Se, restoreAssetsFromCas as Ce, restoreCommand as we, runExport as Te, runImport as Ee, runNativeStep as N, storageAssetSink as De, storageAssetSource as Oe, storageBlobSink as ke, storageBlobSource as Ae, unpackBundle as je, unpackBundleToDir as Me } from "@voltro/data-transfer";
18
18
  import { request as Ne } from "node:http";
19
19
  import { request as Pe } from "node:https";
20
20
  //#region src/longRequest.ts
@@ -26,7 +26,7 @@ var Fe = /* @__PURE__ */ new Set([
26
26
  "ENOTFOUND",
27
27
  "ECONNRESET",
28
28
  "EAI_AGAIN"
29
- ]), N = class extends Error {
29
+ ]), P = class extends Error {
30
30
  url;
31
31
  cause;
32
32
  constructor(e, t) {
@@ -39,13 +39,13 @@ var Fe = /* @__PURE__ */ new Set([
39
39
  })();
40
40
  super(`the instance at ${n} is not answering (${t.code ?? "connect failed"}).`), this.url = e, this.cause = t, this.name = "InstanceUnreachable";
41
41
  }
42
- }, P = class extends Error {
42
+ }, F = class extends Error {
43
43
  elapsedMs;
44
44
  url;
45
45
  constructor(e, t) {
46
46
  super(`no response after ${Math.round(e / 1e3)}s`), this.elapsedMs = e, this.url = t, this.name = "LongRequestTimeout";
47
47
  }
48
- }, F = async (e, t, n, r) => {
48
+ }, I = async (e, t, n, r) => {
49
49
  let i = new URL(e), a = i.protocol === "https:" ? Pe : Ne, o = Date.now();
50
50
  return await new Promise((s, c) => {
51
51
  let l = a({
@@ -64,8 +64,8 @@ var Fe = /* @__PURE__ */ new Set([
64
64
  })), e.on("error", c);
65
65
  });
66
66
  if (r?.timeoutMs !== void 0 && r.timeoutMs > 0 && l.setTimeout(r.timeoutMs, () => {
67
- l.destroy(new P(Date.now() - o, e));
68
- }), l.on("error", (t) => c(Fe.has(t.code ?? "") ? new N(e, t) : t)), typeof t == "string" || Buffer.isBuffer(t)) {
67
+ l.destroy(new F(Date.now() - o, e));
68
+ }), l.on("error", (t) => c(Fe.has(t.code ?? "") ? new P(e, t) : t)), typeof t == "string" || Buffer.isBuffer(t)) {
69
69
  l.end(t);
70
70
  return;
71
71
  }
@@ -78,7 +78,7 @@ var Fe = /* @__PURE__ */ new Set([
78
78
  }
79
79
  })();
80
80
  });
81
- }, I = (e) => `${e.message}\n That address came from --api-url (or VOLTRO_API_URL) — it is the running instance, not the database.\n Nothing was sent, so nothing was imported. Check the instance is up and reachable from here\n (a VPN, an ingress or a stopped deployment are the usual three), e.g. curl -sS ${e.url}/_voltro/inspect/app`, Ie = (e, t) => `the instance did not answer within ${Math.round(e.elapsedMs / 1e3)}s. This is a client-side deadline, not a failure on the server: the upload itself finished long before, and the response arrives only when the import does. The instance is very probably STILL IMPORTING and will finish.\n` + (t === "replace" ? " Do NOT simply re-run: --mode replace empties the target first, so a second run started while the first is mid-flight would empty it under the first one. Check the instance's log for the import's completion, and check the target's row counts, before deciding." : ` Re-running the same bundle is safe once the first run has finished (--mode ${t} is idempotent), but check the instance's log first — the work may already be done.`) + "\n To keep a deadline anyway, pass --timeout <seconds>; the default is to wait.", Le = 16777216, Re = async function* (e, t) {
81
+ }, L = (e) => `${e.message}\n That address came from --api-url (or VOLTRO_API_URL) — it is the running instance, not the database.\n Nothing was sent, so nothing was imported. Check the instance is up and reachable from here\n (a VPN, an ingress or a stopped deployment are the usual three), e.g. curl -sS ${e.url}/_voltro/inspect/app`, Ie = (e, t) => `the instance did not answer within ${Math.round(e.elapsedMs / 1e3)}s. This is a client-side deadline, not a failure on the server: the upload itself finished long before, and the response arrives only when the import does. The instance is very probably STILL IMPORTING and will finish.\n` + (t === "replace" ? " Do NOT simply re-run: --mode replace empties the target first, so a second run started while the first is mid-flight would empty it under the first one. Check the instance's log for the import's completion, and check the target's row counts, before deciding." : ` Re-running the same bundle is safe once the first run has finished (--mode ${t} is idempotent), but check the instance's log first — the work may already be done.`) + "\n To keep a deadline anyway, pass --timeout <seconds>; the default is to wait.", Le = 16777216, Re = async function* (e, t) {
82
82
  let n = [], r = 0, i = 0, a = function* (e) {
83
83
  let t = Buffer.concat(n);
84
84
  n = [], r = 0;
@@ -131,7 +131,7 @@ var Fe = /* @__PURE__ */ new Set([
131
131
  bytes: t,
132
132
  resumedFrom: e.alreadyHeld
133
133
  };
134
- }, L = "voltro-backup-stamp.json", Ve = (e) => ({
134
+ }, R = "voltro-backup-stamp.json", Ve = (e) => ({
135
135
  stampVersion: 1,
136
136
  dialect: e.dialect,
137
137
  schemaFingerprint: e.schemaFingerprint,
@@ -165,7 +165,7 @@ var Fe = /* @__PURE__ */ new Set([
165
165
  }, Ue = (e) => {
166
166
  let { stamp: t, currentDialect: n, currentFingerprint: r } = e;
167
167
  if (t === null) return {
168
- warn: `no ${L} beside the dump — an older/handmade backup. Cannot verify dialect or schema version; make sure this dump is a ${n} dump.`,
168
+ warn: `no ${R} beside the dump — an older/handmade backup. Cannot verify dialect or schema version; make sure this dump is a ${n} dump.`,
169
169
  info: []
170
170
  };
171
171
  let i = [`backup produced by @voltro/cli ${t.voltroVersion} at ${t.createdAt}`, `schema fingerprint: ${t.schemaFingerprint ?? "<none recorded>"}`];
@@ -179,7 +179,7 @@ var Fe = /* @__PURE__ */ new Set([
179
179
  }, We = async (e, t) => {
180
180
  let n = ee("dimp", `${t.direction}-${t.artifact}-${Date.now()}-${Math.random()}`);
181
181
  try {
182
- return te(x), await e.insert(y, {
182
+ return w(x), await e.insert(y, {
183
183
  id: n,
184
184
  direction: t.direction,
185
185
  startedAt: /* @__PURE__ */ new Date(),
@@ -202,43 +202,63 @@ var Fe = /* @__PURE__ */ new Set([
202
202
  recorded: !1
203
203
  };
204
204
  }
205
- }, R = async (e, t, n) => {
205
+ }, z = async (e, t, n) => {
206
206
  t.recorded && await e.update(y, t.runId, {
207
207
  finishedAt: /* @__PURE__ */ new Date(),
208
208
  failure: n.failure ?? null,
209
209
  ...n.assets === void 0 ? {} : { rowsWritten: n.assets }
210
210
  }).then(() => void 0, () => void 0);
211
211
  }, Ge = async (e, t) => {
212
- let n = ee("repl", `restore-${t.artifact}-${Date.now()}-${Math.random()}`);
212
+ let n = ee("repl", `restore-${t.artifact}-${Date.now()}-${Math.random()}`), r = {
213
+ id: n,
214
+ startedAt: /* @__PURE__ */ new Date(),
215
+ kind: "restore",
216
+ tables: null,
217
+ capture: t.artifact,
218
+ via: "cli"
219
+ };
213
220
  try {
214
- te(S), await e.insert(b, {
215
- id: n,
216
- startedAt: /* @__PURE__ */ new Date(),
217
- kind: "restore",
218
- tables: null,
219
- capture: t.artifact,
220
- via: "cli"
221
- });
221
+ w(S), await e.insert(b, r);
222
222
  } catch {
223
223
  return;
224
224
  }
225
- return async () => {
226
- await e.deleteMany(b, { where: {
227
- column: "id",
228
- op: "eq",
229
- value: n
230
- } }).then(() => void 0, () => void 0);
225
+ let i = async () => (await e.query({
226
+ table: b,
227
+ predicate: void 0,
228
+ order: [],
229
+ take: void 0,
230
+ skip: void 0,
231
+ projection: void 0
232
+ })).some((e) => String(e.id ?? "") === n);
233
+ return {
234
+ reassert: async () => {
235
+ try {
236
+ if (await i()) return "held";
237
+ } catch {}
238
+ try {
239
+ return w(S), await e.insert(b, r), "rewritten";
240
+ } catch {
241
+ return "lost";
242
+ }
243
+ },
244
+ clear: async () => {
245
+ await e.deleteMany(b, { where: {
246
+ column: "id",
247
+ op: "eq",
248
+ value: n
249
+ } }).then(() => void 0, () => void 0);
250
+ }
231
251
  };
232
252
  }, Ke = async (e) => {
233
- let t = await T.runPromiseExit(e);
234
- if (ae.isSuccess(t)) return;
235
- let n = w.failureOption(t.cause);
236
- if (oe.isSome(n)) {
253
+ let t = await E.runPromiseExit(e);
254
+ if (ie.isSuccess(t)) return;
255
+ let n = T.failureOption(t.cause);
256
+ if (ae.isSome(n)) {
237
257
  let e = n.value;
238
258
  return String(e?.message ?? e);
239
259
  }
240
- return w.pretty(t.cause);
241
- }, z = (e) => {
260
+ return T.pretty(t.cause);
261
+ }, B = (e) => {
242
262
  try {
243
263
  let t = new URL(e), n = t.pathname.replace(/^\//, "");
244
264
  return `${t.hostname.toLowerCase()}:${t.port || "(default)"}/${n}`;
@@ -251,7 +271,7 @@ var Fe = /* @__PURE__ */ new Set([
251
271
  ok: !1,
252
272
  error: "no drill target — pass `--drill-url <url>` or set `DRILL_DB_URL`. The drill restores into a THROWAWAY database (never the live one), so it needs its own connection."
253
273
  };
254
- let n = z(t);
274
+ let n = B(t);
255
275
  return e.liveKeys.some((e) => e === n) ? {
256
276
  ok: !1,
257
277
  error: `drill target (${n}) is the LIVE database — a restore drill must target a throwaway DB, never production. It would --clean and overwrite it.`
@@ -274,7 +294,7 @@ var Fe = /* @__PURE__ */ new Set([
274
294
  pass: !0,
275
295
  lines: [`PASS — restored ${r} table(s); schema fingerprint matches the backup stamp (${n.slice(0, 12)}).`]
276
296
  };
277
- }, B = v({ scope: "voltro:data" }), Ye = async () => {
297
+ }, V = v({ scope: "voltro:data" }), Ye = async () => {
278
298
  try {
279
299
  let { createRequire: e } = await import("node:module"), { join: t } = await import("node:path"), { readFileSync: n } = await import("node:fs"), r = e(t(process.cwd(), "package.json")).resolve("@voltro/cli/package.json");
280
300
  return JSON.parse(n(r, "utf8")).version ?? "unknown";
@@ -283,14 +303,14 @@ var Fe = /* @__PURE__ */ new Set([
283
303
  }
284
304
  }, Xe = async (e) => {
285
305
  try {
286
- return ue(await tt(e));
306
+ return le(await tt(e));
287
307
  } catch {
288
308
  return null;
289
309
  }
290
- }, V = (e) => {
310
+ }, H = (e) => {
291
311
  if (e.event !== "done") return;
292
312
  let t = e.total === void 0 ? "" : ` / ${e.total}`;
293
- B.info(`${e.phase} [${e.index + 1}/${e.tableCount}] ${e.table}`, { rows: `${e.rowsDone}${t}` });
313
+ V.info(`${e.phase} [${e.index + 1}/${e.tableCount}] ${e.table}`, { rows: `${e.rowsDone}${t}` });
294
314
  }, Ze = async (e) => {
295
315
  let t = (e) => e?.meta?.databaseId;
296
316
  if (e) {
@@ -312,20 +332,20 @@ var Fe = /* @__PURE__ */ new Set([
312
332
  }
313
333
  return null;
314
334
  }, Qe = async (e) => {
315
- let t = e.includes("--allow-live"), n = t ? null : await Ze(H(e, "--api-url")), r = C({
316
- dialect: W(),
335
+ let t = e.includes("--allow-live"), n = t ? null : await Ze(U(e, "--api-url")), r = C({
336
+ dialect: G(),
317
337
  ...a()
318
- }), i = ne({
319
- dialect: W(),
338
+ }), i = te({
339
+ dialect: G(),
320
340
  ...a()
321
341
  }), { refuse: o, message: s } = ge({
322
342
  liveInstance: n?.label ?? null,
323
343
  allowLive: t,
324
- sameTarget: re(r, n?.databaseId),
344
+ sameTarget: ne(r, n?.databaseId),
325
345
  ...i === void 0 ? {} : { targetLabel: `${i.host}:${i.port}/${i.database}` }
326
346
  });
327
- return !o || (B.error(s ?? "refusing: live instance detected"), !1);
328
- }, H = s, $e = [
347
+ return !o || (V.error(s ?? "refusing: live instance detected"), !1);
348
+ }, U = s, $e = [
329
349
  "--api-url",
330
350
  "--bundle-key",
331
351
  "--compression",
@@ -345,42 +365,42 @@ var Fe = /* @__PURE__ */ new Set([
345
365
  "--timeout",
346
366
  "--tenant",
347
367
  "--token"
348
- ], U = (e) => c(e, $e), W = () => {
368
+ ], W = (e) => c(e, $e), G = () => {
349
369
  let e = (process.env.DB_DIALECT ?? "postgres").toLowerCase();
350
370
  if (e === "memory") throw new n("voltro data: requires a real dialect, not DB_DIALECT=memory.");
351
371
  return e;
352
372
  }, et = async (e, t) => {
353
373
  let n = (await l(e)).makeSqlLayer(t);
354
- return T.runPromise(ce.SqlClient.pipe(T.flatMap(de), T.provide(n)));
374
+ return E.runPromise(se.SqlClient.pipe(E.flatMap(ue), E.provide(n)));
355
375
  }, tt = (e) => et(e, a()), nt = () => {
356
376
  let e = a(), t = [];
357
- return e.url && t.push(z(e.url)), (e.host || e.database) && t.push(`${(e.host ?? "localhost").toLowerCase()}:${e.port ?? "(default)"}/${e.database ?? ""}`), t;
358
- }, G = async () => {
377
+ return e.url && t.push(B(e.url)), (e.host || e.database) && t.push(`${(e.host ?? "localhost").toLowerCase()}:${e.port ?? "(default)"}/${e.database ?? ""}`), t;
378
+ }, K = async () => {
359
379
  let e = process.cwd(), t = await r(e);
360
380
  if (!t) throw new n("voltro data: no app.config.ts found in the current directory.");
361
- let a = await i(t, void 0), o = W();
381
+ let a = await i(t, void 0), o = G();
362
382
  return {
363
383
  store: a,
364
384
  snapshot: await tt(o),
365
385
  dialect: o
366
386
  };
367
- }, K = (e) => ie(e, {
368
- table: fe,
387
+ }, q = (e) => re(e, {
388
+ table: de,
369
389
  chunkSize: 500
370
- }).pipe(se.map((e) => ({
390
+ }).pipe(oe.map((e) => ({
371
391
  key: String(e.key),
372
392
  contentType: String(e.contentType ?? "application/octet-stream"),
373
393
  size: Number(e.size ?? 0)
374
- }))), q = (e) => !!e && e.endsWith(".vbundle"), J = (e) => H(e, "--passphrase") ?? process.env.VOLTRO_BUNDLE_KEY, rt = (e) => e.includes("--encrypt") || H(e, "--passphrase") !== void 0 || process.env.VOLTRO_BUNDLE_KEY !== void 0, it = async (e, t) => {
394
+ }))), J = (e) => !!e && e.endsWith(".vbundle"), Y = (e) => U(e, "--passphrase") ?? process.env.VOLTRO_BUNDLE_KEY, rt = (e) => e.includes("--encrypt") || U(e, "--passphrase") !== void 0 || process.env.VOLTRO_BUNDLE_KEY !== void 0, it = async (e, t) => {
375
395
  let { createWriteStream: n } = await import("node:fs"), { pipeline: r } = await import("node:stream/promises"), { Readable: i } = await import("node:stream");
376
396
  await r(i.from(e), n(t));
377
- }, Y = (e) => ({ async *[Symbol.asyncIterator]() {
397
+ }, X = (e) => ({ async *[Symbol.asyncIterator]() {
378
398
  let { createReadStream: t } = await import("node:fs");
379
399
  for await (let n of t(e)) yield n instanceof Uint8Array ? n : new Uint8Array(n);
380
400
  } }), at = async (e, t) => {
381
401
  if (t !== void 0 || e === void 0) return null;
382
402
  try {
383
- let { resolve: t, join: n } = await import("node:path"), r = await import("node:fs/promises"), i = t(process.cwd(), e), a = q(e) ? (await j(Y(i), ["manifest.json"])).get("manifest.json") : await r.readFile(n(i, "manifest.json"));
403
+ let { resolve: t, join: n } = await import("node:path"), r = await import("node:fs/promises"), i = t(process.cwd(), e), a = J(e) ? (await M(X(i), ["manifest.json"])).get("manifest.json") : await r.readFile(n(i, "manifest.json"));
384
404
  if (a === void 0) return null;
385
405
  let o = (JSON.parse(Buffer.from(a).toString("utf8")).tables ?? []).map((e) => e.name).filter((e) => typeof e == "string");
386
406
  return o.length > 0 ? o : null;
@@ -388,7 +408,7 @@ var Fe = /* @__PURE__ */ new Set([
388
408
  return null;
389
409
  }
390
410
  }, ot = (e) => {
391
- let t = H(e, "--max-request-seconds") ?? process.env.VOLTRO_MAX_REQUEST_SECONDS;
411
+ let t = U(e, "--max-request-seconds") ?? process.env.VOLTRO_MAX_REQUEST_SECONDS;
392
412
  if (t === void 0) return { pollMs: 2e3 };
393
413
  let r = Number(t);
394
414
  if (!Number.isFinite(r) || r <= 0) throw new n(`--max-request-seconds expects a positive number of seconds, got '${t}'`);
@@ -428,8 +448,8 @@ var Fe = /* @__PURE__ */ new Set([
428
448
  e.log.info(` downloading — ${r}/${i ?? "?"} bytes`);
429
449
  }
430
450
  return new Uint8Array(Buffer.concat(n));
431
- }, X = "transfers", lt = (e) => (e ?? "").split(",").map((e) => e.trim()).filter(Boolean), ut = (e, t) => {
432
- let r = H(e, "--tenant"), i = H(e, "--tables"), a = H(e, "--exclude");
451
+ }, Z = "transfers", lt = (e) => (e ?? "").split(",").map((e) => e.trim()).filter(Boolean), ut = (e, t) => {
452
+ let r = U(e, "--tenant"), i = U(e, "--tables"), a = U(e, "--exclude");
433
453
  if (a !== void 0) {
434
454
  if (i !== void 0) throw new n("voltro data export: --exclude and --tables are two ways to say the same thing; use one.");
435
455
  if (r !== void 0) throw new n("voltro data export: --exclude does not apply to --tenant, whose table set is derived from the tenant closure.");
@@ -449,7 +469,7 @@ var Fe = /* @__PURE__ */ new Set([
449
469
  } : { kind: "all" };
450
470
  }, dt = async () => {
451
471
  let e = await g(process.cwd());
452
- return ye(le(e));
472
+ return ye(ce(e));
453
473
  }, ft = "voltro/tenant", pt = async () => {
454
474
  let e = (await g(process.cwd())).filter((e) => (e.appliedMixins ?? []).some((e) => e.id === ft)).map((e) => e.tableName);
455
475
  return e.length > 0 ? e : void 0;
@@ -467,7 +487,7 @@ var Fe = /* @__PURE__ */ new Set([
467
487
  for (let t of e.unclassified) console.log(` ${t}`);
468
488
  } else console.log("\n ✓ every exported column is classified — safe to run.");
469
489
  }, ht = async (e) => {
470
- let { resolve: t, join: r } = await import("node:path"), i = await import("node:fs/promises"), a = H(e.args, "--chunk-size"), o = a === void 0 ? Le : Math.round(Number(a) * 1024 * 1024);
490
+ let { resolve: t, join: r } = await import("node:path"), i = await import("node:fs/promises"), a = U(e.args, "--chunk-size"), o = a === void 0 ? Le : Math.round(Number(a) * 1024 * 1024);
471
491
  if (!Number.isFinite(o) || o <= 0) throw new n(`--chunk-size expects a positive number of megabytes, got '${String(a)}'`);
472
492
  let s = e.stream[Symbol.asyncIterator](), c = [], l = 0, u = !1;
473
493
  for (; l <= o;) {
@@ -482,11 +502,11 @@ var Fe = /* @__PURE__ */ new Set([
482
502
  kind: "small",
483
503
  body: Buffer.concat(c)
484
504
  };
485
- let d = t(process.cwd(), e.bundleDir), f = ze(q(e.bundleDir) ? await i.readFile(d) : await i.readFile(r(d, "manifest.json"))), p = `up-${f.slice(0, 32)}`, m = await F(e.url, Buffer.alloc(0), {
505
+ let d = t(process.cwd(), e.bundleDir), f = ze(J(e.bundleDir) ? await i.readFile(d) : await i.readFile(r(d, "manifest.json"))), p = `up-${f.slice(0, 32)}`, m = await I(e.url, Buffer.alloc(0), {
486
506
  ...e.headers,
487
507
  "x-import-upload-id": p,
488
508
  "x-import-probe": "1"
489
- }, Q(e.args)), h = m.status === 200 ? Number(JSON.parse(m.body.toString("utf8")).bytes ?? 0) : 0;
509
+ }, $(e.args)), h = m.status === 200 ? Number(JSON.parse(m.body.toString("utf8")).bytes ?? 0) : 0;
490
510
  h > 0 && e.log.info("api import: resuming a chunked upload the instance already holds", { bytes: h });
491
511
  let g = (async function* () {
492
512
  for (let e of c) yield e;
@@ -509,7 +529,7 @@ var Fe = /* @__PURE__ */ new Set([
509
529
  e.log.info("api import: upload done — the instance is importing now. This request stays open until it finishes, which on a full bundle is minutes, and nothing more is printed until then. It is not a hang; the instance logs the import itself.");
510
530
  },
511
531
  target: { send: async (t, n) => {
512
- let r = await F(e.url, t, n, Q(e.args)), i = {};
532
+ let r = await I(e.url, t, n, $(e.args)), i = {};
513
533
  try {
514
534
  i = JSON.parse(r.body.toString("utf8") || "{}");
515
535
  } catch {}
@@ -531,9 +551,9 @@ var Fe = /* @__PURE__ */ new Set([
531
551
  body: Buffer.from(JSON.stringify(v.body))
532
552
  }
533
553
  };
534
- }, gt = (e) => `--mode replace with --no-atomic against a ${e ? "RUNNING instance" : "live database"}: the target is empty between the delete and the load, and anything the application writes in that window can collide with a row from the bundle — or survive the import as a row the bundle never carried. Drop --no-atomic to run the whole load in one transaction (concurrent writers then wait instead of racing), or stop the traffic for the duration.`, Z = (e, t) => e.includes("--no-atomic") ? !1 : e.includes("--atomic") || t === "replace", _t = (e, t, n) => {
554
+ }, gt = (e) => `--mode replace with --no-atomic against a ${e ? "RUNNING instance" : "live database"}: the target is empty between the delete and the load, and anything the application writes in that window can collide with a row from the bundle — or survive the import as a row the bundle never carried. Drop --no-atomic to run the whole load in one transaction (concurrent writers then wait instead of racing), or stop the traffic for the duration.`, Q = (e, t) => e.includes("--no-atomic") ? !1 : e.includes("--atomic") || t === "replace", _t = (e, t, n) => {
535
555
  if (t !== "replace" || e.includes("--no-rollback")) return;
536
- let r = H(e, "--rollback-dir");
556
+ let r = U(e, "--rollback-dir");
537
557
  return r === void 0 ? o(n) : _(r);
538
558
  }, vt = (e, t, n) => {
539
559
  let r = _t(e, t, n);
@@ -542,56 +562,56 @@ var Fe = /* @__PURE__ */ new Set([
542
562
  recordInterruption: !0,
543
563
  via: "direct"
544
564
  };
545
- }, Q = (e) => {
546
- let t = H(e, "--timeout");
565
+ }, $ = (e) => {
566
+ let t = U(e, "--timeout");
547
567
  if (t === void 0) return {};
548
568
  let r = Number(t);
549
569
  if (!Number.isFinite(r) || r <= 0) throw new n(`--timeout expects a positive number of seconds, got '${t}'`);
550
570
  return { timeoutMs: Math.round(r * 1e3) };
551
571
  }, yt = async (e) => {
552
- let t = H(e, "--target") === "api", n = H(e, "--bundle-key"), r = U(e);
553
- if (!r && !(t && n)) return B.error("usage: voltro data export <outDir> [--target direct|api] [--api-url <url>] [--token <secret>] [--timeout <seconds>] [--profile <name>] [--tenant <id>] [--tables a,b] [--exclude a,b] [--bundle-key <storage-key>] [--assets] [--compression zstd|gzip|none] [--consistency live|snapshot] [--dry-run]"), 1;
572
+ let t = U(e, "--target") === "api", n = U(e, "--bundle-key"), r = W(e);
573
+ if (!r && !(t && n)) return V.error("usage: voltro data export <outDir> [--target direct|api] [--api-url <url>] [--token <secret>] [--timeout <seconds>] [--profile <name>] [--tenant <id>] [--tables a,b] [--exclude a,b] [--bundle-key <storage-key>] [--assets] [--compression zstd|gzip|none] [--consistency live|snapshot] [--dry-run]"), 1;
554
574
  if (t) {
555
- let t = H(e, "--api-url");
556
- if (!t) return B.error("--target api requires --api-url <url> (the running instance)"), 1;
557
- let i = H(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
558
- if (!i) return B.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
559
- let a = H(e, "--tables"), o = H(e, "--exclude");
560
- if (o !== void 0 && a !== void 0) return B.error("voltro data export: --exclude and --tables are two ways to say the same thing; use one."), 1;
575
+ let t = U(e, "--api-url");
576
+ if (!t) return V.error("--target api requires --api-url <url> (the running instance)"), 1;
577
+ let i = U(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
578
+ if (!i) return V.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
579
+ let a = U(e, "--tables"), o = U(e, "--exclude");
580
+ if (o !== void 0 && a !== void 0) return V.error("voltro data export: --exclude and --tables are two ways to say the same thing; use one."), 1;
561
581
  let s = {
562
- ...H(e, "--profile") ? { profile: H(e, "--profile") } : {},
563
- ...H(e, "--tenant") ? { tenant: H(e, "--tenant") } : {},
582
+ ...U(e, "--profile") ? { profile: U(e, "--profile") } : {},
583
+ ...U(e, "--tenant") ? { tenant: U(e, "--tenant") } : {},
564
584
  ...a ? { tables: a.split(",").map((e) => e.trim()).filter(Boolean) } : {},
565
585
  ...o ? { exclude: o.split(",").map((e) => e.trim()).filter(Boolean) } : {},
566
- ...H(e, "--consistency") === "snapshot" ? { consistency: "snapshot" } : {},
567
- ...H(e, "--compression") ? { compression: H(e, "--compression") } : {},
586
+ ...U(e, "--consistency") === "snapshot" ? { consistency: "snapshot" } : {},
587
+ ...U(e, "--compression") ? { compression: U(e, "--compression") } : {},
568
588
  ...e.includes("--assets") ? { assets: !0 } : {},
569
589
  ...n ? { bundleKey: n } : {}
570
590
  }, c = ot(e), l;
571
591
  try {
572
- let n = await F(`${t.replace(/\/+$/, "")}/_voltro/admin/export`, JSON.stringify(s), {
592
+ let n = await I(`${t.replace(/\/+$/, "")}/_voltro/admin/export`, JSON.stringify(s), {
573
593
  "content-type": "application/json",
574
594
  authorization: `Bearer ${i}`
575
- }, c.perRequest ?? Q(e));
576
- if (n.status < 200 || n.status >= 300) return B.error(`api export failed: HTTP ${n.status} — ${n.body.toString("utf8")}`), 1;
595
+ }, c.perRequest ?? $(e));
596
+ if (n.status < 200 || n.status >= 300) return V.error(`api export failed: HTTP ${n.status} — ${n.body.toString("utf8")}`), 1;
577
597
  l = JSON.parse(n.body.toString("utf8"));
578
598
  } catch (e) {
579
- if (e instanceof P) return B.error(`api export: the instance did not answer within ${Math.round(e.elapsedMs / 1e3)}s. That is a client-side deadline. Nothing was written locally; re-run, or raise --timeout.`), 1;
580
- if (e instanceof N) return B.error(`api export: ${I(e)}`), 1;
599
+ if (e instanceof F) return V.error(`api export: the instance did not answer within ${Math.round(e.elapsedMs / 1e3)}s. That is a client-side deadline. Nothing was written locally; re-run, or raise --timeout.`), 1;
600
+ if (e instanceof P) return V.error(`api export: ${L(e)}`), 1;
581
601
  throw e;
582
602
  }
583
- if (e.includes("--detach")) return B.info(`api export: started as ${l.runId}. NOT waiting for it.\n The outcome is not known yet — read it with: voltro data ${X} --target api --api-url ${t}`), 0;
584
- if (l.recorded === !1) return B.warn(`api export: started as ${l.runId}, but this instance could not record the run — so its outcome\n cannot be read back. Run \`voltro db apply\` against it so the next one is watchable.`), 0;
603
+ if (e.includes("--detach")) return V.info(`api export: started as ${l.runId}. NOT waiting for it.\n The outcome is not known yet — read it with: voltro data ${Z} --target api --api-url ${t}`), 0;
604
+ if (l.recorded === !1) return V.warn(`api export: started as ${l.runId}, but this instance could not record the run — so its outcome\n cannot be read back. Run \`voltro db apply\` against it so the next one is watchable.`), 0;
585
605
  let p = await d({
586
606
  read: () => st(t, i, l.runId),
587
607
  onTick: (e) => {
588
- B.info(f(e));
608
+ V.info(f(e));
589
609
  },
590
610
  intervalMs: c.pollMs,
591
611
  ...c.total === void 0 ? {} : { timeoutMs: c.total }
592
612
  }), m = u(p);
593
- if (m !== 0) return B.error(m === 1 ? `api export FAILED (${l.runId}): ${String(p?.failure ?? "no reason recorded")}` : `api export: no outcome visible for ${l.runId}. The run is not cancelled; it is simply not readable from here.`), m;
594
- if (n) return B.info("api export complete (pushed to storage)", {
613
+ if (m !== 0) return V.error(m === 1 ? `api export FAILED (${l.runId}): ${String(p?.failure ?? "no reason recorded")}` : `api export: no outcome visible for ${l.runId}. The run is not cancelled; it is simply not readable from here.`), m;
614
+ if (n) return V.info("api export complete (pushed to storage)", {
595
615
  via: t,
596
616
  runId: l.runId,
597
617
  bundleKey: n,
@@ -602,12 +622,12 @@ var Fe = /* @__PURE__ */ new Set([
602
622
  apiUrl: t,
603
623
  secret: i,
604
624
  runId: l.runId,
605
- log: B,
625
+ log: V,
606
626
  ...c.perRequest ? { perRequest: c.perRequest } : {}
607
627
  });
608
628
  return g === null ? 1 : (await Me((async function* () {
609
629
  yield g;
610
- })(), h(process.cwd(), r)), B.info("api export complete (downloaded from the running instance)", {
630
+ })(), h(process.cwd(), r)), V.info("api export complete (downloaded from the running instance)", {
611
631
  outDir: r,
612
632
  runId: l.runId,
613
633
  tables: p?.tablesWritten ?? 0,
@@ -615,11 +635,13 @@ var Fe = /* @__PURE__ */ new Set([
615
635
  bytes: g.byteLength
616
636
  }), 0);
617
637
  }
618
- if (!r) return B.error("a <outDir> is required for a direct export"), 1;
619
- let i = H(e, "--profile"), a = i ? await p(i, { allowPath: !0 }) : {}, { store: o, snapshot: s, dialect: c } = await G(), l = e.includes("--assets") || a.assets === !0, m = l ? E({}) : void 0, h = H(e, "--compression") ?? a.compression, g = H(e, "--consistency") === "snapshot" ? "snapshot" : a.consistency ?? "live", _ = a.masking, v = a.subset, y = a.scope ?? ut(e, s.tables.map((e) => e.name)), b = _ ? await dt() : void 0, x = y.kind === "tenant" ? await pt() : void 0, S = x ? { tenantTables: x } : {};
638
+ if (!r) return V.error("a <outDir> is required for a direct export"), 1;
639
+ let i = U(e, "--profile"), a = i ? await p(i, { allowPath: !0 }) : {}, { store: o, snapshot: s, dialect: c } = await K(), l = e.includes("--assets") || a.assets === !0, m = l ? D() : void 0;
640
+ if (l && !m) return V.error("--assets: this app has no storage provider configured, so there are no blobs to export.\n Install `storagePlugin(...)` in app.config.ts or set STORAGE_PROVIDER, or drop the flag."), 1;
641
+ let h = U(e, "--compression") ?? a.compression, g = U(e, "--consistency") === "snapshot" ? "snapshot" : a.consistency ?? "live", _ = a.masking, v = a.subset, y = a.scope ?? ut(e, s.tables.map((e) => e.name)), b = _ ? await dt() : void 0, x = y.kind === "tenant" ? await pt() : void 0, S = x ? { tenantTables: x } : {};
620
642
  if (e.includes("--dry-run")) {
621
643
  let e = y.kind === "tables" && y.tables ? [...y.tables] : s.tables.map((e) => e.name);
622
- if (B.info("export DRY RUN — nothing was written", {
644
+ if (V.info("export DRY RUN — nothing was written", {
623
645
  outDir: r,
624
646
  tables: e.length,
625
647
  scope: y.kind,
@@ -627,8 +649,8 @@ var Fe = /* @__PURE__ */ new Set([
627
649
  compression: h ?? "zstd",
628
650
  assets: l,
629
651
  masking: _ ? "profile policy applies" : "none"
630
- }), B.info(`would export: ${e.join(", ")}`), !_) return 0;
631
- let t = await T.runPromise(Se({
652
+ }), V.info(`would export: ${e.join(", ")}`), !_) return 0;
653
+ let t = await E.runPromise(Se({
632
654
  store: o,
633
655
  snapshot: s,
634
656
  masking: _,
@@ -640,10 +662,10 @@ var Fe = /* @__PURE__ */ new Set([
640
662
  }));
641
663
  return mt(t), +(t.unclassified.length > 0);
642
664
  }
643
- if (q(r)) {
665
+ if (J(r)) {
644
666
  let t = await import("node:os"), n = await import("node:fs/promises"), { resolve: i, join: a } = await import("node:path"), u = await n.mkdtemp(a(t.tmpdir(), "voltro-export-"));
645
667
  try {
646
- let t = await T.runPromise(Te({
668
+ let t = await E.runPromise(Te({
647
669
  store: o,
648
670
  snapshot: s,
649
671
  dialect: c,
@@ -656,17 +678,17 @@ var Fe = /* @__PURE__ */ new Set([
656
678
  ...h ? { compression: h } : {},
657
679
  ..._ ? { masking: _ } : {},
658
680
  ...b ? { classification: b } : {},
659
- onProgress: V
681
+ onProgress: H
660
682
  })), n = xe({
661
683
  dir: u,
662
- ...m ? { blobs: Ae(m, () => K(o)) } : {}
684
+ ...m ? { blobs: Ae(m, () => q(o)) } : {}
663
685
  }), a = rt(e);
664
686
  if (a) {
665
- let t = J(e);
666
- if (!t) return B.error("--encrypt requires --passphrase <p> or VOLTRO_BUNDLE_KEY (a dedicated key, NOT the transfer secret)"), 1;
687
+ let t = Y(e);
688
+ if (!t) return V.error("--encrypt requires --passphrase <p> or VOLTRO_BUNDLE_KEY (a dedicated key, NOT the transfer secret)"), 1;
667
689
  n = be(n, t);
668
690
  }
669
- return await it(n, i(process.cwd(), r)), B.info("export complete (single file)", {
691
+ return await it(n, i(process.cwd(), r)), V.info("export complete (single file)", {
670
692
  file: r,
671
693
  encrypted: a,
672
694
  assets: l,
@@ -680,7 +702,7 @@ var Fe = /* @__PURE__ */ new Set([
680
702
  });
681
703
  }
682
704
  }
683
- let C = await T.runPromise(Te({
705
+ let C = await E.runPromise(Te({
684
706
  store: o,
685
707
  snapshot: s,
686
708
  dialect: c,
@@ -693,10 +715,10 @@ var Fe = /* @__PURE__ */ new Set([
693
715
  ...h ? { compression: h } : {},
694
716
  ..._ ? { masking: _ } : {},
695
717
  ...b ? { classification: b } : {},
696
- ...m ? { assets: Oe(m, () => K(o)) } : {},
697
- onProgress: V
718
+ ...m ? { assets: Oe(m, () => q(o)) } : {},
719
+ onProgress: H
698
720
  }));
699
- return B.info("export complete", {
721
+ return V.info("export complete", {
700
722
  outDir: r,
701
723
  tables: C.tables.length,
702
724
  rows: C.tables.reduce((e, t) => e + t.rowCount, 0),
@@ -705,7 +727,7 @@ var Fe = /* @__PURE__ */ new Set([
705
727
  ...C.masking ? { maskedColumns: C.masking.transformed.length } : {}
706
728
  }), 0;
707
729
  }, bt = () => "dry run checked: schema fit, cross-dialect portability, mode legality, the table selection. It did NOT read per-table checksums (those stream during the load) and cannot see conflicts that depend on the target's current rows.", xt = (e) => {
708
- let t = H(e, "--tables");
730
+ let t = U(e, "--tables");
709
731
  return {
710
732
  ...t ? { tables: t.split(",").map((e) => e.trim()).filter(Boolean) } : {},
711
733
  ...e.includes("--dry-run") ? { dryRun: !0 } : {}
@@ -720,25 +742,25 @@ var Fe = /* @__PURE__ */ new Set([
720
742
  } : {}
721
743
  }), Ct = (e, t) => {
722
744
  if (e.includes("--dry-run")) {
723
- B.info("import DRY RUN — nothing was written", t), B.info(bt());
745
+ V.info("import DRY RUN — nothing was written", t), V.info(bt());
724
746
  return;
725
747
  }
726
748
  if (t.rows === 0 && typeof t.skippedRows == "number" && t.skippedRows !== 0) {
727
- B.info("import complete — 0 rows written, every table was already applied by an earlier run of this bundle directory", t);
749
+ V.info("import complete — 0 rows written, every table was already applied by an earlier run of this bundle directory", t);
728
750
  return;
729
751
  }
730
- B.info("import complete", t);
752
+ V.info("import complete", t);
731
753
  }, wt = Symbol("refused"), Tt = (e) => {
732
754
  let t = he(e) ?? e;
733
755
  if (t?._tag !== "RowsRefusedError" || !Array.isArray(t.rows)) return !1;
734
756
  let n = t.rows, r = n.filter((e) => !e.derived), i = Number(t.totalCount ?? n.length), a = Number(t.primaryCount ?? r.length);
735
- B.error(`import refused ${i} row(s), of which ${a} are the actual failures — the rest could not land because a row they reference did not.`);
757
+ V.error(`import refused ${i} row(s), of which ${a} are the actual failures — the rest could not land because a row they reference did not.`);
736
758
  let o = Array.isArray(t.byTable) ? t.byTable : [];
737
- o.length > 1 && B.error(` by table: ${o.map((e) => `${e.table} ${e.refused}`).join(", ")}`);
738
- for (let e of r) B.error(` ${e.table} ${e.id} ${e.reason}`);
739
- n.length < i && B.error(` (the list above is capped at ${n.length} of ${i} — the counts by table are complete)`);
759
+ o.length > 1 && V.error(` by table: ${o.map((e) => `${e.table} ${e.refused}`).join(", ")}`);
760
+ for (let e of r) V.error(` ${e.table} ${e.id} ${e.reason}`);
761
+ n.length < i && V.error(` (the list above is capped at ${n.length} of ${i} — the counts by table are complete)`);
740
762
  let s = i - a;
741
- return s > 0 && B.error(` … and ${s} row(s) behind them. Fix the ${a} above and re-run; they resolve with their parents.`), !0;
763
+ return s > 0 && V.error(` … and ${s} row(s) behind them. Fix the ${a} above and re-run; they resolve with their parents.`), !0;
742
764
  }, Et = (e) => {
743
765
  let t = typeof e == "string" ? e : e.toString("utf8"), n = t;
744
766
  try {
@@ -780,21 +802,21 @@ var Fe = /* @__PURE__ */ new Set([
780
802
  }
781
803
  }
782
804
  }, Dt = async (e) => {
783
- let t = H(e, "--target") === "api", n = H(e, "--bundle-key"), r = U(e);
784
- if (!r && !(t && n)) return B.error("usage: voltro data import <bundleDir> [--target direct|api] [--api-url <url>] [--token <secret>] [--timeout <seconds>] [--bundle-key <storage-key>] [--tables a,b] [--mode upsert|append|replace] [--on-conflict skip|fail] [--atomic] [--assets] [--no-verify] [--force] [--allow-live] [--dry-run] (--force: import despite schema drift AND cross-dialect warnings; --dry-run: report what would move, write nothing)"), 1;
785
- let i = H(e, "--mode") ?? "upsert", o = H(e, "--on-conflict") ?? "skip";
805
+ let t = U(e, "--target") === "api", n = U(e, "--bundle-key"), r = W(e);
806
+ if (!r && !(t && n)) return V.error("usage: voltro data import <bundleDir> [--target direct|api] [--api-url <url>] [--token <secret>] [--timeout <seconds>] [--bundle-key <storage-key>] [--tables a,b] [--mode upsert|append|replace] [--on-conflict skip|fail] [--atomic] [--assets] [--no-verify] [--force] [--allow-live] [--dry-run] (--force: import despite schema drift AND cross-dialect warnings; --dry-run: report what would move, write nothing)"), 1;
807
+ let i = U(e, "--mode") ?? "upsert", o = U(e, "--on-conflict") ?? "skip";
786
808
  if (t) {
787
- let t = H(e, "--api-url");
788
- if (!t) return B.error("--target api requires --api-url <url> (the running instance)"), 1;
789
- let a = H(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
790
- if (!a) return B.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
791
- let s = H(e, "--tables"), c = H(e, "--rollback-key");
792
- i === "replace" && c === void 0 && B.warn("api replace: no rollback capture — this run empties the target first and nothing was asked to be kept.\n Pass --rollback-key <storage-key> and the INSTANCE stores the target's current rows in its own\n object storage before deleting them, which is the one place that survives the pod going away.");
809
+ let t = U(e, "--api-url");
810
+ if (!t) return V.error("--target api requires --api-url <url> (the running instance)"), 1;
811
+ let a = U(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
812
+ if (!a) return V.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
813
+ let s = U(e, "--tables"), c = U(e, "--rollback-key");
814
+ i === "replace" && c === void 0 && V.warn("api replace: no rollback capture — this run empties the target first and nothing was asked to be kept.\n Pass --rollback-key <storage-key> and the INSTANCE stores the target's current rows in its own\n object storage before deleting them, which is the one place that survives the pod going away.");
793
815
  let l = {
794
816
  authorization: `Bearer ${a}`,
795
817
  "x-import-mode": i,
796
818
  "x-import-on-conflict": o,
797
- ...Z(e, i) ? { "x-import-atomic": "1" } : {},
819
+ ...Q(e, i) ? { "x-import-atomic": "1" } : {},
798
820
  ...e.includes("--no-atomic") ? { "x-import-atomic": "0" } : {},
799
821
  ...c === void 0 ? {} : { "x-import-rollback-key": c },
800
822
  ...e.includes("--force") ? { "x-import-force": "1" } : {},
@@ -802,23 +824,23 @@ var Fe = /* @__PURE__ */ new Set([
802
824
  ...s ? { "x-import-tables": s } : {}
803
825
  }, { resolve: p } = await import("node:path"), m;
804
826
  if (n) l["content-type"] = "application/json", m = JSON.stringify({ bundleKey: n });
805
- else if (q(r)) {
806
- let t = Y(p(process.cwd(), r)), n = J(e);
807
- n && (t = A(t, n)), l["content-type"] = "application/octet-stream", m = t;
808
- } else await (await import("node:fs/promises")).access(p(process.cwd(), r, "assets", "index.ndjson")).then(() => !0, () => !1) && B.warn("this directory bundle has assets; --target api uploads DATA ONLY. Pack a single-file `.vbundle` (voltro data export <name>.vbundle --assets) to transfer assets over the API."), l["content-type"] = "application/octet-stream", m = xe({ dir: p(process.cwd(), r) });
827
+ else if (J(r)) {
828
+ let t = X(p(process.cwd(), r)), n = Y(e);
829
+ n && (t = j(t, n)), l["content-type"] = "application/octet-stream", m = t;
830
+ } else await (await import("node:fs/promises")).access(p(process.cwd(), r, "assets", "index.ndjson")).then(() => !0, () => !1) && V.warn("this directory bundle has assets; --target api uploads DATA ONLY. Pack a single-file `.vbundle` (voltro data export <name>.vbundle --assets) to transfer assets over the API."), l["content-type"] = "application/octet-stream", m = xe({ dir: p(process.cwd(), r) });
809
831
  if (i === "replace") {
810
832
  let i = await at(r, n);
811
833
  {
812
- let r = i === null ? { bundleKey: n } : { tables: i }, a = await F(`${t.replace(/\/+$/, "")}/_voltro/admin/import`, JSON.stringify(r), {
834
+ let r = i === null ? { bundleKey: n } : { tables: i }, a = await I(`${t.replace(/\/+$/, "")}/_voltro/admin/import`, JSON.stringify(r), {
813
835
  ...l,
814
836
  "content-type": "application/json",
815
837
  "x-import-preflight": "1"
816
- }, Q(e)).catch(() => null), o = a !== null && a.status === 200 ? JSON.parse(a.body.toString("utf8")) : null;
817
- o === null ? B.warn("api replace: the instance did not answer the preflight (an older build does not have it). The run still works; the decision will only be visible in the pod log.") : o.staged === !0 ? B.info(`api replace: the instance WILL stage — ${o.stagedTables ?? 0} table(s) load into copies and the\n target keeps its rows until one short swap at the end. Interrupting the load leaves the target intact.`) : B.warn(`api replace: the instance will NOT stage — it empties the target first and refills it, so an
838
+ }, $(e)).catch(() => null), o = a !== null && a.status === 200 ? JSON.parse(a.body.toString("utf8")) : null;
839
+ o === null ? V.warn("api replace: the instance did not answer the preflight (an older build does not have it). The run still works; the decision will only be visible in the pod log.") : o.staged === !0 ? V.info(`api replace: the instance WILL stage — ${o.stagedTables ?? 0} table(s) load into copies and the\n target keeps its rows until one short swap at the end. Interrupting the load leaves the target intact.`) : V.warn(`api replace: the instance will NOT stage — it empties the target first and refills it, so an
818
840
  interrupted run leaves the target empty.\n Reason: ${o.reason ?? "not stated"}`);
819
841
  }
820
842
  }
821
- i === "replace" && !Z(e, i) && B.warn(gt(!0));
843
+ i === "replace" && !Q(e, i) && V.warn(gt(!0));
822
844
  let h = `${t.replace(/\/+$/, "")}/_voltro/admin/import`, g = ot(e), _;
823
845
  try {
824
846
  let t = typeof m == "string" ? null : await ht({
@@ -827,41 +849,41 @@ var Fe = /* @__PURE__ */ new Set([
827
849
  headers: l,
828
850
  bundleDir: r,
829
851
  args: e,
830
- log: B
831
- }), n = t === null ? await F(h, m, l, g.perRequest ?? Q(e)) : t.kind === "sent" ? t.res : await F(h, t.body, l, g.perRequest ?? Q(e));
832
- if (n.status < 200 || n.status >= 300) return Tt(Et(n.body)) || B.error(`api import failed: HTTP ${n.status} — ${n.body.toString("utf8")}`), 1;
852
+ log: V
853
+ }), n = t === null ? await I(h, m, l, g.perRequest ?? $(e)) : t.kind === "sent" ? t.res : await I(h, t.body, l, g.perRequest ?? $(e));
854
+ if (n.status < 200 || n.status >= 300) return Tt(Et(n.body)) || V.error(`api import failed: HTTP ${n.status} — ${n.body.toString("utf8")}`), 1;
833
855
  _ = JSON.parse(n.body.toString("utf8"));
834
856
  } catch (e) {
835
- if (e instanceof P) return B.error(`api import: ${Ie(e, i)}`), 1;
836
- if (e instanceof N) return B.error(`api import: ${I(e)}`), 1;
857
+ if (e instanceof F) return V.error(`api import: ${Ie(e, i)}`), 1;
858
+ if (e instanceof P) return V.error(`api import: ${L(e)}`), 1;
837
859
  throw e;
838
860
  }
839
- let v = await F(`${t.replace(/\/+$/, "")}/_voltro/admin/import/start`, JSON.stringify(_.bundleKey === void 0 ? { uploadId: _.uploadId } : { bundleKey: _.bundleKey }), {
861
+ let v = await I(`${t.replace(/\/+$/, "")}/_voltro/admin/import/start`, JSON.stringify(_.bundleKey === void 0 ? { uploadId: _.uploadId } : { bundleKey: _.bundleKey }), {
840
862
  ...l,
841
863
  "content-type": "application/json"
842
- }, g.perRequest ?? Q(e)).catch((e) => {
843
- if (e instanceof N) return B.error(`api import: ${I(e)}`), null;
864
+ }, g.perRequest ?? $(e)).catch((e) => {
865
+ if (e instanceof P) return V.error(`api import: ${L(e)}`), null;
844
866
  throw e;
845
867
  });
846
868
  if (v === null) return 1;
847
- if (v.status < 200 || v.status >= 300) return Tt(Et(v.body)) || B.error(`api import refused: HTTP ${v.status} — ${v.body.toString("utf8")}`), 1;
869
+ if (v.status < 200 || v.status >= 300) return Tt(Et(v.body)) || V.error(`api import refused: HTTP ${v.status} — ${v.body.toString("utf8")}`), 1;
848
870
  let y = JSON.parse(v.body.toString("utf8"));
849
- if (y.alreadyStarted === !0 && B.info(`api import: this bundle is already being imported as ${y.runId} — watching that run instead of starting a second one`), e.includes("--detach")) return B.info(`api import: started as ${y.runId}. NOT waiting for it.\n The outcome is not known yet — read it with: voltro data ${X} --target api --api-url ${t}`), 0;
850
- if (y.recorded === !1) return B.warn(`api import: started as ${y.runId}, but this instance could not record the run — so its outcome\n cannot be read back. Run \`voltro db apply\` against it so the next import is watchable.`), 0;
871
+ if (y.alreadyStarted === !0 && V.info(`api import: this bundle is already being imported as ${y.runId} — watching that run instead of starting a second one`), e.includes("--detach")) return V.info(`api import: started as ${y.runId}. NOT waiting for it.\n The outcome is not known yet — read it with: voltro data ${Z} --target api --api-url ${t}`), 0;
872
+ if (y.recorded === !1) return V.warn(`api import: started as ${y.runId}, but this instance could not record the run — so its outcome\n cannot be read back. Run \`voltro db apply\` against it so the next import is watchable.`), 0;
851
873
  let b = await d({
852
874
  read: () => st(t, a, y.runId),
853
875
  onTick: (e) => {
854
- B.info(f(e));
876
+ V.info(f(e));
855
877
  },
856
878
  intervalMs: g.pollMs,
857
879
  ...g.total === void 0 ? {} : { timeoutMs: g.total }
858
880
  }), x = u(b);
859
- return x === 2 ? (B.warn(b === null ? `api import: started as ${y.runId}, but its record could not be READ back from this instance.\n That is a channel problem, not a slow import — an older instance without the history route, a
881
+ return x === 2 ? (V.warn(b === null ? `api import: started as ${y.runId}, but its record could not be READ back from this instance.\n That is a channel problem, not a slow import — an older instance without the history route, a
860
882
  proxy dropping the GET, or a target with no history table. The run itself is unaffected and
861
- is NOT cancelled; its outcome is simply not visible from here.` : `api import: still running after the time allowed. The run is NOT cancelled — it is decoupled from\n this client by design. Watch it with: voltro data ${X} --target api --api-url ${t}`), 2) : x === 1 ? (B.error(`api import FAILED (${y.runId}): ${String(b?.failure ?? "no reason recorded")}`), 1) : e.includes("--dry-run") ? (B.info("api import DRY RUN — nothing was written", {
883
+ is NOT cancelled; its outcome is simply not visible from here.` : `api import: still running after the time allowed. The run is NOT cancelled — it is decoupled from\n this client by design. Watch it with: voltro data ${Z} --target api --api-url ${t}`), 2) : x === 1 ? (V.error(`api import FAILED (${y.runId}): ${String(b?.failure ?? "no reason recorded")}`), 1) : e.includes("--dry-run") ? (V.info("api import DRY RUN — nothing was written", {
862
884
  via: t,
863
885
  runId: y.runId
864
- }), B.info(bt()), 0) : (B.info("api import complete (imported by the running instance)", {
886
+ }), V.info(bt()), 0) : (V.info("api import complete (imported by the running instance)", {
865
887
  via: t,
866
888
  runId: y.runId,
867
889
  tables: b?.tablesWritten ?? 0,
@@ -869,72 +891,74 @@ var Fe = /* @__PURE__ */ new Set([
869
891
  ...b?.staged !== null && b?.staged !== void 0 ? { staged: b.staged } : {}
870
892
  }), 0);
871
893
  }
872
- if (!r) return B.error("a <bundleDir> is required for a direct import"), 1;
894
+ if (!r) return V.error("a <bundleDir> is required for a direct import"), 1;
873
895
  if (!await Qe(e)) return 1;
874
- i === "replace" && e.includes("--allow-live") && !Z(e, i) && B.warn(gt(!1));
875
- let { store: s, snapshot: c } = await G();
876
- c.tables.some((e) => e.name === y) || B.warn(`this target has no \`${y}\` table, so this import will not be recorded.\n The import itself is unaffected. \`voltro db apply\` creates it.`);
877
- let l = e.includes("--force"), p = (e) => B.warn(e), m = e.includes("--assets") ? E({}) : void 0, h = W() === "postgres" ? (await import("@voltro/sql-postgres")).makePgCopySession(a()) : void 0;
878
- if (q(r)) {
896
+ i === "replace" && e.includes("--allow-live") && !Q(e, i) && V.warn(gt(!1));
897
+ let { store: s, snapshot: c } = await K();
898
+ c.tables.some((e) => e.name === y) || V.warn(`this target has no \`${y}\` table, so this import will not be recorded.\n The import itself is unaffected. \`voltro db apply\` creates it.`);
899
+ let l = e.includes("--force"), p = (e) => V.warn(e), m = e.includes("--assets"), h = m ? D() : void 0;
900
+ if (m && !h) return V.error("--assets: this app has no storage provider configured, so there is nowhere to put the blobs.\n Install `storagePlugin(...)` in app.config.ts or set STORAGE_PROVIDER, or drop the flag."), 1;
901
+ let g = G() === "postgres" ? (await import("@voltro/sql-postgres")).makePgCopySession(a()) : void 0;
902
+ if (J(r)) {
879
903
  let t = await import("node:os"), n = await import("node:fs/promises"), { resolve: a, join: u } = await import("node:path"), d = await n.mkdtemp(u(t.tmpdir(), "voltro-import-"));
880
904
  try {
881
- let t = Y(a(process.cwd(), r)), n = J(e);
882
- return n && (t = A(t, n)), await je(t, {
905
+ let t = X(a(process.cwd(), r)), n = Y(e);
906
+ return n && (t = j(t, n)), await je(t, {
883
907
  dir: d,
884
- blobs: ke(m ?? E({}))
908
+ blobs: ke(h ?? fe())
885
909
  }), Ct(e, {
886
910
  file: r,
887
- ...St(await T.runPromise(Ee({
911
+ ...St(await E.runPromise(Ee({
888
912
  store: s,
889
913
  bundleDir: d,
890
914
  mode: i,
891
915
  onConflict: o,
892
- atomic: Z(e, i),
916
+ atomic: Q(e, i),
893
917
  ...vt(e, i, r),
894
918
  verify: !e.includes("--no-verify"),
895
- targetDialect: W(),
919
+ targetDialect: G(),
896
920
  allowIncompatible: l,
897
921
  targetSnapshot: c,
898
922
  force: l,
899
923
  onWarn: p,
900
- onProgress: V,
924
+ onProgress: H,
901
925
  assetsAlreadyRestored: !0,
902
926
  ...xt(e),
903
- ...h ? { copyLoader: h } : {}
927
+ ...g ? { copyLoader: g } : {}
904
928
  })))
905
929
  }), 0;
906
930
  } finally {
907
- await h?.close(), await n.rm(d, {
931
+ await g?.close(), await n.rm(d, {
908
932
  recursive: !0,
909
933
  force: !0
910
934
  });
911
935
  }
912
936
  }
913
- let g = await T.runPromise(Ee({
937
+ let _ = await E.runPromise(Ee({
914
938
  ...vt(e, i, r),
915
939
  store: s,
916
940
  bundleDir: r,
917
941
  mode: i,
918
942
  onConflict: o,
919
- atomic: Z(e, i),
943
+ atomic: Q(e, i),
920
944
  verify: !e.includes("--no-verify"),
921
- targetDialect: W(),
945
+ targetDialect: G(),
922
946
  allowIncompatible: l,
923
947
  targetSnapshot: c,
924
948
  force: l,
925
949
  onWarn: p,
926
- onProgress: V,
950
+ onProgress: H,
927
951
  ...xt(e),
928
- ...m ? { assets: De(m) } : {},
929
- ...h ? { copyLoader: h } : {}
952
+ ...h ? { assets: De(h) } : {},
953
+ ...g ? { copyLoader: g } : {}
930
954
  })).catch((e) => {
931
955
  if (Tt(e)) return wt;
932
956
  throw e;
933
- }).finally(() => h?.close());
934
- return typeof g == "symbol" ? 1 : (Ct(e, {
957
+ }).finally(() => g?.close());
958
+ return typeof _ == "symbol" ? 1 : (Ct(e, {
935
959
  bundleDir: r,
936
- ...St(g),
937
- assets: g.manifest.assets.count
960
+ ...St(_),
961
+ assets: _.manifest.assets.count
938
962
  }), 0);
939
963
  }, Ot = () => {
940
964
  let e = a();
@@ -947,28 +971,37 @@ var Fe = /* @__PURE__ */ new Set([
947
971
  ...e.database ? { database: e.database } : {}
948
972
  };
949
973
  }, kt = async (e) => {
950
- let t = U(e);
951
- if (!t) return B.error("usage: voltro data backup <outDir> [--assets] (native pg_dump/mariadb-dump/… + consistent artifact)"), 1;
952
- let n = W(), r = e.includes("--assets"), { mkdir: i, writeFile: a } = await import("node:fs/promises"), { join: o } = await import("node:path"), s = r ? E({}) : void 0;
953
- if (r && !s) return B.error("--assets: this app has no storage provider configured, so there are no blobs to capture.\n Configure one in app.config.ts, or drop the flag to take the rows-only dump."), 1;
974
+ let t = W(e);
975
+ if (!t) return V.error("usage: voltro data backup <outDir> [--assets] (native pg_dump/mariadb-dump/… + consistent artifact)"), 1;
976
+ let n = G(), r = e.includes("--assets"), { mkdir: i, writeFile: a } = await import("node:fs/promises"), { join: o } = await import("node:path"), s = await At(), c = r ? D() : void 0;
977
+ if (r && !c) return V.error("--assets: this app has no storage provider configured, so there are no blobs to capture.\n Install `storagePlugin(...)` in app.config.ts or set STORAGE_PROVIDER, or drop the\n flag to take the rows-only dump."), 1;
954
978
  await i(t, { recursive: !0 });
955
- let c = o(t, k(n)), l = await At(), u = l ? await We(l.store, {
979
+ let l = o(t, A(n)), u = s ? await We(s.store, {
956
980
  direction: "backup",
957
981
  dialect: n,
958
- artifact: c,
982
+ artifact: l,
959
983
  assets: r
960
- }) : void 0, d = await Ke(M(_e(n, Ot(), c)));
961
- if (d !== void 0) return l && u && await R(l.store, u, { failure: d }), B.error(`native backup failed: ${d}`), 1;
962
- let f = 0, p = 0;
963
- if (s && l) {
964
- let e = o(t, D);
984
+ }) : void 0, d = await Ke(N(_e(n, Ot(), l)));
985
+ if (d !== void 0) return s && u && await z(s.store, u, { failure: d }), V.error(`native backup failed: ${d}`), 1;
986
+ let f = await Xe(n), p = await Ye(), m = (/* @__PURE__ */ new Date()).toISOString(), h = async (e) => {
987
+ let r = Ve({
988
+ dialect: n,
989
+ schemaFingerprint: f,
990
+ voltroVersion: p,
991
+ createdAt: m,
992
+ assets: e
993
+ });
994
+ return await a(o(t, R), `${JSON.stringify(r, null, 2)}\n`, "utf8"), r;
995
+ }, g = 0, _ = 0, v = [];
996
+ if (c && s) {
997
+ let e = o(t, O);
965
998
  await i(e, { recursive: !0 });
966
- let n = o(t, O), r = l.store, a = await T.runPromiseExit(ve({
967
- source: Oe(s, () => K(r)),
999
+ let n = o(t, k), r = s.store, a = await E.runPromiseExit(ve({
1000
+ source: Oe(c, () => q(r)),
968
1001
  assetsDir: e,
969
1002
  progress: {
970
1003
  done: () => !1,
971
- mark: (e, t) => T.tryPromise({
1004
+ mark: (e, t) => E.tryPromise({
972
1005
  try: async () => {
973
1006
  await (await import("node:fs/promises")).appendFile(n, `${JSON.stringify(t)}\n`);
974
1007
  },
@@ -980,28 +1013,23 @@ var Fe = /* @__PURE__ */ new Set([
980
1013
  }
981
1014
  }));
982
1015
  if (a._tag === "Failure") {
983
- let e = w.pretty(a.cause);
984
- return u && await R(l.store, u, { failure: `assets: ${e}` }), B.error(`the rows were dumped to ${c}, but the asset capture failed: ${e}\n This directory holds a ROWS-ONLY backup. Re-run with --assets once the storage
1016
+ let e = T.pretty(a.cause);
1017
+ return u && await z(s.store, u, { failure: `assets: ${e}` }), await h(null).catch(() => void 0), V.error(`the rows were dumped to ${l}, but the asset capture failed: ${e}\n This directory holds a ROWS-ONLY backup. Re-run with --assets once the storage
985
1018
  backend is reachable, or restore without --assets and accept the dangling refs.`), 1;
986
1019
  }
987
- f = a.value.count, p = a.value.totalBytes;
1020
+ g = a.value.count, _ = a.value.totalBytes, v = a.value.missing, v.length > 0 && V.warn(`${v.length} of ${v.length + g} blob reference(s) point at objects the storage provider does not have; they are NOT in this backup and no restore can bring them back.
1021
+ e.g. ${v.slice(0, 3).map((e) => `'${e}'`).join(", ")}` + (v.length > 3 ? `, and ${v.length - 3} more` : ""));
988
1022
  }
989
- let m = Ve({
990
- dialect: n,
991
- schemaFingerprint: await Xe(n),
992
- voltroVersion: await Ye(),
993
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
994
- assets: r ? {
995
- count: f,
996
- totalBytes: p
997
- } : null
998
- });
999
- return await a(o(t, L), `${JSON.stringify(m, null, 2)}\n`, "utf8"), l && u && await R(l.store, u, { assets: f }), B.info("native backup complete", {
1023
+ let y = await h(r ? {
1024
+ count: g,
1025
+ totalBytes: _
1026
+ } : null);
1027
+ return s && u && await z(s.store, u, { assets: g }), V.info("native backup complete", {
1000
1028
  dialect: n,
1001
- artifact: c,
1002
- stamp: L,
1003
- schemaFingerprint: m.schemaFingerprint ?? "<none>",
1004
- assets: r ? `${f} blob(s), ${p} byte(s) under ${D}/` : "NOT included — re-run with --assets, or use `voltro data export --assets`",
1029
+ artifact: l,
1030
+ stamp: R,
1031
+ schemaFingerprint: y.schemaFingerprint ?? "<none>",
1032
+ assets: r ? `${g} blob(s), ${_} byte(s) under ${O}/` + (v.length > 0 ? ` — ${v.length} reference(s) had no object and are NOT in here` : "") : "NOT included — re-run with --assets, or use `voltro data export --assets`",
1005
1033
  recorded: u?.recorded === !0 ? "voltro data transfers" : "NOT recorded (this target keeps no transfer history)"
1006
1034
  }), 0;
1007
1035
  }, At = async () => {
@@ -1012,89 +1040,89 @@ var Fe = /* @__PURE__ */ new Set([
1012
1040
  return;
1013
1041
  }
1014
1042
  }, jt = async (e, t) => {
1015
- let n = W(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(e, k(n)), o = qe({
1016
- flagUrl: H(t, "--drill-url"),
1043
+ let n = G(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(e, A(n)), o = qe({
1044
+ flagUrl: U(t, "--drill-url"),
1017
1045
  envUrl: process.env.DRILL_DB_URL,
1018
1046
  liveKeys: nt()
1019
1047
  });
1020
- if (!o.ok) return B.error(`restore --drill: ${o.error}`), 1;
1021
- let s = await i(r(e, L), "utf8").then(He, () => null);
1022
- if (s && s.dialect !== n) return B.error(`restore --drill: backup is a ${s.dialect} dump but DB_DIALECT is ${n} — cross-dialect restore is never valid.`), 1;
1023
- B.info("restore drill: restoring into throwaway DB", {
1048
+ if (!o.ok) return V.error(`restore --drill: ${o.error}`), 1;
1049
+ let s = await i(r(e, R), "utf8").then(He, () => null);
1050
+ if (s && s.dialect !== n) return V.error(`restore --drill: backup is a ${s.dialect} dump but DB_DIALECT is ${n} — cross-dialect restore is never valid.`), 1;
1051
+ V.info("restore drill: restoring into throwaway DB", {
1024
1052
  dialect: n,
1025
- target: z(o.url)
1026
- }), await T.runPromise(M(we(n, { url: o.url }, a)));
1053
+ target: B(o.url)
1054
+ }), await E.runPromise(N(we(n, { url: o.url }, a)));
1027
1055
  let c = null, l = 0;
1028
1056
  try {
1029
1057
  let e = await et(n, { url: o.url });
1030
- c = ue(e), l = e.tables.length;
1058
+ c = le(e), l = e.tables.length;
1031
1059
  } catch (e) {
1032
- return B.error(`restore --drill: could not introspect the restored DB — ${String(e)}`), 1;
1060
+ return V.error(`restore --drill: could not introspect the restored DB — ${String(e)}`), 1;
1033
1061
  }
1034
1062
  let u = Je({
1035
1063
  stampFingerprint: s?.schemaFingerprint ?? null,
1036
1064
  restoredFingerprint: c,
1037
1065
  restoredTableCount: l
1038
1066
  });
1039
- for (let e of u.lines) u.pass ? B.info(`restore drill: ${e}`) : B.error(`restore drill: ${e}`);
1067
+ for (let e of u.lines) u.pass ? V.info(`restore drill: ${e}`) : V.error(`restore drill: ${e}`);
1040
1068
  return +!u.pass;
1041
1069
  }, Mt = async (e) => {
1042
- let t = U(e);
1043
- if (!t) return B.error("usage: voltro data restore <backupDir> [--assets] [--allow-live] [--api-url <url>] [--force] [--drill [--drill-url <url>]] (native pg_restore/mariadb/…)"), 1;
1070
+ let t = W(e);
1071
+ if (!t) return V.error("usage: voltro data restore <backupDir> [--assets] [--allow-live] [--api-url <url>] [--force] [--drill [--drill-url <url>]] (native pg_restore/mariadb/…)"), 1;
1044
1072
  if (e.includes("--drill")) return jt(t, e);
1045
1073
  if (!await Qe(e)) return 1;
1046
- let n = W(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(t, k(n)), o = e.includes("--assets"), s = Ue({
1047
- stamp: await i(r(t, L), "utf8").then(He, () => null),
1074
+ let n = G(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(t, A(n)), o = e.includes("--assets"), s = Ue({
1075
+ stamp: await i(r(t, R), "utf8").then(He, () => null),
1048
1076
  currentDialect: n,
1049
1077
  currentFingerprint: await Xe(n)
1050
1078
  });
1051
- for (let e of s.info) B.info(`backup stamp: ${e}`);
1052
- if (s.warn && B.warn(s.warn), s.refuse) {
1053
- if (!e.includes("--force")) return B.error(`restore refused: ${s.refuse} (pass --force to override)`), 1;
1054
- B.warn(`restore proceeding despite: ${s.refuse} (--force)`);
1079
+ for (let e of s.info) V.info(`backup stamp: ${e}`);
1080
+ if (s.warn && V.warn(s.warn), s.refuse) {
1081
+ if (!e.includes("--force")) return V.error(`restore refused: ${s.refuse} (pass --force to override)`), 1;
1082
+ V.warn(`restore proceeding despite: ${s.refuse} (--force)`);
1055
1083
  }
1056
- let c = r(t, O), l = await i(c, "utf8").then(() => !0, () => !1);
1057
- if (o && !l) return B.error(`--assets: this backup carries no assets — there is no ${O} in ${t}.\n It was taken without --assets, so its rows will reference blobs this restore cannot
1084
+ let c = r(t, k), l = await i(c, "utf8").then(() => !0, () => !1);
1085
+ if (o && !l) return V.error(`--assets: this backup carries no assets — there is no ${k} in ${t}.\n It was taken without --assets, so its rows will reference blobs this restore cannot
1058
1086
  put back. Restore from a backup taken with --assets, or drop the flag to accept that.`), 1;
1059
- !o && l && B.warn("this backup CARRIES assets and --assets was not passed: the rows will be restored and the blobs will not. Pass --assets to restore both.");
1060
- let u = o ? E({}) : void 0;
1061
- if (o && !u) return B.error("--assets: this app has no storage provider configured, so there is nowhere to put the blobs."), 1;
1062
- let d = await At(), f = d ? await Ge(d.store, { artifact: a }) : void 0;
1063
- if (d && f === void 0) return B.error(`refusing to restore: could not write the in-progress marker.
1087
+ !o && l && V.warn("this backup CARRIES assets and --assets was not passed: the rows will be restored and the blobs will not. Pass --assets to restore both.");
1088
+ let u = await At(), d = o ? D() : void 0;
1089
+ if (o && !d) return V.error("--assets: this app has no storage provider configured, so there is nowhere to put the blobs.\n Install `storagePlugin(...)` in app.config.ts or set STORAGE_PROVIDER, or drop the flag."), 1;
1090
+ let f = u ? await Ge(u.store, { artifact: a }) : void 0;
1091
+ if (u && f === void 0) return V.error(`refusing to restore: could not write the in-progress marker.
1064
1092
  It is one row in \`${b}\`, written before the first destructive\n statement so a killed restore refuses the next boot rather than serving a half-loaded
1065
1093
  database. Run \`voltro db apply\` so the table exists, then retry.`), 1;
1066
- let p = d ? await We(d.store, {
1094
+ let p = u ? await We(u.store, {
1067
1095
  direction: "restore",
1068
1096
  dialect: n,
1069
1097
  artifact: a,
1070
1098
  assets: o
1071
- }) : void 0, m = await Ke(M(we(n, Ot(), a)));
1072
- if (m !== void 0) return d && p && await R(d.store, p, { failure: m }), B.error(`native restore failed: ${m}\n This database is now in an unknown state and the next boot will REFUSE, by design.
1073
- Re-run the restore to completion, or clear the marker deliberately with
1074
- \`voltro data clear-replace-marker --yes\` once you have decided the state is correct.`), 1;
1075
- let h = 0;
1076
- if (u) {
1077
- let e = await T.runPromiseExit(Ce({
1078
- sink: De(u),
1079
- assetsDir: r(t, D),
1099
+ }) : void 0, m = await Ke(N(we(n, Ot(), a))), h = f === void 0 ? "held" : await f.reassert();
1100
+ if (h === "rewritten" ? V.warn(`the restore artefact removed the in-progress marker (it carries \`${b}\`) it has been written back.\n Backups taken from this version on exclude that table, so this only affects older
1101
+ and hand-made dumps.`) : h === "lost" && V.error(`the restore artefact removed the in-progress marker and it could NOT be written back.\n \`${b}\` is unwritable, so if this restore does not finish,\n nothing will stop the next boot from serving a half-loaded database. Check the
1102
+ result of this command before you start the app.`), m !== void 0) return u && p && await z(u.store, p, { failure: m }), V.error(`native restore failed: ${m}\n` + (h === "lost" ? " This database is now in an unknown state and NOTHING WILL STOP THE NEXT BOOT — see above.\n" : " This database is now in an unknown state and the next boot will REFUSE, by design.\n") + " Re-run the restore to completion, or clear the marker deliberately with\n `voltro data clear-replace-marker --yes` once you have decided the state is correct."), 1;
1103
+ let g = 0;
1104
+ if (d) {
1105
+ let e = await E.runPromiseExit(Ce({
1106
+ sink: De(d),
1107
+ assetsDir: r(t, O),
1080
1108
  indexPath: c
1081
1109
  }));
1082
1110
  if (e._tag === "Failure") {
1083
- let t = w.pretty(e.cause);
1084
- return d && p && await R(d.store, p, { failure: `assets: ${t}` }), B.error(`the rows were restored, but the asset restore failed: ${t}\n The in-progress marker is still set and the next boot will refuse. Re-run
1111
+ let t = T.pretty(e.cause);
1112
+ return u && p && await z(u.store, p, { failure: `assets: ${t}` }), V.error(`the rows were restored, but the asset restore failed: ${t}\n The in-progress marker is still set and the next boot will refuse. Re-run
1085
1113
  \`voltro data restore <dir> --assets\` once storage is reachable.`), 1;
1086
1114
  }
1087
- h = e.value;
1115
+ g = e.value;
1088
1116
  }
1089
- return f && await f(), d && p && await R(d.store, p, { assets: h }), B.info("native restore complete", {
1117
+ return f && await f.clear(), u && p && await z(u.store, p, { assets: g }), V.info("native restore complete", {
1090
1118
  dialect: n,
1091
1119
  artifact: a,
1092
- assets: o ? `${h} blob(s) restored` : "not restored (no --assets)",
1120
+ assets: o ? `${g} blob(s) restored` : "not restored (no --assets)",
1093
1121
  recorded: p?.recorded === !0 ? "voltro data transfers" : "NOT recorded (this target keeps no transfer history)"
1094
1122
  }), 0;
1095
1123
  }, Nt = async (e) => {
1096
- let t = U(e);
1097
- if (!t) return B.error("usage: voltro data inspect <file.vbundle|dir> [--json] [--passphrase <p>]"), 1;
1124
+ let t = W(e);
1125
+ if (!t) return V.error("usage: voltro data inspect <file.vbundle|dir> [--json] [--passphrase <p>]"), 1;
1098
1126
  let { resolve: n, join: r } = await import("node:path"), i = await import("node:fs/promises"), a = n(process.cwd(), t);
1099
1127
  if ((await i.stat(a).catch(() => void 0))?.isDirectory()) {
1100
1128
  let n = r(a, "manifest.json"), o = r(a, "README.md");
@@ -1103,24 +1131,24 @@ var Fe = /* @__PURE__ */ new Set([
1103
1131
  if (e !== void 0) return console.log(e), 0;
1104
1132
  }
1105
1133
  let s = await i.readFile(n, "utf8").catch(() => void 0);
1106
- return s === void 0 ? (B.error(`'${t}' is a directory but holds no manifest.json — is it an unpacked bundle? (a bundle exported with --target api is always unpacked into a directory, even when the path ends in .vbundle)`), 1) : (console.log(s), 0);
1134
+ return s === void 0 ? (V.error(`'${t}' is a directory but holds no manifest.json — is it an unpacked bundle? (a bundle exported with --target api is always unpacked into a directory, even when the path ends in .vbundle)`), 1) : (console.log(s), 0);
1107
1135
  }
1108
- let o = J(e), s = () => {
1109
- let e = Y(a);
1110
- return o ? A(e, o) : e;
1136
+ let o = Y(e), s = () => {
1137
+ let e = X(a);
1138
+ return o ? j(e, o) : e;
1111
1139
  };
1112
1140
  if (e.includes("--json")) {
1113
- let e = (await j(s(), ["manifest.json"])).get("manifest.json");
1114
- return e ? (console.log(e.toString("utf8")), 0) : (B.error("no manifest.json found in the bundle"), 1);
1141
+ let e = (await M(s(), ["manifest.json"])).get("manifest.json");
1142
+ return e ? (console.log(e.toString("utf8")), 0) : (V.error("no manifest.json found in the bundle"), 1);
1115
1143
  }
1116
- let c = (await j(s(), ["README.md"])).get("README.md");
1144
+ let c = (await M(s(), ["README.md"])).get("README.md");
1117
1145
  if (c) return console.log(c.toString("utf8")), 0;
1118
- let l = (await j(s(), ["manifest.json"])).get("manifest.json");
1119
- return l ? (console.log(l.toString("utf8")), 0) : (B.error("bundle has no README.md or manifest.json"), 1);
1146
+ let l = (await M(s(), ["manifest.json"])).get("manifest.json");
1147
+ return l ? (console.log(l.toString("utf8")), 0) : (V.error("bundle has no README.md or manifest.json"), 1);
1120
1148
  }, Pt = async (e) => {
1121
- let { REPLACE_IN_PROGRESS_TABLE: t } = await import("@voltro/database"), { interruptedReplaceAtBoot: n } = await import("./interruptedReplace-CvmiAM9K.js"), { store: r } = await G(), i = await n(r);
1122
- if (i === void 0) return B.info("no interrupted replace is recorded — nothing to clear"), 0;
1123
- if (!e.includes("--yes")) return B.error(`${i}\n\n Re-run with --yes to clear it.`), 1;
1149
+ let { REPLACE_IN_PROGRESS_TABLE: t } = await import("@voltro/database"), { interruptedReplaceAtBoot: n } = await import("./interruptedReplace-CvmiAM9K.js"), { store: r } = await K(), i = await n(r);
1150
+ if (i === void 0) return V.info("no interrupted replace is recorded — nothing to clear"), 0;
1151
+ if (!e.includes("--yes")) return V.error(`${i}\n\n Re-run with --yes to clear it.`), 1;
1124
1152
  let a = await r.query({
1125
1153
  table: t,
1126
1154
  predicate: void 0,
@@ -1130,30 +1158,30 @@ var Fe = /* @__PURE__ */ new Set([
1130
1158
  projection: void 0
1131
1159
  });
1132
1160
  for (let e of a) await r.delete(t, String(e.id));
1133
- return B.info(`cleared ${a.length} interrupted-replace marker(s) — the next boot will start`), 0;
1161
+ return V.info(`cleared ${a.length} interrupted-replace marker(s) — the next boot will start`), 0;
1134
1162
  }, Ft = async (e) => {
1135
- let { STAGING_PREFIX: t, dropStagingSql: n, execStatements: r } = await import("@voltro/data-transfer"), { store: i } = await G(), a = W();
1136
- if (a !== "postgres" && a !== "mysql" && a !== "mariadb" && a !== "sqlite" && a !== "mssql") return B.error(`this store has no staging tables to clear (dialect: ${a})`), 1;
1163
+ let { STAGING_PREFIX: t, dropStagingSql: n, execStatements: r } = await import("@voltro/data-transfer"), { store: i } = await K(), a = G();
1164
+ if (a !== "postgres" && a !== "mysql" && a !== "mariadb" && a !== "sqlite" && a !== "mssql") return V.error(`this store has no staging tables to clear (dialect: ${a})`), 1;
1137
1165
  let { introspectSchema: o } = await import("@voltro/database/sql"), s = (await i.run((await import("@effect/sql")).SqlClient.SqlClient.pipe((await import("effect")).Effect.flatMap(o)))).tables.map((e) => e.name).filter((e) => e.startsWith(t));
1138
- return s.length === 0 ? (B.info("no staging tables are present — nothing to clear"), 0) : e.includes("--yes") ? (await r(i, s.map((e) => n(e.slice(t.length), a))), B.info(`dropped ${s.length} staging table(s)`), 0) : (B.error(`${s.length} staging table(s) from an earlier \`--mode replace\`:\n` + s.map((e) => ` ${e}`).join("\n") + "\n\n Each holds a copy of what a run was loading. Nothing else removes them.\n Make sure no import is running right now — this cannot tell a leftover from one in flight.\n Re-run with --yes to drop them."), 1);
1166
+ return s.length === 0 ? (V.info("no staging tables are present — nothing to clear"), 0) : e.includes("--yes") ? (await r(i, s.map((e) => n(e.slice(t.length), a))), V.info(`dropped ${s.length} staging table(s)`), 0) : (V.error(`${s.length} staging table(s) from an earlier \`--mode replace\`:\n` + s.map((e) => ` ${e}`).join("\n") + "\n\n Each holds a copy of what a run was loading. Nothing else removes them.\n Make sure no import is running right now — this cannot tell a leftover from one in flight.\n Re-run with --yes to drop them."), 1);
1139
1167
  }, It = async (e) => {
1140
- let { describeTransferRun: t, DATA_TRANSFERS_TABLE: n } = await import("@voltro/database"), r = Number(H(e, "--limit") ?? "20"), i = Number.isFinite(r) ? Math.max(1, Math.min(200, Math.trunc(r))) : 20;
1141
- if (H(e, "--target") === "api") {
1142
- let t = H(e, "--api-url");
1143
- if (!t) return B.error("--target api requires --api-url <url> (the running instance)"), 1;
1144
- let n = H(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
1145
- if (!n) return B.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET)"), 1;
1168
+ let { describeTransferRun: t, DATA_TRANSFERS_TABLE: n } = await import("@voltro/database"), r = Number(U(e, "--limit") ?? "20"), i = Number.isFinite(r) ? Math.max(1, Math.min(200, Math.trunc(r))) : 20;
1169
+ if (U(e, "--target") === "api") {
1170
+ let t = U(e, "--api-url");
1171
+ if (!t) return V.error("--target api requires --api-url <url> (the running instance)"), 1;
1172
+ let n = U(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
1173
+ if (!n) return V.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET)"), 1;
1146
1174
  let r = await fetch(`${t.replace(/\/+$/, "")}/_voltro/admin/transfers?limit=${i}`, { headers: { authorization: `Bearer ${n}` } }), a = await r.text();
1147
- if (r.status !== 200) return B.error(`api transfers: ${r.status} ${a}`), 1;
1175
+ if (r.status !== 200) return V.error(`api transfers: ${r.status} ${a}`), 1;
1148
1176
  let o = JSON.parse(a);
1149
1177
  if (e.includes("--json")) return console.log(a), 0;
1150
1178
  let s = o.runs ?? [];
1151
- if (s.length === 0) return B.info("no data transfers recorded on this instance"), 0;
1152
- (o.running ?? 0) > 0 && B.info(`${o.running} transfer(s) IN FLIGHT — re-run this to watch the counters move`);
1153
- for (let e of s) B.info(` ${e.line ?? ""}`);
1179
+ if (s.length === 0) return V.info("no data transfers recorded on this instance"), 0;
1180
+ (o.running ?? 0) > 0 && V.info(`${o.running} transfer(s) IN FLIGHT — re-run this to watch the counters move`);
1181
+ for (let e of s) V.info(` ${e.line ?? ""}`);
1154
1182
  return 0;
1155
1183
  }
1156
- let { store: a } = await G(), o;
1184
+ let { store: a } = await K(), o;
1157
1185
  try {
1158
1186
  o = await a.query({
1159
1187
  table: n,
@@ -1167,12 +1195,12 @@ var Fe = /* @__PURE__ */ new Set([
1167
1195
  take: i
1168
1196
  });
1169
1197
  } catch {
1170
- return B.error(`this target has no \`${n}\` table, so no transfer has been recorded here.\n Run \`voltro db apply\`; the transfers themselves are unaffected by its absence.`), 1;
1198
+ return V.error(`this target has no \`${n}\` table, so no transfer has been recorded here.\n Run \`voltro db apply\`; the transfers themselves are unaffected by its absence.`), 1;
1171
1199
  }
1172
- if (o.length === 0) return B.info("no data transfers recorded against this target"), 0;
1200
+ if (o.length === 0) return V.info("no data transfers recorded against this target"), 0;
1173
1201
  for (let e of o) {
1174
1202
  let n = e;
1175
- B.info(` ${t({
1203
+ V.info(` ${t({
1176
1204
  ...e,
1177
1205
  startedAt: new Date(n.startedAt),
1178
1206
  finishedAt: n.finishedAt === null ? null : new Date(n.finishedAt)
@@ -1180,14 +1208,14 @@ var Fe = /* @__PURE__ */ new Set([
1180
1208
  }
1181
1209
  return 0;
1182
1210
  }, Lt = async (e) => {
1183
- let t = U(e), n = U(e.filter((e) => e !== t));
1184
- if (!t || !n) return B.error("usage: voltro data unpack <file.vbundle> <dir> [--passphrase <p>]"), 1;
1185
- let { resolve: r } = await import("node:path"), i = Y(r(process.cwd(), t)), a = J(e);
1186
- return a && (i = A(i, a)), await Me(i, r(process.cwd(), n)), B.info("unpack complete", {
1211
+ let t = W(e), n = W(e.filter((e) => e !== t));
1212
+ if (!t || !n) return V.error("usage: voltro data unpack <file.vbundle> <dir> [--passphrase <p>]"), 1;
1213
+ let { resolve: r } = await import("node:path"), i = X(r(process.cwd(), t)), a = Y(e);
1214
+ return a && (i = j(i, a)), await Me(i, r(process.cwd(), n)), V.info("unpack complete", {
1187
1215
  file: t,
1188
1216
  dir: n
1189
1217
  }), 0;
1190
- }, $ = {
1218
+ }, Rt = {
1191
1219
  export: {
1192
1220
  common: [
1193
1221
  "--target",
@@ -1267,23 +1295,23 @@ var Fe = /* @__PURE__ */ new Set([
1267
1295
  "--drill-url",
1268
1296
  "--api-url"
1269
1297
  ] }
1270
- }, Rt = (e) => e.split("=")[0], zt = (e, t) => {
1271
- let n = $[e];
1298
+ }, zt = (e) => e.split("=")[0], Bt = (e, t) => {
1299
+ let n = Rt[e];
1272
1300
  if (!n) return;
1273
- let r = H(t, "--target") === "api" ? "api" : "direct", i = /* @__PURE__ */ new Set([...n.common, ...r === "api" ? n.apiOnly ?? [] : n.directOnly ?? []]), a = new Set(r === "api" ? n.directOnly ?? [] : n.apiOnly ?? []);
1301
+ let r = U(t, "--target") === "api" ? "api" : "direct", i = /* @__PURE__ */ new Set([...n.common, ...r === "api" ? n.apiOnly ?? [] : n.directOnly ?? []]), a = new Set(r === "api" ? n.directOnly ?? [] : n.apiOnly ?? []);
1274
1302
  for (let n of t) {
1275
1303
  if (!n.startsWith("--")) continue;
1276
- let t = Rt(n);
1304
+ let t = zt(n);
1277
1305
  if (i.has(t)) continue;
1278
1306
  if (a.has(t)) return `voltro data ${e}: ${t} is not read with --target ${r} (it is a --target ${r === "api" ? "direct" : "api"} flag). Remove it, or change --target.`;
1279
- let o = Object.entries($).filter(([n, r]) => n !== e && [
1307
+ let o = Object.entries(Rt).filter(([n, r]) => n !== e && [
1280
1308
  ...r.common,
1281
1309
  ...r.directOnly ?? [],
1282
1310
  ...r.apiOnly ?? []
1283
1311
  ].includes(t)).map(([e]) => e);
1284
1312
  return o.length > 0 ? `voltro data ${e}: ${t} is not a \`${e}\` flag (it belongs to \`voltro data ${o.join("` / `")}\`). Remove it.` : `voltro data ${e}: unknown flag ${t}. Run \`voltro data --help\` for the flags this command reads.`;
1285
1313
  }
1286
- }, Bt = {
1314
+ }, Vt = {
1287
1315
  export: yt,
1288
1316
  import: Dt,
1289
1317
  transfers: It,
@@ -1293,14 +1321,14 @@ var Fe = /* @__PURE__ */ new Set([
1293
1321
  restore: Mt,
1294
1322
  "clear-replace-marker": Pt,
1295
1323
  "clear-staging": Ft
1296
- }, Vt = async (n) => {
1324
+ }, Ht = async (n) => {
1297
1325
  let [r, ...i] = n;
1298
- if (r !== void 0 && $[r] !== void 0) {
1299
- let e = zt(r, i);
1300
- if (e) return B.error(e), 2;
1326
+ if (r !== void 0 && Rt[r] !== void 0) {
1327
+ let e = Bt(r, i);
1328
+ if (e) return V.error(e), 2;
1301
1329
  }
1302
- let a = r === void 0 ? void 0 : Bt[r];
1303
- return a === void 0 ? (B.error(`usage: voltro data ${e(t)} … (logical: export/import; native: backup/restore; \`imports\` reads the history, incl. a run in flight)`), r ? 2 : 1) : a(i);
1330
+ let a = r === void 0 ? void 0 : Vt[r];
1331
+ return a === void 0 ? (V.error(`usage: voltro data ${e(t)} … (logical: export/import; native: backup/restore; \`imports\` reads the history, incl. a run in flight)`), r ? 2 : 1) : a(i);
1304
1332
  };
1305
1333
  //#endregion
1306
- export { Vt as runDataCommand };
1334
+ export { Ht as runDataCommand };