@voltro/data-transfer 0.50.0 → 0.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +160 -0
- package/dist/index.d.ts +102 -1
- package/dist/index.js +441 -401
- 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
|
-
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
|
|
3
|
-
import { fingerprintSchema as
|
|
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
|
|
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 ee, streamTable as C, suspendWriteRecorders as te, suspendWriteRecordersEffect as ne, unregisterTable as re } from "@voltro/database";
|
|
3
|
+
import { fingerprintSchema as ie } from "@voltro/database/sql";
|
|
4
|
+
import { createCipheriv as w, createDecipheriv as T, createHash as E, createHmac as ae, randomBytes as D, 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) => ae("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,8 +342,8 @@ 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),
|
|
346
|
-
return l.runForEach(
|
|
345
|
+
let a = f(r, G(t, r), tt(t, r));
|
|
346
|
+
return l.runForEach(C(e, {
|
|
347
347
|
table: r,
|
|
348
348
|
pk: G(t, r),
|
|
349
349
|
...i === void 0 ? {} : { where: i }
|
|
@@ -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,53 @@ 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 = 0, o = 0, s = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Set(), u = [];
|
|
462
|
+
return yield* l.runForEach(e.source.list(), (l) => (a++, t.done(l.key) || c.has(l.key) ? n.void : (c.add(l.key), e.source.open(l.key).pipe(n.map((e) => e), n.catchIf(dt, () => n.sync(() => {
|
|
463
|
+
u.push(l.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: l.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, s.has(e.sha256) || (s.add(e.sha256), o += e.size), t.mark(l.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
|
+
references: a,
|
|
476
|
+
objects: s.size,
|
|
477
|
+
objectBytes: o,
|
|
478
|
+
missing: u
|
|
473
479
|
};
|
|
474
|
-
}),
|
|
480
|
+
}), 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
481
|
reason: `asset index unreadable: ${String(t)}`,
|
|
476
482
|
path: e
|
|
477
|
-
}))),
|
|
478
|
-
let t = e.progress ??
|
|
479
|
-
return yield* l.runForEach(
|
|
480
|
-
r
|
|
481
|
-
})), n.andThen(t.mark(
|
|
482
|
-
|
|
483
|
+
}))), mt = (e) => n.gen(function* () {
|
|
484
|
+
let t = e.progress ?? ut, r = 0, i = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new Set();
|
|
485
|
+
return yield* l.runForEach(pt(e.indexPath), (o) => t.done(o.key) || a.has(o.key) ? n.void : (a.add(o.key), lt(e.sink, e.assetsDir, o)).pipe(n.andThen(n.sync(() => {
|
|
486
|
+
r++, i.add(o.sha256);
|
|
487
|
+
})), n.andThen(t.mark(o.key, o)))), {
|
|
488
|
+
count: r,
|
|
489
|
+
objects: i.size
|
|
490
|
+
};
|
|
491
|
+
}), 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
492
|
name: c.String,
|
|
484
493
|
file: c.String,
|
|
485
494
|
rowCount: c.Number,
|
|
@@ -489,12 +498,12 @@ var Ce = (e) => {
|
|
|
489
498
|
value: c.String
|
|
490
499
|
}),
|
|
491
500
|
primaryKey: c.String
|
|
492
|
-
}),
|
|
501
|
+
}), St = c.Struct({
|
|
493
502
|
kind: c.Literal("all", "tenant", "tables"),
|
|
494
503
|
tenantId: c.optional(c.String),
|
|
495
504
|
tables: c.optional(c.Array(c.String)),
|
|
496
505
|
exclude: c.optional(c.Array(c.String))
|
|
497
|
-
}),
|
|
506
|
+
}), Ct = c.Struct({
|
|
498
507
|
count: c.Number,
|
|
499
508
|
totalBytes: c.Number,
|
|
500
509
|
index: c.optional(c.String)
|
|
@@ -505,23 +514,23 @@ c.Struct({
|
|
|
505
514
|
size: c.Number,
|
|
506
515
|
contentType: c.String
|
|
507
516
|
});
|
|
508
|
-
var
|
|
517
|
+
var wt = c.Struct({
|
|
509
518
|
formatVersion: c.Number,
|
|
510
519
|
createdAt: c.String,
|
|
511
520
|
source: c.Struct({
|
|
512
521
|
dialect: c.String,
|
|
513
522
|
schemaFingerprint: c.String
|
|
514
523
|
}),
|
|
515
|
-
scope:
|
|
524
|
+
scope: St,
|
|
516
525
|
consistency: c.Literal("live", "snapshot"),
|
|
517
526
|
compression: c.Literal("zstd", "gzip", "none"),
|
|
518
|
-
tables: c.Array(
|
|
519
|
-
assets:
|
|
527
|
+
tables: c.Array(xt),
|
|
528
|
+
assets: Ct,
|
|
520
529
|
masking: c.optional(c.Struct({
|
|
521
530
|
policyId: c.optional(c.String),
|
|
522
531
|
transformed: c.Array(c.String)
|
|
523
532
|
}))
|
|
524
|
-
}),
|
|
533
|
+
}), 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
534
|
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
535
|
return `# Voltro data export
|
|
527
536
|
|
|
@@ -535,7 +544,7 @@ The machine-readable manifest is \`manifest.json\`; this file is a human summary
|
|
|
535
544
|
| **Format version** | ${e.formatVersion} |
|
|
536
545
|
| **Consistency** | ${e.consistency} |
|
|
537
546
|
| **Compression** | ${e.compression} |
|
|
538
|
-
| **Scope** | ${
|
|
547
|
+
| **Scope** | ${Mt(e.scope)} |
|
|
539
548
|
| **Tables** | ${e.tables.length} |
|
|
540
549
|
| **Rows (total)** | ${n} |
|
|
541
550
|
| **Assets** | ${a} |
|
|
@@ -560,26 +569,26 @@ voltro data import <this-directory>
|
|
|
560
569
|
voltro data import <this-directory> --target api --api-url <url> --token <secret>
|
|
561
570
|
\`\`\`
|
|
562
571
|
`;
|
|
563
|
-
},
|
|
572
|
+
}, Pt = i.counter("voltro_data_transfer_rows", { description: "Rows exported/imported by @voltro/data-transfer, tagged by phase + table." }), Ft = a.exponential({
|
|
564
573
|
start: .01,
|
|
565
574
|
factor: 2,
|
|
566
575
|
count: 16
|
|
567
|
-
}),
|
|
576
|
+
}), It = i.histogram("voltro_data_transfer_table_seconds", Ft, "Per-table export/import duration in seconds, tagged by phase."), q = (e, t) => {
|
|
568
577
|
if (e) try {
|
|
569
578
|
e(t);
|
|
570
579
|
} catch {}
|
|
571
|
-
},
|
|
580
|
+
}, 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
581
|
table: t,
|
|
573
582
|
index: r,
|
|
574
583
|
tableCount: a,
|
|
575
584
|
phase: e
|
|
576
|
-
} })),
|
|
585
|
+
} })), Rt = () => ({
|
|
577
586
|
tables: {},
|
|
578
587
|
assets: {}
|
|
579
|
-
}),
|
|
588
|
+
}), zt = (e) => n.tryPromise(async () => {
|
|
580
589
|
let t = await (await import("node:fs/promises")).readFile(e, "utf8");
|
|
581
590
|
return JSON.parse(t);
|
|
582
|
-
}).pipe(n.orElseSucceed(
|
|
591
|
+
}).pipe(n.orElseSucceed(Rt)), J = (e, t) => n.tryPromise({
|
|
583
592
|
try: async () => {
|
|
584
593
|
let n = await import("node:fs/promises"), { randomUUID: r } = await import("node:crypto"), i = `${e}.tmp-${r()}`;
|
|
585
594
|
await n.writeFile(i, JSON.stringify(t)), await n.rename(i, e);
|
|
@@ -588,11 +597,11 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
588
597
|
reason: `ledger write failed: ${String(t?.message ?? t)}`,
|
|
589
598
|
path: e
|
|
590
599
|
})
|
|
591
|
-
}),
|
|
600
|
+
}), Bt = (e, t) => t in e.tables, Vt = (e, t) => t in e.assets, Ht = /* @__PURE__ */ new Set([
|
|
592
601
|
"json",
|
|
593
602
|
"array",
|
|
594
603
|
"vector"
|
|
595
|
-
]),
|
|
604
|
+
]), 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
605
|
$v: "bigint",
|
|
597
606
|
d: e.toString()
|
|
598
607
|
} : typeof e == "number" && !Number.isFinite(e) ? {
|
|
@@ -603,30 +612,30 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
603
612
|
d: e.toISOString()
|
|
604
613
|
} : e instanceof Uint8Array ? {
|
|
605
614
|
$v: "bytes",
|
|
606
|
-
d:
|
|
607
|
-
} : e,
|
|
615
|
+
d: Wt(e)
|
|
616
|
+
} : e, Jt = (e) => {
|
|
608
617
|
switch (e.$v) {
|
|
609
618
|
case "bigint": return BigInt(e.d);
|
|
610
619
|
case "number": return Number(e.d);
|
|
611
620
|
case "date": return new Date(e.d);
|
|
612
|
-
case "bytes": return
|
|
621
|
+
case "bytes": return Gt(e.d);
|
|
613
622
|
default: return e;
|
|
614
623
|
}
|
|
615
|
-
},
|
|
624
|
+
}, 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
625
|
let n = {};
|
|
617
|
-
for (let [r, i] of Object.entries(e)) n[r] =
|
|
626
|
+
for (let [r, i] of Object.entries(e)) n[r] = qt(i, t[r]);
|
|
618
627
|
return n;
|
|
619
|
-
},
|
|
628
|
+
}, Zt = (e, t) => {
|
|
620
629
|
let n = {};
|
|
621
|
-
for (let [r, i] of Object.entries(e)) n[r] =
|
|
630
|
+
for (let [r, i] of Object.entries(e)) n[r] = Yt(i, t[r]);
|
|
622
631
|
return n;
|
|
623
|
-
},
|
|
624
|
-
try: () =>
|
|
625
|
-
catch: (e) => new
|
|
632
|
+
}, 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({
|
|
633
|
+
try: () => Zt(JSON.parse(e), r),
|
|
634
|
+
catch: (e) => new qe({
|
|
626
635
|
table: t,
|
|
627
636
|
reason: String(e?.message ?? e)
|
|
628
637
|
})
|
|
629
|
-
}))),
|
|
638
|
+
}))), tn = (e, t) => {
|
|
630
639
|
let n = new Set(e), r = /* @__PURE__ */ new Map();
|
|
631
640
|
for (let e of t.tables) {
|
|
632
641
|
if (!n.has(e.name)) continue;
|
|
@@ -652,33 +661,33 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
652
661
|
let r = typeof t?.message == "string" ? t.message.trim() : "";
|
|
653
662
|
if (r === "" ? t?.cause !== void 0 && t.cause !== null && n.push(Y(t.cause)) : n.push(r), n.length === 0) {
|
|
654
663
|
let t = String(e ?? "").trim();
|
|
655
|
-
return t === "" || t === "[object Object]" ?
|
|
664
|
+
return t === "" || t === "[object Object]" ? nn(e) : t;
|
|
656
665
|
}
|
|
657
666
|
return n.join(": ");
|
|
658
|
-
},
|
|
667
|
+
}, nn = (e) => {
|
|
659
668
|
try {
|
|
660
669
|
let t = JSON.stringify(e);
|
|
661
670
|
return t === void 0 || t === "{}" ? "unknown error (no message, cause or tag)" : t;
|
|
662
671
|
} catch {
|
|
663
672
|
return "unknown error (not serialisable)";
|
|
664
673
|
}
|
|
665
|
-
},
|
|
674
|
+
}, rn = (e, t) => {
|
|
666
675
|
let n = e.tables.find((e) => e.name === t), r = {};
|
|
667
676
|
for (let e of n?.columns ?? []) e.generatedAs === void 0 && (r[e.name] = e.type);
|
|
668
677
|
return r;
|
|
669
|
-
},
|
|
678
|
+
}, 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
679
|
if (t.length === 0) return e;
|
|
671
680
|
let n = { ...e };
|
|
672
681
|
for (let e of t) delete n[e];
|
|
673
682
|
return n;
|
|
674
|
-
},
|
|
683
|
+
}, sn = (e, t) => {
|
|
675
684
|
let n = e.tables.find((e) => e.name === t);
|
|
676
685
|
if (n === void 0) return { refusal: `${t}: not in the schema snapshot, so its primary key is unknown.` };
|
|
677
686
|
let r = n.columns.find((e) => e.type === "id");
|
|
678
687
|
if (r !== void 0) return { column: r.name };
|
|
679
688
|
let i = n.indexes.find((e) => e.name === `${t}_pkey`)?.columns ?? n.primaryKey ?? [];
|
|
680
689
|
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
|
-
},
|
|
690
|
+
}, cn = (e, t, r) => n.tryPromise({
|
|
682
691
|
try: async () => {
|
|
683
692
|
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
693
|
d.update(e);
|
|
@@ -687,7 +696,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
687
696
|
n(null, e);
|
|
688
697
|
} }), m = c.fromWeb(l.toReadableStream(e)), h = `${t}.tmp-${o()}`;
|
|
689
698
|
try {
|
|
690
|
-
await s(m, p,
|
|
699
|
+
await s(m, p, vt(r), n(h)), await i.rename(h, t);
|
|
691
700
|
} catch (e) {
|
|
692
701
|
throw await i.rm(h, { force: !0 }).catch(() => {}), e;
|
|
693
702
|
}
|
|
@@ -700,7 +709,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
700
709
|
reason: `write table failed: ${Y(e)}`,
|
|
701
710
|
path: t
|
|
702
711
|
})
|
|
703
|
-
}),
|
|
712
|
+
}), ln = (e, t) => n.tryPromise({
|
|
704
713
|
try: async () => {
|
|
705
714
|
await (await import("node:fs/promises")).appendFile(e, `${t}\n`);
|
|
706
715
|
},
|
|
@@ -708,13 +717,13 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
708
717
|
reason: `append failed: ${Y(t)}`,
|
|
709
718
|
path: e
|
|
710
719
|
})
|
|
711
|
-
}),
|
|
720
|
+
}), un = (e, t) => n.gen(function* () {
|
|
712
721
|
let r = [], i = t.ordered.length;
|
|
713
722
|
for (let a = 0; a < t.ordered.length; a++) {
|
|
714
|
-
let o = t.ordered[a], s =
|
|
723
|
+
let o = t.ordered[a], s = rn(t.snapshot, o), c = sn(t.snapshot, o);
|
|
715
724
|
if ("refusal" in c) return yield* n.fail(new U({ reason: `export: ${c.refusal}` }));
|
|
716
|
-
let u = c.column, d = `${
|
|
717
|
-
if (
|
|
725
|
+
let u = c.column, d = `${Ot}/${o}.ndjson${_t(t.compression)}`;
|
|
726
|
+
if (Bt(t.ledger, o)) {
|
|
718
727
|
let e = t.ledger.tables[o];
|
|
719
728
|
q(t.onProgress, {
|
|
720
729
|
phase: "export",
|
|
@@ -742,13 +751,13 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
742
751
|
event: "start",
|
|
743
752
|
rowsDone: 0
|
|
744
753
|
});
|
|
745
|
-
let f = t.resolved.predicateFor(o), p =
|
|
754
|
+
let f = t.resolved.predicateFor(o), p = C(e, {
|
|
746
755
|
table: o,
|
|
747
756
|
pk: u,
|
|
748
757
|
chunkSize: t.chunkSize,
|
|
749
758
|
retry: t.retry,
|
|
750
759
|
...f === void 0 ? {} : { where: f }
|
|
751
|
-
}), m =
|
|
760
|
+
}), 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
761
|
t.ledger.tables[o] = {
|
|
753
762
|
rowCount: _,
|
|
754
763
|
checksum: v
|
|
@@ -770,43 +779,43 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
770
779
|
});
|
|
771
780
|
}
|
|
772
781
|
return r;
|
|
773
|
-
}),
|
|
782
|
+
}), dn = (e) => ({
|
|
774
783
|
_tag: "RawSqlFragment",
|
|
775
784
|
strings: [e],
|
|
776
785
|
values: []
|
|
777
|
-
}),
|
|
786
|
+
}), fn = (t, i, a) => n.tryPromise({
|
|
778
787
|
try: () => t.transactional(async (t) => {
|
|
779
|
-
if (t.raw) for (let e of
|
|
788
|
+
if (t.raw) for (let e of we(i)) await t.raw(dn(e));
|
|
780
789
|
let o = await n.runPromiseExit(a(t));
|
|
781
790
|
if (r.isFailure(o)) throw Error(e.pretty(o.cause));
|
|
782
791
|
return o.value;
|
|
783
792
|
}),
|
|
784
793
|
catch: (e) => e instanceof H ? e : new H({ reason: `snapshot export failed: ${Y(e)}` })
|
|
785
|
-
}),
|
|
786
|
-
let t = e.scope ?? { kind: "all" }, r =
|
|
794
|
+
}), pn = (e) => n.gen(function* () {
|
|
795
|
+
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
796
|
yield* n.tryPromise({
|
|
788
797
|
try: async () => {
|
|
789
798
|
let t = await import("node:fs/promises");
|
|
790
|
-
await t.mkdir(l(
|
|
799
|
+
await t.mkdir(l(Ot), { recursive: !0 }), e.assets && await t.mkdir(l(kt), { recursive: !0 });
|
|
791
800
|
},
|
|
792
801
|
catch: (t) => new H({
|
|
793
802
|
reason: `mkdir failed: ${Y(t)}`,
|
|
794
803
|
path: e.outDir
|
|
795
804
|
})
|
|
796
805
|
});
|
|
797
|
-
let u = l(
|
|
806
|
+
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
807
|
store: e.store,
|
|
799
808
|
...e.tenantTables ? { tenantTables: e.tenantTables } : {}
|
|
800
|
-
}), p =
|
|
809
|
+
}), p = tn(f.tables, e.snapshot), m = e.consistency ?? "live", h, g;
|
|
801
810
|
if (e.masking) {
|
|
802
|
-
let t = e.classification ??
|
|
811
|
+
let t = e.classification ?? Ee(e.snapshot), r = ze(p.map((t) => ({
|
|
803
812
|
name: t,
|
|
804
813
|
columns: (e.snapshot.tables.find((e) => e.name === t)?.columns ?? []).map((e) => ({
|
|
805
814
|
name: e.name,
|
|
806
815
|
type: e.type
|
|
807
816
|
}))
|
|
808
817
|
})), t, e.masking);
|
|
809
|
-
if (r.unclassified.length > 0 || r.invalid.length > 0) return yield* n.fail(new
|
|
818
|
+
if (r.unclassified.length > 0 || r.invalid.length > 0) return yield* n.fail(new Qe({
|
|
810
819
|
unclassified: r.unclassified,
|
|
811
820
|
...r.invalid.length > 0 ? { invalidActions: r.invalid.map((e) => `${e.column}: ${JSON.stringify(e.action)}`) } : {}
|
|
812
821
|
}));
|
|
@@ -832,24 +841,24 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
832
841
|
bundleFile: l,
|
|
833
842
|
...g ? { mask: g } : {},
|
|
834
843
|
...e.onProgress ? { onProgress: e.onProgress } : {}
|
|
835
|
-
}, v = m === "snapshot" ? yield*
|
|
844
|
+
}, v = m === "snapshot" ? yield* fn(e.store, e.dialect, (e) => un(e, _)) : yield* un(e.store, _), y = 0, b = 0;
|
|
836
845
|
if (e.assets) {
|
|
837
|
-
let t = l(
|
|
846
|
+
let t = l(At), r = yield* ft({
|
|
838
847
|
source: e.assets,
|
|
839
|
-
assetsDir: l(
|
|
848
|
+
assetsDir: l(kt),
|
|
840
849
|
progress: {
|
|
841
850
|
done: (e) => e in d.assets,
|
|
842
|
-
mark: (e, r) => (d.assets[e] = !0,
|
|
851
|
+
mark: (e, r) => (d.assets[e] = !0, ln(t, JSON.stringify(r)).pipe(n.andThen(J(u, d))))
|
|
843
852
|
}
|
|
844
853
|
});
|
|
845
|
-
y = r.count, b = r.totalBytes;
|
|
854
|
+
y = r.count, b = r.totalBytes, r.missing.length > 0 && (yield* n.logWarning(`${r.missing.length} of ${r.missing.length + r.count} blob reference(s) point at objects the storage provider does not have; they are NOT in this bundle and no import can bring them back. e.g. ${r.missing.slice(0, 3).map((e) => `'${e}'`).join(", ")}` + (r.missing.length > 3 ? `, and ${r.missing.length - 3} more` : "")));
|
|
846
855
|
}
|
|
847
856
|
let x = {
|
|
848
857
|
formatVersion: 1,
|
|
849
858
|
createdAt: e.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
850
859
|
source: {
|
|
851
860
|
dialect: e.dialect,
|
|
852
|
-
schemaFingerprint:
|
|
861
|
+
schemaFingerprint: ie(e.snapshot)
|
|
853
862
|
},
|
|
854
863
|
scope: t,
|
|
855
864
|
consistency: m,
|
|
@@ -858,7 +867,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
858
867
|
assets: y > 0 ? {
|
|
859
868
|
count: y,
|
|
860
869
|
totalBytes: b,
|
|
861
|
-
index:
|
|
870
|
+
index: At
|
|
862
871
|
} : {
|
|
863
872
|
count: 0,
|
|
864
873
|
totalBytes: 0
|
|
@@ -867,7 +876,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
867
876
|
};
|
|
868
877
|
return yield* n.tryPromise({
|
|
869
878
|
try: async () => {
|
|
870
|
-
await (await import("node:fs/promises")).writeFile(l(K),
|
|
879
|
+
await (await import("node:fs/promises")).writeFile(l(K), Tt(x));
|
|
871
880
|
},
|
|
872
881
|
catch: (e) => new H({
|
|
873
882
|
reason: `manifest write failed: ${Y(e)}`,
|
|
@@ -876,14 +885,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
876
885
|
}), yield* n.tryPromise({
|
|
877
886
|
try: async () => {
|
|
878
887
|
let e = await import("node:fs/promises"), t = await import("node:os");
|
|
879
|
-
await e.writeFile(l(
|
|
888
|
+
await e.writeFile(l(Dt), Nt(x, { hostname: t.hostname() }));
|
|
880
889
|
},
|
|
881
890
|
catch: (e) => new H({
|
|
882
891
|
reason: `readme write failed: ${Y(e)}`,
|
|
883
|
-
path:
|
|
892
|
+
path: Dt
|
|
884
893
|
})
|
|
885
894
|
}), x;
|
|
886
|
-
}),
|
|
895
|
+
}), mn = (e, t) => {
|
|
887
896
|
let n = new Set(t), r = [];
|
|
888
897
|
for (let t of e.tables) if (!n.has(t.name)) for (let e of t.columns) {
|
|
889
898
|
let i = e.references?.table;
|
|
@@ -894,7 +903,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
894
903
|
});
|
|
895
904
|
}
|
|
896
905
|
return r;
|
|
897
|
-
},
|
|
906
|
+
}, hn = (e) => {
|
|
898
907
|
let t = /* @__PURE__ */ new Map();
|
|
899
908
|
for (let n of e) t.set(n.from, [...t.get(n.from) ?? [], n]);
|
|
900
909
|
let n = [...t.entries()].map(([e, t]) => {
|
|
@@ -902,7 +911,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
902
911
|
return ` ${e} (${n} row${n === 1 ? "" : "s"}): ${r}`;
|
|
903
912
|
});
|
|
904
913
|
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
|
-
},
|
|
914
|
+
}, gn = (e) => {
|
|
906
915
|
switch (e) {
|
|
907
916
|
case "id":
|
|
908
917
|
case "text":
|
|
@@ -921,12 +930,12 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
921
930
|
case "raw": return "raw";
|
|
922
931
|
default: return "string";
|
|
923
932
|
}
|
|
924
|
-
},
|
|
933
|
+
}, _n = {
|
|
925
934
|
vector: /* @__PURE__ */ new Set(["postgres"]),
|
|
926
935
|
array: /* @__PURE__ */ new Set(["postgres"]),
|
|
927
936
|
interval: /* @__PURE__ */ new Set(["postgres"])
|
|
928
|
-
},
|
|
929
|
-
let i =
|
|
937
|
+
}, vn = (e, t, n, r) => {
|
|
938
|
+
let i = gn(n);
|
|
930
939
|
if (i === "raw") return {
|
|
931
940
|
table: e,
|
|
932
941
|
column: t,
|
|
@@ -934,7 +943,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
934
943
|
severity: "block",
|
|
935
944
|
reason: `raw() is verbatim source-dialect SQL — it cannot be assumed valid on ${r}`
|
|
936
945
|
};
|
|
937
|
-
let a =
|
|
946
|
+
let a = _n[i];
|
|
938
947
|
return !a || a.has(r) ? null : i === "array" || i === "interval" ? {
|
|
939
948
|
table: e,
|
|
940
949
|
column: t,
|
|
@@ -948,15 +957,15 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
948
957
|
severity: "block",
|
|
949
958
|
reason: `${i} columns require a ${[...a].join("/")} target; ${r} has no compatible column type`
|
|
950
959
|
};
|
|
951
|
-
},
|
|
960
|
+
}, yn = (e, t, n) => {
|
|
952
961
|
if (t === n) return [];
|
|
953
962
|
let r = [];
|
|
954
963
|
for (let t of e) for (let [e, i] of Object.entries(t.columnTypes)) {
|
|
955
|
-
let a =
|
|
964
|
+
let a = vn(t.name, e, i, n);
|
|
956
965
|
a && r.push(a);
|
|
957
966
|
}
|
|
958
967
|
return r;
|
|
959
|
-
},
|
|
968
|
+
}, bn = (e) => `[${e.severity}] ${e.table}.${e.column} (${e.type}): ${e.reason}`, xn = (e) => {
|
|
960
969
|
let t = e.constraint ?? e.column, n = t === void 0 ? "" : ` ${t}`;
|
|
961
970
|
switch (e.kind) {
|
|
962
971
|
case "foreignKey": return `foreign key${n}: the referenced row does not exist (import it first, or check the bundle's table order)`;
|
|
@@ -965,35 +974,35 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
965
974
|
case "notNull": return `not-null constraint${n}: the column requires a value`;
|
|
966
975
|
case "check": return `check constraint${n}: the row does not satisfy it`;
|
|
967
976
|
}
|
|
968
|
-
},
|
|
977
|
+
}, Sn = (e) => {
|
|
969
978
|
let t = [e.dbCode, e.dbErrno ?? e.dbNumber].filter((e) => e !== void 0).map(String);
|
|
970
979
|
return t.length > 0 ? t.join("/") : void 0;
|
|
971
|
-
},
|
|
980
|
+
}, Cn = "Failed to execute statement", wn = (e) => {
|
|
972
981
|
let t = (e.split("\n", 1)[0] ?? "").trim();
|
|
973
982
|
for (; t.startsWith("(FiberFailure)");) t = t.slice(14).trim();
|
|
974
|
-
return t === `SqlError: ${
|
|
975
|
-
},
|
|
983
|
+
return t === `SqlError: ${Cn}` ? Cn : t;
|
|
984
|
+
}, Tn = (e) => {
|
|
976
985
|
let t = String(e?.stack ?? e), n = t.length <= 1200 ? t : `${t.slice(0, 1200)}…`, r = (e, t) => ({
|
|
977
986
|
reason: e.length <= 300 ? e : `${e.slice(0, 300)}…`,
|
|
978
987
|
unclassified: t,
|
|
979
988
|
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
|
-
},
|
|
989
|
+
}), i = _(e), a = p(i), o = Sn(i), s = o === void 0 ? "" : ` [${o}]`;
|
|
990
|
+
if (a !== void 0) return r(`${xn(a)}${s}`, !1);
|
|
991
|
+
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})` : "";
|
|
992
|
+
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);
|
|
993
|
+
}, En = (e) => Tn(e).reason, Dn = (e) => {
|
|
985
994
|
let t = _(e), n = p(t);
|
|
986
995
|
if (n?.kind === "foreignKeyInUse") {
|
|
987
|
-
let e = n.constraint ?? n.column, r = e === void 0 ? "" : ` ${e}`, i =
|
|
996
|
+
let e = n.constraint ?? n.column, r = e === void 0 ? "" : ` ${e}`, i = Sn(t);
|
|
988
997
|
return `foreign key${r}: rows elsewhere still reference this table${i === void 0 ? "" : ` [${i}]`}`;
|
|
989
998
|
}
|
|
990
|
-
return
|
|
991
|
-
},
|
|
999
|
+
return En(e);
|
|
1000
|
+
}, 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
1001
|
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 (!
|
|
1002
|
+
written before the first delete is what covers that case.`, jn = /^[a-zA-Z_][a-zA-Z0-9_]*$/, Z = (e, t) => {
|
|
1003
|
+
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
1004
|
return t === "mysql" || t === "mariadb" ? `\`${e}\`` : t === "mssql" ? `[${e}]` : `"${e}"`;
|
|
996
|
-
},
|
|
1005
|
+
}, Mn = (e, t) => {
|
|
997
1006
|
let n = Z(e, t), r = Z(X(e), t);
|
|
998
1007
|
switch (t) {
|
|
999
1008
|
case "postgres": return `CREATE TABLE ${r} (LIKE ${n})`;
|
|
@@ -1002,10 +1011,10 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1002
1011
|
case "sqlite": return `CREATE TABLE ${r} AS SELECT * FROM ${n} WHERE 0`;
|
|
1003
1012
|
case "mssql": return `SELECT * INTO ${r} FROM ${n} WHERE 1 = 0`;
|
|
1004
1013
|
}
|
|
1005
|
-
},
|
|
1014
|
+
}, Nn = (e, t) => {
|
|
1006
1015
|
let n = Z(X(e), t);
|
|
1007
1016
|
return t === "mssql" ? `IF OBJECT_ID('${X(e)}', 'U') IS NOT NULL DROP TABLE ${n}` : `DROP TABLE IF EXISTS ${n}`;
|
|
1008
|
-
},
|
|
1017
|
+
}, Pn = (e, t) => {
|
|
1009
1018
|
let n = t === "mysql" || t === "mariadb", r = [];
|
|
1010
1019
|
n && r.push("SET FOREIGN_KEY_CHECKS = 0");
|
|
1011
1020
|
for (let n of [...e].reverse()) r.push(`DELETE FROM ${Z(n.name, t)}`);
|
|
@@ -1015,7 +1024,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1015
1024
|
r.push(`INSERT INTO ${Z(n.name, t)} (${e}) SELECT ${e} FROM ${Z(X(n.name), t)}`);
|
|
1016
1025
|
}
|
|
1017
1026
|
return n && r.push("SET FOREIGN_KEY_CHECKS = 1"), r;
|
|
1018
|
-
},
|
|
1027
|
+
}, Fn = (e, t) => {
|
|
1019
1028
|
let n = [], r = () => {
|
|
1020
1029
|
for (let e of n) t.unregisterTable(e);
|
|
1021
1030
|
};
|
|
@@ -1037,7 +1046,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1037
1046
|
staged: n,
|
|
1038
1047
|
undo: r
|
|
1039
1048
|
};
|
|
1040
|
-
},
|
|
1049
|
+
}, In = (e, t) => {
|
|
1041
1050
|
let n = new Set(t), r = [];
|
|
1042
1051
|
for (let t of e.tables) {
|
|
1043
1052
|
if (!n.has(t.name)) continue;
|
|
@@ -1054,22 +1063,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1054
1063
|
}
|
|
1055
1064
|
}
|
|
1056
1065
|
return r;
|
|
1057
|
-
},
|
|
1066
|
+
}, Ln = (e, t) => {
|
|
1058
1067
|
let n = Z(X(e.from), t), r = Z(X(e.to), t), i = Z(e.column, t), a = Z(e.toColumn, t);
|
|
1059
1068
|
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
|
-
},
|
|
1069
|
+
}, Rn = (e) => {
|
|
1061
1070
|
if (e.length === 0) return;
|
|
1062
1071
|
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
1072
|
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
|
-
},
|
|
1073
|
+
}, zn = async (e, t) => {
|
|
1074
|
+
t.length !== 0 && await e.run(_e.SqlClient.pipe(n.flatMap((e) => n.forEach(t, (t) => e.unsafe(t), { discard: !0 }))));
|
|
1075
|
+
}, Bn = async (e, t, r) => {
|
|
1076
|
+
let i = Pn(t, r);
|
|
1077
|
+
i.length !== 0 && await e.run(_e.SqlClient.pipe(n.flatMap((e) => e.withTransaction(n.forEach(i, (t) => e.unsafe(t), { discard: !0 })))));
|
|
1078
|
+
}, Vn = async (e, t, r) => {
|
|
1070
1079
|
let i = [];
|
|
1071
1080
|
for (let a of t) {
|
|
1072
|
-
let t = await e.run(
|
|
1081
|
+
let t = await e.run(_e.SqlClient.pipe(n.flatMap((e) => e.unsafe(Ln(a, r)))));
|
|
1073
1082
|
for (let e of t) i.push({
|
|
1074
1083
|
table: a.from,
|
|
1075
1084
|
primaryKey: String(e.pk ?? ""),
|
|
@@ -1079,14 +1088,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1079
1088
|
});
|
|
1080
1089
|
}
|
|
1081
1090
|
return i;
|
|
1082
|
-
},
|
|
1091
|
+
}, Hn = (e, t) => {
|
|
1083
1092
|
let n = new Map(t.map((e, t) => [e, t]));
|
|
1084
1093
|
return e.filter((e) => {
|
|
1085
1094
|
if (e.from === e.to) return !1;
|
|
1086
1095
|
let t = n.get(e.from), r = n.get(e.to);
|
|
1087
1096
|
return t === void 0 || r === void 0 ? !1 : r > t;
|
|
1088
1097
|
});
|
|
1089
|
-
},
|
|
1098
|
+
}, Un = (e) => e === "mysql" || e === "mariadb", Wn = (e) => {
|
|
1090
1099
|
if (e.mode !== "replace") return {
|
|
1091
1100
|
active: !1,
|
|
1092
1101
|
tables: [],
|
|
@@ -1136,7 +1145,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1136
1145
|
tables: [],
|
|
1137
1146
|
blocker: "every table in the bundle is one that describes a deployment, so there is nothing for a staged swap to move."
|
|
1138
1147
|
};
|
|
1139
|
-
let s = o.map((e) => e.name), c =
|
|
1148
|
+
let s = o.map((e) => e.name), c = Un(t) ? [] : Hn(In(n, s), s);
|
|
1140
1149
|
return c.length > 0 ? {
|
|
1141
1150
|
active: !1,
|
|
1142
1151
|
tables: [],
|
|
@@ -1145,7 +1154,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1145
1154
|
active: !0,
|
|
1146
1155
|
tables: o
|
|
1147
1156
|
};
|
|
1148
|
-
},
|
|
1157
|
+
}, Gn = (e) => n.gen(function* () {
|
|
1149
1158
|
if (e.mode !== "replace" || e.dir === void 0 || e.tables.length === 0) return;
|
|
1150
1159
|
if (e.snapshot === void 0) return yield* n.fail(new H({
|
|
1151
1160
|
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 +1167,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1158
1167
|
if (t.tables.length === 0) return;
|
|
1159
1168
|
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
1169
|
so it survives a run whose process does not.`);
|
|
1161
|
-
let r = yield*
|
|
1170
|
+
let r = yield* pn({
|
|
1162
1171
|
store: e.store,
|
|
1163
1172
|
snapshot: t,
|
|
1164
1173
|
dialect: e.dialect ?? "unknown",
|
|
@@ -1174,18 +1183,18 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1174
1183
|
rows: r.tables.reduce((e, t) => e + t.rowCount, 0),
|
|
1175
1184
|
tables: r.tables.length
|
|
1176
1185
|
};
|
|
1177
|
-
}),
|
|
1186
|
+
}), 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
1187
|
let n = [];
|
|
1179
1188
|
for (let r of [...e.tables].sort((e, t) => e.name.localeCompare(t.name))) {
|
|
1180
|
-
if (
|
|
1189
|
+
if (qn(t, r.name) === void 0) {
|
|
1181
1190
|
n.push(`table '${r.name}' is in the bundle but MISSING from the target — its rows have nowhere to go`);
|
|
1182
1191
|
continue;
|
|
1183
1192
|
}
|
|
1184
|
-
let e =
|
|
1193
|
+
let e = Jn(t, r.name), i = new Map(r.columns.map((e) => [e.name, e]));
|
|
1185
1194
|
for (let [t, a] of i) {
|
|
1186
1195
|
let i = e.get(t);
|
|
1187
1196
|
if (i === void 0) {
|
|
1188
|
-
n.push(
|
|
1197
|
+
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
1198
|
continue;
|
|
1190
1199
|
}
|
|
1191
1200
|
i.type !== a.type && n.push(`${r.name}.${t}: type '${a.type}' (bundle) vs '${i.type}' (target)`);
|
|
@@ -1193,22 +1202,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1193
1202
|
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
1203
|
}
|
|
1195
1204
|
return n.length > 30 ? [...n.slice(0, 30), `… and ${n.length - 30} more difference(s)`] : n;
|
|
1196
|
-
},
|
|
1197
|
-
let r =
|
|
1205
|
+
}, Zn = (e, t, n) => {
|
|
1206
|
+
let r = ie(t);
|
|
1198
1207
|
if (r === e || n === void 0) return {
|
|
1199
1208
|
drifted: !1,
|
|
1200
1209
|
bundleFingerprint: e,
|
|
1201
1210
|
targetFingerprint: r,
|
|
1202
1211
|
diff: []
|
|
1203
1212
|
};
|
|
1204
|
-
let i =
|
|
1213
|
+
let i = Xn(n, t);
|
|
1205
1214
|
return {
|
|
1206
1215
|
drifted: i.length > 0,
|
|
1207
1216
|
bundleFingerprint: e,
|
|
1208
1217
|
targetFingerprint: r,
|
|
1209
1218
|
diff: i
|
|
1210
1219
|
};
|
|
1211
|
-
},
|
|
1220
|
+
}, Qn = 2e3, $n = 200, er = /* @__PURE__ */ new Set([
|
|
1212
1221
|
"BundleError",
|
|
1213
1222
|
"CodecError",
|
|
1214
1223
|
"IntegrityError",
|
|
@@ -1217,29 +1226,29 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1217
1226
|
"RowsRefusedError",
|
|
1218
1227
|
"SchemaDriftError",
|
|
1219
1228
|
"StorageError"
|
|
1220
|
-
]),
|
|
1229
|
+
]), tr = (t) => {
|
|
1221
1230
|
let n = o.isFiberFailure(t) ? [...e.failures(t[o.FiberFailureCauseId]), ...e.defects(t[o.FiberFailureCauseId])] : [t];
|
|
1222
1231
|
for (let e of n) {
|
|
1223
1232
|
let t = e?._tag;
|
|
1224
|
-
if (typeof t == "string" &&
|
|
1233
|
+
if (typeof t == "string" && er.has(t)) return e;
|
|
1225
1234
|
if (o.isFiberFailure(e)) {
|
|
1226
|
-
let t =
|
|
1235
|
+
let t = tr(e);
|
|
1227
1236
|
if (t) return t;
|
|
1228
1237
|
}
|
|
1229
1238
|
}
|
|
1230
|
-
},
|
|
1239
|
+
}, nr = (t) => [...e.failures(t)][0] ?? Error(e.pretty(t)), rr = (e) => n.tryPromise({
|
|
1231
1240
|
try: async () => {
|
|
1232
1241
|
let t = await import("node:fs/promises"), n = await import("node:path");
|
|
1233
|
-
return
|
|
1242
|
+
return Et(await t.readFile(n.join(e, K), "utf8"));
|
|
1234
1243
|
},
|
|
1235
1244
|
catch: (e) => new H({
|
|
1236
1245
|
reason: `manifest read/parse failed: ${String(e?.message ?? e)}`,
|
|
1237
1246
|
path: K
|
|
1238
1247
|
})
|
|
1239
|
-
}),
|
|
1248
|
+
}), ir = (e) => {
|
|
1240
1249
|
let t;
|
|
1241
1250
|
return n.gen(function* () {
|
|
1242
|
-
let i = yield* n.promise(() => import("node:path")), a = yield*
|
|
1251
|
+
let i = yield* n.promise(() => import("node:path")), a = yield* rr(e.bundleDir);
|
|
1243
1252
|
if (a.formatVersion !== 1) return yield* n.fail(new H({ reason: `unsupported bundle formatVersion ${a.formatVersion} (expected 1)` }));
|
|
1244
1253
|
if (e.tables !== void 0) {
|
|
1245
1254
|
let t = new Set(a.tables.map((e) => e.name)), r = e.tables.filter((e) => !t.has(e));
|
|
@@ -1260,9 +1269,9 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1260
1269
|
unique: !1,
|
|
1261
1270
|
hasDefault: !1
|
|
1262
1271
|
}))
|
|
1263
|
-
})) }, r =
|
|
1272
|
+
})) }, r = Zn(s.source.schemaFingerprint, e.targetSnapshot, t);
|
|
1264
1273
|
if (r.drifted) {
|
|
1265
|
-
if (!e.force) return yield* n.fail(new
|
|
1274
|
+
if (!e.force) return yield* n.fail(new Ze({
|
|
1266
1275
|
bundleFingerprint: r.bundleFingerprint,
|
|
1267
1276
|
targetFingerprint: r.targetFingerprint,
|
|
1268
1277
|
diff: r.diff
|
|
@@ -1271,15 +1280,15 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1271
1280
|
}
|
|
1272
1281
|
}
|
|
1273
1282
|
if (e.targetDialect && e.targetDialect !== s.source.dialect) {
|
|
1274
|
-
let t =
|
|
1275
|
-
if (t.length > 0 && !e.allowIncompatible) return yield* n.fail(new
|
|
1283
|
+
let t = yn(s.tables, s.source.dialect, e.targetDialect).filter((e) => e.severity === "block");
|
|
1284
|
+
if (t.length > 0 && !e.allowIncompatible) return yield* n.fail(new et({
|
|
1276
1285
|
sourceDialect: s.source.dialect,
|
|
1277
1286
|
targetDialect: e.targetDialect,
|
|
1278
|
-
blocking: t.map(
|
|
1287
|
+
blocking: t.map(bn)
|
|
1279
1288
|
}));
|
|
1280
1289
|
}
|
|
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
|
|
1290
|
+
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);
|
|
1291
|
+
if (p === "replace" && s.scope.kind !== "all") return yield* n.fail(new $e({
|
|
1283
1292
|
mode: p,
|
|
1284
1293
|
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
1294
|
}));
|
|
@@ -1291,8 +1300,8 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1291
1300
|
if (p === "replace") {
|
|
1292
1301
|
let t = s.tables.map((e) => e.name), r = e.store.incomingForeignKeys ? yield* n.tryPromise({
|
|
1293
1302
|
try: () => e.store.incomingForeignKeys(t),
|
|
1294
|
-
catch: (e) => new H({ reason: `foreign-key pre-flight failed: ${
|
|
1295
|
-
}) : e.targetSnapshot === void 0 ? [] :
|
|
1303
|
+
catch: (e) => new H({ reason: `foreign-key pre-flight failed: ${Dn(e)}` })
|
|
1304
|
+
}) : e.targetSnapshot === void 0 ? [] : mn(e.targetSnapshot, t), i = [], a = /* @__PURE__ */ new Map();
|
|
1296
1305
|
for (let t of r) {
|
|
1297
1306
|
if (!a.has(t.from)) {
|
|
1298
1307
|
let r = yield* n.tryPromise({
|
|
@@ -1314,9 +1323,9 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1314
1323
|
rowCount: r
|
|
1315
1324
|
});
|
|
1316
1325
|
}
|
|
1317
|
-
if (i.length > 0) return yield* n.fail(new
|
|
1326
|
+
if (i.length > 0) return yield* n.fail(new $e({
|
|
1318
1327
|
mode: p,
|
|
1319
|
-
reason:
|
|
1328
|
+
reason: hn(i)
|
|
1320
1329
|
}));
|
|
1321
1330
|
}
|
|
1322
1331
|
if (e.dryRun === !0) return e.traceId !== void 0 && (yield* n.promise(() => e.store.update(u, e.traceId, {
|
|
@@ -1332,25 +1341,25 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1332
1341
|
rowsSkipped: 0,
|
|
1333
1342
|
fullyResumed: !1
|
|
1334
1343
|
};
|
|
1335
|
-
let
|
|
1344
|
+
let C = /* @__PURE__ */ new Map();
|
|
1336
1345
|
for (let t of e.targetSnapshot?.tables ?? []) {
|
|
1337
1346
|
let e = t.columns.filter((e) => e.generatedAs !== void 0).map((e) => e.name);
|
|
1338
|
-
e.length > 0 &&
|
|
1347
|
+
e.length > 0 && C.set(t.name, e);
|
|
1339
1348
|
}
|
|
1340
|
-
let
|
|
1341
|
-
let n =
|
|
1349
|
+
let ie = (e, t) => {
|
|
1350
|
+
let n = C.get(e);
|
|
1342
1351
|
if (n === void 0) return t;
|
|
1343
1352
|
let r;
|
|
1344
1353
|
for (let e of n) e in t && (r ??= { ...t }, delete r[e]);
|
|
1345
1354
|
return r ?? t;
|
|
1346
|
-
},
|
|
1347
|
-
let i =
|
|
1355
|
+
}, w = (e, t, n, r = !1) => {
|
|
1356
|
+
let i = k ? X(t.name) : t.name, a = t.primaryKey, o = ie(t.name, n);
|
|
1348
1357
|
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
1358
|
}, T = (e, t) => e.savepoint ? e.savepoint(t) : t(), E = 0, ae = (t, n, r) => {
|
|
1350
1359
|
r.unclassified && (E++, !(E > 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}` + (E === 3 ? " (further unclassified refusals are counted, not logged)" : "")));
|
|
1351
1360
|
}, D = (e, t, r = !0) => n.tryPromise({
|
|
1352
1361
|
try: e,
|
|
1353
|
-
catch: (e) =>
|
|
1362
|
+
catch: (e) => Tn(e)
|
|
1354
1363
|
}).pipe(n.map(() => !0), n.catchAll((e) => n.sync(() => (r && (t.reason = e.reason, ae(t.entry, t.row, e)), !1)))), oe = (e) => {
|
|
1355
1364
|
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
1365
|
if (t.length !== 0) return {
|
|
@@ -1375,7 +1384,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1375
1384
|
};
|
|
1376
1385
|
t.refused++, e.derived || t.primary++, a.set(e.table, t);
|
|
1377
1386
|
}
|
|
1378
|
-
return new
|
|
1387
|
+
return new Xe({
|
|
1379
1388
|
rows: i.slice(0, 20),
|
|
1380
1389
|
primaryCount: r.filter((e) => !e.derived).length,
|
|
1381
1390
|
totalCount: e.length,
|
|
@@ -1390,10 +1399,10 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1390
1399
|
for (; r.length > 0 && a;) {
|
|
1391
1400
|
a = !1;
|
|
1392
1401
|
let t = [];
|
|
1393
|
-
for (let n of r) (yield* D(() => T(e, () =>
|
|
1402
|
+
for (let n of r) (yield* D(() => T(e, () => w(e, n.entry, n.row, !0)), n)) ? a = !0 : t.push(n);
|
|
1394
1403
|
if (!a && t.length > 0) for (let n = t.length - 1; n >= 0; n--) {
|
|
1395
1404
|
let r = t[n], o = oe(r);
|
|
1396
|
-
o !== void 0 && (yield* D(() => T(e, () =>
|
|
1405
|
+
o !== void 0 && (yield* D(() => T(e, () => w(e, r.entry, o, !0)), r, !1)) && (i.push(r), t.splice(n, 1), a = !0);
|
|
1397
1406
|
}
|
|
1398
1407
|
r = t;
|
|
1399
1408
|
}
|
|
@@ -1402,21 +1411,21 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1402
1411
|
}), O = (() => {
|
|
1403
1412
|
let t = e.targetDialect;
|
|
1404
1413
|
return t === "postgres" || t === "mysql" || t === "mariadb" || t === "sqlite" || t === "mssql" ? t : void 0;
|
|
1405
|
-
})(),
|
|
1414
|
+
})(), ue = Wn({
|
|
1406
1415
|
mode: p,
|
|
1407
1416
|
...e.targetDialect === void 0 ? {} : { targetDialect: e.targetDialect },
|
|
1408
1417
|
...e.targetSnapshot === void 0 ? {} : { targetSnapshot: e.targetSnapshot },
|
|
1409
1418
|
bundleTables: s.tables.map((e) => e.name),
|
|
1410
1419
|
isSkipped: V,
|
|
1411
|
-
canRunSql:
|
|
1412
|
-
}),
|
|
1413
|
-
if (p === "replace" && !
|
|
1420
|
+
canRunSql: kn(e.store)
|
|
1421
|
+
}), 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* () {
|
|
1422
|
+
if (p === "replace" && !k && !(r && x.truncated)) {
|
|
1414
1423
|
e.recordInterruption === !0 && (yield* n.tryPromise({
|
|
1415
1424
|
try: () => t.insert(d, {
|
|
1416
|
-
id: m("repl",
|
|
1417
|
-
startedAt:
|
|
1425
|
+
id: m("repl", _e),
|
|
1426
|
+
startedAt: P,
|
|
1418
1427
|
tables: String(s.tables.length),
|
|
1419
|
-
capture:
|
|
1428
|
+
capture: F?.dir ?? null,
|
|
1420
1429
|
via: e.via ?? "direct"
|
|
1421
1430
|
}),
|
|
1422
1431
|
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 +1438,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1429
1438
|
});
|
|
1430
1439
|
yield* n.tryPromise({
|
|
1431
1440
|
try: o,
|
|
1432
|
-
catch: (e) => new H({ reason: `emptying the target for --mode replace failed (nothing was deleted): ${
|
|
1441
|
+
catch: (e) => new H({ reason: `emptying the target for --mode replace failed (nothing was deleted): ${Dn(e)}` })
|
|
1433
1442
|
}), r && (x.truncated = !0, yield* J(y, x));
|
|
1434
1443
|
}
|
|
1435
1444
|
let a = [], o = [], u = [], f = [], h = s.tables.length;
|
|
@@ -1440,7 +1449,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1440
1449
|
continue;
|
|
1441
1450
|
}
|
|
1442
1451
|
if (r && m.name in x.tables) {
|
|
1443
|
-
u.push(m.name),
|
|
1452
|
+
u.push(m.name), N++, M += x.tables[m.name].rowCount, q(e.onProgress, {
|
|
1444
1453
|
phase: "import",
|
|
1445
1454
|
table: m.name,
|
|
1446
1455
|
index: d,
|
|
@@ -1462,16 +1471,16 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1462
1471
|
total: m.rowCount
|
|
1463
1472
|
});
|
|
1464
1473
|
let v = a.length, b = n.gen(function* () {
|
|
1465
|
-
let { createHash: r } = yield* n.promise(() => import("node:crypto")), i = r("sha256"), o = 0, c =
|
|
1474
|
+
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
1475
|
let n = {
|
|
1467
1476
|
entry: m,
|
|
1468
1477
|
row: e,
|
|
1469
1478
|
reason: ""
|
|
1470
1479
|
};
|
|
1471
1480
|
try {
|
|
1472
|
-
await T(t, () =>
|
|
1481
|
+
await T(t, () => w(t, m, e));
|
|
1473
1482
|
} catch (t) {
|
|
1474
|
-
let r =
|
|
1483
|
+
let r = Tn(t);
|
|
1475
1484
|
n.reason = r.reason, ae(m, e, r), a.push(n);
|
|
1476
1485
|
}
|
|
1477
1486
|
}, d = yield* n.promise(async () => {
|
|
@@ -1507,40 +1516,40 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1507
1516
|
d = !1, e.onWarn?.(`bulk COPY into ${m.name} failed (${String(n?.message ?? n)}); falling back to per-row writes for this table`);
|
|
1508
1517
|
for (let e of t) await u(e);
|
|
1509
1518
|
}
|
|
1510
|
-
}, b = Math.max(1, e.savepointBatchSize ?? 200), x = typeof t.savepoint == "function", S = [],
|
|
1519
|
+
}, b = Math.max(1, e.savepointBatchSize ?? 200), x = typeof t.savepoint == "function", S = [], ee = async () => {
|
|
1511
1520
|
if (S.length === 0) return;
|
|
1512
1521
|
let e = S;
|
|
1513
1522
|
S = [];
|
|
1514
1523
|
try {
|
|
1515
1524
|
await t.savepoint(async () => {
|
|
1516
|
-
for (let n of e) await
|
|
1525
|
+
for (let n of e) await w(t, m, n);
|
|
1517
1526
|
});
|
|
1518
1527
|
} catch {
|
|
1519
1528
|
for (let t of e) await u(t);
|
|
1520
1529
|
}
|
|
1521
1530
|
};
|
|
1522
|
-
return yield* l.runForEach(
|
|
1531
|
+
return yield* l.runForEach(en(c, m.name, m.columnTypes), (e) => n.promise(async () => {
|
|
1523
1532
|
if (o++, d) {
|
|
1524
1533
|
v.push(e), v.length >= h && await y();
|
|
1525
1534
|
return;
|
|
1526
1535
|
}
|
|
1527
1536
|
if (x) {
|
|
1528
|
-
S.push(e), S.length >= b && await
|
|
1537
|
+
S.push(e), S.length >= b && await ee();
|
|
1529
1538
|
return;
|
|
1530
1539
|
}
|
|
1531
1540
|
await u(e);
|
|
1532
|
-
})), yield* n.promise(
|
|
1541
|
+
})), yield* n.promise(ee), yield* n.promise(y), {
|
|
1533
1542
|
rowCount: o,
|
|
1534
1543
|
checksum: i.digest("hex")
|
|
1535
1544
|
};
|
|
1536
|
-
}), { rowCount: S, checksum:
|
|
1545
|
+
}), { rowCount: S, checksum: ee } = yield* Lt("import", m.name, d, h, (e) => e.rowCount, b);
|
|
1537
1546
|
if (c) {
|
|
1538
|
-
if (
|
|
1547
|
+
if (ee !== m.checksum) return yield* n.fail(new Je({
|
|
1539
1548
|
what: `table ${m.name} checksum`,
|
|
1540
1549
|
expected: m.checksum,
|
|
1541
|
-
actual:
|
|
1550
|
+
actual: ee
|
|
1542
1551
|
}));
|
|
1543
|
-
if (S !== m.rowCount) return yield* n.fail(new
|
|
1552
|
+
if (S !== m.rowCount) return yield* n.fail(new Je({
|
|
1544
1553
|
what: `table ${m.name} rowCount`,
|
|
1545
1554
|
expected: String(m.rowCount),
|
|
1546
1555
|
actual: String(S)
|
|
@@ -1554,7 +1563,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1554
1563
|
event: "done",
|
|
1555
1564
|
rowsDone: S,
|
|
1556
1565
|
total: m.rowCount
|
|
1557
|
-
}),
|
|
1566
|
+
}), j++, A += S, he?.(), r && (a.length > v ? o.push({
|
|
1558
1567
|
name: m.name,
|
|
1559
1568
|
rowCount: S
|
|
1560
1569
|
}) : (x.tables[m.name] = {
|
|
@@ -1565,7 +1574,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1565
1574
|
if (a.length > 0 && (yield* ce(t, a)), p === "replace" && (yield* n.promise(() => t.deleteMany(d, { where: {
|
|
1566
1575
|
column: "startedAt",
|
|
1567
1576
|
op: "lte",
|
|
1568
|
-
value:
|
|
1577
|
+
value: P
|
|
1569
1578
|
} }).then(() => void 0, () => void 0))), r && o.length > 0) {
|
|
1570
1579
|
for (let e of o) {
|
|
1571
1580
|
let t = s.tables.find((t) => t.name === e.name);
|
|
@@ -1577,14 +1586,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1577
1586
|
yield* J(y, x);
|
|
1578
1587
|
}
|
|
1579
1588
|
{
|
|
1580
|
-
let t =
|
|
1589
|
+
let t = Ke(f, "skipped");
|
|
1581
1590
|
t !== void 0 && e.onWarn?.(t);
|
|
1582
1591
|
}
|
|
1583
1592
|
if (u.length > 0) {
|
|
1584
1593
|
let t = u.length === s.tables.length;
|
|
1585
1594
|
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
1595
|
}
|
|
1587
|
-
}),
|
|
1596
|
+
}), _e = `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`, P = /* @__PURE__ */ new Date(), F = yield* Gn({
|
|
1588
1597
|
store: e.store,
|
|
1589
1598
|
mode: p,
|
|
1590
1599
|
dir: e.rollbackDir,
|
|
@@ -1593,15 +1602,15 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1593
1602
|
tables: s.tables.map((e) => e.name).filter((e) => !V(e)),
|
|
1594
1603
|
onWarn: e.onWarn
|
|
1595
1604
|
});
|
|
1596
|
-
|
|
1597
|
-
try: () => e.onRollbackCaptured(
|
|
1605
|
+
F !== void 0 && (e.onRollbackCaptured !== void 0 && (yield* n.tryPromise({
|
|
1606
|
+
try: () => e.onRollbackCaptured(F),
|
|
1598
1607
|
catch: (e) => new H({
|
|
1599
1608
|
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:
|
|
1609
|
+
path: F.dir
|
|
1601
1610
|
})
|
|
1602
|
-
})), e.onWarn?.(
|
|
1603
|
-
let
|
|
1604
|
-
|
|
1611
|
+
})), e.onWarn?.(Kn(F)));
|
|
1612
|
+
let ve = (e) => p === "replace" ? te(e) : e(), I = (e) => p === "replace" ? ne(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;
|
|
1613
|
+
R && h(f), R && e.traceId === void 0 && (yield* n.promise(() => e.store.insert(u, {
|
|
1605
1614
|
id: L,
|
|
1606
1615
|
mode: p,
|
|
1607
1616
|
via: e.via ?? "direct",
|
|
@@ -1610,75 +1619,75 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1610
1619
|
sourceFingerprint: s.source.schemaFingerprint ?? null,
|
|
1611
1620
|
tablesWritten: 0,
|
|
1612
1621
|
rowsWritten: 0,
|
|
1613
|
-
staged: p === "replace" ?
|
|
1622
|
+
staged: p === "replace" ? k : null
|
|
1614
1623
|
}).then(() => {
|
|
1615
|
-
|
|
1624
|
+
ye = !0;
|
|
1616
1625
|
}, (t) => {
|
|
1617
1626
|
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
1627
|
\`voltro db apply\` so the next one is recorded.`);
|
|
1619
|
-
}))), e.traceId !== void 0 &&
|
|
1620
|
-
staged: p === "replace" ?
|
|
1628
|
+
}))), e.traceId !== void 0 && R && (yield* n.promise(() => e.store.update(u, L, {
|
|
1629
|
+
staged: p === "replace" ? k : null,
|
|
1621
1630
|
sourceFingerprint: s.source.schemaFingerprint ?? null
|
|
1622
1631
|
}).then(() => void 0, () => void 0)));
|
|
1623
1632
|
let be = 0, xe = !1;
|
|
1624
|
-
|
|
1625
|
-
if (!
|
|
1633
|
+
he = () => {
|
|
1634
|
+
if (!ye || xe) return;
|
|
1626
1635
|
let t = Date.now();
|
|
1627
|
-
t - be <
|
|
1628
|
-
tablesWritten:
|
|
1629
|
-
rowsWritten:
|
|
1636
|
+
t - be < Qn || (be = t, e.store.update(u, L, {
|
|
1637
|
+
tablesWritten: j,
|
|
1638
|
+
rowsWritten: A
|
|
1630
1639
|
}).then(() => void 0, () => {
|
|
1631
1640
|
xe = !0;
|
|
1632
1641
|
}));
|
|
1633
1642
|
};
|
|
1634
|
-
let Se = (t) =>
|
|
1643
|
+
let Se = (t) => ye ? e.store.update(u, L, {
|
|
1635
1644
|
finishedAt: t === null ? /* @__PURE__ */ new Date() : null,
|
|
1636
|
-
tablesWritten:
|
|
1637
|
-
rowsWritten:
|
|
1645
|
+
tablesWritten: j,
|
|
1646
|
+
rowsWritten: A,
|
|
1638
1647
|
failure: t
|
|
1639
1648
|
}).then(() => void 0, () => void 0) : Promise.resolve();
|
|
1640
|
-
if (t = (e) => Se(e), p === "replace" && !
|
|
1649
|
+
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
1650
|
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 =
|
|
1651
|
+
tenant scoping or \`audit()\` stamping, for the same reason.`), k) {
|
|
1652
|
+
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.`);
|
|
1653
|
+
let t = e.store, r = de.map((e) => e.name), i = Fn(r, {
|
|
1645
1654
|
getTable: (e) => v(e),
|
|
1646
1655
|
registerTable: (e) => {
|
|
1647
|
-
|
|
1656
|
+
ee(e);
|
|
1648
1657
|
},
|
|
1649
|
-
unregisterTable:
|
|
1658
|
+
unregisterTable: re
|
|
1650
1659
|
}), a = !1;
|
|
1651
1660
|
try {
|
|
1652
|
-
let i = g ? r : r.filter((e) => !
|
|
1661
|
+
let i = g ? r : r.filter((e) => !Bt(x, e));
|
|
1653
1662
|
yield* n.tryPromise({
|
|
1654
1663
|
try: async () => {
|
|
1655
|
-
await
|
|
1664
|
+
await zn(t, i.map((e) => Nn(e, O))), await zn(t, i.map((e) => Mn(e, O)));
|
|
1656
1665
|
},
|
|
1657
1666
|
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: () =>
|
|
1667
|
+
}), yield* I(ge(e.store, !g)), !g && x.truncated === !0 ? a = !0 : yield* n.tryPromise({
|
|
1668
|
+
try: () => Bn(t, de, O).then(() => {
|
|
1660
1669
|
a = !0;
|
|
1661
1670
|
}),
|
|
1662
1671
|
catch: (e) => new H({ reason: String(e?.message ?? e) })
|
|
1663
1672
|
}).pipe(n.catchAll((i) => n.gen(function* () {
|
|
1664
|
-
let a =
|
|
1673
|
+
let a = Rn(yield* n.promise(() => Vn(t, In(e.targetSnapshot, r), O).then((e) => e, () => [])));
|
|
1665
1674
|
return yield* n.fail(new H({ reason: a ?? `the swap failed and the target is UNCHANGED: ${i.reason}` }));
|
|
1666
1675
|
}))), !g && a && x.truncated !== !0 && (x.truncated = !0, yield* J(y, x));
|
|
1667
1676
|
} finally {
|
|
1668
|
-
i.undo(), a || g ? yield* n.promise(() =>
|
|
1677
|
+
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
1678
|
}
|
|
1670
1679
|
} else g ? yield* n.tryPromise({
|
|
1671
1680
|
try: () => e.store.transactional(async (e) => {
|
|
1672
|
-
let t = await
|
|
1673
|
-
if (r.isFailure(t)) throw
|
|
1681
|
+
let t = await ve(() => n.runPromiseExit(ge(e, !1)));
|
|
1682
|
+
if (r.isFailure(t)) throw nr(t.cause);
|
|
1674
1683
|
}),
|
|
1675
|
-
catch: (e) =>
|
|
1676
|
-
}) : yield*
|
|
1684
|
+
catch: (e) => tr(e) ?? new H({ reason: `atomic import failed (rolled back): ${String(e?.message ?? e)}` })
|
|
1685
|
+
}) : yield* I(ge(e.store, !0));
|
|
1677
1686
|
if (e.assets && s.assets.index && !e.assetsAlreadyRestored) {
|
|
1678
1687
|
let t = e.assets;
|
|
1679
|
-
yield*
|
|
1688
|
+
yield* mt({
|
|
1680
1689
|
sink: t,
|
|
1681
|
-
assetsDir: i.join(e.bundleDir,
|
|
1690
|
+
assetsDir: i.join(e.bundleDir, kt),
|
|
1682
1691
|
indexPath: i.join(e.bundleDir, s.assets.index ?? "assets/index.ndjson"),
|
|
1683
1692
|
progress: {
|
|
1684
1693
|
done: (e) => e in x.assets,
|
|
@@ -1688,26 +1697,26 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1688
1697
|
}
|
|
1689
1698
|
return yield* n.promise(() => Se(null)), {
|
|
1690
1699
|
manifest: s,
|
|
1691
|
-
tablesWritten:
|
|
1692
|
-
rowsWritten:
|
|
1693
|
-
tablesSkipped:
|
|
1694
|
-
rowsSkipped:
|
|
1695
|
-
fullyResumed:
|
|
1696
|
-
...
|
|
1700
|
+
tablesWritten: j,
|
|
1701
|
+
rowsWritten: A,
|
|
1702
|
+
tablesSkipped: N,
|
|
1703
|
+
rowsSkipped: M,
|
|
1704
|
+
fullyResumed: j === 0 && N > 0,
|
|
1705
|
+
...F === void 0 ? {} : { rollback: F }
|
|
1697
1706
|
};
|
|
1698
1707
|
}).pipe(n.tapError((e) => n.promise(() => t?.(e?.reason ?? e?._tag ?? "the import did not finish") ?? Promise.resolve())));
|
|
1699
|
-
},
|
|
1708
|
+
}, ar = (e) => e, or = (e) => {
|
|
1700
1709
|
if (e.allowLive || e.liveInstance === null || e.sameTarget === "different") return { refuse: !1 };
|
|
1701
1710
|
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
1711
|
return {
|
|
1703
1712
|
refuse: !0,
|
|
1704
1713
|
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
1714
|
};
|
|
1706
|
-
}, Q = Buffer.from("VBUNDLE2"),
|
|
1715
|
+
}, Q = Buffer.from("VBUNDLE2"), sr = 0, cr = 1, lr = 2, ur = 32, dr = async (e) => {
|
|
1707
1716
|
let t = [], n = async (r) => {
|
|
1708
1717
|
let i;
|
|
1709
1718
|
try {
|
|
1710
|
-
i = await
|
|
1719
|
+
i = await F(R(e, r), { withFileTypes: !0 });
|
|
1711
1720
|
} catch {
|
|
1712
1721
|
return;
|
|
1713
1722
|
}
|
|
@@ -1717,21 +1726,21 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1717
1726
|
}
|
|
1718
1727
|
};
|
|
1719
1728
|
return await n(""), t.sort();
|
|
1720
|
-
},
|
|
1729
|
+
}, fr = (e, t) => {
|
|
1721
1730
|
let n = Buffer.from(e, "utf8"), r = Buffer.alloc(5 + n.length + 8);
|
|
1722
|
-
return r.writeUInt8(
|
|
1723
|
-
},
|
|
1731
|
+
return r.writeUInt8(cr, 0), r.writeUInt32BE(n.length, 1), n.copy(r, 5), r.writeBigUInt64BE(BigInt(t), 5 + n.length), r;
|
|
1732
|
+
}, pr = (e, t, n) => {
|
|
1724
1733
|
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(
|
|
1734
|
+
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
1735
|
};
|
|
1727
|
-
async function*
|
|
1736
|
+
async function* mr(e) {
|
|
1728
1737
|
yield new Uint8Array(Q);
|
|
1729
|
-
for (let t of await
|
|
1730
|
-
let n = R(e.dir, t), r = await
|
|
1731
|
-
if (yield new Uint8Array(
|
|
1738
|
+
for (let t of await dr(e.dir)) {
|
|
1739
|
+
let n = R(e.dir, t), r = await ve(n);
|
|
1740
|
+
if (yield new Uint8Array(fr(t, r.size)), r.size > 0) for await (let e of le(n)) yield new Uint8Array(e);
|
|
1732
1741
|
}
|
|
1733
1742
|
if (e.blobs) for await (let t of e.blobs.list()) {
|
|
1734
|
-
yield new Uint8Array(
|
|
1743
|
+
yield new Uint8Array(pr(t.key, t.contentType, t.size));
|
|
1735
1744
|
let n = E("sha256"), r = 0;
|
|
1736
1745
|
for await (let i of e.blobs.open(t.key)) {
|
|
1737
1746
|
let e = Buffer.from(i);
|
|
@@ -1740,11 +1749,11 @@ async function* fr(e) {
|
|
|
1740
1749
|
if (r !== t.size) throw Error(`blob '${t.key}' size mismatch: header ${t.size}, streamed ${r}`);
|
|
1741
1750
|
yield new Uint8Array(n.digest());
|
|
1742
1751
|
}
|
|
1743
|
-
yield new Uint8Array(Buffer.from([
|
|
1752
|
+
yield new Uint8Array(Buffer.from([sr]));
|
|
1744
1753
|
}
|
|
1745
|
-
var
|
|
1746
|
-
let n =
|
|
1747
|
-
await
|
|
1754
|
+
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) => {
|
|
1755
|
+
let n = be(t.dir);
|
|
1756
|
+
await P(n, { recursive: !0 });
|
|
1748
1757
|
let r = Buffer.alloc(0), i = e[Symbol.asyncIterator](), a = !1, o = async () => {
|
|
1749
1758
|
let { value: e, done: t } = await i.next();
|
|
1750
1759
|
return t ? (a = !0, !1) : (r = r.length === 0 ? Buffer.from(e) : Buffer.concat([r, Buffer.from(e)]), !0);
|
|
@@ -1759,24 +1768,24 @@ var pr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), mr
|
|
|
1759
1768
|
for (;;) {
|
|
1760
1769
|
await s(1);
|
|
1761
1770
|
let e = c(1).readUInt8(0);
|
|
1762
|
-
if (e ===
|
|
1763
|
-
if (e ===
|
|
1771
|
+
if (e === sr) return;
|
|
1772
|
+
if (e === cr) {
|
|
1764
1773
|
await s(4);
|
|
1765
1774
|
let e = c(4).readUInt32BE(0);
|
|
1766
1775
|
await s(e);
|
|
1767
1776
|
let t = c(e).toString("utf8");
|
|
1768
1777
|
await s(8);
|
|
1769
|
-
let i = c(8).readBigUInt64BE(0), a =
|
|
1770
|
-
if (a !== n && !a.startsWith(n +
|
|
1771
|
-
await
|
|
1778
|
+
let i = c(8).readBigUInt64BE(0), a = be(n, t);
|
|
1779
|
+
if (a !== n && !a.startsWith(n + xe)) throw Error(`archive path '${t}' escapes the destination`);
|
|
1780
|
+
await P(ye(a), { recursive: !0 });
|
|
1772
1781
|
let o = O(a);
|
|
1773
1782
|
for (; i > 0n;) {
|
|
1774
1783
|
r.length === 0 && await s(1);
|
|
1775
1784
|
let e = i < BigInt(r.length) ? Number(i) : r.length;
|
|
1776
|
-
await
|
|
1785
|
+
await hr(o, c(e)), i -= BigInt(e);
|
|
1777
1786
|
}
|
|
1778
|
-
await
|
|
1779
|
-
} else if (e ===
|
|
1787
|
+
await gr(o);
|
|
1788
|
+
} else if (e === lr) {
|
|
1780
1789
|
await s(4);
|
|
1781
1790
|
let e = c(4).readUInt32BE(0);
|
|
1782
1791
|
await s(e);
|
|
@@ -1786,24 +1795,24 @@ var pr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), mr
|
|
|
1786
1795
|
await s(i);
|
|
1787
1796
|
let a = c(i).toString("utf8");
|
|
1788
1797
|
await s(8);
|
|
1789
|
-
let o = c(8).readBigUInt64BE(0), l = await t.blobs.has(n), u = E("sha256"), d = new
|
|
1798
|
+
let o = c(8).readBigUInt64BE(0), l = await t.blobs.has(n), u = E("sha256"), d = new N(), f = l ? Promise.resolve() : t.blobs.write(n, d, {
|
|
1790
1799
|
contentType: a,
|
|
1791
1800
|
size: Number(o)
|
|
1792
1801
|
}), p = o;
|
|
1793
1802
|
for (; p > 0n;) {
|
|
1794
1803
|
r.length === 0 && await s(1);
|
|
1795
1804
|
let e = p < BigInt(r.length) ? Number(p) : r.length, t = c(e);
|
|
1796
|
-
u.update(t), l || await
|
|
1805
|
+
u.update(t), l || await hr(d, t), p -= BigInt(e);
|
|
1797
1806
|
}
|
|
1798
|
-
l ? d.destroy() : await
|
|
1799
|
-
let m = c(
|
|
1807
|
+
l ? d.destroy() : await gr(d), await f, await s(ur);
|
|
1808
|
+
let m = c(ur);
|
|
1800
1809
|
if (!u.digest().equals(m)) throw Error(`blob '${n}' failed integrity (sha mismatch)`);
|
|
1801
1810
|
} else throw Error(`unknown bundle entry kind ${e}`);
|
|
1802
1811
|
}
|
|
1803
1812
|
} finally {
|
|
1804
1813
|
a || await Promise.resolve(i.return?.()).catch(() => void 0);
|
|
1805
1814
|
}
|
|
1806
|
-
},
|
|
1815
|
+
}, vr = async (e, t) => {
|
|
1807
1816
|
let n = new Set(t), r = /* @__PURE__ */ new Map(), i = Buffer.alloc(0), a = e[Symbol.asyncIterator](), o = async () => {
|
|
1808
1817
|
let { value: e, done: t } = await a.next();
|
|
1809
1818
|
return !t && (i = i.length === 0 ? Buffer.from(e) : Buffer.concat([i, Buffer.from(e)]), !0);
|
|
@@ -1825,8 +1834,8 @@ var pr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), mr
|
|
|
1825
1834
|
if (!await s(Q.length) || !c(Q.length).equals(Q)) throw Error("not a bundle archive (bad magic)");
|
|
1826
1835
|
for (; await s(1);) {
|
|
1827
1836
|
let e = c(1).readUInt8(0);
|
|
1828
|
-
if (e ===
|
|
1829
|
-
if (e !==
|
|
1837
|
+
if (e === sr || e === lr) break;
|
|
1838
|
+
if (e !== cr) throw Error(`unknown bundle entry kind ${e}`);
|
|
1830
1839
|
if (!await s(4)) break;
|
|
1831
1840
|
let t = c(4).readUInt32BE(0);
|
|
1832
1841
|
if (!await s(t)) break;
|
|
@@ -1836,16 +1845,16 @@ var pr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), mr
|
|
|
1836
1845
|
if (a === null || n.has(i) && (r.set(i, a), n.delete(i), n.size === 0)) break;
|
|
1837
1846
|
}
|
|
1838
1847
|
return r;
|
|
1839
|
-
},
|
|
1848
|
+
}, yr = (e, t) => _r(e, {
|
|
1840
1849
|
dir: t,
|
|
1841
|
-
blobs:
|
|
1842
|
-
}),
|
|
1850
|
+
blobs: br(t)
|
|
1851
|
+
}), br = (e) => {
|
|
1843
1852
|
let t = /* @__PURE__ */ new Set();
|
|
1844
1853
|
return {
|
|
1845
1854
|
has: async (e) => t.has(e),
|
|
1846
1855
|
write: async (n, r, i) => {
|
|
1847
1856
|
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
|
|
1857
|
+
await P(c, { recursive: !0 });
|
|
1849
1858
|
let l = E("sha256"), u = 0, d = new s({ transform(e, t, n) {
|
|
1850
1859
|
l.update(e), u += e.length, n(null, e);
|
|
1851
1860
|
} }), f = R(c, `.tmp-${Date.now()}-${t.size}`);
|
|
@@ -1859,33 +1868,33 @@ var pr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), mr
|
|
|
1859
1868
|
})}\n`), t.add(n);
|
|
1860
1869
|
}
|
|
1861
1870
|
};
|
|
1862
|
-
},
|
|
1871
|
+
}, xr = Se(se), Sr = Buffer.from("VENC1\0\0\0"), Cr = 32, wr = 16, Tr = 7, Er = 16, Dr = 262144, Or = {
|
|
1863
1872
|
N: 32768,
|
|
1864
1873
|
r: 8,
|
|
1865
1874
|
p: 1
|
|
1866
|
-
},
|
|
1875
|
+
}, kr = 134217728, Ar = 43, jr = (e, t, n) => {
|
|
1867
1876
|
let r = Buffer.alloc(12);
|
|
1868
|
-
return e.copy(r, 0, 0,
|
|
1877
|
+
return e.copy(r, 0, 0, Tr), r.writeUInt32BE(t >>> 0, Tr), r.writeUInt8(+!!n, 11), r;
|
|
1869
1878
|
};
|
|
1870
|
-
async function*
|
|
1879
|
+
async function* Mr(e, t) {
|
|
1871
1880
|
if (!t) throw Error("encryptStream: a non-empty passphrase is required");
|
|
1872
|
-
let n = D(
|
|
1873
|
-
...
|
|
1874
|
-
maxmem:
|
|
1875
|
-
}), a = Buffer.alloc(
|
|
1876
|
-
|
|
1881
|
+
let n = D(wr), r = D(Tr), i = await xr(t, n, Cr, {
|
|
1882
|
+
...Or,
|
|
1883
|
+
maxmem: kr
|
|
1884
|
+
}), a = Buffer.alloc(Ar);
|
|
1885
|
+
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
1886
|
let o = 0, s = (e, t) => {
|
|
1878
|
-
let n =
|
|
1887
|
+
let n = w("aes-256-gcm", i, jr(r, o, t));
|
|
1879
1888
|
o === 0 && n.setAAD(a);
|
|
1880
1889
|
let s = Buffer.concat([n.update(e), n.final()]), c = n.getAuthTag();
|
|
1881
1890
|
o++;
|
|
1882
|
-
let l = Buffer.alloc(5 + s.length +
|
|
1883
|
-
return l.writeUInt8(+!!t, 0), l.writeUInt32BE(s.length +
|
|
1891
|
+
let l = Buffer.alloc(5 + s.length + Er);
|
|
1892
|
+
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
1893
|
}, 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 >
|
|
1894
|
+
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
1895
|
yield s(c, !0);
|
|
1887
1896
|
}
|
|
1888
|
-
async function*
|
|
1897
|
+
async function* Nr(e, t) {
|
|
1889
1898
|
if (!t) throw Error("decryptStream: a non-empty passphrase is required");
|
|
1890
1899
|
let n = e[Symbol.asyncIterator](), r = Buffer.alloc(0), i = !1, a = async () => {
|
|
1891
1900
|
let { value: e, done: t } = await n.next();
|
|
@@ -1894,16 +1903,16 @@ async function* jr(e, t) {
|
|
|
1894
1903
|
for (; r.length < e && !i && await a(););
|
|
1895
1904
|
return r.length >= e;
|
|
1896
1905
|
};
|
|
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,
|
|
1906
|
+
if (!await o(Ar)) throw Error("encrypted bundle truncated (no header)");
|
|
1907
|
+
let s = r.subarray(0, Ar);
|
|
1908
|
+
if (!s.subarray(0, 8).equals(Sr)) throw Error("not an encrypted bundle (bad magic / wrong passphrase target)");
|
|
1909
|
+
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
1910
|
N: c,
|
|
1902
1911
|
r: l,
|
|
1903
1912
|
p: u,
|
|
1904
|
-
maxmem:
|
|
1913
|
+
maxmem: kr
|
|
1905
1914
|
});
|
|
1906
|
-
r = r.subarray(
|
|
1915
|
+
r = r.subarray(Ar);
|
|
1907
1916
|
let m = 0, h = !1;
|
|
1908
1917
|
for (;;) {
|
|
1909
1918
|
if (!await o(5)) {
|
|
@@ -1912,11 +1921,11 @@ async function* jr(e, t) {
|
|
|
1912
1921
|
}
|
|
1913
1922
|
if (h) throw Error("encrypted bundle has trailing data after the final frame");
|
|
1914
1923
|
let e = r.readUInt8(0) === 1, t = r.readUInt32BE(1);
|
|
1915
|
-
if (t <
|
|
1924
|
+
if (t < Er) throw Error("encrypted bundle corrupt (short frame)");
|
|
1916
1925
|
if (!await o(5 + t)) throw Error("encrypted bundle truncated (frame body)");
|
|
1917
|
-
let n = r.subarray(5, 5 + t -
|
|
1926
|
+
let n = r.subarray(5, 5 + t - Er), i = r.subarray(5 + t - Er, 5 + t);
|
|
1918
1927
|
r = r.subarray(5 + t);
|
|
1919
|
-
let a = T("aes-256-gcm", p,
|
|
1928
|
+
let a = T("aes-256-gcm", p, jr(f, m, e));
|
|
1920
1929
|
m === 0 && a.setAAD(s), a.setAuthTag(i);
|
|
1921
1930
|
let c = Buffer.concat([a.update(n), a.final()]);
|
|
1922
1931
|
m++, e && (h = !0), c.length > 0 && (yield new Uint8Array(c));
|
|
@@ -1924,7 +1933,7 @@ async function* jr(e, t) {
|
|
|
1924
1933
|
}
|
|
1925
1934
|
//#endregion
|
|
1926
1935
|
//#region src/blobStorage.ts
|
|
1927
|
-
var
|
|
1936
|
+
var Pr = (e, t) => ({
|
|
1928
1937
|
list: () => {
|
|
1929
1938
|
let e = t();
|
|
1930
1939
|
return { async *[Symbol.asyncIterator]() {
|
|
@@ -1937,32 +1946,32 @@ var Mr = (e, t) => ({
|
|
|
1937
1946
|
} };
|
|
1938
1947
|
},
|
|
1939
1948
|
open: (t) => ({ async *[Symbol.asyncIterator]() {
|
|
1940
|
-
let r = await n.runPromise(
|
|
1949
|
+
let r = await n.runPromise(A(e, t)), i = await he(r.stream);
|
|
1941
1950
|
for await (let e of i) yield e instanceof Uint8Array ? e : new Uint8Array(e);
|
|
1942
1951
|
} })
|
|
1943
|
-
}),
|
|
1944
|
-
table:
|
|
1952
|
+
}), Fr = (e, t) => Pr(e, () => C(t, {
|
|
1953
|
+
table: pe,
|
|
1945
1954
|
chunkSize: 500
|
|
1946
1955
|
}).pipe(l.map((e) => ({
|
|
1947
1956
|
key: String(e.key),
|
|
1948
1957
|
contentType: String(e.contentType ?? "application/octet-stream"),
|
|
1949
1958
|
size: Number(e.size ?? 0)
|
|
1950
|
-
})))),
|
|
1959
|
+
})))), Ir = (e) => ({
|
|
1951
1960
|
has: (t) => n.runPromise(e.head(t).pipe(n.map((e) => e !== null))),
|
|
1952
1961
|
write: async (t, r, i) => {
|
|
1953
|
-
let a =
|
|
1962
|
+
let a = me("storage", () => ge.from(r));
|
|
1954
1963
|
await n.runPromise(j(e, t, a, {
|
|
1955
1964
|
contentType: i.contentType,
|
|
1956
1965
|
totalSize: i.size
|
|
1957
1966
|
}));
|
|
1958
1967
|
}
|
|
1959
|
-
}),
|
|
1968
|
+
}), Lr = (e, t) => {
|
|
1960
1969
|
let n = t === "dump" ? "mariadb-dump" : "mariadb", r = t === "dump" ? "mysqldump" : "mysql";
|
|
1961
|
-
return e === "mariadb" ?
|
|
1970
|
+
return e === "mariadb" ? Rr(n) ? { tool: n } : {
|
|
1962
1971
|
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.`
|
|
1972
|
+
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
1973
|
} : { tool: r };
|
|
1965
|
-
},
|
|
1974
|
+
}, Rr = (e) => (process.env.PATH ?? "").split(L).filter((e) => e !== "").some((t) => ue(R(t, e))), zr = (e) => {
|
|
1966
1975
|
switch (e) {
|
|
1967
1976
|
case "postgres": return "db.dump";
|
|
1968
1977
|
case "mysql":
|
|
@@ -1972,7 +1981,7 @@ var Mr = (e, t) => ({
|
|
|
1972
1981
|
case "mssql": return "db.bacpac";
|
|
1973
1982
|
default: return "db.dump";
|
|
1974
1983
|
}
|
|
1975
|
-
},
|
|
1984
|
+
}, Br = (e) => e.filename ?? e.database ?? ((e.url ?? "").replace(/^file:/, "") || "app.sqlite"), $ = (e) => {
|
|
1976
1985
|
if (e.host || e.database) return {
|
|
1977
1986
|
host: e.host ?? "localhost",
|
|
1978
1987
|
port: e.port ?? 3306,
|
|
@@ -1988,7 +1997,7 @@ var Mr = (e, t) => ({
|
|
|
1988
1997
|
password: decodeURIComponent(t.password) || "",
|
|
1989
1998
|
database: t.pathname.replace(/^\//, "") || ""
|
|
1990
1999
|
};
|
|
1991
|
-
},
|
|
2000
|
+
}, Vr = (e) => `Server=${e.host},${e.port};Database=${e.database};User ID=${e.username};Password=${e.password};TrustServerCertificate=True`, Hr = (e, t, n) => {
|
|
1992
2001
|
switch (e) {
|
|
1993
2002
|
case "postgres": {
|
|
1994
2003
|
if (t.url) return {
|
|
@@ -1998,6 +2007,7 @@ var Mr = (e, t) => ({
|
|
|
1998
2007
|
"--format=custom",
|
|
1999
2008
|
"--no-owner",
|
|
2000
2009
|
"--no-privileges",
|
|
2010
|
+
...Wr,
|
|
2001
2011
|
"--dbname",
|
|
2002
2012
|
t.url,
|
|
2003
2013
|
"--file",
|
|
@@ -2016,6 +2026,7 @@ var Mr = (e, t) => ({
|
|
|
2016
2026
|
"--format=custom",
|
|
2017
2027
|
"--no-owner",
|
|
2018
2028
|
"--no-privileges",
|
|
2029
|
+
...Wr,
|
|
2019
2030
|
"-h",
|
|
2020
2031
|
e.host,
|
|
2021
2032
|
"-p",
|
|
@@ -2035,13 +2046,14 @@ var Mr = (e, t) => ({
|
|
|
2035
2046
|
let r = $(t);
|
|
2036
2047
|
return {
|
|
2037
2048
|
kind: "spawn",
|
|
2038
|
-
...
|
|
2049
|
+
...Lr(e, "dump"),
|
|
2039
2050
|
args: [
|
|
2040
2051
|
"--single-transaction",
|
|
2041
2052
|
"--routines",
|
|
2042
2053
|
"--triggers",
|
|
2043
2054
|
"--no-tablespaces",
|
|
2044
2055
|
"--protocol=TCP",
|
|
2056
|
+
...Ur.map((e) => `--ignore-table=${r.database}.${e}`),
|
|
2045
2057
|
"-h",
|
|
2046
2058
|
r.host,
|
|
2047
2059
|
"-P",
|
|
@@ -2057,7 +2069,7 @@ var Mr = (e, t) => ({
|
|
|
2057
2069
|
case "sqlite":
|
|
2058
2070
|
case "turso": return {
|
|
2059
2071
|
kind: "copy",
|
|
2060
|
-
from:
|
|
2072
|
+
from: Br(t),
|
|
2061
2073
|
to: n
|
|
2062
2074
|
};
|
|
2063
2075
|
case "mssql": return {
|
|
@@ -2065,7 +2077,7 @@ var Mr = (e, t) => ({
|
|
|
2065
2077
|
tool: "sqlpackage",
|
|
2066
2078
|
args: [
|
|
2067
2079
|
"/Action:Export",
|
|
2068
|
-
`/SourceConnectionString:${
|
|
2080
|
+
`/SourceConnectionString:${Vr($({
|
|
2069
2081
|
...t,
|
|
2070
2082
|
port: t.port ?? 1433
|
|
2071
2083
|
}))}`,
|
|
@@ -2078,7 +2090,7 @@ var Mr = (e, t) => ({
|
|
|
2078
2090
|
reason: `no native backup for dialect '${e}'`
|
|
2079
2091
|
});
|
|
2080
2092
|
}
|
|
2081
|
-
},
|
|
2093
|
+
}, Ur = [d, u], Wr = Ur.flatMap((e) => ["--exclude-table", e]), Gr = (e, t, n) => {
|
|
2082
2094
|
switch (e) {
|
|
2083
2095
|
case "postgres": {
|
|
2084
2096
|
if (t.url) return {
|
|
@@ -2123,7 +2135,7 @@ var Mr = (e, t) => ({
|
|
|
2123
2135
|
let r = $(t);
|
|
2124
2136
|
return {
|
|
2125
2137
|
kind: "spawn",
|
|
2126
|
-
...
|
|
2138
|
+
...Lr(e, "client"),
|
|
2127
2139
|
args: [
|
|
2128
2140
|
"--protocol=TCP",
|
|
2129
2141
|
"-h",
|
|
@@ -2142,14 +2154,14 @@ var Mr = (e, t) => ({
|
|
|
2142
2154
|
case "turso": return {
|
|
2143
2155
|
kind: "copy",
|
|
2144
2156
|
from: n,
|
|
2145
|
-
to:
|
|
2157
|
+
to: Br(t)
|
|
2146
2158
|
};
|
|
2147
2159
|
case "mssql": return {
|
|
2148
2160
|
kind: "spawn",
|
|
2149
2161
|
tool: "sqlpackage",
|
|
2150
2162
|
args: [
|
|
2151
2163
|
"/Action:Import",
|
|
2152
|
-
`/TargetConnectionString:${
|
|
2164
|
+
`/TargetConnectionString:${Vr($({
|
|
2153
2165
|
...t,
|
|
2154
2166
|
port: t.port ?? 1433
|
|
2155
2167
|
}))}`,
|
|
@@ -2162,10 +2174,10 @@ var Mr = (e, t) => ({
|
|
|
2162
2174
|
reason: `no native restore for dialect '${e}'`
|
|
2163
2175
|
});
|
|
2164
2176
|
}
|
|
2165
|
-
},
|
|
2177
|
+
}, Kr = (e) => e.kind === "copy" ? n.async((t) => {
|
|
2166
2178
|
let r = `${e.to}.restoring-${oe()}`, i = (e) => {
|
|
2167
2179
|
try {
|
|
2168
|
-
|
|
2180
|
+
k(r);
|
|
2169
2181
|
} catch {}
|
|
2170
2182
|
t(n.fail(new W({
|
|
2171
2183
|
tool: "copy",
|
|
@@ -2177,7 +2189,7 @@ var Mr = (e, t) => ({
|
|
|
2177
2189
|
i(`copy ${e.from} → ${e.to}: ${a.message}`);
|
|
2178
2190
|
return;
|
|
2179
2191
|
}
|
|
2180
|
-
|
|
2192
|
+
de(r, e.to, (r) => {
|
|
2181
2193
|
if (r) {
|
|
2182
2194
|
i(`copy ${e.from} → ${e.to}: ${r.message}`);
|
|
2183
2195
|
return;
|
|
@@ -2186,7 +2198,7 @@ var Mr = (e, t) => ({
|
|
|
2186
2198
|
});
|
|
2187
2199
|
});
|
|
2188
2200
|
}) : n.async((t) => {
|
|
2189
|
-
let r =
|
|
2201
|
+
let r = Ce(e.tool, [...e.args], {
|
|
2190
2202
|
env: {
|
|
2191
2203
|
...process.env,
|
|
2192
2204
|
...e.env
|
|
@@ -2199,35 +2211,63 @@ var Mr = (e, t) => ({
|
|
|
2199
2211
|
}), i = "";
|
|
2200
2212
|
r.stderr?.on("data", (e) => {
|
|
2201
2213
|
i += String(e);
|
|
2202
|
-
})
|
|
2203
|
-
let a = () => {
|
|
2214
|
+
});
|
|
2215
|
+
let a = !1, o = (e) => {
|
|
2216
|
+
a || (a = !0, t(e));
|
|
2217
|
+
}, s, c = (e) => {
|
|
2218
|
+
s ??= e;
|
|
2219
|
+
};
|
|
2220
|
+
if (e.stdoutFile && r.stdout) {
|
|
2221
|
+
let t = O(e.stdoutFile);
|
|
2222
|
+
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);
|
|
2223
|
+
}
|
|
2224
|
+
let l = 0;
|
|
2225
|
+
if (e.stdinFile && r.stdin) {
|
|
2226
|
+
let t = le(e.stdinFile);
|
|
2227
|
+
t.on("data", (e) => {
|
|
2228
|
+
l += e.length;
|
|
2229
|
+
}), t.on("error", (t) => {
|
|
2230
|
+
c(`reading ${I(e.stdinFile)}: ${t.message}`), r.stdin?.end();
|
|
2231
|
+
}), r.stdin.on("error", (t) => {
|
|
2232
|
+
t.code !== "EPIPE" && c(`feeding ${I(e.stdinFile)} to ${e.tool}: ${t.message}`);
|
|
2233
|
+
}), t.pipe(r.stdin);
|
|
2234
|
+
}
|
|
2235
|
+
let u = () => {
|
|
2204
2236
|
if (e.stdoutFile !== void 0) try {
|
|
2205
|
-
|
|
2237
|
+
k(e.stdoutFile);
|
|
2206
2238
|
} catch {}
|
|
2207
2239
|
};
|
|
2208
|
-
r.on("error", (
|
|
2209
|
-
|
|
2240
|
+
r.on("error", (t) => {
|
|
2241
|
+
u(), o(n.fail(new W({
|
|
2210
2242
|
tool: e.tool,
|
|
2211
|
-
reason: `failed to launch (is '${e.tool}' installed + on PATH?): ${
|
|
2243
|
+
reason: `failed to launch (is '${e.tool}' installed + on PATH?): ${t.message}`,
|
|
2212
2244
|
...e.hint === void 0 ? {} : { hint: e.hint }
|
|
2213
2245
|
})));
|
|
2214
|
-
}), r.on("close", (
|
|
2215
|
-
if (
|
|
2216
|
-
|
|
2246
|
+
}), r.on("close", (t) => {
|
|
2247
|
+
if (t === 0 && s === void 0) {
|
|
2248
|
+
o(n.void);
|
|
2217
2249
|
return;
|
|
2218
2250
|
}
|
|
2219
|
-
|
|
2251
|
+
u();
|
|
2252
|
+
let r = e.stdinFile === void 0 ? "" : ` — ${l} of ${qr(e.stdinFile)} byte(s) of ${I(e.stdinFile)} had been fed to it`;
|
|
2253
|
+
o(n.fail(new W({
|
|
2220
2254
|
tool: e.tool,
|
|
2221
|
-
reason: `exited with code ${
|
|
2222
|
-
stderr: i.slice(-2e3),
|
|
2255
|
+
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`),
|
|
2256
|
+
stderr: i.trim() === "" ? `(${e.tool} printed nothing to stderr)` : i.slice(-2e3),
|
|
2223
2257
|
...e.hint === void 0 ? {} : { hint: e.hint }
|
|
2224
2258
|
})));
|
|
2225
2259
|
});
|
|
2226
|
-
}),
|
|
2227
|
-
|
|
2260
|
+
}), qr = (e) => {
|
|
2261
|
+
try {
|
|
2262
|
+
return String(fe(e).size);
|
|
2263
|
+
} catch {
|
|
2264
|
+
return "?";
|
|
2265
|
+
}
|
|
2266
|
+
}, Jr = (e) => typeof e == "object" && e ? "fake" in e ? `fake:${e.fake}` : "custom" : String(e), Yr = (e) => n.gen(function* () {
|
|
2267
|
+
let t = yield* at(e.scope ?? { kind: "all" }, e.snapshot, {
|
|
2228
2268
|
store: e.store,
|
|
2229
2269
|
...e.tenantTables ? { tenantTables: e.tenantTables } : {}
|
|
2230
|
-
}), r =
|
|
2270
|
+
}), r = tn(t.tables, e.snapshot), i = e.classification ?? Ee(e.snapshot), a = e.sampleSize ?? 20, o = ze(r.map((t) => ({
|
|
2231
2271
|
name: t,
|
|
2232
2272
|
columns: (e.snapshot.tables.find((e) => e.name === t)?.columns ?? []).map((e) => ({
|
|
2233
2273
|
name: e.name,
|
|
@@ -2235,19 +2275,19 @@ var Mr = (e, t) => ({
|
|
|
2235
2275
|
}))
|
|
2236
2276
|
})), i, e.masking), s = [], c = [];
|
|
2237
2277
|
for (let i of r) {
|
|
2238
|
-
let r = t.predicateFor(i), u = yield*
|
|
2278
|
+
let r = t.predicateFor(i), u = yield* C(e.store, {
|
|
2239
2279
|
table: i,
|
|
2240
2280
|
chunkSize: a,
|
|
2241
2281
|
...r === void 0 ? {} : { where: r }
|
|
2242
|
-
}).pipe(l.take(a), l.runCollect, n.map((e) => [...e])), d = u.map((t) =>
|
|
2243
|
-
c.push(...
|
|
2282
|
+
}).pipe(l.take(a), l.runCollect, n.map((e) => [...e])), d = u.map((t) => He(t, i, o.actions, e.masking.seed));
|
|
2283
|
+
c.push(...Ve(d, i, o.actions));
|
|
2244
2284
|
let f = u[0], p = d[0], m = [];
|
|
2245
2285
|
if (f && p) for (let [e, t] of Object.entries(o.actions)) {
|
|
2246
2286
|
if (!e.startsWith(`${i}.`) || t === "keep") continue;
|
|
2247
2287
|
let n = e.slice(i.length + 1);
|
|
2248
2288
|
m.push({
|
|
2249
2289
|
column: n,
|
|
2250
|
-
action:
|
|
2290
|
+
action: Jr(t),
|
|
2251
2291
|
before: f[n],
|
|
2252
2292
|
after: p[n]
|
|
2253
2293
|
});
|
|
@@ -2262,7 +2302,7 @@ var Mr = (e, t) => ({
|
|
|
2262
2302
|
leaks: c,
|
|
2263
2303
|
unclassified: o.unclassified
|
|
2264
2304
|
};
|
|
2265
|
-
}),
|
|
2305
|
+
}), Xr = (e, t) => {
|
|
2266
2306
|
let n = new Map(t.map((e) => [e.name, e])), r = [], i = {};
|
|
2267
2307
|
for (let t of e) {
|
|
2268
2308
|
let e = n.get(t.name);
|
|
@@ -2317,7 +2357,7 @@ var Mr = (e, t) => ({
|
|
|
2317
2357
|
skipColumns: i,
|
|
2318
2358
|
refuse: r.some((e) => e.verdict === "refuse")
|
|
2319
2359
|
};
|
|
2320
|
-
},
|
|
2360
|
+
}, Zr = (e) => {
|
|
2321
2361
|
if (e.findings.length === 0) return [" schema matches the bundle"];
|
|
2322
2362
|
let t = {
|
|
2323
2363
|
safe: "✓",
|
|
@@ -2328,4 +2368,4 @@ var Mr = (e, t) => ({
|
|
|
2328
2368
|
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
2369
|
};
|
|
2330
2370
|
//#endregion
|
|
2331
|
-
export {
|
|
2371
|
+
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, Ur as EXCLUDED_FROM_DUMP, 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, Xr 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, Zr 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, Yr as previewMasking, pt as readAssetIndex, zt as readLedger, De as resolveAction, at as resolveScope, lt as restoreAssetFromCas, mt as restoreAssetsFromCas, Gr as restoreCommand, $t as rowsToNdjson, pn as runExport, ir as runImport, Kr 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 };
|