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