@voltro/cli 0.50.1 → 0.52.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 +231 -0
- package/dist/{agentsMd-D6yD7IQv.js → agentsMd-0l980yhL.js} +4 -1
- package/dist/agentsMd-SDDSkyl4.js +2 -0
- package/dist/apiBuild-BYBpL7Pz.js +2 -0
- package/dist/{apiBuild-D3s7lx57.js → apiBuild-CSFI8QGq.js} +3 -3
- package/dist/appGraph-CFmFKHb2.js +2 -0
- package/dist/appGraph-yRuKjOba.js +111 -0
- package/dist/bin.js +1 -1
- package/dist/build-CPgcMQug.js +793 -0
- package/dist/checkCommand-2SbqzukH.js +2 -0
- package/dist/{checkCommand-DsKIjL6k.js → checkCommand-COmqc2cB.js} +107 -60
- package/dist/{cloudCmd-F4YJeqM3.js → cloudCmd-QUXh-b5w.js} +1 -1
- package/dist/codegen-CctkDO-1.js +2 -0
- package/dist/{codegen-CrMXs4hb.js → codegen-VF479Cnb.js} +1 -1
- package/dist/{codegenCommand-C0S27nbB.js → codegenCommand-DCdG2JN-.js} +12 -12
- package/dist/{codemodRunner-DwY8Rjbl.js → codemodRunner-r7J9lIa7.js} +771 -636
- package/dist/{commands-Brp4DI8u.js → commands-Cc_nV8WI.js} +37 -36
- package/dist/{dashboardCommand-bbLfc9FW.js → dashboardCommand-C-gKvwqh.js} +3 -3
- package/dist/{dataCommand-k9mXTXin.js → dataCommand-BgpBHnlB.js} +299 -253
- package/dist/dbCommand-DNb6yeOG.js +2 -0
- package/dist/{dbCommand-Bf7Cy0mn.js → dbCommand-sHedr-NJ.js} +3 -3
- package/dist/dev--A3nsxA3.js +3 -0
- package/dist/{dev-C0cbqysu.js → dev-CRHoCEiy.js} +2258 -2219
- package/dist/doctorCommand-CqoWA2p5.js +2 -0
- package/dist/{doctorCommand-DyViaaCP.js → doctorCommand-DtfJ3FA6.js} +314 -234
- package/dist/{dormancyCommand-DMZPA_HW.js → dormancyCommand-Drn7o0No.js} +1 -1
- package/dist/{embeddingsCommand-CMxRPkg6.js → embeddingsCommand-Z-jO1fWN.js} +1 -1
- package/dist/{envCommand-CDLr-yD4.js → envCommand-D4gCrrTZ.js} +15 -15
- package/dist/{evolveCommand-Ct4NesL3.js → evolveCommand-CMROeKeA.js} +2 -2
- package/dist/fileConventions-DOqD3lPS.js +34 -0
- package/dist/{fileTaxonomy-CJfgOllU.js → fileTaxonomy-DvDUV9wq.js} +1 -1
- package/dist/frameworkTableAssembly-C6ETawPR.js +2 -0
- package/dist/{frameworkTableAssembly-BwJVEKLr.js → frameworkTableAssembly-w-XnLa3q.js} +1 -1
- package/dist/{generateCommand-BDdOxhnv.js → generateCommand-DTNPGjxo.js} +1 -1
- package/dist/index.js +1 -1
- package/dist/{infoCommand-orsKJKUy.js → infoCommand-DXM868o_.js} +1 -1
- package/dist/inspectMetrics-CGF94puw.js +143 -0
- package/dist/{metaCommands-CfRLra0s.js → metaCommands-C6RFmF1r.js} +2 -2
- package/dist/{migrate-D3MK9BpK.js → migrate-D0F-eTlK.js} +2 -2
- package/dist/{pageConvention-cEiRxdab.js → pageConvention-CzUiSbtU.js} +1 -1
- package/dist/{privacyCommand-XejDMvmu.js → privacyCommand-DGdopOI6.js} +1 -1
- package/dist/{projectScaffold-mIX_DpSe.js → projectScaffold-B4dmTlwT.js} +1 -1
- package/dist/{projectScaffold-BIl97_E6.js → projectScaffold-EzlErR4E.js} +1 -1
- package/dist/{renderModeScan-D7J1B7Kw.js → renderModeScan-CcH2X1_D.js} +25 -10
- package/dist/{renderProfile-1OWWAAtx.js → renderProfile-Ck32Fzxr.js} +2 -2
- package/dist/{runtimeTrace-Bo8jWsNe.js → runtimeTrace-BPQyCmC5.js} +1 -1
- package/dist/{sdkgen-OZhiT2vz.js → sdkgen-Se88ifTd.js} +1 -1
- package/dist/serveCommand-DLc-BznW.js +2 -0
- package/dist/{serveCommand-YbD5VgfV.js → serveCommand-DkP3OT0W.js} +885 -868
- package/dist/serveEntry.js +1 -1
- package/dist/start-DfL3fOiN.js +3 -0
- package/dist/start-jw89Xbqy.js +1339 -0
- package/dist/startEntry.js +1 -1
- package/dist/{staticCommand-Dr2M6tpU.js → staticCommand-BwNEDlSU.js} +1 -1
- package/dist/{test-rXFq4S76.js → test-f3amja6a.js} +1 -1
- package/dist/updateCommand-5gFVfK5q.js +2 -0
- package/dist/{updateCommand-BgH6vTtq.js → updateCommand-BMk2e4ky.js} +1 -1
- package/dist/{webDev-BbdkzMbd.js → webDev-BgWL9gKV.js} +1233 -853
- package/dist/webDev-CZbTsDcH.js +2 -0
- package/dist/{webhooksCommand-DjE6u0r4.js → webhooksCommand-CoIO3jbj.js} +1 -1
- package/package.json +48 -17
- package/templates/AGENTS.core.md +26 -5
- package/templates/AGENTS.md +30 -9
- package/templates/agent-docs/_index.md +4 -4
- package/templates/agent-docs/_manifest.json +11 -11
- package/templates/agent-docs/cli.md +125 -14
- package/templates/agent-docs/data.md +210 -7
- package/templates/agent-docs/database/schema.md +1 -1
- package/templates/agent-docs/database/seedsdialects.md +1 -1
- package/templates/agent-docs/deployment.md +22 -3
- package/templates/agent-docs/internationalization.md +131 -13
- package/templates/agent-docs/introduction.md +46 -0
- package/templates/agent-docs/local-first-mobile.md +34 -7
- package/templates/agent-docs/plugins/ai-flows.md +1 -1
- package/templates/agent-docs/plugins/audit.md +5 -5
- package/templates/agent-docs/plugins/cdc-out.md +2 -2
- package/templates/agent-docs/plugins/{versioning.md → row-history.md} +22 -22
- package/templates/agent-docs/plugins/storage.md +2 -2
- package/templates/agent-docs/plugins.md +29 -7
- package/templates/agent-docs/reference.md +39 -2
- package/templates/agent-docs/routing.md +341 -47
- package/templates/agent-docs/schema-driven-ui.md +78 -2
- package/templates/agent-docs/security.md +125 -8
- package/templates/agent-docs/templates/apibackends.md +14 -14
- package/templates/agent-docs/templates/overview.md +1 -1
- package/templates/agent-docs/whats-new.md +100 -29
- package/templates/apps/api-ai/package.json +6 -7
- package/templates/apps/api-ai/tests/summarize.test.ts +1 -1
- 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 +9 -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-versioning → api-row-history}/README.md +3 -3
- package/templates/apps/{api-versioning → api-row-history}/actions/documents.asOf.action.server.ts +1 -1
- package/templates/apps/{api-versioning → api-row-history}/actions/documents.history.action.server.ts +1 -1
- package/templates/apps/{api-versioning → api-row-history}/app.config.ts +3 -3
- package/templates/apps/{api-versioning → api-row-history}/database/schema.ts +1 -1
- package/templates/apps/{api-versioning → api-row-history}/mutations/documents.create.mutation.server.ts +1 -1
- package/templates/apps/{api-versioning → api-row-history}/mutations/documents.create.mutation.ts +1 -1
- package/templates/apps/{api-versioning → api-row-history}/mutations/documents.update.mutation.ts +1 -1
- package/templates/apps/{api-versioning → api-row-history}/package.json +8 -8
- package/templates/apps/api-row-history/template.json +6 -0
- package/templates/apps/{api-versioning → api-row-history}/tests/documents.create.test.ts +1 -1
- package/templates/apps/api-saas/app.config.ts +1 -0
- package/templates/apps/api-saas/package.json +10 -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-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-collab/src/pages/page.test.tsx +10 -9
- package/templates/apps/frontend-collab/src/pages/page.tsx +42 -65
- 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 +6 -7
- package/templates/apps/frontend-i18n/package.json +6 -6
- package/templates/apps/frontend-landing/package.json +6 -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/agentsMd-Bu_XQgVf.js +0 -2
- package/dist/apiBuild-BZ-plaQN.js +0 -2
- package/dist/appGraph-CM9wvUmD.js +0 -2
- package/dist/appGraph-Cv2W_wO5.js +0 -111
- package/dist/build-CFmqF39c.js +0 -721
- package/dist/checkCommand-DomvYDi1.js +0 -2
- package/dist/codegen-DiMn2KkZ.js +0 -2
- package/dist/dbCommand-Bnl7MSGC.js +0 -2
- package/dist/dev-Dz9GqA6P.js +0 -3
- package/dist/doctorCommand-BlciWUJb.js +0 -2
- package/dist/fileConventions-Cof68_BL.js +0 -33
- package/dist/frameworkTableAssembly-CVDB2hCq.js +0 -2
- package/dist/inspectMetrics-CfdKLh6t.js +0 -72
- package/dist/serveCommand-Bbgg7Paq.js +0 -2
- package/dist/start-7b_bL8Uc.js +0 -3
- package/dist/start-B1nH9ahf.js +0 -1150
- package/dist/updateCommand-BweY17z-.js +0 -2
- package/dist/webDev-BcRFTsMA.js +0 -2
- package/templates/apps/api-versioning/template.json +0 -6
- /package/templates/apps/{api-versioning → api-row-history}/actions/documents.asOf.action.ts +0 -0
- /package/templates/apps/{api-versioning → api-row-history}/actions/documents.history.action.ts +0 -0
- /package/templates/apps/{api-versioning → api-row-history}/mutations/documents.update.mutation.server.ts +0 -0
- /package/templates/apps/{api-versioning → api-row-history}/tsconfig.json +0 -0
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { i as e, t } from "./subcommandNames-DpYs3DXr.js";
|
|
2
2
|
import { t as n } from "./cliError-BmdYnghb.js";
|
|
3
|
-
import {
|
|
3
|
+
import { B as r, c as i, i as a, o } from "./dev-CRHoCEiy.js";
|
|
4
4
|
import { n as s, t as c } from "./cliArgs-D4p8n7EE.js";
|
|
5
5
|
import { r as l } from "./dialectDriver-czCHYpeH.js";
|
|
6
6
|
import { i as u, n as d, r as f, t as p } from "./dataProfile-Du3ztYxv.js";
|
|
7
7
|
import { o as m, t as h } from "./inspectFetch-EMuhTG_9.js";
|
|
8
|
-
import { r as g } from "./dbCommand-
|
|
8
|
+
import { r as g } from "./dbCommand-sHedr-NJ.js";
|
|
9
9
|
import { resolve as _ } from "node:path";
|
|
10
10
|
import { createLogger as v } from "@voltro/logger";
|
|
11
|
-
import { DATA_TRANSFERS_TABLE as y, REPLACE_IN_PROGRESS_TABLE as b, _voltroDataTransfersTable as x, _voltroReplaceInProgressTable as S, connectionIdentity as C, derivedRowId as
|
|
12
|
-
import { Cause as
|
|
13
|
-
import { SqlClient as
|
|
14
|
-
import { declaredSnapshot as
|
|
15
|
-
import { STORAGE_REFS_TABLE as
|
|
16
|
-
import { createHash as
|
|
17
|
-
import { ASSETS_DIR 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 w, ensureTableRegistered as T, normaliseTarget as ee, sameDatabase as te, streamTable as ne } from "@voltro/database";
|
|
12
|
+
import { Cause as E, Effect as D, Exit as re, Option as ie, Stream as ae } from "effect";
|
|
13
|
+
import { SqlClient as oe } from "@effect/sql";
|
|
14
|
+
import { declaredSnapshot as se, fingerprintSchema as ce, introspectSchema as le } from "@voltro/database/sql";
|
|
15
|
+
import { STORAGE_REFS_TABLE as ue, appStorageProvider as de, configuredStorageProvider as O } from "@voltro/plugin-storage";
|
|
16
|
+
import { createHash as fe } from "node:crypto";
|
|
17
|
+
import { ASSETS_DIR as k, ASSET_INDEX_FILE as A, BundleError as pe, asImportError as me, assessLiveImport as he, backupArtifactName as j, backupCommand as ge, captureAssetsToCas as _e, classificationFromSnapshot as ve, decryptStream as M, encryptStream as ye, packBundle as be, peekBundle as N, previewMasking as xe, restoreAssetsFromCas as Se, restoreCommand as Ce, runExport as we, runImport as Te, runNativeStep as Ee, storageAssetSink as De, storageAssetSource as Oe, storageBlobSink as ke, storageBlobSource as Ae, unpackBundle as je, unpackBundleToDir as Me } from "@voltro/data-transfer";
|
|
18
18
|
import { request as Ne } from "node:http";
|
|
19
19
|
import { request as Pe } from "node:https";
|
|
20
20
|
//#region src/longRequest.ts
|
|
@@ -100,7 +100,7 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
100
100
|
i += a.byteLength, yield s;
|
|
101
101
|
}
|
|
102
102
|
yield* a(!0);
|
|
103
|
-
}, ze = (e) =>
|
|
103
|
+
}, ze = (e) => fe("sha256").update(Buffer.from(e)).digest("hex"), Be = async (e) => {
|
|
104
104
|
let t = 0, n = 0, r = {
|
|
105
105
|
status: 0,
|
|
106
106
|
body: {}
|
|
@@ -150,9 +150,15 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
150
150
|
if (n.stampVersion !== 1 || typeof n.dialect != "string" || typeof n.voltroVersion != "string" || typeof n.createdAt != "string") return null;
|
|
151
151
|
let r = n.schemaFingerprint;
|
|
152
152
|
if (r !== null && typeof r != "string") return null;
|
|
153
|
-
let i = n.assets, a =
|
|
153
|
+
let i = n.assets, a = (e) => {
|
|
154
|
+
let t = i?.[e];
|
|
155
|
+
return typeof t == "number" ? t : void 0;
|
|
156
|
+
}, o = typeof i == "object" && i && typeof i.count == "number" && typeof i.totalBytes == "number" ? {
|
|
154
157
|
count: i.count,
|
|
155
|
-
totalBytes: i.totalBytes
|
|
158
|
+
totalBytes: i.totalBytes,
|
|
159
|
+
...a("references") === void 0 ? {} : { references: a("references") },
|
|
160
|
+
...a("objects") === void 0 ? {} : { objects: a("objects") },
|
|
161
|
+
...a("objectBytes") === void 0 ? {} : { objectBytes: a("objectBytes") }
|
|
156
162
|
} : null;
|
|
157
163
|
return {
|
|
158
164
|
stampVersion: 1,
|
|
@@ -160,56 +166,72 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
160
166
|
schemaFingerprint: r,
|
|
161
167
|
voltroVersion: n.voltroVersion,
|
|
162
168
|
createdAt: n.createdAt,
|
|
163
|
-
assets:
|
|
169
|
+
assets: o
|
|
164
170
|
};
|
|
165
171
|
}, Ue = (e) => {
|
|
166
|
-
let { stamp: t, currentDialect: n,
|
|
172
|
+
let { stamp: t, currentDialect: n, targetFingerprint: r } = e;
|
|
167
173
|
if (t === null) return {
|
|
168
174
|
warn: `no ${R} beside the dump — an older/handmade backup. Cannot verify dialect or schema version; make sure this dump is a ${n} dump.`,
|
|
169
175
|
info: []
|
|
170
176
|
};
|
|
171
177
|
let i = [`backup produced by @voltro/cli ${t.voltroVersion} at ${t.createdAt}`, `schema fingerprint: ${t.schemaFingerprint ?? "<none recorded>"}`];
|
|
172
178
|
return t.dialect === n ? t.schemaFingerprint !== null && r !== null && t.schemaFingerprint !== r ? {
|
|
173
|
-
warn: `schema skew — the backup's schema (${t.schemaFingerprint.slice(0, 12)}) differs from
|
|
179
|
+
warn: `schema skew — the backup's schema (${t.schemaFingerprint.slice(0, 12)}) differs from the schema this TARGET database currently has (${r.slice(0, 12)}). This compares the backup against the target's present state, not against what your code declares. The restore replaces the target's schema with the backup's; run \`voltro db apply\` afterwards to bring it to what the code declares.`,
|
|
174
180
|
info: i
|
|
175
181
|
} : { info: i } : {
|
|
176
182
|
refuse: `dialect mismatch — backup is a ${t.dialect} dump, but DB_DIALECT is ${n}. A cross-dialect restore is never valid.`,
|
|
177
183
|
info: i
|
|
178
184
|
};
|
|
179
185
|
}, We = async (e, t) => {
|
|
180
|
-
let n =
|
|
186
|
+
let n = w("dimp", `${t.direction}-${t.artifact}-${Date.now()}-${Math.random()}`), r = {
|
|
187
|
+
id: n,
|
|
188
|
+
direction: t.direction,
|
|
189
|
+
startedAt: /* @__PURE__ */ new Date(),
|
|
190
|
+
finishedAt: null,
|
|
191
|
+
failure: null,
|
|
192
|
+
mode: `native ${t.dialect}${t.assets ? " + assets" : ""}`,
|
|
193
|
+
via: "cli",
|
|
194
|
+
bundle: t.artifact,
|
|
195
|
+
sourceFingerprint: null,
|
|
196
|
+
tablesWritten: 0,
|
|
197
|
+
rowsWritten: 0,
|
|
198
|
+
staged: null
|
|
199
|
+
};
|
|
181
200
|
try {
|
|
182
|
-
return
|
|
183
|
-
id: n,
|
|
184
|
-
direction: t.direction,
|
|
185
|
-
startedAt: /* @__PURE__ */ new Date(),
|
|
186
|
-
finishedAt: null,
|
|
187
|
-
failure: null,
|
|
188
|
-
mode: `native ${t.dialect}${t.assets ? " + assets" : ""}`,
|
|
189
|
-
via: "cli",
|
|
190
|
-
bundle: t.artifact,
|
|
191
|
-
sourceFingerprint: null,
|
|
192
|
-
tablesWritten: 0,
|
|
193
|
-
rowsWritten: 0,
|
|
194
|
-
staged: null
|
|
195
|
-
}), {
|
|
201
|
+
return T(x), await e.insert(y, r), {
|
|
196
202
|
runId: n,
|
|
197
|
-
recorded: !0
|
|
203
|
+
recorded: !0,
|
|
204
|
+
opened: r
|
|
198
205
|
};
|
|
199
206
|
} catch {
|
|
200
207
|
return {
|
|
201
208
|
runId: n,
|
|
202
|
-
recorded: !1
|
|
209
|
+
recorded: !1,
|
|
210
|
+
opened: r
|
|
203
211
|
};
|
|
204
212
|
}
|
|
205
213
|
}, z = async (e, t, n) => {
|
|
206
|
-
|
|
214
|
+
if (!t.recorded) return;
|
|
215
|
+
let r = {
|
|
207
216
|
finishedAt: /* @__PURE__ */ new Date(),
|
|
208
217
|
failure: n.failure ?? null,
|
|
209
218
|
...n.assets === void 0 ? {} : { rowsWritten: n.assets }
|
|
210
|
-
}
|
|
219
|
+
};
|
|
220
|
+
if (await e.update(y, t.runId, r).then(() => void 0, () => void 0), !await e.query({
|
|
221
|
+
table: y,
|
|
222
|
+
predicate: void 0,
|
|
223
|
+
order: [],
|
|
224
|
+
take: void 0,
|
|
225
|
+
skip: void 0,
|
|
226
|
+
projection: void 0
|
|
227
|
+
}).then((e) => e.some((e) => String(e.id ?? "") === t.runId), () => !0)) try {
|
|
228
|
+
T(x), await e.insert(y, {
|
|
229
|
+
...t.opened,
|
|
230
|
+
...r
|
|
231
|
+
});
|
|
232
|
+
} catch {}
|
|
211
233
|
}, Ge = async (e, t) => {
|
|
212
|
-
let n =
|
|
234
|
+
let n = w("repl", `restore-${t.artifact}-${Date.now()}-${Math.random()}`), r = {
|
|
213
235
|
id: n,
|
|
214
236
|
startedAt: /* @__PURE__ */ new Date(),
|
|
215
237
|
kind: "restore",
|
|
@@ -218,7 +240,7 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
218
240
|
via: "cli"
|
|
219
241
|
};
|
|
220
242
|
try {
|
|
221
|
-
|
|
243
|
+
T(S), await e.insert(b, r);
|
|
222
244
|
} catch {
|
|
223
245
|
return;
|
|
224
246
|
}
|
|
@@ -236,7 +258,7 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
236
258
|
if (await i()) return "held";
|
|
237
259
|
} catch {}
|
|
238
260
|
try {
|
|
239
|
-
return
|
|
261
|
+
return T(S), await e.insert(b, r), "rewritten";
|
|
240
262
|
} catch {
|
|
241
263
|
return "lost";
|
|
242
264
|
}
|
|
@@ -250,14 +272,14 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
250
272
|
}
|
|
251
273
|
};
|
|
252
274
|
}, Ke = async (e) => {
|
|
253
|
-
let t = await
|
|
254
|
-
if (
|
|
255
|
-
let n =
|
|
256
|
-
if (
|
|
275
|
+
let t = await D.runPromiseExit(e);
|
|
276
|
+
if (re.isSuccess(t)) return;
|
|
277
|
+
let n = E.failureOption(t.cause);
|
|
278
|
+
if (ie.isSome(n)) {
|
|
257
279
|
let e = n.value;
|
|
258
280
|
return String(e?.message ?? e);
|
|
259
281
|
}
|
|
260
|
-
return
|
|
282
|
+
return E.pretty(t.cause);
|
|
261
283
|
}, B = (e) => {
|
|
262
284
|
try {
|
|
263
285
|
let t = new URL(e), n = t.pathname.replace(/^\//, "");
|
|
@@ -303,7 +325,7 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
303
325
|
}
|
|
304
326
|
}, Xe = async (e) => {
|
|
305
327
|
try {
|
|
306
|
-
return
|
|
328
|
+
return ce(await tt(e));
|
|
307
329
|
} catch {
|
|
308
330
|
return null;
|
|
309
331
|
}
|
|
@@ -334,17 +356,17 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
334
356
|
}, Qe = async (e) => {
|
|
335
357
|
let t = e.includes("--allow-live"), n = t ? null : await Ze(U(e, "--api-url")), r = C({
|
|
336
358
|
dialect: G(),
|
|
337
|
-
...
|
|
338
|
-
}), i =
|
|
359
|
+
...o()
|
|
360
|
+
}), i = ee({
|
|
339
361
|
dialect: G(),
|
|
340
|
-
...
|
|
341
|
-
}), { refuse:
|
|
362
|
+
...o()
|
|
363
|
+
}), { refuse: a, message: s } = he({
|
|
342
364
|
liveInstance: n?.label ?? null,
|
|
343
365
|
allowLive: t,
|
|
344
|
-
sameTarget:
|
|
366
|
+
sameTarget: te(r, n?.databaseId),
|
|
345
367
|
...i === void 0 ? {} : { targetLabel: `${i.host}:${i.port}/${i.database}` }
|
|
346
368
|
});
|
|
347
|
-
return !
|
|
369
|
+
return !a || (V.error(s ?? "refusing: live instance detected"), !1);
|
|
348
370
|
}, U = s, $e = [
|
|
349
371
|
"--api-url",
|
|
350
372
|
"--bundle-key",
|
|
@@ -371,43 +393,43 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
371
393
|
return e;
|
|
372
394
|
}, et = async (e, t) => {
|
|
373
395
|
let n = (await l(e)).makeSqlLayer(t);
|
|
374
|
-
return
|
|
375
|
-
}, tt = (e) => et(e,
|
|
376
|
-
let e =
|
|
396
|
+
return D.runPromise(oe.SqlClient.pipe(D.flatMap(le), D.provide(n)));
|
|
397
|
+
}, tt = (e) => et(e, o()), nt = () => {
|
|
398
|
+
let e = o(), t = [];
|
|
377
399
|
return e.url && t.push(B(e.url)), (e.host || e.database) && t.push(`${(e.host ?? "localhost").toLowerCase()}:${e.port ?? "(default)"}/${e.database ?? ""}`), t;
|
|
378
400
|
}, K = async () => {
|
|
379
|
-
let e = process.cwd(), t = await
|
|
401
|
+
let e = process.cwd(), t = await i(e);
|
|
380
402
|
if (!t) throw new n("voltro data: no app.config.ts found in the current directory.");
|
|
381
|
-
let
|
|
403
|
+
let r = await a(t, void 0), o = G();
|
|
382
404
|
return {
|
|
383
|
-
store:
|
|
405
|
+
store: r,
|
|
384
406
|
snapshot: await tt(o),
|
|
385
407
|
dialect: o
|
|
386
408
|
};
|
|
387
|
-
},
|
|
388
|
-
table:
|
|
409
|
+
}, rt = (e) => ne(e, {
|
|
410
|
+
table: ue,
|
|
389
411
|
chunkSize: 500
|
|
390
|
-
}).pipe(
|
|
412
|
+
}).pipe(ae.map((e) => ({
|
|
391
413
|
key: String(e.key),
|
|
392
414
|
contentType: String(e.contentType ?? "application/octet-stream"),
|
|
393
415
|
size: Number(e.size ?? 0)
|
|
394
|
-
}))),
|
|
416
|
+
}))), q = (e) => !!e && e.endsWith(".vbundle"), J = (e) => U(e, "--passphrase") ?? process.env.VOLTRO_BUNDLE_KEY, it = (e) => e.includes("--encrypt") || U(e, "--passphrase") !== void 0 || process.env.VOLTRO_BUNDLE_KEY !== void 0, at = async (e, t) => {
|
|
395
417
|
let { createWriteStream: n } = await import("node:fs"), { pipeline: r } = await import("node:stream/promises"), { Readable: i } = await import("node:stream");
|
|
396
418
|
await r(i.from(e), n(t));
|
|
397
|
-
},
|
|
419
|
+
}, Y = (e) => ({ async *[Symbol.asyncIterator]() {
|
|
398
420
|
let { createReadStream: t } = await import("node:fs");
|
|
399
421
|
for await (let n of t(e)) yield n instanceof Uint8Array ? n : new Uint8Array(n);
|
|
400
|
-
} }),
|
|
422
|
+
} }), ot = async (e, t) => {
|
|
401
423
|
if (t !== void 0 || e === void 0) return null;
|
|
402
424
|
try {
|
|
403
|
-
let { resolve: t, join: n } = await import("node:path"), r = await import("node:fs/promises"), i = t(process.cwd(), e), a =
|
|
425
|
+
let { resolve: t, join: n } = await import("node:path"), r = await import("node:fs/promises"), i = t(process.cwd(), e), a = q(e) ? (await N(Y(i), ["manifest.json"])).get("manifest.json") : await r.readFile(n(i, "manifest.json"));
|
|
404
426
|
if (a === void 0) return null;
|
|
405
427
|
let o = (JSON.parse(Buffer.from(a).toString("utf8")).tables ?? []).map((e) => e.name).filter((e) => typeof e == "string");
|
|
406
428
|
return o.length > 0 ? o : null;
|
|
407
429
|
} catch {
|
|
408
430
|
return null;
|
|
409
431
|
}
|
|
410
|
-
},
|
|
432
|
+
}, st = (e) => {
|
|
411
433
|
let t = U(e, "--max-request-seconds") ?? process.env.VOLTRO_MAX_REQUEST_SECONDS;
|
|
412
434
|
if (t === void 0) return { pollMs: 2e3 };
|
|
413
435
|
let r = Number(t);
|
|
@@ -417,7 +439,7 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
417
439
|
perRequest: { timeoutMs: i },
|
|
418
440
|
pollMs: Math.max(500, Math.min(2e3, Math.floor(i / 2)))
|
|
419
441
|
};
|
|
420
|
-
},
|
|
442
|
+
}, ct = async (e, t, n) => {
|
|
421
443
|
let r = await fetch(`${e.replace(/\/+$/, "")}/_voltro/admin/transfers?limit=50`, { headers: { authorization: `Bearer ${t}` } }).catch(() => null);
|
|
422
444
|
if (r === null || r.status !== 200) return null;
|
|
423
445
|
let i = ((await r.json().catch(() => null))?.runs ?? []).find((e) => e.id === n);
|
|
@@ -426,7 +448,7 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
426
448
|
startedAt: new Date(String(i.startedAt)),
|
|
427
449
|
finishedAt: i.finishedAt === null || i.finishedAt === void 0 ? null : new Date(String(i.finishedAt))
|
|
428
450
|
};
|
|
429
|
-
},
|
|
451
|
+
}, lt = async (e) => {
|
|
430
452
|
let t = e.apiUrl.replace(/\/+$/, ""), n = [], r = 0, i;
|
|
431
453
|
for (;;) {
|
|
432
454
|
let a = `${t}/_voltro/admin/export/download?runId=${encodeURIComponent(e.runId)}&offset=${r}`, o = new AbortController(), s = e.perRequest === void 0 ? void 0 : setTimeout(() => {
|
|
@@ -448,12 +470,12 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
448
470
|
e.log.info(` downloading — ${r}/${i ?? "?"} bytes`);
|
|
449
471
|
}
|
|
450
472
|
return new Uint8Array(Buffer.concat(n));
|
|
451
|
-
},
|
|
473
|
+
}, ut = "transfers", dt = (e) => (e ?? "").split(",").map((e) => e.trim()).filter(Boolean), ft = (e, t) => {
|
|
452
474
|
let r = U(e, "--tenant"), i = U(e, "--tables"), a = U(e, "--exclude");
|
|
453
475
|
if (a !== void 0) {
|
|
454
476
|
if (i !== void 0) throw new n("voltro data export: --exclude and --tables are two ways to say the same thing; use one.");
|
|
455
477
|
if (r !== void 0) throw new n("voltro data export: --exclude does not apply to --tenant, whose table set is derived from the tenant closure.");
|
|
456
|
-
let e =
|
|
478
|
+
let e = dt(a), o = new Set(t), s = e.filter((e) => !o.has(e));
|
|
457
479
|
if (s.length > 0) throw new n(`voltro data export: --exclude names ${s.length} table(s) that do not exist: ${s.join(", ")}. An exclusion that excludes nothing would leave the run looking like it worked.`);
|
|
458
480
|
return {
|
|
459
481
|
kind: "all",
|
|
@@ -465,15 +487,15 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
465
487
|
tenantId: r
|
|
466
488
|
} : i ? {
|
|
467
489
|
kind: "tables",
|
|
468
|
-
tables:
|
|
490
|
+
tables: dt(i)
|
|
469
491
|
} : { kind: "all" };
|
|
470
|
-
},
|
|
492
|
+
}, pt = async () => {
|
|
471
493
|
let e = await g(process.cwd());
|
|
472
|
-
return
|
|
473
|
-
},
|
|
474
|
-
let e = (await g(process.cwd())).filter((e) => (e.appliedMixins ?? []).some((e) => e.id ===
|
|
494
|
+
return ve(se(e));
|
|
495
|
+
}, mt = "voltro/tenant", ht = async () => {
|
|
496
|
+
let e = (await g(process.cwd())).filter((e) => (e.appliedMixins ?? []).some((e) => e.id === mt)).map((e) => e.tableName);
|
|
475
497
|
return e.length > 0 ? e : void 0;
|
|
476
|
-
},
|
|
498
|
+
}, gt = (e) => {
|
|
477
499
|
for (let t of e.tables) if (t.samples.length !== 0) {
|
|
478
500
|
console.log(`\n ${t.table}`);
|
|
479
501
|
for (let e of t.samples) console.log(` ${e.column} [${e.action}] ${JSON.stringify(e.before)} → ${JSON.stringify(e.after)}`);
|
|
@@ -486,7 +508,7 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
486
508
|
console.log("\n ✗ unclassified (would BLOCK a real export — add .sensitive()/.safe() or a policy override):");
|
|
487
509
|
for (let t of e.unclassified) console.log(` ${t}`);
|
|
488
510
|
} else console.log("\n ✓ every exported column is classified — safe to run.");
|
|
489
|
-
},
|
|
511
|
+
}, _t = async (e) => {
|
|
490
512
|
let { resolve: t, join: r } = await import("node:path"), i = await import("node:fs/promises"), a = U(e.args, "--chunk-size"), o = a === void 0 ? Le : Math.round(Number(a) * 1024 * 1024);
|
|
491
513
|
if (!Number.isFinite(o) || o <= 0) throw new n(`--chunk-size expects a positive number of megabytes, got '${String(a)}'`);
|
|
492
514
|
let s = e.stream[Symbol.asyncIterator](), c = [], l = 0, u = !1;
|
|
@@ -502,11 +524,11 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
502
524
|
kind: "small",
|
|
503
525
|
body: Buffer.concat(c)
|
|
504
526
|
};
|
|
505
|
-
let d = t(process.cwd(), e.bundleDir), f = ze(
|
|
527
|
+
let d = t(process.cwd(), e.bundleDir), f = ze(q(e.bundleDir) ? await i.readFile(d) : await i.readFile(r(d, "manifest.json"))), p = `up-${f.slice(0, 32)}`, m = await I(e.url, Buffer.alloc(0), {
|
|
506
528
|
...e.headers,
|
|
507
529
|
"x-import-upload-id": p,
|
|
508
530
|
"x-import-probe": "1"
|
|
509
|
-
},
|
|
531
|
+
}, Z(e.args)), h = m.status === 200 ? Number(JSON.parse(m.body.toString("utf8")).bytes ?? 0) : 0;
|
|
510
532
|
h > 0 && e.log.info("api import: resuming a chunked upload the instance already holds", { bytes: h });
|
|
511
533
|
let g = (async function* () {
|
|
512
534
|
for (let e of c) yield e;
|
|
@@ -529,7 +551,7 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
529
551
|
e.log.info("api import: upload done — the instance is importing now. This request stays open until it finishes, which on a full bundle is minutes, and nothing more is printed until then. It is not a hang; the instance logs the import itself.");
|
|
530
552
|
},
|
|
531
553
|
target: { send: async (t, n) => {
|
|
532
|
-
let r = await I(e.url, t, n,
|
|
554
|
+
let r = await I(e.url, t, n, Z(e.args)), i = {};
|
|
533
555
|
try {
|
|
534
556
|
i = JSON.parse(r.body.toString("utf8") || "{}");
|
|
535
557
|
} catch {}
|
|
@@ -551,24 +573,24 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
551
573
|
body: Buffer.from(JSON.stringify(v.body))
|
|
552
574
|
}
|
|
553
575
|
};
|
|
554
|
-
},
|
|
576
|
+
}, vt = (e) => `--mode replace with --no-atomic against a ${e ? "RUNNING instance" : "live database"}: the target is empty between the delete and the load, and anything the application writes in that window can collide with a row from the bundle — or survive the import as a row the bundle never carried. Drop --no-atomic to run the whole load in one transaction (concurrent writers then wait instead of racing), or stop the traffic for the duration.`, X = (e, t) => e.includes("--no-atomic") ? !1 : e.includes("--atomic") || t === "replace", yt = (e, t, n) => {
|
|
555
577
|
if (t !== "replace" || e.includes("--no-rollback")) return;
|
|
556
|
-
let
|
|
557
|
-
return
|
|
558
|
-
},
|
|
559
|
-
let r =
|
|
578
|
+
let i = U(e, "--rollback-dir");
|
|
579
|
+
return i === void 0 ? r(n) : _(i);
|
|
580
|
+
}, bt = (e, t, n) => {
|
|
581
|
+
let r = yt(e, t, n);
|
|
560
582
|
return {
|
|
561
583
|
...r === void 0 ? {} : { rollbackDir: r },
|
|
562
584
|
recordInterruption: !0,
|
|
563
585
|
via: "direct"
|
|
564
586
|
};
|
|
565
|
-
},
|
|
587
|
+
}, Z = (e) => {
|
|
566
588
|
let t = U(e, "--timeout");
|
|
567
589
|
if (t === void 0) return {};
|
|
568
590
|
let r = Number(t);
|
|
569
591
|
if (!Number.isFinite(r) || r <= 0) throw new n(`--timeout expects a positive number of seconds, got '${t}'`);
|
|
570
592
|
return { timeoutMs: Math.round(r * 1e3) };
|
|
571
|
-
},
|
|
593
|
+
}, xt = async (e) => {
|
|
572
594
|
let t = U(e, "--target") === "api", n = U(e, "--bundle-key"), r = W(e);
|
|
573
595
|
if (!r && !(t && n)) return V.error("usage: voltro data export <outDir> [--target direct|api] [--api-url <url>] [--token <secret>] [--timeout <seconds>] [--profile <name>] [--tenant <id>] [--tables a,b] [--exclude a,b] [--bundle-key <storage-key>] [--assets] [--compression zstd|gzip|none] [--consistency live|snapshot] [--dry-run]"), 1;
|
|
574
596
|
if (t) {
|
|
@@ -587,12 +609,12 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
587
609
|
...U(e, "--compression") ? { compression: U(e, "--compression") } : {},
|
|
588
610
|
...e.includes("--assets") ? { assets: !0 } : {},
|
|
589
611
|
...n ? { bundleKey: n } : {}
|
|
590
|
-
}, c =
|
|
612
|
+
}, c = st(e), l;
|
|
591
613
|
try {
|
|
592
614
|
let n = await I(`${t.replace(/\/+$/, "")}/_voltro/admin/export`, JSON.stringify(s), {
|
|
593
615
|
"content-type": "application/json",
|
|
594
616
|
authorization: `Bearer ${i}`
|
|
595
|
-
}, c.perRequest ??
|
|
617
|
+
}, c.perRequest ?? Z(e));
|
|
596
618
|
if (n.status < 200 || n.status >= 300) return V.error(`api export failed: HTTP ${n.status} — ${n.body.toString("utf8")}`), 1;
|
|
597
619
|
l = JSON.parse(n.body.toString("utf8"));
|
|
598
620
|
} catch (e) {
|
|
@@ -600,10 +622,10 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
600
622
|
if (e instanceof P) return V.error(`api export: ${L(e)}`), 1;
|
|
601
623
|
throw e;
|
|
602
624
|
}
|
|
603
|
-
if (e.includes("--detach")) return V.info(`api export: started as ${l.runId}. NOT waiting for it.\n The outcome is not known yet — read it with: voltro data ${
|
|
625
|
+
if (e.includes("--detach")) return V.info(`api export: started as ${l.runId}. NOT waiting for it.\n The outcome is not known yet — read it with: voltro data ${ut} --target api --api-url ${t}`), 0;
|
|
604
626
|
if (l.recorded === !1) return V.warn(`api export: started as ${l.runId}, but this instance could not record the run — so its outcome\n cannot be read back. Run \`voltro db apply\` against it so the next one is watchable.`), 0;
|
|
605
627
|
let p = await d({
|
|
606
|
-
read: () =>
|
|
628
|
+
read: () => ct(t, i, l.runId),
|
|
607
629
|
onTick: (e) => {
|
|
608
630
|
V.info(f(e));
|
|
609
631
|
},
|
|
@@ -618,7 +640,7 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
618
640
|
tables: p?.tablesWritten ?? 0,
|
|
619
641
|
rows: p?.rowsWritten ?? 0
|
|
620
642
|
}), 0;
|
|
621
|
-
let { resolve: h } = await import("node:path"), g = await
|
|
643
|
+
let { resolve: h } = await import("node:path"), g = await lt({
|
|
622
644
|
apiUrl: t,
|
|
623
645
|
secret: i,
|
|
624
646
|
runId: l.runId,
|
|
@@ -636,9 +658,9 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
636
658
|
}), 0);
|
|
637
659
|
}
|
|
638
660
|
if (!r) return V.error("a <outDir> is required for a direct export"), 1;
|
|
639
|
-
let i = U(e, "--profile"), a = i ? await p(i, { allowPath: !0 }) : {}, { store: o, snapshot: s, dialect: c } = await K(), l = e.includes("--assets") || a.assets === !0, m = l ?
|
|
661
|
+
let i = U(e, "--profile"), a = i ? await p(i, { allowPath: !0 }) : {}, { store: o, snapshot: s, dialect: c } = await K(), l = e.includes("--assets") || a.assets === !0, m = l ? O() : void 0;
|
|
640
662
|
if (l && !m) return V.error("--assets: this app has no storage provider configured, so there are no blobs to export.\n Install `storagePlugin(...)` in app.config.ts or set STORAGE_PROVIDER, or drop the flag."), 1;
|
|
641
|
-
let h = U(e, "--compression") ?? a.compression, g = U(e, "--consistency") === "snapshot" ? "snapshot" : a.consistency ?? "live", _ = a.masking, v = a.subset, y = a.scope ??
|
|
663
|
+
let h = U(e, "--compression") ?? a.compression, g = U(e, "--consistency") === "snapshot" ? "snapshot" : a.consistency ?? "live", _ = a.masking, v = a.subset, y = a.scope ?? ft(e, s.tables.map((e) => e.name)), b = _ ? await pt() : void 0, x = y.kind === "tenant" ? await ht() : void 0, S = x ? { tenantTables: x } : {};
|
|
642
664
|
if (e.includes("--dry-run")) {
|
|
643
665
|
let e = y.kind === "tables" && y.tables ? [...y.tables] : s.tables.map((e) => e.name);
|
|
644
666
|
if (V.info("export DRY RUN — nothing was written", {
|
|
@@ -650,7 +672,7 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
650
672
|
assets: l,
|
|
651
673
|
masking: _ ? "profile policy applies" : "none"
|
|
652
674
|
}), V.info(`would export: ${e.join(", ")}`), !_) return 0;
|
|
653
|
-
let t = await
|
|
675
|
+
let t = await D.runPromise(xe({
|
|
654
676
|
store: o,
|
|
655
677
|
snapshot: s,
|
|
656
678
|
masking: _,
|
|
@@ -660,12 +682,12 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
660
682
|
...S
|
|
661
683
|
}
|
|
662
684
|
}));
|
|
663
|
-
return
|
|
685
|
+
return gt(t), +(t.unclassified.length > 0);
|
|
664
686
|
}
|
|
665
|
-
if (
|
|
687
|
+
if (q(r)) {
|
|
666
688
|
let t = await import("node:os"), n = await import("node:fs/promises"), { resolve: i, join: a } = await import("node:path"), u = await n.mkdtemp(a(t.tmpdir(), "voltro-export-"));
|
|
667
689
|
try {
|
|
668
|
-
let t = await
|
|
690
|
+
let t = await D.runPromise(we({
|
|
669
691
|
store: o,
|
|
670
692
|
snapshot: s,
|
|
671
693
|
dialect: c,
|
|
@@ -679,16 +701,16 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
679
701
|
..._ ? { masking: _ } : {},
|
|
680
702
|
...b ? { classification: b } : {},
|
|
681
703
|
onProgress: H
|
|
682
|
-
})), n =
|
|
704
|
+
})), n = be({
|
|
683
705
|
dir: u,
|
|
684
|
-
...m ? { blobs: Ae(m, () =>
|
|
685
|
-
}), a =
|
|
706
|
+
...m ? { blobs: Ae(m, () => rt(o)) } : {}
|
|
707
|
+
}), a = it(e);
|
|
686
708
|
if (a) {
|
|
687
|
-
let t =
|
|
709
|
+
let t = J(e);
|
|
688
710
|
if (!t) return V.error("--encrypt requires --passphrase <p> or VOLTRO_BUNDLE_KEY (a dedicated key, NOT the transfer secret)"), 1;
|
|
689
|
-
n =
|
|
711
|
+
n = ye(n, t);
|
|
690
712
|
}
|
|
691
|
-
return await
|
|
713
|
+
return await at(n, i(process.cwd(), r)), V.info("export complete (single file)", {
|
|
692
714
|
file: r,
|
|
693
715
|
encrypted: a,
|
|
694
716
|
assets: l,
|
|
@@ -702,7 +724,7 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
702
724
|
});
|
|
703
725
|
}
|
|
704
726
|
}
|
|
705
|
-
let C = await
|
|
727
|
+
let C = await D.runPromise(we({
|
|
706
728
|
store: o,
|
|
707
729
|
snapshot: s,
|
|
708
730
|
dialect: c,
|
|
@@ -715,7 +737,7 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
715
737
|
...h ? { compression: h } : {},
|
|
716
738
|
..._ ? { masking: _ } : {},
|
|
717
739
|
...b ? { classification: b } : {},
|
|
718
|
-
...m ? { assets: Oe(m, () =>
|
|
740
|
+
...m ? { assets: Oe(m, () => rt(o)) } : {},
|
|
719
741
|
onProgress: H
|
|
720
742
|
}));
|
|
721
743
|
return V.info("export complete", {
|
|
@@ -726,13 +748,13 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
726
748
|
compression: C.compression,
|
|
727
749
|
...C.masking ? { maskedColumns: C.masking.transformed.length } : {}
|
|
728
750
|
}), 0;
|
|
729
|
-
},
|
|
751
|
+
}, St = () => "dry run checked: schema fit, cross-dialect portability, mode legality, the table selection. It did NOT read per-table checksums (those stream during the load) and cannot see conflicts that depend on the target's current rows.", Ct = (e) => {
|
|
730
752
|
let t = U(e, "--tables");
|
|
731
753
|
return {
|
|
732
754
|
...t ? { tables: t.split(",").map((e) => e.trim()).filter(Boolean) } : {},
|
|
733
755
|
...e.includes("--dry-run") ? { dryRun: !0 } : {}
|
|
734
756
|
};
|
|
735
|
-
},
|
|
757
|
+
}, wt = (e) => ({
|
|
736
758
|
tables: e.tablesWritten,
|
|
737
759
|
rows: e.rowsWritten,
|
|
738
760
|
carried: e.manifest.tables.reduce((e, t) => e + t.rowCount, 0),
|
|
@@ -740,9 +762,9 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
740
762
|
skippedTables: e.tablesSkipped,
|
|
741
763
|
skippedRows: e.rowsSkipped
|
|
742
764
|
} : {}
|
|
743
|
-
}),
|
|
765
|
+
}), Tt = (e, t) => {
|
|
744
766
|
if (e.includes("--dry-run")) {
|
|
745
|
-
V.info("import DRY RUN — nothing was written", t), V.info(
|
|
767
|
+
V.info("import DRY RUN — nothing was written", t), V.info(St());
|
|
746
768
|
return;
|
|
747
769
|
}
|
|
748
770
|
if (t.rows === 0 && typeof t.skippedRows == "number" && t.skippedRows !== 0) {
|
|
@@ -750,8 +772,8 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
750
772
|
return;
|
|
751
773
|
}
|
|
752
774
|
V.info("import complete", t);
|
|
753
|
-
},
|
|
754
|
-
let t =
|
|
775
|
+
}, Et = Symbol("refused"), Q = (e) => {
|
|
776
|
+
let t = me(e) ?? e;
|
|
755
777
|
if (t?._tag !== "RowsRefusedError" || !Array.isArray(t.rows)) return !1;
|
|
756
778
|
let n = t.rows, r = n.filter((e) => !e.derived), i = Number(t.totalCount ?? n.length), a = Number(t.primaryCount ?? r.length);
|
|
757
779
|
V.error(`import refused ${i} row(s), of which ${a} are the actual failures — the rest could not land because a row they reference did not.`);
|
|
@@ -761,7 +783,7 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
761
783
|
n.length < i && V.error(` (the list above is capped at ${n.length} of ${i} — the counts by table are complete)`);
|
|
762
784
|
let s = i - a;
|
|
763
785
|
return s > 0 && V.error(` … and ${s} row(s) behind them. Fix the ${a} above and re-run; they resolve with their parents.`), !0;
|
|
764
|
-
},
|
|
786
|
+
}, Dt = (e) => {
|
|
765
787
|
let t = typeof e == "string" ? e : e.toString("utf8"), n = t;
|
|
766
788
|
try {
|
|
767
789
|
let e = JSON.parse(t), r = e.error ?? e.message;
|
|
@@ -801,22 +823,22 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
801
823
|
return;
|
|
802
824
|
}
|
|
803
825
|
}
|
|
804
|
-
},
|
|
826
|
+
}, Ot = async (e) => {
|
|
805
827
|
let t = U(e, "--target") === "api", n = U(e, "--bundle-key"), r = W(e);
|
|
806
828
|
if (!r && !(t && n)) return V.error("usage: voltro data import <bundleDir> [--target direct|api] [--api-url <url>] [--token <secret>] [--timeout <seconds>] [--bundle-key <storage-key>] [--tables a,b] [--mode upsert|append|replace] [--on-conflict skip|fail] [--atomic] [--assets] [--no-verify] [--force] [--allow-live] [--dry-run] (--force: import despite schema drift AND cross-dialect warnings; --dry-run: report what would move, write nothing)"), 1;
|
|
807
|
-
let i = U(e, "--mode") ?? "upsert",
|
|
829
|
+
let i = U(e, "--mode") ?? "upsert", a = U(e, "--on-conflict") ?? "skip";
|
|
808
830
|
if (t) {
|
|
809
831
|
let t = U(e, "--api-url");
|
|
810
832
|
if (!t) return V.error("--target api requires --api-url <url> (the running instance)"), 1;
|
|
811
|
-
let
|
|
812
|
-
if (!
|
|
833
|
+
let o = U(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
|
|
834
|
+
if (!o) return V.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
|
|
813
835
|
let s = U(e, "--tables"), c = U(e, "--rollback-key");
|
|
814
836
|
i === "replace" && c === void 0 && V.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.");
|
|
815
837
|
let l = {
|
|
816
|
-
authorization: `Bearer ${
|
|
838
|
+
authorization: `Bearer ${o}`,
|
|
817
839
|
"x-import-mode": i,
|
|
818
|
-
"x-import-on-conflict":
|
|
819
|
-
...
|
|
840
|
+
"x-import-on-conflict": a,
|
|
841
|
+
...X(e, i) ? { "x-import-atomic": "1" } : {},
|
|
820
842
|
...e.includes("--no-atomic") ? { "x-import-atomic": "0" } : {},
|
|
821
843
|
...c === void 0 ? {} : { "x-import-rollback-key": c },
|
|
822
844
|
...e.includes("--force") ? { "x-import-force": "1" } : {},
|
|
@@ -824,34 +846,34 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
824
846
|
...s ? { "x-import-tables": s } : {}
|
|
825
847
|
}, { resolve: p } = await import("node:path"), m;
|
|
826
848
|
if (n) l["content-type"] = "application/json", m = JSON.stringify({ bundleKey: n });
|
|
827
|
-
else if (
|
|
828
|
-
let t =
|
|
829
|
-
n && (t =
|
|
830
|
-
} else await (await import("node:fs/promises")).access(p(process.cwd(), r, "assets", "index.ndjson")).then(() => !0, () => !1) && V.warn("this directory bundle has assets; --target api uploads DATA ONLY. Pack a single-file `.vbundle` (voltro data export <name>.vbundle --assets) to transfer assets over the API."), l["content-type"] = "application/octet-stream", m =
|
|
849
|
+
else if (q(r)) {
|
|
850
|
+
let t = Y(p(process.cwd(), r)), n = J(e);
|
|
851
|
+
n && (t = M(t, n)), l["content-type"] = "application/octet-stream", m = t;
|
|
852
|
+
} else await (await import("node:fs/promises")).access(p(process.cwd(), r, "assets", "index.ndjson")).then(() => !0, () => !1) && V.warn("this directory bundle has assets; --target api uploads DATA ONLY. Pack a single-file `.vbundle` (voltro data export <name>.vbundle --assets) to transfer assets over the API."), l["content-type"] = "application/octet-stream", m = be({ dir: p(process.cwd(), r) });
|
|
831
853
|
if (i === "replace") {
|
|
832
|
-
let i = await
|
|
854
|
+
let i = await ot(r, n);
|
|
833
855
|
{
|
|
834
856
|
let r = i === null ? { bundleKey: n } : { tables: i }, a = await I(`${t.replace(/\/+$/, "")}/_voltro/admin/import`, JSON.stringify(r), {
|
|
835
857
|
...l,
|
|
836
858
|
"content-type": "application/json",
|
|
837
859
|
"x-import-preflight": "1"
|
|
838
|
-
},
|
|
860
|
+
}, Z(e)).catch(() => null), o = a !== null && a.status === 200 ? JSON.parse(a.body.toString("utf8")) : null;
|
|
839
861
|
o === null ? V.warn("api replace: the instance did not answer the preflight (an older build does not have it). The run still works; the decision will only be visible in the pod log.") : o.staged === !0 ? V.info(`api replace: the instance WILL stage — ${o.stagedTables ?? 0} table(s) load into copies and the\n target keeps its rows until one short swap at the end. Interrupting the load leaves the target intact.`) : V.warn(`api replace: the instance will NOT stage — it empties the target first and refills it, so an
|
|
840
862
|
interrupted run leaves the target empty.\n Reason: ${o.reason ?? "not stated"}`);
|
|
841
863
|
}
|
|
842
864
|
}
|
|
843
|
-
i === "replace" && !
|
|
844
|
-
let h = `${t.replace(/\/+$/, "")}/_voltro/admin/import`, g =
|
|
865
|
+
i === "replace" && !X(e, i) && V.warn(vt(!0));
|
|
866
|
+
let h = `${t.replace(/\/+$/, "")}/_voltro/admin/import`, g = st(e), _;
|
|
845
867
|
try {
|
|
846
|
-
let t = typeof m == "string" ? null : await
|
|
868
|
+
let t = typeof m == "string" ? null : await _t({
|
|
847
869
|
stream: m,
|
|
848
870
|
url: h,
|
|
849
871
|
headers: l,
|
|
850
872
|
bundleDir: r,
|
|
851
873
|
args: e,
|
|
852
874
|
log: V
|
|
853
|
-
}), n = t === null ? await I(h, m, l, g.perRequest ??
|
|
854
|
-
if (n.status < 200 || n.status >= 300) return
|
|
875
|
+
}), n = t === null ? await I(h, m, l, g.perRequest ?? Z(e)) : t.kind === "sent" ? t.res : await I(h, t.body, l, g.perRequest ?? Z(e));
|
|
876
|
+
if (n.status < 200 || n.status >= 300) return Q(Dt(n.body)) || V.error(`api import failed: HTTP ${n.status} — ${n.body.toString("utf8")}`), 1;
|
|
855
877
|
_ = JSON.parse(n.body.toString("utf8"));
|
|
856
878
|
} catch (e) {
|
|
857
879
|
if (e instanceof F) return V.error(`api import: ${Ie(e, i)}`), 1;
|
|
@@ -861,17 +883,17 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
861
883
|
let v = await I(`${t.replace(/\/+$/, "")}/_voltro/admin/import/start`, JSON.stringify(_.bundleKey === void 0 ? { uploadId: _.uploadId } : { bundleKey: _.bundleKey }), {
|
|
862
884
|
...l,
|
|
863
885
|
"content-type": "application/json"
|
|
864
|
-
}, g.perRequest ??
|
|
886
|
+
}, g.perRequest ?? Z(e)).catch((e) => {
|
|
865
887
|
if (e instanceof P) return V.error(`api import: ${L(e)}`), null;
|
|
866
888
|
throw e;
|
|
867
889
|
});
|
|
868
890
|
if (v === null) return 1;
|
|
869
|
-
if (v.status < 200 || v.status >= 300) return
|
|
891
|
+
if (v.status < 200 || v.status >= 300) return Q(Dt(v.body)) || V.error(`api import refused: HTTP ${v.status} — ${v.body.toString("utf8")}`), 1;
|
|
870
892
|
let y = JSON.parse(v.body.toString("utf8"));
|
|
871
|
-
if (y.alreadyStarted === !0 && V.info(`api import: this bundle is already being imported as ${y.runId} — watching that run instead of starting a second one`), e.includes("--detach")) return V.info(`api import: started as ${y.runId}. NOT waiting for it.\n The outcome is not known yet — read it with: voltro data ${
|
|
893
|
+
if (y.alreadyStarted === !0 && V.info(`api import: this bundle is already being imported as ${y.runId} — watching that run instead of starting a second one`), e.includes("--detach")) return V.info(`api import: started as ${y.runId}. NOT waiting for it.\n The outcome is not known yet — read it with: voltro data ${ut} --target api --api-url ${t}`), 0;
|
|
872
894
|
if (y.recorded === !1) return V.warn(`api import: started as ${y.runId}, but this instance could not record the run — so its outcome\n cannot be read back. Run \`voltro db apply\` against it so the next import is watchable.`), 0;
|
|
873
895
|
let b = await d({
|
|
874
|
-
read: () =>
|
|
896
|
+
read: () => ct(t, o, y.runId),
|
|
875
897
|
onTick: (e) => {
|
|
876
898
|
V.info(f(e));
|
|
877
899
|
},
|
|
@@ -880,10 +902,10 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
880
902
|
}), x = u(b);
|
|
881
903
|
return x === 2 ? (V.warn(b === null ? `api import: started as ${y.runId}, but its record could not be READ back from this instance.\n That is a channel problem, not a slow import — an older instance without the history route, a
|
|
882
904
|
proxy dropping the GET, or a target with no history table. The run itself is unaffected and
|
|
883
|
-
is NOT cancelled; its outcome is simply not visible from here.` : `api import: still running after the time allowed. The run is NOT cancelled — it is decoupled from\n this client by design. Watch it with: voltro data ${
|
|
905
|
+
is NOT cancelled; its outcome is simply not visible from here.` : `api import: still running after the time allowed. The run is NOT cancelled — it is decoupled from\n this client by design. Watch it with: voltro data ${ut} --target api --api-url ${t}`), 2) : x === 1 ? (V.error(`api import FAILED (${y.runId}): ${String(b?.failure ?? "no reason recorded")}`), 1) : e.includes("--dry-run") ? (V.info("api import DRY RUN — nothing was written", {
|
|
884
906
|
via: t,
|
|
885
907
|
runId: y.runId
|
|
886
|
-
}), V.info(
|
|
908
|
+
}), V.info(St()), 0) : (V.info("api import complete (imported by the running instance)", {
|
|
887
909
|
via: t,
|
|
888
910
|
runId: y.runId,
|
|
889
911
|
tables: b?.tablesWritten ?? 0,
|
|
@@ -893,28 +915,28 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
893
915
|
}
|
|
894
916
|
if (!r) return V.error("a <bundleDir> is required for a direct import"), 1;
|
|
895
917
|
if (!await Qe(e)) return 1;
|
|
896
|
-
i === "replace" && e.includes("--allow-live") && !
|
|
918
|
+
i === "replace" && e.includes("--allow-live") && !X(e, i) && V.warn(vt(!1));
|
|
897
919
|
let { store: s, snapshot: c } = await K();
|
|
898
920
|
c.tables.some((e) => e.name === y) || V.warn(`this target has no \`${y}\` table, so this import will not be recorded.\n The import itself is unaffected. \`voltro db apply\` creates it.`);
|
|
899
|
-
let l = e.includes("--force"), p = (e) => V.warn(e), m = e.includes("--assets"), h = m ?
|
|
921
|
+
let l = e.includes("--force"), p = (e) => V.warn(e), m = e.includes("--assets"), h = m ? O() : void 0;
|
|
900
922
|
if (m && !h) return V.error("--assets: this app has no storage provider configured, so there is nowhere to put the blobs.\n Install `storagePlugin(...)` in app.config.ts or set STORAGE_PROVIDER, or drop the flag."), 1;
|
|
901
|
-
let g = G() === "postgres" ? (await import("@voltro/sql-postgres")).makePgCopySession(
|
|
902
|
-
if (
|
|
903
|
-
let t = await import("node:os"), n = await import("node:fs/promises"), { resolve:
|
|
923
|
+
let g = G() === "postgres" ? (await import("@voltro/sql-postgres")).makePgCopySession(o()) : void 0;
|
|
924
|
+
if (q(r)) {
|
|
925
|
+
let t = await import("node:os"), n = await import("node:fs/promises"), { resolve: o, join: u } = await import("node:path"), d = await n.mkdtemp(u(t.tmpdir(), "voltro-import-"));
|
|
904
926
|
try {
|
|
905
|
-
let t =
|
|
906
|
-
return n && (t =
|
|
927
|
+
let t = Y(o(process.cwd(), r)), n = J(e);
|
|
928
|
+
return n && (t = M(t, n)), await je(t, {
|
|
907
929
|
dir: d,
|
|
908
|
-
blobs: ke(h ??
|
|
909
|
-
}),
|
|
930
|
+
blobs: ke(h ?? de())
|
|
931
|
+
}), Tt(e, {
|
|
910
932
|
file: r,
|
|
911
|
-
...
|
|
933
|
+
...wt(await D.runPromise(Te({
|
|
912
934
|
store: s,
|
|
913
935
|
bundleDir: d,
|
|
914
936
|
mode: i,
|
|
915
|
-
onConflict:
|
|
916
|
-
atomic:
|
|
917
|
-
...
|
|
937
|
+
onConflict: a,
|
|
938
|
+
atomic: X(e, i),
|
|
939
|
+
...bt(e, i, r),
|
|
918
940
|
verify: !e.includes("--no-verify"),
|
|
919
941
|
targetDialect: G(),
|
|
920
942
|
allowIncompatible: l,
|
|
@@ -923,7 +945,7 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
923
945
|
onWarn: p,
|
|
924
946
|
onProgress: H,
|
|
925
947
|
assetsAlreadyRestored: !0,
|
|
926
|
-
...
|
|
948
|
+
...Ct(e),
|
|
927
949
|
...g ? { copyLoader: g } : {}
|
|
928
950
|
})))
|
|
929
951
|
}), 0;
|
|
@@ -934,13 +956,13 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
934
956
|
});
|
|
935
957
|
}
|
|
936
958
|
}
|
|
937
|
-
let _ = await
|
|
938
|
-
...
|
|
959
|
+
let _ = await D.runPromise(Te({
|
|
960
|
+
...bt(e, i, r),
|
|
939
961
|
store: s,
|
|
940
962
|
bundleDir: r,
|
|
941
963
|
mode: i,
|
|
942
|
-
onConflict:
|
|
943
|
-
atomic:
|
|
964
|
+
onConflict: a,
|
|
965
|
+
atomic: X(e, i),
|
|
944
966
|
verify: !e.includes("--no-verify"),
|
|
945
967
|
targetDialect: G(),
|
|
946
968
|
allowIncompatible: l,
|
|
@@ -948,20 +970,20 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
948
970
|
force: l,
|
|
949
971
|
onWarn: p,
|
|
950
972
|
onProgress: H,
|
|
951
|
-
...
|
|
973
|
+
...Ct(e),
|
|
952
974
|
...h ? { assets: De(h) } : {},
|
|
953
975
|
...g ? { copyLoader: g } : {}
|
|
954
976
|
})).catch((e) => {
|
|
955
|
-
if (
|
|
977
|
+
if (Q(e)) return Et;
|
|
956
978
|
throw e;
|
|
957
979
|
}).finally(() => g?.close());
|
|
958
|
-
return typeof _ == "symbol" ? 1 : (
|
|
980
|
+
return typeof _ == "symbol" ? 1 : (Tt(e, {
|
|
959
981
|
bundleDir: r,
|
|
960
|
-
...
|
|
982
|
+
...wt(_),
|
|
961
983
|
assets: _.manifest.assets.count
|
|
962
984
|
}), 0);
|
|
963
|
-
},
|
|
964
|
-
let e =
|
|
985
|
+
}, kt = () => {
|
|
986
|
+
let e = o();
|
|
965
987
|
return {
|
|
966
988
|
...e.url ? { url: e.url } : {},
|
|
967
989
|
...e.host ? { host: e.host } : {},
|
|
@@ -970,42 +992,42 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
970
992
|
...e.password ? { password: e.password } : {},
|
|
971
993
|
...e.database ? { database: e.database } : {}
|
|
972
994
|
};
|
|
973
|
-
},
|
|
995
|
+
}, At = async (e) => {
|
|
974
996
|
let t = W(e);
|
|
975
997
|
if (!t) return V.error("usage: voltro data backup <outDir> [--assets] (native pg_dump/mariadb-dump/… + consistent artifact)"), 1;
|
|
976
|
-
let n = G(), r = e.includes("--assets"), { mkdir: i, writeFile: a } = await import("node:fs/promises"), { join: o } = await import("node:path"), s = await
|
|
998
|
+
let n = G(), r = e.includes("--assets"), { mkdir: i, writeFile: a } = await import("node:fs/promises"), { join: o } = await import("node:path"), s = await Mt(), c = r ? O() : void 0;
|
|
977
999
|
if (r && !c) return V.error("--assets: this app has no storage provider configured, so there are no blobs to capture.\n Install `storagePlugin(...)` in app.config.ts or set STORAGE_PROVIDER, or drop the\n flag to take the rows-only dump."), 1;
|
|
978
1000
|
await i(t, { recursive: !0 });
|
|
979
|
-
let l = o(t,
|
|
1001
|
+
let l = o(t, j(n)), u = Pt(s), d = Ft(s), f = u ? await We(u, {
|
|
980
1002
|
direction: "backup",
|
|
981
1003
|
dialect: n,
|
|
982
1004
|
artifact: l,
|
|
983
1005
|
assets: r
|
|
984
|
-
}) : void 0,
|
|
985
|
-
if (
|
|
986
|
-
let
|
|
1006
|
+
}) : void 0, p = await Ke(Ee(ge(n, kt(), l)));
|
|
1007
|
+
if (p !== void 0) return u && f && await z(u, f, { failure: p }), V.error(`native backup failed: ${p}`), 1;
|
|
1008
|
+
let m = await Xe(n), h = await Ye(), g = (/* @__PURE__ */ new Date()).toISOString(), _ = async (e) => {
|
|
987
1009
|
let r = Ve({
|
|
988
1010
|
dialect: n,
|
|
989
|
-
schemaFingerprint:
|
|
990
|
-
voltroVersion:
|
|
991
|
-
createdAt:
|
|
1011
|
+
schemaFingerprint: m,
|
|
1012
|
+
voltroVersion: h,
|
|
1013
|
+
createdAt: g,
|
|
992
1014
|
assets: e
|
|
993
1015
|
});
|
|
994
1016
|
return await a(o(t, R), `${JSON.stringify(r, null, 2)}\n`, "utf8"), r;
|
|
995
|
-
},
|
|
996
|
-
if (c &&
|
|
997
|
-
let e = o(t,
|
|
1017
|
+
}, v = 0, y = 0, b = [], x = 0, S = 0, C = 0;
|
|
1018
|
+
if (c && u) {
|
|
1019
|
+
let e = o(t, k);
|
|
998
1020
|
await i(e, { recursive: !0 });
|
|
999
|
-
let n = o(t,
|
|
1000
|
-
source: Oe(c, () =>
|
|
1021
|
+
let n = o(t, A), r = u, a = await D.runPromiseExit(_e({
|
|
1022
|
+
source: Oe(c, () => rt(r)),
|
|
1001
1023
|
assetsDir: e,
|
|
1002
1024
|
progress: {
|
|
1003
1025
|
done: () => !1,
|
|
1004
|
-
mark: (e, t) =>
|
|
1026
|
+
mark: (e, t) => D.tryPromise({
|
|
1005
1027
|
try: async () => {
|
|
1006
1028
|
await (await import("node:fs/promises")).appendFile(n, `${JSON.stringify(t)}\n`);
|
|
1007
1029
|
},
|
|
1008
|
-
catch: (e) => new
|
|
1030
|
+
catch: (e) => new pe({
|
|
1009
1031
|
reason: `asset index append failed: ${String(e)}`,
|
|
1010
1032
|
path: n
|
|
1011
1033
|
})
|
|
@@ -1013,34 +1035,52 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
1013
1035
|
}
|
|
1014
1036
|
}));
|
|
1015
1037
|
if (a._tag === "Failure") {
|
|
1016
|
-
let e =
|
|
1017
|
-
return
|
|
1038
|
+
let e = E.pretty(a.cause);
|
|
1039
|
+
return f && await z(u, f, { failure: `assets: ${e}` }), await _(null).catch(() => void 0), V.error(`the rows were dumped to ${l}, but the asset capture failed: ${e}\n This directory holds a ROWS-ONLY backup. Re-run with --assets once the storage
|
|
1018
1040
|
backend is reachable, or restore without --assets and accept the dangling refs.`), 1;
|
|
1019
1041
|
}
|
|
1020
|
-
|
|
1021
|
-
e.g. ${
|
|
1042
|
+
v = a.value.count, y = a.value.totalBytes, b = a.value.missing, x = a.value.objects, S = a.value.objectBytes, C = a.value.references, b.length > 0 && V.warn(`${b.length} of ${b.length + v} blob reference(s) point at objects the storage provider does not have; they are NOT in this backup and no restore can bring them back.
|
|
1043
|
+
e.g. ${b.slice(0, 3).map((e) => `'${e}'`).join(", ")}` + (b.length > 3 ? `, and ${b.length - 3} more` : ""));
|
|
1022
1044
|
}
|
|
1023
|
-
let
|
|
1024
|
-
count:
|
|
1025
|
-
totalBytes:
|
|
1045
|
+
let w = await _(r ? {
|
|
1046
|
+
count: v,
|
|
1047
|
+
totalBytes: y,
|
|
1048
|
+
references: C,
|
|
1049
|
+
objects: x,
|
|
1050
|
+
objectBytes: S
|
|
1026
1051
|
} : null);
|
|
1027
|
-
return
|
|
1052
|
+
return u && f && await z(u, f, { assets: v }), V.info("native backup complete", {
|
|
1028
1053
|
dialect: n,
|
|
1029
1054
|
artifact: l,
|
|
1030
1055
|
stamp: R,
|
|
1031
|
-
schemaFingerprint:
|
|
1032
|
-
assets: r ? `${
|
|
1033
|
-
recorded:
|
|
1056
|
+
schemaFingerprint: w.schemaFingerprint ?? "<none>",
|
|
1057
|
+
assets: r ? `${v} key(s) → ${x} object(s), ${S} byte(s) under ${k}/ (from ${C} reference(s))` + (b.length > 0 ? ` — ${b.length} reference(s) had no object and are NOT in here` : "") : "NOT included — re-run with --assets, or use `voltro data export --assets`",
|
|
1058
|
+
recorded: jt(f, d)
|
|
1034
1059
|
}), 0;
|
|
1035
|
-
},
|
|
1060
|
+
}, jt = (e, t) => e?.recorded === !0 ? "voltro data transfers" : t === void 0 ? "NOT recorded (this target keeps no transfer history)" : `NOT recorded — bookkeeping was unavailable HERE, not at the target: ${t}`, Mt = async () => {
|
|
1061
|
+
let e;
|
|
1036
1062
|
try {
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1063
|
+
e = await i(process.cwd());
|
|
1064
|
+
} catch (e) {
|
|
1065
|
+
return {
|
|
1066
|
+
unavailable: "store-unopenable",
|
|
1067
|
+
reason: `app.config.ts could not be loaded: ${Nt(e)}`
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
if (!e) return { unavailable: "no-app-config" };
|
|
1071
|
+
try {
|
|
1072
|
+
return { store: await a(e, void 0) };
|
|
1073
|
+
} catch (e) {
|
|
1074
|
+
return {
|
|
1075
|
+
unavailable: "store-unopenable",
|
|
1076
|
+
reason: Nt(e)
|
|
1077
|
+
};
|
|
1041
1078
|
}
|
|
1042
|
-
},
|
|
1043
|
-
let
|
|
1079
|
+
}, Nt = (e) => {
|
|
1080
|
+
let t = e?.message, n = typeof t == "string" && t.trim() !== "" ? t : String(e);
|
|
1081
|
+
return n.split("\n")[0] ?? n;
|
|
1082
|
+
}, Pt = (e) => "store" in e ? e.store : void 0, Ft = (e) => "store" in e ? void 0 : e.unavailable === "no-app-config" ? "no app.config.ts was found from this directory, so there is no store to record through" : e.reason, It = async (e, t) => {
|
|
1083
|
+
let n = G(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(e, j(n)), o = qe({
|
|
1044
1084
|
flagUrl: U(t, "--drill-url"),
|
|
1045
1085
|
envUrl: process.env.DRILL_DB_URL,
|
|
1046
1086
|
liveKeys: nt()
|
|
@@ -1051,11 +1091,11 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
1051
1091
|
V.info("restore drill: restoring into throwaway DB", {
|
|
1052
1092
|
dialect: n,
|
|
1053
1093
|
target: B(o.url)
|
|
1054
|
-
}), await
|
|
1094
|
+
}), await D.runPromise(Ee(Ce(n, { url: o.url }, a)));
|
|
1055
1095
|
let c = null, l = 0;
|
|
1056
1096
|
try {
|
|
1057
1097
|
let e = await et(n, { url: o.url });
|
|
1058
|
-
c =
|
|
1098
|
+
c = ce(e), l = e.tables.length;
|
|
1059
1099
|
} catch (e) {
|
|
1060
1100
|
return V.error(`restore --drill: could not introspect the restored DB — ${String(e)}`), 1;
|
|
1061
1101
|
}
|
|
@@ -1066,61 +1106,66 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
1066
1106
|
});
|
|
1067
1107
|
for (let e of u.lines) u.pass ? V.info(`restore drill: ${e}`) : V.error(`restore drill: ${e}`);
|
|
1068
1108
|
return +!u.pass;
|
|
1069
|
-
},
|
|
1109
|
+
}, Lt = async (e) => {
|
|
1070
1110
|
let t = W(e);
|
|
1071
|
-
if (!t) return V.error("usage: voltro data restore <backupDir> [--assets] [--allow-live] [--api-url <url>] [--force] [--drill [--drill-url <url>]] (native pg_restore/mariadb/…)"), 1;
|
|
1072
|
-
if (e.includes("--drill")) return
|
|
1111
|
+
if (!t) return V.error("usage: voltro data restore <backupDir> [--assets] [--allow-live] [--api-url <url>] [--force] [--no-marker] [--drill [--drill-url <url>]] (native pg_restore/mariadb/…)"), 1;
|
|
1112
|
+
if (e.includes("--drill")) return It(t, e);
|
|
1073
1113
|
if (!await Qe(e)) return 1;
|
|
1074
|
-
let n = G(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(t,
|
|
1114
|
+
let n = G(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(t, j(n)), o = e.includes("--assets"), s = Ue({
|
|
1075
1115
|
stamp: await i(r(t, R), "utf8").then(He, () => null),
|
|
1076
1116
|
currentDialect: n,
|
|
1077
|
-
|
|
1117
|
+
targetFingerprint: await Xe(n)
|
|
1078
1118
|
});
|
|
1079
1119
|
for (let e of s.info) V.info(`backup stamp: ${e}`);
|
|
1080
1120
|
if (s.warn && V.warn(s.warn), s.refuse) {
|
|
1081
1121
|
if (!e.includes("--force")) return V.error(`restore refused: ${s.refuse} (pass --force to override)`), 1;
|
|
1082
1122
|
V.warn(`restore proceeding despite: ${s.refuse} (--force)`);
|
|
1083
1123
|
}
|
|
1084
|
-
let c = r(t,
|
|
1085
|
-
if (o && !l) return V.error(`--assets: this backup carries no assets — there is no ${
|
|
1124
|
+
let c = r(t, A), l = await i(c, "utf8").then(() => !0, () => !1);
|
|
1125
|
+
if (o && !l) return V.error(`--assets: this backup carries no assets — there is no ${A} in ${t}.\n It was taken without --assets, so its rows will reference blobs this restore cannot
|
|
1086
1126
|
put back. Restore from a backup taken with --assets, or drop the flag to accept that.`), 1;
|
|
1087
1127
|
!o && l && V.warn("this backup CARRIES assets and --assets was not passed: the rows will be restored and the blobs will not. Pass --assets to restore both.");
|
|
1088
|
-
let u = await
|
|
1128
|
+
let u = await Mt(), d = o ? O() : void 0;
|
|
1089
1129
|
if (o && !d) return V.error("--assets: this app has no storage provider configured, so there is nowhere to put the blobs.\n Install `storagePlugin(...)` in app.config.ts or set STORAGE_PROVIDER, or drop the flag."), 1;
|
|
1090
|
-
let f = u ? await Ge(
|
|
1091
|
-
if (
|
|
1092
|
-
|
|
1093
|
-
database.
|
|
1094
|
-
|
|
1130
|
+
let f = Ft(u), p = e.includes("--no-marker"), m = Pt(u), h = m ? await Ge(m, { artifact: a }) : void 0, g = f === void 0 ? h === void 0 ? `the marker row could not be written to \`${b}\` (run \`voltro db apply\` so the table exists)` : void 0 : `bookkeeping is unavailable: ${f}`;
|
|
1131
|
+
if (g !== void 0 && !p) return V.error(`refusing to restore: the in-progress marker cannot be written.
|
|
1132
|
+
reason: ${g}\n The marker is one row in \`${b}\`, written before the first\n destructive statement so a killed restore refuses the next boot instead of serving a
|
|
1133
|
+
half-loaded database. Without it this restore has no guard at all.
|
|
1134
|
+
Fix the reason above, or pass --no-marker to restore WITHOUT that protection,
|
|
1135
|
+
deliberately.`), 1;
|
|
1136
|
+
g !== void 0 && V.warn(`--no-marker: restoring with NO in-progress marker. If this run does not finish, nothing
|
|
1137
|
+
will stop the next boot from serving a half-loaded database.
|
|
1138
|
+
${g}`);
|
|
1139
|
+
let _ = m ? await We(m, {
|
|
1095
1140
|
direction: "restore",
|
|
1096
1141
|
dialect: n,
|
|
1097
1142
|
artifact: a,
|
|
1098
1143
|
assets: o
|
|
1099
|
-
}) : void 0,
|
|
1100
|
-
if (
|
|
1101
|
-
and hand-made dumps.`) :
|
|
1102
|
-
result of this command before you start the app.`),
|
|
1103
|
-
let
|
|
1144
|
+
}) : void 0, v = await Ke(Ee(Ce(n, kt(), a))), y = h === void 0 ? "lost" : await h.reassert();
|
|
1145
|
+
if (y === "rewritten" ? V.warn(`the restore artefact removed the in-progress marker (it carries \`${b}\`) — it has been written back.\n Backups taken from this version on exclude that table, so this only affects older
|
|
1146
|
+
and hand-made dumps.`) : y === "lost" && V.error(`the restore artefact removed the in-progress marker and it could NOT be written back.\n \`${b}\` is unwritable, so if this restore does not finish,\n nothing will stop the next boot from serving a half-loaded database. Check the
|
|
1147
|
+
result of this command before you start the app.`), v !== void 0) return m && _ && await z(m, _, { failure: v }), V.error(`native restore failed: ${v}\n` + (y === "lost" ? " This database is now in an unknown state and NOTHING WILL STOP THE NEXT BOOT — see above.\n" : " This database is now in an unknown state and the next boot will REFUSE, by design.\n") + " Re-run the restore to completion, or clear the marker deliberately with\n `voltro data clear-replace-marker --yes` once you have decided the state is correct."), 1;
|
|
1148
|
+
let x = 0, S = 0;
|
|
1104
1149
|
if (d) {
|
|
1105
|
-
let e = await
|
|
1150
|
+
let e = await D.runPromiseExit(Se({
|
|
1106
1151
|
sink: De(d),
|
|
1107
|
-
assetsDir: r(t,
|
|
1152
|
+
assetsDir: r(t, k),
|
|
1108
1153
|
indexPath: c
|
|
1109
1154
|
}));
|
|
1110
1155
|
if (e._tag === "Failure") {
|
|
1111
|
-
let t =
|
|
1112
|
-
return
|
|
1156
|
+
let t = E.pretty(e.cause);
|
|
1157
|
+
return m && _ && await z(m, _, { failure: `assets: ${t}` }), V.error(`the rows were restored, but the asset restore failed: ${t}\n The in-progress marker is still set and the next boot will refuse. Re-run
|
|
1113
1158
|
\`voltro data restore <dir> --assets\` once storage is reachable.`), 1;
|
|
1114
1159
|
}
|
|
1115
|
-
|
|
1160
|
+
x = e.value.count, S = e.value.objects;
|
|
1116
1161
|
}
|
|
1117
|
-
return
|
|
1162
|
+
return h && await h.clear(), m && _ && await z(m, _, { assets: x }), V.info("native restore complete", {
|
|
1118
1163
|
dialect: n,
|
|
1119
1164
|
artifact: a,
|
|
1120
|
-
assets: o ? `${
|
|
1121
|
-
recorded:
|
|
1165
|
+
assets: o ? `${x} key(s) restored from ${S} object(s)` : "not restored (no --assets)",
|
|
1166
|
+
recorded: jt(_, f)
|
|
1122
1167
|
}), 0;
|
|
1123
|
-
},
|
|
1168
|
+
}, Rt = async (e) => {
|
|
1124
1169
|
let t = W(e);
|
|
1125
1170
|
if (!t) return V.error("usage: voltro data inspect <file.vbundle|dir> [--json] [--passphrase <p>]"), 1;
|
|
1126
1171
|
let { resolve: n, join: r } = await import("node:path"), i = await import("node:fs/promises"), a = n(process.cwd(), t);
|
|
@@ -1133,19 +1178,19 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
1133
1178
|
let s = await i.readFile(n, "utf8").catch(() => void 0);
|
|
1134
1179
|
return s === void 0 ? (V.error(`'${t}' is a directory but holds no manifest.json — is it an unpacked bundle? (a bundle exported with --target api is always unpacked into a directory, even when the path ends in .vbundle)`), 1) : (console.log(s), 0);
|
|
1135
1180
|
}
|
|
1136
|
-
let o =
|
|
1137
|
-
let e =
|
|
1138
|
-
return o ?
|
|
1181
|
+
let o = J(e), s = () => {
|
|
1182
|
+
let e = Y(a);
|
|
1183
|
+
return o ? M(e, o) : e;
|
|
1139
1184
|
};
|
|
1140
1185
|
if (e.includes("--json")) {
|
|
1141
|
-
let e = (await
|
|
1186
|
+
let e = (await N(s(), ["manifest.json"])).get("manifest.json");
|
|
1142
1187
|
return e ? (console.log(e.toString("utf8")), 0) : (V.error("no manifest.json found in the bundle"), 1);
|
|
1143
1188
|
}
|
|
1144
|
-
let c = (await
|
|
1189
|
+
let c = (await N(s(), ["README.md"])).get("README.md");
|
|
1145
1190
|
if (c) return console.log(c.toString("utf8")), 0;
|
|
1146
|
-
let l = (await
|
|
1191
|
+
let l = (await N(s(), ["manifest.json"])).get("manifest.json");
|
|
1147
1192
|
return l ? (console.log(l.toString("utf8")), 0) : (V.error("bundle has no README.md or manifest.json"), 1);
|
|
1148
|
-
},
|
|
1193
|
+
}, zt = async (e) => {
|
|
1149
1194
|
let { REPLACE_IN_PROGRESS_TABLE: t } = await import("@voltro/database"), { interruptedReplaceAtBoot: n } = await import("./interruptedReplace-CvmiAM9K.js"), { store: r } = await K(), i = await n(r);
|
|
1150
1195
|
if (i === void 0) return V.info("no interrupted replace is recorded — nothing to clear"), 0;
|
|
1151
1196
|
if (!e.includes("--yes")) return V.error(`${i}\n\n Re-run with --yes to clear it.`), 1;
|
|
@@ -1159,12 +1204,12 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
1159
1204
|
});
|
|
1160
1205
|
for (let e of a) await r.delete(t, String(e.id));
|
|
1161
1206
|
return V.info(`cleared ${a.length} interrupted-replace marker(s) — the next boot will start`), 0;
|
|
1162
|
-
},
|
|
1207
|
+
}, Bt = async (e) => {
|
|
1163
1208
|
let { STAGING_PREFIX: t, dropStagingSql: n, execStatements: r } = await import("@voltro/data-transfer"), { store: i } = await K(), a = G();
|
|
1164
1209
|
if (a !== "postgres" && a !== "mysql" && a !== "mariadb" && a !== "sqlite" && a !== "mssql") return V.error(`this store has no staging tables to clear (dialect: ${a})`), 1;
|
|
1165
1210
|
let { introspectSchema: o } = await import("@voltro/database/sql"), s = (await i.run((await import("@effect/sql")).SqlClient.SqlClient.pipe((await import("effect")).Effect.flatMap(o)))).tables.map((e) => e.name).filter((e) => e.startsWith(t));
|
|
1166
1211
|
return s.length === 0 ? (V.info("no staging tables are present — nothing to clear"), 0) : e.includes("--yes") ? (await r(i, s.map((e) => n(e.slice(t.length), a))), V.info(`dropped ${s.length} staging table(s)`), 0) : (V.error(`${s.length} staging table(s) from an earlier \`--mode replace\`:\n` + s.map((e) => ` ${e}`).join("\n") + "\n\n Each holds a copy of what a run was loading. Nothing else removes them.\n Make sure no import is running right now — this cannot tell a leftover from one in flight.\n Re-run with --yes to drop them."), 1);
|
|
1167
|
-
},
|
|
1212
|
+
}, Vt = async (e) => {
|
|
1168
1213
|
let { describeTransferRun: t, DATA_TRANSFERS_TABLE: n } = await import("@voltro/database"), r = Number(U(e, "--limit") ?? "20"), i = Number.isFinite(r) ? Math.max(1, Math.min(200, Math.trunc(r))) : 20;
|
|
1169
1214
|
if (U(e, "--target") === "api") {
|
|
1170
1215
|
let t = U(e, "--api-url");
|
|
@@ -1207,15 +1252,15 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
1207
1252
|
})}`);
|
|
1208
1253
|
}
|
|
1209
1254
|
return 0;
|
|
1210
|
-
},
|
|
1255
|
+
}, Ht = async (e) => {
|
|
1211
1256
|
let t = W(e), n = W(e.filter((e) => e !== t));
|
|
1212
1257
|
if (!t || !n) return V.error("usage: voltro data unpack <file.vbundle> <dir> [--passphrase <p>]"), 1;
|
|
1213
|
-
let { resolve: r } = await import("node:path"), i =
|
|
1214
|
-
return a && (i =
|
|
1258
|
+
let { resolve: r } = await import("node:path"), i = Y(r(process.cwd(), t)), a = J(e);
|
|
1259
|
+
return a && (i = M(i, a)), await Me(i, r(process.cwd(), n)), V.info("unpack complete", {
|
|
1215
1260
|
file: t,
|
|
1216
1261
|
dir: n
|
|
1217
1262
|
}), 0;
|
|
1218
|
-
},
|
|
1263
|
+
}, $ = {
|
|
1219
1264
|
export: {
|
|
1220
1265
|
common: [
|
|
1221
1266
|
"--target",
|
|
@@ -1291,44 +1336,45 @@ var Fe = /* @__PURE__ */ new Set([
|
|
|
1291
1336
|
"--assets",
|
|
1292
1337
|
"--allow-live",
|
|
1293
1338
|
"--force",
|
|
1339
|
+
"--no-marker",
|
|
1294
1340
|
"--drill",
|
|
1295
1341
|
"--drill-url",
|
|
1296
1342
|
"--api-url"
|
|
1297
1343
|
] }
|
|
1298
|
-
},
|
|
1299
|
-
let n =
|
|
1344
|
+
}, Ut = (e) => e.split("=")[0], Wt = (e, t) => {
|
|
1345
|
+
let n = $[e];
|
|
1300
1346
|
if (!n) return;
|
|
1301
1347
|
let r = U(t, "--target") === "api" ? "api" : "direct", i = /* @__PURE__ */ new Set([...n.common, ...r === "api" ? n.apiOnly ?? [] : n.directOnly ?? []]), a = new Set(r === "api" ? n.directOnly ?? [] : n.apiOnly ?? []);
|
|
1302
1348
|
for (let n of t) {
|
|
1303
1349
|
if (!n.startsWith("--")) continue;
|
|
1304
|
-
let t =
|
|
1350
|
+
let t = Ut(n);
|
|
1305
1351
|
if (i.has(t)) continue;
|
|
1306
1352
|
if (a.has(t)) return `voltro data ${e}: ${t} is not read with --target ${r} (it is a --target ${r === "api" ? "direct" : "api"} flag). Remove it, or change --target.`;
|
|
1307
|
-
let o = Object.entries(
|
|
1353
|
+
let o = Object.entries($).filter(([n, r]) => n !== e && [
|
|
1308
1354
|
...r.common,
|
|
1309
1355
|
...r.directOnly ?? [],
|
|
1310
1356
|
...r.apiOnly ?? []
|
|
1311
1357
|
].includes(t)).map(([e]) => e);
|
|
1312
1358
|
return o.length > 0 ? `voltro data ${e}: ${t} is not a \`${e}\` flag (it belongs to \`voltro data ${o.join("` / `")}\`). Remove it.` : `voltro data ${e}: unknown flag ${t}. Run \`voltro data --help\` for the flags this command reads.`;
|
|
1313
1359
|
}
|
|
1314
|
-
},
|
|
1315
|
-
export:
|
|
1316
|
-
import:
|
|
1317
|
-
transfers:
|
|
1318
|
-
inspect:
|
|
1319
|
-
unpack:
|
|
1320
|
-
backup:
|
|
1321
|
-
restore:
|
|
1322
|
-
"clear-replace-marker":
|
|
1323
|
-
"clear-staging":
|
|
1324
|
-
},
|
|
1360
|
+
}, Gt = {
|
|
1361
|
+
export: xt,
|
|
1362
|
+
import: Ot,
|
|
1363
|
+
transfers: Vt,
|
|
1364
|
+
inspect: Rt,
|
|
1365
|
+
unpack: Ht,
|
|
1366
|
+
backup: At,
|
|
1367
|
+
restore: Lt,
|
|
1368
|
+
"clear-replace-marker": zt,
|
|
1369
|
+
"clear-staging": Bt
|
|
1370
|
+
}, Kt = async (n) => {
|
|
1325
1371
|
let [r, ...i] = n;
|
|
1326
|
-
if (r !== void 0 &&
|
|
1327
|
-
let e =
|
|
1372
|
+
if (r !== void 0 && $[r] !== void 0) {
|
|
1373
|
+
let e = Wt(r, i);
|
|
1328
1374
|
if (e) return V.error(e), 2;
|
|
1329
1375
|
}
|
|
1330
|
-
let a = r === void 0 ? void 0 :
|
|
1376
|
+
let a = r === void 0 ? void 0 : Gt[r];
|
|
1331
1377
|
return a === void 0 ? (V.error(`usage: voltro data ${e(t)} … (logical: export/import; native: backup/restore; \`imports\` reads the history, incl. a run in flight)`), r ? 2 : 1) : a(i);
|
|
1332
1378
|
};
|
|
1333
1379
|
//#endregion
|
|
1334
|
-
export {
|
|
1380
|
+
export { Kt as runDataCommand };
|