@voltro/data-transfer 0.50.0 → 0.50.1
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 +56 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +423 -389
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { Cause as e, Data as t, Effect as n, Exit as r, Metric as i, MetricBoundaries as a, Runtime as o, Schedule as s, Schema as c, Stream as l } from "effect";
|
|
2
2
|
import { DATA_TRANSFERS_TABLE as u, REPLACE_IN_PROGRESS_TABLE as d, _voltroDataTransfersTable as f, classifyConstraintViolation as p, derivedRowId as m, ensureTableRegistered as h, eq as g, extractDbCause as _, getTable as v, inSet as y, isNotNull as b, or as x, recordsTable as S, registerTable as C, streamTable as w, suspendWriteRecorders as ee, suspendWriteRecordersEffect as te, unregisterTable as ne } from "@voltro/database";
|
|
3
3
|
import { fingerprintSchema as re } from "@voltro/database/sql";
|
|
4
|
-
import { createCipheriv as
|
|
5
|
-
import { copyFile as ce, createReadStream as le, createWriteStream as O, existsSync as
|
|
6
|
-
import { STORAGE_REFS_TABLE as
|
|
7
|
-
import * as
|
|
8
|
-
import { PassThrough as
|
|
9
|
-
import { SqlClient as
|
|
10
|
-
import { mkdir as
|
|
11
|
-
import { basename as
|
|
12
|
-
import { promisify as
|
|
13
|
-
import { spawn as
|
|
4
|
+
import { createCipheriv as T, createDecipheriv as E, createHash as D, createHmac as ie, randomBytes as ae, randomUUID as oe, scrypt as se } from "node:crypto";
|
|
5
|
+
import { copyFile as ce, createReadStream as le, createWriteStream as O, existsSync as ue, rename as de, statSync as fe, unlinkSync as k } from "node:fs";
|
|
6
|
+
import { STORAGE_REFS_TABLE as pe, fromNodeReadable as me, getObjectStream as A, putObjectStream as j, toNodeReadable as he } from "@voltro/plugin-storage";
|
|
7
|
+
import * as M from "node:zlib";
|
|
8
|
+
import { PassThrough as N, Readable as ge } from "node:stream";
|
|
9
|
+
import { SqlClient as _e } from "@effect/sql";
|
|
10
|
+
import { mkdir as P, readdir as F, stat as ve } from "node:fs/promises";
|
|
11
|
+
import { basename as I, delimiter as L, dirname as ye, join as R, resolve as be, sep as xe } from "node:path";
|
|
12
|
+
import { promisify as Se } from "node:util";
|
|
13
|
+
import { spawn as Ce } from "node:child_process";
|
|
14
14
|
//#region src/consistency.ts
|
|
15
|
-
var
|
|
15
|
+
var we = (e) => {
|
|
16
16
|
switch (e) {
|
|
17
17
|
case "postgres": return ["SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"];
|
|
18
18
|
case "mysql":
|
|
@@ -22,7 +22,7 @@ var Ce = (e) => {
|
|
|
22
22
|
case "turso": return [];
|
|
23
23
|
default: return [];
|
|
24
24
|
}
|
|
25
|
-
},
|
|
25
|
+
}, Te = {
|
|
26
26
|
email: { fake: "email" },
|
|
27
27
|
fullName: { fake: "fullName" },
|
|
28
28
|
firstName: { fake: "firstName" },
|
|
@@ -37,7 +37,7 @@ var Ce = (e) => {
|
|
|
37
37
|
date: "dateShift",
|
|
38
38
|
secret: "null",
|
|
39
39
|
freeText: "redact"
|
|
40
|
-
},
|
|
40
|
+
}, Ee = (e) => {
|
|
41
41
|
let t = {};
|
|
42
42
|
for (let n of e.tables) {
|
|
43
43
|
let e = {};
|
|
@@ -49,15 +49,15 @@ var Ce = (e) => {
|
|
|
49
49
|
t[n.name] = e;
|
|
50
50
|
}
|
|
51
51
|
return t;
|
|
52
|
-
},
|
|
52
|
+
}, De = (e, t, n, r) => {
|
|
53
53
|
let i = r.columns?.[`${e}.${t}`];
|
|
54
54
|
if (i) return i;
|
|
55
55
|
if (n?.sensitive) {
|
|
56
56
|
let e = n.sensitive.class;
|
|
57
|
-
return r.classes?.[e] ??
|
|
57
|
+
return r.classes?.[e] ?? Te[e] ?? "redact";
|
|
58
58
|
}
|
|
59
59
|
return n?.safe ? r.onSafe ?? "keep" : n?.columnType === "id" || n?.columnType === "reference" ? "keep" : r.onUnclassified ?? "error";
|
|
60
|
-
},
|
|
60
|
+
}, Oe = (e, t) => ie("sha256", e).update(t == null ? "∅" : String(t)).digest(), z = (e, t) => e.readUInt32BE(t * 4 % (e.length - 4)), ke = [
|
|
61
61
|
"Ada",
|
|
62
62
|
"Alan",
|
|
63
63
|
"Grace",
|
|
@@ -70,7 +70,7 @@ var Ce = (e) => {
|
|
|
70
70
|
"Guido",
|
|
71
71
|
"Margaret",
|
|
72
72
|
"Bjarne"
|
|
73
|
-
],
|
|
73
|
+
], Ae = [
|
|
74
74
|
"Lovelace",
|
|
75
75
|
"Turing",
|
|
76
76
|
"Hopper",
|
|
@@ -83,7 +83,7 @@ var Ce = (e) => {
|
|
|
83
83
|
"Rossum",
|
|
84
84
|
"Hamilton",
|
|
85
85
|
"Stroustrup"
|
|
86
|
-
],
|
|
86
|
+
], je = [
|
|
87
87
|
"Maple",
|
|
88
88
|
"Oak",
|
|
89
89
|
"Cedar",
|
|
@@ -92,7 +92,7 @@ var Ce = (e) => {
|
|
|
92
92
|
"Birch",
|
|
93
93
|
"Willow",
|
|
94
94
|
"Ash"
|
|
95
|
-
],
|
|
95
|
+
], Me = [
|
|
96
96
|
"Initech",
|
|
97
97
|
"Hooli",
|
|
98
98
|
"Umbrella",
|
|
@@ -101,23 +101,23 @@ var Ce = (e) => {
|
|
|
101
101
|
"Soylent",
|
|
102
102
|
"Stark",
|
|
103
103
|
"Wayne"
|
|
104
|
-
], B = (e, t, n) => e[z(t, n) % e.length],
|
|
105
|
-
let r =
|
|
104
|
+
], B = (e, t, n) => e[z(t, n) % e.length], Ne = (e, t, n) => {
|
|
105
|
+
let r = Oe(n, `${e}:${String(t)}`), i = z(r, 1) % 1e4;
|
|
106
106
|
switch (e) {
|
|
107
|
-
case "email": return `${B(
|
|
108
|
-
case "fullName": return `${B(
|
|
109
|
-
case "firstName": return B(
|
|
110
|
-
case "lastName": return B(
|
|
111
|
-
case "username": return `${B(
|
|
107
|
+
case "email": return `${B(ke, r, 0).toLowerCase()}.${B(Ae, r, 2).toLowerCase()}${i}@example.com`;
|
|
108
|
+
case "fullName": return `${B(ke, r, 0)} ${B(Ae, r, 1)}`;
|
|
109
|
+
case "firstName": return B(ke, r, 0);
|
|
110
|
+
case "lastName": return B(Ae, r, 1);
|
|
111
|
+
case "username": return `${B(ke, r, 0).toLowerCase()}${i}`;
|
|
112
112
|
case "phone": return `+1${String(z(r, 0) % 1e10).padStart(10, "0")}`;
|
|
113
|
-
case "address": return `${z(r, 0) % 9899 + 100} ${B(
|
|
114
|
-
case "company": return B(
|
|
113
|
+
case "address": return `${z(r, 0) % 9899 + 100} ${B(je, r, 1)} St`;
|
|
114
|
+
case "company": return B(Me, r, 0);
|
|
115
115
|
case "url": return `https://example.com/${r.toString("hex").slice(0, 12)}`;
|
|
116
116
|
case "ip": return `${z(r, 0) % 256}.${z(r, 1) % 256}.${z(r, 2) % 256}.${z(r, 3) % 254 + 1}`;
|
|
117
|
-
case "creditCard": return
|
|
117
|
+
case "creditCard": return Pe(`4${r.toString("hex").replace(/\D/g, "").padEnd(14, "0").slice(0, 14)}`);
|
|
118
118
|
default: return `${e}_${r.toString("hex").slice(0, 8)}`;
|
|
119
119
|
}
|
|
120
|
-
},
|
|
120
|
+
}, Pe = (e) => {
|
|
121
121
|
let t = e.slice(0, 15).split("").map(Number), n = 0;
|
|
122
122
|
t.forEach((e, t) => {
|
|
123
123
|
let r = e;
|
|
@@ -125,31 +125,31 @@ var Ce = (e) => {
|
|
|
125
125
|
});
|
|
126
126
|
let r = (10 - n % 10) % 10;
|
|
127
127
|
return e.slice(0, 15) + String(r);
|
|
128
|
-
},
|
|
128
|
+
}, Fe = 864e5, Ie = (e, t) => {
|
|
129
129
|
let n = e instanceof Date ? e.getTime() : Date.parse(String(e));
|
|
130
130
|
if (Number.isNaN(n)) return e;
|
|
131
|
-
let r = z(
|
|
131
|
+
let r = z(Oe(t, "date-shift-offset"), 0) % 730 - 365, i = new Date(n + r * Fe);
|
|
132
132
|
return e instanceof Date ? i : i.toISOString();
|
|
133
|
-
},
|
|
133
|
+
}, Le = (e, t) => {
|
|
134
134
|
if (t.value === null || t.value === void 0) return null;
|
|
135
135
|
if (e === "error") throw Error(`masking: unresolved 'error' action for ${t.table}.${t.column}`);
|
|
136
136
|
if (e === "keep") return t.value;
|
|
137
137
|
if (e === "null") return null;
|
|
138
138
|
if (e === "redact") return t.columnType === "text" || typeof t.value == "string" ? "[redacted]" : null;
|
|
139
|
-
if (e === "hash") return
|
|
140
|
-
if (e === "dateShift") return
|
|
141
|
-
if (typeof e == "object" && "fake" in e) return
|
|
139
|
+
if (e === "hash") return Oe(t.seed, t.value).toString("hex").slice(0, 16);
|
|
140
|
+
if (e === "dateShift") return Ie(t.value, t.seed);
|
|
141
|
+
if (typeof e == "object" && "fake" in e) return Ne(e.fake, t.value, t.seed);
|
|
142
142
|
if (typeof e == "object" && "custom" in e) return e.custom(t);
|
|
143
143
|
throw Error(`masking: '${t.table}.${t.column}' resolved to an action this build does not understand (${JSON.stringify(e)}). Refusing to copy the value through. Valid actions: 'keep' | 'null' | 'redact' | 'hash' | 'dateShift' | { fake: '<class>' } | { custom: fn }.`);
|
|
144
|
-
},
|
|
144
|
+
}, Re = (e) => typeof e == "string" ? e === "keep" || e === "null" || e === "redact" || e === "hash" || e === "dateShift" || e === "error" : typeof e != "object" || !e ? !1 : "fake" in e ? typeof e.fake == "string" : "custom" in e && typeof e.custom == "function", ze = (e, t, n) => {
|
|
145
145
|
let r = {}, i = [], a = [];
|
|
146
146
|
for (let o of e) for (let e of o.columns) {
|
|
147
|
-
let s = `${o.name}.${e.name}`, c =
|
|
147
|
+
let s = `${o.name}.${e.name}`, c = De(o.name, e.name, t[o.name]?.[e.name], n);
|
|
148
148
|
if (c === "error") {
|
|
149
149
|
i.push(s);
|
|
150
150
|
continue;
|
|
151
151
|
}
|
|
152
|
-
if (!
|
|
152
|
+
if (!Re(c)) {
|
|
153
153
|
a.push({
|
|
154
154
|
column: s,
|
|
155
155
|
action: c
|
|
@@ -163,7 +163,7 @@ var Ce = (e) => {
|
|
|
163
163
|
unclassified: i,
|
|
164
164
|
invalid: a
|
|
165
165
|
};
|
|
166
|
-
},
|
|
166
|
+
}, Be = [
|
|
167
167
|
{
|
|
168
168
|
name: "email",
|
|
169
169
|
re: /[\w.+-]+@[\w-]+\.[\w.-]+/
|
|
@@ -180,7 +180,7 @@ var Ce = (e) => {
|
|
|
180
180
|
name: "creditCard",
|
|
181
181
|
re: /\b(?:\d[ -]?){13,16}\b/
|
|
182
182
|
}
|
|
183
|
-
],
|
|
183
|
+
], Ve = (e, t, n) => {
|
|
184
184
|
let r = [], i = /* @__PURE__ */ new Set();
|
|
185
185
|
for (let [a, o] of Object.entries(n)) {
|
|
186
186
|
if (!a.startsWith(`${t}.`) || o !== "keep") continue;
|
|
@@ -188,7 +188,7 @@ var Ce = (e) => {
|
|
|
188
188
|
for (let a of e) {
|
|
189
189
|
let e = a[n];
|
|
190
190
|
if (typeof e != "string" || e.length === 0) continue;
|
|
191
|
-
let o =
|
|
191
|
+
let o = Be.find((t) => t.re.test(e));
|
|
192
192
|
if (o && !i.has(n)) {
|
|
193
193
|
i.add(n), r.push({
|
|
194
194
|
table: t,
|
|
@@ -201,9 +201,9 @@ var Ce = (e) => {
|
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
203
|
return r;
|
|
204
|
-
},
|
|
204
|
+
}, He = (e, t, n, r, i) => {
|
|
205
205
|
let a = {};
|
|
206
|
-
for (let [o, s] of Object.entries(e)) a[o] =
|
|
206
|
+
for (let [o, s] of Object.entries(e)) a[o] = Le(n[`${t}.${o}`] ?? "keep", {
|
|
207
207
|
value: s,
|
|
208
208
|
table: t,
|
|
209
209
|
column: o,
|
|
@@ -211,7 +211,7 @@ var Ce = (e) => {
|
|
|
211
211
|
...i?.[o] ? { columnType: i[o] } : {}
|
|
212
212
|
});
|
|
213
213
|
return a;
|
|
214
|
-
},
|
|
214
|
+
}, Ue = /* @__PURE__ */ new Map([
|
|
215
215
|
["_voltro_migration_plans", "the schema fingerprint THIS deployment applied — a foreign row makes the next boot refuse"],
|
|
216
216
|
["_voltro_migrations", "which file-based migrations ran HERE — a foreign row marks unrun migrations as done"],
|
|
217
217
|
["_voltro_seeds", "which seeds ran HERE — a foreign row suppresses seeding the target still needs"],
|
|
@@ -243,7 +243,7 @@ var Ce = (e) => {
|
|
|
243
243
|
["_voltro_notification_held", "notifications waiting to be SENT from here — a foreign row makes the target deliver something queued elsewhere"],
|
|
244
244
|
["_voltro_webhook_event_stats", "per-deployment delivery counters a backoff decision reads — foreign counts steer the target's retries"],
|
|
245
245
|
["_voltro_webhook_rate_windows", "the live rate-limit windows this deployment is inside — a foreign window throttles or releases wrongly"]
|
|
246
|
-
]),
|
|
246
|
+
]), We = /* @__PURE__ */ new Map([
|
|
247
247
|
["_voltro_agent_threads", "conversations the app's users had — app data"],
|
|
248
248
|
["_voltro_agent_messages", "the messages in those conversations — app data"],
|
|
249
249
|
["_voltro_prompts", "prompt definitions the app authored — app data"],
|
|
@@ -274,21 +274,21 @@ var Ce = (e) => {
|
|
|
274
274
|
["_voltro_audit_log", "the app's audit trail — compliance data the app owns, not deployment bookkeeping"],
|
|
275
275
|
["_voltro_feature_flags", "the flags the app defined — app configuration"],
|
|
276
276
|
["_voltro_feature_flag_audit", "who changed which flag — belongs with the flags"]
|
|
277
|
-
]), V = (e) =>
|
|
277
|
+
]), V = (e) => Ue.has(e), Ge = (e) => Ue.get(e), Ke = (e, t) => {
|
|
278
278
|
if (e.length === 0) return;
|
|
279
|
-
let n = e.map((e) => ` ${e} — ${
|
|
279
|
+
let n = e.map((e) => ` ${e} — ${Ge(e) ?? "describes this deployment"}`);
|
|
280
280
|
return `${t} ${e.length} table(s) that describe a deployment rather than its data:\n${n.join("\n")}\n A row from another environment is not stale there, it is a false statement about this one.`;
|
|
281
281
|
}, H = class extends c.TaggedError()("BundleError", {
|
|
282
282
|
reason: c.String,
|
|
283
283
|
path: c.optional(c.String)
|
|
284
|
-
}) {},
|
|
284
|
+
}) {}, qe = class extends c.TaggedError()("CodecError", {
|
|
285
285
|
table: c.String,
|
|
286
286
|
reason: c.String
|
|
287
|
-
}) {},
|
|
287
|
+
}) {}, Je = class extends c.TaggedError()("IntegrityError", {
|
|
288
288
|
what: c.String,
|
|
289
289
|
expected: c.String,
|
|
290
290
|
actual: c.String
|
|
291
|
-
}) {},
|
|
291
|
+
}) {}, Ye = class extends t.TaggedError("CompressionError") {}, U = class extends c.TaggedError()("ScopeError", { reason: c.String }) {}, Xe = class extends c.TaggedError()("RowsRefusedError", {
|
|
292
292
|
rows: c.Array(c.Struct({
|
|
293
293
|
table: c.String,
|
|
294
294
|
id: c.String,
|
|
@@ -302,7 +302,7 @@ var Ce = (e) => {
|
|
|
302
302
|
refused: c.Number,
|
|
303
303
|
primary: c.Number
|
|
304
304
|
}))
|
|
305
|
-
}) {},
|
|
305
|
+
}) {}, Ze = class extends c.TaggedError()("SchemaDriftError", {
|
|
306
306
|
bundleFingerprint: c.String,
|
|
307
307
|
targetFingerprint: c.String,
|
|
308
308
|
diff: c.Array(c.String)
|
|
@@ -311,20 +311,20 @@ var Ce = (e) => {
|
|
|
311
311
|
let e = this.stderr?.trim(), t = this.hint?.trim();
|
|
312
312
|
return `${this.tool}: ${this.reason}${e ? `\n${e}` : ""}${t ? `\n\nhint: ${t}` : ""}`;
|
|
313
313
|
}
|
|
314
|
-
},
|
|
314
|
+
}, Qe = class extends c.TaggedError()("MaskingError", {
|
|
315
315
|
unclassified: c.Array(c.String),
|
|
316
316
|
invalidActions: c.optional(c.Array(c.String))
|
|
317
|
-
}) {},
|
|
317
|
+
}) {}, $e = class extends c.TaggedError()("ImportModeError", {
|
|
318
318
|
mode: c.String,
|
|
319
319
|
reason: c.String
|
|
320
|
-
}) {},
|
|
320
|
+
}) {}, et = class extends c.TaggedError()("CrossDialectError", {
|
|
321
321
|
sourceDialect: c.String,
|
|
322
322
|
targetDialect: c.String,
|
|
323
323
|
blocking: c.Array(c.String)
|
|
324
|
-
}) {}, G = (e, t) => e.tables.find((e) => e.name === t)?.columns.find((e) => e.type === "id")?.name ?? "id",
|
|
324
|
+
}) {}, G = (e, t) => e.tables.find((e) => e.name === t)?.columns.find((e) => e.type === "id")?.name ?? "id", tt = (e, t) => (e.tables.find((e) => e.name === t)?.columns ?? []).filter((e) => e.references).map((e) => ({
|
|
325
325
|
col: e.name,
|
|
326
326
|
refTable: e.references.table
|
|
327
|
-
})),
|
|
327
|
+
})), nt = (e, t, r) => n.gen(function* () {
|
|
328
328
|
let i = r.maxDepth ?? 12, a = new Set(r.pinned ?? []), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map(), u = (e) => {
|
|
329
329
|
let t = s.get(e) ?? /* @__PURE__ */ new Set();
|
|
330
330
|
return s.set(e, t), t;
|
|
@@ -342,7 +342,7 @@ var Ce = (e) => {
|
|
|
342
342
|
for (let t of n) d(t.refTable, e[t.col]);
|
|
343
343
|
};
|
|
344
344
|
}, p = (r, i) => {
|
|
345
|
-
let a = f(r, G(t, r),
|
|
345
|
+
let a = f(r, G(t, r), tt(t, r));
|
|
346
346
|
return l.runForEach(w(e, {
|
|
347
347
|
table: r,
|
|
348
348
|
pk: G(t, r),
|
|
@@ -377,13 +377,13 @@ var Ce = (e) => {
|
|
|
377
377
|
}
|
|
378
378
|
}
|
|
379
379
|
return o;
|
|
380
|
-
}),
|
|
380
|
+
}), rt = (e, t) => ({
|
|
381
381
|
tables: [...e.keys()],
|
|
382
382
|
predicateFor: (n) => {
|
|
383
383
|
let r = e.get(n);
|
|
384
384
|
return r ? y(G(t, n), [...r]) : void 0;
|
|
385
385
|
}
|
|
386
|
-
}),
|
|
386
|
+
}), it = "tenantId", at = (e, t, r) => n.gen(function* () {
|
|
387
387
|
let i = t.tables.map((e) => e.name), a = new Map(t.tables.map((e) => [e.name, e]));
|
|
388
388
|
if (e.kind === "all") {
|
|
389
389
|
let t = new Set(e.exclude ?? []);
|
|
@@ -403,29 +403,29 @@ var Ce = (e) => {
|
|
|
403
403
|
}
|
|
404
404
|
let o = e.tenantId;
|
|
405
405
|
if (o === void 0 || o === "") return yield* n.fail(new U({ reason: "scope { kind: 'tenant' } requires a tenantId — pass --tenant <id> (CLI) or scope.tenantId (API). Refusing to fall back to an unfiltered export." }));
|
|
406
|
-
let s = r.tenantTables ? r.tenantTables.filter((e) => a.has(e)) : i.filter((e) => a.get(e)?.columns.some((e) => e.name ===
|
|
407
|
-
if (s.length === 0) return yield* n.fail(new U({ reason: r.tenantTables ? "tenant scope: none of the provided tenantTables exist in the schema — nothing to filter." : `tenant scope: no table carries a '${
|
|
408
|
-
let c = yield*
|
|
409
|
-
seeds: Object.fromEntries(s.map((e) => [e, g(
|
|
406
|
+
let s = r.tenantTables ? r.tenantTables.filter((e) => a.has(e)) : i.filter((e) => a.get(e)?.columns.some((e) => e.name === it) ?? !1);
|
|
407
|
+
if (s.length === 0) return yield* n.fail(new U({ reason: r.tenantTables ? "tenant scope: none of the provided tenantTables exist in the schema — nothing to filter." : `tenant scope: no table carries a '${it}' column — nothing to filter. A tenant export of a schema without tenant-scoped tables would be the full database; refusing.` }));
|
|
408
|
+
let c = yield* nt(r.store, t, {
|
|
409
|
+
seeds: Object.fromEntries(s.map((e) => [e, g(it, o)])),
|
|
410
410
|
pinned: s,
|
|
411
411
|
children: { roots: s }
|
|
412
412
|
}), l = [...c.entries()].filter(([, e]) => e.size > 0).map(([e]) => e), u = new Set(s);
|
|
413
413
|
return {
|
|
414
414
|
tables: [...s, ...l],
|
|
415
|
-
predicateFor: (e) => u.has(e) ? g(
|
|
415
|
+
predicateFor: (e) => u.has(e) ? g(it, o) : c.has(e) ? y(G(t, e), [...c.get(e)]) : void 0
|
|
416
416
|
};
|
|
417
|
-
}),
|
|
417
|
+
}), ot = (e, t) => ({
|
|
418
418
|
list: t,
|
|
419
|
-
open: (t) =>
|
|
420
|
-
}),
|
|
419
|
+
open: (t) => A(e, t)
|
|
420
|
+
}), st = (e) => ({
|
|
421
421
|
write: (t, n, r) => j(e, t, n, r),
|
|
422
422
|
has: (t) => e.head(t).pipe(n.map((e) => e !== null))
|
|
423
|
-
}),
|
|
423
|
+
}), ct = (e, t) => n.tryPromise({
|
|
424
424
|
try: async () => {
|
|
425
425
|
let { createWriteStream: n } = await import("node:fs"), r = await import("node:fs/promises"), { createHash: i, randomUUID: a } = await import("node:crypto"), { pipeline: o } = await import("node:stream/promises"), { Transform: s } = await import("node:stream"), c = await import("node:path"), l = c.join(t, `.tmp-${a()}`), u = i("sha256"), d = 0, f = new s({ transform(e, t, n) {
|
|
426
426
|
u.update(e), d += e.length, n(null, e);
|
|
427
427
|
} });
|
|
428
|
-
await o(await
|
|
428
|
+
await o(await he(e.stream), f, n(l));
|
|
429
429
|
let p = u.digest("hex"), m = c.join(t, p);
|
|
430
430
|
try {
|
|
431
431
|
await r.access(m), await r.rm(l, { force: !0 });
|
|
@@ -442,44 +442,47 @@ var Ce = (e) => {
|
|
|
442
442
|
reason: `asset write failed: ${String(e?.message ?? e)}`,
|
|
443
443
|
path: t
|
|
444
444
|
})
|
|
445
|
-
}),
|
|
446
|
-
let i = yield* n.promise(() => import("node:path")), { createReadStream: a } = yield* n.promise(() => import("node:fs")), { createHash: o } = yield* n.promise(() => import("node:crypto")), s = i.join(t, r.sha256), c = o("sha256"), u =
|
|
445
|
+
}), lt = (e, t, r) => n.gen(function* () {
|
|
446
|
+
let i = yield* n.promise(() => import("node:path")), { createReadStream: a } = yield* n.promise(() => import("node:fs")), { createHash: o } = yield* n.promise(() => import("node:crypto")), s = i.join(t, r.sha256), c = o("sha256"), u = me("bundle", () => a(s)).pipe(l.tap((e) => n.sync(() => c.update(e))));
|
|
447
447
|
yield* e.write(r.key, u, {
|
|
448
448
|
contentType: r.contentType,
|
|
449
449
|
totalSize: r.size
|
|
450
450
|
});
|
|
451
451
|
let d = c.digest("hex");
|
|
452
|
-
if (d !== r.sha256) return yield* n.fail(new
|
|
452
|
+
if (d !== r.sha256) return yield* n.fail(new Je({
|
|
453
453
|
what: `asset ${r.key}`,
|
|
454
454
|
expected: r.sha256,
|
|
455
455
|
actual: d
|
|
456
456
|
}));
|
|
457
|
-
}),
|
|
457
|
+
}), ut = {
|
|
458
458
|
done: () => !1,
|
|
459
459
|
mark: () => n.void
|
|
460
|
-
},
|
|
461
|
-
let t = e.progress ??
|
|
462
|
-
return yield* l.runForEach(e.source.list(), (
|
|
460
|
+
}, dt = (e) => typeof e == "object" && !!e && e.status === 404, ft = (e) => n.gen(function* () {
|
|
461
|
+
let t = e.progress ?? ut, r = 0, i = 0, a = [];
|
|
462
|
+
return yield* l.runForEach(e.source.list(), (o) => t.done(o.key) ? n.void : e.source.open(o.key).pipe(n.map((e) => e), n.catchIf(dt, () => n.sync(() => {
|
|
463
|
+
a.push(o.key);
|
|
464
|
+
})), n.flatMap((a) => a === void 0 ? n.void : ct(a, e.assetsDir).pipe(n.flatMap((e) => {
|
|
463
465
|
let n = {
|
|
464
|
-
key:
|
|
466
|
+
key: o.key,
|
|
465
467
|
sha256: e.sha256,
|
|
466
468
|
size: e.size,
|
|
467
469
|
contentType: e.contentType
|
|
468
470
|
};
|
|
469
|
-
return r++, i += e.size, t.mark(
|
|
470
|
-
}))).pipe(n.mapError((e) => e instanceof H ? e : new H({ reason: `asset export failed: ${String(e)}` }))), {
|
|
471
|
+
return r++, i += e.size, t.mark(o.key, n);
|
|
472
|
+
}))))).pipe(n.mapError((e) => e instanceof H ? e : new H({ reason: `asset export failed: ${String(e)}` }))), {
|
|
471
473
|
count: r,
|
|
472
|
-
totalBytes: i
|
|
474
|
+
totalBytes: i,
|
|
475
|
+
missing: a
|
|
473
476
|
};
|
|
474
|
-
}),
|
|
477
|
+
}), pt = (e) => me("bundle", () => le(e)).pipe(l.decodeText(), l.splitLines, l.filter((e) => e.trim().length > 0), l.map((e) => JSON.parse(e)), l.mapError((t) => t instanceof H ? t : new H({
|
|
475
478
|
reason: `asset index unreadable: ${String(t)}`,
|
|
476
479
|
path: e
|
|
477
|
-
}))),
|
|
478
|
-
let t = e.progress ??
|
|
479
|
-
return yield* l.runForEach(
|
|
480
|
+
}))), mt = (e) => n.gen(function* () {
|
|
481
|
+
let t = e.progress ?? ut, r = 0;
|
|
482
|
+
return yield* l.runForEach(pt(e.indexPath), (i) => t.done(i.key) ? n.void : lt(e.sink, e.assetsDir, i).pipe(n.andThen(n.sync(() => {
|
|
480
483
|
r++;
|
|
481
484
|
})), n.andThen(t.mark(i.key, i)))), r;
|
|
482
|
-
}),
|
|
485
|
+
}), ht = () => typeof M.createZstdCompress == "function", gt = (e) => e === "none" ? "none" : e === "gzip" ? "gzip" : ht() ? "zstd" : "gzip", _t = (e) => e === "zstd" ? ".zst" : e === "gzip" ? ".gz" : "", vt = (e) => e === "zstd" ? M.createZstdCompress() : e === "gzip" ? M.createGzip() : new N(), yt = (e) => e === "zstd" ? M.createZstdDecompress() : e === "gzip" ? M.createGunzip() : new N(), bt = 1, xt = c.Struct({
|
|
483
486
|
name: c.String,
|
|
484
487
|
file: c.String,
|
|
485
488
|
rowCount: c.Number,
|
|
@@ -489,12 +492,12 @@ var Ce = (e) => {
|
|
|
489
492
|
value: c.String
|
|
490
493
|
}),
|
|
491
494
|
primaryKey: c.String
|
|
492
|
-
}),
|
|
495
|
+
}), St = c.Struct({
|
|
493
496
|
kind: c.Literal("all", "tenant", "tables"),
|
|
494
497
|
tenantId: c.optional(c.String),
|
|
495
498
|
tables: c.optional(c.Array(c.String)),
|
|
496
499
|
exclude: c.optional(c.Array(c.String))
|
|
497
|
-
}),
|
|
500
|
+
}), Ct = c.Struct({
|
|
498
501
|
count: c.Number,
|
|
499
502
|
totalBytes: c.Number,
|
|
500
503
|
index: c.optional(c.String)
|
|
@@ -505,23 +508,23 @@ c.Struct({
|
|
|
505
508
|
size: c.Number,
|
|
506
509
|
contentType: c.String
|
|
507
510
|
});
|
|
508
|
-
var
|
|
511
|
+
var wt = c.Struct({
|
|
509
512
|
formatVersion: c.Number,
|
|
510
513
|
createdAt: c.String,
|
|
511
514
|
source: c.Struct({
|
|
512
515
|
dialect: c.String,
|
|
513
516
|
schemaFingerprint: c.String
|
|
514
517
|
}),
|
|
515
|
-
scope:
|
|
518
|
+
scope: St,
|
|
516
519
|
consistency: c.Literal("live", "snapshot"),
|
|
517
520
|
compression: c.Literal("zstd", "gzip", "none"),
|
|
518
|
-
tables: c.Array(
|
|
519
|
-
assets:
|
|
521
|
+
tables: c.Array(xt),
|
|
522
|
+
assets: Ct,
|
|
520
523
|
masking: c.optional(c.Struct({
|
|
521
524
|
policyId: c.optional(c.String),
|
|
522
525
|
transformed: c.Array(c.String)
|
|
523
526
|
}))
|
|
524
|
-
}),
|
|
527
|
+
}), Tt = c.encodeSync(c.parseJson(wt)), Et = c.decodeUnknownSync(c.parseJson(wt)), K = "manifest.json", Dt = "README.md", Ot = "data", kt = "assets", At = "assets/index.ndjson", jt = ".ledger.json", Mt = (e) => e.kind === "tenant" ? `tenant \`${e.tenantId}\`` : e.kind === "tables" ? `tables \`${(e.tables ?? []).join(", ")}\`` : "all tables", Nt = (e, t) => {
|
|
525
528
|
let n = e.tables.reduce((e, t) => e + t.rowCount, 0), r = e.masking ? `✅ **Masked at the source** — ${e.masking.transformed.length} column(s) transformed${e.masking.policyId ? ` (policy \`${e.masking.policyId}\`)` : ""}. Personal data was replaced with realistic, referentially-consistent fakes before any byte was written.` : "⚠️ **NOT masked — this bundle contains REAL data (PII included).** Treat it as production data: do not copy it into a lower environment or share it without review. To produce a safe copy, re-export under a masking profile (`--profile`).", i = e.masking && e.masking.transformed.length > 0 ? `\n\nMasked columns: ${e.masking.transformed.map((e) => `\`${e}\``).join(", ")}.` : "", a = e.assets.count > 0 ? `${e.assets.count} object(s), ${e.assets.totalBytes} bytes` : "none", o = e.tables.map((e) => `| \`${e.name}\` | ${e.rowCount} |`).join("\n");
|
|
526
529
|
return `# Voltro data export
|
|
527
530
|
|
|
@@ -535,7 +538,7 @@ The machine-readable manifest is \`manifest.json\`; this file is a human summary
|
|
|
535
538
|
| **Format version** | ${e.formatVersion} |
|
|
536
539
|
| **Consistency** | ${e.consistency} |
|
|
537
540
|
| **Compression** | ${e.compression} |
|
|
538
|
-
| **Scope** | ${
|
|
541
|
+
| **Scope** | ${Mt(e.scope)} |
|
|
539
542
|
| **Tables** | ${e.tables.length} |
|
|
540
543
|
| **Rows (total)** | ${n} |
|
|
541
544
|
| **Assets** | ${a} |
|
|
@@ -560,26 +563,26 @@ voltro data import <this-directory>
|
|
|
560
563
|
voltro data import <this-directory> --target api --api-url <url> --token <secret>
|
|
561
564
|
\`\`\`
|
|
562
565
|
`;
|
|
563
|
-
},
|
|
566
|
+
}, Pt = i.counter("voltro_data_transfer_rows", { description: "Rows exported/imported by @voltro/data-transfer, tagged by phase + table." }), Ft = a.exponential({
|
|
564
567
|
start: .01,
|
|
565
568
|
factor: 2,
|
|
566
569
|
count: 16
|
|
567
|
-
}),
|
|
570
|
+
}), It = i.histogram("voltro_data_transfer_table_seconds", Ft, "Per-table export/import duration in seconds, tagged by phase."), q = (e, t) => {
|
|
568
571
|
if (e) try {
|
|
569
572
|
e(t);
|
|
570
573
|
} catch {}
|
|
571
|
-
},
|
|
574
|
+
}, Lt = (e, t, r, a, o, s) => n.Do.pipe(n.bind("start", () => n.clockWith((e) => e.currentTimeMillis)), n.bind("result", () => s), n.tap(({ start: r, result: a }) => n.clockWith((e) => e.currentTimeMillis).pipe(n.flatMap((s) => n.zipRight(It.pipe(i.tagged("phase", e), i.update((s - r) / 1e3)), Pt.pipe(i.tagged("phase", e), i.tagged("table", t), i.update(o(a))))))), n.map(({ result: e }) => e), n.withSpan(`data-transfer.${e}.table`, { attributes: {
|
|
572
575
|
table: t,
|
|
573
576
|
index: r,
|
|
574
577
|
tableCount: a,
|
|
575
578
|
phase: e
|
|
576
|
-
} })),
|
|
579
|
+
} })), Rt = () => ({
|
|
577
580
|
tables: {},
|
|
578
581
|
assets: {}
|
|
579
|
-
}),
|
|
582
|
+
}), zt = (e) => n.tryPromise(async () => {
|
|
580
583
|
let t = await (await import("node:fs/promises")).readFile(e, "utf8");
|
|
581
584
|
return JSON.parse(t);
|
|
582
|
-
}).pipe(n.orElseSucceed(
|
|
585
|
+
}).pipe(n.orElseSucceed(Rt)), J = (e, t) => n.tryPromise({
|
|
583
586
|
try: async () => {
|
|
584
587
|
let n = await import("node:fs/promises"), { randomUUID: r } = await import("node:crypto"), i = `${e}.tmp-${r()}`;
|
|
585
588
|
await n.writeFile(i, JSON.stringify(t)), await n.rename(i, e);
|
|
@@ -588,11 +591,11 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
588
591
|
reason: `ledger write failed: ${String(t?.message ?? t)}`,
|
|
589
592
|
path: e
|
|
590
593
|
})
|
|
591
|
-
}),
|
|
594
|
+
}), Bt = (e, t) => t in e.tables, Vt = (e, t) => t in e.assets, Ht = /* @__PURE__ */ new Set([
|
|
592
595
|
"json",
|
|
593
596
|
"array",
|
|
594
597
|
"vector"
|
|
595
|
-
]),
|
|
598
|
+
]), Ut = (e) => typeof e == "object" && !!e && !Array.isArray(e) && typeof e.$v == "string", Wt = (e) => Buffer.from(e).toString("base64"), Gt = (e) => new Uint8Array(Buffer.from(e, "base64")), Kt = (e) => e instanceof Date ? e.toISOString() : typeof e == "number" ? new Date(e).toISOString() : String(e), qt = (e, t) => e == null ? null : t !== void 0 && Ht.has(t) ? e : t === "bytes" ? Wt(e) : t === "timestamp" || t === "date" ? Kt(e) : typeof e == "bigint" ? {
|
|
596
599
|
$v: "bigint",
|
|
597
600
|
d: e.toString()
|
|
598
601
|
} : typeof e == "number" && !Number.isFinite(e) ? {
|
|
@@ -603,30 +606,30 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
603
606
|
d: e.toISOString()
|
|
604
607
|
} : e instanceof Uint8Array ? {
|
|
605
608
|
$v: "bytes",
|
|
606
|
-
d:
|
|
607
|
-
} : e,
|
|
609
|
+
d: Wt(e)
|
|
610
|
+
} : e, Jt = (e) => {
|
|
608
611
|
switch (e.$v) {
|
|
609
612
|
case "bigint": return BigInt(e.d);
|
|
610
613
|
case "number": return Number(e.d);
|
|
611
614
|
case "date": return new Date(e.d);
|
|
612
|
-
case "bytes": return
|
|
615
|
+
case "bytes": return Gt(e.d);
|
|
613
616
|
default: return e;
|
|
614
617
|
}
|
|
615
|
-
},
|
|
618
|
+
}, Yt = (e, t) => e == null ? null : t !== void 0 && Ht.has(t) ? e : Ut(e) ? Jt(e) : t === "bytes" ? Gt(e) : t === "timestamp" || t === "date" ? new Date(e) : e, Xt = (e, t) => {
|
|
616
619
|
let n = {};
|
|
617
|
-
for (let [r, i] of Object.entries(e)) n[r] =
|
|
620
|
+
for (let [r, i] of Object.entries(e)) n[r] = qt(i, t[r]);
|
|
618
621
|
return n;
|
|
619
|
-
},
|
|
622
|
+
}, Zt = (e, t) => {
|
|
620
623
|
let n = {};
|
|
621
|
-
for (let [r, i] of Object.entries(e)) n[r] =
|
|
624
|
+
for (let [r, i] of Object.entries(e)) n[r] = Yt(i, t[r]);
|
|
622
625
|
return n;
|
|
623
|
-
},
|
|
624
|
-
try: () =>
|
|
625
|
-
catch: (e) => new
|
|
626
|
+
}, Qt = new TextEncoder(), $t = (e, t) => e.pipe(l.map((e) => Qt.encode(`${JSON.stringify(Xt(e, t))}\n`))), en = (e, t, r) => e.pipe(l.decodeText(), l.splitLines, l.filter((e) => e.trim().length > 0), l.mapEffect((e) => n.try({
|
|
627
|
+
try: () => Zt(JSON.parse(e), r),
|
|
628
|
+
catch: (e) => new qe({
|
|
626
629
|
table: t,
|
|
627
630
|
reason: String(e?.message ?? e)
|
|
628
631
|
})
|
|
629
|
-
}))),
|
|
632
|
+
}))), tn = (e, t) => {
|
|
630
633
|
let n = new Set(e), r = /* @__PURE__ */ new Map();
|
|
631
634
|
for (let e of t.tables) {
|
|
632
635
|
if (!n.has(e.name)) continue;
|
|
@@ -652,33 +655,33 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
652
655
|
let r = typeof t?.message == "string" ? t.message.trim() : "";
|
|
653
656
|
if (r === "" ? t?.cause !== void 0 && t.cause !== null && n.push(Y(t.cause)) : n.push(r), n.length === 0) {
|
|
654
657
|
let t = String(e ?? "").trim();
|
|
655
|
-
return t === "" || t === "[object Object]" ?
|
|
658
|
+
return t === "" || t === "[object Object]" ? nn(e) : t;
|
|
656
659
|
}
|
|
657
660
|
return n.join(": ");
|
|
658
|
-
},
|
|
661
|
+
}, nn = (e) => {
|
|
659
662
|
try {
|
|
660
663
|
let t = JSON.stringify(e);
|
|
661
664
|
return t === void 0 || t === "{}" ? "unknown error (no message, cause or tag)" : t;
|
|
662
665
|
} catch {
|
|
663
666
|
return "unknown error (not serialisable)";
|
|
664
667
|
}
|
|
665
|
-
},
|
|
668
|
+
}, rn = (e, t) => {
|
|
666
669
|
let n = e.tables.find((e) => e.name === t), r = {};
|
|
667
670
|
for (let e of n?.columns ?? []) e.generatedAs === void 0 && (r[e.name] = e.type);
|
|
668
671
|
return r;
|
|
669
|
-
},
|
|
672
|
+
}, an = (e, t) => (e.tables.find((e) => e.name === t)?.columns ?? []).filter((e) => e.generatedAs !== void 0).map((e) => e.name), on = (e, t) => {
|
|
670
673
|
if (t.length === 0) return e;
|
|
671
674
|
let n = { ...e };
|
|
672
675
|
for (let e of t) delete n[e];
|
|
673
676
|
return n;
|
|
674
|
-
},
|
|
677
|
+
}, sn = (e, t) => {
|
|
675
678
|
let n = e.tables.find((e) => e.name === t);
|
|
676
679
|
if (n === void 0) return { refusal: `${t}: not in the schema snapshot, so its primary key is unknown.` };
|
|
677
680
|
let r = n.columns.find((e) => e.type === "id");
|
|
678
681
|
if (r !== void 0) return { column: r.name };
|
|
679
682
|
let i = n.indexes.find((e) => e.name === `${t}_pkey`)?.columns ?? n.primaryKey ?? [];
|
|
680
683
|
return i.length === 1 ? { column: i[0] } : i.length > 1 ? { refusal: `${t}: composite primary key (${i.join(", ")}). Keyset export orders by ONE column; ordering by the first alone would split equal values across pages and drop or duplicate rows. Exclude this table from the scope, or give it a single-column key.` } : { refusal: `${t}: no primary key, so there is no stable order to paginate by. A keyset export would return rows in an order the database may change between pages. Exclude this table from the scope.` };
|
|
681
|
-
},
|
|
684
|
+
}, cn = (e, t, r) => n.tryPromise({
|
|
682
685
|
try: async () => {
|
|
683
686
|
let { createWriteStream: n } = await import("node:fs"), i = await import("node:fs/promises"), { createHash: a, randomUUID: o } = await import("node:crypto"), { pipeline: s } = await import("node:stream/promises"), { Readable: c, Transform: u } = await import("node:stream"), d = a("sha256"), f = 0, p = new u({ transform(e, t, n) {
|
|
684
687
|
d.update(e);
|
|
@@ -687,7 +690,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
687
690
|
n(null, e);
|
|
688
691
|
} }), m = c.fromWeb(l.toReadableStream(e)), h = `${t}.tmp-${o()}`;
|
|
689
692
|
try {
|
|
690
|
-
await s(m, p,
|
|
693
|
+
await s(m, p, vt(r), n(h)), await i.rename(h, t);
|
|
691
694
|
} catch (e) {
|
|
692
695
|
throw await i.rm(h, { force: !0 }).catch(() => {}), e;
|
|
693
696
|
}
|
|
@@ -700,7 +703,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
700
703
|
reason: `write table failed: ${Y(e)}`,
|
|
701
704
|
path: t
|
|
702
705
|
})
|
|
703
|
-
}),
|
|
706
|
+
}), ln = (e, t) => n.tryPromise({
|
|
704
707
|
try: async () => {
|
|
705
708
|
await (await import("node:fs/promises")).appendFile(e, `${t}\n`);
|
|
706
709
|
},
|
|
@@ -708,13 +711,13 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
708
711
|
reason: `append failed: ${Y(t)}`,
|
|
709
712
|
path: e
|
|
710
713
|
})
|
|
711
|
-
}),
|
|
714
|
+
}), un = (e, t) => n.gen(function* () {
|
|
712
715
|
let r = [], i = t.ordered.length;
|
|
713
716
|
for (let a = 0; a < t.ordered.length; a++) {
|
|
714
|
-
let o = t.ordered[a], s =
|
|
717
|
+
let o = t.ordered[a], s = rn(t.snapshot, o), c = sn(t.snapshot, o);
|
|
715
718
|
if ("refusal" in c) return yield* n.fail(new U({ reason: `export: ${c.refusal}` }));
|
|
716
|
-
let u = c.column, d = `${
|
|
717
|
-
if (
|
|
719
|
+
let u = c.column, d = `${Ot}/${o}.ndjson${_t(t.compression)}`;
|
|
720
|
+
if (Bt(t.ledger, o)) {
|
|
718
721
|
let e = t.ledger.tables[o];
|
|
719
722
|
q(t.onProgress, {
|
|
720
723
|
phase: "export",
|
|
@@ -748,7 +751,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
748
751
|
chunkSize: t.chunkSize,
|
|
749
752
|
retry: t.retry,
|
|
750
753
|
...f === void 0 ? {} : { where: f }
|
|
751
|
-
}), m =
|
|
754
|
+
}), m = an(t.snapshot, o), h = m.length === 0 ? p : p.pipe(l.map((e) => on(e, m))), g = t.mask ? h.pipe(l.map((e) => He(e, o, t.mask.actions, t.mask.seed, s))) : h, { rowCount: _, checksum: v } = yield* Lt("export", o, a, i, (e) => e.rowCount, cn($t(g, s), t.bundleFile(d), t.compression));
|
|
752
755
|
t.ledger.tables[o] = {
|
|
753
756
|
rowCount: _,
|
|
754
757
|
checksum: v
|
|
@@ -770,43 +773,43 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
770
773
|
});
|
|
771
774
|
}
|
|
772
775
|
return r;
|
|
773
|
-
}),
|
|
776
|
+
}), dn = (e) => ({
|
|
774
777
|
_tag: "RawSqlFragment",
|
|
775
778
|
strings: [e],
|
|
776
779
|
values: []
|
|
777
|
-
}),
|
|
780
|
+
}), fn = (t, i, a) => n.tryPromise({
|
|
778
781
|
try: () => t.transactional(async (t) => {
|
|
779
|
-
if (t.raw) for (let e of
|
|
782
|
+
if (t.raw) for (let e of we(i)) await t.raw(dn(e));
|
|
780
783
|
let o = await n.runPromiseExit(a(t));
|
|
781
784
|
if (r.isFailure(o)) throw Error(e.pretty(o.cause));
|
|
782
785
|
return o.value;
|
|
783
786
|
}),
|
|
784
787
|
catch: (e) => e instanceof H ? e : new H({ reason: `snapshot export failed: ${Y(e)}` })
|
|
785
|
-
}),
|
|
786
|
-
let t = e.scope ?? { kind: "all" }, r =
|
|
788
|
+
}), pn = (e) => n.gen(function* () {
|
|
789
|
+
let t = e.scope ?? { kind: "all" }, r = gt(e.compression), i = e.chunkSize ?? 1e3, a = e.retryTimes ?? 5, o = s.exponential("50 millis").pipe(s.jittered, s.intersect(s.recurs(a))), c = yield* n.promise(() => import("node:path")), l = (t) => c.join(e.outDir, t);
|
|
787
790
|
yield* n.tryPromise({
|
|
788
791
|
try: async () => {
|
|
789
792
|
let t = await import("node:fs/promises");
|
|
790
|
-
await t.mkdir(l(
|
|
793
|
+
await t.mkdir(l(Ot), { recursive: !0 }), e.assets && await t.mkdir(l(kt), { recursive: !0 });
|
|
791
794
|
},
|
|
792
795
|
catch: (t) => new H({
|
|
793
796
|
reason: `mkdir failed: ${Y(t)}`,
|
|
794
797
|
path: e.outDir
|
|
795
798
|
})
|
|
796
799
|
});
|
|
797
|
-
let u = l(
|
|
800
|
+
let u = l(jt), d = yield* zt(u), f = e.subset ? rt(yield* nt(e.store, e.snapshot, e.subset), e.snapshot) : yield* at(t, e.snapshot, {
|
|
798
801
|
store: e.store,
|
|
799
802
|
...e.tenantTables ? { tenantTables: e.tenantTables } : {}
|
|
800
|
-
}), p =
|
|
803
|
+
}), p = tn(f.tables, e.snapshot), m = e.consistency ?? "live", h, g;
|
|
801
804
|
if (e.masking) {
|
|
802
|
-
let t = e.classification ??
|
|
805
|
+
let t = e.classification ?? Ee(e.snapshot), r = ze(p.map((t) => ({
|
|
803
806
|
name: t,
|
|
804
807
|
columns: (e.snapshot.tables.find((e) => e.name === t)?.columns ?? []).map((e) => ({
|
|
805
808
|
name: e.name,
|
|
806
809
|
type: e.type
|
|
807
810
|
}))
|
|
808
811
|
})), t, e.masking);
|
|
809
|
-
if (r.unclassified.length > 0 || r.invalid.length > 0) return yield* n.fail(new
|
|
812
|
+
if (r.unclassified.length > 0 || r.invalid.length > 0) return yield* n.fail(new Qe({
|
|
810
813
|
unclassified: r.unclassified,
|
|
811
814
|
...r.invalid.length > 0 ? { invalidActions: r.invalid.map((e) => `${e.column}: ${JSON.stringify(e.action)}`) } : {}
|
|
812
815
|
}));
|
|
@@ -832,14 +835,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
832
835
|
bundleFile: l,
|
|
833
836
|
...g ? { mask: g } : {},
|
|
834
837
|
...e.onProgress ? { onProgress: e.onProgress } : {}
|
|
835
|
-
}, v = m === "snapshot" ? yield*
|
|
838
|
+
}, v = m === "snapshot" ? yield* fn(e.store, e.dialect, (e) => un(e, _)) : yield* un(e.store, _), y = 0, b = 0;
|
|
836
839
|
if (e.assets) {
|
|
837
|
-
let t = l(
|
|
840
|
+
let t = l(At), r = yield* ft({
|
|
838
841
|
source: e.assets,
|
|
839
|
-
assetsDir: l(
|
|
842
|
+
assetsDir: l(kt),
|
|
840
843
|
progress: {
|
|
841
844
|
done: (e) => e in d.assets,
|
|
842
|
-
mark: (e, r) => (d.assets[e] = !0,
|
|
845
|
+
mark: (e, r) => (d.assets[e] = !0, ln(t, JSON.stringify(r)).pipe(n.andThen(J(u, d))))
|
|
843
846
|
}
|
|
844
847
|
});
|
|
845
848
|
y = r.count, b = r.totalBytes;
|
|
@@ -858,7 +861,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
858
861
|
assets: y > 0 ? {
|
|
859
862
|
count: y,
|
|
860
863
|
totalBytes: b,
|
|
861
|
-
index:
|
|
864
|
+
index: At
|
|
862
865
|
} : {
|
|
863
866
|
count: 0,
|
|
864
867
|
totalBytes: 0
|
|
@@ -867,7 +870,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
867
870
|
};
|
|
868
871
|
return yield* n.tryPromise({
|
|
869
872
|
try: async () => {
|
|
870
|
-
await (await import("node:fs/promises")).writeFile(l(K),
|
|
873
|
+
await (await import("node:fs/promises")).writeFile(l(K), Tt(x));
|
|
871
874
|
},
|
|
872
875
|
catch: (e) => new H({
|
|
873
876
|
reason: `manifest write failed: ${Y(e)}`,
|
|
@@ -876,14 +879,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
876
879
|
}), yield* n.tryPromise({
|
|
877
880
|
try: async () => {
|
|
878
881
|
let e = await import("node:fs/promises"), t = await import("node:os");
|
|
879
|
-
await e.writeFile(l(
|
|
882
|
+
await e.writeFile(l(Dt), Nt(x, { hostname: t.hostname() }));
|
|
880
883
|
},
|
|
881
884
|
catch: (e) => new H({
|
|
882
885
|
reason: `readme write failed: ${Y(e)}`,
|
|
883
|
-
path:
|
|
886
|
+
path: Dt
|
|
884
887
|
})
|
|
885
888
|
}), x;
|
|
886
|
-
}),
|
|
889
|
+
}), mn = (e, t) => {
|
|
887
890
|
let n = new Set(t), r = [];
|
|
888
891
|
for (let t of e.tables) if (!n.has(t.name)) for (let e of t.columns) {
|
|
889
892
|
let i = e.references?.table;
|
|
@@ -894,7 +897,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
894
897
|
});
|
|
895
898
|
}
|
|
896
899
|
return r;
|
|
897
|
-
},
|
|
900
|
+
}, hn = (e) => {
|
|
898
901
|
let t = /* @__PURE__ */ new Map();
|
|
899
902
|
for (let n of e) t.set(n.from, [...t.get(n.from) ?? [], n]);
|
|
900
903
|
let n = [...t.entries()].map(([e, t]) => {
|
|
@@ -902,7 +905,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
902
905
|
return ` ${e} (${n} row${n === 1 ? "" : "s"}): ${r}`;
|
|
903
906
|
});
|
|
904
907
|
return `replace cannot empty this target: ${t.size} table(s) OUTSIDE the bundle hold rows that reference tables INSIDE it. Emptying the bundle's tables would leave those rows pointing at nothing, and the bundle cannot restore them.\n${n.join("\n")}\nNothing has been deleted. Either re-export with a scope that includes those tables, or use --mode upsert if those rows are meant to survive.`;
|
|
905
|
-
},
|
|
908
|
+
}, gn = (e) => {
|
|
906
909
|
switch (e) {
|
|
907
910
|
case "id":
|
|
908
911
|
case "text":
|
|
@@ -921,12 +924,12 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
921
924
|
case "raw": return "raw";
|
|
922
925
|
default: return "string";
|
|
923
926
|
}
|
|
924
|
-
},
|
|
927
|
+
}, _n = {
|
|
925
928
|
vector: /* @__PURE__ */ new Set(["postgres"]),
|
|
926
929
|
array: /* @__PURE__ */ new Set(["postgres"]),
|
|
927
930
|
interval: /* @__PURE__ */ new Set(["postgres"])
|
|
928
|
-
},
|
|
929
|
-
let i =
|
|
931
|
+
}, vn = (e, t, n, r) => {
|
|
932
|
+
let i = gn(n);
|
|
930
933
|
if (i === "raw") return {
|
|
931
934
|
table: e,
|
|
932
935
|
column: t,
|
|
@@ -934,7 +937,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
934
937
|
severity: "block",
|
|
935
938
|
reason: `raw() is verbatim source-dialect SQL — it cannot be assumed valid on ${r}`
|
|
936
939
|
};
|
|
937
|
-
let a =
|
|
940
|
+
let a = _n[i];
|
|
938
941
|
return !a || a.has(r) ? null : i === "array" || i === "interval" ? {
|
|
939
942
|
table: e,
|
|
940
943
|
column: t,
|
|
@@ -948,15 +951,15 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
948
951
|
severity: "block",
|
|
949
952
|
reason: `${i} columns require a ${[...a].join("/")} target; ${r} has no compatible column type`
|
|
950
953
|
};
|
|
951
|
-
},
|
|
954
|
+
}, yn = (e, t, n) => {
|
|
952
955
|
if (t === n) return [];
|
|
953
956
|
let r = [];
|
|
954
957
|
for (let t of e) for (let [e, i] of Object.entries(t.columnTypes)) {
|
|
955
|
-
let a =
|
|
958
|
+
let a = vn(t.name, e, i, n);
|
|
956
959
|
a && r.push(a);
|
|
957
960
|
}
|
|
958
961
|
return r;
|
|
959
|
-
},
|
|
962
|
+
}, bn = (e) => `[${e.severity}] ${e.table}.${e.column} (${e.type}): ${e.reason}`, xn = (e) => {
|
|
960
963
|
let t = e.constraint ?? e.column, n = t === void 0 ? "" : ` ${t}`;
|
|
961
964
|
switch (e.kind) {
|
|
962
965
|
case "foreignKey": return `foreign key${n}: the referenced row does not exist (import it first, or check the bundle's table order)`;
|
|
@@ -965,35 +968,35 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
965
968
|
case "notNull": return `not-null constraint${n}: the column requires a value`;
|
|
966
969
|
case "check": return `check constraint${n}: the row does not satisfy it`;
|
|
967
970
|
}
|
|
968
|
-
},
|
|
971
|
+
}, Sn = (e) => {
|
|
969
972
|
let t = [e.dbCode, e.dbErrno ?? e.dbNumber].filter((e) => e !== void 0).map(String);
|
|
970
973
|
return t.length > 0 ? t.join("/") : void 0;
|
|
971
|
-
},
|
|
974
|
+
}, Cn = "Failed to execute statement", wn = (e) => {
|
|
972
975
|
let t = (e.split("\n", 1)[0] ?? "").trim();
|
|
973
976
|
for (; t.startsWith("(FiberFailure)");) t = t.slice(14).trim();
|
|
974
|
-
return t === `SqlError: ${
|
|
975
|
-
},
|
|
977
|
+
return t === `SqlError: ${Cn}` ? Cn : t;
|
|
978
|
+
}, Tn = (e) => {
|
|
976
979
|
let t = String(e?.stack ?? e), n = t.length <= 1200 ? t : `${t.slice(0, 1200)}…`, r = (e, t) => ({
|
|
977
980
|
reason: e.length <= 300 ? e : `${e.slice(0, 300)}…`,
|
|
978
981
|
unclassified: t,
|
|
979
982
|
raw: n
|
|
980
|
-
}), i = _(e), a = p(i), o =
|
|
981
|
-
if (a !== void 0) return r(`${
|
|
982
|
-
let c = typeof i.dbMessage == "string" ? i.dbMessage : void 0, l = e?.message, u =
|
|
983
|
-
return r(d ===
|
|
984
|
-
},
|
|
983
|
+
}), i = _(e), a = p(i), o = Sn(i), s = o === void 0 ? "" : ` [${o}]`;
|
|
984
|
+
if (a !== void 0) return r(`${xn(a)}${s}`, !1);
|
|
985
|
+
let c = typeof i.dbMessage == "string" ? i.dbMessage : void 0, l = e?.message, u = wn(typeof l == "string" && l.length > 0 ? l : String(e)), d = c !== void 0 && c !== u && !c.startsWith("SqlError:") ? c : u, f = typeof i.dbCauseChain == "string" ? i.dbCauseChain : void 0, m = f !== void 0 && /[←‖]/.test(f) ? ` (via ${f})` : "";
|
|
986
|
+
return r(d === Cn || d.length === 0 ? `the database refused the write and the driver gave no detail${s}${m}` : `${d}${s}`, d === Cn || d.length === 0);
|
|
987
|
+
}, En = (e) => Tn(e).reason, Dn = (e) => {
|
|
985
988
|
let t = _(e), n = p(t);
|
|
986
989
|
if (n?.kind === "foreignKeyInUse") {
|
|
987
|
-
let e = n.constraint ?? n.column, r = e === void 0 ? "" : ` ${e}`, i =
|
|
990
|
+
let e = n.constraint ?? n.column, r = e === void 0 ? "" : ` ${e}`, i = Sn(t);
|
|
988
991
|
return `foreign key${r}: rows elsewhere still reference this table${i === void 0 ? "" : ` [${i}]`}`;
|
|
989
992
|
}
|
|
990
|
-
return
|
|
991
|
-
},
|
|
993
|
+
return En(e);
|
|
994
|
+
}, On = "_voltro_staging_", X = (e) => `${On}${e}`, kn = (e) => typeof e.run == "function", An = (e) => `staging is not available for this run — loading directly into the target instead: ${e}\n The load therefore holds the destructive transaction open for its whole duration, so a
|
|
992
995
|
process that dies mid-load depends on the database rolling it back. The rollback capture
|
|
993
|
-
written before the first delete is what covers that case.`,
|
|
994
|
-
if (!
|
|
996
|
+
written before the first delete is what covers that case.`, jn = /^[a-zA-Z_][a-zA-Z0-9_]*$/, Z = (e, t) => {
|
|
997
|
+
if (!jn.test(e)) throw Error(`refusing to build SQL for the table name ${JSON.stringify(e)}: it is outside the identifier class the framework allows. A name from a bundle manifest reaches this concatenation, so it is checked here rather than assumed to still be what the declaration validated.`);
|
|
995
998
|
return t === "mysql" || t === "mariadb" ? `\`${e}\`` : t === "mssql" ? `[${e}]` : `"${e}"`;
|
|
996
|
-
},
|
|
999
|
+
}, Mn = (e, t) => {
|
|
997
1000
|
let n = Z(e, t), r = Z(X(e), t);
|
|
998
1001
|
switch (t) {
|
|
999
1002
|
case "postgres": return `CREATE TABLE ${r} (LIKE ${n})`;
|
|
@@ -1002,10 +1005,10 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1002
1005
|
case "sqlite": return `CREATE TABLE ${r} AS SELECT * FROM ${n} WHERE 0`;
|
|
1003
1006
|
case "mssql": return `SELECT * INTO ${r} FROM ${n} WHERE 1 = 0`;
|
|
1004
1007
|
}
|
|
1005
|
-
},
|
|
1008
|
+
}, Nn = (e, t) => {
|
|
1006
1009
|
let n = Z(X(e), t);
|
|
1007
1010
|
return t === "mssql" ? `IF OBJECT_ID('${X(e)}', 'U') IS NOT NULL DROP TABLE ${n}` : `DROP TABLE IF EXISTS ${n}`;
|
|
1008
|
-
},
|
|
1011
|
+
}, Pn = (e, t) => {
|
|
1009
1012
|
let n = t === "mysql" || t === "mariadb", r = [];
|
|
1010
1013
|
n && r.push("SET FOREIGN_KEY_CHECKS = 0");
|
|
1011
1014
|
for (let n of [...e].reverse()) r.push(`DELETE FROM ${Z(n.name, t)}`);
|
|
@@ -1015,7 +1018,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1015
1018
|
r.push(`INSERT INTO ${Z(n.name, t)} (${e}) SELECT ${e} FROM ${Z(X(n.name), t)}`);
|
|
1016
1019
|
}
|
|
1017
1020
|
return n && r.push("SET FOREIGN_KEY_CHECKS = 1"), r;
|
|
1018
|
-
},
|
|
1021
|
+
}, Fn = (e, t) => {
|
|
1019
1022
|
let n = [], r = () => {
|
|
1020
1023
|
for (let e of n) t.unregisterTable(e);
|
|
1021
1024
|
};
|
|
@@ -1037,7 +1040,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1037
1040
|
staged: n,
|
|
1038
1041
|
undo: r
|
|
1039
1042
|
};
|
|
1040
|
-
},
|
|
1043
|
+
}, In = (e, t) => {
|
|
1041
1044
|
let n = new Set(t), r = [];
|
|
1042
1045
|
for (let t of e.tables) {
|
|
1043
1046
|
if (!n.has(t.name)) continue;
|
|
@@ -1054,22 +1057,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1054
1057
|
}
|
|
1055
1058
|
}
|
|
1056
1059
|
return r;
|
|
1057
|
-
},
|
|
1060
|
+
}, Ln = (e, t) => {
|
|
1058
1061
|
let n = Z(X(e.from), t), r = Z(X(e.to), t), i = Z(e.column, t), a = Z(e.toColumn, t);
|
|
1059
1062
|
return `SELECT ${Z(e.primaryKey, t)} AS pk, ${i} AS value FROM ${n} c WHERE ${i} IS NOT NULL AND NOT EXISTS (SELECT 1 FROM ${r} p WHERE p.${a} = c.${i})`;
|
|
1060
|
-
},
|
|
1063
|
+
}, Rn = (e) => {
|
|
1061
1064
|
if (e.length === 0) return;
|
|
1062
1065
|
let t = e.slice(0, 20), n = t.map((e) => ` ${e.table}.${e.primaryKey}: ${e.column} = ${JSON.stringify(e.value)} — no such row in ${e.references}`);
|
|
1063
1066
|
return `the swap could not run: ${e.length} row(s) in the bundle reference a row the bundle does not carry.\n${n.join("\n")}\n` + (e.length > t.length ? ` … and ${e.length - t.length} more\n` : "") + " The target is UNCHANGED — the swap runs in one transaction and none of it committed.\n Every offending row is listed above rather than only the first, so this can be fixed in one pass.";
|
|
1064
|
-
},
|
|
1065
|
-
t.length !== 0 && await e.run(
|
|
1066
|
-
},
|
|
1067
|
-
let i =
|
|
1068
|
-
i.length !== 0 && await e.run(
|
|
1069
|
-
},
|
|
1067
|
+
}, zn = async (e, t) => {
|
|
1068
|
+
t.length !== 0 && await e.run(_e.SqlClient.pipe(n.flatMap((e) => n.forEach(t, (t) => e.unsafe(t), { discard: !0 }))));
|
|
1069
|
+
}, Bn = async (e, t, r) => {
|
|
1070
|
+
let i = Pn(t, r);
|
|
1071
|
+
i.length !== 0 && await e.run(_e.SqlClient.pipe(n.flatMap((e) => e.withTransaction(n.forEach(i, (t) => e.unsafe(t), { discard: !0 })))));
|
|
1072
|
+
}, Vn = async (e, t, r) => {
|
|
1070
1073
|
let i = [];
|
|
1071
1074
|
for (let a of t) {
|
|
1072
|
-
let t = await e.run(
|
|
1075
|
+
let t = await e.run(_e.SqlClient.pipe(n.flatMap((e) => e.unsafe(Ln(a, r)))));
|
|
1073
1076
|
for (let e of t) i.push({
|
|
1074
1077
|
table: a.from,
|
|
1075
1078
|
primaryKey: String(e.pk ?? ""),
|
|
@@ -1079,14 +1082,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1079
1082
|
});
|
|
1080
1083
|
}
|
|
1081
1084
|
return i;
|
|
1082
|
-
},
|
|
1085
|
+
}, Hn = (e, t) => {
|
|
1083
1086
|
let n = new Map(t.map((e, t) => [e, t]));
|
|
1084
1087
|
return e.filter((e) => {
|
|
1085
1088
|
if (e.from === e.to) return !1;
|
|
1086
1089
|
let t = n.get(e.from), r = n.get(e.to);
|
|
1087
1090
|
return t === void 0 || r === void 0 ? !1 : r > t;
|
|
1088
1091
|
});
|
|
1089
|
-
},
|
|
1092
|
+
}, Un = (e) => e === "mysql" || e === "mariadb", Wn = (e) => {
|
|
1090
1093
|
if (e.mode !== "replace") return {
|
|
1091
1094
|
active: !1,
|
|
1092
1095
|
tables: [],
|
|
@@ -1136,7 +1139,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1136
1139
|
tables: [],
|
|
1137
1140
|
blocker: "every table in the bundle is one that describes a deployment, so there is nothing for a staged swap to move."
|
|
1138
1141
|
};
|
|
1139
|
-
let s = o.map((e) => e.name), c =
|
|
1142
|
+
let s = o.map((e) => e.name), c = Un(t) ? [] : Hn(In(n, s), s);
|
|
1140
1143
|
return c.length > 0 ? {
|
|
1141
1144
|
active: !1,
|
|
1142
1145
|
tables: [],
|
|
@@ -1145,7 +1148,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1145
1148
|
active: !0,
|
|
1146
1149
|
tables: o
|
|
1147
1150
|
};
|
|
1148
|
-
},
|
|
1151
|
+
}, Gn = (e) => n.gen(function* () {
|
|
1149
1152
|
if (e.mode !== "replace" || e.dir === void 0 || e.tables.length === 0) return;
|
|
1150
1153
|
if (e.snapshot === void 0) return yield* n.fail(new H({
|
|
1151
1154
|
reason: "rollback capture needs the TARGET's schema, and this run has none.\n `--mode replace` empties the target first, so a run without a capture can leave it\n emptied and unfilled if the process does not survive to roll back. Pass the target\n snapshot, or `--no-rollback` to accept that risk deliberately.",
|
|
@@ -1158,7 +1161,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1158
1161
|
if (t.tables.length === 0) return;
|
|
1159
1162
|
e.onWarn?.(`capturing the target's current rows before emptying it → ${e.dir}\n This is what a failed replace is restored FROM. It is written before the first delete,
|
|
1160
1163
|
so it survives a run whose process does not.`);
|
|
1161
|
-
let r = yield*
|
|
1164
|
+
let r = yield* pn({
|
|
1162
1165
|
store: e.store,
|
|
1163
1166
|
snapshot: t,
|
|
1164
1167
|
dialect: e.dialect ?? "unknown",
|
|
@@ -1174,18 +1177,18 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1174
1177
|
rows: r.tables.reduce((e, t) => e + t.rowCount, 0),
|
|
1175
1178
|
tables: r.tables.length
|
|
1176
1179
|
};
|
|
1177
|
-
}),
|
|
1180
|
+
}), Kn = (e) => `rollback capture: ${e.rows} row(s) across ${e.tables} table(s) → ${e.dir}\n If this run does not finish, restore with: voltro data import ${e.dir} --mode replace`, qn = (e, t) => e.tables.find((e) => e.name === t), Jn = (e, t) => new Map((qn(e, t)?.columns ?? []).map((e) => [e.name, e])), Yn = /__dropped_\d+$/, Xn = (e, t) => {
|
|
1178
1181
|
let n = [];
|
|
1179
1182
|
for (let r of [...e.tables].sort((e, t) => e.name.localeCompare(t.name))) {
|
|
1180
|
-
if (
|
|
1183
|
+
if (qn(t, r.name) === void 0) {
|
|
1181
1184
|
n.push(`table '${r.name}' is in the bundle but MISSING from the target — its rows have nowhere to go`);
|
|
1182
1185
|
continue;
|
|
1183
1186
|
}
|
|
1184
|
-
let e =
|
|
1187
|
+
let e = Jn(t, r.name), i = new Map(r.columns.map((e) => [e.name, e]));
|
|
1185
1188
|
for (let [t, a] of i) {
|
|
1186
1189
|
let i = e.get(t);
|
|
1187
1190
|
if (i === void 0) {
|
|
1188
|
-
n.push(
|
|
1191
|
+
n.push(Yn.test(t) ? `${r.name}.${t}: a soft-dropped column, present only in the SOURCE — reclaim it there (voltro db gc-snapshots --before <date>) or re-export without it; the target is not missing anything` : `${r.name}.${t}: in the bundle, MISSING from the target — the value has nowhere to go`);
|
|
1189
1192
|
continue;
|
|
1190
1193
|
}
|
|
1191
1194
|
i.type !== a.type && n.push(`${r.name}.${t}: type '${a.type}' (bundle) vs '${i.type}' (target)`);
|
|
@@ -1193,7 +1196,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1193
1196
|
for (let [t, a] of e) i.has(t) || !a.nullable && !a.hasDefault && n.push(`${r.name}.${t}: the target requires it (NOT NULL, no default) and the bundle carries no value — every row of this table would fail`);
|
|
1194
1197
|
}
|
|
1195
1198
|
return n.length > 30 ? [...n.slice(0, 30), `… and ${n.length - 30} more difference(s)`] : n;
|
|
1196
|
-
},
|
|
1199
|
+
}, Zn = (e, t, n) => {
|
|
1197
1200
|
let r = re(t);
|
|
1198
1201
|
if (r === e || n === void 0) return {
|
|
1199
1202
|
drifted: !1,
|
|
@@ -1201,14 +1204,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1201
1204
|
targetFingerprint: r,
|
|
1202
1205
|
diff: []
|
|
1203
1206
|
};
|
|
1204
|
-
let i =
|
|
1207
|
+
let i = Xn(n, t);
|
|
1205
1208
|
return {
|
|
1206
1209
|
drifted: i.length > 0,
|
|
1207
1210
|
bundleFingerprint: e,
|
|
1208
1211
|
targetFingerprint: r,
|
|
1209
1212
|
diff: i
|
|
1210
1213
|
};
|
|
1211
|
-
},
|
|
1214
|
+
}, Qn = 2e3, $n = 200, er = /* @__PURE__ */ new Set([
|
|
1212
1215
|
"BundleError",
|
|
1213
1216
|
"CodecError",
|
|
1214
1217
|
"IntegrityError",
|
|
@@ -1217,29 +1220,29 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1217
1220
|
"RowsRefusedError",
|
|
1218
1221
|
"SchemaDriftError",
|
|
1219
1222
|
"StorageError"
|
|
1220
|
-
]),
|
|
1223
|
+
]), tr = (t) => {
|
|
1221
1224
|
let n = o.isFiberFailure(t) ? [...e.failures(t[o.FiberFailureCauseId]), ...e.defects(t[o.FiberFailureCauseId])] : [t];
|
|
1222
1225
|
for (let e of n) {
|
|
1223
1226
|
let t = e?._tag;
|
|
1224
|
-
if (typeof t == "string" &&
|
|
1227
|
+
if (typeof t == "string" && er.has(t)) return e;
|
|
1225
1228
|
if (o.isFiberFailure(e)) {
|
|
1226
|
-
let t =
|
|
1229
|
+
let t = tr(e);
|
|
1227
1230
|
if (t) return t;
|
|
1228
1231
|
}
|
|
1229
1232
|
}
|
|
1230
|
-
},
|
|
1233
|
+
}, nr = (t) => [...e.failures(t)][0] ?? Error(e.pretty(t)), rr = (e) => n.tryPromise({
|
|
1231
1234
|
try: async () => {
|
|
1232
1235
|
let t = await import("node:fs/promises"), n = await import("node:path");
|
|
1233
|
-
return
|
|
1236
|
+
return Et(await t.readFile(n.join(e, K), "utf8"));
|
|
1234
1237
|
},
|
|
1235
1238
|
catch: (e) => new H({
|
|
1236
1239
|
reason: `manifest read/parse failed: ${String(e?.message ?? e)}`,
|
|
1237
1240
|
path: K
|
|
1238
1241
|
})
|
|
1239
|
-
}),
|
|
1242
|
+
}), ir = (e) => {
|
|
1240
1243
|
let t;
|
|
1241
1244
|
return n.gen(function* () {
|
|
1242
|
-
let i = yield* n.promise(() => import("node:path")), a = yield*
|
|
1245
|
+
let i = yield* n.promise(() => import("node:path")), a = yield* rr(e.bundleDir);
|
|
1243
1246
|
if (a.formatVersion !== 1) return yield* n.fail(new H({ reason: `unsupported bundle formatVersion ${a.formatVersion} (expected 1)` }));
|
|
1244
1247
|
if (e.tables !== void 0) {
|
|
1245
1248
|
let t = new Set(a.tables.map((e) => e.name)), r = e.tables.filter((e) => !t.has(e));
|
|
@@ -1260,9 +1263,9 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1260
1263
|
unique: !1,
|
|
1261
1264
|
hasDefault: !1
|
|
1262
1265
|
}))
|
|
1263
|
-
})) }, r =
|
|
1266
|
+
})) }, r = Zn(s.source.schemaFingerprint, e.targetSnapshot, t);
|
|
1264
1267
|
if (r.drifted) {
|
|
1265
|
-
if (!e.force) return yield* n.fail(new
|
|
1268
|
+
if (!e.force) return yield* n.fail(new Ze({
|
|
1266
1269
|
bundleFingerprint: r.bundleFingerprint,
|
|
1267
1270
|
targetFingerprint: r.targetFingerprint,
|
|
1268
1271
|
diff: r.diff
|
|
@@ -1271,15 +1274,15 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1271
1274
|
}
|
|
1272
1275
|
}
|
|
1273
1276
|
if (e.targetDialect && e.targetDialect !== s.source.dialect) {
|
|
1274
|
-
let t =
|
|
1275
|
-
if (t.length > 0 && !e.allowIncompatible) return yield* n.fail(new
|
|
1277
|
+
let t = yn(s.tables, s.source.dialect, e.targetDialect).filter((e) => e.severity === "block");
|
|
1278
|
+
if (t.length > 0 && !e.allowIncompatible) return yield* n.fail(new et({
|
|
1276
1279
|
sourceDialect: s.source.dialect,
|
|
1277
1280
|
targetDialect: e.targetDialect,
|
|
1278
|
-
blocking: t.map(
|
|
1281
|
+
blocking: t.map(bn)
|
|
1279
1282
|
}));
|
|
1280
1283
|
}
|
|
1281
|
-
let c = e.verify ?? !0, p = e.mode ?? "upsert", g = e.atomic ?? p === "replace", _ = e.onConflict ?? "skip", y = e.ledgerPath ?? i.join(e.bundleDir, ".import..ledger.json"), x = yield*
|
|
1282
|
-
if (p === "replace" && s.scope.kind !== "all") return yield* n.fail(new
|
|
1284
|
+
let c = e.verify ?? !0, p = e.mode ?? "upsert", g = e.atomic ?? p === "replace", _ = e.onConflict ?? "skip", y = e.ledgerPath ?? i.join(e.bundleDir, ".import..ledger.json"), x = yield* zt(y);
|
|
1285
|
+
if (p === "replace" && s.scope.kind !== "all") return yield* n.fail(new $e({
|
|
1283
1286
|
mode: p,
|
|
1284
1287
|
reason: `replace refuses a partial bundle (scope='${s.scope.kind}') — truncating would delete rows not in the bundle. Use --mode upsert, or re-export with full scope. To leave specific tables out of a FULL export, use \`--exclude a,b\`: it keeps the scope \`all\` and records what it left out.`
|
|
1285
1288
|
}));
|
|
@@ -1291,8 +1294,8 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1291
1294
|
if (p === "replace") {
|
|
1292
1295
|
let t = s.tables.map((e) => e.name), r = e.store.incomingForeignKeys ? yield* n.tryPromise({
|
|
1293
1296
|
try: () => e.store.incomingForeignKeys(t),
|
|
1294
|
-
catch: (e) => new H({ reason: `foreign-key pre-flight failed: ${
|
|
1295
|
-
}) : e.targetSnapshot === void 0 ? [] :
|
|
1297
|
+
catch: (e) => new H({ reason: `foreign-key pre-flight failed: ${Dn(e)}` })
|
|
1298
|
+
}) : e.targetSnapshot === void 0 ? [] : mn(e.targetSnapshot, t), i = [], a = /* @__PURE__ */ new Map();
|
|
1296
1299
|
for (let t of r) {
|
|
1297
1300
|
if (!a.has(t.from)) {
|
|
1298
1301
|
let r = yield* n.tryPromise({
|
|
@@ -1314,9 +1317,9 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1314
1317
|
rowCount: r
|
|
1315
1318
|
});
|
|
1316
1319
|
}
|
|
1317
|
-
if (i.length > 0) return yield* n.fail(new
|
|
1320
|
+
if (i.length > 0) return yield* n.fail(new $e({
|
|
1318
1321
|
mode: p,
|
|
1319
|
-
reason:
|
|
1322
|
+
reason: hn(i)
|
|
1320
1323
|
}));
|
|
1321
1324
|
}
|
|
1322
1325
|
if (e.dryRun === !0) return e.traceId !== void 0 && (yield* n.promise(() => e.store.update(u, e.traceId, {
|
|
@@ -1343,15 +1346,15 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1343
1346
|
let r;
|
|
1344
1347
|
for (let e of n) e in t && (r ??= { ...t }, delete r[e]);
|
|
1345
1348
|
return r ?? t;
|
|
1346
|
-
},
|
|
1347
|
-
let i =
|
|
1349
|
+
}, T = (e, t, n, r = !1) => {
|
|
1350
|
+
let i = k ? X(t.name) : t.name, a = t.primaryKey, o = re(t.name, n);
|
|
1348
1351
|
return p === "append" ? _ === "fail" ? e.insert(i, o) : e.insertIgnore(i, o, { conflictColumns: [a] }) : p === "replace" ? r ? e.upsert(i, o, { conflictColumns: [a] }) : e.insert(i, o) : e.upsert(i, o, { conflictColumns: [a] });
|
|
1349
|
-
},
|
|
1350
|
-
r.unclassified && (
|
|
1351
|
-
},
|
|
1352
|
+
}, E = (e, t) => e.savepoint ? e.savepoint(t) : t(), D = 0, ie = (t, n, r) => {
|
|
1353
|
+
r.unclassified && (D++, !(D > 3) && e.onWarn?.(`row refused with no driver detail — table '${t.name}', row '${String(n.id ?? "?")}'. The full rendering follows so the LAYER that refused is on the record; it is logged, never returned. ${r.raw}` + (D === 3 ? " (further unclassified refusals are counted, not logged)" : "")));
|
|
1354
|
+
}, ae = (e, t, r = !0) => n.tryPromise({
|
|
1352
1355
|
try: e,
|
|
1353
|
-
catch: (e) =>
|
|
1354
|
-
}).pipe(n.map(() => !0), n.catchAll((e) => n.sync(() => (r && (t.reason = e.reason,
|
|
1356
|
+
catch: (e) => Tn(e)
|
|
1357
|
+
}).pipe(n.map(() => !0), n.catchAll((e) => n.sync(() => (r && (t.reason = e.reason, ie(t.entry, t.row, e)), !1)))), oe = (e) => {
|
|
1355
1358
|
let t = Object.entries(e.entry.columnTypes).filter(([t, n]) => n === "reference" && e.row[t] !== null && e.row[t] !== void 0).map(([e]) => e);
|
|
1356
1359
|
if (t.length !== 0) return {
|
|
1357
1360
|
...e.row,
|
|
@@ -1375,7 +1378,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1375
1378
|
};
|
|
1376
1379
|
t.refused++, e.derived || t.primary++, a.set(e.table, t);
|
|
1377
1380
|
}
|
|
1378
|
-
return new
|
|
1381
|
+
return new Xe({
|
|
1379
1382
|
rows: i.slice(0, 20),
|
|
1380
1383
|
primaryCount: r.filter((e) => !e.derived).length,
|
|
1381
1384
|
totalCount: e.length,
|
|
@@ -1390,33 +1393,33 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1390
1393
|
for (; r.length > 0 && a;) {
|
|
1391
1394
|
a = !1;
|
|
1392
1395
|
let t = [];
|
|
1393
|
-
for (let n of r) (yield*
|
|
1396
|
+
for (let n of r) (yield* ae(() => E(e, () => T(e, n.entry, n.row, !0)), n)) ? a = !0 : t.push(n);
|
|
1394
1397
|
if (!a && t.length > 0) for (let n = t.length - 1; n >= 0; n--) {
|
|
1395
1398
|
let r = t[n], o = oe(r);
|
|
1396
|
-
o !== void 0 && (yield*
|
|
1399
|
+
o !== void 0 && (yield* ae(() => E(e, () => T(e, r.entry, o, !0)), r, !1)) && (i.push(r), t.splice(n, 1), a = !0);
|
|
1397
1400
|
}
|
|
1398
1401
|
r = t;
|
|
1399
1402
|
}
|
|
1400
|
-
for (let t of i) (yield*
|
|
1403
|
+
for (let t of i) (yield* ae(() => E(e, () => e.upsert(t.entry.name, t.row, { conflictColumns: [t.entry.primaryKey] })), t)) || (r = [...r, t]);
|
|
1401
1404
|
if (r.length > 0) return yield* n.fail(se(r));
|
|
1402
1405
|
}), O = (() => {
|
|
1403
1406
|
let t = e.targetDialect;
|
|
1404
1407
|
return t === "postgres" || t === "mysql" || t === "mariadb" || t === "sqlite" || t === "mssql" ? t : void 0;
|
|
1405
|
-
})(),
|
|
1408
|
+
})(), ue = Wn({
|
|
1406
1409
|
mode: p,
|
|
1407
1410
|
...e.targetDialect === void 0 ? {} : { targetDialect: e.targetDialect },
|
|
1408
1411
|
...e.targetSnapshot === void 0 ? {} : { targetSnapshot: e.targetSnapshot },
|
|
1409
1412
|
bundleTables: s.tables.map((e) => e.name),
|
|
1410
1413
|
isSkipped: V,
|
|
1411
|
-
canRunSql:
|
|
1412
|
-
}),
|
|
1413
|
-
if (p === "replace" && !
|
|
1414
|
+
canRunSql: kn(e.store)
|
|
1415
|
+
}), de = ue.tables, fe = s.tables.filter((e) => !V(e.name) && S(e.name)).map((e) => e.name), k = ue.active, pe = !1, A = 0, j = 0, he, M = 0, N = 0, ge = (t, r) => n.gen(function* () {
|
|
1416
|
+
if (p === "replace" && !k && !(r && x.truncated)) {
|
|
1414
1417
|
e.recordInterruption === !0 && (yield* n.tryPromise({
|
|
1415
1418
|
try: () => t.insert(d, {
|
|
1416
|
-
id: m("repl",
|
|
1417
|
-
startedAt:
|
|
1419
|
+
id: m("repl", _e),
|
|
1420
|
+
startedAt: P,
|
|
1418
1421
|
tables: String(s.tables.length),
|
|
1419
|
-
capture:
|
|
1422
|
+
capture: F?.dir ?? null,
|
|
1420
1423
|
via: e.via ?? "direct"
|
|
1421
1424
|
}),
|
|
1422
1425
|
catch: (e) => new H({ reason: `could not record that this replace started: ${String(e?.message ?? e)}\n The marker is what makes an interrupted run visible instead of silent, so the run does
|
|
@@ -1429,7 +1432,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1429
1432
|
});
|
|
1430
1433
|
yield* n.tryPromise({
|
|
1431
1434
|
try: o,
|
|
1432
|
-
catch: (e) => new H({ reason: `emptying the target for --mode replace failed (nothing was deleted): ${
|
|
1435
|
+
catch: (e) => new H({ reason: `emptying the target for --mode replace failed (nothing was deleted): ${Dn(e)}` })
|
|
1433
1436
|
}), r && (x.truncated = !0, yield* J(y, x));
|
|
1434
1437
|
}
|
|
1435
1438
|
let a = [], o = [], u = [], f = [], h = s.tables.length;
|
|
@@ -1440,7 +1443,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1440
1443
|
continue;
|
|
1441
1444
|
}
|
|
1442
1445
|
if (r && m.name in x.tables) {
|
|
1443
|
-
u.push(m.name),
|
|
1446
|
+
u.push(m.name), N++, M += x.tables[m.name].rowCount, q(e.onProgress, {
|
|
1444
1447
|
phase: "import",
|
|
1445
1448
|
table: m.name,
|
|
1446
1449
|
index: d,
|
|
@@ -1462,17 +1465,17 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1462
1465
|
total: m.rowCount
|
|
1463
1466
|
});
|
|
1464
1467
|
let v = a.length, b = n.gen(function* () {
|
|
1465
|
-
let { createHash: r } = yield* n.promise(() => import("node:crypto")), i = r("sha256"), o = 0, c =
|
|
1468
|
+
let { createHash: r } = yield* n.promise(() => import("node:crypto")), i = r("sha256"), o = 0, c = me("bundle", () => le(_).pipe(yt(s.compression))).pipe(l.tap((e) => n.sync(() => i.update(e)))), u = async (e) => {
|
|
1466
1469
|
let n = {
|
|
1467
1470
|
entry: m,
|
|
1468
1471
|
row: e,
|
|
1469
1472
|
reason: ""
|
|
1470
1473
|
};
|
|
1471
1474
|
try {
|
|
1472
|
-
await
|
|
1475
|
+
await E(t, () => T(t, m, e));
|
|
1473
1476
|
} catch (t) {
|
|
1474
|
-
let r =
|
|
1475
|
-
n.reason = r.reason,
|
|
1477
|
+
let r = Tn(t);
|
|
1478
|
+
n.reason = r.reason, ie(m, e, r), a.push(n);
|
|
1476
1479
|
}
|
|
1477
1480
|
}, d = yield* n.promise(async () => {
|
|
1478
1481
|
let n = e.copyLoader;
|
|
@@ -1513,13 +1516,13 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1513
1516
|
S = [];
|
|
1514
1517
|
try {
|
|
1515
1518
|
await t.savepoint(async () => {
|
|
1516
|
-
for (let n of e) await
|
|
1519
|
+
for (let n of e) await T(t, m, n);
|
|
1517
1520
|
});
|
|
1518
1521
|
} catch {
|
|
1519
1522
|
for (let t of e) await u(t);
|
|
1520
1523
|
}
|
|
1521
1524
|
};
|
|
1522
|
-
return yield* l.runForEach(
|
|
1525
|
+
return yield* l.runForEach(en(c, m.name, m.columnTypes), (e) => n.promise(async () => {
|
|
1523
1526
|
if (o++, d) {
|
|
1524
1527
|
v.push(e), v.length >= h && await y();
|
|
1525
1528
|
return;
|
|
@@ -1533,14 +1536,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1533
1536
|
rowCount: o,
|
|
1534
1537
|
checksum: i.digest("hex")
|
|
1535
1538
|
};
|
|
1536
|
-
}), { rowCount: S, checksum: C } = yield*
|
|
1539
|
+
}), { rowCount: S, checksum: C } = yield* Lt("import", m.name, d, h, (e) => e.rowCount, b);
|
|
1537
1540
|
if (c) {
|
|
1538
|
-
if (C !== m.checksum) return yield* n.fail(new
|
|
1541
|
+
if (C !== m.checksum) return yield* n.fail(new Je({
|
|
1539
1542
|
what: `table ${m.name} checksum`,
|
|
1540
1543
|
expected: m.checksum,
|
|
1541
1544
|
actual: C
|
|
1542
1545
|
}));
|
|
1543
|
-
if (S !== m.rowCount) return yield* n.fail(new
|
|
1546
|
+
if (S !== m.rowCount) return yield* n.fail(new Je({
|
|
1544
1547
|
what: `table ${m.name} rowCount`,
|
|
1545
1548
|
expected: String(m.rowCount),
|
|
1546
1549
|
actual: String(S)
|
|
@@ -1554,7 +1557,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1554
1557
|
event: "done",
|
|
1555
1558
|
rowsDone: S,
|
|
1556
1559
|
total: m.rowCount
|
|
1557
|
-
}),
|
|
1560
|
+
}), j++, A += S, he?.(), r && (a.length > v ? o.push({
|
|
1558
1561
|
name: m.name,
|
|
1559
1562
|
rowCount: S
|
|
1560
1563
|
}) : (x.tables[m.name] = {
|
|
@@ -1565,7 +1568,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1565
1568
|
if (a.length > 0 && (yield* ce(t, a)), p === "replace" && (yield* n.promise(() => t.deleteMany(d, { where: {
|
|
1566
1569
|
column: "startedAt",
|
|
1567
1570
|
op: "lte",
|
|
1568
|
-
value:
|
|
1571
|
+
value: P
|
|
1569
1572
|
} }).then(() => void 0, () => void 0))), r && o.length > 0) {
|
|
1570
1573
|
for (let e of o) {
|
|
1571
1574
|
let t = s.tables.find((t) => t.name === e.name);
|
|
@@ -1577,14 +1580,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1577
1580
|
yield* J(y, x);
|
|
1578
1581
|
}
|
|
1579
1582
|
{
|
|
1580
|
-
let t =
|
|
1583
|
+
let t = Ke(f, "skipped");
|
|
1581
1584
|
t !== void 0 && e.onWarn?.(t);
|
|
1582
1585
|
}
|
|
1583
1586
|
if (u.length > 0) {
|
|
1584
1587
|
let t = u.length === s.tables.length;
|
|
1585
1588
|
e.onWarn?.(`resume: ${u.length} of ${s.tables.length} table(s) were already applied by an earlier run of THIS bundle directory, so this run wrote NO rows for them${t ? " — that is every table in the bundle, so nothing was written at all" : ""}. Tables: ${u.join(", ")}. Delete ${y} to force a full re-import.`);
|
|
1586
1589
|
}
|
|
1587
|
-
}),
|
|
1590
|
+
}), _e = `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`, P = /* @__PURE__ */ new Date(), F = yield* Gn({
|
|
1588
1591
|
store: e.store,
|
|
1589
1592
|
mode: p,
|
|
1590
1593
|
dir: e.rollbackDir,
|
|
@@ -1593,15 +1596,15 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1593
1596
|
tables: s.tables.map((e) => e.name).filter((e) => !V(e)),
|
|
1594
1597
|
onWarn: e.onWarn
|
|
1595
1598
|
});
|
|
1596
|
-
|
|
1597
|
-
try: () => e.onRollbackCaptured(
|
|
1599
|
+
F !== void 0 && (e.onRollbackCaptured !== void 0 && (yield* n.tryPromise({
|
|
1600
|
+
try: () => e.onRollbackCaptured(F),
|
|
1598
1601
|
catch: (e) => new H({
|
|
1599
1602
|
reason: `the rollback capture could not be stored durably, so the import did not start and the target is untouched: ${String(e?.message ?? e)}\n The capture only helps if it outlives this process — that is the failure it exists for.`,
|
|
1600
|
-
path:
|
|
1603
|
+
path: F.dir
|
|
1601
1604
|
})
|
|
1602
|
-
})), e.onWarn?.(
|
|
1603
|
-
let
|
|
1604
|
-
|
|
1605
|
+
})), e.onWarn?.(Kn(F)));
|
|
1606
|
+
let ve = (e) => p === "replace" ? ee(e) : e(), I = (e) => p === "replace" ? te(e) : e, L = e.traceId ?? m("dimp", `${Date.now()}-${s.source.schemaFingerprint ?? ""}`), ye = e.traceId !== void 0, R = (e.targetSnapshot?.tables.some((e) => e.name === u) ?? !1) || v(u) !== void 0;
|
|
1607
|
+
R && h(f), R && e.traceId === void 0 && (yield* n.promise(() => e.store.insert(u, {
|
|
1605
1608
|
id: L,
|
|
1606
1609
|
mode: p,
|
|
1607
1610
|
via: e.via ?? "direct",
|
|
@@ -1610,38 +1613,38 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1610
1613
|
sourceFingerprint: s.source.schemaFingerprint ?? null,
|
|
1611
1614
|
tablesWritten: 0,
|
|
1612
1615
|
rowsWritten: 0,
|
|
1613
|
-
staged: p === "replace" ?
|
|
1616
|
+
staged: p === "replace" ? k : null
|
|
1614
1617
|
}).then(() => {
|
|
1615
|
-
|
|
1618
|
+
ye = !0;
|
|
1616
1619
|
}, (t) => {
|
|
1617
1620
|
e.onWarn?.(`the import trace could not be written (${String(t?.message ?? t)}).\n The import continues — this is a record of what happened, not a safety check. Run
|
|
1618
1621
|
\`voltro db apply\` so the next one is recorded.`);
|
|
1619
|
-
}))), e.traceId !== void 0 &&
|
|
1620
|
-
staged: p === "replace" ?
|
|
1622
|
+
}))), e.traceId !== void 0 && R && (yield* n.promise(() => e.store.update(u, L, {
|
|
1623
|
+
staged: p === "replace" ? k : null,
|
|
1621
1624
|
sourceFingerprint: s.source.schemaFingerprint ?? null
|
|
1622
1625
|
}).then(() => void 0, () => void 0)));
|
|
1623
1626
|
let be = 0, xe = !1;
|
|
1624
|
-
|
|
1625
|
-
if (!
|
|
1627
|
+
he = () => {
|
|
1628
|
+
if (!ye || xe) return;
|
|
1626
1629
|
let t = Date.now();
|
|
1627
|
-
t - be <
|
|
1628
|
-
tablesWritten:
|
|
1629
|
-
rowsWritten:
|
|
1630
|
+
t - be < Qn || (be = t, e.store.update(u, L, {
|
|
1631
|
+
tablesWritten: j,
|
|
1632
|
+
rowsWritten: A
|
|
1630
1633
|
}).then(() => void 0, () => {
|
|
1631
1634
|
xe = !0;
|
|
1632
1635
|
}));
|
|
1633
1636
|
};
|
|
1634
|
-
let Se = (t) =>
|
|
1637
|
+
let Se = (t) => ye ? e.store.update(u, L, {
|
|
1635
1638
|
finishedAt: t === null ? /* @__PURE__ */ new Date() : null,
|
|
1636
|
-
tablesWritten:
|
|
1637
|
-
rowsWritten:
|
|
1639
|
+
tablesWritten: j,
|
|
1640
|
+
rowsWritten: A,
|
|
1638
1641
|
failure: t
|
|
1639
1642
|
}).then(() => void 0, () => void 0) : Promise.resolve();
|
|
1640
|
-
if (t = (e) => Se(e), p === "replace" && !
|
|
1643
|
+
if (t = (e) => Se(e), p === "replace" && !k && ue.blocker !== void 0 && e.onWarn?.(An(ue.blocker)), p === "replace" && fe.length > 0 && e.onWarn?.(`write recorders are SUSPENDED for this replace (${fe.length} table(s) have one).\n A replace sets a state rather than changing rows, so a per-row history entry would describe
|
|
1641
1644
|
something that did not happen — and this path already writes through the raw store, without
|
|
1642
|
-
tenant scoping or \`audit()\` stamping, for the same reason.`),
|
|
1643
|
-
e.onWarn?.(`staging ${
|
|
1644
|
-
let t = e.store, r =
|
|
1645
|
+
tenant scoping or \`audit()\` stamping, for the same reason.`), k) {
|
|
1646
|
+
e.onWarn?.(`staging ${de.length} table(s) before the swap — the target keeps its rows until the load stands.\n The destructive step is one server-side transaction at the end, not the whole load.`);
|
|
1647
|
+
let t = e.store, r = de.map((e) => e.name), i = Fn(r, {
|
|
1645
1648
|
getTable: (e) => v(e),
|
|
1646
1649
|
registerTable: (e) => {
|
|
1647
1650
|
C(e);
|
|
@@ -1649,36 +1652,36 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1649
1652
|
unregisterTable: ne
|
|
1650
1653
|
}), a = !1;
|
|
1651
1654
|
try {
|
|
1652
|
-
let i = g ? r : r.filter((e) => !
|
|
1655
|
+
let i = g ? r : r.filter((e) => !Bt(x, e));
|
|
1653
1656
|
yield* n.tryPromise({
|
|
1654
1657
|
try: async () => {
|
|
1655
|
-
await
|
|
1658
|
+
await zn(t, i.map((e) => Nn(e, O))), await zn(t, i.map((e) => Mn(e, O)));
|
|
1656
1659
|
},
|
|
1657
1660
|
catch: (e) => new H({ reason: `could not prepare the staging tables, so the import did not start and the target is untouched: ${String(e?.message ?? e)}` })
|
|
1658
|
-
}), yield*
|
|
1659
|
-
try: () =>
|
|
1661
|
+
}), yield* I(ge(e.store, !g)), !g && x.truncated === !0 ? a = !0 : yield* n.tryPromise({
|
|
1662
|
+
try: () => Bn(t, de, O).then(() => {
|
|
1660
1663
|
a = !0;
|
|
1661
1664
|
}),
|
|
1662
1665
|
catch: (e) => new H({ reason: String(e?.message ?? e) })
|
|
1663
1666
|
}).pipe(n.catchAll((i) => n.gen(function* () {
|
|
1664
|
-
let a =
|
|
1667
|
+
let a = Rn(yield* n.promise(() => Vn(t, In(e.targetSnapshot, r), O).then((e) => e, () => [])));
|
|
1665
1668
|
return yield* n.fail(new H({ reason: a ?? `the swap failed and the target is UNCHANGED: ${i.reason}` }));
|
|
1666
1669
|
}))), !g && a && x.truncated !== !0 && (x.truncated = !0, yield* J(y, x));
|
|
1667
1670
|
} finally {
|
|
1668
|
-
i.undo(), a || g ? yield* n.promise(() =>
|
|
1671
|
+
i.undo(), a || g ? yield* n.promise(() => zn(t, r.map((e) => Nn(e, O))).then(() => void 0, () => void 0)) : e.onWarn?.("the staged rows are KEPT so a re-run can continue from them rather than reload.\n If you are not going to re-run this bundle, drop them: voltro data clear-staging --yes");
|
|
1669
1672
|
}
|
|
1670
1673
|
} else g ? yield* n.tryPromise({
|
|
1671
1674
|
try: () => e.store.transactional(async (e) => {
|
|
1672
|
-
let t = await
|
|
1673
|
-
if (r.isFailure(t)) throw
|
|
1675
|
+
let t = await ve(() => n.runPromiseExit(ge(e, !1)));
|
|
1676
|
+
if (r.isFailure(t)) throw nr(t.cause);
|
|
1674
1677
|
}),
|
|
1675
|
-
catch: (e) =>
|
|
1676
|
-
}) : yield*
|
|
1678
|
+
catch: (e) => tr(e) ?? new H({ reason: `atomic import failed (rolled back): ${String(e?.message ?? e)}` })
|
|
1679
|
+
}) : yield* I(ge(e.store, !0));
|
|
1677
1680
|
if (e.assets && s.assets.index && !e.assetsAlreadyRestored) {
|
|
1678
1681
|
let t = e.assets;
|
|
1679
|
-
yield*
|
|
1682
|
+
yield* mt({
|
|
1680
1683
|
sink: t,
|
|
1681
|
-
assetsDir: i.join(e.bundleDir,
|
|
1684
|
+
assetsDir: i.join(e.bundleDir, kt),
|
|
1682
1685
|
indexPath: i.join(e.bundleDir, s.assets.index ?? "assets/index.ndjson"),
|
|
1683
1686
|
progress: {
|
|
1684
1687
|
done: (e) => e in x.assets,
|
|
@@ -1688,26 +1691,26 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1688
1691
|
}
|
|
1689
1692
|
return yield* n.promise(() => Se(null)), {
|
|
1690
1693
|
manifest: s,
|
|
1691
|
-
tablesWritten:
|
|
1692
|
-
rowsWritten:
|
|
1693
|
-
tablesSkipped:
|
|
1694
|
-
rowsSkipped:
|
|
1695
|
-
fullyResumed:
|
|
1696
|
-
...
|
|
1694
|
+
tablesWritten: j,
|
|
1695
|
+
rowsWritten: A,
|
|
1696
|
+
tablesSkipped: N,
|
|
1697
|
+
rowsSkipped: M,
|
|
1698
|
+
fullyResumed: j === 0 && N > 0,
|
|
1699
|
+
...F === void 0 ? {} : { rollback: F }
|
|
1697
1700
|
};
|
|
1698
1701
|
}).pipe(n.tapError((e) => n.promise(() => t?.(e?.reason ?? e?._tag ?? "the import did not finish") ?? Promise.resolve())));
|
|
1699
|
-
},
|
|
1702
|
+
}, ar = (e) => e, or = (e) => {
|
|
1700
1703
|
if (e.allowLive || e.liveInstance === null || e.sameTarget === "different") return { refuse: !1 };
|
|
1701
1704
|
let t = e.targetLabel === void 0 ? "" : ` Target: ${e.targetLabel}.`, n = e.sameTarget === "same" ? " That instance is connected to the SAME database." : " We could not confirm which database that instance is connected to, so this is refused on the conservative reading — an older instance, or one whose connection could not be parsed, reports nothing to compare.";
|
|
1702
1705
|
return {
|
|
1703
1706
|
refuse: !0,
|
|
1704
1707
|
message: `refusing to write into a target with a LIVE instance (${e.liveInstance}).${t}${n} A direct import is an uncoordinated concurrent writer — readers see partial state, the reactive layer either storms or goes stale, and rows race with live writes. Re-run with --allow-live to override, or use a live-safe strategy (shadow-swap for replace, or the api target).`
|
|
1705
1708
|
};
|
|
1706
|
-
}, Q = Buffer.from("VBUNDLE2"),
|
|
1709
|
+
}, Q = Buffer.from("VBUNDLE2"), sr = 0, cr = 1, lr = 2, ur = 32, dr = async (e) => {
|
|
1707
1710
|
let t = [], n = async (r) => {
|
|
1708
1711
|
let i;
|
|
1709
1712
|
try {
|
|
1710
|
-
i = await
|
|
1713
|
+
i = await F(R(e, r), { withFileTypes: !0 });
|
|
1711
1714
|
} catch {
|
|
1712
1715
|
return;
|
|
1713
1716
|
}
|
|
@@ -1717,22 +1720,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1717
1720
|
}
|
|
1718
1721
|
};
|
|
1719
1722
|
return await n(""), t.sort();
|
|
1720
|
-
},
|
|
1723
|
+
}, fr = (e, t) => {
|
|
1721
1724
|
let n = Buffer.from(e, "utf8"), r = Buffer.alloc(5 + n.length + 8);
|
|
1722
|
-
return r.writeUInt8(
|
|
1723
|
-
},
|
|
1725
|
+
return r.writeUInt8(cr, 0), r.writeUInt32BE(n.length, 1), n.copy(r, 5), r.writeBigUInt64BE(BigInt(t), 5 + n.length), r;
|
|
1726
|
+
}, pr = (e, t, n) => {
|
|
1724
1727
|
let r = Buffer.from(e, "utf8"), i = Buffer.from(t, "utf8"), a = Buffer.alloc(5 + r.length + 2 + i.length + 8), o = 0;
|
|
1725
|
-
return a.writeUInt8(
|
|
1728
|
+
return a.writeUInt8(lr, o), o += 1, a.writeUInt32BE(r.length, o), o += 4, r.copy(a, o), o += r.length, a.writeUInt16BE(i.length, o), o += 2, i.copy(a, o), o += i.length, a.writeBigUInt64BE(BigInt(n), o), a;
|
|
1726
1729
|
};
|
|
1727
|
-
async function*
|
|
1730
|
+
async function* mr(e) {
|
|
1728
1731
|
yield new Uint8Array(Q);
|
|
1729
|
-
for (let t of await
|
|
1730
|
-
let n = R(e.dir, t), r = await
|
|
1731
|
-
if (yield new Uint8Array(
|
|
1732
|
+
for (let t of await dr(e.dir)) {
|
|
1733
|
+
let n = R(e.dir, t), r = await ve(n);
|
|
1734
|
+
if (yield new Uint8Array(fr(t, r.size)), r.size > 0) for await (let e of le(n)) yield new Uint8Array(e);
|
|
1732
1735
|
}
|
|
1733
1736
|
if (e.blobs) for await (let t of e.blobs.list()) {
|
|
1734
|
-
yield new Uint8Array(
|
|
1735
|
-
let n =
|
|
1737
|
+
yield new Uint8Array(pr(t.key, t.contentType, t.size));
|
|
1738
|
+
let n = D("sha256"), r = 0;
|
|
1736
1739
|
for await (let i of e.blobs.open(t.key)) {
|
|
1737
1740
|
let e = Buffer.from(i);
|
|
1738
1741
|
n.update(e), r += e.length, yield new Uint8Array(e);
|
|
@@ -1740,11 +1743,11 @@ async function* fr(e) {
|
|
|
1740
1743
|
if (r !== t.size) throw Error(`blob '${t.key}' size mismatch: header ${t.size}, streamed ${r}`);
|
|
1741
1744
|
yield new Uint8Array(n.digest());
|
|
1742
1745
|
}
|
|
1743
|
-
yield new Uint8Array(Buffer.from([
|
|
1746
|
+
yield new Uint8Array(Buffer.from([sr]));
|
|
1744
1747
|
}
|
|
1745
|
-
var
|
|
1746
|
-
let n =
|
|
1747
|
-
await
|
|
1748
|
+
var hr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), gr = (e) => new Promise((t) => e.end(t)), _r = async (e, t) => {
|
|
1749
|
+
let n = be(t.dir);
|
|
1750
|
+
await P(n, { recursive: !0 });
|
|
1748
1751
|
let r = Buffer.alloc(0), i = e[Symbol.asyncIterator](), a = !1, o = async () => {
|
|
1749
1752
|
let { value: e, done: t } = await i.next();
|
|
1750
1753
|
return t ? (a = !0, !1) : (r = r.length === 0 ? Buffer.from(e) : Buffer.concat([r, Buffer.from(e)]), !0);
|
|
@@ -1759,24 +1762,24 @@ var pr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), mr
|
|
|
1759
1762
|
for (;;) {
|
|
1760
1763
|
await s(1);
|
|
1761
1764
|
let e = c(1).readUInt8(0);
|
|
1762
|
-
if (e ===
|
|
1763
|
-
if (e ===
|
|
1765
|
+
if (e === sr) return;
|
|
1766
|
+
if (e === cr) {
|
|
1764
1767
|
await s(4);
|
|
1765
1768
|
let e = c(4).readUInt32BE(0);
|
|
1766
1769
|
await s(e);
|
|
1767
1770
|
let t = c(e).toString("utf8");
|
|
1768
1771
|
await s(8);
|
|
1769
|
-
let i = c(8).readBigUInt64BE(0), a =
|
|
1770
|
-
if (a !== n && !a.startsWith(n +
|
|
1771
|
-
await
|
|
1772
|
+
let i = c(8).readBigUInt64BE(0), a = be(n, t);
|
|
1773
|
+
if (a !== n && !a.startsWith(n + xe)) throw Error(`archive path '${t}' escapes the destination`);
|
|
1774
|
+
await P(ye(a), { recursive: !0 });
|
|
1772
1775
|
let o = O(a);
|
|
1773
1776
|
for (; i > 0n;) {
|
|
1774
1777
|
r.length === 0 && await s(1);
|
|
1775
1778
|
let e = i < BigInt(r.length) ? Number(i) : r.length;
|
|
1776
|
-
await
|
|
1779
|
+
await hr(o, c(e)), i -= BigInt(e);
|
|
1777
1780
|
}
|
|
1778
|
-
await
|
|
1779
|
-
} else if (e ===
|
|
1781
|
+
await gr(o);
|
|
1782
|
+
} else if (e === lr) {
|
|
1780
1783
|
await s(4);
|
|
1781
1784
|
let e = c(4).readUInt32BE(0);
|
|
1782
1785
|
await s(e);
|
|
@@ -1786,24 +1789,24 @@ var pr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), mr
|
|
|
1786
1789
|
await s(i);
|
|
1787
1790
|
let a = c(i).toString("utf8");
|
|
1788
1791
|
await s(8);
|
|
1789
|
-
let o = c(8).readBigUInt64BE(0), l = await t.blobs.has(n), u =
|
|
1792
|
+
let o = c(8).readBigUInt64BE(0), l = await t.blobs.has(n), u = D("sha256"), d = new N(), f = l ? Promise.resolve() : t.blobs.write(n, d, {
|
|
1790
1793
|
contentType: a,
|
|
1791
1794
|
size: Number(o)
|
|
1792
1795
|
}), p = o;
|
|
1793
1796
|
for (; p > 0n;) {
|
|
1794
1797
|
r.length === 0 && await s(1);
|
|
1795
1798
|
let e = p < BigInt(r.length) ? Number(p) : r.length, t = c(e);
|
|
1796
|
-
u.update(t), l || await
|
|
1799
|
+
u.update(t), l || await hr(d, t), p -= BigInt(e);
|
|
1797
1800
|
}
|
|
1798
|
-
l ? d.destroy() : await
|
|
1799
|
-
let m = c(
|
|
1801
|
+
l ? d.destroy() : await gr(d), await f, await s(ur);
|
|
1802
|
+
let m = c(ur);
|
|
1800
1803
|
if (!u.digest().equals(m)) throw Error(`blob '${n}' failed integrity (sha mismatch)`);
|
|
1801
1804
|
} else throw Error(`unknown bundle entry kind ${e}`);
|
|
1802
1805
|
}
|
|
1803
1806
|
} finally {
|
|
1804
1807
|
a || await Promise.resolve(i.return?.()).catch(() => void 0);
|
|
1805
1808
|
}
|
|
1806
|
-
},
|
|
1809
|
+
}, vr = async (e, t) => {
|
|
1807
1810
|
let n = new Set(t), r = /* @__PURE__ */ new Map(), i = Buffer.alloc(0), a = e[Symbol.asyncIterator](), o = async () => {
|
|
1808
1811
|
let { value: e, done: t } = await a.next();
|
|
1809
1812
|
return !t && (i = i.length === 0 ? Buffer.from(e) : Buffer.concat([i, Buffer.from(e)]), !0);
|
|
@@ -1825,8 +1828,8 @@ var pr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), mr
|
|
|
1825
1828
|
if (!await s(Q.length) || !c(Q.length).equals(Q)) throw Error("not a bundle archive (bad magic)");
|
|
1826
1829
|
for (; await s(1);) {
|
|
1827
1830
|
let e = c(1).readUInt8(0);
|
|
1828
|
-
if (e ===
|
|
1829
|
-
if (e !==
|
|
1831
|
+
if (e === sr || e === lr) break;
|
|
1832
|
+
if (e !== cr) throw Error(`unknown bundle entry kind ${e}`);
|
|
1830
1833
|
if (!await s(4)) break;
|
|
1831
1834
|
let t = c(4).readUInt32BE(0);
|
|
1832
1835
|
if (!await s(t)) break;
|
|
@@ -1836,17 +1839,17 @@ var pr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), mr
|
|
|
1836
1839
|
if (a === null || n.has(i) && (r.set(i, a), n.delete(i), n.size === 0)) break;
|
|
1837
1840
|
}
|
|
1838
1841
|
return r;
|
|
1839
|
-
},
|
|
1842
|
+
}, yr = (e, t) => _r(e, {
|
|
1840
1843
|
dir: t,
|
|
1841
|
-
blobs:
|
|
1842
|
-
}),
|
|
1844
|
+
blobs: br(t)
|
|
1845
|
+
}), br = (e) => {
|
|
1843
1846
|
let t = /* @__PURE__ */ new Set();
|
|
1844
1847
|
return {
|
|
1845
1848
|
has: async (e) => t.has(e),
|
|
1846
1849
|
write: async (n, r, i) => {
|
|
1847
1850
|
let a = await import("node:fs/promises"), { pipeline: o } = await import("node:stream/promises"), { Transform: s } = await import("node:stream"), c = R(e, "assets");
|
|
1848
|
-
await
|
|
1849
|
-
let l =
|
|
1851
|
+
await P(c, { recursive: !0 });
|
|
1852
|
+
let l = D("sha256"), u = 0, d = new s({ transform(e, t, n) {
|
|
1850
1853
|
l.update(e), u += e.length, n(null, e);
|
|
1851
1854
|
} }), f = R(c, `.tmp-${Date.now()}-${t.size}`);
|
|
1852
1855
|
await o(r, d, O(f));
|
|
@@ -1859,33 +1862,33 @@ var pr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), mr
|
|
|
1859
1862
|
})}\n`), t.add(n);
|
|
1860
1863
|
}
|
|
1861
1864
|
};
|
|
1862
|
-
},
|
|
1865
|
+
}, xr = Se(se), Sr = Buffer.from("VENC1\0\0\0"), Cr = 32, wr = 16, Tr = 7, Er = 16, Dr = 262144, Or = {
|
|
1863
1866
|
N: 32768,
|
|
1864
1867
|
r: 8,
|
|
1865
1868
|
p: 1
|
|
1866
|
-
},
|
|
1869
|
+
}, kr = 134217728, Ar = 43, jr = (e, t, n) => {
|
|
1867
1870
|
let r = Buffer.alloc(12);
|
|
1868
|
-
return e.copy(r, 0, 0,
|
|
1871
|
+
return e.copy(r, 0, 0, Tr), r.writeUInt32BE(t >>> 0, Tr), r.writeUInt8(+!!n, 11), r;
|
|
1869
1872
|
};
|
|
1870
|
-
async function*
|
|
1873
|
+
async function* Mr(e, t) {
|
|
1871
1874
|
if (!t) throw Error("encryptStream: a non-empty passphrase is required");
|
|
1872
|
-
let n =
|
|
1873
|
-
...
|
|
1874
|
-
maxmem:
|
|
1875
|
-
}), a = Buffer.alloc(
|
|
1876
|
-
|
|
1875
|
+
let n = ae(wr), r = ae(Tr), i = await xr(t, n, Cr, {
|
|
1876
|
+
...Or,
|
|
1877
|
+
maxmem: kr
|
|
1878
|
+
}), a = Buffer.alloc(Ar);
|
|
1879
|
+
Sr.copy(a, 0), a.writeUInt32BE(Or.N, 8), a.writeUInt32BE(Or.r, 12), a.writeUInt32BE(Or.p, 16), n.copy(a, 20), r.copy(a, 36), yield new Uint8Array(a);
|
|
1877
1880
|
let o = 0, s = (e, t) => {
|
|
1878
|
-
let n =
|
|
1881
|
+
let n = T("aes-256-gcm", i, jr(r, o, t));
|
|
1879
1882
|
o === 0 && n.setAAD(a);
|
|
1880
1883
|
let s = Buffer.concat([n.update(e), n.final()]), c = n.getAuthTag();
|
|
1881
1884
|
o++;
|
|
1882
|
-
let l = Buffer.alloc(5 + s.length +
|
|
1883
|
-
return l.writeUInt8(+!!t, 0), l.writeUInt32BE(s.length +
|
|
1885
|
+
let l = Buffer.alloc(5 + s.length + Er);
|
|
1886
|
+
return l.writeUInt8(+!!t, 0), l.writeUInt32BE(s.length + Er, 1), s.copy(l, 5), c.copy(l, 5 + s.length), new Uint8Array(l);
|
|
1884
1887
|
}, c = Buffer.alloc(0);
|
|
1885
|
-
for await (let t of e) for (c = c.length === 0 ? Buffer.from(t) : Buffer.concat([c, Buffer.from(t)]); c.length >
|
|
1888
|
+
for await (let t of e) for (c = c.length === 0 ? Buffer.from(t) : Buffer.concat([c, Buffer.from(t)]); c.length > Dr;) yield s(c.subarray(0, Dr), !1), c = c.subarray(Dr);
|
|
1886
1889
|
yield s(c, !0);
|
|
1887
1890
|
}
|
|
1888
|
-
async function*
|
|
1891
|
+
async function* Nr(e, t) {
|
|
1889
1892
|
if (!t) throw Error("decryptStream: a non-empty passphrase is required");
|
|
1890
1893
|
let n = e[Symbol.asyncIterator](), r = Buffer.alloc(0), i = !1, a = async () => {
|
|
1891
1894
|
let { value: e, done: t } = await n.next();
|
|
@@ -1894,16 +1897,16 @@ async function* jr(e, t) {
|
|
|
1894
1897
|
for (; r.length < e && !i && await a(););
|
|
1895
1898
|
return r.length >= e;
|
|
1896
1899
|
};
|
|
1897
|
-
if (!await o(
|
|
1898
|
-
let s = r.subarray(0,
|
|
1899
|
-
if (!s.subarray(0, 8).equals(
|
|
1900
|
-
let c = s.readUInt32BE(8), l = s.readUInt32BE(12), u = s.readUInt32BE(16), d = Buffer.from(s.subarray(20, 36)), f = Buffer.from(s.subarray(36,
|
|
1900
|
+
if (!await o(Ar)) throw Error("encrypted bundle truncated (no header)");
|
|
1901
|
+
let s = r.subarray(0, Ar);
|
|
1902
|
+
if (!s.subarray(0, 8).equals(Sr)) throw Error("not an encrypted bundle (bad magic / wrong passphrase target)");
|
|
1903
|
+
let c = s.readUInt32BE(8), l = s.readUInt32BE(12), u = s.readUInt32BE(16), d = Buffer.from(s.subarray(20, 36)), f = Buffer.from(s.subarray(36, Ar)), p = await xr(t, d, Cr, {
|
|
1901
1904
|
N: c,
|
|
1902
1905
|
r: l,
|
|
1903
1906
|
p: u,
|
|
1904
|
-
maxmem:
|
|
1907
|
+
maxmem: kr
|
|
1905
1908
|
});
|
|
1906
|
-
r = r.subarray(
|
|
1909
|
+
r = r.subarray(Ar);
|
|
1907
1910
|
let m = 0, h = !1;
|
|
1908
1911
|
for (;;) {
|
|
1909
1912
|
if (!await o(5)) {
|
|
@@ -1912,11 +1915,11 @@ async function* jr(e, t) {
|
|
|
1912
1915
|
}
|
|
1913
1916
|
if (h) throw Error("encrypted bundle has trailing data after the final frame");
|
|
1914
1917
|
let e = r.readUInt8(0) === 1, t = r.readUInt32BE(1);
|
|
1915
|
-
if (t <
|
|
1918
|
+
if (t < Er) throw Error("encrypted bundle corrupt (short frame)");
|
|
1916
1919
|
if (!await o(5 + t)) throw Error("encrypted bundle truncated (frame body)");
|
|
1917
|
-
let n = r.subarray(5, 5 + t -
|
|
1920
|
+
let n = r.subarray(5, 5 + t - Er), i = r.subarray(5 + t - Er, 5 + t);
|
|
1918
1921
|
r = r.subarray(5 + t);
|
|
1919
|
-
let a =
|
|
1922
|
+
let a = E("aes-256-gcm", p, jr(f, m, e));
|
|
1920
1923
|
m === 0 && a.setAAD(s), a.setAuthTag(i);
|
|
1921
1924
|
let c = Buffer.concat([a.update(n), a.final()]);
|
|
1922
1925
|
m++, e && (h = !0), c.length > 0 && (yield new Uint8Array(c));
|
|
@@ -1924,7 +1927,7 @@ async function* jr(e, t) {
|
|
|
1924
1927
|
}
|
|
1925
1928
|
//#endregion
|
|
1926
1929
|
//#region src/blobStorage.ts
|
|
1927
|
-
var
|
|
1930
|
+
var Pr = (e, t) => ({
|
|
1928
1931
|
list: () => {
|
|
1929
1932
|
let e = t();
|
|
1930
1933
|
return { async *[Symbol.asyncIterator]() {
|
|
@@ -1937,32 +1940,32 @@ var Mr = (e, t) => ({
|
|
|
1937
1940
|
} };
|
|
1938
1941
|
},
|
|
1939
1942
|
open: (t) => ({ async *[Symbol.asyncIterator]() {
|
|
1940
|
-
let r = await n.runPromise(
|
|
1943
|
+
let r = await n.runPromise(A(e, t)), i = await he(r.stream);
|
|
1941
1944
|
for await (let e of i) yield e instanceof Uint8Array ? e : new Uint8Array(e);
|
|
1942
1945
|
} })
|
|
1943
|
-
}),
|
|
1944
|
-
table:
|
|
1946
|
+
}), Fr = (e, t) => Pr(e, () => w(t, {
|
|
1947
|
+
table: pe,
|
|
1945
1948
|
chunkSize: 500
|
|
1946
1949
|
}).pipe(l.map((e) => ({
|
|
1947
1950
|
key: String(e.key),
|
|
1948
1951
|
contentType: String(e.contentType ?? "application/octet-stream"),
|
|
1949
1952
|
size: Number(e.size ?? 0)
|
|
1950
|
-
})))),
|
|
1953
|
+
})))), Ir = (e) => ({
|
|
1951
1954
|
has: (t) => n.runPromise(e.head(t).pipe(n.map((e) => e !== null))),
|
|
1952
1955
|
write: async (t, r, i) => {
|
|
1953
|
-
let a =
|
|
1956
|
+
let a = me("storage", () => ge.from(r));
|
|
1954
1957
|
await n.runPromise(j(e, t, a, {
|
|
1955
1958
|
contentType: i.contentType,
|
|
1956
1959
|
totalSize: i.size
|
|
1957
1960
|
}));
|
|
1958
1961
|
}
|
|
1959
|
-
}),
|
|
1962
|
+
}), Lr = (e, t) => {
|
|
1960
1963
|
let n = t === "dump" ? "mariadb-dump" : "mariadb", r = t === "dump" ? "mysqldump" : "mysql";
|
|
1961
|
-
return e === "mariadb" ?
|
|
1964
|
+
return e === "mariadb" ? Rr(n) ? { tool: n } : {
|
|
1962
1965
|
tool: r,
|
|
1963
|
-
hint: `'${n}' is not on PATH, so this ran '${r}' instead. If that binary came from Oracle's MySQL client it queries information_schema.COLUMN_STATISTICS, which MariaDB does not have, and the run dies with error 1109 after the first table. Install the MariaDB client package (which ships '${n}') and re-run. Do NOT reach for --column-statistics=0: that flag does not exist on '${n}', so it fixes the wrong client and breaks the right one.`
|
|
1966
|
+
hint: `'${n}' is not on PATH, so this ran '${r}' instead. If that binary came from Oracle's MySQL client it queries information_schema.COLUMN_STATISTICS, which MariaDB does not have, and the run dies with error 1109 after the first table. Install the MariaDB client package (which ships '${n}') and re-run. Do NOT reach for --column-statistics=0: that flag does not exist on '${n}', so it fixes the wrong client and breaks the right one. Note: a MariaDB 12.x client requires TLS by default, so running '${n}' BY HAND against a server without it fails with "TLS/SSL error: SSL is required" (2026) and needs --skip-ssl. This command is not affected.`
|
|
1964
1967
|
} : { tool: r };
|
|
1965
|
-
},
|
|
1968
|
+
}, Rr = (e) => (process.env.PATH ?? "").split(L).filter((e) => e !== "").some((t) => ue(R(t, e))), zr = (e) => {
|
|
1966
1969
|
switch (e) {
|
|
1967
1970
|
case "postgres": return "db.dump";
|
|
1968
1971
|
case "mysql":
|
|
@@ -1972,7 +1975,7 @@ var Mr = (e, t) => ({
|
|
|
1972
1975
|
case "mssql": return "db.bacpac";
|
|
1973
1976
|
default: return "db.dump";
|
|
1974
1977
|
}
|
|
1975
|
-
},
|
|
1978
|
+
}, Br = (e) => e.filename ?? e.database ?? ((e.url ?? "").replace(/^file:/, "") || "app.sqlite"), $ = (e) => {
|
|
1976
1979
|
if (e.host || e.database) return {
|
|
1977
1980
|
host: e.host ?? "localhost",
|
|
1978
1981
|
port: e.port ?? 3306,
|
|
@@ -1988,7 +1991,7 @@ var Mr = (e, t) => ({
|
|
|
1988
1991
|
password: decodeURIComponent(t.password) || "",
|
|
1989
1992
|
database: t.pathname.replace(/^\//, "") || ""
|
|
1990
1993
|
};
|
|
1991
|
-
},
|
|
1994
|
+
}, Vr = (e) => `Server=${e.host},${e.port};Database=${e.database};User ID=${e.username};Password=${e.password};TrustServerCertificate=True`, Hr = (e, t, n) => {
|
|
1992
1995
|
switch (e) {
|
|
1993
1996
|
case "postgres": {
|
|
1994
1997
|
if (t.url) return {
|
|
@@ -1998,6 +2001,7 @@ var Mr = (e, t) => ({
|
|
|
1998
2001
|
"--format=custom",
|
|
1999
2002
|
"--no-owner",
|
|
2000
2003
|
"--no-privileges",
|
|
2004
|
+
...Ur,
|
|
2001
2005
|
"--dbname",
|
|
2002
2006
|
t.url,
|
|
2003
2007
|
"--file",
|
|
@@ -2016,6 +2020,7 @@ var Mr = (e, t) => ({
|
|
|
2016
2020
|
"--format=custom",
|
|
2017
2021
|
"--no-owner",
|
|
2018
2022
|
"--no-privileges",
|
|
2023
|
+
...Ur,
|
|
2019
2024
|
"-h",
|
|
2020
2025
|
e.host,
|
|
2021
2026
|
"-p",
|
|
@@ -2035,13 +2040,14 @@ var Mr = (e, t) => ({
|
|
|
2035
2040
|
let r = $(t);
|
|
2036
2041
|
return {
|
|
2037
2042
|
kind: "spawn",
|
|
2038
|
-
...
|
|
2043
|
+
...Lr(e, "dump"),
|
|
2039
2044
|
args: [
|
|
2040
2045
|
"--single-transaction",
|
|
2041
2046
|
"--routines",
|
|
2042
2047
|
"--triggers",
|
|
2043
2048
|
"--no-tablespaces",
|
|
2044
2049
|
"--protocol=TCP",
|
|
2050
|
+
`--ignore-table=${r.database}.${d}`,
|
|
2045
2051
|
"-h",
|
|
2046
2052
|
r.host,
|
|
2047
2053
|
"-P",
|
|
@@ -2057,7 +2063,7 @@ var Mr = (e, t) => ({
|
|
|
2057
2063
|
case "sqlite":
|
|
2058
2064
|
case "turso": return {
|
|
2059
2065
|
kind: "copy",
|
|
2060
|
-
from:
|
|
2066
|
+
from: Br(t),
|
|
2061
2067
|
to: n
|
|
2062
2068
|
};
|
|
2063
2069
|
case "mssql": return {
|
|
@@ -2065,7 +2071,7 @@ var Mr = (e, t) => ({
|
|
|
2065
2071
|
tool: "sqlpackage",
|
|
2066
2072
|
args: [
|
|
2067
2073
|
"/Action:Export",
|
|
2068
|
-
`/SourceConnectionString:${
|
|
2074
|
+
`/SourceConnectionString:${Vr($({
|
|
2069
2075
|
...t,
|
|
2070
2076
|
port: t.port ?? 1433
|
|
2071
2077
|
}))}`,
|
|
@@ -2078,7 +2084,7 @@ var Mr = (e, t) => ({
|
|
|
2078
2084
|
reason: `no native backup for dialect '${e}'`
|
|
2079
2085
|
});
|
|
2080
2086
|
}
|
|
2081
|
-
},
|
|
2087
|
+
}, Ur = ["--exclude-table", d], Wr = (e, t, n) => {
|
|
2082
2088
|
switch (e) {
|
|
2083
2089
|
case "postgres": {
|
|
2084
2090
|
if (t.url) return {
|
|
@@ -2123,7 +2129,7 @@ var Mr = (e, t) => ({
|
|
|
2123
2129
|
let r = $(t);
|
|
2124
2130
|
return {
|
|
2125
2131
|
kind: "spawn",
|
|
2126
|
-
...
|
|
2132
|
+
...Lr(e, "client"),
|
|
2127
2133
|
args: [
|
|
2128
2134
|
"--protocol=TCP",
|
|
2129
2135
|
"-h",
|
|
@@ -2142,14 +2148,14 @@ var Mr = (e, t) => ({
|
|
|
2142
2148
|
case "turso": return {
|
|
2143
2149
|
kind: "copy",
|
|
2144
2150
|
from: n,
|
|
2145
|
-
to:
|
|
2151
|
+
to: Br(t)
|
|
2146
2152
|
};
|
|
2147
2153
|
case "mssql": return {
|
|
2148
2154
|
kind: "spawn",
|
|
2149
2155
|
tool: "sqlpackage",
|
|
2150
2156
|
args: [
|
|
2151
2157
|
"/Action:Import",
|
|
2152
|
-
`/TargetConnectionString:${
|
|
2158
|
+
`/TargetConnectionString:${Vr($({
|
|
2153
2159
|
...t,
|
|
2154
2160
|
port: t.port ?? 1433
|
|
2155
2161
|
}))}`,
|
|
@@ -2162,10 +2168,10 @@ var Mr = (e, t) => ({
|
|
|
2162
2168
|
reason: `no native restore for dialect '${e}'`
|
|
2163
2169
|
});
|
|
2164
2170
|
}
|
|
2165
|
-
},
|
|
2171
|
+
}, Gr = (e) => e.kind === "copy" ? n.async((t) => {
|
|
2166
2172
|
let r = `${e.to}.restoring-${oe()}`, i = (e) => {
|
|
2167
2173
|
try {
|
|
2168
|
-
|
|
2174
|
+
k(r);
|
|
2169
2175
|
} catch {}
|
|
2170
2176
|
t(n.fail(new W({
|
|
2171
2177
|
tool: "copy",
|
|
@@ -2177,7 +2183,7 @@ var Mr = (e, t) => ({
|
|
|
2177
2183
|
i(`copy ${e.from} → ${e.to}: ${a.message}`);
|
|
2178
2184
|
return;
|
|
2179
2185
|
}
|
|
2180
|
-
|
|
2186
|
+
de(r, e.to, (r) => {
|
|
2181
2187
|
if (r) {
|
|
2182
2188
|
i(`copy ${e.from} → ${e.to}: ${r.message}`);
|
|
2183
2189
|
return;
|
|
@@ -2186,7 +2192,7 @@ var Mr = (e, t) => ({
|
|
|
2186
2192
|
});
|
|
2187
2193
|
});
|
|
2188
2194
|
}) : n.async((t) => {
|
|
2189
|
-
let r =
|
|
2195
|
+
let r = Ce(e.tool, [...e.args], {
|
|
2190
2196
|
env: {
|
|
2191
2197
|
...process.env,
|
|
2192
2198
|
...e.env
|
|
@@ -2199,35 +2205,63 @@ var Mr = (e, t) => ({
|
|
|
2199
2205
|
}), i = "";
|
|
2200
2206
|
r.stderr?.on("data", (e) => {
|
|
2201
2207
|
i += String(e);
|
|
2202
|
-
})
|
|
2203
|
-
let a = () => {
|
|
2208
|
+
});
|
|
2209
|
+
let a = !1, o = (e) => {
|
|
2210
|
+
a || (a = !0, t(e));
|
|
2211
|
+
}, s, c = (e) => {
|
|
2212
|
+
s ??= e;
|
|
2213
|
+
};
|
|
2214
|
+
if (e.stdoutFile && r.stdout) {
|
|
2215
|
+
let t = O(e.stdoutFile);
|
|
2216
|
+
t.on("error", (t) => c(`writing ${I(e.stdoutFile)}: ${t.message}`)), r.stdout.on("error", (e) => c(`reading the tool's output: ${e.message}`)), r.stdout.pipe(t);
|
|
2217
|
+
}
|
|
2218
|
+
let l = 0;
|
|
2219
|
+
if (e.stdinFile && r.stdin) {
|
|
2220
|
+
let t = le(e.stdinFile);
|
|
2221
|
+
t.on("data", (e) => {
|
|
2222
|
+
l += e.length;
|
|
2223
|
+
}), t.on("error", (t) => {
|
|
2224
|
+
c(`reading ${I(e.stdinFile)}: ${t.message}`), r.stdin?.end();
|
|
2225
|
+
}), r.stdin.on("error", (t) => {
|
|
2226
|
+
t.code !== "EPIPE" && c(`feeding ${I(e.stdinFile)} to ${e.tool}: ${t.message}`);
|
|
2227
|
+
}), t.pipe(r.stdin);
|
|
2228
|
+
}
|
|
2229
|
+
let u = () => {
|
|
2204
2230
|
if (e.stdoutFile !== void 0) try {
|
|
2205
|
-
|
|
2231
|
+
k(e.stdoutFile);
|
|
2206
2232
|
} catch {}
|
|
2207
2233
|
};
|
|
2208
|
-
r.on("error", (
|
|
2209
|
-
|
|
2234
|
+
r.on("error", (t) => {
|
|
2235
|
+
u(), o(n.fail(new W({
|
|
2210
2236
|
tool: e.tool,
|
|
2211
|
-
reason: `failed to launch (is '${e.tool}' installed + on PATH?): ${
|
|
2237
|
+
reason: `failed to launch (is '${e.tool}' installed + on PATH?): ${t.message}`,
|
|
2212
2238
|
...e.hint === void 0 ? {} : { hint: e.hint }
|
|
2213
2239
|
})));
|
|
2214
|
-
}), r.on("close", (
|
|
2215
|
-
if (
|
|
2216
|
-
|
|
2240
|
+
}), r.on("close", (t) => {
|
|
2241
|
+
if (t === 0 && s === void 0) {
|
|
2242
|
+
o(n.void);
|
|
2217
2243
|
return;
|
|
2218
2244
|
}
|
|
2219
|
-
|
|
2245
|
+
u();
|
|
2246
|
+
let r = e.stdinFile === void 0 ? "" : ` — ${l} of ${Kr(e.stdinFile)} byte(s) of ${I(e.stdinFile)} had been fed to it`;
|
|
2247
|
+
o(n.fail(new W({
|
|
2220
2248
|
tool: e.tool,
|
|
2221
|
-
reason: `exited with code ${
|
|
2222
|
-
stderr: i.slice(-2e3),
|
|
2249
|
+
reason: (t === 0 ? `exited cleanly, but ${s}` : `exited with code ${t}${s === void 0 ? "" : ` (${s})`}`) + r + (e.stdoutFile === void 0 ? "" : ` — the partial ${I(e.stdoutFile)} was removed, so it cannot be mistaken for a backup`),
|
|
2250
|
+
stderr: i.trim() === "" ? `(${e.tool} printed nothing to stderr)` : i.slice(-2e3),
|
|
2223
2251
|
...e.hint === void 0 ? {} : { hint: e.hint }
|
|
2224
2252
|
})));
|
|
2225
2253
|
});
|
|
2226
|
-
}),
|
|
2227
|
-
|
|
2254
|
+
}), Kr = (e) => {
|
|
2255
|
+
try {
|
|
2256
|
+
return String(fe(e).size);
|
|
2257
|
+
} catch {
|
|
2258
|
+
return "?";
|
|
2259
|
+
}
|
|
2260
|
+
}, qr = (e) => typeof e == "object" && e ? "fake" in e ? `fake:${e.fake}` : "custom" : String(e), Jr = (e) => n.gen(function* () {
|
|
2261
|
+
let t = yield* at(e.scope ?? { kind: "all" }, e.snapshot, {
|
|
2228
2262
|
store: e.store,
|
|
2229
2263
|
...e.tenantTables ? { tenantTables: e.tenantTables } : {}
|
|
2230
|
-
}), r =
|
|
2264
|
+
}), r = tn(t.tables, e.snapshot), i = e.classification ?? Ee(e.snapshot), a = e.sampleSize ?? 20, o = ze(r.map((t) => ({
|
|
2231
2265
|
name: t,
|
|
2232
2266
|
columns: (e.snapshot.tables.find((e) => e.name === t)?.columns ?? []).map((e) => ({
|
|
2233
2267
|
name: e.name,
|
|
@@ -2239,15 +2273,15 @@ var Mr = (e, t) => ({
|
|
|
2239
2273
|
table: i,
|
|
2240
2274
|
chunkSize: a,
|
|
2241
2275
|
...r === void 0 ? {} : { where: r }
|
|
2242
|
-
}).pipe(l.take(a), l.runCollect, n.map((e) => [...e])), d = u.map((t) =>
|
|
2243
|
-
c.push(...
|
|
2276
|
+
}).pipe(l.take(a), l.runCollect, n.map((e) => [...e])), d = u.map((t) => He(t, i, o.actions, e.masking.seed));
|
|
2277
|
+
c.push(...Ve(d, i, o.actions));
|
|
2244
2278
|
let f = u[0], p = d[0], m = [];
|
|
2245
2279
|
if (f && p) for (let [e, t] of Object.entries(o.actions)) {
|
|
2246
2280
|
if (!e.startsWith(`${i}.`) || t === "keep") continue;
|
|
2247
2281
|
let n = e.slice(i.length + 1);
|
|
2248
2282
|
m.push({
|
|
2249
2283
|
column: n,
|
|
2250
|
-
action:
|
|
2284
|
+
action: qr(t),
|
|
2251
2285
|
before: f[n],
|
|
2252
2286
|
after: p[n]
|
|
2253
2287
|
});
|
|
@@ -2262,7 +2296,7 @@ var Mr = (e, t) => ({
|
|
|
2262
2296
|
leaks: c,
|
|
2263
2297
|
unclassified: o.unclassified
|
|
2264
2298
|
};
|
|
2265
|
-
}),
|
|
2299
|
+
}), Yr = (e, t) => {
|
|
2266
2300
|
let n = new Map(t.map((e) => [e.name, e])), r = [], i = {};
|
|
2267
2301
|
for (let t of e) {
|
|
2268
2302
|
let e = n.get(t.name);
|
|
@@ -2317,7 +2351,7 @@ var Mr = (e, t) => ({
|
|
|
2317
2351
|
skipColumns: i,
|
|
2318
2352
|
refuse: r.some((e) => e.verdict === "refuse")
|
|
2319
2353
|
};
|
|
2320
|
-
},
|
|
2354
|
+
}, Xr = (e) => {
|
|
2321
2355
|
if (e.findings.length === 0) return [" schema matches the bundle"];
|
|
2322
2356
|
let t = {
|
|
2323
2357
|
safe: "✓",
|
|
@@ -2328,4 +2362,4 @@ var Mr = (e, t) => ({
|
|
|
2328
2362
|
return n.push(""), n.push(` discarded: ${r("value-dropped")} defaulted: ${r("filled-by-default")} refused: ${r("refuse")}`), e.refuse && (n.push(""), n.push(" REFUSED — no row was written. These are the differences that would make"), n.push(" imported rows WRONG rather than merely incomplete.")), n;
|
|
2329
2363
|
};
|
|
2330
2364
|
//#endregion
|
|
2331
|
-
export {
|
|
2365
|
+
export { kt as ASSETS_DIR, At as ASSET_INDEX_FILE, H as BundleError, qe as CodecError, Ye as CompressionError, et as CrossDialectError, Ot as DATA_DIR, Te as DEFAULT_CLASS_ACTIONS, Ue as ENVIRONMENT_LOCAL_TABLES, We as ENVIRONMENT_PORTABLE_TABLES, bt as FORMAT_VERSION, $e as ImportModeError, Je as IntegrityError, jt as LEDGER_FILE, K as MANIFEST_FILE, Qe as MaskingError, W as NativeToolError, Xe as RowsRefusedError, $n as SAVEPOINT_BATCH_SIZE, On as STAGING_PREFIX, Ze as SchemaDriftError, U as ScopeError, Le as applyAction, tr as asImportError, or as assessLiveImport, Vt as assetDone, zr as backupArtifactName, Hr as backupCommand, gn as canonicalType, ft as captureAssetsToCas, yn as checkPortability, Zn as checkSchemaDrift, Ee as classificationFromSnapshot, Yr as classifyImportDrift, _t as compressionExt, nt as computeSubsetIds, Wn as decideStaging, Et as decodeManifest, Zt as decodeRow, Yt as decodeValue, Nr as decryptStream, ar as defineDataProfile, Xn as diffSnapshots, br as dirBlobSink, Nn as dropStagingSql, Rt as emptyLedger, Tt as encodeManifest, Xt as encodeRow, qt as encodeValue, Mr as encryptStream, Ke as environmentLocalNotice, Ge as environmentLocalReason, zn as execStatements, Xr as formatImportDrift, bn as formatIssue, ht as hasZstd, V as isEnvironmentLocal, vt as makeCompressor, yt as makeDecompressor, He as maskRow, en as ndjsonToRows, ut as noAssetProgress, hn as outsideReferenceRefusal, mn as outsideReferencesInto, mr as packBundle, vr as peekBundle, gt as pickCompression, ze as planMasking, Jr as previewMasking, pt as readAssetIndex, zt as readLedger, De as resolveAction, at as resolveScope, lt as restoreAssetFromCas, mt as restoreAssetsFromCas, Wr as restoreCommand, $t as rowsToNdjson, pn as runExport, ir as runImport, Gr as runNativeStep, Ve as scanForLeaks, X as stagingNameFor, st as storageAssetSink, ot as storageAssetSource, Ir as storageBlobSink, Pr as storageBlobSource, Fr as storageRefsBlobSource, rt as subsetToScope, Bt as tableDone, tn as topoSortTables, _r as unpackBundle, yr as unpackBundleToDir, ct as writeAssetToCas, J as writeLedger };
|