@voltro/cli 0.43.0 → 0.43.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/dist/{apiBuild-DF0f69Gf.js → apiBuild-BWuw8ZXS.js} +1 -1
  3. package/dist/apiBuild-Cw2-TEXW.js +2 -0
  4. package/dist/bin.js +1 -1
  5. package/dist/{build-LC_IJaHL.js → build-CGBs4ZOv.js} +6 -6
  6. package/dist/{checkCommand-DDxwJCja.js → checkCommand-BFtFBsqL.js} +2 -2
  7. package/dist/{checkCommand-DBpTSK8d.js → checkCommand-lTPSN3EQ.js} +1 -1
  8. package/dist/{codegenCommand-LjxfK4Am.js → codegenCommand-BJeyFlip.js} +1 -1
  9. package/dist/{commands-CbQcuWsE.js → commands-pEDOcOo2.js} +15 -15
  10. package/dist/{dashboardCommand-CAHjCe_9.js → dashboardCommand-Bt2hHMro.js} +1 -1
  11. package/dist/{dataCommand-CrqvbVOv.js → dataCommand-DD2bRHCu.js} +377 -208
  12. package/dist/{dev-D0E5x2Ue.js → dev-DMx-MF2s.js} +1 -1
  13. package/dist/{dev-B2rZfqxw.js → dev-wumUfDm1.js} +922 -912
  14. package/dist/doctorCommand-FOXTTaGp.js +2 -0
  15. package/dist/{doctorCommand-Ct_3BHgd.js → doctorCommand-RFKpnLih.js} +9 -9
  16. package/dist/{dormancyCommand-D1DKnYce.js → dormancyCommand-EFDQWiUw.js} +1 -1
  17. package/dist/{embeddingsCommand-1sZRBKlM.js → embeddingsCommand-OeYp3qSq.js} +1 -1
  18. package/dist/{envCommand-7qjlQgLD.js → envCommand-CKgBZK7x.js} +1 -1
  19. package/dist/{evolveCommand-D5opB48I.js → evolveCommand-ClQlAH0j.js} +1 -1
  20. package/dist/index.js +1 -1
  21. package/dist/{runtimeTrace-Wmi7V-wN.js → runtimeTrace-CgpAD9wL.js} +1 -1
  22. package/dist/{sdkgen-DbTFGCjg.js → sdkgen-Ca2zj4cd.js} +1 -1
  23. package/dist/{serveCommand-C8xzYCwa.js → serveCommand-CgK7Kj6j.js} +472 -368
  24. package/dist/serveCommand-DUm2-ikx.js +2 -0
  25. package/dist/serveEntry.js +1 -1
  26. package/dist/{webhooksCommand-BXUP5YjW.js → webhooksCommand-BVNtNsI0.js} +1 -1
  27. package/package.json +17 -17
  28. package/templates/AGENTS.md +1 -1
  29. package/templates/agent-docs/_index.md +1 -1
  30. package/templates/agent-docs/cli.md +126 -2
  31. package/templates/agent-docs/database/seedsdialects.md +12 -0
  32. package/templates/agent-docs/whats-new.md +14 -74
  33. package/templates/apps/api-ai/package.json +7 -7
  34. package/templates/apps/api-auth/package.json +8 -8
  35. package/templates/apps/api-backend/package.json +7 -7
  36. package/templates/apps/api-backend-deactivation/package.json +7 -7
  37. package/templates/apps/api-backend-mail/package.json +8 -8
  38. package/templates/apps/api-backend-mariadb/package.json +9 -9
  39. package/templates/apps/api-backend-sqlite/package.json +8 -8
  40. package/templates/apps/api-backend-storage/package.json +8 -8
  41. package/templates/apps/api-cms/package.json +10 -10
  42. package/templates/apps/api-collab/package.json +8 -8
  43. package/templates/apps/api-data-advanced/package.json +8 -8
  44. package/templates/apps/api-durable/package.json +8 -8
  45. package/templates/apps/api-feature-flags/package.json +9 -9
  46. package/templates/apps/api-governance/package.json +8 -8
  47. package/templates/apps/api-kv/package.json +8 -8
  48. package/templates/apps/api-moderation/package.json +8 -8
  49. package/templates/apps/api-observability/package.json +8 -8
  50. package/templates/apps/api-ratelimit/package.json +8 -8
  51. package/templates/apps/api-rbac/package.json +8 -8
  52. package/templates/apps/api-rest/package.json +7 -7
  53. package/templates/apps/api-saas/package.json +11 -11
  54. package/templates/apps/api-saas-starter/package.json +10 -10
  55. package/templates/apps/api-search/package.json +8 -8
  56. package/templates/apps/api-status/package.json +8 -8
  57. package/templates/apps/api-versioning/package.json +8 -8
  58. package/templates/apps/api-webhooks/package.json +9 -9
  59. package/templates/apps/changelog/package.json +6 -6
  60. package/templates/apps/edge-functions/package.json +2 -2
  61. package/templates/apps/frontend-admin/package.json +8 -8
  62. package/templates/apps/frontend-app/package.json +9 -9
  63. package/templates/apps/frontend-auth/package.json +8 -8
  64. package/templates/apps/frontend-blank/package.json +7 -7
  65. package/templates/apps/frontend-cms/package.json +9 -9
  66. package/templates/apps/frontend-collab/package.json +10 -10
  67. package/templates/apps/frontend-contact/package.json +7 -7
  68. package/templates/apps/frontend-dashboard/package.json +7 -7
  69. package/templates/apps/frontend-docs/package.json +7 -7
  70. package/templates/apps/frontend-i18n/package.json +6 -6
  71. package/templates/apps/frontend-landing/package.json +7 -7
  72. package/templates/apps/frontend-portal/package.json +8 -8
  73. package/templates/apps/frontend-saas/package.json +8 -8
  74. package/templates/apps/frontend-spa/package.json +7 -7
  75. package/templates/apps/frontend-ssr/package.json +7 -7
  76. package/templates/apps/frontend-ssr-api/package.json +8 -8
  77. package/templates/apps/frontend-static-blog/package.json +6 -6
  78. package/templates/apps/frontend-status/package.json +8 -8
  79. package/templates/apps/mobile-app/package.json +4 -4
  80. package/dist/apiBuild-B7NgSMhX.js +0 -2
  81. package/dist/doctorCommand-CdsctSwg.js +0 -2
  82. package/dist/serveCommand-CGNTXafv.js +0 -2
@@ -1,5 +1,5 @@
1
1
  import { t as e } from "./cliError-BmdYnghb.js";
2
- import { c as t, i as n, o as r } from "./dev-B2rZfqxw.js";
2
+ import { c as t, i as n, o as r } from "./dev-wumUfDm1.js";
3
3
  import { n as i, t as a } from "./cliArgs-D4p8n7EE.js";
4
4
  import { r as o } from "./dialectDriver-czCHYpeH.js";
5
5
  import { t as s } from "./dataProfile-Cm0YVKSy.js";
@@ -11,15 +11,110 @@ import { SqlClient as m } from "@effect/sql";
11
11
  import { declaredSnapshot as h, fingerprintSchema as g, introspectSchema as _ } from "@voltro/database/sql";
12
12
  import { connectionIdentity as v, normaliseTarget as y, sameDatabase as b, streamTable as x } from "@voltro/database";
13
13
  import { STORAGE_REFS_TABLE as ee, resolveStorageProvider as S } from "@voltro/plugin-storage";
14
- import { assessLiveImport as te, backupArtifactName as C, backupCommand as ne, classificationFromSnapshot as re, decryptStream as w, encryptStream as ie, packBundle as T, peekBundle as E, previewMasking as ae, restoreCommand as D, runExport as O, runImport as k, runNativeStep as A, storageAssetSink as oe, storageAssetSource as se, storageBlobSink as ce, storageBlobSource as le, unpackBundle as ue, unpackBundleToDir as de } from "@voltro/data-transfer";
15
- //#region src/backupStamp.ts
16
- var j = "voltro-backup-stamp.json", fe = (e) => ({
14
+ import { createHash as te } from "node:crypto";
15
+ import { assessLiveImport as ne, backupArtifactName as C, backupCommand as re, classificationFromSnapshot as ie, decryptStream as w, encryptStream as ae, packBundle as T, peekBundle as E, previewMasking as oe, restoreCommand as D, runExport as O, runImport as se, runNativeStep as k, storageAssetSink as ce, storageAssetSource as le, storageBlobSink as ue, storageBlobSource as de, unpackBundle as fe, unpackBundleToDir as A } from "@voltro/data-transfer";
16
+ import { request as pe } from "node:http";
17
+ import { request as me } from "node:https";
18
+ //#region src/longRequest.ts
19
+ var j = class extends Error {
20
+ elapsedMs;
21
+ url;
22
+ constructor(e, t) {
23
+ super(`no response after ${Math.round(e / 1e3)}s`), this.elapsedMs = e, this.url = t, this.name = "LongRequestTimeout";
24
+ }
25
+ }, M = async (e, t, n, r) => {
26
+ let i = new URL(e), a = i.protocol === "https:" ? me : pe, o = Date.now();
27
+ return await new Promise((s, c) => {
28
+ let l = a({
29
+ protocol: i.protocol,
30
+ hostname: i.hostname,
31
+ port: i.port === "" ? void 0 : Number(i.port),
32
+ path: `${i.pathname}${i.search}`,
33
+ method: "POST",
34
+ headers: n
35
+ }, (e) => {
36
+ let t = [];
37
+ e.on("data", (e) => t.push(e)), e.on("end", () => s({
38
+ status: e.statusCode ?? 0,
39
+ headers: Object.fromEntries(Object.entries(e.headers).map(([e, t]) => [e, Array.isArray(t) ? t.join(", ") : String(t ?? "")])),
40
+ body: Buffer.concat(t)
41
+ })), e.on("error", c);
42
+ });
43
+ if (r?.timeoutMs !== void 0 && r.timeoutMs > 0 && l.setTimeout(r.timeoutMs, () => {
44
+ l.destroy(new j(Date.now() - o, e));
45
+ }), l.on("error", c), typeof t == "string" || Buffer.isBuffer(t)) {
46
+ l.end(t);
47
+ return;
48
+ }
49
+ (async () => {
50
+ try {
51
+ for await (let e of t) l.write(Buffer.from(e)) || await new Promise((e) => l.once("drain", () => e()));
52
+ l.end();
53
+ } catch (e) {
54
+ l.destroy(e);
55
+ }
56
+ })();
57
+ });
58
+ }, he = (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.", ge = 16777216, _e = async function* (e, t) {
59
+ let n = [], r = 0, i = 0, a = function* (e) {
60
+ let t = Buffer.concat(n);
61
+ n = [], r = 0;
62
+ let a = {
63
+ bytes: t,
64
+ offset: i,
65
+ final: e
66
+ };
67
+ i += t.byteLength, yield a;
68
+ };
69
+ for await (let a of e) for (n.push(Buffer.from(a)), r += a.byteLength; r >= t;) {
70
+ let e = Buffer.concat(n), a = e.subarray(0, t), o = e.subarray(t);
71
+ n = o.byteLength > 0 ? [Buffer.from(o)] : [], r = o.byteLength;
72
+ let s = {
73
+ bytes: Buffer.from(a),
74
+ offset: i,
75
+ final: !1
76
+ };
77
+ i += a.byteLength, yield s;
78
+ }
79
+ yield* a(!0);
80
+ }, ve = (e) => te("sha256").update(Buffer.from(e)).digest("hex"), ye = async (e) => {
81
+ let t = 0, n = 0, r = {
82
+ status: 0,
83
+ body: {}
84
+ };
85
+ for await (let i of _e(e.stream, e.chunkBytes)) {
86
+ if (i.offset + i.bytes.byteLength <= e.alreadyHeld && !i.final) {
87
+ n++;
88
+ continue;
89
+ }
90
+ let a = Math.max(0, e.alreadyHeld - i.offset), o = a > 0 ? i.bytes.subarray(a) : i.bytes, s = i.offset + a;
91
+ if (o.byteLength === 0 && !i.final) {
92
+ n++;
93
+ continue;
94
+ }
95
+ if (r = await e.target.send(Buffer.from(o), {
96
+ ...e.baseHeaders,
97
+ "content-type": "application/octet-stream",
98
+ "x-import-upload-id": e.uploadId,
99
+ "x-import-upload-key": e.key,
100
+ "x-import-chunk-offset": String(s),
101
+ ...i.final ? { "x-import-chunk-final": "1" } : {}
102
+ }), n++, t += o.byteLength, e.onProgress?.(t), r.status >= 400) break;
103
+ }
104
+ return {
105
+ status: r.status,
106
+ body: r.body,
107
+ chunks: n,
108
+ bytes: t,
109
+ resumedFrom: e.alreadyHeld
110
+ };
111
+ }, N = "voltro-backup-stamp.json", be = (e) => ({
17
112
  stampVersion: 1,
18
113
  dialect: e.dialect,
19
114
  schemaFingerprint: e.schemaFingerprint,
20
115
  voltroVersion: e.voltroVersion,
21
116
  createdAt: e.createdAt
22
- }), M = (e) => {
117
+ }), P = (e) => {
23
118
  let t;
24
119
  try {
25
120
  t = JSON.parse(e);
@@ -37,10 +132,10 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
37
132
  voltroVersion: n.voltroVersion,
38
133
  createdAt: n.createdAt
39
134
  };
40
- }, pe = (e) => {
135
+ }, xe = (e) => {
41
136
  let { stamp: t, currentDialect: n, currentFingerprint: r } = e;
42
137
  if (t === null) return {
43
- warn: `no ${j} beside the dump — an older/handmade backup. Cannot verify dialect or schema version; make sure this dump is a ${n} dump.`,
138
+ warn: `no ${N} beside the dump — an older/handmade backup. Cannot verify dialect or schema version; make sure this dump is a ${n} dump.`,
44
139
  info: []
45
140
  };
46
141
  let i = [`backup produced by @voltro/cli ${t.voltroVersion} at ${t.createdAt}`, `schema fingerprint: ${t.schemaFingerprint ?? "<none recorded>"}`];
@@ -51,20 +146,20 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
51
146
  refuse: `dialect mismatch — backup is a ${t.dialect} dump, but DB_DIALECT is ${n}. A cross-dialect restore is never valid.`,
52
147
  info: i
53
148
  };
54
- }, N = (e) => {
149
+ }, F = (e) => {
55
150
  try {
56
151
  let t = new URL(e), n = t.pathname.replace(/^\//, "");
57
152
  return `${t.hostname.toLowerCase()}:${t.port || "(default)"}/${n}`;
58
153
  } catch {
59
154
  return e.trim();
60
155
  }
61
- }, me = (e) => {
156
+ }, Se = (e) => {
62
157
  let t = e.flagUrl ?? e.envUrl;
63
158
  if (t === void 0 || t.trim() === "") return {
64
159
  ok: !1,
65
160
  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."
66
161
  };
67
- let n = N(t);
162
+ let n = F(t);
68
163
  return e.liveKeys.some((e) => e === n) ? {
69
164
  ok: !1,
70
165
  error: `drill target (${n}) is the LIVE database — a restore drill must target a throwaway DB, never production. It would --clean and overwrite it.`
@@ -72,7 +167,7 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
72
167
  ok: !0,
73
168
  url: t
74
169
  };
75
- }, he = (e) => {
170
+ }, Ce = (e) => {
76
171
  let { stampFingerprint: t, restoredFingerprint: n, restoredTableCount: r } = e;
77
172
  return r === 0 ? {
78
173
  pass: !1,
@@ -87,24 +182,24 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
87
182
  pass: !0,
88
183
  lines: [`PASS — restored ${r} table(s); schema fingerprint matches the backup stamp (${n.slice(0, 12)}).`]
89
184
  };
90
- }, P = d({ scope: "voltro:data" }), ge = async () => {
185
+ }, I = d({ scope: "voltro:data" }), we = async () => {
91
186
  try {
92
187
  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");
93
188
  return JSON.parse(n(r, "utf8")).version ?? "unknown";
94
189
  } catch {
95
190
  return "unknown";
96
191
  }
97
- }, F = async (e) => {
192
+ }, L = async (e) => {
98
193
  try {
99
- return g(await H(e));
194
+ return g(await W(e));
100
195
  } catch {
101
196
  return null;
102
197
  }
103
- }, I = (e) => {
198
+ }, R = (e) => {
104
199
  if (e.event !== "done") return;
105
200
  let t = e.total === void 0 ? "" : ` / ${e.total}`;
106
- P.info(`${e.phase} [${e.index + 1}/${e.tableCount}] ${e.table}`, { rows: `${e.rowsDone}${t}` });
107
- }, _e = async (e) => {
201
+ I.info(`${e.phase} [${e.index + 1}/${e.tableCount}] ${e.table}`, { rows: `${e.rowsDone}${t}` });
202
+ }, Te = async (e) => {
108
203
  let t = (e) => e?.meta?.databaseId;
109
204
  if (e) {
110
205
  let n = await l({
@@ -124,26 +219,27 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
124
219
  };
125
220
  }
126
221
  return null;
127
- }, L = async (e) => {
128
- let t = e.includes("--allow-live"), n = t ? null : await _e(R(e, "--api-url")), i = v({
129
- dialect: B(),
222
+ }, z = async (e) => {
223
+ let t = e.includes("--allow-live"), n = t ? null : await Te(B(e, "--api-url")), i = v({
224
+ dialect: H(),
130
225
  ...r()
131
226
  }), a = y({
132
- dialect: B(),
227
+ dialect: H(),
133
228
  ...r()
134
- }), { refuse: o, message: s } = te({
229
+ }), { refuse: o, message: s } = ne({
135
230
  liveInstance: n?.label ?? null,
136
231
  allowLive: t,
137
232
  sameTarget: b(i, n?.databaseId),
138
233
  ...a === void 0 ? {} : { targetLabel: `${a.host}:${a.port}/${a.database}` }
139
234
  });
140
- return !o || (P.error(s ?? "refusing: live instance detected"), !1);
141
- }, R = i, ve = [
235
+ return !o || (I.error(s ?? "refusing: live instance detected"), !1);
236
+ }, B = i, Ee = [
142
237
  "--api-url",
143
238
  "--bundle-key",
144
239
  "--compression",
145
240
  "--consistency",
146
241
  "--drill-url",
242
+ "--chunk-size",
147
243
  "--exclude",
148
244
  "--mode",
149
245
  "--on-conflict",
@@ -151,46 +247,47 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
151
247
  "--profile",
152
248
  "--tables",
153
249
  "--target",
250
+ "--timeout",
154
251
  "--tenant",
155
252
  "--token"
156
- ], z = (e) => a(e, ve), B = () => {
253
+ ], V = (e) => a(e, Ee), H = () => {
157
254
  let t = (process.env.DB_DIALECT ?? "postgres").toLowerCase();
158
255
  if (t === "memory") throw new e("voltro data: requires a real dialect, not DB_DIALECT=memory.");
159
256
  return t;
160
- }, V = async (e, t) => {
257
+ }, U = async (e, t) => {
161
258
  let n = (await o(e)).makeSqlLayer(t);
162
259
  return f.runPromise(m.SqlClient.pipe(f.flatMap(_), f.provide(n)));
163
- }, H = (e) => V(e, r()), ye = () => {
260
+ }, W = (e) => U(e, r()), De = () => {
164
261
  let e = r(), t = [];
165
- return e.url && t.push(N(e.url)), (e.host || e.database) && t.push(`${(e.host ?? "localhost").toLowerCase()}:${e.port ?? "(default)"}/${e.database ?? ""}`), t;
166
- }, U = async () => {
262
+ return e.url && t.push(F(e.url)), (e.host || e.database) && t.push(`${(e.host ?? "localhost").toLowerCase()}:${e.port ?? "(default)"}/${e.database ?? ""}`), t;
263
+ }, G = async () => {
167
264
  let r = process.cwd(), i = await t(r);
168
265
  if (!i) throw new e("voltro data: no app.config.ts found in the current directory.");
169
- let a = await n(i, void 0), o = B();
266
+ let a = await n(i, void 0), o = H();
170
267
  return {
171
268
  store: a,
172
- snapshot: await H(o),
269
+ snapshot: await W(o),
173
270
  dialect: o
174
271
  };
175
- }, W = (e) => x(e, {
272
+ }, K = (e) => x(e, {
176
273
  table: ee,
177
274
  chunkSize: 500
178
275
  }).pipe(p.map((e) => ({
179
276
  key: String(e.key),
180
277
  contentType: String(e.contentType ?? "application/octet-stream"),
181
278
  size: Number(e.size ?? 0)
182
- }))), G = (e) => !!e && e.endsWith(".vbundle"), K = (e) => R(e, "--passphrase") ?? process.env.VOLTRO_BUNDLE_KEY, be = (e) => e.includes("--encrypt") || R(e, "--passphrase") !== void 0 || process.env.VOLTRO_BUNDLE_KEY !== void 0, xe = async (e, t) => {
279
+ }))), q = (e) => !!e && e.endsWith(".vbundle"), J = (e) => B(e, "--passphrase") ?? process.env.VOLTRO_BUNDLE_KEY, Oe = (e) => e.includes("--encrypt") || B(e, "--passphrase") !== void 0 || process.env.VOLTRO_BUNDLE_KEY !== void 0, ke = async (e, t) => {
183
280
  let { createWriteStream: n } = await import("node:fs"), { pipeline: r } = await import("node:stream/promises"), { Readable: i } = await import("node:stream");
184
281
  await r(i.from(e), n(t));
185
- }, q = (e) => ({ async *[Symbol.asyncIterator]() {
282
+ }, Y = (e) => ({ async *[Symbol.asyncIterator]() {
186
283
  let { createReadStream: t } = await import("node:fs");
187
284
  for await (let n of t(e)) yield n instanceof Uint8Array ? n : new Uint8Array(n);
188
- } }), J = (e) => (e ?? "").split(",").map((e) => e.trim()).filter(Boolean), Se = (t, n) => {
189
- let r = R(t, "--tenant"), i = R(t, "--tables"), a = R(t, "--exclude");
285
+ } }), X = (e) => (e ?? "").split(",").map((e) => e.trim()).filter(Boolean), Ae = (t, n) => {
286
+ let r = B(t, "--tenant"), i = B(t, "--tables"), a = B(t, "--exclude");
190
287
  if (a !== void 0) {
191
288
  if (i !== void 0) throw new e("voltro data export: --exclude and --tables are two ways to say the same thing; use one.");
192
289
  if (r !== void 0) throw new e("voltro data export: --exclude does not apply to --tenant, whose table set is derived from the tenant closure.");
193
- let t = J(a), o = new Set(n), s = t.filter((e) => !o.has(e));
290
+ let t = X(a), o = new Set(n), s = t.filter((e) => !o.has(e));
194
291
  if (s.length > 0) throw new e(`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.`);
195
292
  let c = new Set(t);
196
293
  return {
@@ -203,15 +300,15 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
203
300
  tenantId: r
204
301
  } : i ? {
205
302
  kind: "tables",
206
- tables: J(i)
303
+ tables: X(i)
207
304
  } : { kind: "all" };
208
- }, Ce = async () => {
305
+ }, je = async () => {
209
306
  let e = await u(process.cwd());
210
- return re(h(e));
211
- }, we = "voltro/tenant", Te = async () => {
212
- let e = (await u(process.cwd())).filter((e) => (e.appliedMixins ?? []).some((e) => e.id === we)).map((e) => e.tableName);
307
+ return ie(h(e));
308
+ }, Me = "voltro/tenant", Ne = async () => {
309
+ let e = (await u(process.cwd())).filter((e) => (e.appliedMixins ?? []).some((e) => e.id === Me)).map((e) => e.tableName);
213
310
  return e.length > 0 ? e : void 0;
214
- }, Ee = (e) => {
311
+ }, Pe = (e) => {
215
312
  for (let t of e.tables) if (t.samples.length !== 0) {
216
313
  console.log(`\n ${t.table}`);
217
314
  for (let e of t.samples) console.log(` ${e.column} [${e.action}] ${JSON.stringify(e.before)} → ${JSON.stringify(e.after)}`);
@@ -224,51 +321,118 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
224
321
  console.log("\n ✗ unclassified (would BLOCK a real export — add .sensitive()/.safe() or a policy override):");
225
322
  for (let t of e.unclassified) console.log(` ${t}`);
226
323
  } else console.log("\n ✓ every exported column is classified — safe to run.");
227
- }, De = async (e) => {
228
- let t = R(e, "--target") === "api", n = R(e, "--bundle-key"), r = z(e);
229
- if (!r && !(t && n)) return P.error("usage: voltro data export <outDir> [--target direct|api] [--api-url <url>] [--token <secret>] [--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;
324
+ }, Fe = async (t) => {
325
+ let { resolve: n, join: r } = await import("node:path"), i = await import("node:fs/promises"), a = B(t.args, "--chunk-size"), o = a === void 0 ? ge : Math.round(Number(a) * 1024 * 1024);
326
+ if (!Number.isFinite(o) || o <= 0) throw new e(`--chunk-size expects a positive number of megabytes, got '${String(a)}'`);
327
+ let s = t.stream[Symbol.asyncIterator](), c = [], l = 0, u = !1;
328
+ for (; l <= o;) {
329
+ let e = await s.next();
330
+ if (e.done === !0) {
331
+ u = !0;
332
+ break;
333
+ }
334
+ c.push(Buffer.from(e.value)), l += e.value.byteLength;
335
+ }
336
+ if (u && l <= o) return {
337
+ kind: "small",
338
+ body: Buffer.concat(c)
339
+ };
340
+ let d = n(process.cwd(), t.bundleDir), f = ve(q(t.bundleDir) ? await i.readFile(d) : await i.readFile(r(d, "manifest.json"))), p = `up-${f.slice(0, 32)}`, m = await M(t.url, Buffer.alloc(0), {
341
+ ...t.headers,
342
+ "x-import-upload-id": p,
343
+ "x-import-probe": "1"
344
+ }, Z(t.args)), h = m.status === 200 ? Number(JSON.parse(m.body.toString("utf8")).bytes ?? 0) : 0;
345
+ h > 0 && t.log.info("api import: resuming a chunked upload the instance already holds", { bytes: h });
346
+ let g = await ye({
347
+ stream: (async function* () {
348
+ for (let e of c) yield e;
349
+ for (;;) {
350
+ let e = await s.next();
351
+ if (e.done === !0) return;
352
+ yield e.value;
353
+ }
354
+ })(),
355
+ chunkBytes: o,
356
+ uploadId: p,
357
+ key: f,
358
+ alreadyHeld: h,
359
+ baseHeaders: t.headers,
360
+ target: { send: async (e, n) => {
361
+ let r = await M(t.url, e, n, Z(t.args)), i = {};
362
+ try {
363
+ i = JSON.parse(r.body.toString("utf8") || "{}");
364
+ } catch {}
365
+ return {
366
+ status: r.status,
367
+ body: i
368
+ };
369
+ } }
370
+ });
371
+ return t.log.info("api import: uploaded in chunks", {
372
+ chunks: g.chunks,
373
+ bytes: g.bytes,
374
+ ...g.resumedFrom > 0 ? { resumedFrom: g.resumedFrom } : {}
375
+ }), {
376
+ kind: "sent",
377
+ res: {
378
+ status: g.status,
379
+ headers: {},
380
+ body: Buffer.from(JSON.stringify(g.body))
381
+ }
382
+ };
383
+ }, Z = (t) => {
384
+ let n = B(t, "--timeout");
385
+ if (n === void 0) return {};
386
+ let r = Number(n);
387
+ if (!Number.isFinite(r) || r <= 0) throw new e(`--timeout expects a positive number of seconds, got '${n}'`);
388
+ return { timeoutMs: Math.round(r * 1e3) };
389
+ }, Ie = async (e) => {
390
+ let t = B(e, "--target") === "api", n = B(e, "--bundle-key"), r = V(e);
391
+ if (!r && !(t && n)) return I.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;
230
392
  if (t) {
231
- let t = R(e, "--api-url");
232
- if (!t) return P.error("--target api requires --api-url <url> (the running instance)"), 1;
233
- let i = R(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
234
- if (!i) return P.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
235
- if (R(e, "--exclude") !== void 0) return P.error("--exclude is a direct-target flag: it expands against the live table list, which --target api does not expose. Use --tables with the explicit set."), 1;
236
- let a = R(e, "--tables"), o = {
237
- ...R(e, "--profile") ? { profile: R(e, "--profile") } : {},
238
- ...R(e, "--tenant") ? { tenant: R(e, "--tenant") } : {},
393
+ let t = B(e, "--api-url");
394
+ if (!t) return I.error("--target api requires --api-url <url> (the running instance)"), 1;
395
+ let i = B(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
396
+ if (!i) return I.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
397
+ if (B(e, "--exclude") !== void 0) return I.error("--exclude is a direct-target flag: it expands against the live table list, which --target api does not expose. Use --tables with the explicit set."), 1;
398
+ let a = B(e, "--tables"), o = {
399
+ ...B(e, "--profile") ? { profile: B(e, "--profile") } : {},
400
+ ...B(e, "--tenant") ? { tenant: B(e, "--tenant") } : {},
239
401
  ...a ? { tables: a.split(",").map((e) => e.trim()).filter(Boolean) } : {},
240
- ...R(e, "--consistency") === "snapshot" ? { consistency: "snapshot" } : {},
241
- ...R(e, "--compression") ? { compression: R(e, "--compression") } : {},
402
+ ...B(e, "--consistency") === "snapshot" ? { consistency: "snapshot" } : {},
403
+ ...B(e, "--compression") ? { compression: B(e, "--compression") } : {},
242
404
  ...e.includes("--assets") ? { assets: !0 } : {},
243
405
  ...n ? { bundleKey: n } : {}
244
- }, s = await fetch(`${t.replace(/\/+$/, "")}/_voltro/admin/export`, {
245
- method: "POST",
246
- headers: {
406
+ }, s;
407
+ try {
408
+ s = await M(`${t.replace(/\/+$/, "")}/_voltro/admin/export`, JSON.stringify(o), {
247
409
  "content-type": "application/json",
248
410
  authorization: `Bearer ${i}`
249
- },
250
- body: JSON.stringify(o)
251
- });
252
- if (!s.ok) return P.error(`api export failed: HTTP ${s.status} — ${await s.text()}`), 1;
253
- if (n) return P.info("api export complete (pushed to storage)", {
411
+ }, Z(e));
412
+ } catch (e) {
413
+ if (e instanceof j) return I.error(`api export: the instance did not answer within ${Math.round(e.elapsedMs / 1e3)}s. That is a client-side deadline, not a server failure — the response arrives only when the export does. Nothing was written locally; re-run, or pass --timeout <seconds> (the default is to wait).`), 1;
414
+ throw e;
415
+ }
416
+ if (s.status < 200 || s.status >= 300) return I.error(`api export failed: HTTP ${s.status} — ${s.body.toString("utf8")}`), 1;
417
+ if (n) return I.info("api export complete (pushed to storage)", {
254
418
  via: t,
255
- ...await s.json()
419
+ ...JSON.parse(s.body.toString("utf8"))
256
420
  }), 0;
257
- let { resolve: c } = await import("node:path"), l = new Uint8Array(await s.arrayBuffer());
258
- return await de((async function* () {
421
+ let { resolve: c } = await import("node:path"), l = new Uint8Array(s.body);
422
+ return await A((async function* () {
259
423
  yield l;
260
- })(), c(process.cwd(), r)), P.info("api export complete (downloaded from the running instance)", {
424
+ })(), c(process.cwd(), r)), I.info("api export complete (downloaded from the running instance)", {
261
425
  outDir: r,
262
- tables: s.headers.get("x-export-tables") ?? void 0,
263
- rows: s.headers.get("x-export-rows") ?? void 0,
264
- masked: s.headers.get("x-export-masked") ?? void 0
426
+ tables: s.headers["x-export-tables"],
427
+ rows: s.headers["x-export-rows"],
428
+ masked: s.headers["x-export-masked"]
265
429
  }), 0;
266
430
  }
267
- if (!r) return P.error("a <outDir> is required for a direct export"), 1;
268
- let i = R(e, "--profile"), a = i ? await s(i, { allowPath: !0 }) : {}, { store: o, snapshot: c, dialect: l } = await U(), u = e.includes("--assets") || a.assets === !0, d = u ? S({}) : void 0, p = R(e, "--compression") ?? a.compression, m = R(e, "--consistency") === "snapshot" ? "snapshot" : a.consistency ?? "live", h = a.masking, g = a.subset, _ = a.scope ?? Se(e, c.tables.map((e) => e.name)), v = h ? await Ce() : void 0, y = _.kind === "tenant" ? await Te() : void 0, b = y ? { tenantTables: y } : {};
431
+ if (!r) return I.error("a <outDir> is required for a direct export"), 1;
432
+ let i = B(e, "--profile"), a = i ? await s(i, { allowPath: !0 }) : {}, { store: o, snapshot: c, dialect: l } = await G(), u = e.includes("--assets") || a.assets === !0, d = u ? S({}) : void 0, p = B(e, "--compression") ?? a.compression, m = B(e, "--consistency") === "snapshot" ? "snapshot" : a.consistency ?? "live", h = a.masking, g = a.subset, _ = a.scope ?? Ae(e, c.tables.map((e) => e.name)), v = h ? await je() : void 0, y = _.kind === "tenant" ? await Ne() : void 0, b = y ? { tenantTables: y } : {};
269
433
  if (e.includes("--dry-run")) {
270
434
  let e = _.kind === "tables" && _.tables ? [..._.tables] : c.tables.map((e) => e.name);
271
- if (P.info("export DRY RUN — nothing was written", {
435
+ if (I.info("export DRY RUN — nothing was written", {
272
436
  outDir: r,
273
437
  tables: e.length,
274
438
  scope: _.kind,
@@ -276,8 +440,8 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
276
440
  compression: p ?? "zstd",
277
441
  assets: u,
278
442
  masking: h ? "profile policy applies" : "none"
279
- }), P.info(`would export: ${e.join(", ")}`), !h) return 0;
280
- let t = await f.runPromise(ae({
443
+ }), I.info(`would export: ${e.join(", ")}`), !h) return 0;
444
+ let t = await f.runPromise(oe({
281
445
  store: o,
282
446
  snapshot: c,
283
447
  masking: h,
@@ -287,9 +451,9 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
287
451
  ...b
288
452
  }
289
453
  }));
290
- return Ee(t), +(t.unclassified.length > 0);
454
+ return Pe(t), +(t.unclassified.length > 0);
291
455
  }
292
- if (G(r)) {
456
+ if (q(r)) {
293
457
  let t = await import("node:os"), n = await import("node:fs/promises"), { resolve: i, join: a } = await import("node:path"), s = await n.mkdtemp(a(t.tmpdir(), "voltro-export-"));
294
458
  try {
295
459
  let t = await f.runPromise(O({
@@ -305,17 +469,17 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
305
469
  ...p ? { compression: p } : {},
306
470
  ...h ? { masking: h } : {},
307
471
  ...v ? { classification: v } : {},
308
- onProgress: I
472
+ onProgress: R
309
473
  })), n = T({
310
474
  dir: s,
311
- ...d ? { blobs: le(d, () => W(o)) } : {}
312
- }), a = be(e);
475
+ ...d ? { blobs: de(d, () => K(o)) } : {}
476
+ }), a = Oe(e);
313
477
  if (a) {
314
- let t = K(e);
315
- if (!t) return P.error("--encrypt requires --passphrase <p> or VOLTRO_BUNDLE_KEY (a dedicated key, NOT the transfer secret)"), 1;
316
- n = ie(n, t);
478
+ let t = J(e);
479
+ if (!t) return I.error("--encrypt requires --passphrase <p> or VOLTRO_BUNDLE_KEY (a dedicated key, NOT the transfer secret)"), 1;
480
+ n = ae(n, t);
317
481
  }
318
- return await xe(n, i(process.cwd(), r)), P.info("export complete (single file)", {
482
+ return await ke(n, i(process.cwd(), r)), I.info("export complete (single file)", {
319
483
  file: r,
320
484
  encrypted: a,
321
485
  assets: u,
@@ -342,10 +506,10 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
342
506
  ...p ? { compression: p } : {},
343
507
  ...h ? { masking: h } : {},
344
508
  ...v ? { classification: v } : {},
345
- ...d ? { assets: se(d, () => W(o)) } : {},
346
- onProgress: I
509
+ ...d ? { assets: le(d, () => K(o)) } : {},
510
+ onProgress: R
347
511
  }));
348
- return P.info("export complete", {
512
+ return I.info("export complete", {
349
513
  outDir: r,
350
514
  tables: x.tables.length,
351
515
  rows: x.tables.reduce((e, t) => e + t.rowCount, 0),
@@ -353,36 +517,36 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
353
517
  compression: x.compression,
354
518
  ...x.masking ? { maskedColumns: x.masking.transformed.length } : {}
355
519
  }), 0;
356
- }, Y = () => "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.", X = (e) => {
357
- let t = R(e, "--tables");
520
+ }, Q = () => "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.", Le = (e) => {
521
+ let t = B(e, "--tables");
358
522
  return {
359
523
  ...t ? { tables: t.split(",").map((e) => e.trim()).filter(Boolean) } : {},
360
524
  ...e.includes("--dry-run") ? { dryRun: !0 } : {}
361
525
  };
362
- }, Z = (e, t) => {
526
+ }, Re = (e, t) => {
363
527
  if (e.includes("--dry-run")) {
364
- P.info("import DRY RUN — nothing was written", t), P.info(Y());
528
+ I.info("import DRY RUN — nothing was written", t), I.info(Q());
365
529
  return;
366
530
  }
367
- P.info("import complete", t);
368
- }, Oe = (e) => {
531
+ I.info("import complete", t);
532
+ }, ze = (e) => {
369
533
  let t = e;
370
534
  if (t?._tag !== "RowsRefusedError" || !Array.isArray(t.rows)) return;
371
535
  let n = t.rows, r = n.filter((e) => !e.derived), i = Number(t.totalCount ?? n.length), a = Number(t.primaryCount ?? r.length);
372
- P.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.`);
373
- for (let e of r) P.error(` ${e.table} ${e.id} ${e.reason}`);
536
+ I.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.`);
537
+ for (let e of r) I.error(` ${e.table} ${e.id} ${e.reason}`);
374
538
  let o = i - a;
375
- o > 0 && P.error(` … and ${o} row(s) behind them. Fix the ${a} above and re-run; they resolve with their parents.`);
376
- }, ke = async (e) => {
377
- let t = R(e, "--target") === "api", n = R(e, "--bundle-key"), i = z(e);
378
- if (!i && !(t && n)) return P.error("usage: voltro data import <bundleDir> [--target direct|api] [--api-url <url>] [--token <secret>] [--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;
379
- let a = R(e, "--mode") ?? "upsert", o = R(e, "--on-conflict") ?? "skip";
539
+ o > 0 && I.error(` … and ${o} row(s) behind them. Fix the ${a} above and re-run; they resolve with their parents.`);
540
+ }, Be = async (e) => {
541
+ let t = B(e, "--target") === "api", n = B(e, "--bundle-key"), i = V(e);
542
+ if (!i && !(t && n)) return I.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;
543
+ let a = B(e, "--mode") ?? "upsert", o = B(e, "--on-conflict") ?? "skip";
380
544
  if (t) {
381
- let t = R(e, "--api-url");
382
- if (!t) return P.error("--target api requires --api-url <url> (the running instance)"), 1;
383
- let r = R(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
384
- if (!r) return P.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
385
- let s = R(e, "--tables"), c = {
545
+ let t = B(e, "--api-url");
546
+ if (!t) return I.error("--target api requires --api-url <url> (the running instance)"), 1;
547
+ let r = B(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
548
+ if (!r) return I.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
549
+ let s = B(e, "--tables"), c = {
386
550
  authorization: `Bearer ${r}`,
387
551
  "x-import-mode": a,
388
552
  "x-import-on-conflict": o,
@@ -392,62 +556,64 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
392
556
  ...s ? { "x-import-tables": s } : {}
393
557
  }, { resolve: l } = await import("node:path"), u;
394
558
  if (n) c["content-type"] = "application/json", u = JSON.stringify({ bundleKey: n });
395
- else if (G(i)) {
396
- let t = q(l(process.cwd(), i)), n = K(e);
397
- n && (t = w(t, n));
398
- let r = [];
399
- for await (let e of t) r.push(Buffer.from(e));
400
- c["content-type"] = "application/octet-stream", u = Buffer.concat(r);
401
- } else {
402
- await (await import("node:fs/promises")).access(l(process.cwd(), i, "assets", "index.ndjson")).then(() => !0, () => !1) && P.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.");
403
- let e = [];
404
- for await (let t of T({ dir: l(process.cwd(), i) })) e.push(Buffer.from(t));
405
- c["content-type"] = "application/octet-stream", u = Buffer.concat(e);
559
+ else if (q(i)) {
560
+ let t = Y(l(process.cwd(), i)), n = J(e);
561
+ n && (t = w(t, n)), c["content-type"] = "application/octet-stream", u = t;
562
+ } else await (await import("node:fs/promises")).access(l(process.cwd(), i, "assets", "index.ndjson")).then(() => !0, () => !1) && I.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."), c["content-type"] = "application/octet-stream", u = T({ dir: l(process.cwd(), i) });
563
+ let d = `${t.replace(/\/+$/, "")}/_voltro/admin/import`, f;
564
+ try {
565
+ let t = typeof u == "string" ? null : await Fe({
566
+ stream: u,
567
+ url: d,
568
+ headers: c,
569
+ bundleDir: i,
570
+ args: e,
571
+ log: I
572
+ });
573
+ f = t === null ? await M(d, u, c, Z(e)) : t.kind === "sent" ? t.res : await M(d, t.body, c, Z(e));
574
+ } catch (e) {
575
+ if (e instanceof j) return I.error(`api import: ${he(e, a)}`), 1;
576
+ throw e;
406
577
  }
407
- let d = await fetch(`${t.replace(/\/+$/, "")}/_voltro/admin/import`, {
408
- method: "POST",
409
- body: u,
410
- headers: c
411
- });
412
- if (!d.ok) return P.error(`api import failed: HTTP ${d.status} — ${await d.text()}`), 1;
413
- let f = await d.json();
414
- return e.includes("--dry-run") ? (P.info("api import DRY RUN — nothing was written", {
578
+ if (f.status < 200 || f.status >= 300) return I.error(`api import failed: HTTP ${f.status} — ${f.body.toString("utf8")}`), 1;
579
+ let p = JSON.parse(f.body.toString("utf8"));
580
+ return e.includes("--dry-run") ? (I.info("api import DRY RUN — nothing was written", {
415
581
  via: t,
416
- ...f
417
- }), P.info(Y()), 0) : (P.info("api import complete (imported by the running instance)", {
582
+ ...p
583
+ }), I.info(Q()), 0) : (I.info("api import complete (imported by the running instance)", {
418
584
  via: t,
419
- ...f
585
+ ...p
420
586
  }), 0);
421
587
  }
422
- if (!i) return P.error("a <bundleDir> is required for a direct import"), 1;
423
- if (!await L(e)) return 1;
424
- let { store: s, snapshot: c } = await U(), l = e.includes("--force"), u = (e) => P.warn(e), d = e.includes("--assets") ? S({}) : void 0, p = B() === "postgres" ? (await import("@voltro/sql-postgres")).makePgCopySession(r()) : void 0;
425
- if (G(i)) {
588
+ if (!i) return I.error("a <bundleDir> is required for a direct import"), 1;
589
+ if (!await z(e)) return 1;
590
+ let { store: s, snapshot: c } = await G(), l = e.includes("--force"), u = (e) => I.warn(e), d = e.includes("--assets") ? S({}) : void 0, p = H() === "postgres" ? (await import("@voltro/sql-postgres")).makePgCopySession(r()) : void 0;
591
+ if (q(i)) {
426
592
  let t = await import("node:os"), n = await import("node:fs/promises"), { resolve: r, join: m } = await import("node:path"), h = await n.mkdtemp(m(t.tmpdir(), "voltro-import-"));
427
593
  try {
428
- let t = q(r(process.cwd(), i)), n = K(e);
429
- n && (t = w(t, n)), await ue(t, {
594
+ let t = Y(r(process.cwd(), i)), n = J(e);
595
+ n && (t = w(t, n)), await fe(t, {
430
596
  dir: h,
431
- blobs: ce(d ?? S({}))
597
+ blobs: ue(d ?? S({}))
432
598
  });
433
- let m = await f.runPromise(k({
599
+ let m = await f.runPromise(se({
434
600
  store: s,
435
601
  bundleDir: h,
436
602
  mode: a,
437
603
  onConflict: o,
438
604
  atomic: e.includes("--atomic"),
439
605
  verify: !e.includes("--no-verify"),
440
- targetDialect: B(),
606
+ targetDialect: H(),
441
607
  allowIncompatible: l,
442
608
  targetSnapshot: c,
443
609
  force: l,
444
610
  onWarn: u,
445
- onProgress: I,
611
+ onProgress: R,
446
612
  assetsAlreadyRestored: !0,
447
- ...X(e),
613
+ ...Le(e),
448
614
  ...p ? { copyLoader: p } : {}
449
615
  }));
450
- return Z(e, {
616
+ return Re(e, {
451
617
  file: i,
452
618
  tables: m.tables.length,
453
619
  rows: m.tables.reduce((e, t) => e + t.rowCount, 0)
@@ -459,32 +625,32 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
459
625
  });
460
626
  }
461
627
  }
462
- let m = await f.runPromise(k({
628
+ let m = await f.runPromise(se({
463
629
  store: s,
464
630
  bundleDir: i,
465
631
  mode: a,
466
632
  onConflict: o,
467
633
  atomic: e.includes("--atomic"),
468
634
  verify: !e.includes("--no-verify"),
469
- targetDialect: B(),
635
+ targetDialect: H(),
470
636
  allowIncompatible: l,
471
637
  targetSnapshot: c,
472
638
  force: l,
473
639
  onWarn: u,
474
- onProgress: I,
475
- ...X(e),
476
- ...d ? { assets: oe(d) } : {},
640
+ onProgress: R,
641
+ ...Le(e),
642
+ ...d ? { assets: ce(d) } : {},
477
643
  ...p ? { copyLoader: p } : {}
478
644
  })).catch((e) => {
479
- throw Oe(e), e;
645
+ throw ze(e), e;
480
646
  }).finally(() => p?.close());
481
- return Z(e, {
647
+ return Re(e, {
482
648
  bundleDir: i,
483
649
  tables: m.tables.length,
484
650
  rows: m.tables.reduce((e, t) => e + t.rowCount, 0),
485
651
  assets: m.assets.count
486
652
  }), 0;
487
- }, Q = () => {
653
+ }, Ve = () => {
488
654
  let e = r();
489
655
  return {
490
656
  ...e.url ? { url: e.url } : {},
@@ -494,75 +660,75 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
494
660
  ...e.password ? { password: e.password } : {},
495
661
  ...e.database ? { database: e.database } : {}
496
662
  };
497
- }, Ae = async (e) => {
498
- let t = z(e);
499
- if (!t) return P.error("usage: voltro data backup <outDir> (native pg_dump/mysqldump/… + consistent artifact)"), 1;
500
- let n = B(), { mkdir: r, writeFile: i } = await import("node:fs/promises"), { join: a } = await import("node:path");
663
+ }, He = async (e) => {
664
+ let t = V(e);
665
+ if (!t) return I.error("usage: voltro data backup <outDir> (native pg_dump/mysqldump/… + consistent artifact)"), 1;
666
+ let n = H(), { mkdir: r, writeFile: i } = await import("node:fs/promises"), { join: a } = await import("node:path");
501
667
  await r(t, { recursive: !0 });
502
668
  let o = a(t, C(n));
503
- await f.runPromise(A(ne(n, Q(), o)));
504
- let s = fe({
669
+ await f.runPromise(k(re(n, Ve(), o)));
670
+ let s = be({
505
671
  dialect: n,
506
- schemaFingerprint: await F(n),
507
- voltroVersion: await ge(),
672
+ schemaFingerprint: await L(n),
673
+ voltroVersion: await we(),
508
674
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
509
675
  });
510
- return await i(a(t, j), `${JSON.stringify(s, null, 2)}\n`, "utf8"), P.info("native backup complete", {
676
+ return await i(a(t, N), `${JSON.stringify(s, null, 2)}\n`, "utf8"), I.info("native backup complete", {
511
677
  dialect: n,
512
678
  artifact: o,
513
- stamp: j,
679
+ stamp: N,
514
680
  schemaFingerprint: s.schemaFingerprint ?? "<none>",
515
681
  assets: "NOT included — use `voltro data export --assets` for rows + blobs"
516
682
  }), 0;
517
- }, je = async (e, t) => {
518
- let n = B(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(e, C(n)), o = me({
519
- flagUrl: R(t, "--drill-url"),
683
+ }, Ue = async (e, t) => {
684
+ let n = H(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(e, C(n)), o = Se({
685
+ flagUrl: B(t, "--drill-url"),
520
686
  envUrl: process.env.DRILL_DB_URL,
521
- liveKeys: ye()
687
+ liveKeys: De()
522
688
  });
523
- if (!o.ok) return P.error(`restore --drill: ${o.error}`), 1;
524
- let s = await i(r(e, j), "utf8").then(M, () => null);
525
- if (s && s.dialect !== n) return P.error(`restore --drill: backup is a ${s.dialect} dump but DB_DIALECT is ${n} — cross-dialect restore is never valid.`), 1;
526
- P.info("restore drill: restoring into throwaway DB", {
689
+ if (!o.ok) return I.error(`restore --drill: ${o.error}`), 1;
690
+ let s = await i(r(e, N), "utf8").then(P, () => null);
691
+ if (s && s.dialect !== n) return I.error(`restore --drill: backup is a ${s.dialect} dump but DB_DIALECT is ${n} — cross-dialect restore is never valid.`), 1;
692
+ I.info("restore drill: restoring into throwaway DB", {
527
693
  dialect: n,
528
- target: N(o.url)
529
- }), await f.runPromise(A(D(n, { url: o.url }, a)));
694
+ target: F(o.url)
695
+ }), await f.runPromise(k(D(n, { url: o.url }, a)));
530
696
  let c = null, l = 0;
531
697
  try {
532
- let e = await V(n, { url: o.url });
698
+ let e = await U(n, { url: o.url });
533
699
  c = g(e), l = e.tables.length;
534
700
  } catch (e) {
535
- return P.error(`restore --drill: could not introspect the restored DB — ${String(e)}`), 1;
701
+ return I.error(`restore --drill: could not introspect the restored DB — ${String(e)}`), 1;
536
702
  }
537
- let u = he({
703
+ let u = Ce({
538
704
  stampFingerprint: s?.schemaFingerprint ?? null,
539
705
  restoredFingerprint: c,
540
706
  restoredTableCount: l
541
707
  });
542
- for (let e of u.lines) u.pass ? P.info(`restore drill: ${e}`) : P.error(`restore drill: ${e}`);
708
+ for (let e of u.lines) u.pass ? I.info(`restore drill: ${e}`) : I.error(`restore drill: ${e}`);
543
709
  return +!u.pass;
544
- }, Me = async (e) => {
545
- let t = z(e);
546
- if (!t) return P.error("usage: voltro data restore <backupDir> [--allow-live] [--api-url <url>] [--force] [--drill [--drill-url <url>]] (native pg_restore/mysql/…)"), 1;
547
- if (e.includes("--drill")) return je(t, e);
548
- if (!await L(e)) return 1;
549
- let n = B(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(t, C(n)), o = pe({
550
- stamp: await i(r(t, j), "utf8").then(M, () => null),
710
+ }, We = async (e) => {
711
+ let t = V(e);
712
+ if (!t) return I.error("usage: voltro data restore <backupDir> [--allow-live] [--api-url <url>] [--force] [--drill [--drill-url <url>]] (native pg_restore/mysql/…)"), 1;
713
+ if (e.includes("--drill")) return Ue(t, e);
714
+ if (!await z(e)) return 1;
715
+ let n = H(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(t, C(n)), o = xe({
716
+ stamp: await i(r(t, N), "utf8").then(P, () => null),
551
717
  currentDialect: n,
552
- currentFingerprint: await F(n)
718
+ currentFingerprint: await L(n)
553
719
  });
554
- for (let e of o.info) P.info(`backup stamp: ${e}`);
555
- if (o.warn && P.warn(o.warn), o.refuse) {
556
- if (!e.includes("--force")) return P.error(`restore refused: ${o.refuse} (pass --force to override)`), 1;
557
- P.warn(`restore proceeding despite: ${o.refuse} (--force)`);
720
+ for (let e of o.info) I.info(`backup stamp: ${e}`);
721
+ if (o.warn && I.warn(o.warn), o.refuse) {
722
+ if (!e.includes("--force")) return I.error(`restore refused: ${o.refuse} (pass --force to override)`), 1;
723
+ I.warn(`restore proceeding despite: ${o.refuse} (--force)`);
558
724
  }
559
- return await f.runPromise(A(D(n, Q(), a))), P.info("native restore complete", {
725
+ return await f.runPromise(k(D(n, Ve(), a))), I.info("native restore complete", {
560
726
  dialect: n,
561
727
  artifact: a
562
728
  }), 0;
563
- }, Ne = async (e) => {
564
- let t = z(e);
565
- if (!t) return P.error("usage: voltro data inspect <file.vbundle|dir> [--json] [--passphrase <p>]"), 1;
729
+ }, Ge = async (e) => {
730
+ let t = V(e);
731
+ if (!t) return I.error("usage: voltro data inspect <file.vbundle|dir> [--json] [--passphrase <p>]"), 1;
566
732
  let { resolve: n, join: r } = await import("node:path"), i = await import("node:fs/promises"), a = n(process.cwd(), t);
567
733
  if ((await i.stat(a).catch(() => void 0))?.isDirectory()) {
568
734
  let n = r(a, "manifest.json"), o = r(a, "README.md");
@@ -571,25 +737,25 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
571
737
  if (e !== void 0) return console.log(e), 0;
572
738
  }
573
739
  let s = await i.readFile(n, "utf8").catch(() => void 0);
574
- return s === void 0 ? (P.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);
740
+ return s === void 0 ? (I.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);
575
741
  }
576
- let o = K(e), s = () => {
577
- let e = q(a);
742
+ let o = J(e), s = () => {
743
+ let e = Y(a);
578
744
  return o ? w(e, o) : e;
579
745
  };
580
746
  if (e.includes("--json")) {
581
747
  let e = (await E(s(), ["manifest.json"])).get("manifest.json");
582
- return e ? (console.log(e.toString("utf8")), 0) : (P.error("no manifest.json found in the bundle"), 1);
748
+ return e ? (console.log(e.toString("utf8")), 0) : (I.error("no manifest.json found in the bundle"), 1);
583
749
  }
584
750
  let c = (await E(s(), ["README.md"])).get("README.md");
585
751
  if (c) return console.log(c.toString("utf8")), 0;
586
752
  let l = (await E(s(), ["manifest.json"])).get("manifest.json");
587
- return l ? (console.log(l.toString("utf8")), 0) : (P.error("bundle has no README.md or manifest.json"), 1);
588
- }, Pe = async (e) => {
589
- let t = z(e), n = z(e.filter((e) => e !== t));
590
- if (!t || !n) return P.error("usage: voltro data unpack <file.vbundle> <dir> [--passphrase <p>]"), 1;
591
- let { resolve: r } = await import("node:path"), i = q(r(process.cwd(), t)), a = K(e);
592
- return a && (i = w(i, a)), await de(i, r(process.cwd(), n)), P.info("unpack complete", {
753
+ return l ? (console.log(l.toString("utf8")), 0) : (I.error("bundle has no README.md or manifest.json"), 1);
754
+ }, Ke = async (e) => {
755
+ let t = V(e), n = V(e.filter((e) => e !== t));
756
+ if (!t || !n) return I.error("usage: voltro data unpack <file.vbundle> <dir> [--passphrase <p>]"), 1;
757
+ let { resolve: r } = await import("node:path"), i = Y(r(process.cwd(), t)), a = J(e);
758
+ return a && (i = w(i, a)), await A(i, r(process.cwd(), n)), I.info("unpack complete", {
593
759
  file: t,
594
760
  dir: n
595
761
  }), 0;
@@ -614,7 +780,8 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
614
780
  apiOnly: [
615
781
  "--api-url",
616
782
  "--token",
617
- "--bundle-key"
783
+ "--bundle-key",
784
+ "--timeout"
618
785
  ]
619
786
  },
620
787
  import: {
@@ -637,7 +804,9 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
637
804
  apiOnly: [
638
805
  "--api-url",
639
806
  "--token",
640
- "--bundle-key"
807
+ "--bundle-key",
808
+ "--timeout",
809
+ "--chunk-size"
641
810
  ]
642
811
  },
643
812
  unpack: { common: ["--passphrase", "--json"] },
@@ -651,13 +820,13 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
651
820
  "--drill-url",
652
821
  "--api-url"
653
822
  ] }
654
- }, Fe = (e) => e.split("=")[0], Ie = (e, t) => {
823
+ }, qe = (e) => e.split("=")[0], Je = (e, t) => {
655
824
  let n = $[e];
656
825
  if (!n) return;
657
- let r = R(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 ?? []);
826
+ let r = B(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 ?? []);
658
827
  for (let n of t) {
659
828
  if (!n.startsWith("--")) continue;
660
- let t = Fe(n);
829
+ let t = qe(n);
661
830
  if (i.has(t)) continue;
662
831
  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.`;
663
832
  let o = Object.entries($).filter(([n, r]) => n !== e && [
@@ -667,13 +836,13 @@ var j = "voltro-backup-stamp.json", fe = (e) => ({
667
836
  ].includes(t)).map(([e]) => e);
668
837
  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.`;
669
838
  }
670
- }, Le = async (e) => {
839
+ }, Ye = async (e) => {
671
840
  let [t, ...n] = e;
672
841
  if (t !== void 0 && $[t] !== void 0) {
673
- let e = Ie(t, n);
674
- if (e) return P.error(e), 2;
842
+ let e = Je(t, n);
843
+ if (e) return I.error(e), 2;
675
844
  }
676
- return t === "export" ? De(n) : t === "import" ? ke(n) : t === "unpack" ? Pe(n) : t === "inspect" ? Ne(n) : t === "backup" ? Ae(n) : t === "restore" ? Me(n) : (P.error("usage: voltro data <export|import|unpack|inspect|backup|restore> … (logical: export/import; native: backup/restore)"), t ? 2 : 1);
845
+ return t === "export" ? Ie(n) : t === "import" ? Be(n) : t === "unpack" ? Ke(n) : t === "inspect" ? Ge(n) : t === "backup" ? He(n) : t === "restore" ? We(n) : (I.error("usage: voltro data <export|import|unpack|inspect|backup|restore> … (logical: export/import; native: backup/restore)"), t ? 2 : 1);
677
846
  };
678
847
  //#endregion
679
- export { Le as runDataCommand };
848
+ export { Ye as runDataCommand };