@voltro/cli 0.50.1 → 0.51.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 (103) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/dist/{apiBuild-D3s7lx57.js → apiBuild-CPDHXF72.js} +2 -2
  3. package/dist/apiBuild-GDKuGOMV.js +2 -0
  4. package/dist/appGraph-CFmFKHb2.js +2 -0
  5. package/dist/appGraph-yRuKjOba.js +111 -0
  6. package/dist/bin.js +1 -1
  7. package/dist/{build-CFmqF39c.js → build-DETLZAFt.js} +271 -240
  8. package/dist/{checkCommand-DomvYDi1.js → checkCommand-CWcnDArJ.js} +1 -1
  9. package/dist/{checkCommand-DsKIjL6k.js → checkCommand-DNuPiWMc.js} +29 -28
  10. package/dist/{codegenCommand-C0S27nbB.js → codegenCommand-BNBHcNNj.js} +2 -2
  11. package/dist/{codemodRunner-DwY8Rjbl.js → codemodRunner-BDVixlSw.js} +278 -191
  12. package/dist/{commands-Brp4DI8u.js → commands-B1OiS9bX.js} +24 -23
  13. package/dist/{dashboardCommand-bbLfc9FW.js → dashboardCommand-C-vvPY1B.js} +5 -5
  14. package/dist/{dataCommand-k9mXTXin.js → dataCommand-C1GxXW5q.js} +279 -233
  15. package/dist/dbCommand-C27HIsGE.js +2 -0
  16. package/dist/{dbCommand-Bf7Cy0mn.js → dbCommand-If4Y1xQ-.js} +1 -1
  17. package/dist/{dev-Dz9GqA6P.js → dev-CK522MV5.js} +1 -1
  18. package/dist/{dev-C0cbqysu.js → dev-kdAg9Q7l.js} +1246 -1246
  19. package/dist/doctorCommand-BK4l18eG.js +2 -0
  20. package/dist/{doctorCommand-DyViaaCP.js → doctorCommand-nKmeW78u.js} +16 -16
  21. package/dist/{dormancyCommand-DMZPA_HW.js → dormancyCommand-CY3wa_SW.js} +1 -1
  22. package/dist/{embeddingsCommand-CMxRPkg6.js → embeddingsCommand-BDLIgje_.js} +1 -1
  23. package/dist/{envCommand-CDLr-yD4.js → envCommand-C6V_xVlT.js} +13 -13
  24. package/dist/{evolveCommand-Ct4NesL3.js → evolveCommand-D3c4DSfN.js} +2 -2
  25. package/dist/{generateCommand-BDdOxhnv.js → generateCommand-DTNPGjxo.js} +1 -1
  26. package/dist/index.js +1 -1
  27. package/dist/{infoCommand-orsKJKUy.js → infoCommand-BnRFEF1o.js} +1 -1
  28. package/dist/{migrate-D3MK9BpK.js → migrate-DehuBakM.js} +1 -1
  29. package/dist/{runtimeTrace-Bo8jWsNe.js → runtimeTrace-ZsBU7Tkx.js} +1 -1
  30. package/dist/{sdkgen-OZhiT2vz.js → sdkgen-O4XqWOjM.js} +1 -1
  31. package/dist/serveCommand-BRnPCxVd.js +2 -0
  32. package/dist/{serveCommand-YbD5VgfV.js → serveCommand-DdiYNBBu.js} +3 -3
  33. package/dist/serveEntry.js +1 -1
  34. package/dist/{start-B1nH9ahf.js → start-BLNmWkLa.js} +331 -327
  35. package/dist/{start-7b_bL8Uc.js → start-Dzicuyw8.js} +1 -1
  36. package/dist/startEntry.js +1 -1
  37. package/dist/{updateCommand-BgH6vTtq.js → updateCommand-Bs322Q78.js} +1 -1
  38. package/dist/updateCommand-eXB35SEv.js +2 -0
  39. package/dist/{webDev-BbdkzMbd.js → webDev-B-ubQEMX.js} +282 -223
  40. package/dist/webDev-DposiF3j.js +2 -0
  41. package/dist/{webhooksCommand-DjE6u0r4.js → webhooksCommand-FLYY9IXh.js} +1 -1
  42. package/package.json +35 -17
  43. package/templates/AGENTS.core.md +15 -5
  44. package/templates/AGENTS.md +16 -6
  45. package/templates/agent-docs/_index.md +1 -1
  46. package/templates/agent-docs/cli.md +29 -0
  47. package/templates/agent-docs/internationalization.md +131 -13
  48. package/templates/agent-docs/whats-new.md +75 -27
  49. package/templates/apps/api-ai/package.json +7 -7
  50. package/templates/apps/api-auth/package.json +8 -8
  51. package/templates/apps/api-backend/package.json +7 -7
  52. package/templates/apps/api-backend-deactivation/package.json +7 -7
  53. package/templates/apps/api-backend-mail/package.json +8 -8
  54. package/templates/apps/api-backend-mariadb/package.json +9 -9
  55. package/templates/apps/api-backend-sqlite/package.json +8 -8
  56. package/templates/apps/api-backend-storage/package.json +8 -8
  57. package/templates/apps/api-cms/package.json +10 -10
  58. package/templates/apps/api-collab/package.json +8 -8
  59. package/templates/apps/api-data-advanced/package.json +8 -8
  60. package/templates/apps/api-durable/package.json +8 -8
  61. package/templates/apps/api-feature-flags/package.json +9 -9
  62. package/templates/apps/api-governance/package.json +8 -8
  63. package/templates/apps/api-kv/package.json +8 -8
  64. package/templates/apps/api-moderation/package.json +8 -8
  65. package/templates/apps/api-observability/package.json +8 -8
  66. package/templates/apps/api-ratelimit/package.json +8 -8
  67. package/templates/apps/api-rbac/package.json +8 -8
  68. package/templates/apps/api-rest/package.json +7 -7
  69. package/templates/apps/api-saas/package.json +11 -11
  70. package/templates/apps/api-saas-starter/package.json +10 -10
  71. package/templates/apps/api-search/package.json +8 -8
  72. package/templates/apps/api-status/package.json +8 -8
  73. package/templates/apps/api-versioning/package.json +8 -8
  74. package/templates/apps/api-webhooks/package.json +9 -9
  75. package/templates/apps/changelog/package.json +6 -6
  76. package/templates/apps/edge-functions/package.json +2 -2
  77. package/templates/apps/frontend-admin/package.json +8 -8
  78. package/templates/apps/frontend-app/package.json +9 -9
  79. package/templates/apps/frontend-auth/package.json +8 -8
  80. package/templates/apps/frontend-blank/package.json +7 -7
  81. package/templates/apps/frontend-cms/package.json +9 -9
  82. package/templates/apps/frontend-collab/package.json +10 -10
  83. package/templates/apps/frontend-contact/package.json +7 -7
  84. package/templates/apps/frontend-dashboard/package.json +7 -7
  85. package/templates/apps/frontend-docs/package.json +7 -7
  86. package/templates/apps/frontend-i18n/package.json +6 -6
  87. package/templates/apps/frontend-landing/package.json +7 -7
  88. package/templates/apps/frontend-portal/package.json +8 -8
  89. package/templates/apps/frontend-saas/package.json +8 -8
  90. package/templates/apps/frontend-spa/package.json +7 -7
  91. package/templates/apps/frontend-ssr/package.json +7 -7
  92. package/templates/apps/frontend-ssr-api/package.json +8 -8
  93. package/templates/apps/frontend-static-blog/package.json +6 -6
  94. package/templates/apps/frontend-status/package.json +8 -8
  95. package/templates/apps/mobile-app/package.json +4 -4
  96. package/dist/apiBuild-BZ-plaQN.js +0 -2
  97. package/dist/appGraph-CM9wvUmD.js +0 -2
  98. package/dist/appGraph-Cv2W_wO5.js +0 -111
  99. package/dist/dbCommand-Bnl7MSGC.js +0 -2
  100. package/dist/doctorCommand-BlciWUJb.js +0 -2
  101. package/dist/serveCommand-Bbgg7Paq.js +0 -2
  102. package/dist/updateCommand-BweY17z-.js +0 -2
  103. package/dist/webDev-BcRFTsMA.js +0 -2
@@ -1,20 +1,20 @@
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-C0cbqysu.js";
3
+ import { c as r, i, o as a, z as o } from "./dev-kdAg9Q7l.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";
7
7
  import { o as m, t as h } from "./inspectFetch-EMuhTG_9.js";
8
- import { r as g } from "./dbCommand-Bf7Cy0mn.js";
8
+ import { r as g } from "./dbCommand-If4Y1xQ-.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 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
- import { createHash as pe } from "node:crypto";
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";
11
+ import { DATA_TRANSFERS_TABLE as y, REPLACE_IN_PROGRESS_TABLE as b, _voltroDataTransfersTable as x, _voltroReplaceInProgressTable as S, connectionIdentity as C, derivedRowId as w, ensureTableRegistered as T, normaliseTarget as ee, sameDatabase as te, streamTable as ne } from "@voltro/database";
12
+ import { Cause as E, Effect as D, Exit as re, Option as ie, Stream as ae } from "effect";
13
+ import { SqlClient as oe } from "@effect/sql";
14
+ import { declaredSnapshot as se, fingerprintSchema as ce, introspectSchema as le } from "@voltro/database/sql";
15
+ import { STORAGE_REFS_TABLE as ue, appStorageProvider as de, configuredStorageProvider as O } from "@voltro/plugin-storage";
16
+ import { createHash as fe } from "node:crypto";
17
+ import { ASSETS_DIR as k, ASSET_INDEX_FILE as A, BundleError as pe, asImportError as me, assessLiveImport as he, backupArtifactName as j, backupCommand as ge, captureAssetsToCas as _e, classificationFromSnapshot as ve, decryptStream as M, encryptStream as ye, packBundle as be, peekBundle as N, previewMasking as xe, restoreAssetsFromCas as Se, restoreCommand as Ce, runExport as we, runImport as Te, runNativeStep as Ee, 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
@@ -100,7 +100,7 @@ var Fe = /* @__PURE__ */ new Set([
100
100
  i += a.byteLength, yield s;
101
101
  }
102
102
  yield* a(!0);
103
- }, ze = (e) => pe("sha256").update(Buffer.from(e)).digest("hex"), Be = async (e) => {
103
+ }, ze = (e) => fe("sha256").update(Buffer.from(e)).digest("hex"), Be = async (e) => {
104
104
  let t = 0, n = 0, r = {
105
105
  status: 0,
106
106
  body: {}
@@ -150,9 +150,15 @@ var Fe = /* @__PURE__ */ new Set([
150
150
  if (n.stampVersion !== 1 || typeof n.dialect != "string" || typeof n.voltroVersion != "string" || typeof n.createdAt != "string") return null;
151
151
  let r = n.schemaFingerprint;
152
152
  if (r !== null && typeof r != "string") return null;
153
- let i = n.assets, a = typeof i == "object" && i && typeof i.count == "number" && typeof i.totalBytes == "number" ? {
153
+ let i = n.assets, a = (e) => {
154
+ let t = i?.[e];
155
+ return typeof t == "number" ? t : void 0;
156
+ }, o = typeof i == "object" && i && typeof i.count == "number" && typeof i.totalBytes == "number" ? {
154
157
  count: i.count,
155
- totalBytes: i.totalBytes
158
+ totalBytes: i.totalBytes,
159
+ ...a("references") === void 0 ? {} : { references: a("references") },
160
+ ...a("objects") === void 0 ? {} : { objects: a("objects") },
161
+ ...a("objectBytes") === void 0 ? {} : { objectBytes: a("objectBytes") }
156
162
  } : null;
157
163
  return {
158
164
  stampVersion: 1,
@@ -160,56 +166,72 @@ var Fe = /* @__PURE__ */ new Set([
160
166
  schemaFingerprint: r,
161
167
  voltroVersion: n.voltroVersion,
162
168
  createdAt: n.createdAt,
163
- assets: a
169
+ assets: o
164
170
  };
165
171
  }, Ue = (e) => {
166
- let { stamp: t, currentDialect: n, currentFingerprint: r } = e;
172
+ let { stamp: t, currentDialect: n, targetFingerprint: r } = e;
167
173
  if (t === null) return {
168
174
  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
175
  info: []
170
176
  };
171
177
  let i = [`backup produced by @voltro/cli ${t.voltroVersion} at ${t.createdAt}`, `schema fingerprint: ${t.schemaFingerprint ?? "<none recorded>"}`];
172
178
  return t.dialect === n ? t.schemaFingerprint !== null && r !== null && t.schemaFingerprint !== r ? {
173
- warn: `schema skew — the backup's schema (${t.schemaFingerprint.slice(0, 12)}) differs from what this code declares (${r.slice(0, 12)}). Run \`voltro db apply\` after the restore, or the app may boot against a schema it doesn't understand.`,
179
+ warn: `schema skew — the backup's schema (${t.schemaFingerprint.slice(0, 12)}) differs from the schema this TARGET database currently has (${r.slice(0, 12)}). This compares the backup against the target's present state, not against what your code declares. The restore replaces the target's schema with the backup's; run \`voltro db apply\` afterwards to bring it to what the code declares.`,
174
180
  info: i
175
181
  } : { info: i } : {
176
182
  refuse: `dialect mismatch — backup is a ${t.dialect} dump, but DB_DIALECT is ${n}. A cross-dialect restore is never valid.`,
177
183
  info: i
178
184
  };
179
185
  }, We = async (e, t) => {
180
- let n = ee("dimp", `${t.direction}-${t.artifact}-${Date.now()}-${Math.random()}`);
186
+ let n = w("dimp", `${t.direction}-${t.artifact}-${Date.now()}-${Math.random()}`), r = {
187
+ id: n,
188
+ direction: t.direction,
189
+ startedAt: /* @__PURE__ */ new Date(),
190
+ finishedAt: null,
191
+ failure: null,
192
+ mode: `native ${t.dialect}${t.assets ? " + assets" : ""}`,
193
+ via: "cli",
194
+ bundle: t.artifact,
195
+ sourceFingerprint: null,
196
+ tablesWritten: 0,
197
+ rowsWritten: 0,
198
+ staged: null
199
+ };
181
200
  try {
182
- return w(x), await e.insert(y, {
183
- id: n,
184
- direction: t.direction,
185
- startedAt: /* @__PURE__ */ new Date(),
186
- finishedAt: null,
187
- failure: null,
188
- mode: `native ${t.dialect}${t.assets ? " + assets" : ""}`,
189
- via: "cli",
190
- bundle: t.artifact,
191
- sourceFingerprint: null,
192
- tablesWritten: 0,
193
- rowsWritten: 0,
194
- staged: null
195
- }), {
201
+ return T(x), await e.insert(y, r), {
196
202
  runId: n,
197
- recorded: !0
203
+ recorded: !0,
204
+ opened: r
198
205
  };
199
206
  } catch {
200
207
  return {
201
208
  runId: n,
202
- recorded: !1
209
+ recorded: !1,
210
+ opened: r
203
211
  };
204
212
  }
205
213
  }, z = async (e, t, n) => {
206
- t.recorded && await e.update(y, t.runId, {
214
+ if (!t.recorded) return;
215
+ let r = {
207
216
  finishedAt: /* @__PURE__ */ new Date(),
208
217
  failure: n.failure ?? null,
209
218
  ...n.assets === void 0 ? {} : { rowsWritten: n.assets }
210
- }).then(() => void 0, () => void 0);
219
+ };
220
+ if (await e.update(y, t.runId, r).then(() => void 0, () => void 0), !await e.query({
221
+ table: y,
222
+ predicate: void 0,
223
+ order: [],
224
+ take: void 0,
225
+ skip: void 0,
226
+ projection: void 0
227
+ }).then((e) => e.some((e) => String(e.id ?? "") === t.runId), () => !0)) try {
228
+ T(x), await e.insert(y, {
229
+ ...t.opened,
230
+ ...r
231
+ });
232
+ } catch {}
211
233
  }, Ge = async (e, t) => {
212
- let n = ee("repl", `restore-${t.artifact}-${Date.now()}-${Math.random()}`), r = {
234
+ let n = w("repl", `restore-${t.artifact}-${Date.now()}-${Math.random()}`), r = {
213
235
  id: n,
214
236
  startedAt: /* @__PURE__ */ new Date(),
215
237
  kind: "restore",
@@ -218,7 +240,7 @@ var Fe = /* @__PURE__ */ new Set([
218
240
  via: "cli"
219
241
  };
220
242
  try {
221
- w(S), await e.insert(b, r);
243
+ T(S), await e.insert(b, r);
222
244
  } catch {
223
245
  return;
224
246
  }
@@ -236,7 +258,7 @@ var Fe = /* @__PURE__ */ new Set([
236
258
  if (await i()) return "held";
237
259
  } catch {}
238
260
  try {
239
- return w(S), await e.insert(b, r), "rewritten";
261
+ return T(S), await e.insert(b, r), "rewritten";
240
262
  } catch {
241
263
  return "lost";
242
264
  }
@@ -250,14 +272,14 @@ var Fe = /* @__PURE__ */ new Set([
250
272
  }
251
273
  };
252
274
  }, Ke = async (e) => {
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)) {
275
+ let t = await D.runPromiseExit(e);
276
+ if (re.isSuccess(t)) return;
277
+ let n = E.failureOption(t.cause);
278
+ if (ie.isSome(n)) {
257
279
  let e = n.value;
258
280
  return String(e?.message ?? e);
259
281
  }
260
- return T.pretty(t.cause);
282
+ return E.pretty(t.cause);
261
283
  }, B = (e) => {
262
284
  try {
263
285
  let t = new URL(e), n = t.pathname.replace(/^\//, "");
@@ -303,7 +325,7 @@ var Fe = /* @__PURE__ */ new Set([
303
325
  }
304
326
  }, Xe = async (e) => {
305
327
  try {
306
- return le(await tt(e));
328
+ return ce(await tt(e));
307
329
  } catch {
308
330
  return null;
309
331
  }
@@ -335,13 +357,13 @@ var Fe = /* @__PURE__ */ new Set([
335
357
  let t = e.includes("--allow-live"), n = t ? null : await Ze(U(e, "--api-url")), r = C({
336
358
  dialect: G(),
337
359
  ...a()
338
- }), i = te({
360
+ }), i = ee({
339
361
  dialect: G(),
340
362
  ...a()
341
- }), { refuse: o, message: s } = ge({
363
+ }), { refuse: o, message: s } = he({
342
364
  liveInstance: n?.label ?? null,
343
365
  allowLive: t,
344
- sameTarget: ne(r, n?.databaseId),
366
+ sameTarget: te(r, n?.databaseId),
345
367
  ...i === void 0 ? {} : { targetLabel: `${i.host}:${i.port}/${i.database}` }
346
368
  });
347
369
  return !o || (V.error(s ?? "refusing: live instance detected"), !1);
@@ -371,7 +393,7 @@ var Fe = /* @__PURE__ */ new Set([
371
393
  return e;
372
394
  }, et = async (e, t) => {
373
395
  let n = (await l(e)).makeSqlLayer(t);
374
- return E.runPromise(se.SqlClient.pipe(E.flatMap(ue), E.provide(n)));
396
+ return D.runPromise(oe.SqlClient.pipe(D.flatMap(le), D.provide(n)));
375
397
  }, tt = (e) => et(e, a()), nt = () => {
376
398
  let e = a(), t = [];
377
399
  return e.url && t.push(B(e.url)), (e.host || e.database) && t.push(`${(e.host ?? "localhost").toLowerCase()}:${e.port ?? "(default)"}/${e.database ?? ""}`), t;
@@ -384,30 +406,30 @@ var Fe = /* @__PURE__ */ new Set([
384
406
  snapshot: await tt(o),
385
407
  dialect: o
386
408
  };
387
- }, q = (e) => re(e, {
388
- table: de,
409
+ }, rt = (e) => ne(e, {
410
+ table: ue,
389
411
  chunkSize: 500
390
- }).pipe(oe.map((e) => ({
412
+ }).pipe(ae.map((e) => ({
391
413
  key: String(e.key),
392
414
  contentType: String(e.contentType ?? "application/octet-stream"),
393
415
  size: Number(e.size ?? 0)
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) => {
416
+ }))), q = (e) => !!e && e.endsWith(".vbundle"), J = (e) => U(e, "--passphrase") ?? process.env.VOLTRO_BUNDLE_KEY, it = (e) => e.includes("--encrypt") || U(e, "--passphrase") !== void 0 || process.env.VOLTRO_BUNDLE_KEY !== void 0, at = async (e, t) => {
395
417
  let { createWriteStream: n } = await import("node:fs"), { pipeline: r } = await import("node:stream/promises"), { Readable: i } = await import("node:stream");
396
418
  await r(i.from(e), n(t));
397
- }, X = (e) => ({ async *[Symbol.asyncIterator]() {
419
+ }, Y = (e) => ({ async *[Symbol.asyncIterator]() {
398
420
  let { createReadStream: t } = await import("node:fs");
399
421
  for await (let n of t(e)) yield n instanceof Uint8Array ? n : new Uint8Array(n);
400
- } }), at = async (e, t) => {
422
+ } }), ot = async (e, t) => {
401
423
  if (t !== void 0 || e === void 0) return null;
402
424
  try {
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"));
425
+ let { resolve: t, join: n } = await import("node:path"), r = await import("node:fs/promises"), i = t(process.cwd(), e), a = q(e) ? (await N(Y(i), ["manifest.json"])).get("manifest.json") : await r.readFile(n(i, "manifest.json"));
404
426
  if (a === void 0) return null;
405
427
  let o = (JSON.parse(Buffer.from(a).toString("utf8")).tables ?? []).map((e) => e.name).filter((e) => typeof e == "string");
406
428
  return o.length > 0 ? o : null;
407
429
  } catch {
408
430
  return null;
409
431
  }
410
- }, ot = (e) => {
432
+ }, st = (e) => {
411
433
  let t = U(e, "--max-request-seconds") ?? process.env.VOLTRO_MAX_REQUEST_SECONDS;
412
434
  if (t === void 0) return { pollMs: 2e3 };
413
435
  let r = Number(t);
@@ -417,7 +439,7 @@ var Fe = /* @__PURE__ */ new Set([
417
439
  perRequest: { timeoutMs: i },
418
440
  pollMs: Math.max(500, Math.min(2e3, Math.floor(i / 2)))
419
441
  };
420
- }, st = async (e, t, n) => {
442
+ }, ct = async (e, t, n) => {
421
443
  let r = await fetch(`${e.replace(/\/+$/, "")}/_voltro/admin/transfers?limit=50`, { headers: { authorization: `Bearer ${t}` } }).catch(() => null);
422
444
  if (r === null || r.status !== 200) return null;
423
445
  let i = ((await r.json().catch(() => null))?.runs ?? []).find((e) => e.id === n);
@@ -426,7 +448,7 @@ var Fe = /* @__PURE__ */ new Set([
426
448
  startedAt: new Date(String(i.startedAt)),
427
449
  finishedAt: i.finishedAt === null || i.finishedAt === void 0 ? null : new Date(String(i.finishedAt))
428
450
  };
429
- }, ct = async (e) => {
451
+ }, lt = async (e) => {
430
452
  let t = e.apiUrl.replace(/\/+$/, ""), n = [], r = 0, i;
431
453
  for (;;) {
432
454
  let a = `${t}/_voltro/admin/export/download?runId=${encodeURIComponent(e.runId)}&offset=${r}`, o = new AbortController(), s = e.perRequest === void 0 ? void 0 : setTimeout(() => {
@@ -448,12 +470,12 @@ var Fe = /* @__PURE__ */ new Set([
448
470
  e.log.info(` downloading — ${r}/${i ?? "?"} bytes`);
449
471
  }
450
472
  return new Uint8Array(Buffer.concat(n));
451
- }, Z = "transfers", lt = (e) => (e ?? "").split(",").map((e) => e.trim()).filter(Boolean), ut = (e, t) => {
473
+ }, ut = "transfers", dt = (e) => (e ?? "").split(",").map((e) => e.trim()).filter(Boolean), ft = (e, t) => {
452
474
  let r = U(e, "--tenant"), i = U(e, "--tables"), a = U(e, "--exclude");
453
475
  if (a !== void 0) {
454
476
  if (i !== void 0) throw new n("voltro data export: --exclude and --tables are two ways to say the same thing; use one.");
455
477
  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.");
456
- let e = lt(a), o = new Set(t), s = e.filter((e) => !o.has(e));
478
+ let e = dt(a), o = new Set(t), s = e.filter((e) => !o.has(e));
457
479
  if (s.length > 0) throw new n(`voltro data export: --exclude names ${s.length} table(s) that do not exist: ${s.join(", ")}. An exclusion that excludes nothing would leave the run looking like it worked.`);
458
480
  return {
459
481
  kind: "all",
@@ -465,15 +487,15 @@ var Fe = /* @__PURE__ */ new Set([
465
487
  tenantId: r
466
488
  } : i ? {
467
489
  kind: "tables",
468
- tables: lt(i)
490
+ tables: dt(i)
469
491
  } : { kind: "all" };
470
- }, dt = async () => {
492
+ }, pt = async () => {
471
493
  let e = await g(process.cwd());
472
- return ye(ce(e));
473
- }, ft = "voltro/tenant", pt = async () => {
474
- let e = (await g(process.cwd())).filter((e) => (e.appliedMixins ?? []).some((e) => e.id === ft)).map((e) => e.tableName);
494
+ return ve(se(e));
495
+ }, mt = "voltro/tenant", ht = async () => {
496
+ let e = (await g(process.cwd())).filter((e) => (e.appliedMixins ?? []).some((e) => e.id === mt)).map((e) => e.tableName);
475
497
  return e.length > 0 ? e : void 0;
476
- }, mt = (e) => {
498
+ }, gt = (e) => {
477
499
  for (let t of e.tables) if (t.samples.length !== 0) {
478
500
  console.log(`\n ${t.table}`);
479
501
  for (let e of t.samples) console.log(` ${e.column} [${e.action}] ${JSON.stringify(e.before)} → ${JSON.stringify(e.after)}`);
@@ -486,7 +508,7 @@ var Fe = /* @__PURE__ */ new Set([
486
508
  console.log("\n ✗ unclassified (would BLOCK a real export — add .sensitive()/.safe() or a policy override):");
487
509
  for (let t of e.unclassified) console.log(` ${t}`);
488
510
  } else console.log("\n ✓ every exported column is classified — safe to run.");
489
- }, ht = async (e) => {
511
+ }, _t = async (e) => {
490
512
  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);
491
513
  if (!Number.isFinite(o) || o <= 0) throw new n(`--chunk-size expects a positive number of megabytes, got '${String(a)}'`);
492
514
  let s = e.stream[Symbol.asyncIterator](), c = [], l = 0, u = !1;
@@ -502,11 +524,11 @@ var Fe = /* @__PURE__ */ new Set([
502
524
  kind: "small",
503
525
  body: Buffer.concat(c)
504
526
  };
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), {
527
+ 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 I(e.url, Buffer.alloc(0), {
506
528
  ...e.headers,
507
529
  "x-import-upload-id": p,
508
530
  "x-import-probe": "1"
509
- }, $(e.args)), h = m.status === 200 ? Number(JSON.parse(m.body.toString("utf8")).bytes ?? 0) : 0;
531
+ }, Z(e.args)), h = m.status === 200 ? Number(JSON.parse(m.body.toString("utf8")).bytes ?? 0) : 0;
510
532
  h > 0 && e.log.info("api import: resuming a chunked upload the instance already holds", { bytes: h });
511
533
  let g = (async function* () {
512
534
  for (let e of c) yield e;
@@ -529,7 +551,7 @@ var Fe = /* @__PURE__ */ new Set([
529
551
  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.");
530
552
  },
531
553
  target: { send: async (t, n) => {
532
- let r = await I(e.url, t, n, $(e.args)), i = {};
554
+ let r = await I(e.url, t, n, Z(e.args)), i = {};
533
555
  try {
534
556
  i = JSON.parse(r.body.toString("utf8") || "{}");
535
557
  } catch {}
@@ -551,24 +573,24 @@ var Fe = /* @__PURE__ */ new Set([
551
573
  body: Buffer.from(JSON.stringify(v.body))
552
574
  }
553
575
  };
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) => {
576
+ }, vt = (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.`, X = (e, t) => e.includes("--no-atomic") ? !1 : e.includes("--atomic") || t === "replace", yt = (e, t, n) => {
555
577
  if (t !== "replace" || e.includes("--no-rollback")) return;
556
578
  let r = U(e, "--rollback-dir");
557
579
  return r === void 0 ? o(n) : _(r);
558
- }, vt = (e, t, n) => {
559
- let r = _t(e, t, n);
580
+ }, bt = (e, t, n) => {
581
+ let r = yt(e, t, n);
560
582
  return {
561
583
  ...r === void 0 ? {} : { rollbackDir: r },
562
584
  recordInterruption: !0,
563
585
  via: "direct"
564
586
  };
565
- }, $ = (e) => {
587
+ }, Z = (e) => {
566
588
  let t = U(e, "--timeout");
567
589
  if (t === void 0) return {};
568
590
  let r = Number(t);
569
591
  if (!Number.isFinite(r) || r <= 0) throw new n(`--timeout expects a positive number of seconds, got '${t}'`);
570
592
  return { timeoutMs: Math.round(r * 1e3) };
571
- }, yt = async (e) => {
593
+ }, xt = async (e) => {
572
594
  let t = U(e, "--target") === "api", n = U(e, "--bundle-key"), r = W(e);
573
595
  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;
574
596
  if (t) {
@@ -587,12 +609,12 @@ var Fe = /* @__PURE__ */ new Set([
587
609
  ...U(e, "--compression") ? { compression: U(e, "--compression") } : {},
588
610
  ...e.includes("--assets") ? { assets: !0 } : {},
589
611
  ...n ? { bundleKey: n } : {}
590
- }, c = ot(e), l;
612
+ }, c = st(e), l;
591
613
  try {
592
614
  let n = await I(`${t.replace(/\/+$/, "")}/_voltro/admin/export`, JSON.stringify(s), {
593
615
  "content-type": "application/json",
594
616
  authorization: `Bearer ${i}`
595
- }, c.perRequest ?? $(e));
617
+ }, c.perRequest ?? Z(e));
596
618
  if (n.status < 200 || n.status >= 300) return V.error(`api export failed: HTTP ${n.status} — ${n.body.toString("utf8")}`), 1;
597
619
  l = JSON.parse(n.body.toString("utf8"));
598
620
  } catch (e) {
@@ -600,10 +622,10 @@ var Fe = /* @__PURE__ */ new Set([
600
622
  if (e instanceof P) return V.error(`api export: ${L(e)}`), 1;
601
623
  throw e;
602
624
  }
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;
625
+ 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 ${ut} --target api --api-url ${t}`), 0;
604
626
  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;
605
627
  let p = await d({
606
- read: () => st(t, i, l.runId),
628
+ read: () => ct(t, i, l.runId),
607
629
  onTick: (e) => {
608
630
  V.info(f(e));
609
631
  },
@@ -618,7 +640,7 @@ var Fe = /* @__PURE__ */ new Set([
618
640
  tables: p?.tablesWritten ?? 0,
619
641
  rows: p?.rowsWritten ?? 0
620
642
  }), 0;
621
- let { resolve: h } = await import("node:path"), g = await ct({
643
+ let { resolve: h } = await import("node:path"), g = await lt({
622
644
  apiUrl: t,
623
645
  secret: i,
624
646
  runId: l.runId,
@@ -636,9 +658,9 @@ var Fe = /* @__PURE__ */ new Set([
636
658
  }), 0);
637
659
  }
638
660
  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;
661
+ 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 ? O() : void 0;
640
662
  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 } : {};
663
+ let h = U(e, "--compression") ?? a.compression, g = U(e, "--consistency") === "snapshot" ? "snapshot" : a.consistency ?? "live", _ = a.masking, v = a.subset, y = a.scope ?? ft(e, s.tables.map((e) => e.name)), b = _ ? await pt() : void 0, x = y.kind === "tenant" ? await ht() : void 0, S = x ? { tenantTables: x } : {};
642
664
  if (e.includes("--dry-run")) {
643
665
  let e = y.kind === "tables" && y.tables ? [...y.tables] : s.tables.map((e) => e.name);
644
666
  if (V.info("export DRY RUN — nothing was written", {
@@ -650,7 +672,7 @@ var Fe = /* @__PURE__ */ new Set([
650
672
  assets: l,
651
673
  masking: _ ? "profile policy applies" : "none"
652
674
  }), V.info(`would export: ${e.join(", ")}`), !_) return 0;
653
- let t = await E.runPromise(Se({
675
+ let t = await D.runPromise(xe({
654
676
  store: o,
655
677
  snapshot: s,
656
678
  masking: _,
@@ -660,12 +682,12 @@ var Fe = /* @__PURE__ */ new Set([
660
682
  ...S
661
683
  }
662
684
  }));
663
- return mt(t), +(t.unclassified.length > 0);
685
+ return gt(t), +(t.unclassified.length > 0);
664
686
  }
665
- if (J(r)) {
687
+ if (q(r)) {
666
688
  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-"));
667
689
  try {
668
- let t = await E.runPromise(Te({
690
+ let t = await D.runPromise(we({
669
691
  store: o,
670
692
  snapshot: s,
671
693
  dialect: c,
@@ -679,16 +701,16 @@ var Fe = /* @__PURE__ */ new Set([
679
701
  ..._ ? { masking: _ } : {},
680
702
  ...b ? { classification: b } : {},
681
703
  onProgress: H
682
- })), n = xe({
704
+ })), n = be({
683
705
  dir: u,
684
- ...m ? { blobs: Ae(m, () => q(o)) } : {}
685
- }), a = rt(e);
706
+ ...m ? { blobs: Ae(m, () => rt(o)) } : {}
707
+ }), a = it(e);
686
708
  if (a) {
687
- let t = Y(e);
709
+ let t = J(e);
688
710
  if (!t) return V.error("--encrypt requires --passphrase <p> or VOLTRO_BUNDLE_KEY (a dedicated key, NOT the transfer secret)"), 1;
689
- n = be(n, t);
711
+ n = ye(n, t);
690
712
  }
691
- return await it(n, i(process.cwd(), r)), V.info("export complete (single file)", {
713
+ return await at(n, i(process.cwd(), r)), V.info("export complete (single file)", {
692
714
  file: r,
693
715
  encrypted: a,
694
716
  assets: l,
@@ -702,7 +724,7 @@ var Fe = /* @__PURE__ */ new Set([
702
724
  });
703
725
  }
704
726
  }
705
- let C = await E.runPromise(Te({
727
+ let C = await D.runPromise(we({
706
728
  store: o,
707
729
  snapshot: s,
708
730
  dialect: c,
@@ -715,7 +737,7 @@ var Fe = /* @__PURE__ */ new Set([
715
737
  ...h ? { compression: h } : {},
716
738
  ..._ ? { masking: _ } : {},
717
739
  ...b ? { classification: b } : {},
718
- ...m ? { assets: Oe(m, () => q(o)) } : {},
740
+ ...m ? { assets: Oe(m, () => rt(o)) } : {},
719
741
  onProgress: H
720
742
  }));
721
743
  return V.info("export complete", {
@@ -726,13 +748,13 @@ var Fe = /* @__PURE__ */ new Set([
726
748
  compression: C.compression,
727
749
  ...C.masking ? { maskedColumns: C.masking.transformed.length } : {}
728
750
  }), 0;
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) => {
751
+ }, St = () => "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.", Ct = (e) => {
730
752
  let t = U(e, "--tables");
731
753
  return {
732
754
  ...t ? { tables: t.split(",").map((e) => e.trim()).filter(Boolean) } : {},
733
755
  ...e.includes("--dry-run") ? { dryRun: !0 } : {}
734
756
  };
735
- }, St = (e) => ({
757
+ }, wt = (e) => ({
736
758
  tables: e.tablesWritten,
737
759
  rows: e.rowsWritten,
738
760
  carried: e.manifest.tables.reduce((e, t) => e + t.rowCount, 0),
@@ -740,9 +762,9 @@ var Fe = /* @__PURE__ */ new Set([
740
762
  skippedTables: e.tablesSkipped,
741
763
  skippedRows: e.rowsSkipped
742
764
  } : {}
743
- }), Ct = (e, t) => {
765
+ }), Tt = (e, t) => {
744
766
  if (e.includes("--dry-run")) {
745
- V.info("import DRY RUN — nothing was written", t), V.info(bt());
767
+ V.info("import DRY RUN — nothing was written", t), V.info(St());
746
768
  return;
747
769
  }
748
770
  if (t.rows === 0 && typeof t.skippedRows == "number" && t.skippedRows !== 0) {
@@ -750,8 +772,8 @@ var Fe = /* @__PURE__ */ new Set([
750
772
  return;
751
773
  }
752
774
  V.info("import complete", t);
753
- }, wt = Symbol("refused"), Tt = (e) => {
754
- let t = he(e) ?? e;
775
+ }, Et = Symbol("refused"), Q = (e) => {
776
+ let t = me(e) ?? e;
755
777
  if (t?._tag !== "RowsRefusedError" || !Array.isArray(t.rows)) return !1;
756
778
  let n = t.rows, r = n.filter((e) => !e.derived), i = Number(t.totalCount ?? n.length), a = Number(t.primaryCount ?? r.length);
757
779
  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.`);
@@ -761,7 +783,7 @@ var Fe = /* @__PURE__ */ new Set([
761
783
  n.length < i && V.error(` (the list above is capped at ${n.length} of ${i} — the counts by table are complete)`);
762
784
  let s = i - a;
763
785
  return s > 0 && V.error(` … and ${s} row(s) behind them. Fix the ${a} above and re-run; they resolve with their parents.`), !0;
764
- }, Et = (e) => {
786
+ }, Dt = (e) => {
765
787
  let t = typeof e == "string" ? e : e.toString("utf8"), n = t;
766
788
  try {
767
789
  let e = JSON.parse(t), r = e.error ?? e.message;
@@ -801,7 +823,7 @@ var Fe = /* @__PURE__ */ new Set([
801
823
  return;
802
824
  }
803
825
  }
804
- }, Dt = async (e) => {
826
+ }, Ot = async (e) => {
805
827
  let t = U(e, "--target") === "api", n = U(e, "--bundle-key"), r = W(e);
806
828
  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
829
  let i = U(e, "--mode") ?? "upsert", o = U(e, "--on-conflict") ?? "skip";
@@ -816,7 +838,7 @@ var Fe = /* @__PURE__ */ new Set([
816
838
  authorization: `Bearer ${a}`,
817
839
  "x-import-mode": i,
818
840
  "x-import-on-conflict": o,
819
- ...Q(e, i) ? { "x-import-atomic": "1" } : {},
841
+ ...X(e, i) ? { "x-import-atomic": "1" } : {},
820
842
  ...e.includes("--no-atomic") ? { "x-import-atomic": "0" } : {},
821
843
  ...c === void 0 ? {} : { "x-import-rollback-key": c },
822
844
  ...e.includes("--force") ? { "x-import-force": "1" } : {},
@@ -824,34 +846,34 @@ var Fe = /* @__PURE__ */ new Set([
824
846
  ...s ? { "x-import-tables": s } : {}
825
847
  }, { resolve: p } = await import("node:path"), m;
826
848
  if (n) l["content-type"] = "application/json", m = JSON.stringify({ bundleKey: n });
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) });
849
+ else if (q(r)) {
850
+ let t = Y(p(process.cwd(), r)), n = J(e);
851
+ n && (t = M(t, n)), l["content-type"] = "application/octet-stream", m = t;
852
+ } 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 = be({ dir: p(process.cwd(), r) });
831
853
  if (i === "replace") {
832
- let i = await at(r, n);
854
+ let i = await ot(r, n);
833
855
  {
834
856
  let r = i === null ? { bundleKey: n } : { tables: i }, a = await I(`${t.replace(/\/+$/, "")}/_voltro/admin/import`, JSON.stringify(r), {
835
857
  ...l,
836
858
  "content-type": "application/json",
837
859
  "x-import-preflight": "1"
838
- }, $(e)).catch(() => null), o = a !== null && a.status === 200 ? JSON.parse(a.body.toString("utf8")) : null;
860
+ }, Z(e)).catch(() => null), o = a !== null && a.status === 200 ? JSON.parse(a.body.toString("utf8")) : null;
839
861
  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
840
862
  interrupted run leaves the target empty.\n Reason: ${o.reason ?? "not stated"}`);
841
863
  }
842
864
  }
843
- i === "replace" && !Q(e, i) && V.warn(gt(!0));
844
- let h = `${t.replace(/\/+$/, "")}/_voltro/admin/import`, g = ot(e), _;
865
+ i === "replace" && !X(e, i) && V.warn(vt(!0));
866
+ let h = `${t.replace(/\/+$/, "")}/_voltro/admin/import`, g = st(e), _;
845
867
  try {
846
- let t = typeof m == "string" ? null : await ht({
868
+ let t = typeof m == "string" ? null : await _t({
847
869
  stream: m,
848
870
  url: h,
849
871
  headers: l,
850
872
  bundleDir: r,
851
873
  args: e,
852
874
  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;
875
+ }), n = t === null ? await I(h, m, l, g.perRequest ?? Z(e)) : t.kind === "sent" ? t.res : await I(h, t.body, l, g.perRequest ?? Z(e));
876
+ if (n.status < 200 || n.status >= 300) return Q(Dt(n.body)) || V.error(`api import failed: HTTP ${n.status} — ${n.body.toString("utf8")}`), 1;
855
877
  _ = JSON.parse(n.body.toString("utf8"));
856
878
  } catch (e) {
857
879
  if (e instanceof F) return V.error(`api import: ${Ie(e, i)}`), 1;
@@ -861,17 +883,17 @@ var Fe = /* @__PURE__ */ new Set([
861
883
  let v = await I(`${t.replace(/\/+$/, "")}/_voltro/admin/import/start`, JSON.stringify(_.bundleKey === void 0 ? { uploadId: _.uploadId } : { bundleKey: _.bundleKey }), {
862
884
  ...l,
863
885
  "content-type": "application/json"
864
- }, g.perRequest ?? $(e)).catch((e) => {
886
+ }, g.perRequest ?? Z(e)).catch((e) => {
865
887
  if (e instanceof P) return V.error(`api import: ${L(e)}`), null;
866
888
  throw e;
867
889
  });
868
890
  if (v === null) return 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;
891
+ if (v.status < 200 || v.status >= 300) return Q(Dt(v.body)) || V.error(`api import refused: HTTP ${v.status} — ${v.body.toString("utf8")}`), 1;
870
892
  let y = JSON.parse(v.body.toString("utf8"));
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;
893
+ 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 ${ut} --target api --api-url ${t}`), 0;
872
894
  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;
873
895
  let b = await d({
874
- read: () => st(t, a, y.runId),
896
+ read: () => ct(t, a, y.runId),
875
897
  onTick: (e) => {
876
898
  V.info(f(e));
877
899
  },
@@ -880,10 +902,10 @@ var Fe = /* @__PURE__ */ new Set([
880
902
  }), x = u(b);
881
903
  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
882
904
  proxy dropping the GET, or a target with no history table. The run itself is unaffected and
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", {
905
+ 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 ${ut} --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", {
884
906
  via: t,
885
907
  runId: y.runId
886
- }), V.info(bt()), 0) : (V.info("api import complete (imported by the running instance)", {
908
+ }), V.info(St()), 0) : (V.info("api import complete (imported by the running instance)", {
887
909
  via: t,
888
910
  runId: y.runId,
889
911
  tables: b?.tablesWritten ?? 0,
@@ -893,28 +915,28 @@ var Fe = /* @__PURE__ */ new Set([
893
915
  }
894
916
  if (!r) return V.error("a <bundleDir> is required for a direct import"), 1;
895
917
  if (!await Qe(e)) return 1;
896
- i === "replace" && e.includes("--allow-live") && !Q(e, i) && V.warn(gt(!1));
918
+ i === "replace" && e.includes("--allow-live") && !X(e, i) && V.warn(vt(!1));
897
919
  let { store: s, snapshot: c } = await K();
898
920
  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;
921
+ let l = e.includes("--force"), p = (e) => V.warn(e), m = e.includes("--assets"), h = m ? O() : void 0;
900
922
  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
923
  let g = G() === "postgres" ? (await import("@voltro/sql-postgres")).makePgCopySession(a()) : void 0;
902
- if (J(r)) {
924
+ if (q(r)) {
903
925
  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-"));
904
926
  try {
905
- let t = X(a(process.cwd(), r)), n = Y(e);
906
- return n && (t = j(t, n)), await je(t, {
927
+ let t = Y(a(process.cwd(), r)), n = J(e);
928
+ return n && (t = M(t, n)), await je(t, {
907
929
  dir: d,
908
- blobs: ke(h ?? fe())
909
- }), Ct(e, {
930
+ blobs: ke(h ?? de())
931
+ }), Tt(e, {
910
932
  file: r,
911
- ...St(await E.runPromise(Ee({
933
+ ...wt(await D.runPromise(Te({
912
934
  store: s,
913
935
  bundleDir: d,
914
936
  mode: i,
915
937
  onConflict: o,
916
- atomic: Q(e, i),
917
- ...vt(e, i, r),
938
+ atomic: X(e, i),
939
+ ...bt(e, i, r),
918
940
  verify: !e.includes("--no-verify"),
919
941
  targetDialect: G(),
920
942
  allowIncompatible: l,
@@ -923,7 +945,7 @@ var Fe = /* @__PURE__ */ new Set([
923
945
  onWarn: p,
924
946
  onProgress: H,
925
947
  assetsAlreadyRestored: !0,
926
- ...xt(e),
948
+ ...Ct(e),
927
949
  ...g ? { copyLoader: g } : {}
928
950
  })))
929
951
  }), 0;
@@ -934,13 +956,13 @@ var Fe = /* @__PURE__ */ new Set([
934
956
  });
935
957
  }
936
958
  }
937
- let _ = await E.runPromise(Ee({
938
- ...vt(e, i, r),
959
+ let _ = await D.runPromise(Te({
960
+ ...bt(e, i, r),
939
961
  store: s,
940
962
  bundleDir: r,
941
963
  mode: i,
942
964
  onConflict: o,
943
- atomic: Q(e, i),
965
+ atomic: X(e, i),
944
966
  verify: !e.includes("--no-verify"),
945
967
  targetDialect: G(),
946
968
  allowIncompatible: l,
@@ -948,19 +970,19 @@ var Fe = /* @__PURE__ */ new Set([
948
970
  force: l,
949
971
  onWarn: p,
950
972
  onProgress: H,
951
- ...xt(e),
973
+ ...Ct(e),
952
974
  ...h ? { assets: De(h) } : {},
953
975
  ...g ? { copyLoader: g } : {}
954
976
  })).catch((e) => {
955
- if (Tt(e)) return wt;
977
+ if (Q(e)) return Et;
956
978
  throw e;
957
979
  }).finally(() => g?.close());
958
- return typeof _ == "symbol" ? 1 : (Ct(e, {
980
+ return typeof _ == "symbol" ? 1 : (Tt(e, {
959
981
  bundleDir: r,
960
- ...St(_),
982
+ ...wt(_),
961
983
  assets: _.manifest.assets.count
962
984
  }), 0);
963
- }, Ot = () => {
985
+ }, kt = () => {
964
986
  let e = a();
965
987
  return {
966
988
  ...e.url ? { url: e.url } : {},
@@ -970,42 +992,42 @@ var Fe = /* @__PURE__ */ new Set([
970
992
  ...e.password ? { password: e.password } : {},
971
993
  ...e.database ? { database: e.database } : {}
972
994
  };
973
- }, kt = async (e) => {
995
+ }, At = async (e) => {
974
996
  let t = W(e);
975
997
  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;
998
+ let n = G(), r = e.includes("--assets"), { mkdir: i, writeFile: a } = await import("node:fs/promises"), { join: o } = await import("node:path"), s = await Mt(), c = r ? O() : void 0;
977
999
  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;
978
1000
  await i(t, { recursive: !0 });
979
- let l = o(t, A(n)), u = s ? await We(s.store, {
1001
+ let l = o(t, j(n)), u = Pt(s), d = Ft(s), f = u ? await We(u, {
980
1002
  direction: "backup",
981
1003
  dialect: n,
982
1004
  artifact: l,
983
1005
  assets: r
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) => {
1006
+ }) : void 0, p = await Ke(Ee(ge(n, kt(), l)));
1007
+ if (p !== void 0) return u && f && await z(u, f, { failure: p }), V.error(`native backup failed: ${p}`), 1;
1008
+ let m = await Xe(n), h = await Ye(), g = (/* @__PURE__ */ new Date()).toISOString(), _ = async (e) => {
987
1009
  let r = Ve({
988
1010
  dialect: n,
989
- schemaFingerprint: f,
990
- voltroVersion: p,
991
- createdAt: m,
1011
+ schemaFingerprint: m,
1012
+ voltroVersion: h,
1013
+ createdAt: g,
992
1014
  assets: e
993
1015
  });
994
1016
  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);
1017
+ }, v = 0, y = 0, b = [], x = 0, S = 0, C = 0;
1018
+ if (c && u) {
1019
+ let e = o(t, k);
998
1020
  await i(e, { recursive: !0 });
999
- let n = o(t, k), r = s.store, a = await E.runPromiseExit(ve({
1000
- source: Oe(c, () => q(r)),
1021
+ let n = o(t, A), r = u, a = await D.runPromiseExit(_e({
1022
+ source: Oe(c, () => rt(r)),
1001
1023
  assetsDir: e,
1002
1024
  progress: {
1003
1025
  done: () => !1,
1004
- mark: (e, t) => E.tryPromise({
1026
+ mark: (e, t) => D.tryPromise({
1005
1027
  try: async () => {
1006
1028
  await (await import("node:fs/promises")).appendFile(n, `${JSON.stringify(t)}\n`);
1007
1029
  },
1008
- catch: (e) => new me({
1030
+ catch: (e) => new pe({
1009
1031
  reason: `asset index append failed: ${String(e)}`,
1010
1032
  path: n
1011
1033
  })
@@ -1013,34 +1035,52 @@ var Fe = /* @__PURE__ */ new Set([
1013
1035
  }
1014
1036
  }));
1015
1037
  if (a._tag === "Failure") {
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
1038
+ let e = E.pretty(a.cause);
1039
+ return f && await z(u, f, { failure: `assets: ${e}` }), await _(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
1018
1040
  backend is reachable, or restore without --assets and accept the dangling refs.`), 1;
1019
1041
  }
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` : ""));
1042
+ v = a.value.count, y = a.value.totalBytes, b = a.value.missing, x = a.value.objects, S = a.value.objectBytes, C = a.value.references, b.length > 0 && V.warn(`${b.length} of ${b.length + v} 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.
1043
+ e.g. ${b.slice(0, 3).map((e) => `'${e}'`).join(", ")}` + (b.length > 3 ? `, and ${b.length - 3} more` : ""));
1022
1044
  }
1023
- let y = await h(r ? {
1024
- count: g,
1025
- totalBytes: _
1045
+ let w = await _(r ? {
1046
+ count: v,
1047
+ totalBytes: y,
1048
+ references: C,
1049
+ objects: x,
1050
+ objectBytes: S
1026
1051
  } : null);
1027
- return s && u && await z(s.store, u, { assets: g }), V.info("native backup complete", {
1052
+ return u && f && await z(u, f, { assets: v }), V.info("native backup complete", {
1028
1053
  dialect: n,
1029
1054
  artifact: l,
1030
1055
  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`",
1033
- recorded: u?.recorded === !0 ? "voltro data transfers" : "NOT recorded (this target keeps no transfer history)"
1056
+ schemaFingerprint: w.schemaFingerprint ?? "<none>",
1057
+ assets: r ? `${v} key(s) → ${x} object(s), ${S} byte(s) under ${k}/ (from ${C} reference(s))` + (b.length > 0 ? ` — ${b.length} reference(s) had no object and are NOT in here` : "") : "NOT included — re-run with --assets, or use `voltro data export --assets`",
1058
+ recorded: jt(f, d)
1034
1059
  }), 0;
1035
- }, At = async () => {
1060
+ }, jt = (e, t) => e?.recorded === !0 ? "voltro data transfers" : t === void 0 ? "NOT recorded (this target keeps no transfer history)" : `NOT recorded — bookkeeping was unavailable HERE, not at the target: ${t}`, Mt = async () => {
1061
+ let e;
1036
1062
  try {
1037
- let e = await r(process.cwd());
1038
- return e ? { store: await i(e, void 0) } : void 0;
1039
- } catch {
1040
- return;
1063
+ e = await r(process.cwd());
1064
+ } catch (e) {
1065
+ return {
1066
+ unavailable: "store-unopenable",
1067
+ reason: `app.config.ts could not be loaded: ${Nt(e)}`
1068
+ };
1069
+ }
1070
+ if (!e) return { unavailable: "no-app-config" };
1071
+ try {
1072
+ return { store: await i(e, void 0) };
1073
+ } catch (e) {
1074
+ return {
1075
+ unavailable: "store-unopenable",
1076
+ reason: Nt(e)
1077
+ };
1041
1078
  }
1042
- }, jt = async (e, t) => {
1043
- let n = G(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(e, A(n)), o = qe({
1079
+ }, Nt = (e) => {
1080
+ let t = e?.message, n = typeof t == "string" && t.trim() !== "" ? t : String(e);
1081
+ return n.split("\n")[0] ?? n;
1082
+ }, Pt = (e) => "store" in e ? e.store : void 0, Ft = (e) => "store" in e ? void 0 : e.unavailable === "no-app-config" ? "no app.config.ts was found from this directory, so there is no store to record through" : e.reason, It = async (e, t) => {
1083
+ let n = G(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(e, j(n)), o = qe({
1044
1084
  flagUrl: U(t, "--drill-url"),
1045
1085
  envUrl: process.env.DRILL_DB_URL,
1046
1086
  liveKeys: nt()
@@ -1051,11 +1091,11 @@ var Fe = /* @__PURE__ */ new Set([
1051
1091
  V.info("restore drill: restoring into throwaway DB", {
1052
1092
  dialect: n,
1053
1093
  target: B(o.url)
1054
- }), await E.runPromise(N(we(n, { url: o.url }, a)));
1094
+ }), await D.runPromise(Ee(Ce(n, { url: o.url }, a)));
1055
1095
  let c = null, l = 0;
1056
1096
  try {
1057
1097
  let e = await et(n, { url: o.url });
1058
- c = le(e), l = e.tables.length;
1098
+ c = ce(e), l = e.tables.length;
1059
1099
  } catch (e) {
1060
1100
  return V.error(`restore --drill: could not introspect the restored DB — ${String(e)}`), 1;
1061
1101
  }
@@ -1066,61 +1106,66 @@ var Fe = /* @__PURE__ */ new Set([
1066
1106
  });
1067
1107
  for (let e of u.lines) u.pass ? V.info(`restore drill: ${e}`) : V.error(`restore drill: ${e}`);
1068
1108
  return +!u.pass;
1069
- }, Mt = async (e) => {
1109
+ }, Lt = async (e) => {
1070
1110
  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;
1072
- if (e.includes("--drill")) return jt(t, e);
1111
+ if (!t) return V.error("usage: voltro data restore <backupDir> [--assets] [--allow-live] [--api-url <url>] [--force] [--no-marker] [--drill [--drill-url <url>]] (native pg_restore/mariadb/…)"), 1;
1112
+ if (e.includes("--drill")) return It(t, e);
1073
1113
  if (!await Qe(e)) return 1;
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({
1114
+ let n = G(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(t, j(n)), o = e.includes("--assets"), s = Ue({
1075
1115
  stamp: await i(r(t, R), "utf8").then(He, () => null),
1076
1116
  currentDialect: n,
1077
- currentFingerprint: await Xe(n)
1117
+ targetFingerprint: await Xe(n)
1078
1118
  });
1079
1119
  for (let e of s.info) V.info(`backup stamp: ${e}`);
1080
1120
  if (s.warn && V.warn(s.warn), s.refuse) {
1081
1121
  if (!e.includes("--force")) return V.error(`restore refused: ${s.refuse} (pass --force to override)`), 1;
1082
1122
  V.warn(`restore proceeding despite: ${s.refuse} (--force)`);
1083
1123
  }
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
1124
+ let c = r(t, A), l = await i(c, "utf8").then(() => !0, () => !1);
1125
+ if (o && !l) return V.error(`--assets: this backup carries no assets — there is no ${A} in ${t}.\n It was taken without --assets, so its rows will reference blobs this restore cannot
1086
1126
  put back. Restore from a backup taken with --assets, or drop the flag to accept that.`), 1;
1087
1127
  !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;
1128
+ let u = await Mt(), d = o ? O() : void 0;
1089
1129
  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.
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
1093
- database. Run \`voltro db apply\` so the table exists, then retry.`), 1;
1094
- let p = u ? await We(u.store, {
1130
+ let f = Ft(u), p = e.includes("--no-marker"), m = Pt(u), h = m ? await Ge(m, { artifact: a }) : void 0, g = f === void 0 ? h === void 0 ? `the marker row could not be written to \`${b}\` (run \`voltro db apply\` so the table exists)` : void 0 : `bookkeeping is unavailable: ${f}`;
1131
+ if (g !== void 0 && !p) return V.error(`refusing to restore: the in-progress marker cannot be written.
1132
+ reason: ${g}\n The marker is one row in \`${b}\`, written before the first\n destructive statement so a killed restore refuses the next boot instead of serving a
1133
+ half-loaded database. Without it this restore has no guard at all.
1134
+ Fix the reason above, or pass --no-marker to restore WITHOUT that protection,
1135
+ deliberately.`), 1;
1136
+ g !== void 0 && V.warn(`--no-marker: restoring with NO in-progress marker. If this run does not finish, nothing
1137
+ will stop the next boot from serving a half-loaded database.
1138
+ ${g}`);
1139
+ let _ = m ? await We(m, {
1095
1140
  direction: "restore",
1096
1141
  dialect: n,
1097
1142
  artifact: a,
1098
1143
  assets: o
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;
1144
+ }) : void 0, v = await Ke(Ee(Ce(n, kt(), a))), y = h === void 0 ? "lost" : await h.reassert();
1145
+ if (y === "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
1146
+ and hand-made dumps.`) : y === "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
1147
+ result of this command before you start the app.`), v !== void 0) return m && _ && await z(m, _, { failure: v }), V.error(`native restore failed: ${v}\n` + (y === "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;
1148
+ let x = 0, S = 0;
1104
1149
  if (d) {
1105
- let e = await E.runPromiseExit(Ce({
1150
+ let e = await D.runPromiseExit(Se({
1106
1151
  sink: De(d),
1107
- assetsDir: r(t, O),
1152
+ assetsDir: r(t, k),
1108
1153
  indexPath: c
1109
1154
  }));
1110
1155
  if (e._tag === "Failure") {
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
1156
+ let t = E.pretty(e.cause);
1157
+ return m && _ && await z(m, _, { 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
1113
1158
  \`voltro data restore <dir> --assets\` once storage is reachable.`), 1;
1114
1159
  }
1115
- g = e.value;
1160
+ x = e.value.count, S = e.value.objects;
1116
1161
  }
1117
- return f && await f.clear(), u && p && await z(u.store, p, { assets: g }), V.info("native restore complete", {
1162
+ return h && await h.clear(), m && _ && await z(m, _, { assets: x }), V.info("native restore complete", {
1118
1163
  dialect: n,
1119
1164
  artifact: a,
1120
- assets: o ? `${g} blob(s) restored` : "not restored (no --assets)",
1121
- recorded: p?.recorded === !0 ? "voltro data transfers" : "NOT recorded (this target keeps no transfer history)"
1165
+ assets: o ? `${x} key(s) restored from ${S} object(s)` : "not restored (no --assets)",
1166
+ recorded: jt(_, f)
1122
1167
  }), 0;
1123
- }, Nt = async (e) => {
1168
+ }, Rt = async (e) => {
1124
1169
  let t = W(e);
1125
1170
  if (!t) return V.error("usage: voltro data inspect <file.vbundle|dir> [--json] [--passphrase <p>]"), 1;
1126
1171
  let { resolve: n, join: r } = await import("node:path"), i = await import("node:fs/promises"), a = n(process.cwd(), t);
@@ -1133,19 +1178,19 @@ var Fe = /* @__PURE__ */ new Set([
1133
1178
  let s = await i.readFile(n, "utf8").catch(() => void 0);
1134
1179
  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);
1135
1180
  }
1136
- let o = Y(e), s = () => {
1137
- let e = X(a);
1138
- return o ? j(e, o) : e;
1181
+ let o = J(e), s = () => {
1182
+ let e = Y(a);
1183
+ return o ? M(e, o) : e;
1139
1184
  };
1140
1185
  if (e.includes("--json")) {
1141
- let e = (await M(s(), ["manifest.json"])).get("manifest.json");
1186
+ let e = (await N(s(), ["manifest.json"])).get("manifest.json");
1142
1187
  return e ? (console.log(e.toString("utf8")), 0) : (V.error("no manifest.json found in the bundle"), 1);
1143
1188
  }
1144
- let c = (await M(s(), ["README.md"])).get("README.md");
1189
+ let c = (await N(s(), ["README.md"])).get("README.md");
1145
1190
  if (c) return console.log(c.toString("utf8")), 0;
1146
- let l = (await M(s(), ["manifest.json"])).get("manifest.json");
1191
+ let l = (await N(s(), ["manifest.json"])).get("manifest.json");
1147
1192
  return l ? (console.log(l.toString("utf8")), 0) : (V.error("bundle has no README.md or manifest.json"), 1);
1148
- }, Pt = async (e) => {
1193
+ }, zt = async (e) => {
1149
1194
  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
1195
  if (i === void 0) return V.info("no interrupted replace is recorded — nothing to clear"), 0;
1151
1196
  if (!e.includes("--yes")) return V.error(`${i}\n\n Re-run with --yes to clear it.`), 1;
@@ -1159,12 +1204,12 @@ var Fe = /* @__PURE__ */ new Set([
1159
1204
  });
1160
1205
  for (let e of a) await r.delete(t, String(e.id));
1161
1206
  return V.info(`cleared ${a.length} interrupted-replace marker(s) — the next boot will start`), 0;
1162
- }, Ft = async (e) => {
1207
+ }, Bt = async (e) => {
1163
1208
  let { STAGING_PREFIX: t, dropStagingSql: n, execStatements: r } = await import("@voltro/data-transfer"), { store: i } = await K(), a = G();
1164
1209
  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;
1165
1210
  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));
1166
1211
  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);
1167
- }, It = async (e) => {
1212
+ }, Vt = async (e) => {
1168
1213
  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
1214
  if (U(e, "--target") === "api") {
1170
1215
  let t = U(e, "--api-url");
@@ -1207,15 +1252,15 @@ var Fe = /* @__PURE__ */ new Set([
1207
1252
  })}`);
1208
1253
  }
1209
1254
  return 0;
1210
- }, Lt = async (e) => {
1255
+ }, Ht = async (e) => {
1211
1256
  let t = W(e), n = W(e.filter((e) => e !== t));
1212
1257
  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", {
1258
+ let { resolve: r } = await import("node:path"), i = Y(r(process.cwd(), t)), a = J(e);
1259
+ return a && (i = M(i, a)), await Me(i, r(process.cwd(), n)), V.info("unpack complete", {
1215
1260
  file: t,
1216
1261
  dir: n
1217
1262
  }), 0;
1218
- }, Rt = {
1263
+ }, $ = {
1219
1264
  export: {
1220
1265
  common: [
1221
1266
  "--target",
@@ -1291,44 +1336,45 @@ var Fe = /* @__PURE__ */ new Set([
1291
1336
  "--assets",
1292
1337
  "--allow-live",
1293
1338
  "--force",
1339
+ "--no-marker",
1294
1340
  "--drill",
1295
1341
  "--drill-url",
1296
1342
  "--api-url"
1297
1343
  ] }
1298
- }, zt = (e) => e.split("=")[0], Bt = (e, t) => {
1299
- let n = Rt[e];
1344
+ }, Ut = (e) => e.split("=")[0], Wt = (e, t) => {
1345
+ let n = $[e];
1300
1346
  if (!n) return;
1301
1347
  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 ?? []);
1302
1348
  for (let n of t) {
1303
1349
  if (!n.startsWith("--")) continue;
1304
- let t = zt(n);
1350
+ let t = Ut(n);
1305
1351
  if (i.has(t)) continue;
1306
1352
  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.`;
1307
- let o = Object.entries(Rt).filter(([n, r]) => n !== e && [
1353
+ let o = Object.entries($).filter(([n, r]) => n !== e && [
1308
1354
  ...r.common,
1309
1355
  ...r.directOnly ?? [],
1310
1356
  ...r.apiOnly ?? []
1311
1357
  ].includes(t)).map(([e]) => e);
1312
1358
  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.`;
1313
1359
  }
1314
- }, Vt = {
1315
- export: yt,
1316
- import: Dt,
1317
- transfers: It,
1318
- inspect: Nt,
1319
- unpack: Lt,
1320
- backup: kt,
1321
- restore: Mt,
1322
- "clear-replace-marker": Pt,
1323
- "clear-staging": Ft
1324
- }, Ht = async (n) => {
1360
+ }, Gt = {
1361
+ export: xt,
1362
+ import: Ot,
1363
+ transfers: Vt,
1364
+ inspect: Rt,
1365
+ unpack: Ht,
1366
+ backup: At,
1367
+ restore: Lt,
1368
+ "clear-replace-marker": zt,
1369
+ "clear-staging": Bt
1370
+ }, Kt = async (n) => {
1325
1371
  let [r, ...i] = n;
1326
- if (r !== void 0 && Rt[r] !== void 0) {
1327
- let e = Bt(r, i);
1372
+ if (r !== void 0 && $[r] !== void 0) {
1373
+ let e = Wt(r, i);
1328
1374
  if (e) return V.error(e), 2;
1329
1375
  }
1330
- let a = r === void 0 ? void 0 : Vt[r];
1376
+ let a = r === void 0 ? void 0 : Gt[r];
1331
1377
  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);
1332
1378
  };
1333
1379
  //#endregion
1334
- export { Ht as runDataCommand };
1380
+ export { Kt as runDataCommand };