@voltro/cli 0.44.1 → 0.46.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 +280 -1
- package/dist/{apiBuild-DvWreIQP.js → apiBuild-BKdd0I1Z.js} +2 -2
- package/dist/apiBuild-P2gewrfQ.js +2 -0
- package/dist/bin.d.ts +24 -0
- package/dist/bin.js +46 -11
- package/dist/{build-Ckc-FA7d.js → build-co6yadYz.js} +8 -8
- package/dist/{checkCommand-BNfEs4KG.js → checkCommand-B-eiW-G_.js} +12 -12
- package/dist/{checkCommand-AlbawIal.js → checkCommand-CXAXTjZL.js} +1 -1
- package/dist/codegen-DcE2li1i.js +2 -0
- package/dist/{codegen-CbpGCWLG.js → codegen-sbN1Y8PB.js} +37 -37
- package/dist/codegenCommand-CB6_3sX0.js +144 -0
- package/dist/{codemodRunner-BKTnaGOz.js → codemodRunner-DSZjgyCL.js} +49 -0
- package/dist/{commands-CYkHTox2.js → commands-C-hxgAGr.js} +24 -24
- package/dist/{dashboardCommand-DHDmlo9A.js → dashboardCommand-CEVO0GWF.js} +3 -3
- package/dist/{dataCommand-WFn8CM11.js → dataCommand-k0ezbQWa.js} +355 -250
- package/dist/{dbCommand-B237qI-j.js → dbCommand-BwkyNxn-.js} +110 -110
- package/dist/dbCommand-C2XK63Dd.js +2 -0
- package/dist/{dev-D-JZ6CGQ.js → dev-8hTEnN6s.js} +2154 -2076
- package/dist/{dev-BZO5aLdr.js → dev-DyoYst4j.js} +1 -1
- package/dist/devActivity.d.ts +24 -0
- package/dist/{doctorCommand-BlUyESpD.js → doctorCommand-B6D7HH1-.js} +249 -228
- package/dist/doctorCommand-Btl2Jz1a.js +2 -0
- package/dist/doctorSourceRelations-CPjSwYuZ.js +83 -0
- package/dist/{dormancyCommand-lQxdrU8C.js → dormancyCommand-CrPAwOgo.js} +1 -1
- package/dist/{embeddingsCommand-ByBTju6X.js → embeddingsCommand-DsSxsn_b.js} +1 -1
- package/dist/{envCommand-CpCbYAgR.js → envCommand-B_NPVGUf.js} +2 -2
- package/dist/{evalCommand-6RUfPen4.js → evalCommand-Db01Kbng.js} +24 -24
- package/dist/{evolveCommand-CBV3-TtK.js → evolveCommand-DUuaCIyn.js} +2 -2
- package/dist/{frameworkTableAssembly-oMPBKqlE.js → frameworkTableAssembly-BPlPfU07.js} +82 -78
- package/dist/frameworkTableAssembly-Bob3vj9R.js +2 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +1 -1
- package/dist/{infoCommand-DJoA9cKD.js → infoCommand-CuNl9cbh.js} +1 -1
- package/dist/inspectState.d.ts +24 -0
- package/dist/interruptedReplace-C1ZI84xi.js +27 -0
- package/dist/interruptedReplace-DNJ7MKph.js +2 -0
- package/dist/{migrate-DN47p2PG.js → migrate-CM1qwalu.js} +27 -27
- package/dist/{runtimeTrace-DJ9tPhrc.js → runtimeTrace-BRNM06vK.js} +1 -1
- package/dist/{sdkgen-7dr8-Onw.js → sdkgen-CRCw_XcR.js} +1 -1
- package/dist/{seedRunner-IdHEprqf.js → seedRunner-Dgsiwk_e.js} +59 -59
- package/dist/serveCommand-BNHMVXyp.js +2 -0
- package/dist/serveCommand-CHOr74WM.js +1928 -0
- package/dist/serveEntry.d.ts +24 -0
- package/dist/serveEntry.js +1 -1
- package/dist/{start-Ds3xyn8R.js → start-7HcSIKEp.js} +1 -1
- package/dist/{start-BAlGcjF5.js → start-DvlYDyAr.js} +1 -1
- package/dist/startEntry.d.ts +24 -0
- package/dist/startEntry.js +1 -1
- package/dist/startup.d.ts +24 -0
- package/dist/{test-CLYXrZ2F.js → test-CHb7UwvE.js} +1 -1
- package/dist/{updateCommand-BvRidHp6.js → updateCommand-BlyXavoG.js} +1 -1
- package/dist/updateCommand-CT5AvVg7.js +2 -0
- package/dist/{webDev-101csg6Q.js → webDev-B4IEMB0n.js} +6 -6
- package/dist/webDev-B79ji8M5.js +2 -0
- package/dist/{webhooksCommand-BfO_JF2b.js → webhooksCommand-BRrG_sGf.js} +1 -1
- package/package.json +29 -17
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/cli.md +179 -3
- package/templates/agent-docs/data.md +103 -7
- package/templates/agent-docs/plugins/versioning.md +2 -0
- package/templates/agent-docs/whats-new.md +166 -6
- 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-XaW40W8x.js +0 -2
- package/dist/codegen-i8QGcHsi.js +0 -2
- package/dist/codegenCommand-iClXoRCW.js +0 -129
- package/dist/dbCommand-BvQeKQOb.js +0 -2
- package/dist/doctorCommand-BeLOwq7S.js +0 -2
- package/dist/frameworkTableAssembly-DgylYh9_.js +0 -2
- package/dist/serveCommand-BlnAlNQg.js +0 -1891
- package/dist/serveCommand-Dg_E1ev4.js +0 -2
- package/dist/updateCommand-DcKVmLVN.js +0 -2
- package/dist/webDev-BLKBO34K.js +0 -2
|
@@ -1,29 +1,51 @@
|
|
|
1
1
|
import { t as e } from "./cliError-BmdYnghb.js";
|
|
2
|
-
import { c as t, i as n, o as r } from "./dev-
|
|
3
|
-
import { n as
|
|
4
|
-
import { r as
|
|
5
|
-
import { t as
|
|
6
|
-
import { o as
|
|
7
|
-
import { r as
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import { request as
|
|
2
|
+
import { c as t, i as n, o as r, z as i } from "./dev-8hTEnN6s.js";
|
|
3
|
+
import { n as a, t as o } from "./cliArgs-D4p8n7EE.js";
|
|
4
|
+
import { r as s } from "./dialectDriver-czCHYpeH.js";
|
|
5
|
+
import { t as c } from "./dataProfile-Cm0YVKSy.js";
|
|
6
|
+
import { o as l, t as u } from "./inspectFetch-EMuhTG_9.js";
|
|
7
|
+
import { r as d } from "./dbCommand-BwkyNxn-.js";
|
|
8
|
+
import { resolve as f } from "node:path";
|
|
9
|
+
import { createLogger as p } from "@voltro/logger";
|
|
10
|
+
import { connectionIdentity as m, normaliseTarget as h, sameDatabase as g, streamTable as _ } from "@voltro/database";
|
|
11
|
+
import { Effect as v, Stream as y } from "effect";
|
|
12
|
+
import { SqlClient as b } from "@effect/sql";
|
|
13
|
+
import { declaredSnapshot as x, fingerprintSchema as ee, introspectSchema as te } from "@voltro/database/sql";
|
|
14
|
+
import { STORAGE_REFS_TABLE as ne, resolveStorageProvider as S } from "@voltro/plugin-storage";
|
|
15
|
+
import { createHash as re } from "node:crypto";
|
|
16
|
+
import { asImportError as ie, assessLiveImport as ae, backupArtifactName as C, backupCommand as oe, classificationFromSnapshot as se, decryptStream as w, encryptStream as ce, packBundle as le, peekBundle as T, previewMasking as ue, restoreCommand as de, runExport as E, runImport as D, runNativeStep as O, storageAssetSink as fe, storageAssetSource as pe, storageBlobSink as me, storageBlobSource as he, unpackBundle as ge, unpackBundleToDir as k } from "@voltro/data-transfer";
|
|
17
|
+
import { request as _e } from "node:http";
|
|
18
|
+
import { request as ve } from "node:https";
|
|
18
19
|
//#region src/longRequest.ts
|
|
19
|
-
var
|
|
20
|
+
var ye = /* @__PURE__ */ new Set([
|
|
21
|
+
"ECONNREFUSED",
|
|
22
|
+
"ETIMEDOUT",
|
|
23
|
+
"EHOSTUNREACH",
|
|
24
|
+
"ENETUNREACH",
|
|
25
|
+
"ENOTFOUND",
|
|
26
|
+
"ECONNRESET",
|
|
27
|
+
"EAI_AGAIN"
|
|
28
|
+
]), A = class extends Error {
|
|
29
|
+
url;
|
|
30
|
+
cause;
|
|
31
|
+
constructor(e, t) {
|
|
32
|
+
let n = (() => {
|
|
33
|
+
try {
|
|
34
|
+
return new URL(e).host;
|
|
35
|
+
} catch {
|
|
36
|
+
return e;
|
|
37
|
+
}
|
|
38
|
+
})();
|
|
39
|
+
super(`the instance at ${n} is not answering (${t.code ?? "connect failed"}).`), this.url = e, this.cause = t, this.name = "InstanceUnreachable";
|
|
40
|
+
}
|
|
41
|
+
}, j = class extends Error {
|
|
20
42
|
elapsedMs;
|
|
21
43
|
url;
|
|
22
44
|
constructor(e, t) {
|
|
23
45
|
super(`no response after ${Math.round(e / 1e3)}s`), this.elapsedMs = e, this.url = t, this.name = "LongRequestTimeout";
|
|
24
46
|
}
|
|
25
|
-
},
|
|
26
|
-
let i = new URL(e), a = i.protocol === "https:" ?
|
|
47
|
+
}, M = async (e, t, n, r) => {
|
|
48
|
+
let i = new URL(e), a = i.protocol === "https:" ? ve : _e, o = Date.now();
|
|
27
49
|
return await new Promise((s, c) => {
|
|
28
50
|
let l = a({
|
|
29
51
|
protocol: i.protocol,
|
|
@@ -41,8 +63,8 @@ var A = class extends Error {
|
|
|
41
63
|
})), e.on("error", c);
|
|
42
64
|
});
|
|
43
65
|
if (r?.timeoutMs !== void 0 && r.timeoutMs > 0 && l.setTimeout(r.timeoutMs, () => {
|
|
44
|
-
l.destroy(new
|
|
45
|
-
}), l.on("error", c), typeof t == "string" || Buffer.isBuffer(t)) {
|
|
66
|
+
l.destroy(new j(Date.now() - o, e));
|
|
67
|
+
}), l.on("error", (t) => c(ye.has(t.code ?? "") ? new A(e, t) : t)), typeof t == "string" || Buffer.isBuffer(t)) {
|
|
46
68
|
l.end(t);
|
|
47
69
|
return;
|
|
48
70
|
}
|
|
@@ -55,7 +77,7 @@ var A = class extends Error {
|
|
|
55
77
|
}
|
|
56
78
|
})();
|
|
57
79
|
});
|
|
58
|
-
},
|
|
80
|
+
}, be = (e) => `${e.message}\n That address came from --api-url (or VOLTRO_API_URL) — it is the running instance, not the database.\n Nothing was sent, so nothing was imported. Check the instance is up and reachable from here\n (a VPN, an ingress or a stopped deployment are the usual three), e.g. curl -sS ${e.url}/_voltro/inspect/app`, xe = (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.", Se = 16777216, Ce = async function* (e, t) {
|
|
59
81
|
let n = [], r = 0, i = 0, a = function* (e) {
|
|
60
82
|
let t = Buffer.concat(n);
|
|
61
83
|
n = [], r = 0;
|
|
@@ -77,12 +99,12 @@ var A = class extends Error {
|
|
|
77
99
|
i += a.byteLength, yield s;
|
|
78
100
|
}
|
|
79
101
|
yield* a(!0);
|
|
80
|
-
},
|
|
102
|
+
}, we = (e) => re("sha256").update(Buffer.from(e)).digest("hex"), Te = async (e) => {
|
|
81
103
|
let t = 0, n = 0, r = {
|
|
82
104
|
status: 0,
|
|
83
105
|
body: {}
|
|
84
106
|
};
|
|
85
|
-
for await (let i of
|
|
107
|
+
for await (let i of Ce(e.stream, e.chunkBytes)) {
|
|
86
108
|
if (i.offset + i.bytes.byteLength <= e.alreadyHeld && !i.final) {
|
|
87
109
|
n++;
|
|
88
110
|
continue;
|
|
@@ -108,13 +130,13 @@ var A = class extends Error {
|
|
|
108
130
|
bytes: t,
|
|
109
131
|
resumedFrom: e.alreadyHeld
|
|
110
132
|
};
|
|
111
|
-
},
|
|
133
|
+
}, N = "voltro-backup-stamp.json", Ee = (e) => ({
|
|
112
134
|
stampVersion: 1,
|
|
113
135
|
dialect: e.dialect,
|
|
114
136
|
schemaFingerprint: e.schemaFingerprint,
|
|
115
137
|
voltroVersion: e.voltroVersion,
|
|
116
138
|
createdAt: e.createdAt
|
|
117
|
-
}),
|
|
139
|
+
}), P = (e) => {
|
|
118
140
|
let t;
|
|
119
141
|
try {
|
|
120
142
|
t = JSON.parse(e);
|
|
@@ -132,10 +154,10 @@ var A = class extends Error {
|
|
|
132
154
|
voltroVersion: n.voltroVersion,
|
|
133
155
|
createdAt: n.createdAt
|
|
134
156
|
};
|
|
135
|
-
},
|
|
157
|
+
}, De = (e) => {
|
|
136
158
|
let { stamp: t, currentDialect: n, currentFingerprint: r } = e;
|
|
137
159
|
if (t === null) return {
|
|
138
|
-
warn: `no ${
|
|
160
|
+
warn: `no ${N} beside the dump — an older/handmade backup. Cannot verify dialect or schema version; make sure this dump is a ${n} dump.`,
|
|
139
161
|
info: []
|
|
140
162
|
};
|
|
141
163
|
let i = [`backup produced by @voltro/cli ${t.voltroVersion} at ${t.createdAt}`, `schema fingerprint: ${t.schemaFingerprint ?? "<none recorded>"}`];
|
|
@@ -146,20 +168,20 @@ var A = class extends Error {
|
|
|
146
168
|
refuse: `dialect mismatch — backup is a ${t.dialect} dump, but DB_DIALECT is ${n}. A cross-dialect restore is never valid.`,
|
|
147
169
|
info: i
|
|
148
170
|
};
|
|
149
|
-
},
|
|
171
|
+
}, F = (e) => {
|
|
150
172
|
try {
|
|
151
173
|
let t = new URL(e), n = t.pathname.replace(/^\//, "");
|
|
152
174
|
return `${t.hostname.toLowerCase()}:${t.port || "(default)"}/${n}`;
|
|
153
175
|
} catch {
|
|
154
176
|
return e.trim();
|
|
155
177
|
}
|
|
156
|
-
},
|
|
178
|
+
}, Oe = (e) => {
|
|
157
179
|
let t = e.flagUrl ?? e.envUrl;
|
|
158
180
|
if (t === void 0 || t.trim() === "") return {
|
|
159
181
|
ok: !1,
|
|
160
182
|
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."
|
|
161
183
|
};
|
|
162
|
-
let n =
|
|
184
|
+
let n = F(t);
|
|
163
185
|
return e.liveKeys.some((e) => e === n) ? {
|
|
164
186
|
ok: !1,
|
|
165
187
|
error: `drill target (${n}) is the LIVE database — a restore drill must target a throwaway DB, never production. It would --clean and overwrite it.`
|
|
@@ -167,7 +189,7 @@ var A = class extends Error {
|
|
|
167
189
|
ok: !0,
|
|
168
190
|
url: t
|
|
169
191
|
};
|
|
170
|
-
},
|
|
192
|
+
}, ke = (e) => {
|
|
171
193
|
let { stampFingerprint: t, restoredFingerprint: n, restoredTableCount: r } = e;
|
|
172
194
|
return r === 0 ? {
|
|
173
195
|
pass: !1,
|
|
@@ -182,27 +204,27 @@ var A = class extends Error {
|
|
|
182
204
|
pass: !0,
|
|
183
205
|
lines: [`PASS — restored ${r} table(s); schema fingerprint matches the backup stamp (${n.slice(0, 12)}).`]
|
|
184
206
|
};
|
|
185
|
-
},
|
|
207
|
+
}, I = p({ scope: "voltro:data" }), Ae = async () => {
|
|
186
208
|
try {
|
|
187
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");
|
|
188
210
|
return JSON.parse(n(r, "utf8")).version ?? "unknown";
|
|
189
211
|
} catch {
|
|
190
212
|
return "unknown";
|
|
191
213
|
}
|
|
192
|
-
},
|
|
214
|
+
}, L = async (e) => {
|
|
193
215
|
try {
|
|
194
|
-
return
|
|
216
|
+
return ee(await U(e));
|
|
195
217
|
} catch {
|
|
196
218
|
return null;
|
|
197
219
|
}
|
|
198
|
-
},
|
|
220
|
+
}, R = (e) => {
|
|
199
221
|
if (e.event !== "done") return;
|
|
200
222
|
let t = e.total === void 0 ? "" : ` / ${e.total}`;
|
|
201
|
-
|
|
202
|
-
},
|
|
223
|
+
I.info(`${e.phase} [${e.index + 1}/${e.tableCount}] ${e.table}`, { rows: `${e.rowsDone}${t}` });
|
|
224
|
+
}, je = async (e) => {
|
|
203
225
|
let t = (e) => e?.meta?.databaseId;
|
|
204
226
|
if (e) {
|
|
205
|
-
let n = await
|
|
227
|
+
let n = await u({
|
|
206
228
|
name: "target",
|
|
207
229
|
url: e
|
|
208
230
|
}, "/_voltro/inspect/app");
|
|
@@ -211,29 +233,29 @@ var A = class extends Error {
|
|
|
211
233
|
databaseId: t(n.data)
|
|
212
234
|
};
|
|
213
235
|
}
|
|
214
|
-
for (let e of await
|
|
215
|
-
let n = await
|
|
236
|
+
for (let e of await l()) {
|
|
237
|
+
let n = await u(e, "/_voltro/inspect/app");
|
|
216
238
|
if (n.kind === "ok") return {
|
|
217
239
|
label: `${e.name} (${e.url})`,
|
|
218
240
|
databaseId: t(n.data)
|
|
219
241
|
};
|
|
220
242
|
}
|
|
221
243
|
return null;
|
|
222
|
-
},
|
|
223
|
-
let t = e.includes("--allow-live"), n = t ? null : await
|
|
244
|
+
}, Me = async (e) => {
|
|
245
|
+
let t = e.includes("--allow-live"), n = t ? null : await je(z(e, "--api-url")), i = m({
|
|
224
246
|
dialect: V(),
|
|
225
247
|
...r()
|
|
226
|
-
}), a =
|
|
248
|
+
}), a = h({
|
|
227
249
|
dialect: V(),
|
|
228
250
|
...r()
|
|
229
|
-
}), { refuse: o, message: s } =
|
|
251
|
+
}), { refuse: o, message: s } = ae({
|
|
230
252
|
liveInstance: n?.label ?? null,
|
|
231
253
|
allowLive: t,
|
|
232
|
-
sameTarget:
|
|
254
|
+
sameTarget: g(i, n?.databaseId),
|
|
233
255
|
...a === void 0 ? {} : { targetLabel: `${a.host}:${a.port}/${a.database}` }
|
|
234
256
|
});
|
|
235
|
-
return !o || (
|
|
236
|
-
}, z =
|
|
257
|
+
return !o || (I.error(s ?? "refusing: live instance detected"), !1);
|
|
258
|
+
}, z = a, Ne = [
|
|
237
259
|
"--api-url",
|
|
238
260
|
"--bundle-key",
|
|
239
261
|
"--compression",
|
|
@@ -251,16 +273,16 @@ var A = class extends Error {
|
|
|
251
273
|
"--timeout",
|
|
252
274
|
"--tenant",
|
|
253
275
|
"--token"
|
|
254
|
-
], B = (e) =>
|
|
276
|
+
], B = (e) => o(e, Ne), V = () => {
|
|
255
277
|
let t = (process.env.DB_DIALECT ?? "postgres").toLowerCase();
|
|
256
278
|
if (t === "memory") throw new e("voltro data: requires a real dialect, not DB_DIALECT=memory.");
|
|
257
279
|
return t;
|
|
258
280
|
}, H = async (e, t) => {
|
|
259
|
-
let n = (await
|
|
260
|
-
return
|
|
261
|
-
}, U = (e) => H(e, r()),
|
|
281
|
+
let n = (await s(e)).makeSqlLayer(t);
|
|
282
|
+
return v.runPromise(b.SqlClient.pipe(v.flatMap(te), v.provide(n)));
|
|
283
|
+
}, U = (e) => H(e, r()), Pe = () => {
|
|
262
284
|
let e = r(), t = [];
|
|
263
|
-
return e.url && t.push(
|
|
285
|
+
return e.url && t.push(F(e.url)), (e.host || e.database) && t.push(`${(e.host ?? "localhost").toLowerCase()}:${e.port ?? "(default)"}/${e.database ?? ""}`), t;
|
|
264
286
|
}, W = async () => {
|
|
265
287
|
let r = process.cwd(), i = await t(r);
|
|
266
288
|
if (!i) throw new e("voltro data: no app.config.ts found in the current directory.");
|
|
@@ -270,20 +292,20 @@ var A = class extends Error {
|
|
|
270
292
|
snapshot: await U(o),
|
|
271
293
|
dialect: o
|
|
272
294
|
};
|
|
273
|
-
}, G = (e) =>
|
|
274
|
-
table:
|
|
295
|
+
}, G = (e) => _(e, {
|
|
296
|
+
table: ne,
|
|
275
297
|
chunkSize: 500
|
|
276
|
-
}).pipe(
|
|
298
|
+
}).pipe(y.map((e) => ({
|
|
277
299
|
key: String(e.key),
|
|
278
300
|
contentType: String(e.contentType ?? "application/octet-stream"),
|
|
279
301
|
size: Number(e.size ?? 0)
|
|
280
|
-
}))), K = (e) => !!e && e.endsWith(".vbundle"), q = (e) => z(e, "--passphrase") ?? process.env.VOLTRO_BUNDLE_KEY,
|
|
302
|
+
}))), K = (e) => !!e && e.endsWith(".vbundle"), q = (e) => z(e, "--passphrase") ?? process.env.VOLTRO_BUNDLE_KEY, Fe = (e) => e.includes("--encrypt") || z(e, "--passphrase") !== void 0 || process.env.VOLTRO_BUNDLE_KEY !== void 0, Ie = async (e, t) => {
|
|
281
303
|
let { createWriteStream: n } = await import("node:fs"), { pipeline: r } = await import("node:stream/promises"), { Readable: i } = await import("node:stream");
|
|
282
304
|
await r(i.from(e), n(t));
|
|
283
305
|
}, J = (e) => ({ async *[Symbol.asyncIterator]() {
|
|
284
306
|
let { createReadStream: t } = await import("node:fs");
|
|
285
307
|
for await (let n of t(e)) yield n instanceof Uint8Array ? n : new Uint8Array(n);
|
|
286
|
-
} }), Y = (e) => (e ?? "").split(",").map((e) => e.trim()).filter(Boolean),
|
|
308
|
+
} }), Y = (e) => (e ?? "").split(",").map((e) => e.trim()).filter(Boolean), Le = (t, n) => {
|
|
287
309
|
let r = z(t, "--tenant"), i = z(t, "--tables"), a = z(t, "--exclude");
|
|
288
310
|
if (a !== void 0) {
|
|
289
311
|
if (i !== void 0) throw new e("voltro data export: --exclude and --tables are two ways to say the same thing; use one.");
|
|
@@ -303,13 +325,13 @@ var A = class extends Error {
|
|
|
303
325
|
kind: "tables",
|
|
304
326
|
tables: Y(i)
|
|
305
327
|
} : { kind: "all" };
|
|
306
|
-
},
|
|
307
|
-
let e = await
|
|
308
|
-
return
|
|
309
|
-
},
|
|
310
|
-
let e = (await
|
|
328
|
+
}, Re = async () => {
|
|
329
|
+
let e = await d(process.cwd());
|
|
330
|
+
return se(x(e));
|
|
331
|
+
}, ze = "voltro/tenant", Be = async () => {
|
|
332
|
+
let e = (await d(process.cwd())).filter((e) => (e.appliedMixins ?? []).some((e) => e.id === ze)).map((e) => e.tableName);
|
|
311
333
|
return e.length > 0 ? e : void 0;
|
|
312
|
-
},
|
|
334
|
+
}, Ve = (e) => {
|
|
313
335
|
for (let t of e.tables) if (t.samples.length !== 0) {
|
|
314
336
|
console.log(`\n ${t.table}`);
|
|
315
337
|
for (let e of t.samples) console.log(` ${e.column} [${e.action}] ${JSON.stringify(e.before)} → ${JSON.stringify(e.after)}`);
|
|
@@ -322,8 +344,8 @@ var A = class extends Error {
|
|
|
322
344
|
console.log("\n ✗ unclassified (would BLOCK a real export — add .sensitive()/.safe() or a policy override):");
|
|
323
345
|
for (let t of e.unclassified) console.log(` ${t}`);
|
|
324
346
|
} else console.log("\n ✓ every exported column is classified — safe to run.");
|
|
325
|
-
},
|
|
326
|
-
let { resolve: n, join: r } = await import("node:path"), i = await import("node:fs/promises"), a = z(t.args, "--chunk-size"), o = a === void 0 ?
|
|
347
|
+
}, He = async (t) => {
|
|
348
|
+
let { resolve: n, join: r } = await import("node:path"), i = await import("node:fs/promises"), a = z(t.args, "--chunk-size"), o = a === void 0 ? Se : Math.round(Number(a) * 1024 * 1024);
|
|
327
349
|
if (!Number.isFinite(o) || o <= 0) throw new e(`--chunk-size expects a positive number of megabytes, got '${String(a)}'`);
|
|
328
350
|
let s = t.stream[Symbol.asyncIterator](), c = [], l = 0, u = !1;
|
|
329
351
|
for (; l <= o;) {
|
|
@@ -338,11 +360,11 @@ var A = class extends Error {
|
|
|
338
360
|
kind: "small",
|
|
339
361
|
body: Buffer.concat(c)
|
|
340
362
|
};
|
|
341
|
-
let d = n(process.cwd(), t.bundleDir), f =
|
|
363
|
+
let d = n(process.cwd(), t.bundleDir), f = we(K(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), {
|
|
342
364
|
...t.headers,
|
|
343
365
|
"x-import-upload-id": p,
|
|
344
366
|
"x-import-probe": "1"
|
|
345
|
-
},
|
|
367
|
+
}, Z(t.args)), h = m.status === 200 ? Number(JSON.parse(m.body.toString("utf8")).bytes ?? 0) : 0;
|
|
346
368
|
h > 0 && t.log.info("api import: resuming a chunked upload the instance already holds", { bytes: h });
|
|
347
369
|
let g = (async function* () {
|
|
348
370
|
for (let e of c) yield e;
|
|
@@ -351,7 +373,7 @@ var A = class extends Error {
|
|
|
351
373
|
if (e.done === !0) return;
|
|
352
374
|
yield e.value;
|
|
353
375
|
}
|
|
354
|
-
})(), _ = 0, v = await
|
|
376
|
+
})(), _ = 0, v = await Te({
|
|
355
377
|
stream: g,
|
|
356
378
|
chunkBytes: o,
|
|
357
379
|
uploadId: p,
|
|
@@ -365,7 +387,7 @@ var A = class extends Error {
|
|
|
365
387
|
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.");
|
|
366
388
|
},
|
|
367
389
|
target: { send: async (e, n) => {
|
|
368
|
-
let r = await
|
|
390
|
+
let r = await M(t.url, e, n, Z(t.args)), i = {};
|
|
369
391
|
try {
|
|
370
392
|
i = JSON.parse(r.body.toString("utf8") || "{}");
|
|
371
393
|
} catch {}
|
|
@@ -387,21 +409,32 @@ var A = class extends Error {
|
|
|
387
409
|
body: Buffer.from(JSON.stringify(v.body))
|
|
388
410
|
}
|
|
389
411
|
};
|
|
390
|
-
},
|
|
412
|
+
}, Ue = (e) => `--mode replace with --no-atomic against a ${e ? "RUNNING instance" : "live database"}: the target is empty between the delete and the load, and anything the application writes in that window can collide with a row from the bundle — or survive the import as a row the bundle never carried. Drop --no-atomic to run the whole load in one transaction (concurrent writers then wait instead of racing), or stop the traffic for the duration.`, X = (e, t) => e.includes("--no-atomic") ? !1 : e.includes("--atomic") || t === "replace", We = (e, t, n) => {
|
|
413
|
+
if (t !== "replace" || e.includes("--no-rollback")) return;
|
|
414
|
+
let r = z(e, "--rollback-dir");
|
|
415
|
+
return r === void 0 ? i(n) : f(r);
|
|
416
|
+
}, Ge = (e, t, n) => {
|
|
417
|
+
let r = We(e, t, n);
|
|
418
|
+
return {
|
|
419
|
+
...r === void 0 ? {} : { rollbackDir: r },
|
|
420
|
+
recordInterruption: !0,
|
|
421
|
+
via: "direct"
|
|
422
|
+
};
|
|
423
|
+
}, Z = (t) => {
|
|
391
424
|
let n = z(t, "--timeout");
|
|
392
425
|
if (n === void 0) return {};
|
|
393
426
|
let r = Number(n);
|
|
394
427
|
if (!Number.isFinite(r) || r <= 0) throw new e(`--timeout expects a positive number of seconds, got '${n}'`);
|
|
395
428
|
return { timeoutMs: Math.round(r * 1e3) };
|
|
396
|
-
},
|
|
429
|
+
}, Ke = async (e) => {
|
|
397
430
|
let t = z(e, "--target") === "api", n = z(e, "--bundle-key"), r = B(e);
|
|
398
|
-
if (!r && !(t && n)) return
|
|
431
|
+
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;
|
|
399
432
|
if (t) {
|
|
400
433
|
let t = z(e, "--api-url");
|
|
401
|
-
if (!t) return
|
|
434
|
+
if (!t) return I.error("--target api requires --api-url <url> (the running instance)"), 1;
|
|
402
435
|
let i = z(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
|
|
403
|
-
if (!i) return
|
|
404
|
-
if (z(e, "--exclude") !== void 0) return
|
|
436
|
+
if (!i) return I.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
|
|
437
|
+
if (z(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;
|
|
405
438
|
let a = z(e, "--tables"), o = {
|
|
406
439
|
...z(e, "--profile") ? { profile: z(e, "--profile") } : {},
|
|
407
440
|
...z(e, "--tenant") ? { tenant: z(e, "--tenant") } : {},
|
|
@@ -412,81 +445,82 @@ var A = class extends Error {
|
|
|
412
445
|
...n ? { bundleKey: n } : {}
|
|
413
446
|
}, s;
|
|
414
447
|
try {
|
|
415
|
-
s = await
|
|
448
|
+
s = await M(`${t.replace(/\/+$/, "")}/_voltro/admin/export`, JSON.stringify(o), {
|
|
416
449
|
"content-type": "application/json",
|
|
417
450
|
authorization: `Bearer ${i}`
|
|
418
|
-
},
|
|
451
|
+
}, Z(e));
|
|
419
452
|
} catch (e) {
|
|
420
|
-
if (e instanceof
|
|
453
|
+
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;
|
|
454
|
+
if (e instanceof A) return I.error(`api export: ${be(e)}`), 1;
|
|
421
455
|
throw e;
|
|
422
456
|
}
|
|
423
|
-
if (s.status < 200 || s.status >= 300) return
|
|
424
|
-
if (n) return
|
|
457
|
+
if (s.status < 200 || s.status >= 300) return I.error(`api export failed: HTTP ${s.status} — ${s.body.toString("utf8")}`), 1;
|
|
458
|
+
if (n) return I.info("api export complete (pushed to storage)", {
|
|
425
459
|
via: t,
|
|
426
460
|
...JSON.parse(s.body.toString("utf8"))
|
|
427
461
|
}), 0;
|
|
428
462
|
let { resolve: c } = await import("node:path"), l = new Uint8Array(s.body);
|
|
429
463
|
return await k((async function* () {
|
|
430
464
|
yield l;
|
|
431
|
-
})(), c(process.cwd(), r)),
|
|
465
|
+
})(), c(process.cwd(), r)), I.info("api export complete (downloaded from the running instance)", {
|
|
432
466
|
outDir: r,
|
|
433
467
|
tables: s.headers["x-export-tables"],
|
|
434
468
|
rows: s.headers["x-export-rows"],
|
|
435
469
|
masked: s.headers["x-export-masked"]
|
|
436
470
|
}), 0;
|
|
437
471
|
}
|
|
438
|
-
if (!r) return
|
|
439
|
-
let i = z(e, "--profile"), a = i ? await
|
|
472
|
+
if (!r) return I.error("a <outDir> is required for a direct export"), 1;
|
|
473
|
+
let i = z(e, "--profile"), a = i ? await c(i, { allowPath: !0 }) : {}, { store: o, snapshot: s, dialect: l } = await W(), u = e.includes("--assets") || a.assets === !0, d = u ? S({}) : void 0, f = z(e, "--compression") ?? a.compression, p = z(e, "--consistency") === "snapshot" ? "snapshot" : a.consistency ?? "live", m = a.masking, h = a.subset, g = a.scope ?? Le(e, s.tables.map((e) => e.name)), _ = m ? await Re() : void 0, y = g.kind === "tenant" ? await Be() : void 0, b = y ? { tenantTables: y } : {};
|
|
440
474
|
if (e.includes("--dry-run")) {
|
|
441
|
-
let e =
|
|
442
|
-
if (
|
|
475
|
+
let e = g.kind === "tables" && g.tables ? [...g.tables] : s.tables.map((e) => e.name);
|
|
476
|
+
if (I.info("export DRY RUN — nothing was written", {
|
|
443
477
|
outDir: r,
|
|
444
478
|
tables: e.length,
|
|
445
|
-
scope:
|
|
446
|
-
consistency:
|
|
447
|
-
compression:
|
|
479
|
+
scope: g.kind,
|
|
480
|
+
consistency: p,
|
|
481
|
+
compression: f ?? "zstd",
|
|
448
482
|
assets: u,
|
|
449
|
-
masking:
|
|
450
|
-
}),
|
|
451
|
-
let t = await
|
|
483
|
+
masking: m ? "profile policy applies" : "none"
|
|
484
|
+
}), I.info(`would export: ${e.join(", ")}`), !m) return 0;
|
|
485
|
+
let t = await v.runPromise(ue({
|
|
452
486
|
store: o,
|
|
453
|
-
snapshot:
|
|
454
|
-
masking:
|
|
455
|
-
...
|
|
456
|
-
...
|
|
457
|
-
scope:
|
|
487
|
+
snapshot: s,
|
|
488
|
+
masking: m,
|
|
489
|
+
..._ ? { classification: _ } : {},
|
|
490
|
+
...h ? {} : {
|
|
491
|
+
scope: g,
|
|
458
492
|
...b
|
|
459
493
|
}
|
|
460
494
|
}));
|
|
461
|
-
return
|
|
495
|
+
return Ve(t), +(t.unclassified.length > 0);
|
|
462
496
|
}
|
|
463
497
|
if (K(r)) {
|
|
464
|
-
let t = await import("node:os"), n = await import("node:fs/promises"), { resolve: i, join: a } = await import("node:path"),
|
|
498
|
+
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-"));
|
|
465
499
|
try {
|
|
466
|
-
let t = await
|
|
500
|
+
let t = await v.runPromise(E({
|
|
467
501
|
store: o,
|
|
468
|
-
snapshot:
|
|
502
|
+
snapshot: s,
|
|
469
503
|
dialect: l,
|
|
470
|
-
outDir:
|
|
471
|
-
...
|
|
472
|
-
scope:
|
|
504
|
+
outDir: c,
|
|
505
|
+
...h ? { subset: h } : {
|
|
506
|
+
scope: g,
|
|
473
507
|
...b
|
|
474
508
|
},
|
|
475
|
-
consistency:
|
|
476
|
-
...
|
|
477
|
-
...
|
|
478
|
-
...
|
|
479
|
-
onProgress:
|
|
480
|
-
})), n =
|
|
481
|
-
dir:
|
|
482
|
-
...d ? { blobs:
|
|
483
|
-
}), a =
|
|
509
|
+
consistency: p,
|
|
510
|
+
...f ? { compression: f } : {},
|
|
511
|
+
...m ? { masking: m } : {},
|
|
512
|
+
..._ ? { classification: _ } : {},
|
|
513
|
+
onProgress: R
|
|
514
|
+
})), n = le({
|
|
515
|
+
dir: c,
|
|
516
|
+
...d ? { blobs: he(d, () => G(o)) } : {}
|
|
517
|
+
}), a = Fe(e);
|
|
484
518
|
if (a) {
|
|
485
519
|
let t = q(e);
|
|
486
|
-
if (!t) return
|
|
487
|
-
n =
|
|
520
|
+
if (!t) return I.error("--encrypt requires --passphrase <p> or VOLTRO_BUNDLE_KEY (a dedicated key, NOT the transfer secret)"), 1;
|
|
521
|
+
n = ce(n, t);
|
|
488
522
|
}
|
|
489
|
-
return await
|
|
523
|
+
return await Ie(n, i(process.cwd(), r)), I.info("export complete (single file)", {
|
|
490
524
|
file: r,
|
|
491
525
|
encrypted: a,
|
|
492
526
|
assets: u,
|
|
@@ -494,29 +528,29 @@ var A = class extends Error {
|
|
|
494
528
|
rows: t.tables.reduce((e, t) => e + t.rowCount, 0)
|
|
495
529
|
}), 0;
|
|
496
530
|
} finally {
|
|
497
|
-
await n.rm(
|
|
531
|
+
await n.rm(c, {
|
|
498
532
|
recursive: !0,
|
|
499
533
|
force: !0
|
|
500
534
|
});
|
|
501
535
|
}
|
|
502
536
|
}
|
|
503
|
-
let x = await
|
|
537
|
+
let x = await v.runPromise(E({
|
|
504
538
|
store: o,
|
|
505
|
-
snapshot:
|
|
539
|
+
snapshot: s,
|
|
506
540
|
dialect: l,
|
|
507
541
|
outDir: r,
|
|
508
|
-
...
|
|
509
|
-
scope:
|
|
542
|
+
...h ? { subset: h } : {
|
|
543
|
+
scope: g,
|
|
510
544
|
...b
|
|
511
545
|
},
|
|
512
|
-
consistency:
|
|
513
|
-
...
|
|
514
|
-
...
|
|
515
|
-
...
|
|
516
|
-
...d ? { assets:
|
|
517
|
-
onProgress:
|
|
546
|
+
consistency: p,
|
|
547
|
+
...f ? { compression: f } : {},
|
|
548
|
+
...m ? { masking: m } : {},
|
|
549
|
+
..._ ? { classification: _ } : {},
|
|
550
|
+
...d ? { assets: pe(d, () => G(o)) } : {},
|
|
551
|
+
onProgress: R
|
|
518
552
|
}));
|
|
519
|
-
return
|
|
553
|
+
return I.info("export complete", {
|
|
520
554
|
outDir: r,
|
|
521
555
|
tables: x.tables.length,
|
|
522
556
|
rows: x.tables.reduce((e, t) => e + t.rowCount, 0),
|
|
@@ -524,13 +558,13 @@ var A = class extends Error {
|
|
|
524
558
|
compression: x.compression,
|
|
525
559
|
...x.masking ? { maskedColumns: x.masking.transformed.length } : {}
|
|
526
560
|
}), 0;
|
|
527
|
-
},
|
|
561
|
+
}, qe = () => "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.", Je = (e) => {
|
|
528
562
|
let t = z(e, "--tables");
|
|
529
563
|
return {
|
|
530
564
|
...t ? { tables: t.split(",").map((e) => e.trim()).filter(Boolean) } : {},
|
|
531
565
|
...e.includes("--dry-run") ? { dryRun: !0 } : {}
|
|
532
566
|
};
|
|
533
|
-
},
|
|
567
|
+
}, Q = (e) => ({
|
|
534
568
|
tables: e.tablesWritten,
|
|
535
569
|
rows: e.rowsWritten,
|
|
536
570
|
carried: e.manifest.tables.reduce((e, t) => e + t.rowCount, 0),
|
|
@@ -538,140 +572,187 @@ var A = class extends Error {
|
|
|
538
572
|
skippedTables: e.tablesSkipped,
|
|
539
573
|
skippedRows: e.rowsSkipped
|
|
540
574
|
} : {}
|
|
541
|
-
}),
|
|
575
|
+
}), Ye = (e, t) => {
|
|
542
576
|
if (e.includes("--dry-run")) {
|
|
543
|
-
|
|
577
|
+
I.info("import DRY RUN — nothing was written", t), I.info(qe());
|
|
544
578
|
return;
|
|
545
579
|
}
|
|
546
580
|
if (t.rows === 0 && typeof t.skippedRows == "number" && t.skippedRows !== 0) {
|
|
547
|
-
|
|
581
|
+
I.info("import complete — 0 rows written, every table was already applied by an earlier run of this bundle directory", t);
|
|
548
582
|
return;
|
|
549
583
|
}
|
|
550
|
-
|
|
551
|
-
},
|
|
552
|
-
let t = e;
|
|
553
|
-
if (t?._tag !== "RowsRefusedError" || !Array.isArray(t.rows)) return;
|
|
584
|
+
I.info("import complete", t);
|
|
585
|
+
}, Xe = Symbol("refused"), Ze = (e) => {
|
|
586
|
+
let t = ie(e) ?? e;
|
|
587
|
+
if (t?._tag !== "RowsRefusedError" || !Array.isArray(t.rows)) return !1;
|
|
554
588
|
let n = t.rows, r = n.filter((e) => !e.derived), i = Number(t.totalCount ?? n.length), a = Number(t.primaryCount ?? r.length);
|
|
555
|
-
|
|
589
|
+
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.`);
|
|
556
590
|
let o = Array.isArray(t.byTable) ? t.byTable : [];
|
|
557
|
-
o.length > 1 &&
|
|
558
|
-
for (let e of r)
|
|
559
|
-
n.length < i &&
|
|
591
|
+
o.length > 1 && I.error(` by table: ${o.map((e) => `${e.table} ${e.refused}`).join(", ")}`);
|
|
592
|
+
for (let e of r) I.error(` ${e.table} ${e.id} ${e.reason}`);
|
|
593
|
+
n.length < i && I.error(` (the list above is capped at ${n.length} of ${i} — the counts by table are complete)`);
|
|
560
594
|
let s = i - a;
|
|
561
|
-
s > 0 &&
|
|
562
|
-
},
|
|
595
|
+
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
|
+
}, Qe = (e) => {
|
|
597
|
+
let t = typeof e == "string" ? e : e.toString("utf8"), n = t;
|
|
598
|
+
try {
|
|
599
|
+
let e = JSON.parse(t), r = e.error ?? e.message;
|
|
600
|
+
typeof r == "string" && (n = r);
|
|
601
|
+
} catch {}
|
|
602
|
+
let r = n.indexOf("RowsRefusedError");
|
|
603
|
+
if (r < 0) return;
|
|
604
|
+
let i = n.indexOf("{", r);
|
|
605
|
+
if (i < 0) return;
|
|
606
|
+
let a = 0, o = !1, s = !1;
|
|
607
|
+
for (let e = i; e < n.length; e++) {
|
|
608
|
+
let t = n[e];
|
|
609
|
+
if (o) {
|
|
610
|
+
if (s) {
|
|
611
|
+
s = !1;
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
if (t === "\\") {
|
|
615
|
+
s = !0;
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
t === "\"" && (o = !1);
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
if (t === "\"") {
|
|
622
|
+
o = !0;
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
if (t === "{") a++;
|
|
626
|
+
else if (t === "}" && --a === 0) try {
|
|
627
|
+
let t = JSON.parse(n.slice(i, e + 1));
|
|
628
|
+
return Array.isArray(t.rows) ? {
|
|
629
|
+
_tag: "RowsRefusedError",
|
|
630
|
+
...t
|
|
631
|
+
} : void 0;
|
|
632
|
+
} catch {
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}, $e = async (e) => {
|
|
563
637
|
let t = z(e, "--target") === "api", n = z(e, "--bundle-key"), i = B(e);
|
|
564
|
-
if (!i && !(t && n)) return
|
|
638
|
+
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;
|
|
565
639
|
let a = z(e, "--mode") ?? "upsert", o = z(e, "--on-conflict") ?? "skip";
|
|
566
640
|
if (t) {
|
|
567
641
|
let t = z(e, "--api-url");
|
|
568
|
-
if (!t) return
|
|
642
|
+
if (!t) return I.error("--target api requires --api-url <url> (the running instance)"), 1;
|
|
569
643
|
let r = z(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
|
|
570
|
-
if (!r) return
|
|
571
|
-
let s = z(e, "--tables"), c =
|
|
644
|
+
if (!r) return I.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
|
|
645
|
+
let s = z(e, "--tables"), c = z(e, "--rollback-key");
|
|
646
|
+
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
|
+
let l = {
|
|
572
648
|
authorization: `Bearer ${r}`,
|
|
573
649
|
"x-import-mode": a,
|
|
574
650
|
"x-import-on-conflict": o,
|
|
575
|
-
...
|
|
651
|
+
...X(e, a) ? { "x-import-atomic": "1" } : {},
|
|
576
652
|
...e.includes("--no-atomic") ? { "x-import-atomic": "0" } : {},
|
|
653
|
+
...c === void 0 ? {} : { "x-import-rollback-key": c },
|
|
577
654
|
...e.includes("--force") ? { "x-import-force": "1" } : {},
|
|
578
655
|
...e.includes("--dry-run") ? { "x-import-dry-run": "1" } : {},
|
|
579
656
|
...s ? { "x-import-tables": s } : {}
|
|
580
|
-
}, { resolve:
|
|
581
|
-
if (n)
|
|
657
|
+
}, { resolve: u } = await import("node:path"), d;
|
|
658
|
+
if (n) l["content-type"] = "application/json", d = JSON.stringify({ bundleKey: n });
|
|
582
659
|
else if (K(i)) {
|
|
583
|
-
let t = J(
|
|
584
|
-
n && (t = w(t, n)),
|
|
585
|
-
} else await (await import("node:fs/promises")).access(
|
|
586
|
-
a === "replace" && !
|
|
587
|
-
let
|
|
660
|
+
let t = J(u(process.cwd(), i)), n = q(e);
|
|
661
|
+
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 = le({ dir: u(process.cwd(), i) });
|
|
663
|
+
a === "replace" && !X(e, a) && I.warn(Ue(!0));
|
|
664
|
+
let f = `${t.replace(/\/+$/, "")}/_voltro/admin/import`, p;
|
|
588
665
|
try {
|
|
589
|
-
let t = typeof
|
|
590
|
-
stream:
|
|
591
|
-
url:
|
|
592
|
-
headers:
|
|
666
|
+
let t = typeof d == "string" ? null : await He({
|
|
667
|
+
stream: d,
|
|
668
|
+
url: f,
|
|
669
|
+
headers: l,
|
|
593
670
|
bundleDir: i,
|
|
594
671
|
args: e,
|
|
595
|
-
log:
|
|
672
|
+
log: I
|
|
596
673
|
});
|
|
597
|
-
(t === null || t.kind === "small") &&
|
|
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 M(f, d, l, Z(e)) : t.kind === "sent" ? t.res : await M(f, t.body, l, Z(e));
|
|
598
675
|
} catch (e) {
|
|
599
|
-
if (e instanceof
|
|
676
|
+
if (e instanceof j) return I.error(`api import: ${xe(e, a)}`), 1;
|
|
677
|
+
if (e instanceof A) return I.error(`api import: ${be(e)}`), 1;
|
|
600
678
|
throw e;
|
|
601
679
|
}
|
|
602
|
-
if (
|
|
603
|
-
let
|
|
604
|
-
return e.includes("--dry-run") ? (
|
|
680
|
+
if (p.status < 200 || p.status >= 300) return Ze(Qe(p.body)) || I.error(`api import failed: HTTP ${p.status} — ${p.body.toString("utf8")}`), 1;
|
|
681
|
+
let m = JSON.parse(p.body.toString("utf8"));
|
|
682
|
+
return e.includes("--dry-run") ? (I.info("api import DRY RUN — nothing was written", {
|
|
605
683
|
via: t,
|
|
606
|
-
...
|
|
607
|
-
}),
|
|
684
|
+
...m
|
|
685
|
+
}), I.info(qe()), 0) : (I.info("api import complete (imported by the running instance)", {
|
|
608
686
|
via: t,
|
|
609
|
-
...
|
|
687
|
+
...m
|
|
610
688
|
}), 0);
|
|
611
689
|
}
|
|
612
|
-
if (!i) return
|
|
613
|
-
if (!await
|
|
614
|
-
a === "replace" && e.includes("--allow-live") && !
|
|
615
|
-
let { store: s, snapshot: c } = await W(), l = e.includes("--force"), u = (e) =>
|
|
690
|
+
if (!i) return I.error("a <bundleDir> is required for a direct import"), 1;
|
|
691
|
+
if (!await Me(e)) return 1;
|
|
692
|
+
a === "replace" && e.includes("--allow-live") && !X(e, a) && I.warn(Ue(!1));
|
|
693
|
+
let { store: s, snapshot: c } = await W(), l = e.includes("--force"), u = (e) => I.warn(e), d = e.includes("--assets") ? S({}) : void 0, f = V() === "postgres" ? (await import("@voltro/sql-postgres")).makePgCopySession(r()) : void 0;
|
|
616
694
|
if (K(i)) {
|
|
617
|
-
let t = await import("node:os"), n = await import("node:fs/promises"), { resolve: r, join:
|
|
695
|
+
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-"));
|
|
618
696
|
try {
|
|
619
697
|
let t = J(r(process.cwd(), i)), n = q(e);
|
|
620
|
-
return n && (t = w(t, n)), await
|
|
621
|
-
dir:
|
|
622
|
-
blobs:
|
|
623
|
-
}),
|
|
698
|
+
return n && (t = w(t, n)), await ge(t, {
|
|
699
|
+
dir: m,
|
|
700
|
+
blobs: me(d ?? S({}))
|
|
701
|
+
}), Ye(e, {
|
|
624
702
|
file: i,
|
|
625
|
-
...
|
|
703
|
+
...Q(await v.runPromise(D({
|
|
626
704
|
store: s,
|
|
627
|
-
bundleDir:
|
|
705
|
+
bundleDir: m,
|
|
628
706
|
mode: a,
|
|
629
707
|
onConflict: o,
|
|
630
|
-
atomic:
|
|
708
|
+
atomic: X(e, a),
|
|
709
|
+
...Ge(e, a, i),
|
|
631
710
|
verify: !e.includes("--no-verify"),
|
|
632
711
|
targetDialect: V(),
|
|
633
712
|
allowIncompatible: l,
|
|
634
713
|
targetSnapshot: c,
|
|
635
714
|
force: l,
|
|
636
715
|
onWarn: u,
|
|
637
|
-
onProgress:
|
|
716
|
+
onProgress: R,
|
|
638
717
|
assetsAlreadyRestored: !0,
|
|
639
|
-
...
|
|
640
|
-
...
|
|
718
|
+
...Je(e),
|
|
719
|
+
...f ? { copyLoader: f } : {}
|
|
641
720
|
})))
|
|
642
721
|
}), 0;
|
|
643
722
|
} finally {
|
|
644
|
-
await
|
|
723
|
+
await f?.close(), await n.rm(m, {
|
|
645
724
|
recursive: !0,
|
|
646
725
|
force: !0
|
|
647
726
|
});
|
|
648
727
|
}
|
|
649
728
|
}
|
|
650
|
-
let
|
|
729
|
+
let p = await v.runPromise(D({
|
|
730
|
+
...Ge(e, a, i),
|
|
651
731
|
store: s,
|
|
652
732
|
bundleDir: i,
|
|
653
733
|
mode: a,
|
|
654
734
|
onConflict: o,
|
|
655
|
-
atomic:
|
|
735
|
+
atomic: X(e, a),
|
|
656
736
|
verify: !e.includes("--no-verify"),
|
|
657
737
|
targetDialect: V(),
|
|
658
738
|
allowIncompatible: l,
|
|
659
739
|
targetSnapshot: c,
|
|
660
740
|
force: l,
|
|
661
741
|
onWarn: u,
|
|
662
|
-
onProgress:
|
|
663
|
-
...
|
|
664
|
-
...d ? { assets:
|
|
665
|
-
...
|
|
742
|
+
onProgress: R,
|
|
743
|
+
...Je(e),
|
|
744
|
+
...d ? { assets: fe(d) } : {},
|
|
745
|
+
...f ? { copyLoader: f } : {}
|
|
666
746
|
})).catch((e) => {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
747
|
+
if (Ze(e)) return Xe;
|
|
748
|
+
throw e;
|
|
749
|
+
}).finally(() => f?.close());
|
|
750
|
+
return typeof p == "symbol" ? 1 : (Ye(e, {
|
|
670
751
|
bundleDir: i,
|
|
671
|
-
...
|
|
672
|
-
assets:
|
|
673
|
-
}), 0;
|
|
674
|
-
},
|
|
752
|
+
...Q(p),
|
|
753
|
+
assets: p.manifest.assets.count
|
|
754
|
+
}), 0);
|
|
755
|
+
}, et = () => {
|
|
675
756
|
let e = r();
|
|
676
757
|
return {
|
|
677
758
|
...e.url ? { url: e.url } : {},
|
|
@@ -681,75 +762,75 @@ var A = class extends Error {
|
|
|
681
762
|
...e.password ? { password: e.password } : {},
|
|
682
763
|
...e.database ? { database: e.database } : {}
|
|
683
764
|
};
|
|
684
|
-
},
|
|
765
|
+
}, tt = async (e) => {
|
|
685
766
|
let t = B(e);
|
|
686
|
-
if (!t) return
|
|
767
|
+
if (!t) return I.error("usage: voltro data backup <outDir> (native pg_dump/mysqldump/… + consistent artifact)"), 1;
|
|
687
768
|
let n = V(), { mkdir: r, writeFile: i } = await import("node:fs/promises"), { join: a } = await import("node:path");
|
|
688
769
|
await r(t, { recursive: !0 });
|
|
689
770
|
let o = a(t, C(n));
|
|
690
|
-
await
|
|
691
|
-
let s =
|
|
771
|
+
await v.runPromise(O(oe(n, et(), o)));
|
|
772
|
+
let s = Ee({
|
|
692
773
|
dialect: n,
|
|
693
|
-
schemaFingerprint: await
|
|
694
|
-
voltroVersion: await
|
|
774
|
+
schemaFingerprint: await L(n),
|
|
775
|
+
voltroVersion: await Ae(),
|
|
695
776
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
696
777
|
});
|
|
697
|
-
return await i(a(t,
|
|
778
|
+
return await i(a(t, N), `${JSON.stringify(s, null, 2)}\n`, "utf8"), I.info("native backup complete", {
|
|
698
779
|
dialect: n,
|
|
699
780
|
artifact: o,
|
|
700
|
-
stamp:
|
|
781
|
+
stamp: N,
|
|
701
782
|
schemaFingerprint: s.schemaFingerprint ?? "<none>",
|
|
702
783
|
assets: "NOT included — use `voltro data export --assets` for rows + blobs"
|
|
703
784
|
}), 0;
|
|
704
|
-
},
|
|
705
|
-
let n = V(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(e, C(n)), o =
|
|
785
|
+
}, nt = async (e, t) => {
|
|
786
|
+
let n = V(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(e, C(n)), o = Oe({
|
|
706
787
|
flagUrl: z(t, "--drill-url"),
|
|
707
788
|
envUrl: process.env.DRILL_DB_URL,
|
|
708
|
-
liveKeys:
|
|
789
|
+
liveKeys: Pe()
|
|
709
790
|
});
|
|
710
|
-
if (!o.ok) return
|
|
711
|
-
let s = await i(r(e,
|
|
712
|
-
if (s && s.dialect !== n) return
|
|
713
|
-
|
|
791
|
+
if (!o.ok) return I.error(`restore --drill: ${o.error}`), 1;
|
|
792
|
+
let s = await i(r(e, N), "utf8").then(P, () => null);
|
|
793
|
+
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
|
+
I.info("restore drill: restoring into throwaway DB", {
|
|
714
795
|
dialect: n,
|
|
715
|
-
target:
|
|
716
|
-
}), await
|
|
796
|
+
target: F(o.url)
|
|
797
|
+
}), await v.runPromise(O(de(n, { url: o.url }, a)));
|
|
717
798
|
let c = null, l = 0;
|
|
718
799
|
try {
|
|
719
800
|
let e = await H(n, { url: o.url });
|
|
720
|
-
c =
|
|
801
|
+
c = ee(e), l = e.tables.length;
|
|
721
802
|
} catch (e) {
|
|
722
|
-
return
|
|
803
|
+
return I.error(`restore --drill: could not introspect the restored DB — ${String(e)}`), 1;
|
|
723
804
|
}
|
|
724
|
-
let u =
|
|
805
|
+
let u = ke({
|
|
725
806
|
stampFingerprint: s?.schemaFingerprint ?? null,
|
|
726
807
|
restoredFingerprint: c,
|
|
727
808
|
restoredTableCount: l
|
|
728
809
|
});
|
|
729
|
-
for (let e of u.lines) u.pass ?
|
|
810
|
+
for (let e of u.lines) u.pass ? I.info(`restore drill: ${e}`) : I.error(`restore drill: ${e}`);
|
|
730
811
|
return +!u.pass;
|
|
731
|
-
},
|
|
812
|
+
}, rt = async (e) => {
|
|
732
813
|
let t = B(e);
|
|
733
|
-
if (!t) return
|
|
734
|
-
if (e.includes("--drill")) return
|
|
735
|
-
if (!await
|
|
736
|
-
let n = V(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(t, C(n)), o =
|
|
737
|
-
stamp: await i(r(t,
|
|
814
|
+
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 nt(t, e);
|
|
816
|
+
if (!await Me(e)) return 1;
|
|
817
|
+
let n = V(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(t, C(n)), o = De({
|
|
818
|
+
stamp: await i(r(t, N), "utf8").then(P, () => null),
|
|
738
819
|
currentDialect: n,
|
|
739
|
-
currentFingerprint: await
|
|
820
|
+
currentFingerprint: await L(n)
|
|
740
821
|
});
|
|
741
|
-
for (let e of o.info)
|
|
742
|
-
if (o.warn &&
|
|
743
|
-
if (!e.includes("--force")) return
|
|
744
|
-
|
|
822
|
+
for (let e of o.info) I.info(`backup stamp: ${e}`);
|
|
823
|
+
if (o.warn && I.warn(o.warn), o.refuse) {
|
|
824
|
+
if (!e.includes("--force")) return I.error(`restore refused: ${o.refuse} (pass --force to override)`), 1;
|
|
825
|
+
I.warn(`restore proceeding despite: ${o.refuse} (--force)`);
|
|
745
826
|
}
|
|
746
|
-
return await
|
|
827
|
+
return await v.runPromise(O(de(n, et(), a))), I.info("native restore complete", {
|
|
747
828
|
dialect: n,
|
|
748
829
|
artifact: a
|
|
749
830
|
}), 0;
|
|
750
|
-
},
|
|
831
|
+
}, it = async (e) => {
|
|
751
832
|
let t = B(e);
|
|
752
|
-
if (!t) return
|
|
833
|
+
if (!t) return I.error("usage: voltro data inspect <file.vbundle|dir> [--json] [--passphrase <p>]"), 1;
|
|
753
834
|
let { resolve: n, join: r } = await import("node:path"), i = await import("node:fs/promises"), a = n(process.cwd(), t);
|
|
754
835
|
if ((await i.stat(a).catch(() => void 0))?.isDirectory()) {
|
|
755
836
|
let n = r(a, "manifest.json"), o = r(a, "README.md");
|
|
@@ -758,25 +839,44 @@ var A = class extends Error {
|
|
|
758
839
|
if (e !== void 0) return console.log(e), 0;
|
|
759
840
|
}
|
|
760
841
|
let s = await i.readFile(n, "utf8").catch(() => void 0);
|
|
761
|
-
return s === void 0 ? (
|
|
842
|
+
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);
|
|
762
843
|
}
|
|
763
844
|
let o = q(e), s = () => {
|
|
764
845
|
let e = J(a);
|
|
765
846
|
return o ? w(e, o) : e;
|
|
766
847
|
};
|
|
767
848
|
if (e.includes("--json")) {
|
|
768
|
-
let e = (await
|
|
769
|
-
return e ? (console.log(e.toString("utf8")), 0) : (
|
|
849
|
+
let e = (await T(s(), ["manifest.json"])).get("manifest.json");
|
|
850
|
+
return e ? (console.log(e.toString("utf8")), 0) : (I.error("no manifest.json found in the bundle"), 1);
|
|
770
851
|
}
|
|
771
|
-
let c = (await
|
|
852
|
+
let c = (await T(s(), ["README.md"])).get("README.md");
|
|
772
853
|
if (c) return console.log(c.toString("utf8")), 0;
|
|
773
|
-
let l = (await
|
|
774
|
-
return l ? (console.log(l.toString("utf8")), 0) : (
|
|
775
|
-
},
|
|
854
|
+
let l = (await T(s(), ["manifest.json"])).get("manifest.json");
|
|
855
|
+
return l ? (console.log(l.toString("utf8")), 0) : (I.error("bundle has no README.md or manifest.json"), 1);
|
|
856
|
+
}, at = async (e) => {
|
|
857
|
+
let { REPLACE_IN_PROGRESS_TABLE: t } = await import("@voltro/database"), { interruptedReplaceAtBoot: n } = await import("./interruptedReplace-DNJ7MKph.js"), { store: r } = await W(), i = await n(r);
|
|
858
|
+
if (i === void 0) return I.info("no interrupted replace is recorded — nothing to clear"), 0;
|
|
859
|
+
if (!e.includes("--yes")) return I.error(`${i}\n\n Re-run with --yes to clear it.`), 1;
|
|
860
|
+
let a = await r.query({
|
|
861
|
+
table: t,
|
|
862
|
+
predicate: void 0,
|
|
863
|
+
order: [],
|
|
864
|
+
take: void 0,
|
|
865
|
+
skip: void 0,
|
|
866
|
+
projection: void 0
|
|
867
|
+
});
|
|
868
|
+
for (let e of a) await r.delete(t, String(e.id));
|
|
869
|
+
return I.info(`cleared ${a.length} interrupted-replace marker(s) — the next boot will start`), 0;
|
|
870
|
+
}, ot = async (e) => {
|
|
871
|
+
let { STAGING_PREFIX: t, dropStagingSql: n, execStatements: r } = await import("@voltro/data-transfer"), { store: i } = await W(), a = V();
|
|
872
|
+
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
|
+
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
|
+
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
|
+
}, st = async (e) => {
|
|
776
876
|
let t = B(e), n = B(e.filter((e) => e !== t));
|
|
777
|
-
if (!t || !n) return
|
|
877
|
+
if (!t || !n) return I.error("usage: voltro data unpack <file.vbundle> <dir> [--passphrase <p>]"), 1;
|
|
778
878
|
let { resolve: r } = await import("node:path"), i = J(r(process.cwd(), t)), a = q(e);
|
|
779
|
-
return a && (i = w(i, a)), await k(i, r(process.cwd(), n)),
|
|
879
|
+
return a && (i = w(i, a)), await k(i, r(process.cwd(), n)), I.info("unpack complete", {
|
|
780
880
|
file: t,
|
|
781
881
|
dir: n
|
|
782
882
|
}), 0;
|
|
@@ -805,6 +905,8 @@ var A = class extends Error {
|
|
|
805
905
|
"--timeout"
|
|
806
906
|
]
|
|
807
907
|
},
|
|
908
|
+
"clear-staging": { common: ["--yes"] },
|
|
909
|
+
"clear-replace-marker": { common: ["--yes"] },
|
|
808
910
|
import: {
|
|
809
911
|
common: [
|
|
810
912
|
"--target",
|
|
@@ -821,14 +923,17 @@ var A = class extends Error {
|
|
|
821
923
|
directOnly: [
|
|
822
924
|
"--no-verify",
|
|
823
925
|
"--allow-live",
|
|
824
|
-
"--passphrase"
|
|
926
|
+
"--passphrase",
|
|
927
|
+
"--rollback-dir",
|
|
928
|
+
"--no-rollback"
|
|
825
929
|
],
|
|
826
930
|
apiOnly: [
|
|
827
931
|
"--api-url",
|
|
828
932
|
"--token",
|
|
829
933
|
"--bundle-key",
|
|
830
934
|
"--timeout",
|
|
831
|
-
"--chunk-size"
|
|
935
|
+
"--chunk-size",
|
|
936
|
+
"--rollback-key"
|
|
832
937
|
]
|
|
833
938
|
},
|
|
834
939
|
unpack: { common: ["--passphrase", "--json"] },
|
|
@@ -842,13 +947,13 @@ var A = class extends Error {
|
|
|
842
947
|
"--drill-url",
|
|
843
948
|
"--api-url"
|
|
844
949
|
] }
|
|
845
|
-
},
|
|
950
|
+
}, ct = (e) => e.split("=")[0], lt = (e, t) => {
|
|
846
951
|
let n = $[e];
|
|
847
952
|
if (!n) return;
|
|
848
953
|
let r = z(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 ?? []);
|
|
849
954
|
for (let n of t) {
|
|
850
955
|
if (!n.startsWith("--")) continue;
|
|
851
|
-
let t =
|
|
956
|
+
let t = ct(n);
|
|
852
957
|
if (i.has(t)) continue;
|
|
853
958
|
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.`;
|
|
854
959
|
let o = Object.entries($).filter(([n, r]) => n !== e && [
|
|
@@ -858,13 +963,13 @@ var A = class extends Error {
|
|
|
858
963
|
].includes(t)).map(([e]) => e);
|
|
859
964
|
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.`;
|
|
860
965
|
}
|
|
861
|
-
},
|
|
966
|
+
}, ut = async (e) => {
|
|
862
967
|
let [t, ...n] = e;
|
|
863
968
|
if (t !== void 0 && $[t] !== void 0) {
|
|
864
|
-
let e =
|
|
865
|
-
if (e) return
|
|
969
|
+
let e = lt(t, n);
|
|
970
|
+
if (e) return I.error(e), 2;
|
|
866
971
|
}
|
|
867
|
-
return t === "export" ?
|
|
972
|
+
return t === "export" ? Ke(n) : t === "import" ? $e(n) : t === "unpack" ? st(n) : t === "inspect" ? it(n) : t === "backup" ? tt(n) : t === "restore" ? rt(n) : t === "clear-replace-marker" ? at(n) : t === "clear-staging" ? ot(n) : (I.error("usage: voltro data <export|import|unpack|inspect|backup|restore|clear-replace-marker|clear-staging> … (logical: export/import; native: backup/restore)"), t ? 2 : 1);
|
|
868
973
|
};
|
|
869
974
|
//#endregion
|
|
870
|
-
export {
|
|
975
|
+
export { ut as runDataCommand };
|