@voltro/data-transfer 0.40.0 → 0.41.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 +74 -0
- package/dist/index.js +279 -252
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -56,7 +56,7 @@ var ge = (e) => {
|
|
|
56
56
|
return r.classes?.[e] ?? _e[e] ?? "redact";
|
|
57
57
|
}
|
|
58
58
|
return n?.safe ? r.onSafe ?? "keep" : n?.columnType === "id" || n?.columnType === "reference" ? "keep" : r.onUnclassified ?? "error";
|
|
59
|
-
},
|
|
59
|
+
}, be = (e, t) => v("sha256", e).update(t == null ? "∅" : String(t)).digest(), k = (e, t) => e.readUInt32BE(t * 4 % (e.length - 4)), A = [
|
|
60
60
|
"Ada",
|
|
61
61
|
"Alan",
|
|
62
62
|
"Grace",
|
|
@@ -69,7 +69,7 @@ var ge = (e) => {
|
|
|
69
69
|
"Guido",
|
|
70
70
|
"Margaret",
|
|
71
71
|
"Bjarne"
|
|
72
|
-
],
|
|
72
|
+
], xe = [
|
|
73
73
|
"Lovelace",
|
|
74
74
|
"Turing",
|
|
75
75
|
"Hopper",
|
|
@@ -82,7 +82,7 @@ var ge = (e) => {
|
|
|
82
82
|
"Rossum",
|
|
83
83
|
"Hamilton",
|
|
84
84
|
"Stroustrup"
|
|
85
|
-
],
|
|
85
|
+
], Se = [
|
|
86
86
|
"Maple",
|
|
87
87
|
"Oak",
|
|
88
88
|
"Cedar",
|
|
@@ -91,7 +91,7 @@ var ge = (e) => {
|
|
|
91
91
|
"Birch",
|
|
92
92
|
"Willow",
|
|
93
93
|
"Ash"
|
|
94
|
-
],
|
|
94
|
+
], Ce = [
|
|
95
95
|
"Initech",
|
|
96
96
|
"Hooli",
|
|
97
97
|
"Umbrella",
|
|
@@ -100,23 +100,23 @@ var ge = (e) => {
|
|
|
100
100
|
"Soylent",
|
|
101
101
|
"Stark",
|
|
102
102
|
"Wayne"
|
|
103
|
-
],
|
|
104
|
-
let r =
|
|
103
|
+
], j = (e, t, n) => e[k(t, n) % e.length], we = (e, t, n) => {
|
|
104
|
+
let r = be(n, `${e}:${String(t)}`), i = k(r, 1) % 1e4;
|
|
105
105
|
switch (e) {
|
|
106
|
-
case "email": return `${
|
|
107
|
-
case "fullName": return `${
|
|
108
|
-
case "firstName": return
|
|
109
|
-
case "lastName": return
|
|
110
|
-
case "username": return `${
|
|
111
|
-
case "phone": return `+1${String(
|
|
112
|
-
case "address": return `${
|
|
113
|
-
case "company": return
|
|
106
|
+
case "email": return `${j(A, r, 0).toLowerCase()}.${j(xe, r, 2).toLowerCase()}${i}@example.com`;
|
|
107
|
+
case "fullName": return `${j(A, r, 0)} ${j(xe, r, 1)}`;
|
|
108
|
+
case "firstName": return j(A, r, 0);
|
|
109
|
+
case "lastName": return j(xe, r, 1);
|
|
110
|
+
case "username": return `${j(A, r, 0).toLowerCase()}${i}`;
|
|
111
|
+
case "phone": return `+1${String(k(r, 0) % 1e10).padStart(10, "0")}`;
|
|
112
|
+
case "address": return `${k(r, 0) % 9899 + 100} ${j(Se, r, 1)} St`;
|
|
113
|
+
case "company": return j(Ce, r, 0);
|
|
114
114
|
case "url": return `https://example.com/${r.toString("hex").slice(0, 12)}`;
|
|
115
|
-
case "ip": return `${
|
|
116
|
-
case "creditCard": return
|
|
115
|
+
case "ip": return `${k(r, 0) % 256}.${k(r, 1) % 256}.${k(r, 2) % 256}.${k(r, 3) % 254 + 1}`;
|
|
116
|
+
case "creditCard": return Te(`4${r.toString("hex").replace(/\D/g, "").padEnd(14, "0").slice(0, 14)}`);
|
|
117
117
|
default: return `${e}_${r.toString("hex").slice(0, 8)}`;
|
|
118
118
|
}
|
|
119
|
-
},
|
|
119
|
+
}, Te = (e) => {
|
|
120
120
|
let t = e.slice(0, 15).split("").map(Number), n = 0;
|
|
121
121
|
t.forEach((e, t) => {
|
|
122
122
|
let r = e;
|
|
@@ -124,16 +124,16 @@ var ge = (e) => {
|
|
|
124
124
|
});
|
|
125
125
|
let r = (10 - n % 10) % 10;
|
|
126
126
|
return e.slice(0, 15) + String(r);
|
|
127
|
-
},
|
|
127
|
+
}, Ee = 864e5, De = (e, t) => {
|
|
128
128
|
let n = e instanceof Date ? e.getTime() : Date.parse(String(e));
|
|
129
129
|
if (Number.isNaN(n)) return e;
|
|
130
|
-
let r =
|
|
130
|
+
let r = k(be(t, "date-shift-offset"), 0) % 730 - 365, i = new Date(n + r * Ee);
|
|
131
131
|
return e instanceof Date ? i : i.toISOString();
|
|
132
|
-
},
|
|
132
|
+
}, Oe = (e, t) => {
|
|
133
133
|
if (t.value === null || t.value === void 0) return null;
|
|
134
134
|
if (e === "error") throw Error(`masking: unresolved 'error' action for ${t.table}.${t.column}`);
|
|
135
|
-
return e === "keep" ? t.value : e === "null" ? null : e === "redact" ? t.columnType === "text" || typeof t.value == "string" ? "[redacted]" : null : e === "hash" ?
|
|
136
|
-
},
|
|
135
|
+
return e === "keep" ? t.value : e === "null" ? null : e === "redact" ? t.columnType === "text" || typeof t.value == "string" ? "[redacted]" : null : e === "hash" ? be(t.seed, t.value).toString("hex").slice(0, 16) : e === "dateShift" ? De(t.value, t.seed) : typeof e == "object" && "fake" in e ? we(e.fake, t.value, t.seed) : typeof e == "object" && "custom" in e ? e.custom(t) : t.value;
|
|
136
|
+
}, M = (e, t, n) => {
|
|
137
137
|
let r = {}, i = [];
|
|
138
138
|
for (let a of e) for (let e of a.columns) {
|
|
139
139
|
let o = `${a.name}.${e.name}`, s = ye(a.name, e.name, t[a.name]?.[e.name], n);
|
|
@@ -143,7 +143,7 @@ var ge = (e) => {
|
|
|
143
143
|
actions: r,
|
|
144
144
|
unclassified: i
|
|
145
145
|
};
|
|
146
|
-
},
|
|
146
|
+
}, ke = [
|
|
147
147
|
{
|
|
148
148
|
name: "email",
|
|
149
149
|
re: /[\w.+-]+@[\w-]+\.[\w.-]+/
|
|
@@ -160,7 +160,7 @@ var ge = (e) => {
|
|
|
160
160
|
name: "creditCard",
|
|
161
161
|
re: /\b(?:\d[ -]?){13,16}\b/
|
|
162
162
|
}
|
|
163
|
-
],
|
|
163
|
+
], Ae = (e, t, n) => {
|
|
164
164
|
let r = [], i = /* @__PURE__ */ new Set();
|
|
165
165
|
for (let [a, o] of Object.entries(n)) {
|
|
166
166
|
if (!a.startsWith(`${t}.`) || o !== "keep") continue;
|
|
@@ -168,7 +168,7 @@ var ge = (e) => {
|
|
|
168
168
|
for (let a of e) {
|
|
169
169
|
let e = a[n];
|
|
170
170
|
if (typeof e != "string" || e.length === 0) continue;
|
|
171
|
-
let o =
|
|
171
|
+
let o = ke.find((t) => t.re.test(e));
|
|
172
172
|
if (o && !i.has(n)) {
|
|
173
173
|
i.add(n), r.push({
|
|
174
174
|
table: t,
|
|
@@ -181,9 +181,9 @@ var ge = (e) => {
|
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
183
|
return r;
|
|
184
|
-
},
|
|
184
|
+
}, N = (e, t, n, r, i) => {
|
|
185
185
|
let a = {};
|
|
186
|
-
for (let [o, s] of Object.entries(e)) a[o] =
|
|
186
|
+
for (let [o, s] of Object.entries(e)) a[o] = Oe(n[`${t}.${o}`] ?? "keep", {
|
|
187
187
|
value: s,
|
|
188
188
|
table: t,
|
|
189
189
|
column: o,
|
|
@@ -191,17 +191,17 @@ var ge = (e) => {
|
|
|
191
191
|
...i?.[o] ? { columnType: i[o] } : {}
|
|
192
192
|
});
|
|
193
193
|
return a;
|
|
194
|
-
},
|
|
194
|
+
}, P = class extends s.TaggedError()("BundleError", {
|
|
195
195
|
reason: s.String,
|
|
196
196
|
path: s.optional(s.String)
|
|
197
|
-
}) {},
|
|
197
|
+
}) {}, je = class extends s.TaggedError()("CodecError", {
|
|
198
198
|
table: s.String,
|
|
199
199
|
reason: s.String
|
|
200
|
-
}) {},
|
|
200
|
+
}) {}, F = class extends s.TaggedError()("IntegrityError", {
|
|
201
201
|
what: s.String,
|
|
202
202
|
expected: s.String,
|
|
203
203
|
actual: s.String
|
|
204
|
-
}) {},
|
|
204
|
+
}) {}, Me = class extends t.TaggedError("CompressionError") {}, I = class extends s.TaggedError()("ScopeError", { reason: s.String }) {}, Ne = class extends s.TaggedError()("DanglingReferenceError", {
|
|
205
205
|
rows: s.Array(s.Struct({
|
|
206
206
|
table: s.String,
|
|
207
207
|
id: s.String,
|
|
@@ -286,23 +286,25 @@ var ge = (e) => {
|
|
|
286
286
|
let r = e.get(n);
|
|
287
287
|
return r ? u(R(t, n), [...r]) : void 0;
|
|
288
288
|
}
|
|
289
|
-
}), B = "tenantId",
|
|
289
|
+
}), B = "tenantId", V = (e, t, r) => n.gen(function* () {
|
|
290
290
|
let i = t.tables.map((e) => e.name), a = new Map(t.tables.map((e) => [e.name, e]));
|
|
291
291
|
if (e.kind === "all") return {
|
|
292
292
|
tables: i,
|
|
293
293
|
predicateFor: () => void 0
|
|
294
294
|
};
|
|
295
295
|
if (e.kind === "tables") {
|
|
296
|
-
let t =
|
|
296
|
+
let t = e.tables ?? [], r = new Set(i), a = t.filter((e) => !r.has(e));
|
|
297
|
+
if (a.length > 0) return yield* n.fail(new I({ reason: `scope { kind: 'tables' } names ${a.length} table(s) that are not in the schema: ${a.join(", ")}. Refusing to write a bundle that silently omits them. Known tables: ${i.length}.` }));
|
|
298
|
+
let o = new Set(t);
|
|
297
299
|
return {
|
|
298
|
-
tables: i.filter((e) =>
|
|
300
|
+
tables: i.filter((e) => o.has(e)),
|
|
299
301
|
predicateFor: () => void 0
|
|
300
302
|
};
|
|
301
303
|
}
|
|
302
304
|
let o = e.tenantId;
|
|
303
|
-
if (o === void 0 || o === "") return yield* n.fail(new
|
|
305
|
+
if (o === void 0 || o === "") return yield* n.fail(new I({ reason: "scope { kind: 'tenant' } requires a tenantId — pass --tenant <id> (CLI) or scope.tenantId (API). Refusing to fall back to an unfiltered export." }));
|
|
304
306
|
let s = r.tenantTables ? r.tenantTables.filter((e) => a.has(e)) : i.filter((e) => a.get(e)?.columns.some((e) => e.name === B) ?? !1);
|
|
305
|
-
if (s.length === 0) return yield* n.fail(new
|
|
307
|
+
if (s.length === 0) return yield* n.fail(new I({ reason: r.tenantTables ? "tenant scope: none of the provided tenantTables exist in the schema — nothing to filter." : `tenant scope: no table carries a '${B}' column — nothing to filter. A tenant export of a schema without tenant-scoped tables would be the full database; refusing.` }));
|
|
306
308
|
let c = yield* z(r.store, t, {
|
|
307
309
|
seeds: Object.fromEntries(s.map((e) => [e, l(B, o)])),
|
|
308
310
|
pinned: s,
|
|
@@ -312,13 +314,13 @@ var ge = (e) => {
|
|
|
312
314
|
tables: [...s, ...d],
|
|
313
315
|
predicateFor: (e) => f.has(e) ? l(B, o) : c.has(e) ? u(R(t, e), [...c.get(e)]) : void 0
|
|
314
316
|
};
|
|
315
|
-
}),
|
|
317
|
+
}), Be = (e, t) => ({
|
|
316
318
|
list: t,
|
|
317
319
|
open: (t) => C(e, t)
|
|
318
|
-
}),
|
|
320
|
+
}), Ve = (e) => ({
|
|
319
321
|
write: (t, n, r) => ee(e, t, n, r),
|
|
320
322
|
has: (t) => e.head(t).pipe(n.map((e) => e !== null))
|
|
321
|
-
}),
|
|
323
|
+
}), He = (e, t) => n.tryPromise({
|
|
322
324
|
try: async () => {
|
|
323
325
|
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) {
|
|
324
326
|
u.update(e), d += e.length, n(null, e);
|
|
@@ -336,23 +338,23 @@ var ge = (e) => {
|
|
|
336
338
|
contentType: e.contentType
|
|
337
339
|
};
|
|
338
340
|
},
|
|
339
|
-
catch: (e) => new
|
|
341
|
+
catch: (e) => new P({
|
|
340
342
|
reason: `asset write failed: ${String(e?.message ?? e)}`,
|
|
341
343
|
path: t
|
|
342
344
|
})
|
|
343
|
-
}),
|
|
345
|
+
}), Ue = (e, t, r) => n.gen(function* () {
|
|
344
346
|
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), l = o("sha256"), u = S("bundle", () => a(s)).pipe(c.tap((e) => n.sync(() => l.update(e))));
|
|
345
347
|
yield* e.write(r.key, u, {
|
|
346
348
|
contentType: r.contentType,
|
|
347
349
|
totalSize: r.size
|
|
348
350
|
});
|
|
349
351
|
let d = l.digest("hex");
|
|
350
|
-
if (d !== r.sha256) return yield* n.fail(new
|
|
352
|
+
if (d !== r.sha256) return yield* n.fail(new F({
|
|
351
353
|
what: `asset ${r.key}`,
|
|
352
354
|
expected: r.sha256,
|
|
353
355
|
actual: d
|
|
354
356
|
}));
|
|
355
|
-
}),
|
|
357
|
+
}), We = () => typeof w.createZstdCompress == "function", Ge = (e) => e === "none" ? "none" : e === "gzip" ? "gzip" : We() ? "zstd" : "gzip", Ke = (e) => e === "zstd" ? ".zst" : e === "gzip" ? ".gz" : "", qe = (e) => e === "zstd" ? w.createZstdCompress() : e === "gzip" ? w.createGzip() : new T(), Je = (e) => e === "zstd" ? w.createZstdDecompress() : e === "gzip" ? w.createGunzip() : new T(), Ye = 1, Xe = s.Struct({
|
|
356
358
|
name: s.String,
|
|
357
359
|
file: s.String,
|
|
358
360
|
rowCount: s.Number,
|
|
@@ -362,11 +364,11 @@ var ge = (e) => {
|
|
|
362
364
|
value: s.String
|
|
363
365
|
}),
|
|
364
366
|
primaryKey: s.String
|
|
365
|
-
}),
|
|
367
|
+
}), Ze = s.Struct({
|
|
366
368
|
kind: s.Literal("all", "tenant", "tables"),
|
|
367
369
|
tenantId: s.optional(s.String),
|
|
368
370
|
tables: s.optional(s.Array(s.String))
|
|
369
|
-
}),
|
|
371
|
+
}), Qe = s.Struct({
|
|
370
372
|
count: s.Number,
|
|
371
373
|
totalBytes: s.Number,
|
|
372
374
|
index: s.optional(s.String)
|
|
@@ -377,23 +379,23 @@ s.Struct({
|
|
|
377
379
|
size: s.Number,
|
|
378
380
|
contentType: s.String
|
|
379
381
|
});
|
|
380
|
-
var
|
|
382
|
+
var $e = s.Struct({
|
|
381
383
|
formatVersion: s.Number,
|
|
382
384
|
createdAt: s.String,
|
|
383
385
|
source: s.Struct({
|
|
384
386
|
dialect: s.String,
|
|
385
387
|
schemaFingerprint: s.String
|
|
386
388
|
}),
|
|
387
|
-
scope:
|
|
389
|
+
scope: Ze,
|
|
388
390
|
consistency: s.Literal("live", "snapshot"),
|
|
389
391
|
compression: s.Literal("zstd", "gzip", "none"),
|
|
390
|
-
tables: s.Array(
|
|
391
|
-
assets:
|
|
392
|
+
tables: s.Array(Xe),
|
|
393
|
+
assets: Qe,
|
|
392
394
|
masking: s.optional(s.Struct({
|
|
393
395
|
policyId: s.optional(s.String),
|
|
394
396
|
transformed: s.Array(s.String)
|
|
395
397
|
}))
|
|
396
|
-
}),
|
|
398
|
+
}), et = s.encodeSync(s.parseJson($e)), tt = s.decodeUnknownSync(s.parseJson($e)), H = "manifest.json", nt = "README.md", U = "data", W = "assets", G = "assets/index.ndjson", rt = ".ledger.json", it = (e) => e.kind === "tenant" ? `tenant \`${e.tenantId}\`` : e.kind === "tables" ? `tables \`${(e.tables ?? []).join(", ")}\`` : "all tables", at = (e, t) => {
|
|
397
399
|
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");
|
|
398
400
|
return `# Voltro data export
|
|
399
401
|
|
|
@@ -407,7 +409,7 @@ The machine-readable manifest is \`manifest.json\`; this file is a human summary
|
|
|
407
409
|
| **Format version** | ${e.formatVersion} |
|
|
408
410
|
| **Consistency** | ${e.consistency} |
|
|
409
411
|
| **Compression** | ${e.compression} |
|
|
410
|
-
| **Scope** | ${
|
|
412
|
+
| **Scope** | ${it(e.scope)} |
|
|
411
413
|
| **Tables** | ${e.tables.length} |
|
|
412
414
|
| **Rows (total)** | ${n} |
|
|
413
415
|
| **Assets** | ${a} |
|
|
@@ -432,39 +434,39 @@ voltro data import <this-directory>
|
|
|
432
434
|
voltro data import <this-directory> --target api --api-url <url> --token <secret>
|
|
433
435
|
\`\`\`
|
|
434
436
|
`;
|
|
435
|
-
},
|
|
437
|
+
}, ot = i.counter("voltro_data_transfer_rows", { description: "Rows exported/imported by @voltro/data-transfer, tagged by phase + table." }), st = a.exponential({
|
|
436
438
|
start: .01,
|
|
437
439
|
factor: 2,
|
|
438
440
|
count: 16
|
|
439
|
-
}),
|
|
441
|
+
}), ct = i.histogram("voltro_data_transfer_table_seconds", st, "Per-table export/import duration in seconds, tagged by phase."), K = (e, t) => {
|
|
440
442
|
if (e) try {
|
|
441
443
|
e(t);
|
|
442
444
|
} catch {}
|
|
443
|
-
},
|
|
445
|
+
}, 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(ct.pipe(i.tagged("phase", e), i.update((s - r) / 1e3)), ot.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: {
|
|
444
446
|
table: t,
|
|
445
447
|
index: r,
|
|
446
448
|
tableCount: a,
|
|
447
449
|
phase: e
|
|
448
|
-
} })),
|
|
450
|
+
} })), ut = () => ({
|
|
449
451
|
tables: {},
|
|
450
452
|
assets: {}
|
|
451
|
-
}),
|
|
453
|
+
}), dt = (e) => n.tryPromise(async () => {
|
|
452
454
|
let t = await (await import("node:fs/promises")).readFile(e, "utf8");
|
|
453
455
|
return JSON.parse(t);
|
|
454
|
-
}).pipe(n.orElseSucceed(
|
|
456
|
+
}).pipe(n.orElseSucceed(ut)), q = (e, t) => n.tryPromise({
|
|
455
457
|
try: async () => {
|
|
456
458
|
let n = await import("node:fs/promises"), { randomUUID: r } = await import("node:crypto"), i = `${e}.tmp-${r()}`;
|
|
457
459
|
await n.writeFile(i, JSON.stringify(t)), await n.rename(i, e);
|
|
458
460
|
},
|
|
459
|
-
catch: (t) => new
|
|
461
|
+
catch: (t) => new P({
|
|
460
462
|
reason: `ledger write failed: ${String(t?.message ?? t)}`,
|
|
461
463
|
path: e
|
|
462
464
|
})
|
|
463
|
-
}),
|
|
465
|
+
}), ft = (e, t) => t in e.tables, pt = (e, t) => t in e.assets, mt = /* @__PURE__ */ new Set([
|
|
464
466
|
"json",
|
|
465
467
|
"array",
|
|
466
468
|
"vector"
|
|
467
|
-
]),
|
|
469
|
+
]), ht = (e) => typeof e == "object" && !!e && !Array.isArray(e) && typeof e.$v == "string", gt = (e) => Buffer.from(e).toString("base64"), _t = (e) => new Uint8Array(Buffer.from(e, "base64")), vt = (e) => e instanceof Date ? e.toISOString() : typeof e == "number" ? new Date(e).toISOString() : String(e), yt = (e, t) => e == null ? null : t !== void 0 && mt.has(t) ? e : t === "bytes" ? gt(e) : t === "timestamp" || t === "date" ? vt(e) : typeof e == "bigint" ? {
|
|
468
470
|
$v: "bigint",
|
|
469
471
|
d: e.toString()
|
|
470
472
|
} : typeof e == "number" && !Number.isFinite(e) ? {
|
|
@@ -475,30 +477,30 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
475
477
|
d: e.toISOString()
|
|
476
478
|
} : e instanceof Uint8Array ? {
|
|
477
479
|
$v: "bytes",
|
|
478
|
-
d:
|
|
479
|
-
} : e,
|
|
480
|
+
d: gt(e)
|
|
481
|
+
} : e, bt = (e) => {
|
|
480
482
|
switch (e.$v) {
|
|
481
483
|
case "bigint": return BigInt(e.d);
|
|
482
484
|
case "number": return Number(e.d);
|
|
483
485
|
case "date": return new Date(e.d);
|
|
484
|
-
case "bytes": return
|
|
486
|
+
case "bytes": return _t(e.d);
|
|
485
487
|
default: return e;
|
|
486
488
|
}
|
|
487
|
-
},
|
|
489
|
+
}, xt = (e, t) => e == null ? null : t !== void 0 && mt.has(t) ? e : ht(e) ? bt(e) : t === "bytes" ? _t(e) : t === "timestamp" || t === "date" ? new Date(e) : e, St = (e, t) => {
|
|
488
490
|
let n = {};
|
|
489
|
-
for (let [r, i] of Object.entries(e)) n[r] =
|
|
491
|
+
for (let [r, i] of Object.entries(e)) n[r] = yt(i, t[r]);
|
|
490
492
|
return n;
|
|
491
|
-
},
|
|
493
|
+
}, Ct = (e, t) => {
|
|
492
494
|
let n = {};
|
|
493
|
-
for (let [r, i] of Object.entries(e)) n[r] =
|
|
495
|
+
for (let [r, i] of Object.entries(e)) n[r] = xt(i, t[r]);
|
|
494
496
|
return n;
|
|
495
|
-
},
|
|
496
|
-
try: () =>
|
|
497
|
-
catch: (e) => new
|
|
497
|
+
}, wt = new TextEncoder(), Tt = (e, t) => e.pipe(c.map((e) => wt.encode(`${JSON.stringify(St(e, t))}\n`))), Et = (e, t, r) => e.pipe(c.decodeText(), c.splitLines, c.filter((e) => e.trim().length > 0), c.mapEffect((e) => n.try({
|
|
498
|
+
try: () => Ct(JSON.parse(e), r),
|
|
499
|
+
catch: (e) => new je({
|
|
498
500
|
table: t,
|
|
499
501
|
reason: String(e?.message ?? e)
|
|
500
502
|
})
|
|
501
|
-
}))),
|
|
503
|
+
}))), Dt = (e, t) => {
|
|
502
504
|
let n = new Set(e), r = /* @__PURE__ */ new Map();
|
|
503
505
|
for (let e of t.tables) {
|
|
504
506
|
if (!n.has(e.name)) continue;
|
|
@@ -518,11 +520,34 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
518
520
|
};
|
|
519
521
|
for (let t of e) n.has(t) && s(t);
|
|
520
522
|
return i;
|
|
521
|
-
},
|
|
523
|
+
}, J = (e) => {
|
|
524
|
+
let t = e, n = [];
|
|
525
|
+
typeof t?._tag == "string" && t._tag !== "" && n.push(t._tag);
|
|
526
|
+
let r = typeof t?.message == "string" ? t.message.trim() : "";
|
|
527
|
+
if (r === "" ? t?.cause !== void 0 && t.cause !== null && n.push(J(t.cause)) : n.push(r), n.length === 0) {
|
|
528
|
+
let t = String(e ?? "").trim();
|
|
529
|
+
return t === "" || t === "[object Object]" ? Ot(e) : t;
|
|
530
|
+
}
|
|
531
|
+
return n.join(": ");
|
|
532
|
+
}, Ot = (e) => {
|
|
533
|
+
try {
|
|
534
|
+
let t = JSON.stringify(e);
|
|
535
|
+
return t === void 0 || t === "{}" ? "unknown error (no message, cause or tag)" : t;
|
|
536
|
+
} catch {
|
|
537
|
+
return "unknown error (not serialisable)";
|
|
538
|
+
}
|
|
539
|
+
}, kt = (e, t) => {
|
|
522
540
|
let n = e.tables.find((e) => e.name === t), r = {};
|
|
523
541
|
for (let e of n?.columns ?? []) r[e.name] = e.type;
|
|
524
542
|
return r;
|
|
525
|
-
},
|
|
543
|
+
}, At = (e, t) => {
|
|
544
|
+
let n = e.tables.find((e) => e.name === t);
|
|
545
|
+
if (n === void 0) return { refusal: `${t}: not in the schema snapshot, so its primary key is unknown.` };
|
|
546
|
+
let r = n.columns.find((e) => e.type === "id");
|
|
547
|
+
if (r !== void 0) return { column: r.name };
|
|
548
|
+
let i = n.indexes.find((e) => e.name === `${t}_pkey`)?.columns ?? n.primaryKey ?? [];
|
|
549
|
+
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.` };
|
|
550
|
+
}, jt = (e, t, r) => n.tryPromise({
|
|
526
551
|
try: async () => {
|
|
527
552
|
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: l, Transform: u } = await import("node:stream"), d = a("sha256"), f = 0, p = new u({ transform(e, t, n) {
|
|
528
553
|
d.update(e);
|
|
@@ -531,7 +556,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
531
556
|
n(null, e);
|
|
532
557
|
} }), m = l.fromWeb(c.toReadableStream(e)), h = `${t}.tmp-${o()}`;
|
|
533
558
|
try {
|
|
534
|
-
await s(m, p,
|
|
559
|
+
await s(m, p, qe(r), n(h)), await i.rename(h, t);
|
|
535
560
|
} catch (e) {
|
|
536
561
|
throw await i.rm(h, { force: !0 }).catch(() => {}), e;
|
|
537
562
|
}
|
|
@@ -540,108 +565,110 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
540
565
|
checksum: d.digest("hex")
|
|
541
566
|
};
|
|
542
567
|
},
|
|
543
|
-
catch: (e) => new
|
|
544
|
-
reason: `write table failed: ${
|
|
568
|
+
catch: (e) => new P({
|
|
569
|
+
reason: `write table failed: ${J(e)}`,
|
|
545
570
|
path: t
|
|
546
571
|
})
|
|
547
|
-
}),
|
|
572
|
+
}), Mt = (e, t) => n.tryPromise({
|
|
548
573
|
try: async () => {
|
|
549
574
|
await (await import("node:fs/promises")).appendFile(e, `${t}\n`);
|
|
550
575
|
},
|
|
551
|
-
catch: (t) => new
|
|
552
|
-
reason: `append failed: ${
|
|
576
|
+
catch: (t) => new P({
|
|
577
|
+
reason: `append failed: ${J(t)}`,
|
|
553
578
|
path: e
|
|
554
579
|
})
|
|
555
|
-
}),
|
|
556
|
-
let
|
|
557
|
-
for (let
|
|
558
|
-
let
|
|
559
|
-
if (
|
|
560
|
-
|
|
561
|
-
|
|
580
|
+
}), Nt = (e, t) => n.gen(function* () {
|
|
581
|
+
let r = [], i = t.ordered.length;
|
|
582
|
+
for (let a = 0; a < t.ordered.length; a++) {
|
|
583
|
+
let o = t.ordered[a], s = kt(t.snapshot, o), l = At(t.snapshot, o);
|
|
584
|
+
if ("refusal" in l) return yield* n.fail(new I({ reason: `export: ${l.refusal}` }));
|
|
585
|
+
let u = l.column, d = `${U}/${o}.ndjson${Ke(t.compression)}`;
|
|
586
|
+
if (ft(t.ledger, o)) {
|
|
587
|
+
let e = t.ledger.tables[o];
|
|
588
|
+
K(t.onProgress, {
|
|
562
589
|
phase: "export",
|
|
563
|
-
table:
|
|
564
|
-
index:
|
|
565
|
-
tableCount:
|
|
590
|
+
table: o,
|
|
591
|
+
index: a,
|
|
592
|
+
tableCount: i,
|
|
566
593
|
event: "done",
|
|
567
594
|
rowsDone: e.rowCount,
|
|
568
595
|
total: e.rowCount
|
|
569
|
-
}),
|
|
570
|
-
name:
|
|
571
|
-
file:
|
|
596
|
+
}), r.push({
|
|
597
|
+
name: o,
|
|
598
|
+
file: d,
|
|
572
599
|
rowCount: e.rowCount,
|
|
573
600
|
checksum: e.checksum,
|
|
574
|
-
columnTypes:
|
|
575
|
-
primaryKey:
|
|
601
|
+
columnTypes: s,
|
|
602
|
+
primaryKey: u
|
|
576
603
|
});
|
|
577
604
|
continue;
|
|
578
605
|
}
|
|
579
|
-
|
|
606
|
+
K(t.onProgress, {
|
|
580
607
|
phase: "export",
|
|
581
|
-
table:
|
|
582
|
-
index:
|
|
583
|
-
tableCount:
|
|
608
|
+
table: o,
|
|
609
|
+
index: a,
|
|
610
|
+
tableCount: i,
|
|
584
611
|
event: "start",
|
|
585
612
|
rowsDone: 0
|
|
586
613
|
});
|
|
587
|
-
let
|
|
588
|
-
table:
|
|
589
|
-
pk:
|
|
614
|
+
let f = t.resolved.predicateFor(o), m = p(e, {
|
|
615
|
+
table: o,
|
|
616
|
+
pk: u,
|
|
590
617
|
chunkSize: t.chunkSize,
|
|
591
618
|
retry: t.retry,
|
|
592
|
-
...
|
|
593
|
-
}),
|
|
594
|
-
t.ledger.tables[
|
|
595
|
-
rowCount:
|
|
596
|
-
checksum:
|
|
597
|
-
}, yield*
|
|
619
|
+
...f === void 0 ? {} : { where: f }
|
|
620
|
+
}), h = t.mask ? m.pipe(c.map((e) => N(e, o, t.mask.actions, t.mask.seed, s))) : m, { rowCount: g, checksum: _ } = yield* lt("export", o, a, i, (e) => e.rowCount, jt(Tt(h, s), t.bundleFile(d), t.compression));
|
|
621
|
+
t.ledger.tables[o] = {
|
|
622
|
+
rowCount: g,
|
|
623
|
+
checksum: _
|
|
624
|
+
}, yield* q(t.ledgerPath, t.ledger), K(t.onProgress, {
|
|
598
625
|
phase: "export",
|
|
599
|
-
table:
|
|
600
|
-
index:
|
|
601
|
-
tableCount:
|
|
626
|
+
table: o,
|
|
627
|
+
index: a,
|
|
628
|
+
tableCount: i,
|
|
602
629
|
event: "done",
|
|
603
|
-
rowsDone:
|
|
604
|
-
total:
|
|
605
|
-
}),
|
|
606
|
-
name:
|
|
607
|
-
file:
|
|
608
|
-
rowCount:
|
|
609
|
-
checksum:
|
|
610
|
-
columnTypes:
|
|
611
|
-
primaryKey:
|
|
630
|
+
rowsDone: g,
|
|
631
|
+
total: g
|
|
632
|
+
}), r.push({
|
|
633
|
+
name: o,
|
|
634
|
+
file: d,
|
|
635
|
+
rowCount: g,
|
|
636
|
+
checksum: _,
|
|
637
|
+
columnTypes: s,
|
|
638
|
+
primaryKey: u
|
|
612
639
|
});
|
|
613
640
|
}
|
|
614
|
-
return
|
|
615
|
-
}),
|
|
641
|
+
return r;
|
|
642
|
+
}), Pt = (e) => ({
|
|
616
643
|
_tag: "RawSqlFragment",
|
|
617
644
|
strings: [e],
|
|
618
645
|
values: []
|
|
619
|
-
}),
|
|
646
|
+
}), Ft = (t, i, a) => n.tryPromise({
|
|
620
647
|
try: () => t.transactional(async (t) => {
|
|
621
|
-
if (t.raw) for (let e of ge(i)) await t.raw(
|
|
648
|
+
if (t.raw) for (let e of ge(i)) await t.raw(Pt(e));
|
|
622
649
|
let o = await n.runPromiseExit(a(t));
|
|
623
650
|
if (r.isFailure(o)) throw Error(e.pretty(o.cause));
|
|
624
651
|
return o.value;
|
|
625
652
|
}),
|
|
626
|
-
catch: (e) => e instanceof
|
|
627
|
-
}),
|
|
628
|
-
let t = e.scope ?? { kind: "all" }, r =
|
|
653
|
+
catch: (e) => e instanceof P ? e : new P({ reason: `snapshot export failed: ${J(e)}` })
|
|
654
|
+
}), It = (e) => n.gen(function* () {
|
|
655
|
+
let t = e.scope ?? { kind: "all" }, r = Ge(e.compression), i = e.chunkSize ?? 1e3, a = e.retryTimes ?? 5, s = o.exponential("50 millis").pipe(o.jittered, o.intersect(o.recurs(a))), l = yield* n.promise(() => import("node:path")), u = (t) => l.join(e.outDir, t);
|
|
629
656
|
yield* n.tryPromise({
|
|
630
657
|
try: async () => {
|
|
631
658
|
let t = await import("node:fs/promises");
|
|
632
|
-
await t.mkdir(u(
|
|
659
|
+
await t.mkdir(u(U), { recursive: !0 }), e.assets && await t.mkdir(u(W), { recursive: !0 });
|
|
633
660
|
},
|
|
634
|
-
catch: (t) => new
|
|
635
|
-
reason: `mkdir failed: ${
|
|
661
|
+
catch: (t) => new P({
|
|
662
|
+
reason: `mkdir failed: ${J(t)}`,
|
|
636
663
|
path: e.outDir
|
|
637
664
|
})
|
|
638
665
|
});
|
|
639
|
-
let d = u(
|
|
666
|
+
let d = u(rt), f = yield* dt(d), p = e.subset ? ze(yield* z(e.store, e.snapshot, e.subset), e.snapshot) : yield* V(t, e.snapshot, {
|
|
640
667
|
store: e.store,
|
|
641
668
|
...e.tenantTables ? { tenantTables: e.tenantTables } : {}
|
|
642
|
-
}), h =
|
|
669
|
+
}), h = Dt(p.tables, e.snapshot), g = e.consistency ?? "live", _, v;
|
|
643
670
|
if (e.masking) {
|
|
644
|
-
let t = e.classification ?? ve(e.snapshot), r =
|
|
671
|
+
let t = e.classification ?? ve(e.snapshot), r = M(h.map((t) => ({
|
|
645
672
|
name: t,
|
|
646
673
|
columns: (e.snapshot.tables.find((e) => e.name === t)?.columns ?? []).map((e) => ({
|
|
647
674
|
name: e.name,
|
|
@@ -671,18 +698,18 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
671
698
|
bundleFile: u,
|
|
672
699
|
...v ? { mask: v } : {},
|
|
673
700
|
...e.onProgress ? { onProgress: e.onProgress } : {}
|
|
674
|
-
}, b = g === "snapshot" ? yield*
|
|
701
|
+
}, b = g === "snapshot" ? yield* Ft(e.store, e.dialect, (e) => Nt(e, y)) : yield* Nt(e.store, y), x = 0, S = 0;
|
|
675
702
|
if (e.assets) {
|
|
676
|
-
let t = u(
|
|
677
|
-
yield* c.runForEach(e.assets.list(), (r) => r.key in f.assets ? n.void : e.assets.open(r.key).pipe(n.flatMap((e) =>
|
|
703
|
+
let t = u(G);
|
|
704
|
+
yield* c.runForEach(e.assets.list(), (r) => r.key in f.assets ? n.void : e.assets.open(r.key).pipe(n.flatMap((e) => He(e, u(W))), n.flatMap((e) => {
|
|
678
705
|
let i = {
|
|
679
706
|
key: r.key,
|
|
680
707
|
sha256: e.sha256,
|
|
681
708
|
size: e.size,
|
|
682
709
|
contentType: e.contentType
|
|
683
710
|
};
|
|
684
|
-
return x++, S += e.size, f.assets[r.key] = !0,
|
|
685
|
-
}))).pipe(n.mapError((e) => e instanceof
|
|
711
|
+
return x++, S += e.size, f.assets[r.key] = !0, Mt(t, JSON.stringify(i)).pipe(n.andThen(q(d, f)));
|
|
712
|
+
}))).pipe(n.mapError((e) => e instanceof P ? e : new P({ reason: `asset export failed: ${String(e)}` })));
|
|
686
713
|
}
|
|
687
714
|
let C = {
|
|
688
715
|
formatVersion: 1,
|
|
@@ -698,7 +725,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
698
725
|
assets: x > 0 ? {
|
|
699
726
|
count: x,
|
|
700
727
|
totalBytes: S,
|
|
701
|
-
index:
|
|
728
|
+
index: G
|
|
702
729
|
} : {
|
|
703
730
|
count: 0,
|
|
704
731
|
totalBytes: 0
|
|
@@ -707,23 +734,23 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
707
734
|
};
|
|
708
735
|
return yield* n.tryPromise({
|
|
709
736
|
try: async () => {
|
|
710
|
-
await (await import("node:fs/promises")).writeFile(u(
|
|
737
|
+
await (await import("node:fs/promises")).writeFile(u(H), et(C));
|
|
711
738
|
},
|
|
712
|
-
catch: (e) => new
|
|
713
|
-
reason: `manifest write failed: ${
|
|
714
|
-
path:
|
|
739
|
+
catch: (e) => new P({
|
|
740
|
+
reason: `manifest write failed: ${J(e)}`,
|
|
741
|
+
path: H
|
|
715
742
|
})
|
|
716
743
|
}), yield* n.tryPromise({
|
|
717
744
|
try: async () => {
|
|
718
745
|
let e = await import("node:fs/promises"), t = await import("node:os");
|
|
719
|
-
await e.writeFile(u(
|
|
746
|
+
await e.writeFile(u(nt), at(C, { hostname: t.hostname() }));
|
|
720
747
|
},
|
|
721
|
-
catch: (e) => new
|
|
722
|
-
reason: `readme write failed: ${
|
|
723
|
-
path:
|
|
748
|
+
catch: (e) => new P({
|
|
749
|
+
reason: `readme write failed: ${J(e)}`,
|
|
750
|
+
path: nt
|
|
724
751
|
})
|
|
725
752
|
}), C;
|
|
726
|
-
}),
|
|
753
|
+
}), Lt = (e) => {
|
|
727
754
|
switch (e) {
|
|
728
755
|
case "id":
|
|
729
756
|
case "text":
|
|
@@ -742,12 +769,12 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
742
769
|
case "raw": return "raw";
|
|
743
770
|
default: return "string";
|
|
744
771
|
}
|
|
745
|
-
},
|
|
772
|
+
}, Rt = {
|
|
746
773
|
vector: /* @__PURE__ */ new Set(["postgres"]),
|
|
747
774
|
array: /* @__PURE__ */ new Set(["postgres"]),
|
|
748
775
|
interval: /* @__PURE__ */ new Set(["postgres"])
|
|
749
|
-
},
|
|
750
|
-
let i =
|
|
776
|
+
}, zt = (e, t, n, r) => {
|
|
777
|
+
let i = Lt(n);
|
|
751
778
|
if (i === "raw") return {
|
|
752
779
|
table: e,
|
|
753
780
|
column: t,
|
|
@@ -755,7 +782,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
755
782
|
severity: "block",
|
|
756
783
|
reason: `raw() is verbatim source-dialect SQL — it cannot be assumed valid on ${r}`
|
|
757
784
|
};
|
|
758
|
-
let a =
|
|
785
|
+
let a = Rt[i];
|
|
759
786
|
return !a || a.has(r) ? null : i === "array" || i === "interval" ? {
|
|
760
787
|
table: e,
|
|
761
788
|
column: t,
|
|
@@ -769,20 +796,20 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
769
796
|
severity: "block",
|
|
770
797
|
reason: `${i} columns require a ${[...a].join("/")} target; ${r} has no compatible column type`
|
|
771
798
|
};
|
|
772
|
-
},
|
|
799
|
+
}, Bt = (e, t, n) => {
|
|
773
800
|
if (t === n) return [];
|
|
774
801
|
let r = [];
|
|
775
802
|
for (let t of e) for (let [e, i] of Object.entries(t.columnTypes)) {
|
|
776
|
-
let a =
|
|
803
|
+
let a = zt(t.name, e, i, n);
|
|
777
804
|
a && r.push(a);
|
|
778
805
|
}
|
|
779
806
|
return r;
|
|
780
|
-
},
|
|
807
|
+
}, Vt = (e) => `[${e.severity}] ${e.table}.${e.column} (${e.type}): ${e.reason}`, Ht = (e, t) => new Map((e.tables.find((e) => e.name === t)?.columns ?? []).map((e) => [e.name, e.type])), Ut = (e, t) => {
|
|
781
808
|
let n = [], r = new Set(e.tables.map((e) => e.name)), i = new Set(t.tables.map((e) => e.name));
|
|
782
809
|
for (let e of [...r].filter((e) => !i.has(e)).sort()) n.push(`table '${e}' is in the bundle but MISSING from the target`);
|
|
783
810
|
for (let e of [...i].filter((e) => !r.has(e)).sort()) n.push(`table '${e}' is in the target but NOT in the bundle (import leaves it untouched)`);
|
|
784
811
|
for (let a of [...r].filter((e) => i.has(e)).sort()) {
|
|
785
|
-
let r =
|
|
812
|
+
let r = Ht(e, a), i = Ht(t, a);
|
|
786
813
|
for (let [e] of r) i.has(e) || n.push(`${a}.${e}: in the bundle, MISSING from the target`);
|
|
787
814
|
for (let [e] of i) r.has(e) || n.push(`${a}.${e}: in the target, not in the bundle`);
|
|
788
815
|
for (let [e, t] of r) {
|
|
@@ -791,7 +818,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
791
818
|
}
|
|
792
819
|
}
|
|
793
820
|
return n.length > 30 ? [...n.slice(0, 30), `… and ${n.length - 30} more difference(s)`] : n.length > 0 ? n : ["the schema shape differs (indexes, nullability, or defaults) — the specific change is below the table/column granularity shown here"];
|
|
794
|
-
},
|
|
821
|
+
}, Wt = (e, t, n) => {
|
|
795
822
|
let r = m(t);
|
|
796
823
|
return r === e ? {
|
|
797
824
|
drifted: !1,
|
|
@@ -802,20 +829,20 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
802
829
|
drifted: !0,
|
|
803
830
|
bundleFingerprint: e,
|
|
804
831
|
targetFingerprint: r,
|
|
805
|
-
diff: n ?
|
|
832
|
+
diff: n ? Ut(n, t) : ["the target schema fingerprint does not match the bundle (no source schema available to itemise the diff — the manifest records only the fingerprint)"]
|
|
806
833
|
};
|
|
807
|
-
},
|
|
834
|
+
}, Gt = (e) => n.tryPromise({
|
|
808
835
|
try: async () => {
|
|
809
836
|
let t = await import("node:fs/promises"), n = await import("node:path");
|
|
810
|
-
return
|
|
837
|
+
return tt(await t.readFile(n.join(e, H), "utf8"));
|
|
811
838
|
},
|
|
812
|
-
catch: (e) => new
|
|
839
|
+
catch: (e) => new P({
|
|
813
840
|
reason: `manifest read/parse failed: ${String(e?.message ?? e)}`,
|
|
814
|
-
path:
|
|
841
|
+
path: H
|
|
815
842
|
})
|
|
816
|
-
}),
|
|
817
|
-
let i = yield* n.promise(() => import("node:path")), a = yield*
|
|
818
|
-
if (a.formatVersion !== 1) return yield* n.fail(new
|
|
843
|
+
}), Kt = (t) => n.gen(function* () {
|
|
844
|
+
let i = yield* n.promise(() => import("node:path")), a = yield* Gt(t.bundleDir);
|
|
845
|
+
if (a.formatVersion !== 1) return yield* n.fail(new P({ reason: `unsupported bundle formatVersion ${a.formatVersion} (expected 1)` }));
|
|
819
846
|
if (t.targetSnapshot) {
|
|
820
847
|
let e = { tables: a.tables.map((e) => ({
|
|
821
848
|
name: e.name,
|
|
@@ -827,7 +854,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
827
854
|
unique: !1,
|
|
828
855
|
hasDefault: !1
|
|
829
856
|
}))
|
|
830
|
-
})) }, r =
|
|
857
|
+
})) }, r = Wt(a.source.schemaFingerprint, t.targetSnapshot, e);
|
|
831
858
|
if (r.drifted) {
|
|
832
859
|
if (!t.force) return yield* n.fail(new Pe({
|
|
833
860
|
bundleFingerprint: r.bundleFingerprint,
|
|
@@ -838,14 +865,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
838
865
|
}
|
|
839
866
|
}
|
|
840
867
|
if (t.targetDialect && t.targetDialect !== a.source.dialect) {
|
|
841
|
-
let e =
|
|
868
|
+
let e = Bt(a.tables, a.source.dialect, t.targetDialect).filter((e) => e.severity === "block");
|
|
842
869
|
if (e.length > 0 && !t.allowIncompatible) return yield* n.fail(new Le({
|
|
843
870
|
sourceDialect: a.source.dialect,
|
|
844
871
|
targetDialect: t.targetDialect,
|
|
845
|
-
blocking: e.map(
|
|
872
|
+
blocking: e.map(Vt)
|
|
846
873
|
}));
|
|
847
874
|
}
|
|
848
|
-
let o = t.verify ?? !0, s = t.mode ?? "upsert", l = t.onConflict ?? "skip", u = t.ledgerPath ?? i.join(t.bundleDir, ".import..ledger.json"), f = yield*
|
|
875
|
+
let o = t.verify ?? !0, s = t.mode ?? "upsert", l = t.onConflict ?? "skip", u = t.ledgerPath ?? i.join(t.bundleDir, ".import..ledger.json"), f = yield* dt(u);
|
|
849
876
|
if (s === "replace" && a.scope.kind !== "all") return yield* n.fail(new Ie({
|
|
850
877
|
mode: s,
|
|
851
878
|
reason: `replace refuses a partial bundle (scope='${a.scope.kind}') — truncating would delete rows not in the bundle. Use --mode upsert, or re-export with full scope.`
|
|
@@ -887,15 +914,15 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
887
914
|
if (s === "replace" && !(r && f.truncated)) {
|
|
888
915
|
for (let t of [...a.tables].reverse()) yield* n.tryPromise({
|
|
889
916
|
try: () => e.deleteMany(t.name, { where: d(t.primaryKey) }),
|
|
890
|
-
catch: (e) => new
|
|
917
|
+
catch: (e) => new P({ reason: `truncate ${t.name} failed: ${String(e?.message ?? e)}` })
|
|
891
918
|
});
|
|
892
|
-
r && (f.truncated = !0, yield*
|
|
919
|
+
r && (f.truncated = !0, yield* q(u, f));
|
|
893
920
|
}
|
|
894
921
|
let l = [], m = [], h = a.tables.length;
|
|
895
922
|
for (let d = 0; d < a.tables.length; d++) {
|
|
896
923
|
let g = a.tables[d];
|
|
897
924
|
if (r && g.name in f.tables) {
|
|
898
|
-
|
|
925
|
+
K(t.onProgress, {
|
|
899
926
|
phase: "import",
|
|
900
927
|
table: g.name,
|
|
901
928
|
index: d,
|
|
@@ -907,7 +934,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
907
934
|
continue;
|
|
908
935
|
}
|
|
909
936
|
let _ = i.join(t.bundleDir, g.file);
|
|
910
|
-
|
|
937
|
+
K(t.onProgress, {
|
|
911
938
|
phase: "import",
|
|
912
939
|
table: g.name,
|
|
913
940
|
index: d,
|
|
@@ -917,7 +944,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
917
944
|
total: g.rowCount
|
|
918
945
|
});
|
|
919
946
|
let v = l.length, y = n.gen(function* () {
|
|
920
|
-
let { createHash: r } = yield* n.promise(() => import("node:crypto")), i = r("sha256"), o = 0, u = S("bundle", () => E(_).pipe(
|
|
947
|
+
let { createHash: r } = yield* n.promise(() => import("node:crypto")), i = r("sha256"), o = 0, u = S("bundle", () => E(_).pipe(Je(a.compression))).pipe(c.tap((e) => n.sync(() => i.update(e)))), d = async (t) => {
|
|
921
948
|
let n = {
|
|
922
949
|
entry: g,
|
|
923
950
|
row: t,
|
|
@@ -961,7 +988,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
961
988
|
for (let t of e) await d(t);
|
|
962
989
|
}
|
|
963
990
|
};
|
|
964
|
-
return yield* c.runForEach(
|
|
991
|
+
return yield* c.runForEach(Et(u, g.name, g.columnTypes), (e) => n.promise(async () => {
|
|
965
992
|
if (o++, f) {
|
|
966
993
|
v.push(e), v.length >= h && await y();
|
|
967
994
|
return;
|
|
@@ -971,20 +998,20 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
971
998
|
rowCount: o,
|
|
972
999
|
checksum: i.digest("hex")
|
|
973
1000
|
};
|
|
974
|
-
}), { rowCount: b, checksum: x } = yield*
|
|
1001
|
+
}), { rowCount: b, checksum: x } = yield* lt("import", g.name, d, h, (e) => e.rowCount, y);
|
|
975
1002
|
if (o) {
|
|
976
|
-
if (x !== g.checksum) return yield* n.fail(new
|
|
1003
|
+
if (x !== g.checksum) return yield* n.fail(new F({
|
|
977
1004
|
what: `table ${g.name} checksum`,
|
|
978
1005
|
expected: g.checksum,
|
|
979
1006
|
actual: x
|
|
980
1007
|
}));
|
|
981
|
-
if (b !== g.rowCount) return yield* n.fail(new
|
|
1008
|
+
if (b !== g.rowCount) return yield* n.fail(new F({
|
|
982
1009
|
what: `table ${g.name} rowCount`,
|
|
983
1010
|
expected: String(g.rowCount),
|
|
984
1011
|
actual: String(b)
|
|
985
1012
|
}));
|
|
986
1013
|
}
|
|
987
|
-
|
|
1014
|
+
K(t.onProgress, {
|
|
988
1015
|
phase: "import",
|
|
989
1016
|
table: g.name,
|
|
990
1017
|
index: d,
|
|
@@ -998,7 +1025,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
998
1025
|
}) : (f.tables[g.name] = {
|
|
999
1026
|
rowCount: b,
|
|
1000
1027
|
checksum: g.checksum
|
|
1001
|
-
}, yield*
|
|
1028
|
+
}, yield* q(u, f)));
|
|
1002
1029
|
}
|
|
1003
1030
|
if (l.length > 0 && (yield* g(e, l)), r && m.length > 0) {
|
|
1004
1031
|
for (let e of m) {
|
|
@@ -1008,7 +1035,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1008
1035
|
checksum: t.checksum
|
|
1009
1036
|
};
|
|
1010
1037
|
}
|
|
1011
|
-
yield*
|
|
1038
|
+
yield* q(u, f);
|
|
1012
1039
|
}
|
|
1013
1040
|
});
|
|
1014
1041
|
if (t.atomic ? yield* n.tryPromise({
|
|
@@ -1016,22 +1043,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1016
1043
|
let i = await n.runPromiseExit(_(t, !1));
|
|
1017
1044
|
if (r.isFailure(i)) throw Error(e.pretty(i.cause));
|
|
1018
1045
|
}),
|
|
1019
|
-
catch: (e) => new
|
|
1046
|
+
catch: (e) => new P({ reason: `atomic import failed (rolled back): ${String(e?.message ?? e)}` })
|
|
1020
1047
|
}) : yield* _(t.store, !0), t.assets && a.assets.index && !t.assetsAlreadyRestored) {
|
|
1021
|
-
let e = t.assets, r = i.join(t.bundleDir,
|
|
1022
|
-
yield* c.runForEach(s, (t) => t.key in f.assets ? n.void :
|
|
1048
|
+
let e = t.assets, r = i.join(t.bundleDir, W), o = i.join(t.bundleDir, a.assets.index ?? "assets/index.ndjson"), s = S("bundle", () => E(o)).pipe(c.decodeText(), c.splitLines, c.filter((e) => e.trim().length > 0), c.map((e) => JSON.parse(e)));
|
|
1049
|
+
yield* c.runForEach(s, (t) => t.key in f.assets ? n.void : Ue(e, r, t).pipe(n.andThen(n.sync(() => {
|
|
1023
1050
|
f.assets[t.key] = !0;
|
|
1024
|
-
})), n.andThen(
|
|
1051
|
+
})), n.andThen(q(u, f))));
|
|
1025
1052
|
}
|
|
1026
1053
|
return a;
|
|
1027
|
-
}),
|
|
1054
|
+
}), qt = (e) => e, Jt = (e) => {
|
|
1028
1055
|
if (e.allowLive || e.liveInstance === null || e.sameTarget === "different") return { refuse: !1 };
|
|
1029
1056
|
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.";
|
|
1030
1057
|
return {
|
|
1031
1058
|
refuse: !0,
|
|
1032
1059
|
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).`
|
|
1033
1060
|
};
|
|
1034
|
-
},
|
|
1061
|
+
}, Y = Buffer.from("VBUNDLE2"), Yt = 0, Xt = 1, Zt = 2, Qt = 32, $t = async (e) => {
|
|
1035
1062
|
let t = [], n = async (r) => {
|
|
1036
1063
|
let i;
|
|
1037
1064
|
try {
|
|
@@ -1045,21 +1072,21 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1045
1072
|
}
|
|
1046
1073
|
};
|
|
1047
1074
|
return await n(""), t.sort();
|
|
1048
|
-
},
|
|
1075
|
+
}, en = (e, t) => {
|
|
1049
1076
|
let n = Buffer.from(e, "utf8"), r = Buffer.alloc(5 + n.length + 8);
|
|
1050
|
-
return r.writeUInt8(
|
|
1051
|
-
},
|
|
1077
|
+
return r.writeUInt8(Xt, 0), r.writeUInt32BE(n.length, 1), n.copy(r, 5), r.writeBigUInt64BE(BigInt(t), 5 + n.length), r;
|
|
1078
|
+
}, tn = (e, t, n) => {
|
|
1052
1079
|
let r = Buffer.from(e, "utf8"), i = Buffer.from(t, "utf8"), a = Buffer.alloc(5 + r.length + 2 + i.length + 8), o = 0;
|
|
1053
|
-
return a.writeUInt8(
|
|
1080
|
+
return a.writeUInt8(Zt, 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;
|
|
1054
1081
|
};
|
|
1055
|
-
async function*
|
|
1056
|
-
yield new Uint8Array(
|
|
1057
|
-
for (let t of await
|
|
1082
|
+
async function* nn(e) {
|
|
1083
|
+
yield new Uint8Array(Y);
|
|
1084
|
+
for (let t of await $t(e.dir)) {
|
|
1058
1085
|
let n = O(e.dir, t), r = await ce(n);
|
|
1059
|
-
if (yield new Uint8Array(
|
|
1086
|
+
if (yield new Uint8Array(en(t, r.size)), r.size > 0) for await (let e of E(n)) yield new Uint8Array(e);
|
|
1060
1087
|
}
|
|
1061
1088
|
if (e.blobs) for await (let t of e.blobs.list()) {
|
|
1062
|
-
yield new Uint8Array(
|
|
1089
|
+
yield new Uint8Array(tn(t.key, t.contentType, t.size));
|
|
1063
1090
|
let n = _("sha256"), r = 0;
|
|
1064
1091
|
for await (let i of e.blobs.open(t.key)) {
|
|
1065
1092
|
let e = Buffer.from(i);
|
|
@@ -1068,9 +1095,9 @@ async function* en(e) {
|
|
|
1068
1095
|
if (r !== t.size) throw Error(`blob '${t.key}' size mismatch: header ${t.size}, streamed ${r}`);
|
|
1069
1096
|
yield new Uint8Array(n.digest());
|
|
1070
1097
|
}
|
|
1071
|
-
yield new Uint8Array(Buffer.from([
|
|
1098
|
+
yield new Uint8Array(Buffer.from([Yt]));
|
|
1072
1099
|
}
|
|
1073
|
-
var
|
|
1100
|
+
var rn = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), an = (e) => new Promise((t) => e.end(t)), on = async (e, t) => {
|
|
1074
1101
|
let n = fe(t.dir);
|
|
1075
1102
|
await oe(n, { recursive: !0 });
|
|
1076
1103
|
let r = Buffer.alloc(0), i = e[Symbol.asyncIterator](), a = !1, o = async () => {
|
|
@@ -1083,12 +1110,12 @@ var tn = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), nn
|
|
|
1083
1110
|
return r = r.subarray(e), t;
|
|
1084
1111
|
};
|
|
1085
1112
|
try {
|
|
1086
|
-
if (await s(
|
|
1113
|
+
if (await s(Y.length), !c(Y.length).equals(Y)) throw Error("not a bundle archive (bad magic)");
|
|
1087
1114
|
for (;;) {
|
|
1088
1115
|
await s(1);
|
|
1089
1116
|
let e = c(1).readUInt8(0);
|
|
1090
|
-
if (e ===
|
|
1091
|
-
if (e ===
|
|
1117
|
+
if (e === Yt) return;
|
|
1118
|
+
if (e === Xt) {
|
|
1092
1119
|
await s(4);
|
|
1093
1120
|
let e = c(4).readUInt32BE(0);
|
|
1094
1121
|
await s(e);
|
|
@@ -1101,10 +1128,10 @@ var tn = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), nn
|
|
|
1101
1128
|
for (; i > 0n;) {
|
|
1102
1129
|
r.length === 0 && await s(1);
|
|
1103
1130
|
let e = i < BigInt(r.length) ? Number(i) : r.length;
|
|
1104
|
-
await
|
|
1131
|
+
await rn(o, c(e)), i -= BigInt(e);
|
|
1105
1132
|
}
|
|
1106
|
-
await
|
|
1107
|
-
} else if (e ===
|
|
1133
|
+
await an(o);
|
|
1134
|
+
} else if (e === Zt) {
|
|
1108
1135
|
await s(4);
|
|
1109
1136
|
let e = c(4).readUInt32BE(0);
|
|
1110
1137
|
await s(e);
|
|
@@ -1121,17 +1148,17 @@ var tn = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), nn
|
|
|
1121
1148
|
for (; p > 0n;) {
|
|
1122
1149
|
r.length === 0 && await s(1);
|
|
1123
1150
|
let e = p < BigInt(r.length) ? Number(p) : r.length, t = c(e);
|
|
1124
|
-
u.update(t), l || await
|
|
1151
|
+
u.update(t), l || await rn(d, t), p -= BigInt(e);
|
|
1125
1152
|
}
|
|
1126
|
-
l ? d.destroy() : await
|
|
1127
|
-
let m = c(
|
|
1153
|
+
l ? d.destroy() : await an(d), await f, await s(Qt);
|
|
1154
|
+
let m = c(Qt);
|
|
1128
1155
|
if (!u.digest().equals(m)) throw Error(`blob '${n}' failed integrity (sha mismatch)`);
|
|
1129
1156
|
} else throw Error(`unknown bundle entry kind ${e}`);
|
|
1130
1157
|
}
|
|
1131
1158
|
} finally {
|
|
1132
1159
|
a || await Promise.resolve(i.return?.()).catch(() => void 0);
|
|
1133
1160
|
}
|
|
1134
|
-
},
|
|
1161
|
+
}, sn = async (e, t) => {
|
|
1135
1162
|
let n = new Set(t), r = /* @__PURE__ */ new Map(), i = Buffer.alloc(0), a = e[Symbol.asyncIterator](), o = async () => {
|
|
1136
1163
|
let { value: e, done: t } = await a.next();
|
|
1137
1164
|
return !t && (i = i.length === 0 ? Buffer.from(e) : Buffer.concat([i, Buffer.from(e)]), !0);
|
|
@@ -1150,11 +1177,11 @@ var tn = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), nn
|
|
|
1150
1177
|
}
|
|
1151
1178
|
return Buffer.concat(t);
|
|
1152
1179
|
};
|
|
1153
|
-
if (!await s(
|
|
1180
|
+
if (!await s(Y.length) || !c(Y.length).equals(Y)) throw Error("not a bundle archive (bad magic)");
|
|
1154
1181
|
for (; await s(1);) {
|
|
1155
1182
|
let e = c(1).readUInt8(0);
|
|
1156
|
-
if (e ===
|
|
1157
|
-
if (e !==
|
|
1183
|
+
if (e === Yt || e === Zt) break;
|
|
1184
|
+
if (e !== Xt) throw Error(`unknown bundle entry kind ${e}`);
|
|
1158
1185
|
if (!await s(4)) break;
|
|
1159
1186
|
let t = c(4).readUInt32BE(0);
|
|
1160
1187
|
if (!await s(t)) break;
|
|
@@ -1164,10 +1191,10 @@ var tn = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), nn
|
|
|
1164
1191
|
if (a === null || n.has(i) && (r.set(i, a), n.delete(i), n.size === 0)) break;
|
|
1165
1192
|
}
|
|
1166
1193
|
return r;
|
|
1167
|
-
},
|
|
1194
|
+
}, cn = (e, t) => on(e, {
|
|
1168
1195
|
dir: t,
|
|
1169
|
-
blobs:
|
|
1170
|
-
}),
|
|
1196
|
+
blobs: ln(t)
|
|
1197
|
+
}), ln = (e) => {
|
|
1171
1198
|
let t = /* @__PURE__ */ new Set();
|
|
1172
1199
|
return {
|
|
1173
1200
|
has: async (e) => t.has(e),
|
|
@@ -1187,33 +1214,33 @@ var tn = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), nn
|
|
|
1187
1214
|
})}\n`), t.add(n);
|
|
1188
1215
|
}
|
|
1189
1216
|
};
|
|
1190
|
-
},
|
|
1217
|
+
}, un = me(b), dn = Buffer.from("VENC1\0\0\0"), fn = 32, pn = 16, mn = 7, X = 16, hn = 262144, Z = {
|
|
1191
1218
|
N: 32768,
|
|
1192
1219
|
r: 8,
|
|
1193
1220
|
p: 1
|
|
1194
|
-
},
|
|
1221
|
+
}, gn = 134217728, Q = 43, _n = (e, t, n) => {
|
|
1195
1222
|
let r = Buffer.alloc(12);
|
|
1196
|
-
return e.copy(r, 0, 0,
|
|
1223
|
+
return e.copy(r, 0, 0, mn), r.writeUInt32BE(t >>> 0, mn), r.writeUInt8(+!!n, 11), r;
|
|
1197
1224
|
};
|
|
1198
|
-
async function*
|
|
1225
|
+
async function* vn(e, t) {
|
|
1199
1226
|
if (!t) throw Error("encryptStream: a non-empty passphrase is required");
|
|
1200
|
-
let n = y(
|
|
1227
|
+
let n = y(pn), r = y(mn), i = await un(t, n, fn, {
|
|
1201
1228
|
...Z,
|
|
1202
|
-
maxmem:
|
|
1229
|
+
maxmem: gn
|
|
1203
1230
|
}), a = Buffer.alloc(Q);
|
|
1204
|
-
|
|
1231
|
+
dn.copy(a, 0), a.writeUInt32BE(Z.N, 8), a.writeUInt32BE(Z.r, 12), a.writeUInt32BE(Z.p, 16), n.copy(a, 20), r.copy(a, 36), yield new Uint8Array(a);
|
|
1205
1232
|
let o = 0, s = (e, t) => {
|
|
1206
|
-
let n = h("aes-256-gcm", i,
|
|
1233
|
+
let n = h("aes-256-gcm", i, _n(r, o, t));
|
|
1207
1234
|
o === 0 && n.setAAD(a);
|
|
1208
1235
|
let s = Buffer.concat([n.update(e), n.final()]), c = n.getAuthTag();
|
|
1209
1236
|
o++;
|
|
1210
1237
|
let l = Buffer.alloc(5 + s.length + X);
|
|
1211
1238
|
return l.writeUInt8(+!!t, 0), l.writeUInt32BE(s.length + X, 1), s.copy(l, 5), c.copy(l, 5 + s.length), new Uint8Array(l);
|
|
1212
1239
|
}, c = Buffer.alloc(0);
|
|
1213
|
-
for await (let t of e) for (c = c.length === 0 ? Buffer.from(t) : Buffer.concat([c, Buffer.from(t)]); c.length >
|
|
1240
|
+
for await (let t of e) for (c = c.length === 0 ? Buffer.from(t) : Buffer.concat([c, Buffer.from(t)]); c.length > hn;) yield s(c.subarray(0, hn), !1), c = c.subarray(hn);
|
|
1214
1241
|
yield s(c, !0);
|
|
1215
1242
|
}
|
|
1216
|
-
async function*
|
|
1243
|
+
async function* yn(e, t) {
|
|
1217
1244
|
if (!t) throw Error("decryptStream: a non-empty passphrase is required");
|
|
1218
1245
|
let n = e[Symbol.asyncIterator](), r = Buffer.alloc(0), i = !1, a = async () => {
|
|
1219
1246
|
let { value: e, done: t } = await n.next();
|
|
@@ -1224,12 +1251,12 @@ async function* _n(e, t) {
|
|
|
1224
1251
|
};
|
|
1225
1252
|
if (!await o(Q)) throw Error("encrypted bundle truncated (no header)");
|
|
1226
1253
|
let s = r.subarray(0, Q);
|
|
1227
|
-
if (!s.subarray(0, 8).equals(
|
|
1228
|
-
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, Q)), p = await
|
|
1254
|
+
if (!s.subarray(0, 8).equals(dn)) throw Error("not an encrypted bundle (bad magic / wrong passphrase target)");
|
|
1255
|
+
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, Q)), p = await un(t, d, fn, {
|
|
1229
1256
|
N: c,
|
|
1230
1257
|
r: l,
|
|
1231
1258
|
p: u,
|
|
1232
|
-
maxmem:
|
|
1259
|
+
maxmem: gn
|
|
1233
1260
|
});
|
|
1234
1261
|
r = r.subarray(Q);
|
|
1235
1262
|
let m = 0, h = !1;
|
|
@@ -1244,7 +1271,7 @@ async function* _n(e, t) {
|
|
|
1244
1271
|
if (!await o(5 + t)) throw Error("encrypted bundle truncated (frame body)");
|
|
1245
1272
|
let n = r.subarray(5, 5 + t - X), i = r.subarray(5 + t - X, 5 + t);
|
|
1246
1273
|
r = r.subarray(5 + t);
|
|
1247
|
-
let a = g("aes-256-gcm", p,
|
|
1274
|
+
let a = g("aes-256-gcm", p, _n(f, m, e));
|
|
1248
1275
|
m === 0 && a.setAAD(s), a.setAuthTag(i);
|
|
1249
1276
|
let c = Buffer.concat([a.update(n), a.final()]);
|
|
1250
1277
|
m++, e && (h = !0), c.length > 0 && (yield new Uint8Array(c));
|
|
@@ -1252,7 +1279,7 @@ async function* _n(e, t) {
|
|
|
1252
1279
|
}
|
|
1253
1280
|
//#endregion
|
|
1254
1281
|
//#region src/blobStorage.ts
|
|
1255
|
-
var
|
|
1282
|
+
var bn = (e, t) => ({
|
|
1256
1283
|
list: () => {
|
|
1257
1284
|
let e = t();
|
|
1258
1285
|
return { async *[Symbol.asyncIterator]() {
|
|
@@ -1268,14 +1295,14 @@ var vn = (e, t) => ({
|
|
|
1268
1295
|
let r = await n.runPromise(C(e, t)), i = await te(r.stream);
|
|
1269
1296
|
for await (let e of i) yield e instanceof Uint8Array ? e : new Uint8Array(e);
|
|
1270
1297
|
} })
|
|
1271
|
-
}),
|
|
1298
|
+
}), xn = (e, t) => bn(e, () => p(t, {
|
|
1272
1299
|
table: x,
|
|
1273
1300
|
chunkSize: 500
|
|
1274
1301
|
}).pipe(c.map((e) => ({
|
|
1275
1302
|
key: String(e.key),
|
|
1276
1303
|
contentType: String(e.contentType ?? "application/octet-stream"),
|
|
1277
1304
|
size: Number(e.size ?? 0)
|
|
1278
|
-
})))),
|
|
1305
|
+
})))), Sn = (e) => ({
|
|
1279
1306
|
has: (t) => n.runPromise(e.head(t).pipe(n.map((e) => e !== null))),
|
|
1280
1307
|
write: async (t, r, i) => {
|
|
1281
1308
|
let a = S("storage", () => ne.from(r));
|
|
@@ -1284,10 +1311,10 @@ var vn = (e, t) => ({
|
|
|
1284
1311
|
totalSize: i.size
|
|
1285
1312
|
}));
|
|
1286
1313
|
}
|
|
1287
|
-
}),
|
|
1314
|
+
}), Cn = (e, t) => {
|
|
1288
1315
|
let n = t === "dump" ? "mariadb-dump" : "mariadb", r = t === "dump" ? "mysqldump" : "mysql";
|
|
1289
|
-
return e === "mariadb" &&
|
|
1290
|
-
},
|
|
1316
|
+
return e === "mariadb" && wn(n) ? n : r;
|
|
1317
|
+
}, wn = (e) => (process.env.PATH ?? "").split(ue).filter((e) => e !== "").some((t) => ie(O(t, e))), Tn = (e) => {
|
|
1291
1318
|
switch (e) {
|
|
1292
1319
|
case "postgres": return "db.dump";
|
|
1293
1320
|
case "mysql":
|
|
@@ -1297,7 +1324,7 @@ var vn = (e, t) => ({
|
|
|
1297
1324
|
case "mssql": return "db.bacpac";
|
|
1298
1325
|
default: return "db.dump";
|
|
1299
1326
|
}
|
|
1300
|
-
},
|
|
1327
|
+
}, En = (e) => e.filename ?? e.database ?? ((e.url ?? "").replace(/^file:/, "") || "app.sqlite"), $ = (e) => {
|
|
1301
1328
|
if (e.host || e.database) return {
|
|
1302
1329
|
host: e.host ?? "localhost",
|
|
1303
1330
|
port: e.port ?? 3306,
|
|
@@ -1313,7 +1340,7 @@ var vn = (e, t) => ({
|
|
|
1313
1340
|
password: decodeURIComponent(t.password) || "",
|
|
1314
1341
|
database: t.pathname.replace(/^\//, "") || ""
|
|
1315
1342
|
};
|
|
1316
|
-
},
|
|
1343
|
+
}, Dn = (e) => `Server=${e.host},${e.port};Database=${e.database};User ID=${e.username};Password=${e.password};TrustServerCertificate=True`, On = (e, t, n) => {
|
|
1317
1344
|
switch (e) {
|
|
1318
1345
|
case "postgres": {
|
|
1319
1346
|
if (t.url) return {
|
|
@@ -1360,7 +1387,7 @@ var vn = (e, t) => ({
|
|
|
1360
1387
|
let r = $(t);
|
|
1361
1388
|
return {
|
|
1362
1389
|
kind: "spawn",
|
|
1363
|
-
tool:
|
|
1390
|
+
tool: Cn(e, "dump"),
|
|
1364
1391
|
args: [
|
|
1365
1392
|
"--single-transaction",
|
|
1366
1393
|
"--routines",
|
|
@@ -1382,7 +1409,7 @@ var vn = (e, t) => ({
|
|
|
1382
1409
|
case "sqlite":
|
|
1383
1410
|
case "turso": return {
|
|
1384
1411
|
kind: "copy",
|
|
1385
|
-
from:
|
|
1412
|
+
from: En(t),
|
|
1386
1413
|
to: n
|
|
1387
1414
|
};
|
|
1388
1415
|
case "mssql": return {
|
|
@@ -1390,7 +1417,7 @@ var vn = (e, t) => ({
|
|
|
1390
1417
|
tool: "sqlpackage",
|
|
1391
1418
|
args: [
|
|
1392
1419
|
"/Action:Export",
|
|
1393
|
-
`/SourceConnectionString:${
|
|
1420
|
+
`/SourceConnectionString:${Dn($({
|
|
1394
1421
|
...t,
|
|
1395
1422
|
port: t.port ?? 1433
|
|
1396
1423
|
}))}`,
|
|
@@ -1403,7 +1430,7 @@ var vn = (e, t) => ({
|
|
|
1403
1430
|
reason: `no native backup for dialect '${e}'`
|
|
1404
1431
|
});
|
|
1405
1432
|
}
|
|
1406
|
-
},
|
|
1433
|
+
}, kn = (e, t, n) => {
|
|
1407
1434
|
switch (e) {
|
|
1408
1435
|
case "postgres": {
|
|
1409
1436
|
if (t.url) return {
|
|
@@ -1448,7 +1475,7 @@ var vn = (e, t) => ({
|
|
|
1448
1475
|
let r = $(t);
|
|
1449
1476
|
return {
|
|
1450
1477
|
kind: "spawn",
|
|
1451
|
-
tool:
|
|
1478
|
+
tool: Cn(e, "client"),
|
|
1452
1479
|
args: [
|
|
1453
1480
|
"--protocol=TCP",
|
|
1454
1481
|
"-h",
|
|
@@ -1467,14 +1494,14 @@ var vn = (e, t) => ({
|
|
|
1467
1494
|
case "turso": return {
|
|
1468
1495
|
kind: "copy",
|
|
1469
1496
|
from: n,
|
|
1470
|
-
to:
|
|
1497
|
+
to: En(t)
|
|
1471
1498
|
};
|
|
1472
1499
|
case "mssql": return {
|
|
1473
1500
|
kind: "spawn",
|
|
1474
1501
|
tool: "sqlpackage",
|
|
1475
1502
|
args: [
|
|
1476
1503
|
"/Action:Import",
|
|
1477
|
-
`/TargetConnectionString:${
|
|
1504
|
+
`/TargetConnectionString:${Dn($({
|
|
1478
1505
|
...t,
|
|
1479
1506
|
port: t.port ?? 1433
|
|
1480
1507
|
}))}`,
|
|
@@ -1487,7 +1514,7 @@ var vn = (e, t) => ({
|
|
|
1487
1514
|
reason: `no native restore for dialect '${e}'`
|
|
1488
1515
|
});
|
|
1489
1516
|
}
|
|
1490
|
-
},
|
|
1517
|
+
}, An = (e) => e.kind === "copy" ? n.async((t) => {
|
|
1491
1518
|
re(e.from, e.to, (r) => t(r ? n.fail(new L({
|
|
1492
1519
|
tool: "copy",
|
|
1493
1520
|
reason: `copy ${e.from} → ${e.to}: ${r.message}`
|
|
@@ -1528,11 +1555,11 @@ var vn = (e, t) => ({
|
|
|
1528
1555
|
stderr: i.slice(-2e3)
|
|
1529
1556
|
})));
|
|
1530
1557
|
});
|
|
1531
|
-
}),
|
|
1532
|
-
let t = yield*
|
|
1558
|
+
}), jn = (e) => typeof e == "object" && e ? "fake" in e ? `fake:${e.fake}` : "custom" : String(e), Mn = (e) => n.gen(function* () {
|
|
1559
|
+
let t = yield* V(e.scope ?? { kind: "all" }, e.snapshot, {
|
|
1533
1560
|
store: e.store,
|
|
1534
1561
|
...e.tenantTables ? { tenantTables: e.tenantTables } : {}
|
|
1535
|
-
}), r =
|
|
1562
|
+
}), r = Dt(t.tables, e.snapshot), i = e.classification ?? ve(e.snapshot), a = e.sampleSize ?? 20, o = M(r.map((t) => ({
|
|
1536
1563
|
name: t,
|
|
1537
1564
|
columns: (e.snapshot.tables.find((e) => e.name === t)?.columns ?? []).map((e) => ({
|
|
1538
1565
|
name: e.name,
|
|
@@ -1544,15 +1571,15 @@ var vn = (e, t) => ({
|
|
|
1544
1571
|
table: i,
|
|
1545
1572
|
chunkSize: a,
|
|
1546
1573
|
...r === void 0 ? {} : { where: r }
|
|
1547
|
-
}).pipe(c.take(a), c.runCollect, n.map((e) => [...e])), d = u.map((t) =>
|
|
1548
|
-
l.push(...
|
|
1574
|
+
}).pipe(c.take(a), c.runCollect, n.map((e) => [...e])), d = u.map((t) => N(t, i, o.actions, e.masking.seed));
|
|
1575
|
+
l.push(...Ae(d, i, o.actions));
|
|
1549
1576
|
let f = u[0], m = d[0], h = [];
|
|
1550
1577
|
if (f && m) for (let [e, t] of Object.entries(o.actions)) {
|
|
1551
1578
|
if (!e.startsWith(`${i}.`) || t === "keep") continue;
|
|
1552
1579
|
let n = e.slice(i.length + 1);
|
|
1553
1580
|
h.push({
|
|
1554
1581
|
column: n,
|
|
1555
|
-
action:
|
|
1582
|
+
action: jn(t),
|
|
1556
1583
|
before: f[n],
|
|
1557
1584
|
after: m[n]
|
|
1558
1585
|
});
|
|
@@ -1567,7 +1594,7 @@ var vn = (e, t) => ({
|
|
|
1567
1594
|
leaks: l,
|
|
1568
1595
|
unclassified: o.unclassified
|
|
1569
1596
|
};
|
|
1570
|
-
}),
|
|
1597
|
+
}), Nn = (e, t) => {
|
|
1571
1598
|
let n = new Map(t.map((e) => [e.name, e])), r = [], i = {};
|
|
1572
1599
|
for (let t of e) {
|
|
1573
1600
|
let e = n.get(t.name);
|
|
@@ -1622,7 +1649,7 @@ var vn = (e, t) => ({
|
|
|
1622
1649
|
skipColumns: i,
|
|
1623
1650
|
refuse: r.some((e) => e.verdict === "refuse")
|
|
1624
1651
|
};
|
|
1625
|
-
},
|
|
1652
|
+
}, Pn = (e) => {
|
|
1626
1653
|
if (e.findings.length === 0) return [" schema matches the bundle"];
|
|
1627
1654
|
let t = {
|
|
1628
1655
|
safe: "✓",
|
|
@@ -1633,4 +1660,4 @@ var vn = (e, t) => ({
|
|
|
1633
1660
|
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;
|
|
1634
1661
|
};
|
|
1635
1662
|
//#endregion
|
|
1636
|
-
export {
|
|
1663
|
+
export { W as ASSETS_DIR, G as ASSET_INDEX_FILE, P as BundleError, je as CodecError, Me as CompressionError, Le as CrossDialectError, U as DATA_DIR, _e as DEFAULT_CLASS_ACTIONS, Ne as DanglingReferenceError, Ye as FORMAT_VERSION, Ie as ImportModeError, F as IntegrityError, rt as LEDGER_FILE, H as MANIFEST_FILE, Fe as MaskingError, L as NativeToolError, Pe as SchemaDriftError, I as ScopeError, Oe as applyAction, Jt as assessLiveImport, pt as assetDone, Tn as backupArtifactName, On as backupCommand, Lt as canonicalType, Bt as checkPortability, Wt as checkSchemaDrift, ve as classificationFromSnapshot, Nn as classifyImportDrift, Ke as compressionExt, z as computeSubsetIds, tt as decodeManifest, Ct as decodeRow, xt as decodeValue, yn as decryptStream, qt as defineDataProfile, Ut as diffSnapshots, ln as dirBlobSink, ut as emptyLedger, et as encodeManifest, St as encodeRow, yt as encodeValue, vn as encryptStream, Pn as formatImportDrift, Vt as formatIssue, We as hasZstd, qe as makeCompressor, Je as makeDecompressor, N as maskRow, Et as ndjsonToRows, nn as packBundle, sn as peekBundle, Ge as pickCompression, M as planMasking, Mn as previewMasking, dt as readLedger, ye as resolveAction, V as resolveScope, Ue as restoreAssetFromCas, kn as restoreCommand, Tt as rowsToNdjson, It as runExport, Kt as runImport, An as runNativeStep, Ae as scanForLeaks, Ve as storageAssetSink, Be as storageAssetSource, Sn as storageBlobSink, bn as storageBlobSource, xn as storageRefsBlobSource, ze as subsetToScope, ft as tableDone, Dt as topoSortTables, on as unpackBundle, cn as unpackBundleToDir, He as writeAssetToCas, q as writeLedger };
|