@voltro/cli 0.47.0 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +80 -0
- package/dist/apiBuild-DOnvi2zm.js +2 -0
- package/dist/{apiBuild-FpHCWiv6.js → apiBuild-Dz8TJSxp.js} +1 -1
- package/dist/bin.js +1 -1
- package/dist/{build-zVygXxGB.js → build-DLme2ppa.js} +6 -6
- package/dist/{checkCommand-B2Fw73lu.js → checkCommand-BUBqPBlI.js} +1 -1
- package/dist/{checkCommand-D0dAKciE.js → checkCommand-Dals7g-I.js} +3 -3
- package/dist/{codegenCommand-BTtsnRus.js → codegenCommand-L6vacVRW.js} +3 -2
- package/dist/{commands-BrFKxnYW.js → commands-CAxFLqG4.js} +17 -17
- package/dist/{dashboardCommand-D9SjDc8E.js → dashboardCommand-CJC8Kg-s.js} +1 -1
- package/dist/{dataCommand-Dl11q14e.js → dataCommand-hIaq2iKY.js} +266 -189
- package/dist/dbCommand-D1Q33ktl.js +2 -0
- package/dist/{dbCommand-jbrmzwW_.js → dbCommand-ZGNItjoJ.js} +4 -4
- package/dist/declaredSchemaGates-BlcwObhb.js +25 -0
- package/dist/{dev-CaIfZnw5.js → dev-cGGsLNn6.js} +1 -1
- package/dist/{dev-RjB7eE_B.js → dev-lvnVq5RD.js} +31 -30
- package/dist/{doctorCommand-D7X29cw6.js → doctorCommand-BK0qu7eD.js} +32 -14
- package/dist/doctorCommand-CWgUPye-.js +2 -0
- package/dist/doctorDecidedSchema-BlbWgCD_.js +23 -0
- package/dist/{dormancyCommand-BGOP27fz.js → dormancyCommand-CyIk-zq4.js} +1 -1
- package/dist/{embeddingsCommand-D72E22bw.js → embeddingsCommand-D7TLklps.js} +1 -1
- package/dist/{envCommand-BHSxz6wC.js → envCommand-BHxKkGXq.js} +1 -1
- package/dist/{evolveCommand-C2ofGGlz.js → evolveCommand-CQh6dw21.js} +1 -1
- package/dist/{frameworkTableAssembly-BvZ0Lil_.js → frameworkTableAssembly-BNod_DKN.js} +97 -120
- package/dist/frameworkTableAssembly-Rft-DPUg.js +2 -0
- package/dist/index.js +1 -1
- package/dist/{migrate-odCPGHPq.js → migrate-CL5Ed01M.js} +4 -4
- package/dist/{runtimeTrace-C_OKr0jY.js → runtimeTrace-C0SlIoQY.js} +1 -1
- package/dist/{sdkgen-D9trW7sl.js → sdkgen-BXm7zx7F.js} +1 -1
- package/dist/{serveCommand-BU0wfV6V.js → serveCommand-CV3YO9L3.js} +469 -365
- package/dist/serveCommand-ZP_Cb-yz.js +2 -0
- package/dist/serveEntry.js +1 -1
- package/dist/{webhooksCommand-BqcWcbuW.js → webhooksCommand-QlAk_tED.js} +1 -1
- package/package.json +17 -17
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/cli.md +58 -3
- package/templates/agent-docs/database/migrations.md +19 -5
- package/templates/agent-docs/whats-new.md +63 -13
- package/templates/apps/api-ai/package.json +7 -7
- package/templates/apps/api-auth/package.json +8 -8
- package/templates/apps/api-backend/package.json +7 -7
- package/templates/apps/api-backend-deactivation/package.json +7 -7
- package/templates/apps/api-backend-mail/package.json +8 -8
- package/templates/apps/api-backend-mariadb/package.json +9 -9
- package/templates/apps/api-backend-sqlite/package.json +8 -8
- package/templates/apps/api-backend-storage/package.json +8 -8
- package/templates/apps/api-cms/package.json +10 -10
- package/templates/apps/api-collab/package.json +8 -8
- package/templates/apps/api-data-advanced/package.json +8 -8
- package/templates/apps/api-durable/package.json +8 -8
- package/templates/apps/api-feature-flags/package.json +9 -9
- package/templates/apps/api-governance/package.json +8 -8
- package/templates/apps/api-kv/package.json +8 -8
- package/templates/apps/api-moderation/package.json +8 -8
- package/templates/apps/api-observability/package.json +8 -8
- package/templates/apps/api-ratelimit/package.json +8 -8
- package/templates/apps/api-rbac/package.json +8 -8
- package/templates/apps/api-rest/package.json +7 -7
- package/templates/apps/api-saas/package.json +11 -11
- package/templates/apps/api-saas-starter/package.json +10 -10
- package/templates/apps/api-search/package.json +8 -8
- package/templates/apps/api-status/package.json +8 -8
- package/templates/apps/api-versioning/package.json +8 -8
- package/templates/apps/api-webhooks/package.json +9 -9
- package/templates/apps/changelog/package.json +6 -6
- package/templates/apps/edge-functions/package.json +2 -2
- package/templates/apps/frontend-admin/package.json +8 -8
- package/templates/apps/frontend-app/package.json +9 -9
- package/templates/apps/frontend-auth/package.json +8 -8
- package/templates/apps/frontend-blank/package.json +7 -7
- package/templates/apps/frontend-cms/package.json +9 -9
- package/templates/apps/frontend-collab/package.json +10 -10
- package/templates/apps/frontend-contact/package.json +7 -7
- package/templates/apps/frontend-dashboard/package.json +7 -7
- package/templates/apps/frontend-docs/package.json +7 -7
- package/templates/apps/frontend-i18n/package.json +6 -6
- package/templates/apps/frontend-landing/package.json +7 -7
- package/templates/apps/frontend-portal/package.json +8 -8
- package/templates/apps/frontend-saas/package.json +8 -8
- package/templates/apps/frontend-spa/package.json +7 -7
- package/templates/apps/frontend-ssr/package.json +7 -7
- package/templates/apps/frontend-ssr-api/package.json +8 -8
- package/templates/apps/frontend-static-blog/package.json +6 -6
- package/templates/apps/frontend-status/package.json +8 -8
- package/templates/apps/mobile-app/package.json +4 -4
- package/dist/apiBuild-BsooZpw2.js +0 -2
- package/dist/dbCommand-BUD4Fd8v.js +0 -2
- package/dist/doctorCommand-5zv6PN-G.js +0 -2
- package/dist/frameworkTableAssembly-DDKtwsy2.js +0 -2
- package/dist/serveCommand-Bwrn_9Fn.js +0 -2
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { t as e } from "./cliError-BmdYnghb.js";
|
|
2
|
-
import { c as t, i as n, o as r, z as i } from "./dev-
|
|
2
|
+
import { c as t, i as n, o as r, z as i } from "./dev-lvnVq5RD.js";
|
|
3
3
|
import { n as a, t as o } from "./cliArgs-D4p8n7EE.js";
|
|
4
4
|
import { r as s } from "./dialectDriver-czCHYpeH.js";
|
|
5
5
|
import { t as c } from "./dataProfile-Cm0YVKSy.js";
|
|
6
6
|
import { o as l, t as u } from "./inspectFetch-EMuhTG_9.js";
|
|
7
|
-
import { r as d } from "./dbCommand-
|
|
7
|
+
import { r as d } from "./dbCommand-ZGNItjoJ.js";
|
|
8
8
|
import { resolve as f } from "node:path";
|
|
9
9
|
import { createLogger as p } from "@voltro/logger";
|
|
10
|
-
import {
|
|
11
|
-
import { Effect as
|
|
12
|
-
import { SqlClient as
|
|
13
|
-
import { declaredSnapshot as
|
|
14
|
-
import { STORAGE_REFS_TABLE as
|
|
15
|
-
import { createHash as
|
|
16
|
-
import { asImportError as
|
|
10
|
+
import { IMPORT_RUNS_TABLE as m, connectionIdentity as h, normaliseTarget as g, sameDatabase as _, streamTable as v } from "@voltro/database";
|
|
11
|
+
import { Effect as y, Stream as b } from "effect";
|
|
12
|
+
import { SqlClient as x } from "@effect/sql";
|
|
13
|
+
import { declaredSnapshot as ee, fingerprintSchema as te, introspectSchema as ne } from "@voltro/database/sql";
|
|
14
|
+
import { STORAGE_REFS_TABLE as re, resolveStorageProvider as S } from "@voltro/plugin-storage";
|
|
15
|
+
import { createHash as ie } from "node:crypto";
|
|
16
|
+
import { asImportError as ae, assessLiveImport as oe, backupArtifactName as C, backupCommand as se, classificationFromSnapshot as ce, decryptStream as w, encryptStream as le, packBundle as ue, peekBundle as T, previewMasking as de, restoreCommand as E, runExport as D, runImport as O, runNativeStep as k, storageAssetSink as fe, storageAssetSource as pe, storageBlobSink as me, storageBlobSource as he, unpackBundle as ge, unpackBundleToDir as A } from "@voltro/data-transfer";
|
|
17
17
|
import { request as _e } from "node:http";
|
|
18
18
|
import { request as ve } from "node:https";
|
|
19
19
|
//#region src/longRequest.ts
|
|
@@ -25,7 +25,7 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
25
25
|
"ENOTFOUND",
|
|
26
26
|
"ECONNRESET",
|
|
27
27
|
"EAI_AGAIN"
|
|
28
|
-
]),
|
|
28
|
+
]), j = class extends Error {
|
|
29
29
|
url;
|
|
30
30
|
cause;
|
|
31
31
|
constructor(e, t) {
|
|
@@ -38,13 +38,13 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
38
38
|
})();
|
|
39
39
|
super(`the instance at ${n} is not answering (${t.code ?? "connect failed"}).`), this.url = e, this.cause = t, this.name = "InstanceUnreachable";
|
|
40
40
|
}
|
|
41
|
-
},
|
|
41
|
+
}, M = class extends Error {
|
|
42
42
|
elapsedMs;
|
|
43
43
|
url;
|
|
44
44
|
constructor(e, t) {
|
|
45
45
|
super(`no response after ${Math.round(e / 1e3)}s`), this.elapsedMs = e, this.url = t, this.name = "LongRequestTimeout";
|
|
46
46
|
}
|
|
47
|
-
},
|
|
47
|
+
}, N = async (e, t, n, r) => {
|
|
48
48
|
let i = new URL(e), a = i.protocol === "https:" ? ve : _e, o = Date.now();
|
|
49
49
|
return await new Promise((s, c) => {
|
|
50
50
|
let l = a({
|
|
@@ -63,8 +63,8 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
63
63
|
})), e.on("error", c);
|
|
64
64
|
});
|
|
65
65
|
if (r?.timeoutMs !== void 0 && r.timeoutMs > 0 && l.setTimeout(r.timeoutMs, () => {
|
|
66
|
-
l.destroy(new
|
|
67
|
-
}), l.on("error", (t) => c(ye.has(t.code ?? "") ? new
|
|
66
|
+
l.destroy(new M(Date.now() - o, e));
|
|
67
|
+
}), l.on("error", (t) => c(ye.has(t.code ?? "") ? new j(e, t) : t)), typeof t == "string" || Buffer.isBuffer(t)) {
|
|
68
68
|
l.end(t);
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
@@ -99,7 +99,7 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
99
99
|
i += a.byteLength, yield s;
|
|
100
100
|
}
|
|
101
101
|
yield* a(!0);
|
|
102
|
-
}, we = (e) =>
|
|
102
|
+
}, we = (e) => ie("sha256").update(Buffer.from(e)).digest("hex"), Te = async (e) => {
|
|
103
103
|
let t = 0, n = 0, r = {
|
|
104
104
|
status: 0,
|
|
105
105
|
body: {}
|
|
@@ -130,13 +130,13 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
130
130
|
bytes: t,
|
|
131
131
|
resumedFrom: e.alreadyHeld
|
|
132
132
|
};
|
|
133
|
-
},
|
|
133
|
+
}, P = "voltro-backup-stamp.json", Ee = (e) => ({
|
|
134
134
|
stampVersion: 1,
|
|
135
135
|
dialect: e.dialect,
|
|
136
136
|
schemaFingerprint: e.schemaFingerprint,
|
|
137
137
|
voltroVersion: e.voltroVersion,
|
|
138
138
|
createdAt: e.createdAt
|
|
139
|
-
}),
|
|
139
|
+
}), De = (e) => {
|
|
140
140
|
let t;
|
|
141
141
|
try {
|
|
142
142
|
t = JSON.parse(e);
|
|
@@ -154,10 +154,10 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
154
154
|
voltroVersion: n.voltroVersion,
|
|
155
155
|
createdAt: n.createdAt
|
|
156
156
|
};
|
|
157
|
-
},
|
|
157
|
+
}, Oe = (e) => {
|
|
158
158
|
let { stamp: t, currentDialect: n, currentFingerprint: r } = e;
|
|
159
159
|
if (t === null) return {
|
|
160
|
-
warn: `no ${
|
|
160
|
+
warn: `no ${P} beside the dump — an older/handmade backup. Cannot verify dialect or schema version; make sure this dump is a ${n} dump.`,
|
|
161
161
|
info: []
|
|
162
162
|
};
|
|
163
163
|
let i = [`backup produced by @voltro/cli ${t.voltroVersion} at ${t.createdAt}`, `schema fingerprint: ${t.schemaFingerprint ?? "<none recorded>"}`];
|
|
@@ -175,7 +175,7 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
175
175
|
} catch {
|
|
176
176
|
return e.trim();
|
|
177
177
|
}
|
|
178
|
-
},
|
|
178
|
+
}, ke = (e) => {
|
|
179
179
|
let t = e.flagUrl ?? e.envUrl;
|
|
180
180
|
if (t === void 0 || t.trim() === "") return {
|
|
181
181
|
ok: !1,
|
|
@@ -189,7 +189,7 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
189
189
|
ok: !0,
|
|
190
190
|
url: t
|
|
191
191
|
};
|
|
192
|
-
},
|
|
192
|
+
}, Ae = (e) => {
|
|
193
193
|
let { stampFingerprint: t, restoredFingerprint: n, restoredTableCount: r } = e;
|
|
194
194
|
return r === 0 ? {
|
|
195
195
|
pass: !1,
|
|
@@ -204,7 +204,7 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
204
204
|
pass: !0,
|
|
205
205
|
lines: [`PASS — restored ${r} table(s); schema fingerprint matches the backup stamp (${n.slice(0, 12)}).`]
|
|
206
206
|
};
|
|
207
|
-
}, I = p({ scope: "voltro:data" }),
|
|
207
|
+
}, I = p({ scope: "voltro:data" }), je = async () => {
|
|
208
208
|
try {
|
|
209
209
|
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");
|
|
210
210
|
return JSON.parse(n(r, "utf8")).version ?? "unknown";
|
|
@@ -213,7 +213,7 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
213
213
|
}
|
|
214
214
|
}, L = async (e) => {
|
|
215
215
|
try {
|
|
216
|
-
return
|
|
216
|
+
return te(await W(e));
|
|
217
217
|
} catch {
|
|
218
218
|
return null;
|
|
219
219
|
}
|
|
@@ -221,7 +221,7 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
221
221
|
if (e.event !== "done") return;
|
|
222
222
|
let t = e.total === void 0 ? "" : ` / ${e.total}`;
|
|
223
223
|
I.info(`${e.phase} [${e.index + 1}/${e.tableCount}] ${e.table}`, { rows: `${e.rowsDone}${t}` });
|
|
224
|
-
},
|
|
224
|
+
}, Me = async (e) => {
|
|
225
225
|
let t = (e) => e?.meta?.databaseId;
|
|
226
226
|
if (e) {
|
|
227
227
|
let n = await u({
|
|
@@ -241,21 +241,21 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
241
241
|
};
|
|
242
242
|
}
|
|
243
243
|
return null;
|
|
244
|
-
},
|
|
245
|
-
let t = e.includes("--allow-live"), n = t ? null : await
|
|
246
|
-
dialect:
|
|
244
|
+
}, z = async (e) => {
|
|
245
|
+
let t = e.includes("--allow-live"), n = t ? null : await Me(B(e, "--api-url")), i = h({
|
|
246
|
+
dialect: H(),
|
|
247
247
|
...r()
|
|
248
|
-
}), a =
|
|
249
|
-
dialect:
|
|
248
|
+
}), a = g({
|
|
249
|
+
dialect: H(),
|
|
250
250
|
...r()
|
|
251
|
-
}), { refuse: o, message: s } =
|
|
251
|
+
}), { refuse: o, message: s } = oe({
|
|
252
252
|
liveInstance: n?.label ?? null,
|
|
253
253
|
allowLive: t,
|
|
254
|
-
sameTarget:
|
|
254
|
+
sameTarget: _(i, n?.databaseId),
|
|
255
255
|
...a === void 0 ? {} : { targetLabel: `${a.host}:${a.port}/${a.database}` }
|
|
256
256
|
});
|
|
257
257
|
return !o || (I.error(s ?? "refusing: live instance detected"), !1);
|
|
258
|
-
},
|
|
258
|
+
}, B = a, Ne = [
|
|
259
259
|
"--api-url",
|
|
260
260
|
"--bundle-key",
|
|
261
261
|
"--compression",
|
|
@@ -263,6 +263,7 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
263
263
|
"--drill-url",
|
|
264
264
|
"--chunk-size",
|
|
265
265
|
"--exclude",
|
|
266
|
+
"--limit",
|
|
266
267
|
"--mode",
|
|
267
268
|
"--no-atomic",
|
|
268
269
|
"--on-conflict",
|
|
@@ -273,49 +274,58 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
273
274
|
"--timeout",
|
|
274
275
|
"--tenant",
|
|
275
276
|
"--token"
|
|
276
|
-
],
|
|
277
|
+
], V = (e) => o(e, Ne), H = () => {
|
|
277
278
|
let t = (process.env.DB_DIALECT ?? "postgres").toLowerCase();
|
|
278
279
|
if (t === "memory") throw new e("voltro data: requires a real dialect, not DB_DIALECT=memory.");
|
|
279
280
|
return t;
|
|
280
|
-
},
|
|
281
|
+
}, U = async (e, t) => {
|
|
281
282
|
let n = (await s(e)).makeSqlLayer(t);
|
|
282
|
-
return
|
|
283
|
-
},
|
|
283
|
+
return y.runPromise(x.SqlClient.pipe(y.flatMap(ne), y.provide(n)));
|
|
284
|
+
}, W = (e) => U(e, r()), Pe = () => {
|
|
284
285
|
let e = r(), t = [];
|
|
285
286
|
return e.url && t.push(F(e.url)), (e.host || e.database) && t.push(`${(e.host ?? "localhost").toLowerCase()}:${e.port ?? "(default)"}/${e.database ?? ""}`), t;
|
|
286
|
-
},
|
|
287
|
+
}, G = async () => {
|
|
287
288
|
let r = process.cwd(), i = await t(r);
|
|
288
289
|
if (!i) throw new e("voltro data: no app.config.ts found in the current directory.");
|
|
289
|
-
let a = await n(i, void 0), o =
|
|
290
|
+
let a = await n(i, void 0), o = H();
|
|
290
291
|
return {
|
|
291
292
|
store: a,
|
|
292
|
-
snapshot: await
|
|
293
|
+
snapshot: await W(o),
|
|
293
294
|
dialect: o
|
|
294
295
|
};
|
|
295
|
-
},
|
|
296
|
-
table:
|
|
296
|
+
}, K = (e) => v(e, {
|
|
297
|
+
table: re,
|
|
297
298
|
chunkSize: 500
|
|
298
|
-
}).pipe(
|
|
299
|
+
}).pipe(b.map((e) => ({
|
|
299
300
|
key: String(e.key),
|
|
300
301
|
contentType: String(e.contentType ?? "application/octet-stream"),
|
|
301
302
|
size: Number(e.size ?? 0)
|
|
302
|
-
}))),
|
|
303
|
+
}))), q = (e) => !!e && e.endsWith(".vbundle"), J = (e) => B(e, "--passphrase") ?? process.env.VOLTRO_BUNDLE_KEY, Fe = (e) => e.includes("--encrypt") || B(e, "--passphrase") !== void 0 || process.env.VOLTRO_BUNDLE_KEY !== void 0, Ie = async (e, t) => {
|
|
303
304
|
let { createWriteStream: n } = await import("node:fs"), { pipeline: r } = await import("node:stream/promises"), { Readable: i } = await import("node:stream");
|
|
304
305
|
await r(i.from(e), n(t));
|
|
305
|
-
},
|
|
306
|
+
}, Y = (e) => ({ async *[Symbol.asyncIterator]() {
|
|
306
307
|
let { createReadStream: t } = await import("node:fs");
|
|
307
308
|
for await (let n of t(e)) yield n instanceof Uint8Array ? n : new Uint8Array(n);
|
|
308
|
-
} }),
|
|
309
|
-
|
|
309
|
+
} }), Le = async (e, t) => {
|
|
310
|
+
if (t !== void 0 || e === void 0) return null;
|
|
311
|
+
try {
|
|
312
|
+
let { resolve: t, join: n } = await import("node:path"), r = await import("node:fs/promises"), i = t(process.cwd(), e), a = q(e) ? (await T(Y(i), ["manifest.json"])).get("manifest.json") : await r.readFile(n(i, "manifest.json"));
|
|
313
|
+
if (a === void 0) return null;
|
|
314
|
+
let o = (JSON.parse(Buffer.from(a).toString("utf8")).tables ?? []).map((e) => e.name).filter((e) => typeof e == "string");
|
|
315
|
+
return o.length > 0 ? o : null;
|
|
316
|
+
} catch {
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
}, X = (e) => (e ?? "").split(",").map((e) => e.trim()).filter(Boolean), Re = (t, n) => {
|
|
320
|
+
let r = B(t, "--tenant"), i = B(t, "--tables"), a = B(t, "--exclude");
|
|
310
321
|
if (a !== void 0) {
|
|
311
322
|
if (i !== void 0) throw new e("voltro data export: --exclude and --tables are two ways to say the same thing; use one.");
|
|
312
323
|
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.");
|
|
313
|
-
let t =
|
|
324
|
+
let t = X(a), o = new Set(n), s = t.filter((e) => !o.has(e));
|
|
314
325
|
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.`);
|
|
315
|
-
let c = new Set(t);
|
|
316
326
|
return {
|
|
317
|
-
kind: "
|
|
318
|
-
|
|
327
|
+
kind: "all",
|
|
328
|
+
exclude: t
|
|
319
329
|
};
|
|
320
330
|
}
|
|
321
331
|
return r ? {
|
|
@@ -323,15 +333,15 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
323
333
|
tenantId: r
|
|
324
334
|
} : i ? {
|
|
325
335
|
kind: "tables",
|
|
326
|
-
tables:
|
|
336
|
+
tables: X(i)
|
|
327
337
|
} : { kind: "all" };
|
|
328
|
-
},
|
|
338
|
+
}, ze = async () => {
|
|
329
339
|
let e = await d(process.cwd());
|
|
330
|
-
return
|
|
331
|
-
},
|
|
332
|
-
let e = (await d(process.cwd())).filter((e) => (e.appliedMixins ?? []).some((e) => e.id ===
|
|
340
|
+
return ce(ee(e));
|
|
341
|
+
}, Be = "voltro/tenant", Ve = async () => {
|
|
342
|
+
let e = (await d(process.cwd())).filter((e) => (e.appliedMixins ?? []).some((e) => e.id === Be)).map((e) => e.tableName);
|
|
333
343
|
return e.length > 0 ? e : void 0;
|
|
334
|
-
},
|
|
344
|
+
}, He = (e) => {
|
|
335
345
|
for (let t of e.tables) if (t.samples.length !== 0) {
|
|
336
346
|
console.log(`\n ${t.table}`);
|
|
337
347
|
for (let e of t.samples) console.log(` ${e.column} [${e.action}] ${JSON.stringify(e.before)} → ${JSON.stringify(e.after)}`);
|
|
@@ -344,8 +354,8 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
344
354
|
console.log("\n ✗ unclassified (would BLOCK a real export — add .sensitive()/.safe() or a policy override):");
|
|
345
355
|
for (let t of e.unclassified) console.log(` ${t}`);
|
|
346
356
|
} else console.log("\n ✓ every exported column is classified — safe to run.");
|
|
347
|
-
},
|
|
348
|
-
let { resolve: n, join: r } = await import("node:path"), i = await import("node:fs/promises"), a =
|
|
357
|
+
}, Ue = async (t) => {
|
|
358
|
+
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 ? Se : Math.round(Number(a) * 1024 * 1024);
|
|
349
359
|
if (!Number.isFinite(o) || o <= 0) throw new e(`--chunk-size expects a positive number of megabytes, got '${String(a)}'`);
|
|
350
360
|
let s = t.stream[Symbol.asyncIterator](), c = [], l = 0, u = !1;
|
|
351
361
|
for (; l <= o;) {
|
|
@@ -360,11 +370,11 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
360
370
|
kind: "small",
|
|
361
371
|
body: Buffer.concat(c)
|
|
362
372
|
};
|
|
363
|
-
let d = n(process.cwd(), t.bundleDir), f = we(
|
|
373
|
+
let d = n(process.cwd(), t.bundleDir), f = we(q(t.bundleDir) ? await i.readFile(d) : await i.readFile(r(d, "manifest.json"))), p = `up-${f.slice(0, 32)}`, m = await N(t.url, Buffer.alloc(0), {
|
|
364
374
|
...t.headers,
|
|
365
375
|
"x-import-upload-id": p,
|
|
366
376
|
"x-import-probe": "1"
|
|
367
|
-
},
|
|
377
|
+
}, Q(t.args)), h = m.status === 200 ? Number(JSON.parse(m.body.toString("utf8")).bytes ?? 0) : 0;
|
|
368
378
|
h > 0 && t.log.info("api import: resuming a chunked upload the instance already holds", { bytes: h });
|
|
369
379
|
let g = (async function* () {
|
|
370
380
|
for (let e of c) yield e;
|
|
@@ -387,7 +397,7 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
387
397
|
t.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.");
|
|
388
398
|
},
|
|
389
399
|
target: { send: async (e, n) => {
|
|
390
|
-
let r = await
|
|
400
|
+
let r = await N(t.url, e, n, Q(t.args)), i = {};
|
|
391
401
|
try {
|
|
392
402
|
i = JSON.parse(r.body.toString("utf8") || "{}");
|
|
393
403
|
} catch {}
|
|
@@ -409,68 +419,70 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
409
419
|
body: Buffer.from(JSON.stringify(v.body))
|
|
410
420
|
}
|
|
411
421
|
};
|
|
412
|
-
},
|
|
422
|
+
}, We = (e) => `--mode replace with --no-atomic against a ${e ? "RUNNING instance" : "live database"}: the target is empty between the delete and the load, and anything the application writes in that window can collide with a row from the bundle — or survive the import as a row the bundle never carried. Drop --no-atomic to run the whole load in one transaction (concurrent writers then wait instead of racing), or stop the traffic for the duration.`, Z = (e, t) => e.includes("--no-atomic") ? !1 : e.includes("--atomic") || t === "replace", Ge = (e, t, n) => {
|
|
413
423
|
if (t !== "replace" || e.includes("--no-rollback")) return;
|
|
414
|
-
let r =
|
|
424
|
+
let r = B(e, "--rollback-dir");
|
|
415
425
|
return r === void 0 ? i(n) : f(r);
|
|
416
|
-
},
|
|
417
|
-
let r =
|
|
426
|
+
}, Ke = (e, t, n) => {
|
|
427
|
+
let r = Ge(e, t, n);
|
|
418
428
|
return {
|
|
419
429
|
...r === void 0 ? {} : { rollbackDir: r },
|
|
420
430
|
recordInterruption: !0,
|
|
421
431
|
via: "direct"
|
|
422
432
|
};
|
|
423
|
-
},
|
|
424
|
-
let n =
|
|
433
|
+
}, Q = (t) => {
|
|
434
|
+
let n = B(t, "--timeout");
|
|
425
435
|
if (n === void 0) return {};
|
|
426
436
|
let r = Number(n);
|
|
427
437
|
if (!Number.isFinite(r) || r <= 0) throw new e(`--timeout expects a positive number of seconds, got '${n}'`);
|
|
428
438
|
return { timeoutMs: Math.round(r * 1e3) };
|
|
429
|
-
},
|
|
430
|
-
let t =
|
|
439
|
+
}, qe = async (e) => {
|
|
440
|
+
let t = B(e, "--target") === "api", n = B(e, "--bundle-key"), r = V(e);
|
|
431
441
|
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;
|
|
432
442
|
if (t) {
|
|
433
|
-
let t =
|
|
443
|
+
let t = B(e, "--api-url");
|
|
434
444
|
if (!t) return I.error("--target api requires --api-url <url> (the running instance)"), 1;
|
|
435
|
-
let i =
|
|
445
|
+
let i = B(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
|
|
436
446
|
if (!i) return I.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
...
|
|
447
|
+
let a = B(e, "--tables"), o = B(e, "--exclude");
|
|
448
|
+
if (o !== void 0 && a !== void 0) return I.error("voltro data export: --exclude and --tables are two ways to say the same thing; use one."), 1;
|
|
449
|
+
let s = {
|
|
450
|
+
...B(e, "--profile") ? { profile: B(e, "--profile") } : {},
|
|
451
|
+
...B(e, "--tenant") ? { tenant: B(e, "--tenant") } : {},
|
|
441
452
|
...a ? { tables: a.split(",").map((e) => e.trim()).filter(Boolean) } : {},
|
|
442
|
-
...
|
|
443
|
-
...
|
|
453
|
+
...o ? { exclude: o.split(",").map((e) => e.trim()).filter(Boolean) } : {},
|
|
454
|
+
...B(e, "--consistency") === "snapshot" ? { consistency: "snapshot" } : {},
|
|
455
|
+
...B(e, "--compression") ? { compression: B(e, "--compression") } : {},
|
|
444
456
|
...e.includes("--assets") ? { assets: !0 } : {},
|
|
445
457
|
...n ? { bundleKey: n } : {}
|
|
446
|
-
},
|
|
458
|
+
}, c;
|
|
447
459
|
try {
|
|
448
|
-
|
|
460
|
+
c = await N(`${t.replace(/\/+$/, "")}/_voltro/admin/export`, JSON.stringify(s), {
|
|
449
461
|
"content-type": "application/json",
|
|
450
462
|
authorization: `Bearer ${i}`
|
|
451
|
-
},
|
|
463
|
+
}, Q(e));
|
|
452
464
|
} catch (e) {
|
|
453
|
-
if (e instanceof
|
|
454
|
-
if (e instanceof
|
|
465
|
+
if (e instanceof M) 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;
|
|
466
|
+
if (e instanceof j) return I.error(`api export: ${be(e)}`), 1;
|
|
455
467
|
throw e;
|
|
456
468
|
}
|
|
457
|
-
if (
|
|
469
|
+
if (c.status < 200 || c.status >= 300) return I.error(`api export failed: HTTP ${c.status} — ${c.body.toString("utf8")}`), 1;
|
|
458
470
|
if (n) return I.info("api export complete (pushed to storage)", {
|
|
459
471
|
via: t,
|
|
460
|
-
...JSON.parse(
|
|
472
|
+
...JSON.parse(c.body.toString("utf8"))
|
|
461
473
|
}), 0;
|
|
462
|
-
let { resolve:
|
|
463
|
-
return await
|
|
464
|
-
yield
|
|
465
|
-
})(),
|
|
474
|
+
let { resolve: l } = await import("node:path"), u = new Uint8Array(c.body);
|
|
475
|
+
return await A((async function* () {
|
|
476
|
+
yield u;
|
|
477
|
+
})(), l(process.cwd(), r)), I.info("api export complete (downloaded from the running instance)", {
|
|
466
478
|
outDir: r,
|
|
467
|
-
tables:
|
|
468
|
-
rows:
|
|
469
|
-
masked:
|
|
479
|
+
tables: c.headers["x-export-tables"],
|
|
480
|
+
rows: c.headers["x-export-rows"],
|
|
481
|
+
masked: c.headers["x-export-masked"]
|
|
470
482
|
}), 0;
|
|
471
483
|
}
|
|
472
484
|
if (!r) return I.error("a <outDir> is required for a direct export"), 1;
|
|
473
|
-
let i =
|
|
485
|
+
let i = B(e, "--profile"), a = i ? await c(i, { allowPath: !0 }) : {}, { store: o, snapshot: s, dialect: l } = await G(), u = e.includes("--assets") || a.assets === !0, d = u ? S({}) : void 0, f = B(e, "--compression") ?? a.compression, p = B(e, "--consistency") === "snapshot" ? "snapshot" : a.consistency ?? "live", m = a.masking, h = a.subset, g = a.scope ?? Re(e, s.tables.map((e) => e.name)), _ = m ? await ze() : void 0, v = g.kind === "tenant" ? await Ve() : void 0, b = v ? { tenantTables: v } : {};
|
|
474
486
|
if (e.includes("--dry-run")) {
|
|
475
487
|
let e = g.kind === "tables" && g.tables ? [...g.tables] : s.tables.map((e) => e.name);
|
|
476
488
|
if (I.info("export DRY RUN — nothing was written", {
|
|
@@ -482,7 +494,7 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
482
494
|
assets: u,
|
|
483
495
|
masking: m ? "profile policy applies" : "none"
|
|
484
496
|
}), I.info(`would export: ${e.join(", ")}`), !m) return 0;
|
|
485
|
-
let t = await
|
|
497
|
+
let t = await y.runPromise(de({
|
|
486
498
|
store: o,
|
|
487
499
|
snapshot: s,
|
|
488
500
|
masking: m,
|
|
@@ -492,12 +504,12 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
492
504
|
...b
|
|
493
505
|
}
|
|
494
506
|
}));
|
|
495
|
-
return
|
|
507
|
+
return He(t), +(t.unclassified.length > 0);
|
|
496
508
|
}
|
|
497
|
-
if (
|
|
509
|
+
if (q(r)) {
|
|
498
510
|
let t = await import("node:os"), n = await import("node:fs/promises"), { resolve: i, join: a } = await import("node:path"), c = await n.mkdtemp(a(t.tmpdir(), "voltro-export-"));
|
|
499
511
|
try {
|
|
500
|
-
let t = await
|
|
512
|
+
let t = await y.runPromise(D({
|
|
501
513
|
store: o,
|
|
502
514
|
snapshot: s,
|
|
503
515
|
dialect: l,
|
|
@@ -511,14 +523,14 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
511
523
|
...m ? { masking: m } : {},
|
|
512
524
|
..._ ? { classification: _ } : {},
|
|
513
525
|
onProgress: R
|
|
514
|
-
})), n =
|
|
526
|
+
})), n = ue({
|
|
515
527
|
dir: c,
|
|
516
|
-
...d ? { blobs: he(d, () =>
|
|
528
|
+
...d ? { blobs: he(d, () => K(o)) } : {}
|
|
517
529
|
}), a = Fe(e);
|
|
518
530
|
if (a) {
|
|
519
|
-
let t =
|
|
531
|
+
let t = J(e);
|
|
520
532
|
if (!t) return I.error("--encrypt requires --passphrase <p> or VOLTRO_BUNDLE_KEY (a dedicated key, NOT the transfer secret)"), 1;
|
|
521
|
-
n =
|
|
533
|
+
n = le(n, t);
|
|
522
534
|
}
|
|
523
535
|
return await Ie(n, i(process.cwd(), r)), I.info("export complete (single file)", {
|
|
524
536
|
file: r,
|
|
@@ -534,7 +546,7 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
534
546
|
});
|
|
535
547
|
}
|
|
536
548
|
}
|
|
537
|
-
let x = await
|
|
549
|
+
let x = await y.runPromise(D({
|
|
538
550
|
store: o,
|
|
539
551
|
snapshot: s,
|
|
540
552
|
dialect: l,
|
|
@@ -547,7 +559,7 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
547
559
|
...f ? { compression: f } : {},
|
|
548
560
|
...m ? { masking: m } : {},
|
|
549
561
|
..._ ? { classification: _ } : {},
|
|
550
|
-
...d ? { assets: pe(d, () =>
|
|
562
|
+
...d ? { assets: pe(d, () => K(o)) } : {},
|
|
551
563
|
onProgress: R
|
|
552
564
|
}));
|
|
553
565
|
return I.info("export complete", {
|
|
@@ -558,13 +570,13 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
558
570
|
compression: x.compression,
|
|
559
571
|
...x.masking ? { maskedColumns: x.masking.transformed.length } : {}
|
|
560
572
|
}), 0;
|
|
561
|
-
},
|
|
562
|
-
let t =
|
|
573
|
+
}, Je = () => "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.", Ye = (e) => {
|
|
574
|
+
let t = B(e, "--tables");
|
|
563
575
|
return {
|
|
564
576
|
...t ? { tables: t.split(",").map((e) => e.trim()).filter(Boolean) } : {},
|
|
565
577
|
...e.includes("--dry-run") ? { dryRun: !0 } : {}
|
|
566
578
|
};
|
|
567
|
-
},
|
|
579
|
+
}, Xe = (e) => ({
|
|
568
580
|
tables: e.tablesWritten,
|
|
569
581
|
rows: e.rowsWritten,
|
|
570
582
|
carried: e.manifest.tables.reduce((e, t) => e + t.rowCount, 0),
|
|
@@ -572,9 +584,9 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
572
584
|
skippedTables: e.tablesSkipped,
|
|
573
585
|
skippedRows: e.rowsSkipped
|
|
574
586
|
} : {}
|
|
575
|
-
}),
|
|
587
|
+
}), Ze = (e, t) => {
|
|
576
588
|
if (e.includes("--dry-run")) {
|
|
577
|
-
I.info("import DRY RUN — nothing was written", t), I.info(
|
|
589
|
+
I.info("import DRY RUN — nothing was written", t), I.info(Je());
|
|
578
590
|
return;
|
|
579
591
|
}
|
|
580
592
|
if (t.rows === 0 && typeof t.skippedRows == "number" && t.skippedRows !== 0) {
|
|
@@ -582,8 +594,8 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
582
594
|
return;
|
|
583
595
|
}
|
|
584
596
|
I.info("import complete", t);
|
|
585
|
-
},
|
|
586
|
-
let t =
|
|
597
|
+
}, Qe = Symbol("refused"), $e = (e) => {
|
|
598
|
+
let t = ae(e) ?? e;
|
|
587
599
|
if (t?._tag !== "RowsRefusedError" || !Array.isArray(t.rows)) return !1;
|
|
588
600
|
let n = t.rows, r = n.filter((e) => !e.derived), i = Number(t.totalCount ?? n.length), a = Number(t.primaryCount ?? r.length);
|
|
589
601
|
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.`);
|
|
@@ -593,7 +605,7 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
593
605
|
n.length < i && I.error(` (the list above is capped at ${n.length} of ${i} — the counts by table are complete)`);
|
|
594
606
|
let s = i - a;
|
|
595
607
|
return s > 0 && I.error(` … and ${s} row(s) behind them. Fix the ${a} above and re-run; they resolve with their parents.`), !0;
|
|
596
|
-
},
|
|
608
|
+
}, et = (e) => {
|
|
597
609
|
let t = typeof e == "string" ? e : e.toString("utf8"), n = t;
|
|
598
610
|
try {
|
|
599
611
|
let e = JSON.parse(t), r = e.error ?? e.message;
|
|
@@ -633,22 +645,22 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
633
645
|
return;
|
|
634
646
|
}
|
|
635
647
|
}
|
|
636
|
-
},
|
|
637
|
-
let t =
|
|
648
|
+
}, tt = async (e) => {
|
|
649
|
+
let t = B(e, "--target") === "api", n = B(e, "--bundle-key"), i = V(e);
|
|
638
650
|
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;
|
|
639
|
-
let a =
|
|
651
|
+
let a = B(e, "--mode") ?? "upsert", o = B(e, "--on-conflict") ?? "skip";
|
|
640
652
|
if (t) {
|
|
641
|
-
let t =
|
|
653
|
+
let t = B(e, "--api-url");
|
|
642
654
|
if (!t) return I.error("--target api requires --api-url <url> (the running instance)"), 1;
|
|
643
|
-
let r =
|
|
655
|
+
let r = B(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
|
|
644
656
|
if (!r) return I.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
|
|
645
|
-
let s =
|
|
657
|
+
let s = B(e, "--tables"), c = B(e, "--rollback-key");
|
|
646
658
|
a === "replace" && c === void 0 && I.warn("api replace: no rollback capture — this run empties the target first and nothing was asked to be kept.\n Pass --rollback-key <storage-key> and the INSTANCE stores the target's current rows in its own\n object storage before deleting them, which is the one place that survives the pod going away.");
|
|
647
659
|
let l = {
|
|
648
660
|
authorization: `Bearer ${r}`,
|
|
649
661
|
"x-import-mode": a,
|
|
650
662
|
"x-import-on-conflict": o,
|
|
651
|
-
...
|
|
663
|
+
...Z(e, a) ? { "x-import-atomic": "1" } : {},
|
|
652
664
|
...e.includes("--no-atomic") ? { "x-import-atomic": "0" } : {},
|
|
653
665
|
...c === void 0 ? {} : { "x-import-rollback-key": c },
|
|
654
666
|
...e.includes("--force") ? { "x-import-force": "1" } : {},
|
|
@@ -656,14 +668,26 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
656
668
|
...s ? { "x-import-tables": s } : {}
|
|
657
669
|
}, { resolve: u } = await import("node:path"), d;
|
|
658
670
|
if (n) l["content-type"] = "application/json", d = JSON.stringify({ bundleKey: n });
|
|
659
|
-
else if (
|
|
660
|
-
let t =
|
|
671
|
+
else if (q(i)) {
|
|
672
|
+
let t = Y(u(process.cwd(), i)), n = J(e);
|
|
661
673
|
n && (t = w(t, n)), l["content-type"] = "application/octet-stream", d = t;
|
|
662
|
-
} else await (await import("node:fs/promises")).access(u(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."), l["content-type"] = "application/octet-stream", d =
|
|
663
|
-
a === "replace"
|
|
674
|
+
} else await (await import("node:fs/promises")).access(u(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."), l["content-type"] = "application/octet-stream", d = ue({ dir: u(process.cwd(), i) });
|
|
675
|
+
if (a === "replace") {
|
|
676
|
+
let r = await Le(i, n);
|
|
677
|
+
{
|
|
678
|
+
let i = r === null ? { bundleKey: n } : { tables: r }, a = await N(`${t.replace(/\/+$/, "")}/_voltro/admin/import`, JSON.stringify(i), {
|
|
679
|
+
...l,
|
|
680
|
+
"content-type": "application/json",
|
|
681
|
+
"x-import-preflight": "1"
|
|
682
|
+
}, Q(e)).catch(() => null), o = a !== null && a.status === 200 ? JSON.parse(a.body.toString("utf8")) : null;
|
|
683
|
+
o === null ? I.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 ? I.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.`) : I.warn(`api replace: the instance will NOT stage — it empties the target first and refills it, so an
|
|
684
|
+
interrupted run leaves the target empty.\n Reason: ${o.reason ?? "not stated"}`);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
a === "replace" && !Z(e, a) && I.warn(We(!0));
|
|
664
688
|
let f = `${t.replace(/\/+$/, "")}/_voltro/admin/import`, p;
|
|
665
689
|
try {
|
|
666
|
-
let t = typeof d == "string" ? null : await
|
|
690
|
+
let t = typeof d == "string" ? null : await Ue({
|
|
667
691
|
stream: d,
|
|
668
692
|
url: f,
|
|
669
693
|
headers: l,
|
|
@@ -671,51 +695,53 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
671
695
|
args: e,
|
|
672
696
|
log: I
|
|
673
697
|
});
|
|
674
|
-
(t === null || t.kind === "small") && I.info("api import: uploading the bundle — this request stays open until the instance has imported it"), p = t === null ? await
|
|
698
|
+
(t === null || t.kind === "small") && I.info("api import: uploading the bundle — this request stays open until the instance has imported it"), p = t === null ? await N(f, d, l, Q(e)) : t.kind === "sent" ? t.res : await N(f, t.body, l, Q(e));
|
|
675
699
|
} catch (e) {
|
|
676
|
-
if (e instanceof
|
|
677
|
-
if (e instanceof
|
|
700
|
+
if (e instanceof M) return I.error(`api import: ${xe(e, a)}`), 1;
|
|
701
|
+
if (e instanceof j) return I.error(`api import: ${be(e)}`), 1;
|
|
678
702
|
throw e;
|
|
679
703
|
}
|
|
680
|
-
if (p.status < 200 || p.status >= 300) return
|
|
704
|
+
if (p.status < 200 || p.status >= 300) return $e(et(p.body)) || I.error(`api import failed: HTTP ${p.status} — ${p.body.toString("utf8")}`), 1;
|
|
681
705
|
let m = JSON.parse(p.body.toString("utf8"));
|
|
682
706
|
return e.includes("--dry-run") ? (I.info("api import DRY RUN — nothing was written", {
|
|
683
707
|
via: t,
|
|
684
708
|
...m
|
|
685
|
-
}), I.info(
|
|
709
|
+
}), I.info(Je()), 0) : (I.info("api import complete (imported by the running instance)", {
|
|
686
710
|
via: t,
|
|
687
711
|
...m
|
|
688
712
|
}), 0);
|
|
689
713
|
}
|
|
690
714
|
if (!i) return I.error("a <bundleDir> is required for a direct import"), 1;
|
|
691
|
-
if (!await
|
|
692
|
-
a === "replace" && e.includes("--allow-live") && !
|
|
693
|
-
let { store: s, snapshot: c } = await
|
|
694
|
-
|
|
715
|
+
if (!await z(e)) return 1;
|
|
716
|
+
a === "replace" && e.includes("--allow-live") && !Z(e, a) && I.warn(We(!1));
|
|
717
|
+
let { store: s, snapshot: c } = await G();
|
|
718
|
+
c.tables.some((e) => e.name === m) || I.warn(`this target has no \`${m}\` table, so this import will not be recorded.\n The import itself is unaffected. \`voltro db apply\` creates it.`), c.tables.some((e) => e.name === m) || I.warn(`this target has no \`${m}\` table, so this import will not be recorded.\n The import itself is unaffected. \`voltro db apply\` creates it.`);
|
|
719
|
+
let l = e.includes("--force"), u = (e) => I.warn(e), d = e.includes("--assets") ? S({}) : void 0, f = H() === "postgres" ? (await import("@voltro/sql-postgres")).makePgCopySession(r()) : void 0;
|
|
720
|
+
if (q(i)) {
|
|
695
721
|
let t = await import("node:os"), n = await import("node:fs/promises"), { resolve: r, join: p } = await import("node:path"), m = await n.mkdtemp(p(t.tmpdir(), "voltro-import-"));
|
|
696
722
|
try {
|
|
697
|
-
let t =
|
|
723
|
+
let t = Y(r(process.cwd(), i)), n = J(e);
|
|
698
724
|
return n && (t = w(t, n)), await ge(t, {
|
|
699
725
|
dir: m,
|
|
700
726
|
blobs: me(d ?? S({}))
|
|
701
|
-
}),
|
|
727
|
+
}), Ze(e, {
|
|
702
728
|
file: i,
|
|
703
|
-
...
|
|
729
|
+
...Xe(await y.runPromise(O({
|
|
704
730
|
store: s,
|
|
705
731
|
bundleDir: m,
|
|
706
732
|
mode: a,
|
|
707
733
|
onConflict: o,
|
|
708
|
-
atomic:
|
|
709
|
-
...
|
|
734
|
+
atomic: Z(e, a),
|
|
735
|
+
...Ke(e, a, i),
|
|
710
736
|
verify: !e.includes("--no-verify"),
|
|
711
|
-
targetDialect:
|
|
737
|
+
targetDialect: H(),
|
|
712
738
|
allowIncompatible: l,
|
|
713
739
|
targetSnapshot: c,
|
|
714
740
|
force: l,
|
|
715
741
|
onWarn: u,
|
|
716
742
|
onProgress: R,
|
|
717
743
|
assetsAlreadyRestored: !0,
|
|
718
|
-
...
|
|
744
|
+
...Ye(e),
|
|
719
745
|
...f ? { copyLoader: f } : {}
|
|
720
746
|
})))
|
|
721
747
|
}), 0;
|
|
@@ -726,33 +752,33 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
726
752
|
});
|
|
727
753
|
}
|
|
728
754
|
}
|
|
729
|
-
let p = await
|
|
730
|
-
...
|
|
755
|
+
let p = await y.runPromise(O({
|
|
756
|
+
...Ke(e, a, i),
|
|
731
757
|
store: s,
|
|
732
758
|
bundleDir: i,
|
|
733
759
|
mode: a,
|
|
734
760
|
onConflict: o,
|
|
735
|
-
atomic:
|
|
761
|
+
atomic: Z(e, a),
|
|
736
762
|
verify: !e.includes("--no-verify"),
|
|
737
|
-
targetDialect:
|
|
763
|
+
targetDialect: H(),
|
|
738
764
|
allowIncompatible: l,
|
|
739
765
|
targetSnapshot: c,
|
|
740
766
|
force: l,
|
|
741
767
|
onWarn: u,
|
|
742
768
|
onProgress: R,
|
|
743
|
-
...
|
|
769
|
+
...Ye(e),
|
|
744
770
|
...d ? { assets: fe(d) } : {},
|
|
745
771
|
...f ? { copyLoader: f } : {}
|
|
746
772
|
})).catch((e) => {
|
|
747
|
-
if (
|
|
773
|
+
if ($e(e)) return Qe;
|
|
748
774
|
throw e;
|
|
749
775
|
}).finally(() => f?.close());
|
|
750
|
-
return typeof p == "symbol" ? 1 : (
|
|
776
|
+
return typeof p == "symbol" ? 1 : (Ze(e, {
|
|
751
777
|
bundleDir: i,
|
|
752
|
-
...
|
|
778
|
+
...Xe(p),
|
|
753
779
|
assets: p.manifest.assets.count
|
|
754
780
|
}), 0);
|
|
755
|
-
},
|
|
781
|
+
}, nt = () => {
|
|
756
782
|
let e = r();
|
|
757
783
|
return {
|
|
758
784
|
...e.url ? { url: e.url } : {},
|
|
@@ -762,60 +788,60 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
762
788
|
...e.password ? { password: e.password } : {},
|
|
763
789
|
...e.database ? { database: e.database } : {}
|
|
764
790
|
};
|
|
765
|
-
},
|
|
766
|
-
let t =
|
|
791
|
+
}, rt = async (e) => {
|
|
792
|
+
let t = V(e);
|
|
767
793
|
if (!t) return I.error("usage: voltro data backup <outDir> (native pg_dump/mysqldump/… + consistent artifact)"), 1;
|
|
768
|
-
let n =
|
|
794
|
+
let n = H(), { mkdir: r, writeFile: i } = await import("node:fs/promises"), { join: a } = await import("node:path");
|
|
769
795
|
await r(t, { recursive: !0 });
|
|
770
796
|
let o = a(t, C(n));
|
|
771
|
-
await
|
|
797
|
+
await y.runPromise(k(se(n, nt(), o)));
|
|
772
798
|
let s = Ee({
|
|
773
799
|
dialect: n,
|
|
774
800
|
schemaFingerprint: await L(n),
|
|
775
|
-
voltroVersion: await
|
|
801
|
+
voltroVersion: await je(),
|
|
776
802
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
777
803
|
});
|
|
778
|
-
return await i(a(t,
|
|
804
|
+
return await i(a(t, P), `${JSON.stringify(s, null, 2)}\n`, "utf8"), I.info("native backup complete", {
|
|
779
805
|
dialect: n,
|
|
780
806
|
artifact: o,
|
|
781
|
-
stamp:
|
|
807
|
+
stamp: P,
|
|
782
808
|
schemaFingerprint: s.schemaFingerprint ?? "<none>",
|
|
783
809
|
assets: "NOT included — use `voltro data export --assets` for rows + blobs"
|
|
784
810
|
}), 0;
|
|
785
|
-
},
|
|
786
|
-
let n =
|
|
787
|
-
flagUrl:
|
|
811
|
+
}, it = async (e, t) => {
|
|
812
|
+
let n = H(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(e, C(n)), o = ke({
|
|
813
|
+
flagUrl: B(t, "--drill-url"),
|
|
788
814
|
envUrl: process.env.DRILL_DB_URL,
|
|
789
815
|
liveKeys: Pe()
|
|
790
816
|
});
|
|
791
817
|
if (!o.ok) return I.error(`restore --drill: ${o.error}`), 1;
|
|
792
|
-
let s = await i(r(e,
|
|
818
|
+
let s = await i(r(e, P), "utf8").then(De, () => null);
|
|
793
819
|
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;
|
|
794
820
|
I.info("restore drill: restoring into throwaway DB", {
|
|
795
821
|
dialect: n,
|
|
796
822
|
target: F(o.url)
|
|
797
|
-
}), await
|
|
823
|
+
}), await y.runPromise(k(E(n, { url: o.url }, a)));
|
|
798
824
|
let c = null, l = 0;
|
|
799
825
|
try {
|
|
800
|
-
let e = await
|
|
801
|
-
c =
|
|
826
|
+
let e = await U(n, { url: o.url });
|
|
827
|
+
c = te(e), l = e.tables.length;
|
|
802
828
|
} catch (e) {
|
|
803
829
|
return I.error(`restore --drill: could not introspect the restored DB — ${String(e)}`), 1;
|
|
804
830
|
}
|
|
805
|
-
let u =
|
|
831
|
+
let u = Ae({
|
|
806
832
|
stampFingerprint: s?.schemaFingerprint ?? null,
|
|
807
833
|
restoredFingerprint: c,
|
|
808
834
|
restoredTableCount: l
|
|
809
835
|
});
|
|
810
836
|
for (let e of u.lines) u.pass ? I.info(`restore drill: ${e}`) : I.error(`restore drill: ${e}`);
|
|
811
837
|
return +!u.pass;
|
|
812
|
-
},
|
|
813
|
-
let t =
|
|
838
|
+
}, at = async (e) => {
|
|
839
|
+
let t = V(e);
|
|
814
840
|
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;
|
|
815
|
-
if (e.includes("--drill")) return
|
|
816
|
-
if (!await
|
|
817
|
-
let n =
|
|
818
|
-
stamp: await i(r(t,
|
|
841
|
+
if (e.includes("--drill")) return it(t, e);
|
|
842
|
+
if (!await z(e)) return 1;
|
|
843
|
+
let n = H(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(t, C(n)), o = Oe({
|
|
844
|
+
stamp: await i(r(t, P), "utf8").then(De, () => null),
|
|
819
845
|
currentDialect: n,
|
|
820
846
|
currentFingerprint: await L(n)
|
|
821
847
|
});
|
|
@@ -824,12 +850,12 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
824
850
|
if (!e.includes("--force")) return I.error(`restore refused: ${o.refuse} (pass --force to override)`), 1;
|
|
825
851
|
I.warn(`restore proceeding despite: ${o.refuse} (--force)`);
|
|
826
852
|
}
|
|
827
|
-
return await
|
|
853
|
+
return await y.runPromise(k(E(n, nt(), a))), I.info("native restore complete", {
|
|
828
854
|
dialect: n,
|
|
829
855
|
artifact: a
|
|
830
856
|
}), 0;
|
|
831
|
-
},
|
|
832
|
-
let t =
|
|
857
|
+
}, ot = async (e) => {
|
|
858
|
+
let t = V(e);
|
|
833
859
|
if (!t) return I.error("usage: voltro data inspect <file.vbundle|dir> [--json] [--passphrase <p>]"), 1;
|
|
834
860
|
let { resolve: n, join: r } = await import("node:path"), i = await import("node:fs/promises"), a = n(process.cwd(), t);
|
|
835
861
|
if ((await i.stat(a).catch(() => void 0))?.isDirectory()) {
|
|
@@ -841,8 +867,8 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
841
867
|
let s = await i.readFile(n, "utf8").catch(() => void 0);
|
|
842
868
|
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);
|
|
843
869
|
}
|
|
844
|
-
let o =
|
|
845
|
-
let e =
|
|
870
|
+
let o = J(e), s = () => {
|
|
871
|
+
let e = Y(a);
|
|
846
872
|
return o ? w(e, o) : e;
|
|
847
873
|
};
|
|
848
874
|
if (e.includes("--json")) {
|
|
@@ -853,8 +879,8 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
853
879
|
if (c) return console.log(c.toString("utf8")), 0;
|
|
854
880
|
let l = (await T(s(), ["manifest.json"])).get("manifest.json");
|
|
855
881
|
return l ? (console.log(l.toString("utf8")), 0) : (I.error("bundle has no README.md or manifest.json"), 1);
|
|
856
|
-
},
|
|
857
|
-
let { REPLACE_IN_PROGRESS_TABLE: t } = await import("@voltro/database"), { interruptedReplaceAtBoot: n } = await import("./interruptedReplace-DNJ7MKph.js"), { store: r } = await
|
|
882
|
+
}, st = async (e) => {
|
|
883
|
+
let { REPLACE_IN_PROGRESS_TABLE: t } = await import("@voltro/database"), { interruptedReplaceAtBoot: n } = await import("./interruptedReplace-DNJ7MKph.js"), { store: r } = await G(), i = await n(r);
|
|
858
884
|
if (i === void 0) return I.info("no interrupted replace is recorded — nothing to clear"), 0;
|
|
859
885
|
if (!e.includes("--yes")) return I.error(`${i}\n\n Re-run with --yes to clear it.`), 1;
|
|
860
886
|
let a = await r.query({
|
|
@@ -867,16 +893,59 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
867
893
|
});
|
|
868
894
|
for (let e of a) await r.delete(t, String(e.id));
|
|
869
895
|
return I.info(`cleared ${a.length} interrupted-replace marker(s) — the next boot will start`), 0;
|
|
870
|
-
},
|
|
871
|
-
let { STAGING_PREFIX: t, dropStagingSql: n, execStatements: r } = await import("@voltro/data-transfer"), { store: i } = await
|
|
896
|
+
}, ct = async (e) => {
|
|
897
|
+
let { STAGING_PREFIX: t, dropStagingSql: n, execStatements: r } = await import("@voltro/data-transfer"), { store: i } = await G(), a = H();
|
|
872
898
|
if (a !== "postgres" && a !== "mysql" && a !== "mariadb" && a !== "sqlite" && a !== "mssql") return I.error(`this store has no staging tables to clear (dialect: ${a})`), 1;
|
|
873
899
|
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));
|
|
874
900
|
return s.length === 0 ? (I.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))), I.info(`dropped ${s.length} staging table(s)`), 0) : (I.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);
|
|
875
|
-
},
|
|
876
|
-
let t =
|
|
901
|
+
}, lt = async (e) => {
|
|
902
|
+
let { describeImportRun: t, IMPORT_RUNS_TABLE: n } = await import("@voltro/database"), r = Number(B(e, "--limit") ?? "20"), i = Number.isFinite(r) ? Math.max(1, Math.min(200, Math.trunc(r))) : 20;
|
|
903
|
+
if (B(e, "--target") === "api") {
|
|
904
|
+
let t = B(e, "--api-url");
|
|
905
|
+
if (!t) return I.error("--target api requires --api-url <url> (the running instance)"), 1;
|
|
906
|
+
let n = B(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
|
|
907
|
+
if (!n) return I.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET)"), 1;
|
|
908
|
+
let r = await fetch(`${t.replace(/\/+$/, "")}/_voltro/admin/imports?limit=${i}`, { headers: { authorization: `Bearer ${n}` } }), a = await r.text();
|
|
909
|
+
if (r.status !== 200) return I.error(`api imports: ${r.status} ${a}`), 1;
|
|
910
|
+
let o = JSON.parse(a);
|
|
911
|
+
if (e.includes("--json")) return console.log(a), 0;
|
|
912
|
+
let s = o.runs ?? [];
|
|
913
|
+
if (s.length === 0) return I.info("no imports recorded on this instance"), 0;
|
|
914
|
+
(o.running ?? 0) > 0 && I.info(`${o.running} import(s) IN FLIGHT — re-run this to watch the counters move`);
|
|
915
|
+
for (let e of s) I.info(` ${e.line ?? ""}`);
|
|
916
|
+
return 0;
|
|
917
|
+
}
|
|
918
|
+
let { store: a } = await G(), o;
|
|
919
|
+
try {
|
|
920
|
+
o = await a.query({
|
|
921
|
+
table: n,
|
|
922
|
+
order: [{
|
|
923
|
+
column: "startedAt",
|
|
924
|
+
direction: "desc"
|
|
925
|
+
}],
|
|
926
|
+
predicate: void 0,
|
|
927
|
+
projection: void 0,
|
|
928
|
+
skip: 0,
|
|
929
|
+
take: i
|
|
930
|
+
});
|
|
931
|
+
} catch {
|
|
932
|
+
return I.error(`this target has no \`${n}\` table, so no import has been recorded here.\n Run \`voltro db apply\`; imports themselves are unaffected by its absence.`), 1;
|
|
933
|
+
}
|
|
934
|
+
if (o.length === 0) return I.info("no imports recorded against this target"), 0;
|
|
935
|
+
for (let e of o) {
|
|
936
|
+
let n = e;
|
|
937
|
+
I.info(` ${t({
|
|
938
|
+
...e,
|
|
939
|
+
startedAt: new Date(n.startedAt),
|
|
940
|
+
finishedAt: n.finishedAt === null ? null : new Date(n.finishedAt)
|
|
941
|
+
})}`);
|
|
942
|
+
}
|
|
943
|
+
return 0;
|
|
944
|
+
}, ut = async (e) => {
|
|
945
|
+
let t = V(e), n = V(e.filter((e) => e !== t));
|
|
877
946
|
if (!t || !n) return I.error("usage: voltro data unpack <file.vbundle> <dir> [--passphrase <p>]"), 1;
|
|
878
|
-
let { resolve: r } = await import("node:path"), i =
|
|
879
|
-
return a && (i = w(i, a)), await
|
|
947
|
+
let { resolve: r } = await import("node:path"), i = Y(r(process.cwd(), t)), a = J(e);
|
|
948
|
+
return a && (i = w(i, a)), await A(i, r(process.cwd(), n)), I.info("unpack complete", {
|
|
880
949
|
file: t,
|
|
881
950
|
dir: n
|
|
882
951
|
}), 0;
|
|
@@ -885,6 +954,7 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
885
954
|
common: [
|
|
886
955
|
"--target",
|
|
887
956
|
"--tables",
|
|
957
|
+
"--exclude",
|
|
888
958
|
"--profile",
|
|
889
959
|
"--tenant",
|
|
890
960
|
"--assets",
|
|
@@ -893,7 +963,6 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
893
963
|
"--json"
|
|
894
964
|
],
|
|
895
965
|
directOnly: [
|
|
896
|
-
"--exclude",
|
|
897
966
|
"--passphrase",
|
|
898
967
|
"--dry-run",
|
|
899
968
|
"--encrypt"
|
|
@@ -906,6 +975,14 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
906
975
|
]
|
|
907
976
|
},
|
|
908
977
|
"clear-staging": { common: ["--yes"] },
|
|
978
|
+
imports: {
|
|
979
|
+
common: [
|
|
980
|
+
"--target",
|
|
981
|
+
"--limit",
|
|
982
|
+
"--json"
|
|
983
|
+
],
|
|
984
|
+
apiOnly: ["--api-url", "--token"]
|
|
985
|
+
},
|
|
909
986
|
"clear-replace-marker": { common: ["--yes"] },
|
|
910
987
|
import: {
|
|
911
988
|
common: [
|
|
@@ -947,13 +1024,13 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
947
1024
|
"--drill-url",
|
|
948
1025
|
"--api-url"
|
|
949
1026
|
] }
|
|
950
|
-
},
|
|
1027
|
+
}, dt = (e) => e.split("=")[0], ft = (e, t) => {
|
|
951
1028
|
let n = $[e];
|
|
952
1029
|
if (!n) return;
|
|
953
|
-
let r =
|
|
1030
|
+
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 ?? []);
|
|
954
1031
|
for (let n of t) {
|
|
955
1032
|
if (!n.startsWith("--")) continue;
|
|
956
|
-
let t =
|
|
1033
|
+
let t = dt(n);
|
|
957
1034
|
if (i.has(t)) continue;
|
|
958
1035
|
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.`;
|
|
959
1036
|
let o = Object.entries($).filter(([n, r]) => n !== e && [
|
|
@@ -963,13 +1040,13 @@ var ye = /* @__PURE__ */ new Set([
|
|
|
963
1040
|
].includes(t)).map(([e]) => e);
|
|
964
1041
|
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.`;
|
|
965
1042
|
}
|
|
966
|
-
},
|
|
1043
|
+
}, pt = async (e) => {
|
|
967
1044
|
let [t, ...n] = e;
|
|
968
1045
|
if (t !== void 0 && $[t] !== void 0) {
|
|
969
|
-
let e =
|
|
1046
|
+
let e = ft(t, n);
|
|
970
1047
|
if (e) return I.error(e), 2;
|
|
971
1048
|
}
|
|
972
|
-
return t === "export" ?
|
|
1049
|
+
return t === "export" ? qe(n) : t === "import" ? tt(n) : t === "unpack" ? ut(n) : t === "inspect" ? ot(n) : t === "backup" ? rt(n) : t === "restore" ? at(n) : t === "clear-replace-marker" ? st(n) : t === "clear-staging" ? ct(n) : t === "imports" ? lt(n) : (I.error("usage: voltro data <export|import|imports|unpack|inspect|backup|restore|clear-replace-marker|clear-staging> … (logical: export/import; native: backup/restore; `imports` reads the history, incl. a run in flight)"), t ? 2 : 1);
|
|
973
1050
|
};
|
|
974
1051
|
//#endregion
|
|
975
|
-
export {
|
|
1052
|
+
export { pt as runDataCommand };
|