@voltro/data-transfer 0.81.0 → 0.83.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 +1806 -6
- package/THIRD-PARTY-NOTICES.md +1 -1
- package/dist/index.d.ts +52 -4
- package/dist/index.js +617 -535
- 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, STAGING_TABLE_PREFIX as f, _voltroDataTransfersTable as p, classifyConstraintViolation as m, derivedRowId as h, ensureTableRegistered as g, eq as _, extractDbCause as v, getTable as y, inSet as b, isNotNull as x, or as S, recordsTable as
|
|
3
|
-
import { fingerprintSchema as
|
|
4
|
-
import { createCipheriv as
|
|
5
|
-
import { copyFile 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, STAGING_TABLE_PREFIX as f, _voltroDataTransfersTable as p, classifyConstraintViolation as m, derivedRowId as h, ensureTableRegistered as g, eq as _, extractDbCause as v, getTable as y, inSet as b, isNotNull as x, or as S, recordsTable as ee, registerTable as te, streamTable as C, suspendWriteRecorders as ne, suspendWriteRecordersEffect as re, unregisterTable as ie } from "@voltro/database";
|
|
3
|
+
import { fingerprintSchema as w } from "@voltro/database/sql";
|
|
4
|
+
import { createCipheriv as ae, createDecipheriv as oe, createHash as T, createHmac as se, randomBytes as ce, randomUUID as le, scrypt as ue } from "node:crypto";
|
|
5
|
+
import { copyFile as de, createReadStream as fe, createWriteStream as pe, existsSync as E, rename as D, statSync as me, unlinkSync as he } from "node:fs";
|
|
6
|
+
import { STORAGE_REFS_TABLE as O, fromNodeReadable as ge, getObjectStream as _e, putObjectStream as k, toNodeReadable as A } from "@voltro/plugin-storage";
|
|
7
|
+
import * as j from "node:zlib";
|
|
8
|
+
import { PassThrough as M, Readable as ve } from "node:stream";
|
|
9
|
+
import { SqlClient as N } from "@effect/sql";
|
|
10
|
+
import { mkdir as P, readdir as ye, stat as be } from "node:fs/promises";
|
|
11
|
+
import { basename as F, delimiter as xe, dirname as Se, join as I, resolve as L, sep as Ce } from "node:path";
|
|
12
|
+
import { promisify as we } from "node:util";
|
|
13
|
+
import { spawn as Te } from "node:child_process";
|
|
14
14
|
//#region src/consistency.ts
|
|
15
|
-
var
|
|
15
|
+
var Ee = (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
|
+
}, De = {
|
|
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
|
+
}, Oe = (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
|
+
}, ke = (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] ?? De[e] ?? "redact";
|
|
58
58
|
}
|
|
59
59
|
return n?.safe ? r.onSafe ?? "keep" : n?.columnType === "id" || n?.columnType === "reference" ? "keep" : r.onUnclassified ?? "error";
|
|
60
|
-
},
|
|
60
|
+
}, Ae = (e, t) => se("sha256", e).update(t == null ? "∅" : String(t)).digest(), R = (e, t) => e.readUInt32BE(t * 4 % (e.length - 4)), je = [
|
|
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
|
+
], Me = [
|
|
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
|
+
], Ne = [
|
|
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
|
+
], Pe = [
|
|
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
|
-
],
|
|
105
|
-
let r =
|
|
104
|
+
], z = (e, t, n) => e[R(t, n) % e.length], Fe = (e, t, n) => {
|
|
105
|
+
let r = Ae(n, `${e}:${String(t)}`), i = R(r, 1) % 1e4;
|
|
106
106
|
switch (e) {
|
|
107
|
-
case "email": return `${
|
|
108
|
-
case "fullName": return `${
|
|
109
|
-
case "firstName": return
|
|
110
|
-
case "lastName": return
|
|
111
|
-
case "username": return `${
|
|
112
|
-
case "phone": return `+1${String(
|
|
113
|
-
case "address": return `${
|
|
114
|
-
case "company": return
|
|
107
|
+
case "email": return `${z(je, r, 0).toLowerCase()}.${z(Me, r, 2).toLowerCase()}${i}@example.com`;
|
|
108
|
+
case "fullName": return `${z(je, r, 0)} ${z(Me, r, 1)}`;
|
|
109
|
+
case "firstName": return z(je, r, 0);
|
|
110
|
+
case "lastName": return z(Me, r, 1);
|
|
111
|
+
case "username": return `${z(je, r, 0).toLowerCase()}${i}`;
|
|
112
|
+
case "phone": return `+1${String(R(r, 0) % 1e10).padStart(10, "0")}`;
|
|
113
|
+
case "address": return `${R(r, 0) % 9899 + 100} ${z(Ne, r, 1)} St`;
|
|
114
|
+
case "company": return z(Pe, r, 0);
|
|
115
115
|
case "url": return `https://example.com/${r.toString("hex").slice(0, 12)}`;
|
|
116
|
-
case "ip": return `${
|
|
117
|
-
case "creditCard": return
|
|
116
|
+
case "ip": return `${R(r, 0) % 256}.${R(r, 1) % 256}.${R(r, 2) % 256}.${R(r, 3) % 254 + 1}`;
|
|
117
|
+
case "creditCard": return Ie(`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
|
+
}, Ie = (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,29 +125,29 @@ var Ce = (e) => {
|
|
|
125
125
|
});
|
|
126
126
|
let r = (10 - n % 10) % 10;
|
|
127
127
|
return e.slice(0, 15) + String(r);
|
|
128
|
-
},
|
|
128
|
+
}, Le = 864e5, Re = (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 =
|
|
131
|
+
let r = R(Ae(t, "date-shift-offset"), 0) % 730 - 365, i = new Date(n + r * Le);
|
|
132
132
|
return e instanceof Date ? i : i.toISOString();
|
|
133
|
-
},
|
|
133
|
+
}, B = (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 Ae(t.seed, t.value).toString("hex").slice(0, 16);
|
|
140
|
+
if (e === "dateShift") return Re(t.value, t.seed);
|
|
141
|
+
if (typeof e == "object" && "fake" in e) return Fe(e.fake, t.value, t.seed);
|
|
142
142
|
if (typeof e == "object" && "custom" in e) return e.custom(t);
|
|
143
|
-
if (typeof e == "object" && "json" in e) return
|
|
143
|
+
if (typeof e == "object" && "json" in e) return ze(e, t);
|
|
144
144
|
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 } | { json: { fields, rest? } }.`);
|
|
145
|
-
},
|
|
146
|
-
let { fields: n, rest: r = "redact" } = e.json, i = typeof t.value == "string" ?
|
|
145
|
+
}, ze = (e, t) => {
|
|
146
|
+
let { fields: n, rest: r = "redact" } = e.json, i = typeof t.value == "string" ? Be(t.value) : {
|
|
147
147
|
ok: !0,
|
|
148
148
|
value: t.value
|
|
149
149
|
};
|
|
150
|
-
if (!i.ok) return
|
|
150
|
+
if (!i.ok) return B(r, {
|
|
151
151
|
...t,
|
|
152
152
|
columnType: "text"
|
|
153
153
|
});
|
|
@@ -158,12 +158,12 @@ var Ce = (e) => {
|
|
|
158
158
|
let a = {};
|
|
159
159
|
for (let [o, s] of Object.entries(e)) {
|
|
160
160
|
let e = n[o] ?? r, c = `${i}.${o}`;
|
|
161
|
-
a[o] = typeof e == "object" && "json" in e ?
|
|
161
|
+
a[o] = typeof e == "object" && "json" in e ? ze(e, {
|
|
162
162
|
...t,
|
|
163
163
|
value: s,
|
|
164
164
|
column: c,
|
|
165
165
|
columnType: "json"
|
|
166
|
-
}) :
|
|
166
|
+
}) : B(e, {
|
|
167
167
|
...t,
|
|
168
168
|
value: s,
|
|
169
169
|
column: c,
|
|
@@ -172,7 +172,7 @@ var Ce = (e) => {
|
|
|
172
172
|
}
|
|
173
173
|
return a;
|
|
174
174
|
}
|
|
175
|
-
return
|
|
175
|
+
return B(r, {
|
|
176
176
|
...t,
|
|
177
177
|
value: e,
|
|
178
178
|
column: i,
|
|
@@ -180,7 +180,7 @@ var Ce = (e) => {
|
|
|
180
180
|
});
|
|
181
181
|
}, o = a(i.value, t.column);
|
|
182
182
|
return typeof t.value == "string" ? JSON.stringify(o) : o;
|
|
183
|
-
},
|
|
183
|
+
}, Be = (e) => {
|
|
184
184
|
try {
|
|
185
185
|
return {
|
|
186
186
|
ok: !0,
|
|
@@ -189,7 +189,7 @@ var Ce = (e) => {
|
|
|
189
189
|
} catch {
|
|
190
190
|
return { ok: !1 };
|
|
191
191
|
}
|
|
192
|
-
},
|
|
192
|
+
}, Ve = (e) => {
|
|
193
193
|
if (typeof e == "string") return e === "keep" || e === "null" || e === "redact" || e === "hash" || e === "dateShift" || e === "error";
|
|
194
194
|
if (typeof e != "object" || !e) return !1;
|
|
195
195
|
if ("fake" in e) return typeof e.fake == "string";
|
|
@@ -198,18 +198,18 @@ var Ce = (e) => {
|
|
|
198
198
|
let t = e.json;
|
|
199
199
|
if (typeof t != "object" || !t) return !1;
|
|
200
200
|
let { fields: n, rest: r } = t;
|
|
201
|
-
return typeof n != "object" || !n ? !1 : Object.values(n).every(
|
|
201
|
+
return typeof n != "object" || !n ? !1 : Object.values(n).every(Ve) && (r === void 0 || Ve(r));
|
|
202
202
|
}
|
|
203
203
|
return !1;
|
|
204
|
-
},
|
|
204
|
+
}, He = (e, t, n) => {
|
|
205
205
|
let r = {}, i = [], a = [];
|
|
206
206
|
for (let o of e) for (let e of o.columns) {
|
|
207
|
-
let s = `${o.name}.${e.name}`, c =
|
|
207
|
+
let s = `${o.name}.${e.name}`, c = ke(o.name, e.name, t[o.name]?.[e.name], n);
|
|
208
208
|
if (c === "error") {
|
|
209
209
|
i.push(s);
|
|
210
210
|
continue;
|
|
211
211
|
}
|
|
212
|
-
if (!
|
|
212
|
+
if (!Ve(c)) {
|
|
213
213
|
a.push({
|
|
214
214
|
column: s,
|
|
215
215
|
action: c
|
|
@@ -223,7 +223,7 @@ var Ce = (e) => {
|
|
|
223
223
|
unclassified: i,
|
|
224
224
|
invalid: a
|
|
225
225
|
};
|
|
226
|
-
},
|
|
226
|
+
}, Ue = [
|
|
227
227
|
{
|
|
228
228
|
name: "email",
|
|
229
229
|
re: /[\w.+-]+@[\w-]+\.[\w.-]+/
|
|
@@ -240,7 +240,7 @@ var Ce = (e) => {
|
|
|
240
240
|
name: "creditCard",
|
|
241
241
|
re: /\b(?:\d[ -]?){13,16}\b/
|
|
242
242
|
}
|
|
243
|
-
],
|
|
243
|
+
], We = (e, t, n) => {
|
|
244
244
|
let r = [], i = /* @__PURE__ */ new Set();
|
|
245
245
|
for (let [a, o] of Object.entries(n)) {
|
|
246
246
|
if (!a.startsWith(`${t}.`) || o !== "keep") continue;
|
|
@@ -248,7 +248,7 @@ var Ce = (e) => {
|
|
|
248
248
|
for (let a of e) {
|
|
249
249
|
let e = a[n];
|
|
250
250
|
if (typeof e != "string" || e.length === 0) continue;
|
|
251
|
-
let o =
|
|
251
|
+
let o = Ue.find((t) => t.re.test(e));
|
|
252
252
|
if (o && !i.has(n)) {
|
|
253
253
|
i.add(n), r.push({
|
|
254
254
|
table: t,
|
|
@@ -261,9 +261,9 @@ var Ce = (e) => {
|
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
263
|
return r;
|
|
264
|
-
},
|
|
264
|
+
}, Ge = (e, t, n, r, i) => {
|
|
265
265
|
let a = {};
|
|
266
|
-
for (let [o, s] of Object.entries(e)) a[o] =
|
|
266
|
+
for (let [o, s] of Object.entries(e)) a[o] = B(n[`${t}.${o}`] ?? "keep", {
|
|
267
267
|
value: s,
|
|
268
268
|
table: t,
|
|
269
269
|
column: o,
|
|
@@ -271,9 +271,19 @@ var Ce = (e) => {
|
|
|
271
271
|
...i?.[o] ? { columnType: i[o] } : {}
|
|
272
272
|
});
|
|
273
273
|
return a;
|
|
274
|
-
},
|
|
274
|
+
}, Ke = /* @__PURE__ */ new Map([
|
|
275
|
+
["_voltro_isr_cache", "pages rendered by THIS deployment’s web processes — a foreign row would serve another environment’s HTML here"],
|
|
276
|
+
["_voltro_web_replicas", "heartbeats of the web processes running HERE — a foreign row advertises replicas that do not exist in the target"],
|
|
277
|
+
["_voltro_aggregate_meta", "materialized refresh generations computed HERE — a foreign row would claim that the target refreshed its own source data"],
|
|
278
|
+
["_voltro_aggregate_rows", "materialized rows tied to this deployment’s refresh generation — the target recomputes them from its own data"],
|
|
279
|
+
["_voltro_timeline", "captured source mutations from this deployment — foreign rows invent local timeline history"],
|
|
280
|
+
["_voltro_timeline_meta", "capture epoch and source cursor of this database — foreign metadata claims continuity with another database"],
|
|
281
|
+
["_voltro_timeline_leases", "active capture readers of this database — foreign leases claim readers that do not exist here"],
|
|
282
|
+
["_voltro_timeline_slots", "bounded capture slots belonging to this source epoch — foreign slots invent local mutation history"],
|
|
283
|
+
["_voltro_plugin_migrations", "plugin migration steps applied to this database — a foreign ledger would skip steps that the target has not run"],
|
|
275
284
|
["_voltro_migration_plans", "the schema fingerprint THIS deployment applied — a foreign row makes the next boot refuse"],
|
|
276
285
|
["_voltro_migrations", "which file-based migrations ran HERE — a foreign row marks unrun migrations as done"],
|
|
286
|
+
["_voltro_plugin_migrations", "which plugin migration steps ran HERE — a foreign row marks a plugin's unrun steps as done"],
|
|
277
287
|
["_voltro_schema_owner", "which app owns THIS database — a foreign row hands the target's schema to the source app, so the target's own app refuses to boot on it"],
|
|
278
288
|
["_voltro_deploys", "the deploy THIS database is in the middle of, with the baseline to undo it from — a foreign row makes the next apply undo a deploy the target never started"],
|
|
279
289
|
["_voltro_devices", "devices paired with THIS deployment — token hashes; a foreign row makes a device paired elsewhere authenticate here"],
|
|
@@ -319,6 +329,7 @@ var Ce = (e) => {
|
|
|
319
329
|
["_voltro_workflow_start_receipts", "the caller-facing identity of a start placed HERE, resolved through this deployment's placements — a foreign receipt names a run the target never accepted"],
|
|
320
330
|
["_voltro_workflow_control_requests", "cancel/resume traffic issued against executions HERE — a foreign row claims an operation nobody asked the target to perform"],
|
|
321
331
|
["_voltro_workflow_queued_cancellations", "cancellations waiting on a run that is queued HERE — a foreign row cancels something the target has not queued"],
|
|
332
|
+
["_voltro_workflow_restart_withdrawals", "withdrawal fences for restart requests issued HERE — a foreign row would block a target restart that its operator never withdrew"],
|
|
322
333
|
["_voltro_workflow_restart_requests", "restarts pending against this deployment's generations — a foreign row restarts a generation the target never entered"],
|
|
323
334
|
["_voltro_workflow_retry_requests", "retry intents an operator raised against runs HERE, keyed by their own request id — a foreign row binds the target to an intent nobody raised against it, and lets a later observation read somebody else's execution"],
|
|
324
335
|
["_voltro_workflow_parent_closures", "which parents are still waiting on children in flight HERE — a foreign row holds a parent open against a child the target is not running"],
|
|
@@ -327,8 +338,13 @@ var Ce = (e) => {
|
|
|
327
338
|
["_voltro_notification_deliveries", "the notification attempts this deployment made — a foreign row claims a send the target never performed"],
|
|
328
339
|
["_voltro_notification_held", "notifications waiting to be SENT from here — a foreign row makes the target deliver something queued elsewhere"],
|
|
329
340
|
["_voltro_webhook_event_stats", "per-deployment delivery counters a backoff decision reads — foreign counts steer the target's retries"],
|
|
330
|
-
["_voltro_webhook_rate_windows", "the live rate-limit windows this deployment is inside — a foreign window throttles or releases wrongly"]
|
|
331
|
-
|
|
341
|
+
["_voltro_webhook_rate_windows", "the live rate-limit windows this deployment is inside — a foreign window throttles or releases wrongly"],
|
|
342
|
+
["cluster_runners", "the workflow runners of THIS deployment and their addresses — a foreign row routes shards to a runner that does not exist here"],
|
|
343
|
+
["cluster_locks", "the shard leases THIS deployment's runners hold — a foreign row holds a shard for nobody, and its work stalls"],
|
|
344
|
+
["cluster_messages", "workflow messages in flight HERE — a foreign row makes the target run work that was started, and may be running, elsewhere"],
|
|
345
|
+
["cluster_replies", "replies to those messages — a foreign row answers a request the target never sent"],
|
|
346
|
+
["cluster_migrations", "which engine migrations ran HERE — a foreign row marks the target's engine tables migrated when they are not"]
|
|
347
|
+
]), qe = /* @__PURE__ */ new Map([
|
|
332
348
|
["_voltro_agent_threads", "conversations the app's users had — app data"],
|
|
333
349
|
["_voltro_agent_messages", "the messages in those conversations — app data"],
|
|
334
350
|
["_voltro_prompts", "prompt definitions the app authored — app data"],
|
|
@@ -364,21 +380,21 @@ var Ce = (e) => {
|
|
|
364
380
|
["_voltro_comment_threads", "the threads those comments hang on — app data"],
|
|
365
381
|
["_voltro_comment_reactions", "the reactions the app's users left — app data"],
|
|
366
382
|
["_voltro_comment_reads", "which comments each user has read — app data, and losing it re-marks everything unread"]
|
|
367
|
-
]),
|
|
383
|
+
]), V = (e) => Ke.has(e), Je = (e) => Ke.get(e), Ye = (e, t) => {
|
|
368
384
|
if (e.length === 0) return;
|
|
369
|
-
let n = e.map((e) => ` ${e} — ${
|
|
385
|
+
let n = e.map((e) => ` ${e} — ${Je(e) ?? "describes this deployment"}`);
|
|
370
386
|
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.`;
|
|
371
|
-
},
|
|
387
|
+
}, H = class extends c.TaggedError()("BundleError", {
|
|
372
388
|
reason: c.String,
|
|
373
389
|
path: c.optional(c.String)
|
|
374
|
-
}) {},
|
|
390
|
+
}) {}, Xe = class extends c.TaggedError()("CodecError", {
|
|
375
391
|
table: c.String,
|
|
376
392
|
reason: c.String
|
|
377
|
-
}) {},
|
|
393
|
+
}) {}, Ze = class extends c.TaggedError()("IntegrityError", {
|
|
378
394
|
what: c.String,
|
|
379
395
|
expected: c.String,
|
|
380
396
|
actual: c.String
|
|
381
|
-
}) {},
|
|
397
|
+
}) {}, Qe = class extends t.TaggedError("CompressionError") {}, U = class extends c.TaggedError()("ScopeError", { reason: c.String }) {}, $e = class extends c.TaggedError()("RowsRefusedError", {
|
|
382
398
|
rows: c.Array(c.Struct({
|
|
383
399
|
table: c.String,
|
|
384
400
|
id: c.String,
|
|
@@ -392,29 +408,29 @@ var Ce = (e) => {
|
|
|
392
408
|
refused: c.Number,
|
|
393
409
|
primary: c.Number
|
|
394
410
|
}))
|
|
395
|
-
}) {},
|
|
411
|
+
}) {}, et = class extends c.TaggedError()("SchemaDriftError", {
|
|
396
412
|
bundleFingerprint: c.String,
|
|
397
413
|
targetFingerprint: c.String,
|
|
398
414
|
diff: c.Array(c.String)
|
|
399
|
-
}) {},
|
|
415
|
+
}) {}, W = class extends t.TaggedError("NativeToolError") {
|
|
400
416
|
get message() {
|
|
401
417
|
let e = this.stderr?.trim(), t = this.hint?.trim();
|
|
402
418
|
return `${this.tool}: ${this.reason}${e ? `\n${e}` : ""}${t ? `\n\nhint: ${t}` : ""}`;
|
|
403
419
|
}
|
|
404
|
-
},
|
|
420
|
+
}, tt = class extends c.TaggedError()("MaskingError", {
|
|
405
421
|
unclassified: c.Array(c.String),
|
|
406
422
|
invalidActions: c.optional(c.Array(c.String))
|
|
407
|
-
}) {},
|
|
423
|
+
}) {}, nt = class extends c.TaggedError()("ImportModeError", {
|
|
408
424
|
mode: c.String,
|
|
409
425
|
reason: c.String
|
|
410
|
-
}) {},
|
|
426
|
+
}) {}, rt = class extends c.TaggedError()("CrossDialectError", {
|
|
411
427
|
sourceDialect: c.String,
|
|
412
428
|
targetDialect: c.String,
|
|
413
429
|
blocking: c.Array(c.String)
|
|
414
|
-
}) {},
|
|
430
|
+
}) {}, it = (e, t) => e.tables.find((e) => e.name === t)?.columns.find((e) => e.type === "id")?.name ?? "id", at = (e, t) => (e.tables.find((e) => e.name === t)?.columns ?? []).filter((e) => e.references).map((e) => ({
|
|
415
431
|
col: e.name,
|
|
416
432
|
refTable: e.references.table
|
|
417
|
-
})),
|
|
433
|
+
})), ot = (e, t, r) => n.gen(function* () {
|
|
418
434
|
let i = r.maxDepth ?? 12, a = new Set(r.pinned ?? []), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map(), u = (e) => {
|
|
419
435
|
let t = s.get(e) ?? /* @__PURE__ */ new Set();
|
|
420
436
|
return s.set(e, t), t;
|
|
@@ -432,10 +448,10 @@ var Ce = (e) => {
|
|
|
432
448
|
for (let t of n) d(t.refTable, e[t.col]);
|
|
433
449
|
};
|
|
434
450
|
}, p = (r, i) => {
|
|
435
|
-
let a = f(r,
|
|
436
|
-
return l.runForEach(
|
|
451
|
+
let a = f(r, it(t, r), at(t, r));
|
|
452
|
+
return l.runForEach(C(e, {
|
|
437
453
|
table: r,
|
|
438
|
-
pk:
|
|
454
|
+
pk: it(t, r),
|
|
439
455
|
...i === void 0 ? {} : { where: i }
|
|
440
456
|
}), (e) => n.sync(() => a(e)));
|
|
441
457
|
}, m = n.gen(function* () {
|
|
@@ -444,7 +460,7 @@ var Ce = (e) => {
|
|
|
444
460
|
c.clear();
|
|
445
461
|
for (let [n, r] of e) {
|
|
446
462
|
let e = [...r].filter((e) => !s.get(n)?.has(e));
|
|
447
|
-
e.length !== 0 && (yield* p(n, b(
|
|
463
|
+
e.length !== 0 && (yield* p(n, b(it(t, n), e)));
|
|
448
464
|
}
|
|
449
465
|
}
|
|
450
466
|
});
|
|
@@ -467,24 +483,24 @@ var Ce = (e) => {
|
|
|
467
483
|
}
|
|
468
484
|
}
|
|
469
485
|
return o;
|
|
470
|
-
}),
|
|
486
|
+
}), st = (e, t) => ({
|
|
471
487
|
tables: [...e.keys()],
|
|
472
488
|
predicateFor: (n) => {
|
|
473
489
|
let r = e.get(n);
|
|
474
|
-
return r ? b(
|
|
490
|
+
return r ? b(it(t, n), [...r]) : void 0;
|
|
475
491
|
}
|
|
476
|
-
}),
|
|
492
|
+
}), ct = "tenantId", lt = (e, t, r) => n.gen(function* () {
|
|
477
493
|
let i = t.tables.map((e) => e.name), a = new Map(t.tables.map((e) => [e.name, e]));
|
|
478
494
|
if (e.kind === "all") {
|
|
479
495
|
let t = new Set(e.exclude ?? []);
|
|
480
496
|
return {
|
|
481
|
-
tables: i.filter((e) => !
|
|
497
|
+
tables: i.filter((e) => !V(e) && !t.has(e)),
|
|
482
498
|
predicateFor: () => void 0
|
|
483
499
|
};
|
|
484
500
|
}
|
|
485
501
|
if (e.kind === "tables") {
|
|
486
502
|
let t = e.tables ?? [], r = new Set(i), a = t.filter((e) => !r.has(e));
|
|
487
|
-
if (a.length > 0) return yield* n.fail(new
|
|
503
|
+
if (a.length > 0) return yield* n.fail(new U({ 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}.` }));
|
|
488
504
|
let o = new Set(t);
|
|
489
505
|
return {
|
|
490
506
|
tables: i.filter((e) => o.has(e)),
|
|
@@ -492,30 +508,30 @@ var Ce = (e) => {
|
|
|
492
508
|
};
|
|
493
509
|
}
|
|
494
510
|
let o = e.tenantId;
|
|
495
|
-
if (o === void 0 || o === "") return yield* n.fail(new
|
|
496
|
-
let s = r.tenantTables ? r.tenantTables.filter((e) => a.has(e)) : i.filter((e) => a.get(e)?.columns.some((e) => e.name ===
|
|
497
|
-
if (s.length === 0) return yield* n.fail(new
|
|
498
|
-
let c = yield*
|
|
499
|
-
seeds: Object.fromEntries(s.map((e) => [e, _(
|
|
511
|
+
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." }));
|
|
512
|
+
let s = r.tenantTables ? r.tenantTables.filter((e) => a.has(e)) : i.filter((e) => a.get(e)?.columns.some((e) => e.name === ct) ?? !1);
|
|
513
|
+
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 '${ct}' column — nothing to filter. A tenant export of a schema without tenant-scoped tables would be the full database; refusing.` }));
|
|
514
|
+
let c = yield* ot(r.store, t, {
|
|
515
|
+
seeds: Object.fromEntries(s.map((e) => [e, _(ct, o)])),
|
|
500
516
|
pinned: s,
|
|
501
517
|
children: { roots: s }
|
|
502
518
|
}), l = [...c.entries()].filter(([, e]) => e.size > 0).map(([e]) => e), u = new Set(s);
|
|
503
519
|
return {
|
|
504
520
|
tables: [...s, ...l],
|
|
505
|
-
predicateFor: (e) => u.has(e) ? _(
|
|
521
|
+
predicateFor: (e) => u.has(e) ? _(ct, o) : c.has(e) ? b(it(t, e), [...c.get(e)]) : void 0
|
|
506
522
|
};
|
|
507
|
-
}),
|
|
523
|
+
}), ut = (e, t) => ({
|
|
508
524
|
list: t,
|
|
509
|
-
open: (t) =>
|
|
510
|
-
}),
|
|
511
|
-
write: (t, n, r) =>
|
|
525
|
+
open: (t) => _e(e, t)
|
|
526
|
+
}), dt = (e) => ({
|
|
527
|
+
write: (t, n, r) => k(e, t, n, r),
|
|
512
528
|
has: (t) => e.head(t).pipe(n.map((e) => e !== null))
|
|
513
|
-
}),
|
|
529
|
+
}), ft = (e, t) => n.tryPromise({
|
|
514
530
|
try: async () => {
|
|
515
531
|
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) {
|
|
516
532
|
u.update(e), d += e.length, n(null, e);
|
|
517
533
|
} });
|
|
518
|
-
await o(await
|
|
534
|
+
await o(await A(e.stream), f, n(l));
|
|
519
535
|
let p = u.digest("hex"), m = c.join(t, p);
|
|
520
536
|
try {
|
|
521
537
|
await r.access(m), await r.rm(l, { force: !0 });
|
|
@@ -528,30 +544,30 @@ var Ce = (e) => {
|
|
|
528
544
|
contentType: e.contentType
|
|
529
545
|
};
|
|
530
546
|
},
|
|
531
|
-
catch: (e) => new
|
|
547
|
+
catch: (e) => new H({
|
|
532
548
|
reason: `asset write failed: ${String(e?.message ?? e)}`,
|
|
533
549
|
path: t
|
|
534
550
|
})
|
|
535
|
-
}),
|
|
536
|
-
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 =
|
|
551
|
+
}), pt = (e, t, r) => n.gen(function* () {
|
|
552
|
+
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 = ge("bundle", () => a(s)).pipe(l.tap((e) => n.sync(() => c.update(e))));
|
|
537
553
|
yield* e.write(r.key, u, {
|
|
538
554
|
contentType: r.contentType,
|
|
539
555
|
totalSize: r.size
|
|
540
556
|
});
|
|
541
557
|
let d = c.digest("hex");
|
|
542
|
-
if (d !== r.sha256) return yield* n.fail(new
|
|
558
|
+
if (d !== r.sha256) return yield* n.fail(new Ze({
|
|
543
559
|
what: `asset ${r.key}`,
|
|
544
560
|
expected: r.sha256,
|
|
545
561
|
actual: d
|
|
546
562
|
}));
|
|
547
|
-
}),
|
|
563
|
+
}), mt = {
|
|
548
564
|
done: () => !1,
|
|
549
565
|
mark: () => n.void
|
|
550
|
-
},
|
|
551
|
-
let t = e.progress ??
|
|
552
|
-
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(
|
|
566
|
+
}, ht = (e) => typeof e == "object" && !!e && e.status === 404, gt = (e) => n.gen(function* () {
|
|
567
|
+
let t = e.progress ?? mt, r = 0, i = 0, a = 0, o = 0, s = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Set(), u = [];
|
|
568
|
+
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(ht, () => n.sync(() => {
|
|
553
569
|
u.push(l.key);
|
|
554
|
-
})), n.flatMap((a) => a === void 0 ? n.void :
|
|
570
|
+
})), n.flatMap((a) => a === void 0 ? n.void : ft(a, e.assetsDir).pipe(n.flatMap((e) => {
|
|
555
571
|
let n = {
|
|
556
572
|
key: l.key,
|
|
557
573
|
sha256: e.sha256,
|
|
@@ -559,7 +575,7 @@ var Ce = (e) => {
|
|
|
559
575
|
contentType: e.contentType
|
|
560
576
|
};
|
|
561
577
|
return r++, i += e.size, s.has(e.sha256) || (s.add(e.sha256), o += e.size), t.mark(l.key, n);
|
|
562
|
-
}))))))).pipe(n.mapError((e) => e instanceof
|
|
578
|
+
}))))))).pipe(n.mapError((e) => e instanceof H ? e : new H({ reason: `asset export failed: ${String(e)}` }))), {
|
|
563
579
|
count: r,
|
|
564
580
|
totalBytes: i,
|
|
565
581
|
references: a,
|
|
@@ -567,18 +583,18 @@ var Ce = (e) => {
|
|
|
567
583
|
objectBytes: o,
|
|
568
584
|
missing: u
|
|
569
585
|
};
|
|
570
|
-
}),
|
|
586
|
+
}), _t = (e) => ge("bundle", () => fe(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({
|
|
571
587
|
reason: `asset index unreadable: ${String(t)}`,
|
|
572
588
|
path: e
|
|
573
|
-
}))),
|
|
574
|
-
let t = e.progress ??
|
|
575
|
-
return yield* l.runForEach(
|
|
589
|
+
}))), vt = (e) => n.gen(function* () {
|
|
590
|
+
let t = e.progress ?? mt, r = 0, i = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new Set();
|
|
591
|
+
return yield* l.runForEach(_t(e.indexPath), (o) => t.done(o.key) || a.has(o.key) ? n.void : (a.add(o.key), pt(e.sink, e.assetsDir, o)).pipe(n.andThen(n.sync(() => {
|
|
576
592
|
r++, i.add(o.sha256);
|
|
577
593
|
})), n.andThen(t.mark(o.key, o)))), {
|
|
578
594
|
count: r,
|
|
579
595
|
objects: i.size
|
|
580
596
|
};
|
|
581
|
-
}),
|
|
597
|
+
}), yt = () => typeof j.createZstdCompress == "function", bt = (e) => e === "none" ? "none" : e === "gzip" ? "gzip" : yt() ? "zstd" : "gzip", xt = (e) => e === "zstd" ? ".zst" : e === "gzip" ? ".gz" : "", St = (e) => e === "zstd" ? j.createZstdCompress() : e === "gzip" ? j.createGzip() : new M(), Ct = (e) => e === "zstd" ? j.createZstdDecompress() : e === "gzip" ? j.createGunzip() : new M(), wt = 1, Tt = c.Struct({
|
|
582
598
|
name: c.String,
|
|
583
599
|
file: c.String,
|
|
584
600
|
rowCount: c.Number,
|
|
@@ -588,12 +604,12 @@ var Ce = (e) => {
|
|
|
588
604
|
value: c.String
|
|
589
605
|
}),
|
|
590
606
|
primaryKey: c.String
|
|
591
|
-
}),
|
|
607
|
+
}), Et = c.Struct({
|
|
592
608
|
kind: c.Literal("all", "tenant", "tables"),
|
|
593
609
|
tenantId: c.optional(c.String),
|
|
594
610
|
tables: c.optional(c.Array(c.String)),
|
|
595
611
|
exclude: c.optional(c.Array(c.String))
|
|
596
|
-
}),
|
|
612
|
+
}), Dt = c.Struct({
|
|
597
613
|
count: c.Number,
|
|
598
614
|
totalBytes: c.Number,
|
|
599
615
|
index: c.optional(c.String)
|
|
@@ -604,23 +620,23 @@ c.Struct({
|
|
|
604
620
|
size: c.Number,
|
|
605
621
|
contentType: c.String
|
|
606
622
|
});
|
|
607
|
-
var
|
|
623
|
+
var Ot = c.Struct({
|
|
608
624
|
formatVersion: c.Number,
|
|
609
625
|
createdAt: c.String,
|
|
610
626
|
source: c.Struct({
|
|
611
627
|
dialect: c.String,
|
|
612
628
|
schemaFingerprint: c.String
|
|
613
629
|
}),
|
|
614
|
-
scope:
|
|
630
|
+
scope: Et,
|
|
615
631
|
consistency: c.Literal("live", "snapshot"),
|
|
616
632
|
compression: c.Literal("zstd", "gzip", "none"),
|
|
617
|
-
tables: c.Array(
|
|
618
|
-
assets:
|
|
633
|
+
tables: c.Array(Tt),
|
|
634
|
+
assets: Dt,
|
|
619
635
|
masking: c.optional(c.Struct({
|
|
620
636
|
policyId: c.optional(c.String),
|
|
621
637
|
transformed: c.Array(c.String)
|
|
622
638
|
}))
|
|
623
|
-
}),
|
|
639
|
+
}), kt = c.encodeSync(c.parseJson(Ot)), At = c.decodeUnknownSync(c.parseJson(Ot)), jt = "manifest.json", Mt = "README.md", Nt = "data", Pt = "assets", Ft = "assets/index.ndjson", It = ".ledger.json", Lt = (e) => e.kind === "tenant" ? `tenant \`${e.tenantId}\`` : e.kind === "tables" ? `tables \`${(e.tables ?? []).join(", ")}\`` : "all tables", Rt = (e, t) => {
|
|
624
640
|
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");
|
|
625
641
|
return `# Voltro data export
|
|
626
642
|
|
|
@@ -634,7 +650,7 @@ The machine-readable manifest is \`manifest.json\`; this file is a human summary
|
|
|
634
650
|
| **Format version** | ${e.formatVersion} |
|
|
635
651
|
| **Consistency** | ${e.consistency} |
|
|
636
652
|
| **Compression** | ${e.compression} |
|
|
637
|
-
| **Scope** | ${
|
|
653
|
+
| **Scope** | ${Lt(e.scope)} |
|
|
638
654
|
| **Tables** | ${e.tables.length} |
|
|
639
655
|
| **Rows (total)** | ${n} |
|
|
640
656
|
| **Assets** | ${a} |
|
|
@@ -659,39 +675,39 @@ voltro data import <this-directory>
|
|
|
659
675
|
voltro data import <this-directory> --target api --api-url <url> --token <secret>
|
|
660
676
|
\`\`\`
|
|
661
677
|
`;
|
|
662
|
-
},
|
|
678
|
+
}, zt = i.counter("voltro_data_transfer_rows", { description: "Rows exported/imported by @voltro/data-transfer, tagged by phase + table." }), Bt = a.exponential({
|
|
663
679
|
start: .01,
|
|
664
680
|
factor: 2,
|
|
665
681
|
count: 16
|
|
666
|
-
}),
|
|
682
|
+
}), Vt = i.histogram("voltro_data_transfer_table_seconds", Bt, "Per-table export/import duration in seconds, tagged by phase."), G = (e, t) => {
|
|
667
683
|
if (e) try {
|
|
668
684
|
e(t);
|
|
669
685
|
} catch {}
|
|
670
|
-
},
|
|
686
|
+
}, Ht = (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(Vt.pipe(i.tagged("phase", e), i.update((s - r) / 1e3)), zt.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: {
|
|
671
687
|
table: t,
|
|
672
688
|
index: r,
|
|
673
689
|
tableCount: a,
|
|
674
690
|
phase: e
|
|
675
|
-
} })),
|
|
691
|
+
} })), Ut = () => ({
|
|
676
692
|
tables: {},
|
|
677
693
|
assets: {}
|
|
678
|
-
}),
|
|
694
|
+
}), Wt = (e) => n.tryPromise(async () => {
|
|
679
695
|
let t = await (await import("node:fs/promises")).readFile(e, "utf8");
|
|
680
696
|
return JSON.parse(t);
|
|
681
|
-
}).pipe(n.orElseSucceed(
|
|
697
|
+
}).pipe(n.orElseSucceed(Ut)), K = (e, t) => n.tryPromise({
|
|
682
698
|
try: async () => {
|
|
683
699
|
let n = await import("node:fs/promises"), { randomUUID: r } = await import("node:crypto"), i = `${e}.tmp-${r()}`;
|
|
684
700
|
await n.writeFile(i, JSON.stringify(t)), await n.rename(i, e);
|
|
685
701
|
},
|
|
686
|
-
catch: (t) => new
|
|
702
|
+
catch: (t) => new H({
|
|
687
703
|
reason: `ledger write failed: ${String(t?.message ?? t)}`,
|
|
688
704
|
path: e
|
|
689
705
|
})
|
|
690
|
-
}),
|
|
706
|
+
}), Gt = (e, t) => t in e.tables, Kt = (e, t) => t in e.assets, qt = /* @__PURE__ */ new Set([
|
|
691
707
|
"json",
|
|
692
708
|
"array",
|
|
693
709
|
"vector"
|
|
694
|
-
]),
|
|
710
|
+
]), Jt = (e) => typeof e == "object" && !!e && !Array.isArray(e) && typeof e.$v == "string", Yt = (e) => Buffer.from(e).toString("base64"), Xt = (e) => new Uint8Array(Buffer.from(e, "base64")), Zt = (e) => e instanceof Date ? e.toISOString() : typeof e == "number" ? new Date(e).toISOString() : String(e), Qt = (e, t) => e == null ? null : t !== void 0 && qt.has(t) ? e : t === "bytes" ? Yt(e) : t === "timestamp" || t === "date" ? Zt(e) : typeof e == "bigint" ? {
|
|
695
711
|
$v: "bigint",
|
|
696
712
|
d: e.toString()
|
|
697
713
|
} : typeof e == "number" && !Number.isFinite(e) ? {
|
|
@@ -702,30 +718,30 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
702
718
|
d: e.toISOString()
|
|
703
719
|
} : e instanceof Uint8Array ? {
|
|
704
720
|
$v: "bytes",
|
|
705
|
-
d:
|
|
706
|
-
} : e,
|
|
721
|
+
d: Yt(e)
|
|
722
|
+
} : e, $t = (e) => {
|
|
707
723
|
switch (e.$v) {
|
|
708
724
|
case "bigint": return BigInt(e.d);
|
|
709
725
|
case "number": return Number(e.d);
|
|
710
726
|
case "date": return new Date(e.d);
|
|
711
|
-
case "bytes": return
|
|
727
|
+
case "bytes": return Xt(e.d);
|
|
712
728
|
default: return e;
|
|
713
729
|
}
|
|
714
|
-
},
|
|
730
|
+
}, en = (e, t) => e == null ? null : t !== void 0 && qt.has(t) ? e : Jt(e) ? $t(e) : t === "bytes" ? Xt(e) : t === "timestamp" || t === "date" ? new Date(e) : e, tn = (e, t) => {
|
|
715
731
|
let n = {};
|
|
716
|
-
for (let [r, i] of Object.entries(e)) n[r] =
|
|
732
|
+
for (let [r, i] of Object.entries(e)) n[r] = Qt(i, t[r]);
|
|
717
733
|
return n;
|
|
718
|
-
},
|
|
734
|
+
}, nn = (e, t) => {
|
|
719
735
|
let n = {};
|
|
720
|
-
for (let [r, i] of Object.entries(e)) n[r] =
|
|
736
|
+
for (let [r, i] of Object.entries(e)) n[r] = en(i, t[r]);
|
|
721
737
|
return n;
|
|
722
|
-
},
|
|
723
|
-
try: () =>
|
|
724
|
-
catch: (e) => new
|
|
738
|
+
}, rn = new TextEncoder(), an = (e, t) => e.pipe(l.map((e) => rn.encode(`${JSON.stringify(tn(e, t))}\n`))), on = (e, t, r) => e.pipe(l.decodeText(), l.splitLines, l.filter((e) => e.trim().length > 0), l.mapEffect((e) => n.try({
|
|
739
|
+
try: () => nn(JSON.parse(e), r),
|
|
740
|
+
catch: (e) => new Xe({
|
|
725
741
|
table: t,
|
|
726
742
|
reason: String(e?.message ?? e)
|
|
727
743
|
})
|
|
728
|
-
}))),
|
|
744
|
+
}))), sn = (e, t) => {
|
|
729
745
|
let n = new Set(e), r = /* @__PURE__ */ new Map();
|
|
730
746
|
for (let e of t.tables) {
|
|
731
747
|
if (!n.has(e.name)) continue;
|
|
@@ -745,39 +761,39 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
745
761
|
};
|
|
746
762
|
for (let t of e) n.has(t) && s(t);
|
|
747
763
|
return i;
|
|
748
|
-
},
|
|
764
|
+
}, q = (e) => {
|
|
749
765
|
let t = e, n = [];
|
|
750
766
|
typeof t?._tag == "string" && t._tag !== "" && n.push(t._tag);
|
|
751
767
|
let r = typeof t?.message == "string" ? t.message.trim() : "";
|
|
752
|
-
if (r === "" ? t?.cause !== void 0 && t.cause !== null && n.push(
|
|
768
|
+
if (r === "" ? t?.cause !== void 0 && t.cause !== null && n.push(q(t.cause)) : n.push(r), n.length === 0) {
|
|
753
769
|
let t = String(e ?? "").trim();
|
|
754
|
-
return t === "" || t === "[object Object]" ?
|
|
770
|
+
return t === "" || t === "[object Object]" ? cn(e) : t;
|
|
755
771
|
}
|
|
756
772
|
return n.join(": ");
|
|
757
|
-
},
|
|
773
|
+
}, cn = (e) => {
|
|
758
774
|
try {
|
|
759
775
|
let t = JSON.stringify(e);
|
|
760
776
|
return t === void 0 || t === "{}" ? "unknown error (no message, cause or tag)" : t;
|
|
761
777
|
} catch {
|
|
762
778
|
return "unknown error (not serialisable)";
|
|
763
779
|
}
|
|
764
|
-
},
|
|
780
|
+
}, ln = (e, t) => {
|
|
765
781
|
let n = e.tables.find((e) => e.name === t), r = {};
|
|
766
782
|
for (let e of n?.columns ?? []) e.generatedAs === void 0 && (r[e.name] = e.type);
|
|
767
783
|
return r;
|
|
768
|
-
},
|
|
784
|
+
}, un = (e, t) => (e.tables.find((e) => e.name === t)?.columns ?? []).filter((e) => e.generatedAs !== void 0).map((e) => e.name), dn = (e, t) => {
|
|
769
785
|
if (t.length === 0) return e;
|
|
770
786
|
let n = { ...e };
|
|
771
787
|
for (let e of t) delete n[e];
|
|
772
788
|
return n;
|
|
773
|
-
},
|
|
789
|
+
}, fn = (e, t) => {
|
|
774
790
|
let n = e.tables.find((e) => e.name === t);
|
|
775
791
|
if (n === void 0) return { refusal: `${t}: not in the schema snapshot, so its primary key is unknown.` };
|
|
776
792
|
let r = n.columns.find((e) => e.type === "id");
|
|
777
793
|
if (r !== void 0) return { column: r.name };
|
|
778
794
|
let i = n.indexes.find((e) => e.name === `${t}_pkey`)?.columns ?? n.primaryKey ?? [];
|
|
779
795
|
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.` };
|
|
780
|
-
},
|
|
796
|
+
}, pn = (e, t, r) => n.tryPromise({
|
|
781
797
|
try: async () => {
|
|
782
798
|
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) {
|
|
783
799
|
d.update(e);
|
|
@@ -786,7 +802,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
786
802
|
n(null, e);
|
|
787
803
|
} }), m = c.fromWeb(l.toReadableStream(e)), h = `${t}.tmp-${o()}`;
|
|
788
804
|
try {
|
|
789
|
-
await s(m, p,
|
|
805
|
+
await s(m, p, St(r), n(h)), await i.rename(h, t);
|
|
790
806
|
} catch (e) {
|
|
791
807
|
throw await i.rm(h, { force: !0 }).catch(() => {}), e;
|
|
792
808
|
}
|
|
@@ -795,27 +811,27 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
795
811
|
checksum: d.digest("hex")
|
|
796
812
|
};
|
|
797
813
|
},
|
|
798
|
-
catch: (e) => new
|
|
799
|
-
reason: `write table failed: ${
|
|
814
|
+
catch: (e) => new H({
|
|
815
|
+
reason: `write table failed: ${q(e)}`,
|
|
800
816
|
path: t
|
|
801
817
|
})
|
|
802
|
-
}),
|
|
818
|
+
}), mn = (e, t) => n.tryPromise({
|
|
803
819
|
try: async () => {
|
|
804
820
|
await (await import("node:fs/promises")).appendFile(e, `${t}\n`);
|
|
805
821
|
},
|
|
806
|
-
catch: (t) => new
|
|
807
|
-
reason: `append failed: ${
|
|
822
|
+
catch: (t) => new H({
|
|
823
|
+
reason: `append failed: ${q(t)}`,
|
|
808
824
|
path: e
|
|
809
825
|
})
|
|
810
|
-
}),
|
|
826
|
+
}), hn = (e, t) => n.gen(function* () {
|
|
811
827
|
let r = [], i = t.ordered.length;
|
|
812
828
|
for (let a = 0; a < t.ordered.length; a++) {
|
|
813
|
-
let o = t.ordered[a], s =
|
|
814
|
-
if ("refusal" in c) return yield* n.fail(new
|
|
815
|
-
let u = c.column, d = `${
|
|
816
|
-
if (
|
|
829
|
+
let o = t.ordered[a], s = ln(t.snapshot, o), c = fn(t.snapshot, o);
|
|
830
|
+
if ("refusal" in c) return yield* n.fail(new U({ reason: `export: ${c.refusal}` }));
|
|
831
|
+
let u = c.column, d = `${Nt}/${o}.ndjson${xt(t.compression)}`;
|
|
832
|
+
if (Gt(t.ledger, o)) {
|
|
817
833
|
let e = t.ledger.tables[o];
|
|
818
|
-
|
|
834
|
+
G(t.onProgress, {
|
|
819
835
|
phase: "export",
|
|
820
836
|
table: o,
|
|
821
837
|
index: a,
|
|
@@ -833,7 +849,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
833
849
|
});
|
|
834
850
|
continue;
|
|
835
851
|
}
|
|
836
|
-
|
|
852
|
+
G(t.onProgress, {
|
|
837
853
|
phase: "export",
|
|
838
854
|
table: o,
|
|
839
855
|
index: a,
|
|
@@ -841,17 +857,17 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
841
857
|
event: "start",
|
|
842
858
|
rowsDone: 0
|
|
843
859
|
});
|
|
844
|
-
let f = t.resolved.predicateFor(o), p =
|
|
860
|
+
let f = t.resolved.predicateFor(o), p = C(e, {
|
|
845
861
|
table: o,
|
|
846
862
|
pk: u,
|
|
847
863
|
chunkSize: t.chunkSize,
|
|
848
864
|
retry: t.retry,
|
|
849
865
|
...f === void 0 ? {} : { where: f }
|
|
850
|
-
}), m =
|
|
866
|
+
}), m = un(t.snapshot, o), h = m.length === 0 ? p : p.pipe(l.map((e) => dn(e, m))), g = t.mask ? h.pipe(l.map((e) => Ge(e, o, t.mask.actions, t.mask.seed, s))) : h, { rowCount: _, checksum: v } = yield* Ht("export", o, a, i, (e) => e.rowCount, pn(an(g, s), t.bundleFile(d), t.compression));
|
|
851
867
|
t.ledger.tables[o] = {
|
|
852
868
|
rowCount: _,
|
|
853
869
|
checksum: v
|
|
854
|
-
}, yield*
|
|
870
|
+
}, yield* K(t.ledgerPath, t.ledger), G(t.onProgress, {
|
|
855
871
|
phase: "export",
|
|
856
872
|
table: o,
|
|
857
873
|
index: a,
|
|
@@ -869,43 +885,43 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
869
885
|
});
|
|
870
886
|
}
|
|
871
887
|
return r;
|
|
872
|
-
}),
|
|
888
|
+
}), gn = (e) => ({
|
|
873
889
|
_tag: "RawSqlFragment",
|
|
874
890
|
strings: [e],
|
|
875
891
|
values: []
|
|
876
|
-
}),
|
|
892
|
+
}), _n = (t, i, a) => n.tryPromise({
|
|
877
893
|
try: () => t.transactional(async (t) => {
|
|
878
|
-
if (t.raw) for (let e of
|
|
894
|
+
if (t.raw) for (let e of Ee(i)) await t.raw(gn(e));
|
|
879
895
|
let o = await n.runPromiseExit(a(t));
|
|
880
896
|
if (r.isFailure(o)) throw Error(e.pretty(o.cause));
|
|
881
897
|
return o.value;
|
|
882
898
|
}),
|
|
883
|
-
catch: (e) => e instanceof
|
|
884
|
-
}),
|
|
885
|
-
let t = e.scope ?? { kind: "all" }, r =
|
|
899
|
+
catch: (e) => e instanceof H ? e : new H({ reason: `snapshot export failed: ${q(e)}` })
|
|
900
|
+
}), vn = (e) => n.gen(function* () {
|
|
901
|
+
let t = e.scope ?? { kind: "all" }, r = bt(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);
|
|
886
902
|
yield* n.tryPromise({
|
|
887
903
|
try: async () => {
|
|
888
904
|
let t = await import("node:fs/promises");
|
|
889
|
-
await t.mkdir(l(
|
|
905
|
+
await t.mkdir(l(Nt), { recursive: !0 }), e.assets && await t.mkdir(l(Pt), { recursive: !0 });
|
|
890
906
|
},
|
|
891
|
-
catch: (t) => new
|
|
892
|
-
reason: `mkdir failed: ${
|
|
907
|
+
catch: (t) => new H({
|
|
908
|
+
reason: `mkdir failed: ${q(t)}`,
|
|
893
909
|
path: e.outDir
|
|
894
910
|
})
|
|
895
911
|
});
|
|
896
|
-
let u = l(
|
|
912
|
+
let u = l(It), d = yield* Wt(u), f = e.subset ? st(yield* ot(e.store, e.snapshot, e.subset), e.snapshot) : yield* lt(t, e.snapshot, {
|
|
897
913
|
store: e.store,
|
|
898
914
|
...e.tenantTables ? { tenantTables: e.tenantTables } : {}
|
|
899
|
-
}), p =
|
|
915
|
+
}), p = sn(f.tables, e.snapshot), m = e.consistency ?? "live", h, g;
|
|
900
916
|
if (e.masking) {
|
|
901
|
-
let t = e.classification ??
|
|
917
|
+
let t = e.classification ?? Oe(e.snapshot), r = He(p.map((t) => ({
|
|
902
918
|
name: t,
|
|
903
919
|
columns: (e.snapshot.tables.find((e) => e.name === t)?.columns ?? []).map((e) => ({
|
|
904
920
|
name: e.name,
|
|
905
921
|
type: e.type
|
|
906
922
|
}))
|
|
907
923
|
})), t, e.masking);
|
|
908
|
-
if (r.unclassified.length > 0 || r.invalid.length > 0) return yield* n.fail(new
|
|
924
|
+
if (r.unclassified.length > 0 || r.invalid.length > 0) return yield* n.fail(new tt({
|
|
909
925
|
unclassified: r.unclassified,
|
|
910
926
|
...r.invalid.length > 0 ? { invalidActions: r.invalid.map((e) => `${e.column}: ${JSON.stringify(e.action)}`) } : {}
|
|
911
927
|
}));
|
|
@@ -931,14 +947,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
931
947
|
bundleFile: l,
|
|
932
948
|
...g ? { mask: g } : {},
|
|
933
949
|
...e.onProgress ? { onProgress: e.onProgress } : {}
|
|
934
|
-
}, v = m === "snapshot" ? yield*
|
|
950
|
+
}, v = m === "snapshot" ? yield* _n(e.store, e.dialect, (e) => hn(e, _)) : yield* hn(e.store, _), y = 0, b = 0;
|
|
935
951
|
if (e.assets) {
|
|
936
|
-
let t = l(
|
|
952
|
+
let t = l(Ft), r = yield* gt({
|
|
937
953
|
source: e.assets,
|
|
938
|
-
assetsDir: l(
|
|
954
|
+
assetsDir: l(Pt),
|
|
939
955
|
progress: {
|
|
940
956
|
done: (e) => e in d.assets,
|
|
941
|
-
mark: (e, r) => (d.assets[e] = !0,
|
|
957
|
+
mark: (e, r) => (d.assets[e] = !0, mn(t, JSON.stringify(r)).pipe(n.andThen(K(u, d))))
|
|
942
958
|
}
|
|
943
959
|
});
|
|
944
960
|
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` : "")));
|
|
@@ -948,7 +964,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
948
964
|
createdAt: e.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
949
965
|
source: {
|
|
950
966
|
dialect: e.dialect,
|
|
951
|
-
schemaFingerprint:
|
|
967
|
+
schemaFingerprint: w(e.snapshot)
|
|
952
968
|
},
|
|
953
969
|
scope: t,
|
|
954
970
|
consistency: m,
|
|
@@ -957,7 +973,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
957
973
|
assets: y > 0 ? {
|
|
958
974
|
count: y,
|
|
959
975
|
totalBytes: b,
|
|
960
|
-
index:
|
|
976
|
+
index: Ft
|
|
961
977
|
} : {
|
|
962
978
|
count: 0,
|
|
963
979
|
totalBytes: 0
|
|
@@ -966,23 +982,23 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
966
982
|
};
|
|
967
983
|
return yield* n.tryPromise({
|
|
968
984
|
try: async () => {
|
|
969
|
-
await (await import("node:fs/promises")).writeFile(l(
|
|
985
|
+
await (await import("node:fs/promises")).writeFile(l(jt), kt(x));
|
|
970
986
|
},
|
|
971
|
-
catch: (e) => new
|
|
972
|
-
reason: `manifest write failed: ${
|
|
973
|
-
path:
|
|
987
|
+
catch: (e) => new H({
|
|
988
|
+
reason: `manifest write failed: ${q(e)}`,
|
|
989
|
+
path: jt
|
|
974
990
|
})
|
|
975
991
|
}), yield* n.tryPromise({
|
|
976
992
|
try: async () => {
|
|
977
993
|
let e = await import("node:fs/promises"), t = await import("node:os");
|
|
978
|
-
await e.writeFile(l(
|
|
994
|
+
await e.writeFile(l(Mt), Rt(x, { hostname: t.hostname() }));
|
|
979
995
|
},
|
|
980
|
-
catch: (e) => new
|
|
981
|
-
reason: `readme write failed: ${
|
|
982
|
-
path:
|
|
996
|
+
catch: (e) => new H({
|
|
997
|
+
reason: `readme write failed: ${q(e)}`,
|
|
998
|
+
path: Mt
|
|
983
999
|
})
|
|
984
1000
|
}), x;
|
|
985
|
-
}),
|
|
1001
|
+
}), yn = (e, t) => {
|
|
986
1002
|
let n = new Set(t), r = [];
|
|
987
1003
|
for (let t of e.tables) if (!n.has(t.name)) for (let e of t.columns) {
|
|
988
1004
|
let i = e.references?.table;
|
|
@@ -993,7 +1009,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
993
1009
|
});
|
|
994
1010
|
}
|
|
995
1011
|
return r;
|
|
996
|
-
},
|
|
1012
|
+
}, bn = (e) => {
|
|
997
1013
|
let t = /* @__PURE__ */ new Map();
|
|
998
1014
|
for (let n of e) t.set(n.from, [...t.get(n.from) ?? [], n]);
|
|
999
1015
|
let n = [...t.entries()].map(([e, t]) => {
|
|
@@ -1001,7 +1017,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1001
1017
|
return ` ${e} (${n} row${n === 1 ? "" : "s"}): ${r}`;
|
|
1002
1018
|
});
|
|
1003
1019
|
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.`;
|
|
1004
|
-
},
|
|
1020
|
+
}, xn = (e) => {
|
|
1005
1021
|
switch (e) {
|
|
1006
1022
|
case "id":
|
|
1007
1023
|
case "text":
|
|
@@ -1020,12 +1036,12 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1020
1036
|
case "raw": return "raw";
|
|
1021
1037
|
default: return "string";
|
|
1022
1038
|
}
|
|
1023
|
-
},
|
|
1039
|
+
}, Sn = {
|
|
1024
1040
|
vector: /* @__PURE__ */ new Set(["postgres"]),
|
|
1025
1041
|
array: /* @__PURE__ */ new Set(["postgres"]),
|
|
1026
1042
|
interval: /* @__PURE__ */ new Set(["postgres"])
|
|
1027
|
-
},
|
|
1028
|
-
let i =
|
|
1043
|
+
}, Cn = (e, t, n, r) => {
|
|
1044
|
+
let i = xn(n);
|
|
1029
1045
|
if (i === "raw") return {
|
|
1030
1046
|
table: e,
|
|
1031
1047
|
column: t,
|
|
@@ -1033,7 +1049,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1033
1049
|
severity: "block",
|
|
1034
1050
|
reason: `raw() is verbatim source-dialect SQL — it cannot be assumed valid on ${r}`
|
|
1035
1051
|
};
|
|
1036
|
-
let a =
|
|
1052
|
+
let a = Sn[i];
|
|
1037
1053
|
return !a || a.has(r) ? null : i === "array" || i === "interval" ? {
|
|
1038
1054
|
table: e,
|
|
1039
1055
|
column: t,
|
|
@@ -1047,15 +1063,15 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1047
1063
|
severity: "block",
|
|
1048
1064
|
reason: `${i} columns require a ${[...a].join("/")} target; ${r} has no compatible column type`
|
|
1049
1065
|
};
|
|
1050
|
-
},
|
|
1066
|
+
}, wn = (e, t, n) => {
|
|
1051
1067
|
if (t === n) return [];
|
|
1052
1068
|
let r = [];
|
|
1053
1069
|
for (let t of e) for (let [e, i] of Object.entries(t.columnTypes)) {
|
|
1054
|
-
let a =
|
|
1070
|
+
let a = Cn(t.name, e, i, n);
|
|
1055
1071
|
a && r.push(a);
|
|
1056
1072
|
}
|
|
1057
1073
|
return r;
|
|
1058
|
-
},
|
|
1074
|
+
}, Tn = (e) => `[${e.severity}] ${e.table}.${e.column} (${e.type}): ${e.reason}`, En = (e) => {
|
|
1059
1075
|
let t = e.constraint ?? e.column, n = t === void 0 ? "" : ` ${t}`;
|
|
1060
1076
|
switch (e.kind) {
|
|
1061
1077
|
case "foreignKey": return `foreign key${n}: the referenced row does not exist (import it first, or check the bundle's table order)`;
|
|
@@ -1064,36 +1080,36 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1064
1080
|
case "notNull": return `not-null constraint${n}: the column requires a value`;
|
|
1065
1081
|
case "check": return `check constraint${n}: the row does not satisfy it`;
|
|
1066
1082
|
}
|
|
1067
|
-
},
|
|
1083
|
+
}, Dn = (e) => {
|
|
1068
1084
|
let t = [e.dbCode, e.dbErrno ?? e.dbNumber].filter((e) => e !== void 0).map(String);
|
|
1069
1085
|
return t.length > 0 ? t.join("/") : void 0;
|
|
1070
|
-
},
|
|
1086
|
+
}, On = "Failed to execute statement", kn = (e) => {
|
|
1071
1087
|
let t = (e.split("\n", 1)[0] ?? "").trim();
|
|
1072
1088
|
for (; t.startsWith("(FiberFailure)");) t = t.slice(14).trim();
|
|
1073
|
-
return t === `SqlError: ${
|
|
1074
|
-
},
|
|
1089
|
+
return t === `SqlError: ${On}` ? On : t;
|
|
1090
|
+
}, An = (e) => {
|
|
1075
1091
|
let t = String(e?.stack ?? e), n = t.length <= 1200 ? t : `${t.slice(0, 1200)}…`, r = (e, t) => ({
|
|
1076
1092
|
reason: e.length <= 300 ? e : `${e.slice(0, 300)}…`,
|
|
1077
1093
|
unclassified: t,
|
|
1078
1094
|
raw: n
|
|
1079
|
-
}), i = v(e), a = m(i), o =
|
|
1080
|
-
if (a !== void 0) return r(`${
|
|
1081
|
-
let c = typeof i.dbMessage == "string" ? i.dbMessage : void 0, l = e?.message, u =
|
|
1082
|
-
return r(d ===
|
|
1083
|
-
},
|
|
1095
|
+
}), i = v(e), a = m(i), o = Dn(i), s = o === void 0 ? "" : ` [${o}]`;
|
|
1096
|
+
if (a !== void 0) return r(`${En(a)}${s}`, !1);
|
|
1097
|
+
let c = typeof i.dbMessage == "string" ? i.dbMessage : void 0, l = e?.message, u = kn(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, p = f !== void 0 && /[←‖]/.test(f) ? ` (via ${f})` : "";
|
|
1098
|
+
return r(d === On || d.length === 0 ? `the database refused the write and the driver gave no detail${s}${p}` : `${d}${s}`, d === On || d.length === 0);
|
|
1099
|
+
}, jn = (e) => An(e).reason, Mn = (e) => {
|
|
1084
1100
|
let t = v(e), n = m(t);
|
|
1085
1101
|
if (n?.kind === "foreignKeyInUse") {
|
|
1086
|
-
let e = n.constraint ?? n.column, r = e === void 0 ? "" : ` ${e}`, i =
|
|
1102
|
+
let e = n.constraint ?? n.column, r = e === void 0 ? "" : ` ${e}`, i = Dn(t);
|
|
1087
1103
|
return `foreign key${r}: rows elsewhere still reference this table${i === void 0 ? "" : ` [${i}]`}`;
|
|
1088
1104
|
}
|
|
1089
|
-
return
|
|
1090
|
-
},
|
|
1105
|
+
return jn(e);
|
|
1106
|
+
}, Nn = f, J = (e) => `${Nn}${e}`, Pn = (e) => typeof e.run == "function", Fn = (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
|
|
1091
1107
|
process that dies mid-load depends on the database rolling it back. The rollback capture
|
|
1092
|
-
written before the first delete is what covers that case.`,
|
|
1093
|
-
if (!
|
|
1108
|
+
written before the first delete is what covers that case.`, In = /^[a-zA-Z_][a-zA-Z0-9_]*$/, Y = (e, t) => {
|
|
1109
|
+
if (!In.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.`);
|
|
1094
1110
|
return t === "mysql" || t === "mariadb" ? `\`${e}\`` : t === "mssql" ? `[${e}]` : `"${e}"`;
|
|
1095
|
-
},
|
|
1096
|
-
let n =
|
|
1111
|
+
}, Ln = (e, t) => {
|
|
1112
|
+
let n = Y(e, t), r = Y(J(e), t);
|
|
1097
1113
|
switch (t) {
|
|
1098
1114
|
case "postgres": return `CREATE TABLE ${r} (LIKE ${n})`;
|
|
1099
1115
|
case "mysql":
|
|
@@ -1101,20 +1117,20 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1101
1117
|
case "sqlite": return `CREATE TABLE ${r} AS SELECT * FROM ${n} WHERE 0`;
|
|
1102
1118
|
case "mssql": return `SELECT * INTO ${r} FROM ${n} WHERE 1 = 0`;
|
|
1103
1119
|
}
|
|
1104
|
-
},
|
|
1105
|
-
let n =
|
|
1106
|
-
return t === "mssql" ? `IF OBJECT_ID('${
|
|
1107
|
-
},
|
|
1120
|
+
}, Rn = (e, t) => {
|
|
1121
|
+
let n = Y(J(e), t);
|
|
1122
|
+
return t === "mssql" ? `IF OBJECT_ID('${J(e)}', 'U') IS NOT NULL DROP TABLE ${n}` : `DROP TABLE IF EXISTS ${n}`;
|
|
1123
|
+
}, zn = (e, t) => {
|
|
1108
1124
|
let n = t === "mysql" || t === "mariadb", r = [];
|
|
1109
1125
|
n && r.push("SET FOREIGN_KEY_CHECKS = 0");
|
|
1110
|
-
for (let n of [...e].reverse()) r.push(`DELETE FROM ${
|
|
1126
|
+
for (let n of [...e].reverse()) r.push(`DELETE FROM ${Y(n.name, t)}`);
|
|
1111
1127
|
for (let n of e) {
|
|
1112
1128
|
if (n.columns.length === 0) throw Error(`refusing to build a swap for '${n.name}' with no columns: an empty list would have to mean \`SELECT *\`, which is the shape that fails on a generated column.`);
|
|
1113
|
-
let e = n.columns.map((e) =>
|
|
1114
|
-
r.push(`INSERT INTO ${
|
|
1129
|
+
let e = n.columns.map((e) => Y(e, t)).join(", ");
|
|
1130
|
+
r.push(`INSERT INTO ${Y(n.name, t)} (${e}) SELECT ${e} FROM ${Y(J(n.name), t)}`);
|
|
1115
1131
|
}
|
|
1116
1132
|
return n && r.push("SET FOREIGN_KEY_CHECKS = 1"), r;
|
|
1117
|
-
},
|
|
1133
|
+
}, Bn = (e, t) => {
|
|
1118
1134
|
let n = [], r = () => {
|
|
1119
1135
|
for (let e of n) t.unregisterTable(e);
|
|
1120
1136
|
};
|
|
@@ -1122,7 +1138,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1122
1138
|
for (let r of e) {
|
|
1123
1139
|
let e = t.getTable(r);
|
|
1124
1140
|
if (e === void 0) continue;
|
|
1125
|
-
let i =
|
|
1141
|
+
let i = J(r);
|
|
1126
1142
|
t.registerTable({
|
|
1127
1143
|
...e,
|
|
1128
1144
|
tableName: i,
|
|
@@ -1136,7 +1152,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1136
1152
|
staged: n,
|
|
1137
1153
|
undo: r
|
|
1138
1154
|
};
|
|
1139
|
-
},
|
|
1155
|
+
}, Vn = (e, t) => {
|
|
1140
1156
|
let n = new Set(t), r = [];
|
|
1141
1157
|
for (let t of e.tables) {
|
|
1142
1158
|
if (!n.has(t.name)) continue;
|
|
@@ -1153,22 +1169,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1153
1169
|
}
|
|
1154
1170
|
}
|
|
1155
1171
|
return r;
|
|
1156
|
-
},
|
|
1157
|
-
let n =
|
|
1158
|
-
return `SELECT ${
|
|
1159
|
-
},
|
|
1172
|
+
}, Hn = (e, t) => {
|
|
1173
|
+
let n = Y(J(e.from), t), r = Y(J(e.to), t), i = Y(e.column, t), a = Y(e.toColumn, t);
|
|
1174
|
+
return `SELECT ${Y(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})`;
|
|
1175
|
+
}, Un = (e) => {
|
|
1160
1176
|
if (e.length === 0) return;
|
|
1161
1177
|
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}`);
|
|
1162
1178
|
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.";
|
|
1163
|
-
},
|
|
1164
|
-
t.length !== 0 && await e.run(
|
|
1165
|
-
},
|
|
1166
|
-
let i =
|
|
1167
|
-
i.length !== 0 && await e.run(
|
|
1168
|
-
},
|
|
1179
|
+
}, Wn = async (e, t) => {
|
|
1180
|
+
t.length !== 0 && await e.run(N.SqlClient.pipe(n.flatMap((e) => n.forEach(t, (t) => e.unsafe(t), { discard: !0 }))));
|
|
1181
|
+
}, Gn = async (e, t, r) => {
|
|
1182
|
+
let i = zn(t, r);
|
|
1183
|
+
i.length !== 0 && await e.run(N.SqlClient.pipe(n.flatMap((e) => e.withTransaction(n.forEach(i, (t) => e.unsafe(t), { discard: !0 })))));
|
|
1184
|
+
}, Kn = async (e, t, r) => {
|
|
1169
1185
|
let i = [];
|
|
1170
1186
|
for (let a of t) {
|
|
1171
|
-
let t = await e.run(
|
|
1187
|
+
let t = await e.run(N.SqlClient.pipe(n.flatMap((e) => e.unsafe(Hn(a, r)))));
|
|
1172
1188
|
for (let e of t) i.push({
|
|
1173
1189
|
table: a.from,
|
|
1174
1190
|
primaryKey: String(e.pk ?? ""),
|
|
@@ -1178,14 +1194,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1178
1194
|
});
|
|
1179
1195
|
}
|
|
1180
1196
|
return i;
|
|
1181
|
-
},
|
|
1197
|
+
}, qn = (e, t) => {
|
|
1182
1198
|
let n = new Map(t.map((e, t) => [e, t]));
|
|
1183
1199
|
return e.filter((e) => {
|
|
1184
1200
|
if (e.from === e.to) return !1;
|
|
1185
1201
|
let t = n.get(e.from), r = n.get(e.to);
|
|
1186
1202
|
return t === void 0 || r === void 0 ? !1 : r > t;
|
|
1187
1203
|
});
|
|
1188
|
-
},
|
|
1204
|
+
}, Jn = (e) => e === "mysql" || e === "mariadb", Yn = (e) => {
|
|
1189
1205
|
if (e.mode !== "replace") return {
|
|
1190
1206
|
active: !1,
|
|
1191
1207
|
tables: [],
|
|
@@ -1235,7 +1251,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1235
1251
|
tables: [],
|
|
1236
1252
|
blocker: "every table in the bundle is one that describes a deployment, so there is nothing for a staged swap to move."
|
|
1237
1253
|
};
|
|
1238
|
-
let s = o.map((e) => e.name), c =
|
|
1254
|
+
let s = o.map((e) => e.name), c = Jn(t) ? [] : qn(Vn(n, s), s);
|
|
1239
1255
|
return c.length > 0 ? {
|
|
1240
1256
|
active: !1,
|
|
1241
1257
|
tables: [],
|
|
@@ -1244,9 +1260,9 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1244
1260
|
active: !0,
|
|
1245
1261
|
tables: o
|
|
1246
1262
|
};
|
|
1247
|
-
},
|
|
1263
|
+
}, Xn = (e) => n.gen(function* () {
|
|
1248
1264
|
if (e.mode !== "replace" || e.dir === void 0 || e.tables.length === 0) return;
|
|
1249
|
-
if (e.snapshot === void 0) return yield* n.fail(new
|
|
1265
|
+
if (e.snapshot === void 0) return yield* n.fail(new H({
|
|
1250
1266
|
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.",
|
|
1251
1267
|
path: e.dir
|
|
1252
1268
|
}));
|
|
@@ -1257,14 +1273,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1257
1273
|
if (t.tables.length === 0) return;
|
|
1258
1274
|
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,
|
|
1259
1275
|
so it survives a run whose process does not.`);
|
|
1260
|
-
let r = yield*
|
|
1276
|
+
let r = yield* vn({
|
|
1261
1277
|
store: e.store,
|
|
1262
1278
|
snapshot: t,
|
|
1263
1279
|
dialect: e.dialect ?? "unknown",
|
|
1264
1280
|
outDir: e.dir,
|
|
1265
1281
|
scope: { kind: "all" },
|
|
1266
1282
|
compression: "none"
|
|
1267
|
-
}).pipe(n.mapError((t) => new
|
|
1283
|
+
}).pipe(n.mapError((t) => new H({
|
|
1268
1284
|
reason: `rollback capture failed, so the import did not start and the target is untouched: ${t.reason ?? String(t)}\n Fix the capture, or re-run with \`--no-rollback\` to proceed without one.`,
|
|
1269
1285
|
path: e.dir
|
|
1270
1286
|
})));
|
|
@@ -1273,18 +1289,18 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1273
1289
|
rows: r.tables.reduce((e, t) => e + t.rowCount, 0),
|
|
1274
1290
|
tables: r.tables.length
|
|
1275
1291
|
};
|
|
1276
|
-
}),
|
|
1292
|
+
}), Zn = (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), $n = (e, t) => new Map((Qn(e, t)?.columns ?? []).map((e) => [e.name, e])), er = /__dropped_\d+$/, tr = (e, t) => {
|
|
1277
1293
|
let n = [];
|
|
1278
1294
|
for (let r of [...e.tables].sort((e, t) => e.name.localeCompare(t.name))) {
|
|
1279
|
-
if (
|
|
1295
|
+
if (Qn(t, r.name) === void 0) {
|
|
1280
1296
|
n.push(`table '${r.name}' is in the bundle but MISSING from the target — its rows have nowhere to go`);
|
|
1281
1297
|
continue;
|
|
1282
1298
|
}
|
|
1283
|
-
let e =
|
|
1299
|
+
let e = $n(t, r.name), i = new Map(r.columns.map((e) => [e.name, e]));
|
|
1284
1300
|
for (let [t, a] of i) {
|
|
1285
1301
|
let i = e.get(t);
|
|
1286
1302
|
if (i === void 0) {
|
|
1287
|
-
n.push(
|
|
1303
|
+
n.push(er.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`);
|
|
1288
1304
|
continue;
|
|
1289
1305
|
}
|
|
1290
1306
|
i.type !== a.type && n.push(`${r.name}.${t}: type '${a.type}' (bundle) vs '${i.type}' (target)`);
|
|
@@ -1292,22 +1308,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1292
1308
|
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`);
|
|
1293
1309
|
}
|
|
1294
1310
|
return n.length > 30 ? [...n.slice(0, 30), `… and ${n.length - 30} more difference(s)`] : n;
|
|
1295
|
-
},
|
|
1296
|
-
let r =
|
|
1311
|
+
}, nr = (e, t, n) => {
|
|
1312
|
+
let r = w(t);
|
|
1297
1313
|
if (r === e || n === void 0) return {
|
|
1298
1314
|
drifted: !1,
|
|
1299
1315
|
bundleFingerprint: e,
|
|
1300
1316
|
targetFingerprint: r,
|
|
1301
1317
|
diff: []
|
|
1302
1318
|
};
|
|
1303
|
-
let i =
|
|
1319
|
+
let i = tr(n, t);
|
|
1304
1320
|
return {
|
|
1305
1321
|
drifted: i.length > 0,
|
|
1306
1322
|
bundleFingerprint: e,
|
|
1307
1323
|
targetFingerprint: r,
|
|
1308
1324
|
diff: i
|
|
1309
1325
|
};
|
|
1310
|
-
},
|
|
1326
|
+
}, rr = 2e3, ir = 2e3, ar = 200, or = /* @__PURE__ */ new Set([
|
|
1311
1327
|
"BundleError",
|
|
1312
1328
|
"CodecError",
|
|
1313
1329
|
"IntegrityError",
|
|
@@ -1316,33 +1332,33 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1316
1332
|
"RowsRefusedError",
|
|
1317
1333
|
"SchemaDriftError",
|
|
1318
1334
|
"StorageError"
|
|
1319
|
-
]),
|
|
1335
|
+
]), sr = (t) => {
|
|
1320
1336
|
let n = o.isFiberFailure(t) ? [...e.failures(t[o.FiberFailureCauseId]), ...e.defects(t[o.FiberFailureCauseId])] : [t];
|
|
1321
1337
|
for (let e of n) {
|
|
1322
1338
|
let t = e?._tag;
|
|
1323
|
-
if (typeof t == "string" &&
|
|
1339
|
+
if (typeof t == "string" && or.has(t)) return e;
|
|
1324
1340
|
if (o.isFiberFailure(e)) {
|
|
1325
|
-
let t =
|
|
1341
|
+
let t = sr(e);
|
|
1326
1342
|
if (t) return t;
|
|
1327
1343
|
}
|
|
1328
1344
|
}
|
|
1329
|
-
},
|
|
1345
|
+
}, cr = (t) => [...e.failures(t)][0] ?? Error(e.pretty(t)), lr = (e) => n.tryPromise({
|
|
1330
1346
|
try: async () => {
|
|
1331
1347
|
let t = await import("node:fs/promises"), n = await import("node:path");
|
|
1332
|
-
return
|
|
1348
|
+
return At(await t.readFile(n.join(e, jt), "utf8"));
|
|
1333
1349
|
},
|
|
1334
|
-
catch: (e) => new
|
|
1350
|
+
catch: (e) => new H({
|
|
1335
1351
|
reason: `manifest read/parse failed: ${String(e?.message ?? e)}`,
|
|
1336
|
-
path:
|
|
1352
|
+
path: jt
|
|
1337
1353
|
})
|
|
1338
|
-
}),
|
|
1354
|
+
}), ur = (e) => {
|
|
1339
1355
|
let t;
|
|
1340
1356
|
return n.gen(function* () {
|
|
1341
|
-
let i = yield* n.promise(() => import("node:path")), a = yield*
|
|
1342
|
-
if (a.formatVersion !== 1) return yield* n.fail(new
|
|
1357
|
+
let i = yield* n.promise(() => import("node:path")), a = yield* lr(e.bundleDir);
|
|
1358
|
+
if (a.formatVersion !== 1) return yield* n.fail(new H({ reason: `unsupported bundle formatVersion ${a.formatVersion} (expected 1)` }));
|
|
1343
1359
|
if (e.tables !== void 0) {
|
|
1344
1360
|
let t = new Set(a.tables.map((e) => e.name)), r = e.tables.filter((e) => !t.has(e));
|
|
1345
|
-
if (r.length > 0) return yield* n.fail(new
|
|
1361
|
+
if (r.length > 0) return yield* n.fail(new H({ reason: `--tables names ${r.length} table(s) this bundle does not carry: ${r.join(", ")}. The bundle carries: ${[...t].sort().join(", ")}.` }));
|
|
1346
1362
|
}
|
|
1347
1363
|
let o = e.tables === void 0 ? void 0 : new Set(e.tables), s = o === void 0 ? a : {
|
|
1348
1364
|
...a,
|
|
@@ -1359,9 +1375,9 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1359
1375
|
unique: !1,
|
|
1360
1376
|
hasDefault: !1
|
|
1361
1377
|
}))
|
|
1362
|
-
})) }, r =
|
|
1378
|
+
})) }, r = nr(s.source.schemaFingerprint, e.targetSnapshot, t);
|
|
1363
1379
|
if (r.drifted) {
|
|
1364
|
-
if (!e.force) return yield* n.fail(new
|
|
1380
|
+
if (!e.force) return yield* n.fail(new et({
|
|
1365
1381
|
bundleFingerprint: r.bundleFingerprint,
|
|
1366
1382
|
targetFingerprint: r.targetFingerprint,
|
|
1367
1383
|
diff: r.diff
|
|
@@ -1370,15 +1386,15 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1370
1386
|
}
|
|
1371
1387
|
}
|
|
1372
1388
|
if (e.targetDialect && e.targetDialect !== s.source.dialect) {
|
|
1373
|
-
let t =
|
|
1374
|
-
if (t.length > 0 && !e.allowIncompatible) return yield* n.fail(new
|
|
1389
|
+
let t = wn(s.tables, s.source.dialect, e.targetDialect).filter((e) => e.severity === "block");
|
|
1390
|
+
if (t.length > 0 && !e.allowIncompatible) return yield* n.fail(new rt({
|
|
1375
1391
|
sourceDialect: s.source.dialect,
|
|
1376
1392
|
targetDialect: e.targetDialect,
|
|
1377
|
-
blocking: t.map(
|
|
1393
|
+
blocking: t.map(Tn)
|
|
1378
1394
|
}));
|
|
1379
1395
|
}
|
|
1380
|
-
let c = e.verify ?? !0, f = e.mode ?? "upsert", m = e.atomic ?? f === "replace", _ = e.onConflict ?? "skip", v = e.ledgerPath ?? i.join(e.bundleDir, ".import..ledger.json"), b = yield*
|
|
1381
|
-
if (f === "replace" && s.scope.kind !== "all") return yield* n.fail(new
|
|
1396
|
+
let c = e.verify ?? !0, f = e.mode ?? "upsert", m = e.atomic ?? f === "replace", _ = e.onConflict ?? "skip", v = e.ledgerPath ?? i.join(e.bundleDir, ".import..ledger.json"), b = yield* Wt(v);
|
|
1397
|
+
if (f === "replace" && s.scope.kind !== "all") return yield* n.fail(new nt({
|
|
1382
1398
|
mode: f,
|
|
1383
1399
|
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.`
|
|
1384
1400
|
}));
|
|
@@ -1390,8 +1406,8 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1390
1406
|
if (f === "replace") {
|
|
1391
1407
|
let t = s.tables.map((e) => e.name), r = e.store.incomingForeignKeys ? yield* n.tryPromise({
|
|
1392
1408
|
try: () => e.store.incomingForeignKeys(t),
|
|
1393
|
-
catch: (e) => new
|
|
1394
|
-
}) : e.targetSnapshot === void 0 ? [] :
|
|
1409
|
+
catch: (e) => new H({ reason: `foreign-key pre-flight failed: ${Mn(e)}` })
|
|
1410
|
+
}) : e.targetSnapshot === void 0 ? [] : yn(e.targetSnapshot, t), i = [], a = /* @__PURE__ */ new Map();
|
|
1395
1411
|
for (let t of r) {
|
|
1396
1412
|
if (!a.has(t.from)) {
|
|
1397
1413
|
let r = yield* n.tryPromise({
|
|
@@ -1403,7 +1419,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1403
1419
|
skip: void 0,
|
|
1404
1420
|
projection: []
|
|
1405
1421
|
}),
|
|
1406
|
-
catch: () => new
|
|
1422
|
+
catch: () => new H({ reason: `unreadable: ${t.from}` })
|
|
1407
1423
|
}).pipe(n.map((e) => e.length), n.orElseSucceed(() => 0));
|
|
1408
1424
|
a.set(t.from, r);
|
|
1409
1425
|
}
|
|
@@ -1413,9 +1429,9 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1413
1429
|
rowCount: r
|
|
1414
1430
|
});
|
|
1415
1431
|
}
|
|
1416
|
-
if (i.length > 0) return yield* n.fail(new
|
|
1432
|
+
if (i.length > 0) return yield* n.fail(new nt({
|
|
1417
1433
|
mode: f,
|
|
1418
|
-
reason:
|
|
1434
|
+
reason: bn(i)
|
|
1419
1435
|
}));
|
|
1420
1436
|
}
|
|
1421
1437
|
if (e.dryRun === !0) return e.traceId !== void 0 && (yield* n.promise(() => e.store.update(u, e.traceId, {
|
|
@@ -1436,27 +1452,35 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1436
1452
|
let e = t.columns.filter((e) => e.generatedAs !== void 0).map((e) => e.name);
|
|
1437
1453
|
e.length > 0 && S.set(t.name, e);
|
|
1438
1454
|
}
|
|
1439
|
-
let
|
|
1455
|
+
let C = (e, t) => {
|
|
1440
1456
|
let n = S.get(e);
|
|
1441
1457
|
if (n === void 0) return t;
|
|
1442
1458
|
let r;
|
|
1443
1459
|
for (let e of n) e in t && (r ??= { ...t }, delete r[e]);
|
|
1444
1460
|
return r ?? t;
|
|
1445
|
-
},
|
|
1446
|
-
let i = O ?
|
|
1461
|
+
}, w = (e, t, n, r = !1) => {
|
|
1462
|
+
let i = O ? J(t.name) : t.name, a = t.primaryKey, o = oe(t.name, C(t.name, n), t.columnTypes);
|
|
1447
1463
|
return f === "append" ? _ === "fail" ? e.insert(i, o) : e.insertIgnore(i, o, { conflictColumns: [a] }) : f === "replace" ? r ? e.upsert(i, o, { conflictColumns: [a] }) : e.insert(i, o) : e.upsert(i, o, { conflictColumns: [a] });
|
|
1448
|
-
},
|
|
1449
|
-
|
|
1450
|
-
|
|
1464
|
+
}, ae = e.targetDialect !== void 0 && e.targetDialect !== "memory", oe = (e, t, n) => {
|
|
1465
|
+
if (!ae || n === void 0 || y(e) !== void 0) return t;
|
|
1466
|
+
let r = null;
|
|
1467
|
+
for (let [e, i] of Object.entries(n)) {
|
|
1468
|
+
let n = t[e];
|
|
1469
|
+
i === "json" && n != null && (r === null && (r = { ...t }), r[e] = JSON.stringify(n));
|
|
1470
|
+
}
|
|
1471
|
+
return r ?? t;
|
|
1472
|
+
}, T = (e, t) => e.savepoint ? e.savepoint(t) : t(), se = 0, ce = (t, n, r) => {
|
|
1473
|
+
r.unclassified && (se++, !(se > 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}` + (se === 3 ? " (further unclassified refusals are counted, not logged)" : "")));
|
|
1474
|
+
}, le = (e, t, r = !0) => n.tryPromise({
|
|
1451
1475
|
try: e,
|
|
1452
|
-
catch: (e) =>
|
|
1453
|
-
}).pipe(n.map(() => !0), n.catchAll((e) => n.sync(() => (r && (t.reason = e.reason,
|
|
1476
|
+
catch: (e) => An(e)
|
|
1477
|
+
}).pipe(n.map(() => !0), n.catchAll((e) => n.sync(() => (r && (t.reason = e.reason, ce(t.entry, t.row, e)), !1)))), ue = (e) => {
|
|
1454
1478
|
let t = Object.entries(e.entry.columnTypes).filter(([t, n]) => n === "reference" && e.row[t] !== null && e.row[t] !== void 0).map(([e]) => e);
|
|
1455
1479
|
if (t.length !== 0) return {
|
|
1456
1480
|
...e.row,
|
|
1457
1481
|
...Object.fromEntries(t.map((e) => [e, null]))
|
|
1458
1482
|
};
|
|
1459
|
-
},
|
|
1483
|
+
}, de = (e) => {
|
|
1460
1484
|
let t = new Set(e.map((e) => String(e.row[e.entry.primaryKey]))), n = (e) => Object.entries(e.entry.columnTypes).some(([n, r]) => {
|
|
1461
1485
|
if (r !== "reference") return !1;
|
|
1462
1486
|
let i = e.row[n];
|
|
@@ -1474,7 +1498,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1474
1498
|
};
|
|
1475
1499
|
t.refused++, e.derived || t.primary++, a.set(e.table, t);
|
|
1476
1500
|
}
|
|
1477
|
-
return new
|
|
1501
|
+
return new $e({
|
|
1478
1502
|
rows: i.slice(0, 20),
|
|
1479
1503
|
primaryCount: r.filter((e) => !e.derived).length,
|
|
1480
1504
|
totalCount: e.length,
|
|
@@ -1484,62 +1508,62 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1484
1508
|
primary: t.primary
|
|
1485
1509
|
})).sort((e, t) => t.refused - e.refused || e.table.localeCompare(t.table)).slice(0, 100)
|
|
1486
1510
|
});
|
|
1487
|
-
},
|
|
1511
|
+
}, pe = (e, t) => n.gen(function* () {
|
|
1488
1512
|
let r = t, i = [], a = !0;
|
|
1489
1513
|
for (; r.length > 0 && a;) {
|
|
1490
1514
|
a = !1;
|
|
1491
1515
|
let t = [];
|
|
1492
|
-
for (let n of r) (yield*
|
|
1516
|
+
for (let n of r) (yield* le(() => T(e, () => w(e, n.entry, n.row, !0)), n)) ? a = !0 : t.push(n);
|
|
1493
1517
|
if (!a && t.length > 0) for (let n = t.length - 1; n >= 0; n--) {
|
|
1494
|
-
let r = t[n], o =
|
|
1495
|
-
o !== void 0 && (yield*
|
|
1518
|
+
let r = t[n], o = ue(r);
|
|
1519
|
+
o !== void 0 && (yield* le(() => T(e, () => w(e, r.entry, o, !0)), r, !1)) && (i.push(r), t.splice(n, 1), a = !0);
|
|
1496
1520
|
}
|
|
1497
1521
|
r = t;
|
|
1498
1522
|
}
|
|
1499
|
-
for (let t of i) (yield*
|
|
1500
|
-
if (r.length > 0) return yield* n.fail(
|
|
1523
|
+
for (let t of i) (yield* le(() => T(e, () => e.upsert(t.entry.name, oe(t.entry.name, t.row, t.entry.columnTypes), { conflictColumns: [t.entry.primaryKey] })), t)) || (r = [...r, t]);
|
|
1524
|
+
if (r.length > 0) return yield* n.fail(de(r));
|
|
1501
1525
|
}), E = (() => {
|
|
1502
1526
|
let t = e.targetDialect;
|
|
1503
1527
|
return t === "postgres" || t === "mysql" || t === "mariadb" || t === "sqlite" || t === "mssql" ? t : void 0;
|
|
1504
|
-
})(), D =
|
|
1528
|
+
})(), D = Yn({
|
|
1505
1529
|
mode: f,
|
|
1506
1530
|
...e.targetDialect === void 0 ? {} : { targetDialect: e.targetDialect },
|
|
1507
1531
|
...e.targetSnapshot === void 0 ? {} : { targetSnapshot: e.targetSnapshot },
|
|
1508
1532
|
bundleTables: s.tables.map((e) => e.name),
|
|
1509
|
-
isSkipped:
|
|
1510
|
-
canRunSql:
|
|
1511
|
-
}),
|
|
1533
|
+
isSkipped: V,
|
|
1534
|
+
canRunSql: Pn(e.store)
|
|
1535
|
+
}), me = D.tables, he = s.tables.filter((e) => !V(e.name) && ee(e.name)).map((e) => e.name), O = D.active, _e = !1, k = 0, A = 0, j, M, ve = 0, N = 0, P = (t, r) => n.gen(function* () {
|
|
1512
1536
|
if (f === "replace" && !O && !(r && b.truncated)) {
|
|
1513
1537
|
e.recordInterruption === !0 && (yield* n.tryPromise({
|
|
1514
1538
|
try: () => t.insert(d, {
|
|
1515
|
-
id: h("repl",
|
|
1516
|
-
startedAt:
|
|
1539
|
+
id: h("repl", ye),
|
|
1540
|
+
startedAt: be,
|
|
1517
1541
|
tables: String(s.tables.length),
|
|
1518
|
-
capture:
|
|
1542
|
+
capture: F?.dir ?? null,
|
|
1519
1543
|
via: e.via ?? "direct"
|
|
1520
1544
|
}),
|
|
1521
|
-
catch: (e) => new
|
|
1545
|
+
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
|
|
1522
1546
|
not proceed without it.` })
|
|
1523
1547
|
}));
|
|
1524
|
-
let i = [...s.tables].reverse().map((e) => e.name).filter((e) => !
|
|
1548
|
+
let i = [...s.tables].reverse().map((e) => e.name).filter((e) => !V(e)), a = !r, o = t.emptyTables ? () => t.emptyTables(i) : a ? async () => {
|
|
1525
1549
|
for (let e of [...s.tables].reverse()) await t.deleteMany(e.name, { where: x(e.primaryKey) });
|
|
1526
1550
|
} : () => t.transactional(async (e) => {
|
|
1527
1551
|
for (let t of [...s.tables].reverse()) await e.deleteMany(t.name, { where: x(t.primaryKey) });
|
|
1528
1552
|
});
|
|
1529
1553
|
yield* n.tryPromise({
|
|
1530
1554
|
try: o,
|
|
1531
|
-
catch: (e) => new
|
|
1532
|
-
}), r && (b.truncated = !0, yield*
|
|
1555
|
+
catch: (e) => new H({ reason: `emptying the target for --mode replace failed (nothing was deleted): ${Mn(e)}` })
|
|
1556
|
+
}), r && (b.truncated = !0, yield* K(v, b));
|
|
1533
1557
|
}
|
|
1534
1558
|
let a = [], o = [], u = [], p = [], g = s.tables.length;
|
|
1535
1559
|
for (let d = 0; d < s.tables.length; d++) {
|
|
1536
1560
|
let h = s.tables[d];
|
|
1537
|
-
if (
|
|
1561
|
+
if (V(h.name)) {
|
|
1538
1562
|
p.push(h.name);
|
|
1539
1563
|
continue;
|
|
1540
1564
|
}
|
|
1541
1565
|
if (r && h.name in b.tables) {
|
|
1542
|
-
u.push(h.name),
|
|
1566
|
+
u.push(h.name), N++, ve += b.tables[h.name].rowCount, G(e.onProgress, {
|
|
1543
1567
|
phase: "import",
|
|
1544
1568
|
table: h.name,
|
|
1545
1569
|
index: d,
|
|
@@ -1551,7 +1575,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1551
1575
|
continue;
|
|
1552
1576
|
}
|
|
1553
1577
|
let _ = i.join(e.bundleDir, h.file);
|
|
1554
|
-
|
|
1578
|
+
G(e.onProgress, {
|
|
1555
1579
|
phase: "import",
|
|
1556
1580
|
table: h.name,
|
|
1557
1581
|
index: d,
|
|
@@ -1561,22 +1585,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1561
1585
|
total: h.rowCount
|
|
1562
1586
|
});
|
|
1563
1587
|
let y = a.length, x = n.gen(function* () {
|
|
1564
|
-
let { createHash: r } = yield* n.promise(() => import("node:crypto")), i = r("sha256"), o = 0, c =
|
|
1588
|
+
let { createHash: r } = yield* n.promise(() => import("node:crypto")), i = r("sha256"), o = 0, c = ge("bundle", () => fe(_).pipe(Ct(s.compression))).pipe(l.tap((e) => n.sync(() => i.update(e)))), u = async (e) => {
|
|
1565
1589
|
let n = {
|
|
1566
1590
|
entry: h,
|
|
1567
1591
|
row: e,
|
|
1568
1592
|
reason: ""
|
|
1569
1593
|
};
|
|
1570
1594
|
try {
|
|
1571
|
-
await
|
|
1595
|
+
await T(t, () => w(t, h, e));
|
|
1572
1596
|
} catch (t) {
|
|
1573
|
-
let r =
|
|
1574
|
-
n.reason = r.reason,
|
|
1597
|
+
let r = An(t);
|
|
1598
|
+
n.reason = r.reason, ce(h, e, r), a.push(n);
|
|
1575
1599
|
}
|
|
1576
1600
|
}, d = yield* n.promise(async () => {
|
|
1577
1601
|
let n = e.copyLoader;
|
|
1578
1602
|
if (!n || n.dialect !== "postgres") return !1;
|
|
1579
|
-
if (m) return
|
|
1603
|
+
if (m) return _e || (_e = !0, e.onWarn?.("bulk COPY is off for this run: it needs its own connection and this import runs in ONE transaction (the default for --mode replace, so a failure mid-load cannot leave the target emptied and unfilled). Pass --no-atomic to trade that guarantee back for COPY.")), !1;
|
|
1580
1604
|
if (f === "replace") return !0;
|
|
1581
1605
|
if (f !== "upsert") return !1;
|
|
1582
1606
|
try {
|
|
@@ -1606,46 +1630,46 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1606
1630
|
d = !1, e.onWarn?.(`bulk COPY into ${h.name} failed (${String(n?.message ?? n)}); falling back to per-row writes for this table`);
|
|
1607
1631
|
for (let e of t) await u(e);
|
|
1608
1632
|
}
|
|
1609
|
-
}, b = Math.max(1, e.savepointBatchSize ?? 200), x = typeof t.savepoint == "function", S = [],
|
|
1633
|
+
}, b = Math.max(1, e.savepointBatchSize ?? 200), x = typeof t.savepoint == "function", S = [], ee = async () => {
|
|
1610
1634
|
if (S.length === 0) return;
|
|
1611
1635
|
let e = S;
|
|
1612
1636
|
S = [];
|
|
1613
1637
|
try {
|
|
1614
1638
|
await t.savepoint(async () => {
|
|
1615
|
-
for (let n of e) await
|
|
1639
|
+
for (let n of e) await w(t, h, n);
|
|
1616
1640
|
});
|
|
1617
1641
|
} catch {
|
|
1618
1642
|
for (let t of e) await u(t);
|
|
1619
1643
|
}
|
|
1620
1644
|
};
|
|
1621
|
-
return yield* l.runForEach(
|
|
1645
|
+
return yield* l.runForEach(on(c, h.name, h.columnTypes), (e) => n.promise(async () => {
|
|
1622
1646
|
if (o++, M?.(), d) {
|
|
1623
1647
|
v.push(e), v.length >= g && await y();
|
|
1624
1648
|
return;
|
|
1625
1649
|
}
|
|
1626
1650
|
if (x) {
|
|
1627
|
-
S.push(e), S.length >= b && await
|
|
1651
|
+
S.push(e), S.length >= b && await ee();
|
|
1628
1652
|
return;
|
|
1629
1653
|
}
|
|
1630
1654
|
await u(e);
|
|
1631
|
-
})), yield* n.promise(
|
|
1655
|
+
})), yield* n.promise(ee), yield* n.promise(y), {
|
|
1632
1656
|
rowCount: o,
|
|
1633
1657
|
checksum: i.digest("hex")
|
|
1634
1658
|
};
|
|
1635
|
-
}), { rowCount: S, checksum:
|
|
1659
|
+
}), { rowCount: S, checksum: ee } = yield* Ht("import", h.name, d, g, (e) => e.rowCount, x);
|
|
1636
1660
|
if (c) {
|
|
1637
|
-
if (
|
|
1661
|
+
if (ee !== h.checksum) return yield* n.fail(new Ze({
|
|
1638
1662
|
what: `table ${h.name} checksum`,
|
|
1639
1663
|
expected: h.checksum,
|
|
1640
|
-
actual:
|
|
1664
|
+
actual: ee
|
|
1641
1665
|
}));
|
|
1642
|
-
if (S !== h.rowCount) return yield* n.fail(new
|
|
1666
|
+
if (S !== h.rowCount) return yield* n.fail(new Ze({
|
|
1643
1667
|
what: `table ${h.name} rowCount`,
|
|
1644
1668
|
expected: String(h.rowCount),
|
|
1645
1669
|
actual: String(S)
|
|
1646
1670
|
}));
|
|
1647
1671
|
}
|
|
1648
|
-
|
|
1672
|
+
G(e.onProgress, {
|
|
1649
1673
|
phase: "import",
|
|
1650
1674
|
table: h.name,
|
|
1651
1675
|
index: d,
|
|
@@ -1653,18 +1677,18 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1653
1677
|
event: "done",
|
|
1654
1678
|
rowsDone: S,
|
|
1655
1679
|
total: h.rowCount
|
|
1656
|
-
}),
|
|
1680
|
+
}), A++, k += S, j?.(), M?.(), r && (a.length > y ? o.push({
|
|
1657
1681
|
name: h.name,
|
|
1658
1682
|
rowCount: S
|
|
1659
1683
|
}) : (b.tables[h.name] = {
|
|
1660
1684
|
rowCount: S,
|
|
1661
1685
|
checksum: h.checksum
|
|
1662
|
-
}, yield*
|
|
1686
|
+
}, yield* K(v, b)));
|
|
1663
1687
|
}
|
|
1664
|
-
if (a.length > 0 && (yield*
|
|
1688
|
+
if (a.length > 0 && (yield* pe(t, a)), f === "replace" && (yield* n.promise(() => t.deleteMany(d, { where: {
|
|
1665
1689
|
column: "startedAt",
|
|
1666
1690
|
op: "lte",
|
|
1667
|
-
value:
|
|
1691
|
+
value: be
|
|
1668
1692
|
} }).then(() => void 0, () => void 0))), r && o.length > 0) {
|
|
1669
1693
|
for (let e of o) {
|
|
1670
1694
|
let t = s.tables.find((t) => t.name === e.name);
|
|
@@ -1673,35 +1697,35 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1673
1697
|
checksum: t.checksum
|
|
1674
1698
|
};
|
|
1675
1699
|
}
|
|
1676
|
-
yield*
|
|
1700
|
+
yield* K(v, b);
|
|
1677
1701
|
}
|
|
1678
1702
|
{
|
|
1679
|
-
let t =
|
|
1703
|
+
let t = Ye(p, "skipped");
|
|
1680
1704
|
t !== void 0 && e.onWarn?.(t);
|
|
1681
1705
|
}
|
|
1682
1706
|
if (u.length > 0) {
|
|
1683
1707
|
let t = u.length === s.tables.length;
|
|
1684
1708
|
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 ${v} to force a full re-import.`);
|
|
1685
1709
|
}
|
|
1686
|
-
}),
|
|
1710
|
+
}), ye = `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`, be = /* @__PURE__ */ new Date(), F = yield* Xn({
|
|
1687
1711
|
store: e.store,
|
|
1688
1712
|
mode: f,
|
|
1689
1713
|
dir: e.rollbackDir,
|
|
1690
1714
|
snapshot: e.targetSnapshot,
|
|
1691
1715
|
dialect: e.targetDialect,
|
|
1692
|
-
tables: s.tables.map((e) => e.name).filter((e) => !
|
|
1716
|
+
tables: s.tables.map((e) => e.name).filter((e) => !V(e)),
|
|
1693
1717
|
onWarn: e.onWarn
|
|
1694
1718
|
});
|
|
1695
|
-
|
|
1696
|
-
try: () => e.onRollbackCaptured(
|
|
1697
|
-
catch: (e) => new
|
|
1719
|
+
F !== void 0 && (e.onRollbackCaptured !== void 0 && (yield* n.tryPromise({
|
|
1720
|
+
try: () => e.onRollbackCaptured(F),
|
|
1721
|
+
catch: (e) => new H({
|
|
1698
1722
|
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.`,
|
|
1699
|
-
path:
|
|
1723
|
+
path: F.dir
|
|
1700
1724
|
})
|
|
1701
|
-
})), e.onWarn?.(
|
|
1702
|
-
let
|
|
1703
|
-
|
|
1704
|
-
id:
|
|
1725
|
+
})), e.onWarn?.(Zn(F)));
|
|
1726
|
+
let xe = (e) => f === "replace" ? ne(e) : e(), Se = (e) => f === "replace" ? re(e) : e, I = e.traceId ?? h("dimp", `${Date.now()}-${s.source.schemaFingerprint ?? ""}`), L = e.traceId !== void 0, Ce = (e.targetSnapshot?.tables.some((e) => e.name === u) ?? !1) || y(u) !== void 0;
|
|
1727
|
+
Ce && g(p), Ce && e.traceId === void 0 && (yield* n.promise(() => e.store.insert(u, {
|
|
1728
|
+
id: I,
|
|
1705
1729
|
mode: f,
|
|
1706
1730
|
via: e.via ?? "direct",
|
|
1707
1731
|
direction: "import",
|
|
@@ -1711,45 +1735,45 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1711
1735
|
rowsWritten: 0,
|
|
1712
1736
|
staged: f === "replace" ? O : null
|
|
1713
1737
|
}).then(() => {
|
|
1714
|
-
|
|
1738
|
+
L = !0;
|
|
1715
1739
|
}, (t) => {
|
|
1716
1740
|
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
|
|
1717
1741
|
\`voltro db apply\` so the next one is recorded.`);
|
|
1718
|
-
}))), e.traceId !== void 0 &&
|
|
1742
|
+
}))), e.traceId !== void 0 && Ce && (yield* n.promise(() => e.store.update(u, I, {
|
|
1719
1743
|
staged: f === "replace" ? O : null,
|
|
1720
1744
|
sourceFingerprint: s.source.schemaFingerprint ?? null
|
|
1721
1745
|
}).then(() => void 0, () => void 0)));
|
|
1722
|
-
let
|
|
1723
|
-
|
|
1724
|
-
if (!
|
|
1746
|
+
let we = 0, Te = !1;
|
|
1747
|
+
j = () => {
|
|
1748
|
+
if (!L || Te) return;
|
|
1725
1749
|
let t = Date.now();
|
|
1726
|
-
t -
|
|
1727
|
-
tablesWritten:
|
|
1728
|
-
rowsWritten:
|
|
1750
|
+
t - we < rr || (we = t, e.store.update(u, I, {
|
|
1751
|
+
tablesWritten: A,
|
|
1752
|
+
rowsWritten: k
|
|
1729
1753
|
}).then(() => void 0, () => {
|
|
1730
|
-
|
|
1754
|
+
Te = !0;
|
|
1731
1755
|
}));
|
|
1732
1756
|
};
|
|
1733
|
-
let
|
|
1757
|
+
let Ee = (t) => L ? e.store.update(u, I, {
|
|
1734
1758
|
finishedAt: t === null ? /* @__PURE__ */ new Date() : null,
|
|
1735
|
-
tablesWritten:
|
|
1736
|
-
rowsWritten:
|
|
1759
|
+
tablesWritten: A,
|
|
1760
|
+
rowsWritten: k,
|
|
1737
1761
|
failure: t
|
|
1738
1762
|
}).then(() => void 0, () => void 0) : Promise.resolve();
|
|
1739
|
-
if (t = (e) =>
|
|
1763
|
+
if (t = (e) => Ee(e), f === "replace" && !O && D.blocker !== void 0 && e.onWarn?.(Fn(D.blocker)), f === "replace" && he.length > 0 && e.onWarn?.(`write recorders are SUSPENDED for this replace (${he.length} table(s) have one).\n A replace sets a state rather than changing rows, so a per-row history entry would describe
|
|
1740
1764
|
something that did not happen — and this path already writes through the raw store, without
|
|
1741
1765
|
tenant scoping or \`audit()\` stamping, for the same reason.`), O) {
|
|
1742
|
-
e.onWarn?.(`staging ${
|
|
1743
|
-
let t = e.store, r =
|
|
1766
|
+
e.onWarn?.(`staging ${me.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.`);
|
|
1767
|
+
let t = e.store, r = me.map((e) => e.name), i = h("repl", `staging-${ye}`), a = !1;
|
|
1744
1768
|
if (e.recordInterruption === !0) {
|
|
1745
1769
|
yield* n.promise(() => e.store.insert(d, {
|
|
1746
1770
|
id: i,
|
|
1747
|
-
startedAt:
|
|
1771
|
+
startedAt: be,
|
|
1748
1772
|
kind: "staging",
|
|
1749
|
-
tables: String(
|
|
1750
|
-
capture:
|
|
1773
|
+
tables: String(me.length),
|
|
1774
|
+
capture: F?.dir ?? null,
|
|
1751
1775
|
via: e.via ?? "direct",
|
|
1752
|
-
staging: r.map(
|
|
1776
|
+
staging: r.map(J).join(","),
|
|
1753
1777
|
heartbeatAt: /* @__PURE__ */ new Date(),
|
|
1754
1778
|
resumable: !m
|
|
1755
1779
|
}).then(() => {
|
|
@@ -1763,76 +1787,76 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1763
1787
|
M = () => {
|
|
1764
1788
|
if (!a) return;
|
|
1765
1789
|
let n = Date.now();
|
|
1766
|
-
n - t <
|
|
1790
|
+
n - t < ir || (t = n, e.store.update(d, i, { heartbeatAt: /* @__PURE__ */ new Date() }).then(() => void 0, () => void 0));
|
|
1767
1791
|
};
|
|
1768
1792
|
}
|
|
1769
|
-
let o = () => a ? e.store.delete(d, i).then(() => void 0, () => void 0) : Promise.resolve(), s =
|
|
1793
|
+
let o = () => a ? e.store.delete(d, i).then(() => void 0, () => void 0) : Promise.resolve(), s = Bn(r, {
|
|
1770
1794
|
getTable: (e) => y(e),
|
|
1771
1795
|
registerTable: (e) => {
|
|
1772
|
-
|
|
1796
|
+
te(e);
|
|
1773
1797
|
},
|
|
1774
|
-
unregisterTable:
|
|
1798
|
+
unregisterTable: ie
|
|
1775
1799
|
}), c = !1;
|
|
1776
1800
|
try {
|
|
1777
|
-
let i = m ? r : r.filter((e) => !
|
|
1801
|
+
let i = m ? r : r.filter((e) => !Gt(b, e));
|
|
1778
1802
|
yield* n.tryPromise({
|
|
1779
1803
|
try: async () => {
|
|
1780
|
-
await
|
|
1804
|
+
await Wn(t, i.map((e) => Rn(e, E))), await Wn(t, i.map((e) => Ln(e, E)));
|
|
1781
1805
|
},
|
|
1782
|
-
catch: (e) => new
|
|
1783
|
-
}), yield*
|
|
1784
|
-
try: () =>
|
|
1806
|
+
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)}` })
|
|
1807
|
+
}), yield* Se(P(e.store, !m)), !m && b.truncated === !0 ? c = !0 : yield* n.tryPromise({
|
|
1808
|
+
try: () => Gn(t, me, E).then(() => {
|
|
1785
1809
|
c = !0;
|
|
1786
1810
|
}),
|
|
1787
|
-
catch: (e) => new
|
|
1811
|
+
catch: (e) => new H({ reason: String(e?.message ?? e) })
|
|
1788
1812
|
}).pipe(n.catchAll((i) => n.gen(function* () {
|
|
1789
|
-
let a =
|
|
1790
|
-
return yield* n.fail(new
|
|
1791
|
-
}))), !m && c && b.truncated !== !0 && (b.truncated = !0, yield*
|
|
1813
|
+
let a = Un(yield* n.promise(() => Kn(t, Vn(e.targetSnapshot, r), E).then((e) => e, () => [])));
|
|
1814
|
+
return yield* n.fail(new H({ reason: a ?? `the swap failed and the target is UNCHANGED: ${i.reason}` }));
|
|
1815
|
+
}))), !m && c && b.truncated !== !0 && (b.truncated = !0, yield* K(v, b));
|
|
1792
1816
|
} finally {
|
|
1793
|
-
s.undo(), c || m ? (M = void 0, yield* n.promise(() =>
|
|
1817
|
+
s.undo(), c || m ? (M = void 0, yield* n.promise(() => Wn(t, r.map((e) => Rn(e, E))).then(() => void 0, () => void 0)), yield* n.promise(o)) : 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");
|
|
1794
1818
|
}
|
|
1795
1819
|
} else m ? yield* n.tryPromise({
|
|
1796
1820
|
try: () => e.store.transactional(async (e) => {
|
|
1797
|
-
let t = await
|
|
1798
|
-
if (r.isFailure(t)) throw
|
|
1821
|
+
let t = await xe(() => n.runPromiseExit(P(e, !1)));
|
|
1822
|
+
if (r.isFailure(t)) throw cr(t.cause);
|
|
1799
1823
|
}),
|
|
1800
|
-
catch: (e) =>
|
|
1801
|
-
}) : yield*
|
|
1824
|
+
catch: (e) => sr(e) ?? new H({ reason: `atomic import failed (rolled back): ${String(e?.message ?? e)}` })
|
|
1825
|
+
}) : yield* Se(P(e.store, !0));
|
|
1802
1826
|
if (e.assets && s.assets.index && !e.assetsAlreadyRestored) {
|
|
1803
1827
|
let t = e.assets;
|
|
1804
|
-
yield*
|
|
1828
|
+
yield* vt({
|
|
1805
1829
|
sink: t,
|
|
1806
|
-
assetsDir: i.join(e.bundleDir,
|
|
1830
|
+
assetsDir: i.join(e.bundleDir, Pt),
|
|
1807
1831
|
indexPath: i.join(e.bundleDir, s.assets.index ?? "assets/index.ndjson"),
|
|
1808
1832
|
progress: {
|
|
1809
1833
|
done: (e) => e in b.assets,
|
|
1810
|
-
mark: (e) => (b.assets[e] = !0,
|
|
1834
|
+
mark: (e) => (b.assets[e] = !0, K(v, b))
|
|
1811
1835
|
}
|
|
1812
1836
|
});
|
|
1813
1837
|
}
|
|
1814
|
-
return yield* n.promise(() =>
|
|
1838
|
+
return yield* n.promise(() => Ee(null)), {
|
|
1815
1839
|
manifest: s,
|
|
1816
|
-
tablesWritten:
|
|
1817
|
-
rowsWritten:
|
|
1818
|
-
tablesSkipped:
|
|
1819
|
-
rowsSkipped:
|
|
1820
|
-
fullyResumed:
|
|
1821
|
-
...
|
|
1840
|
+
tablesWritten: A,
|
|
1841
|
+
rowsWritten: k,
|
|
1842
|
+
tablesSkipped: N,
|
|
1843
|
+
rowsSkipped: ve,
|
|
1844
|
+
fullyResumed: A === 0 && N > 0,
|
|
1845
|
+
...F === void 0 ? {} : { rollback: F }
|
|
1822
1846
|
};
|
|
1823
1847
|
}).pipe(n.tapError((e) => n.promise(() => t?.(e?.reason ?? e?._tag ?? "the import did not finish") ?? Promise.resolve())));
|
|
1824
|
-
},
|
|
1848
|
+
}, dr = (e) => e, fr = (e) => {
|
|
1825
1849
|
if (e.allowLive || e.liveInstance === null || e.sameTarget === "different") return { refuse: !1 };
|
|
1826
1850
|
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.";
|
|
1827
1851
|
return {
|
|
1828
1852
|
refuse: !0,
|
|
1829
1853
|
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).`
|
|
1830
1854
|
};
|
|
1831
|
-
},
|
|
1855
|
+
}, X = Buffer.from("VBUNDLE2"), pr = 0, mr = 1, hr = 2, gr = 32, _r = async (e) => {
|
|
1832
1856
|
let t = [], n = async (r) => {
|
|
1833
1857
|
let i;
|
|
1834
1858
|
try {
|
|
1835
|
-
i = await
|
|
1859
|
+
i = await ye(I(e, r), { withFileTypes: !0 });
|
|
1836
1860
|
} catch {
|
|
1837
1861
|
return;
|
|
1838
1862
|
}
|
|
@@ -1842,22 +1866,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1842
1866
|
}
|
|
1843
1867
|
};
|
|
1844
1868
|
return await n(""), t.sort();
|
|
1845
|
-
},
|
|
1869
|
+
}, vr = (e, t) => {
|
|
1846
1870
|
let n = Buffer.from(e, "utf8"), r = Buffer.alloc(5 + n.length + 8);
|
|
1847
|
-
return r.writeUInt8(
|
|
1848
|
-
},
|
|
1871
|
+
return r.writeUInt8(mr, 0), r.writeUInt32BE(n.length, 1), n.copy(r, 5), r.writeBigUInt64BE(BigInt(t), 5 + n.length), r;
|
|
1872
|
+
}, yr = (e, t, n) => {
|
|
1849
1873
|
let r = Buffer.from(e, "utf8"), i = Buffer.from(t, "utf8"), a = Buffer.alloc(5 + r.length + 2 + i.length + 8), o = 0;
|
|
1850
|
-
return a.writeUInt8(
|
|
1874
|
+
return a.writeUInt8(hr, 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;
|
|
1851
1875
|
};
|
|
1852
|
-
async function*
|
|
1853
|
-
yield new Uint8Array(
|
|
1854
|
-
for (let t of await
|
|
1855
|
-
let n =
|
|
1856
|
-
if (yield new Uint8Array(
|
|
1876
|
+
async function* br(e) {
|
|
1877
|
+
yield new Uint8Array(X);
|
|
1878
|
+
for (let t of await _r(e.dir)) {
|
|
1879
|
+
let n = I(e.dir, t), r = await be(n);
|
|
1880
|
+
if (yield new Uint8Array(vr(t, r.size)), r.size > 0) for await (let e of fe(n)) yield new Uint8Array(e);
|
|
1857
1881
|
}
|
|
1858
1882
|
if (e.blobs) for await (let t of e.blobs.list()) {
|
|
1859
|
-
yield new Uint8Array(
|
|
1860
|
-
let n =
|
|
1883
|
+
yield new Uint8Array(yr(t.key, t.contentType, t.size));
|
|
1884
|
+
let n = T("sha256"), r = 0;
|
|
1861
1885
|
for await (let i of e.blobs.open(t.key)) {
|
|
1862
1886
|
let e = Buffer.from(i);
|
|
1863
1887
|
n.update(e), r += e.length, yield new Uint8Array(e);
|
|
@@ -1865,11 +1889,11 @@ async function* vr(e) {
|
|
|
1865
1889
|
if (r !== t.size) throw Error(`blob '${t.key}' size mismatch: header ${t.size}, streamed ${r}`);
|
|
1866
1890
|
yield new Uint8Array(n.digest());
|
|
1867
1891
|
}
|
|
1868
|
-
yield new Uint8Array(Buffer.from([
|
|
1892
|
+
yield new Uint8Array(Buffer.from([pr]));
|
|
1869
1893
|
}
|
|
1870
|
-
var
|
|
1871
|
-
let n =
|
|
1872
|
-
await
|
|
1894
|
+
var xr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), Sr = (e) => new Promise((t) => e.end(t)), Cr = async (e, t) => {
|
|
1895
|
+
let n = L(t.dir);
|
|
1896
|
+
await P(n, { recursive: !0 });
|
|
1873
1897
|
let r = Buffer.alloc(0), i = e[Symbol.asyncIterator](), a = !1, o = async () => {
|
|
1874
1898
|
let { value: e, done: t } = await i.next();
|
|
1875
1899
|
return t ? (a = !0, !1) : (r = r.length === 0 ? Buffer.from(e) : Buffer.concat([r, Buffer.from(e)]), !0);
|
|
@@ -1880,28 +1904,28 @@ var yr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), br
|
|
|
1880
1904
|
return r = r.subarray(e), t;
|
|
1881
1905
|
};
|
|
1882
1906
|
try {
|
|
1883
|
-
if (await s(
|
|
1907
|
+
if (await s(X.length), !c(X.length).equals(X)) throw Error("not a bundle archive (bad magic)");
|
|
1884
1908
|
for (;;) {
|
|
1885
1909
|
await s(1);
|
|
1886
1910
|
let e = c(1).readUInt8(0);
|
|
1887
|
-
if (e ===
|
|
1888
|
-
if (e ===
|
|
1911
|
+
if (e === pr) return;
|
|
1912
|
+
if (e === mr) {
|
|
1889
1913
|
await s(4);
|
|
1890
1914
|
let e = c(4).readUInt32BE(0);
|
|
1891
1915
|
await s(e);
|
|
1892
1916
|
let t = c(e).toString("utf8");
|
|
1893
1917
|
await s(8);
|
|
1894
|
-
let i = c(8).readBigUInt64BE(0), a =
|
|
1895
|
-
if (a !== n && !a.startsWith(n +
|
|
1896
|
-
await
|
|
1897
|
-
let o =
|
|
1918
|
+
let i = c(8).readBigUInt64BE(0), a = L(n, t);
|
|
1919
|
+
if (a !== n && !a.startsWith(n + Ce)) throw Error(`archive path '${t}' escapes the destination`);
|
|
1920
|
+
await P(Se(a), { recursive: !0 });
|
|
1921
|
+
let o = pe(a);
|
|
1898
1922
|
for (; i > 0n;) {
|
|
1899
1923
|
r.length === 0 && await s(1);
|
|
1900
1924
|
let e = i < BigInt(r.length) ? Number(i) : r.length;
|
|
1901
|
-
await
|
|
1925
|
+
await xr(o, c(e)), i -= BigInt(e);
|
|
1902
1926
|
}
|
|
1903
|
-
await
|
|
1904
|
-
} else if (e ===
|
|
1927
|
+
await Sr(o);
|
|
1928
|
+
} else if (e === hr) {
|
|
1905
1929
|
await s(4);
|
|
1906
1930
|
let e = c(4).readUInt32BE(0);
|
|
1907
1931
|
await s(e);
|
|
@@ -1911,24 +1935,24 @@ var yr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), br
|
|
|
1911
1935
|
await s(i);
|
|
1912
1936
|
let a = c(i).toString("utf8");
|
|
1913
1937
|
await s(8);
|
|
1914
|
-
let o = c(8).readBigUInt64BE(0), l = await t.blobs.has(n), u =
|
|
1938
|
+
let o = c(8).readBigUInt64BE(0), l = await t.blobs.has(n), u = T("sha256"), d = new M(), f = l ? Promise.resolve() : t.blobs.write(n, d, {
|
|
1915
1939
|
contentType: a,
|
|
1916
1940
|
size: Number(o)
|
|
1917
1941
|
}), p = o;
|
|
1918
1942
|
for (; p > 0n;) {
|
|
1919
1943
|
r.length === 0 && await s(1);
|
|
1920
1944
|
let e = p < BigInt(r.length) ? Number(p) : r.length, t = c(e);
|
|
1921
|
-
u.update(t), l || await
|
|
1945
|
+
u.update(t), l || await xr(d, t), p -= BigInt(e);
|
|
1922
1946
|
}
|
|
1923
|
-
l ? d.destroy() : await
|
|
1924
|
-
let m = c(
|
|
1947
|
+
l ? d.destroy() : await Sr(d), await f, await s(gr);
|
|
1948
|
+
let m = c(gr);
|
|
1925
1949
|
if (!u.digest().equals(m)) throw Error(`blob '${n}' failed integrity (sha mismatch)`);
|
|
1926
1950
|
} else throw Error(`unknown bundle entry kind ${e}`);
|
|
1927
1951
|
}
|
|
1928
1952
|
} finally {
|
|
1929
1953
|
a || await Promise.resolve(i.return?.()).catch(() => void 0);
|
|
1930
1954
|
}
|
|
1931
|
-
},
|
|
1955
|
+
}, wr = async (e, t) => {
|
|
1932
1956
|
let n = new Set(t), r = /* @__PURE__ */ new Map(), i = Buffer.alloc(0), a = e[Symbol.asyncIterator](), o = async () => {
|
|
1933
1957
|
let { value: e, done: t } = await a.next();
|
|
1934
1958
|
return !t && (i = i.length === 0 ? Buffer.from(e) : Buffer.concat([i, Buffer.from(e)]), !0);
|
|
@@ -1947,11 +1971,11 @@ var yr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), br
|
|
|
1947
1971
|
}
|
|
1948
1972
|
return Buffer.concat(t);
|
|
1949
1973
|
};
|
|
1950
|
-
if (!await s(
|
|
1974
|
+
if (!await s(X.length) || !c(X.length).equals(X)) throw Error("not a bundle archive (bad magic)");
|
|
1951
1975
|
for (; await s(1);) {
|
|
1952
1976
|
let e = c(1).readUInt8(0);
|
|
1953
|
-
if (e ===
|
|
1954
|
-
if (e !==
|
|
1977
|
+
if (e === pr || e === hr) break;
|
|
1978
|
+
if (e !== mr) throw Error(`unknown bundle entry kind ${e}`);
|
|
1955
1979
|
if (!await s(4)) break;
|
|
1956
1980
|
let t = c(4).readUInt32BE(0);
|
|
1957
1981
|
if (!await s(t)) break;
|
|
@@ -1961,22 +1985,22 @@ var yr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), br
|
|
|
1961
1985
|
if (a === null || n.has(i) && (r.set(i, a), n.delete(i), n.size === 0)) break;
|
|
1962
1986
|
}
|
|
1963
1987
|
return r;
|
|
1964
|
-
},
|
|
1988
|
+
}, Tr = (e, t) => Cr(e, {
|
|
1965
1989
|
dir: t,
|
|
1966
|
-
blobs:
|
|
1967
|
-
}),
|
|
1990
|
+
blobs: Er(t)
|
|
1991
|
+
}), Er = (e) => {
|
|
1968
1992
|
let t = /* @__PURE__ */ new Set();
|
|
1969
1993
|
return {
|
|
1970
1994
|
has: async (e) => t.has(e),
|
|
1971
1995
|
write: async (n, r, i) => {
|
|
1972
|
-
let a = await import("node:fs/promises"), { pipeline: o } = await import("node:stream/promises"), { Transform: s } = await import("node:stream"), c =
|
|
1973
|
-
await
|
|
1974
|
-
let l =
|
|
1996
|
+
let a = await import("node:fs/promises"), { pipeline: o } = await import("node:stream/promises"), { Transform: s } = await import("node:stream"), c = I(e, "assets");
|
|
1997
|
+
await P(c, { recursive: !0 });
|
|
1998
|
+
let l = T("sha256"), u = 0, d = new s({ transform(e, t, n) {
|
|
1975
1999
|
l.update(e), u += e.length, n(null, e);
|
|
1976
|
-
} }), f =
|
|
1977
|
-
await o(r, d,
|
|
2000
|
+
} }), f = I(c, `.tmp-${Date.now()}-${t.size}`);
|
|
2001
|
+
await o(r, d, pe(f));
|
|
1978
2002
|
let p = l.digest("hex");
|
|
1979
|
-
await a.rename(f,
|
|
2003
|
+
await a.rename(f, I(c, p)), await a.appendFile(I(c, "index.ndjson"), `${JSON.stringify({
|
|
1980
2004
|
key: n,
|
|
1981
2005
|
sha256: p,
|
|
1982
2006
|
size: u,
|
|
@@ -1984,33 +2008,33 @@ var yr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), br
|
|
|
1984
2008
|
})}\n`), t.add(n);
|
|
1985
2009
|
}
|
|
1986
2010
|
};
|
|
1987
|
-
},
|
|
2011
|
+
}, Dr = we(ue), Or = Buffer.from("VENC1\0\0\0"), kr = 32, Ar = 16, jr = 7, Mr = 16, Nr = 262144, Pr = {
|
|
1988
2012
|
N: 32768,
|
|
1989
2013
|
r: 8,
|
|
1990
2014
|
p: 1
|
|
1991
|
-
},
|
|
2015
|
+
}, Fr = 134217728, Ir = 43, Lr = (e, t, n) => {
|
|
1992
2016
|
let r = Buffer.alloc(12);
|
|
1993
|
-
return e.copy(r, 0, 0,
|
|
2017
|
+
return e.copy(r, 0, 0, jr), r.writeUInt32BE(t >>> 0, jr), r.writeUInt8(+!!n, 11), r;
|
|
1994
2018
|
};
|
|
1995
|
-
async function*
|
|
2019
|
+
async function* Rr(e, t) {
|
|
1996
2020
|
if (!t) throw Error("encryptStream: a non-empty passphrase is required");
|
|
1997
|
-
let n = ce(
|
|
1998
|
-
...
|
|
1999
|
-
maxmem:
|
|
2000
|
-
}), a = Buffer.alloc(
|
|
2001
|
-
|
|
2021
|
+
let n = ce(Ar), r = ce(jr), i = await Dr(t, n, kr, {
|
|
2022
|
+
...Pr,
|
|
2023
|
+
maxmem: Fr
|
|
2024
|
+
}), a = Buffer.alloc(Ir);
|
|
2025
|
+
Or.copy(a, 0), a.writeUInt32BE(Pr.N, 8), a.writeUInt32BE(Pr.r, 12), a.writeUInt32BE(Pr.p, 16), n.copy(a, 20), r.copy(a, 36), yield new Uint8Array(a);
|
|
2002
2026
|
let o = 0, s = (e, t) => {
|
|
2003
|
-
let n =
|
|
2027
|
+
let n = ae("aes-256-gcm", i, Lr(r, o, t));
|
|
2004
2028
|
o === 0 && n.setAAD(a);
|
|
2005
2029
|
let s = Buffer.concat([n.update(e), n.final()]), c = n.getAuthTag();
|
|
2006
2030
|
o++;
|
|
2007
|
-
let l = Buffer.alloc(5 + s.length +
|
|
2008
|
-
return l.writeUInt8(+!!t, 0), l.writeUInt32BE(s.length +
|
|
2031
|
+
let l = Buffer.alloc(5 + s.length + Mr);
|
|
2032
|
+
return l.writeUInt8(+!!t, 0), l.writeUInt32BE(s.length + Mr, 1), s.copy(l, 5), c.copy(l, 5 + s.length), new Uint8Array(l);
|
|
2009
2033
|
}, c = Buffer.alloc(0);
|
|
2010
|
-
for await (let t of e) for (c = c.length === 0 ? Buffer.from(t) : Buffer.concat([c, Buffer.from(t)]); c.length >
|
|
2034
|
+
for await (let t of e) for (c = c.length === 0 ? Buffer.from(t) : Buffer.concat([c, Buffer.from(t)]); c.length > Nr;) yield s(c.subarray(0, Nr), !1), c = c.subarray(Nr);
|
|
2011
2035
|
yield s(c, !0);
|
|
2012
2036
|
}
|
|
2013
|
-
async function*
|
|
2037
|
+
async function* zr(e, t) {
|
|
2014
2038
|
if (!t) throw Error("decryptStream: a non-empty passphrase is required");
|
|
2015
2039
|
let n = e[Symbol.asyncIterator](), r = Buffer.alloc(0), i = !1, a = async () => {
|
|
2016
2040
|
let { value: e, done: t } = await n.next();
|
|
@@ -2019,16 +2043,16 @@ async function* Lr(e, t) {
|
|
|
2019
2043
|
for (; r.length < e && !i && await a(););
|
|
2020
2044
|
return r.length >= e;
|
|
2021
2045
|
};
|
|
2022
|
-
if (!await o(
|
|
2023
|
-
let s = r.subarray(0,
|
|
2024
|
-
if (!s.subarray(0, 8).equals(
|
|
2025
|
-
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,
|
|
2046
|
+
if (!await o(Ir)) throw Error("encrypted bundle truncated (no header)");
|
|
2047
|
+
let s = r.subarray(0, Ir);
|
|
2048
|
+
if (!s.subarray(0, 8).equals(Or)) throw Error("not an encrypted bundle (bad magic / wrong passphrase target)");
|
|
2049
|
+
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, Ir)), p = await Dr(t, d, kr, {
|
|
2026
2050
|
N: c,
|
|
2027
2051
|
r: l,
|
|
2028
2052
|
p: u,
|
|
2029
|
-
maxmem:
|
|
2053
|
+
maxmem: Fr
|
|
2030
2054
|
});
|
|
2031
|
-
r = r.subarray(
|
|
2055
|
+
r = r.subarray(Ir);
|
|
2032
2056
|
let m = 0, h = !1;
|
|
2033
2057
|
for (;;) {
|
|
2034
2058
|
if (!await o(5)) {
|
|
@@ -2037,11 +2061,11 @@ async function* Lr(e, t) {
|
|
|
2037
2061
|
}
|
|
2038
2062
|
if (h) throw Error("encrypted bundle has trailing data after the final frame");
|
|
2039
2063
|
let e = r.readUInt8(0) === 1, t = r.readUInt32BE(1);
|
|
2040
|
-
if (t <
|
|
2064
|
+
if (t < Mr) throw Error("encrypted bundle corrupt (short frame)");
|
|
2041
2065
|
if (!await o(5 + t)) throw Error("encrypted bundle truncated (frame body)");
|
|
2042
|
-
let n = r.subarray(5, 5 + t -
|
|
2066
|
+
let n = r.subarray(5, 5 + t - Mr), i = r.subarray(5 + t - Mr, 5 + t);
|
|
2043
2067
|
r = r.subarray(5 + t);
|
|
2044
|
-
let a =
|
|
2068
|
+
let a = oe("aes-256-gcm", p, Lr(f, m, e));
|
|
2045
2069
|
m === 0 && a.setAAD(s), a.setAuthTag(i);
|
|
2046
2070
|
let c = Buffer.concat([a.update(n), a.final()]);
|
|
2047
2071
|
m++, e && (h = !0), c.length > 0 && (yield new Uint8Array(c));
|
|
@@ -2049,7 +2073,7 @@ async function* Lr(e, t) {
|
|
|
2049
2073
|
}
|
|
2050
2074
|
//#endregion
|
|
2051
2075
|
//#region src/blobStorage.ts
|
|
2052
|
-
var
|
|
2076
|
+
var Br = (e, t) => ({
|
|
2053
2077
|
list: () => {
|
|
2054
2078
|
let e = t();
|
|
2055
2079
|
return { async *[Symbol.asyncIterator]() {
|
|
@@ -2062,32 +2086,32 @@ var Rr = (e, t) => ({
|
|
|
2062
2086
|
} };
|
|
2063
2087
|
},
|
|
2064
2088
|
open: (t) => ({ async *[Symbol.asyncIterator]() {
|
|
2065
|
-
let r = await n.runPromise(
|
|
2089
|
+
let r = await n.runPromise(_e(e, t)), i = await A(r.stream);
|
|
2066
2090
|
for await (let e of i) yield e instanceof Uint8Array ? e : new Uint8Array(e);
|
|
2067
2091
|
} })
|
|
2068
|
-
}),
|
|
2069
|
-
table:
|
|
2092
|
+
}), Vr = (e, t) => Br(e, () => C(t, {
|
|
2093
|
+
table: O,
|
|
2070
2094
|
chunkSize: 500
|
|
2071
2095
|
}).pipe(l.map((e) => ({
|
|
2072
2096
|
key: String(e.key),
|
|
2073
2097
|
contentType: String(e.contentType ?? "application/octet-stream"),
|
|
2074
2098
|
size: Number(e.size ?? 0)
|
|
2075
|
-
})))),
|
|
2099
|
+
})))), Hr = (e) => ({
|
|
2076
2100
|
has: (t) => n.runPromise(e.head(t).pipe(n.map((e) => e !== null))),
|
|
2077
2101
|
write: async (t, r, i) => {
|
|
2078
|
-
let a =
|
|
2079
|
-
await n.runPromise(
|
|
2102
|
+
let a = ge("storage", () => ve.from(r));
|
|
2103
|
+
await n.runPromise(k(e, t, a, {
|
|
2080
2104
|
contentType: i.contentType,
|
|
2081
2105
|
totalSize: i.size
|
|
2082
2106
|
}));
|
|
2083
2107
|
}
|
|
2084
|
-
}),
|
|
2108
|
+
}), Ur = (e, t) => {
|
|
2085
2109
|
let n = t === "dump" ? "mariadb-dump" : "mariadb", r = t === "dump" ? "mysqldump" : "mysql";
|
|
2086
|
-
return e === "mariadb" ?
|
|
2110
|
+
return e === "mariadb" ? Wr(n) ? { tool: n } : {
|
|
2087
2111
|
tool: r,
|
|
2088
2112
|
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.`
|
|
2089
2113
|
} : { tool: r };
|
|
2090
|
-
},
|
|
2114
|
+
}, Wr = (e) => (process.env.PATH ?? "").split(xe).filter((e) => e !== "").some((t) => E(I(t, e))), Gr = (e) => {
|
|
2091
2115
|
switch (e) {
|
|
2092
2116
|
case "postgres": return "db.dump";
|
|
2093
2117
|
case "mysql":
|
|
@@ -2097,23 +2121,23 @@ var Rr = (e, t) => ({
|
|
|
2097
2121
|
case "mssql": return "db.bacpac";
|
|
2098
2122
|
default: return "db.dump";
|
|
2099
2123
|
}
|
|
2100
|
-
},
|
|
2124
|
+
}, Kr = (e) => e.filename ?? e.database ?? ((e.url ?? "").replace(/^file:/, "") || "app.sqlite"), Z = (e, t = 3306) => {
|
|
2101
2125
|
if (e.host || e.database) return {
|
|
2102
2126
|
host: e.host ?? "localhost",
|
|
2103
|
-
port: e.port ??
|
|
2127
|
+
port: e.port ?? t,
|
|
2104
2128
|
username: e.username ?? "root",
|
|
2105
2129
|
password: e.password ?? "",
|
|
2106
2130
|
database: e.database ?? ""
|
|
2107
2131
|
};
|
|
2108
|
-
let
|
|
2132
|
+
let n = new URL(e.url ?? "");
|
|
2109
2133
|
return {
|
|
2110
|
-
host:
|
|
2111
|
-
port:
|
|
2112
|
-
username: decodeURIComponent(
|
|
2113
|
-
password: decodeURIComponent(
|
|
2114
|
-
database:
|
|
2134
|
+
host: n.hostname || "localhost",
|
|
2135
|
+
port: e.port ?? (n.port ? Number(n.port) : t),
|
|
2136
|
+
username: decodeURIComponent(n.username) || "root",
|
|
2137
|
+
password: decodeURIComponent(n.password) || "",
|
|
2138
|
+
database: n.pathname.replace(/^\//, "") || ""
|
|
2115
2139
|
};
|
|
2116
|
-
},
|
|
2140
|
+
}, qr = (e) => `Server=${e.host},${e.port};Database=${e.database};User ID=${e.username};Password=${e.password};TrustServerCertificate=True`, Jr = (e, t, n) => {
|
|
2117
2141
|
switch (e) {
|
|
2118
2142
|
case "postgres": {
|
|
2119
2143
|
if (t.url) return {
|
|
@@ -2123,7 +2147,7 @@ var Rr = (e, t) => ({
|
|
|
2123
2147
|
"--format=custom",
|
|
2124
2148
|
"--no-owner",
|
|
2125
2149
|
"--no-privileges",
|
|
2126
|
-
...
|
|
2150
|
+
...Xr,
|
|
2127
2151
|
"--dbname",
|
|
2128
2152
|
t.url,
|
|
2129
2153
|
"--file",
|
|
@@ -2131,10 +2155,7 @@ var Rr = (e, t) => ({
|
|
|
2131
2155
|
],
|
|
2132
2156
|
env: {}
|
|
2133
2157
|
};
|
|
2134
|
-
let e =
|
|
2135
|
-
...t,
|
|
2136
|
-
port: t.port ?? 5432
|
|
2137
|
-
});
|
|
2158
|
+
let e = Z(t, 5432);
|
|
2138
2159
|
return {
|
|
2139
2160
|
kind: "spawn",
|
|
2140
2161
|
tool: "pg_dump",
|
|
@@ -2142,7 +2163,7 @@ var Rr = (e, t) => ({
|
|
|
2142
2163
|
"--format=custom",
|
|
2143
2164
|
"--no-owner",
|
|
2144
2165
|
"--no-privileges",
|
|
2145
|
-
...
|
|
2166
|
+
...Xr,
|
|
2146
2167
|
"-h",
|
|
2147
2168
|
e.host,
|
|
2148
2169
|
"-p",
|
|
@@ -2159,17 +2180,17 @@ var Rr = (e, t) => ({
|
|
|
2159
2180
|
}
|
|
2160
2181
|
case "mysql":
|
|
2161
2182
|
case "mariadb": {
|
|
2162
|
-
let r =
|
|
2183
|
+
let r = Z(t);
|
|
2163
2184
|
return {
|
|
2164
2185
|
kind: "spawn",
|
|
2165
|
-
...
|
|
2186
|
+
...Ur(e, "dump"),
|
|
2166
2187
|
args: [
|
|
2167
2188
|
"--single-transaction",
|
|
2168
2189
|
"--routines",
|
|
2169
2190
|
"--triggers",
|
|
2170
2191
|
"--no-tablespaces",
|
|
2171
2192
|
"--protocol=TCP",
|
|
2172
|
-
...
|
|
2193
|
+
...Yr.map((e) => `--ignore-table=${r.database}.${e}`),
|
|
2173
2194
|
"-h",
|
|
2174
2195
|
r.host,
|
|
2175
2196
|
"-P",
|
|
@@ -2185,7 +2206,7 @@ var Rr = (e, t) => ({
|
|
|
2185
2206
|
case "sqlite":
|
|
2186
2207
|
case "turso": return {
|
|
2187
2208
|
kind: "copy",
|
|
2188
|
-
from:
|
|
2209
|
+
from: Kr(t),
|
|
2189
2210
|
to: n
|
|
2190
2211
|
};
|
|
2191
2212
|
case "mssql": return {
|
|
@@ -2193,20 +2214,17 @@ var Rr = (e, t) => ({
|
|
|
2193
2214
|
tool: "sqlpackage",
|
|
2194
2215
|
args: [
|
|
2195
2216
|
"/Action:Export",
|
|
2196
|
-
`/SourceConnectionString:${
|
|
2197
|
-
...t,
|
|
2198
|
-
port: t.port ?? 1433
|
|
2199
|
-
}))}`,
|
|
2217
|
+
`/SourceConnectionString:${qr(Z(t, 1433))}`,
|
|
2200
2218
|
`/TargetFile:${n}`
|
|
2201
2219
|
],
|
|
2202
2220
|
env: {}
|
|
2203
2221
|
};
|
|
2204
|
-
default: throw new
|
|
2222
|
+
default: throw new W({
|
|
2205
2223
|
tool: "backup",
|
|
2206
2224
|
reason: `no native backup for dialect '${e}'`
|
|
2207
2225
|
});
|
|
2208
2226
|
}
|
|
2209
|
-
},
|
|
2227
|
+
}, Yr = [d, u], Xr = Yr.flatMap((e) => ["--exclude-table", e]), Zr = (e) => e === "postgres" || e === "mysql" || e === "mariadb" ? Yr : [], Qr = (e, t, n) => {
|
|
2210
2228
|
switch (e) {
|
|
2211
2229
|
case "postgres": {
|
|
2212
2230
|
if (t.url) return {
|
|
@@ -2222,10 +2240,7 @@ var Rr = (e, t) => ({
|
|
|
2222
2240
|
],
|
|
2223
2241
|
env: {}
|
|
2224
2242
|
};
|
|
2225
|
-
let e =
|
|
2226
|
-
...t,
|
|
2227
|
-
port: t.port ?? 5432
|
|
2228
|
-
});
|
|
2243
|
+
let e = Z(t, 5432);
|
|
2229
2244
|
return {
|
|
2230
2245
|
kind: "spawn",
|
|
2231
2246
|
tool: "pg_restore",
|
|
@@ -2248,10 +2263,10 @@ var Rr = (e, t) => ({
|
|
|
2248
2263
|
}
|
|
2249
2264
|
case "mysql":
|
|
2250
2265
|
case "mariadb": {
|
|
2251
|
-
let r =
|
|
2266
|
+
let r = Z(t);
|
|
2252
2267
|
return {
|
|
2253
2268
|
kind: "spawn",
|
|
2254
|
-
...
|
|
2269
|
+
...Ur(e, "client"),
|
|
2255
2270
|
args: [
|
|
2256
2271
|
"--protocol=TCP",
|
|
2257
2272
|
"-h",
|
|
@@ -2270,37 +2285,104 @@ var Rr = (e, t) => ({
|
|
|
2270
2285
|
case "turso": return {
|
|
2271
2286
|
kind: "copy",
|
|
2272
2287
|
from: n,
|
|
2273
|
-
to:
|
|
2274
|
-
};
|
|
2275
|
-
case "mssql": return {
|
|
2276
|
-
kind: "spawn",
|
|
2277
|
-
tool: "sqlpackage",
|
|
2278
|
-
args: [
|
|
2279
|
-
"/Action:Import",
|
|
2280
|
-
`/TargetConnectionString:${Gr($({
|
|
2281
|
-
...t,
|
|
2282
|
-
port: t.port ?? 1433
|
|
2283
|
-
}))}`,
|
|
2284
|
-
`/SourceFile:${n}`
|
|
2285
|
-
],
|
|
2286
|
-
env: {}
|
|
2288
|
+
to: Kr(t)
|
|
2287
2289
|
};
|
|
2288
|
-
|
|
2290
|
+
case "mssql": {
|
|
2291
|
+
let e = Z(t, 1433), r = ei(e.database);
|
|
2292
|
+
return {
|
|
2293
|
+
kind: "mssql-replace",
|
|
2294
|
+
load: {
|
|
2295
|
+
kind: "spawn",
|
|
2296
|
+
tool: "sqlpackage",
|
|
2297
|
+
args: [
|
|
2298
|
+
"/Action:Import",
|
|
2299
|
+
`/TargetConnectionString:${qr({
|
|
2300
|
+
...e,
|
|
2301
|
+
database: r
|
|
2302
|
+
})}`,
|
|
2303
|
+
`/SourceFile:${n}`
|
|
2304
|
+
],
|
|
2305
|
+
env: {}
|
|
2306
|
+
},
|
|
2307
|
+
server: {
|
|
2308
|
+
host: e.host,
|
|
2309
|
+
port: e.port,
|
|
2310
|
+
username: e.username,
|
|
2311
|
+
password: e.password,
|
|
2312
|
+
database: "master"
|
|
2313
|
+
},
|
|
2314
|
+
live: e.database,
|
|
2315
|
+
scratch: r,
|
|
2316
|
+
carry: Yr
|
|
2317
|
+
};
|
|
2318
|
+
}
|
|
2319
|
+
default: throw new W({
|
|
2289
2320
|
tool: "restore",
|
|
2290
2321
|
reason: `no native restore for dialect '${e}'`
|
|
2291
2322
|
});
|
|
2292
2323
|
}
|
|
2293
|
-
},
|
|
2324
|
+
}, Q = (e) => `[${e.replaceAll("]", "]]")}]`, $ = (e) => `N'${e.replaceAll("'", "''")}'`, $r = "__voltro_restore_", ei = (e, t = le().slice(0, 8)) => `${e}${$r}${t}`, ti = (e) => e.replace($r, "__voltro_replaced_"), ni = (e) => `IF DB_ID(${$(e)}) IS NOT NULL BEGIN ALTER DATABASE ${Q(e)} SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE ${Q(e)} END`, ri = (e) => `DECLARE @leftover sysname, @drop nvarchar(max);
|
|
2325
|
+
DECLARE leftovers CURSOR LOCAL FAST_FORWARD FOR SELECT name FROM sys.databases WHERE name LIKE ${$(`${`${e}${$r}`.replace(/[\\%_[]/g, (e) => `\\${e}`)}%`)} ESCAPE N'\\';
|
|
2326
|
+
OPEN leftovers; FETCH NEXT FROM leftovers INTO @leftover;
|
|
2327
|
+
WHILE @@FETCH_STATUS = 0 BEGIN
|
|
2328
|
+
SET @drop = N'ALTER DATABASE ' + QUOTENAME(@leftover) + N' SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE ' + QUOTENAME(@leftover);
|
|
2329
|
+
EXEC(@drop);
|
|
2330
|
+
FETCH NEXT FROM leftovers INTO @leftover;
|
|
2331
|
+
END`, ii = (e) => {
|
|
2332
|
+
let t = Q(e.live), n = Q(e.scratch), r = ti(e.scratch);
|
|
2333
|
+
return {
|
|
2334
|
+
prepare: [ri(e.live)],
|
|
2335
|
+
carry: e.carry.map((e) => {
|
|
2336
|
+
let r = $(`${n}.dbo.${Q(e)}`), i = $(`${t}.dbo.${Q(e)}`);
|
|
2337
|
+
return `IF OBJECT_ID(${r}) IS NOT NULL BEGIN
|
|
2338
|
+
DELETE FROM ${n}.dbo.${Q(e)};
|
|
2339
|
+
IF OBJECT_ID(${i}) IS NOT NULL BEGIN
|
|
2340
|
+
DECLARE @columns nvarchar(max) = (SELECT STRING_AGG(QUOTENAME(s.name), ',') FROM ${n}.sys.columns s
|
|
2341
|
+
JOIN ${t}.sys.columns l ON l.name = s.name AND l.object_id = OBJECT_ID(${i})
|
|
2342
|
+
WHERE s.object_id = OBJECT_ID(${r}) AND s.is_computed = 0);
|
|
2343
|
+
EXEC(N'INSERT INTO ${n.replaceAll("'", "''")}.dbo.${Q(e).replaceAll("'", "''")} (' + @columns + N') SELECT ' + @columns + N' FROM ${t.replaceAll("'", "''")}.dbo.${Q(e).replaceAll("'", "''")}');
|
|
2344
|
+
END
|
|
2345
|
+
END`;
|
|
2346
|
+
}),
|
|
2347
|
+
swap: [
|
|
2348
|
+
`ALTER DATABASE ${t} SET SINGLE_USER WITH ROLLBACK IMMEDIATE`,
|
|
2349
|
+
`ALTER DATABASE ${t} MODIFY NAME = ${Q(r)}`,
|
|
2350
|
+
`ALTER DATABASE ${n} MODIFY NAME = ${t}`,
|
|
2351
|
+
ni(r)
|
|
2352
|
+
],
|
|
2353
|
+
undoSwap: [`IF DB_ID(${$(e.live)}) IS NULL AND DB_ID(${$(r)}) IS NOT NULL ALTER DATABASE ${Q(r)} MODIFY NAME = ${t}`, `IF DB_ID(${$(e.live)}) IS NOT NULL ALTER DATABASE ${t} SET MULTI_USER`],
|
|
2354
|
+
cleanup: [ni(e.scratch)]
|
|
2355
|
+
};
|
|
2356
|
+
}, ai = (e) => {
|
|
2357
|
+
let t = [];
|
|
2358
|
+
for (let n = e, r = 0; n != null && r < 4; r++) {
|
|
2359
|
+
let e = n instanceof Error ? n.message : typeof n == "object" && "message" in n ? String(n.message) : String(n);
|
|
2360
|
+
e && !t.includes(e) && t.push(e), n = typeof n == "object" && "cause" in n ? n.cause : void 0;
|
|
2361
|
+
}
|
|
2362
|
+
return t.join(": ");
|
|
2363
|
+
}, oi = (e, t) => {
|
|
2364
|
+
if (t === void 0) return n.fail(new W({
|
|
2365
|
+
tool: "sqlpackage",
|
|
2366
|
+
reason: "an mssql restore swaps databases and needs a SQL connection to the server; none was provided"
|
|
2367
|
+
}));
|
|
2368
|
+
let r = ii(e), i = (r, i) => t(e.server, i).pipe(n.mapError((e) => new W({
|
|
2369
|
+
tool: "sqlpackage",
|
|
2370
|
+
reason: `${r}: ${ai(e)}`
|
|
2371
|
+
}))), a = i("dropping the scratch database", r.cleanup).pipe(n.ignore);
|
|
2372
|
+
return n.gen(function* () {
|
|
2373
|
+
yield* i(`preparing ${e.scratch}`, r.prepare), yield* si(e.load).pipe(n.tapError(() => a)), yield* i(`carrying ${e.carry.join(", ")} into the imported copy`, r.carry).pipe(n.tapError(() => a)), yield* i(`swapping ${e.scratch} in as ${e.live}`, r.swap).pipe(n.tapError(() => i("putting the original database back", r.undoSwap).pipe(n.ignore)));
|
|
2374
|
+
});
|
|
2375
|
+
}, si = (e, t) => e.kind === "mssql-replace" ? oi(e, t) : e.kind === "copy" ? n.async((t) => {
|
|
2294
2376
|
let r = `${e.to}.restoring-${le()}`, i = (e) => {
|
|
2295
2377
|
try {
|
|
2296
|
-
|
|
2378
|
+
he(r);
|
|
2297
2379
|
} catch {}
|
|
2298
|
-
t(n.fail(new
|
|
2380
|
+
t(n.fail(new W({
|
|
2299
2381
|
tool: "copy",
|
|
2300
2382
|
reason: e
|
|
2301
2383
|
})));
|
|
2302
2384
|
};
|
|
2303
|
-
|
|
2385
|
+
de(e.from, r, (a) => {
|
|
2304
2386
|
if (a) {
|
|
2305
2387
|
i(`copy ${e.from} → ${e.to}: ${a.message}`);
|
|
2306
2388
|
return;
|
|
@@ -2310,9 +2392,9 @@ var Rr = (e, t) => ({
|
|
|
2310
2392
|
`${e.to}-shm`,
|
|
2311
2393
|
`${e.to}-journal`
|
|
2312
2394
|
]) try {
|
|
2313
|
-
|
|
2395
|
+
he(t);
|
|
2314
2396
|
} catch {}
|
|
2315
|
-
|
|
2397
|
+
D(r, e.to, (r) => {
|
|
2316
2398
|
if (r) {
|
|
2317
2399
|
i(`copy ${e.from} → ${e.to}: ${r.message}`);
|
|
2318
2400
|
return;
|
|
@@ -2321,7 +2403,7 @@ var Rr = (e, t) => ({
|
|
|
2321
2403
|
});
|
|
2322
2404
|
});
|
|
2323
2405
|
}) : n.async((t) => {
|
|
2324
|
-
let r =
|
|
2406
|
+
let r = Te(e.tool, [...e.args], {
|
|
2325
2407
|
env: {
|
|
2326
2408
|
...process.env,
|
|
2327
2409
|
...e.env
|
|
@@ -2341,27 +2423,27 @@ var Rr = (e, t) => ({
|
|
|
2341
2423
|
s ??= e;
|
|
2342
2424
|
};
|
|
2343
2425
|
if (e.stdoutFile && r.stdout) {
|
|
2344
|
-
let t =
|
|
2345
|
-
t.on("error", (t) => c(`writing ${
|
|
2426
|
+
let t = pe(e.stdoutFile);
|
|
2427
|
+
t.on("error", (t) => c(`writing ${F(e.stdoutFile)}: ${t.message}`)), r.stdout.on("error", (e) => c(`reading the tool's output: ${e.message}`)), r.stdout.pipe(t);
|
|
2346
2428
|
}
|
|
2347
2429
|
let l = 0;
|
|
2348
2430
|
if (e.stdinFile && r.stdin) {
|
|
2349
|
-
let t =
|
|
2431
|
+
let t = fe(e.stdinFile);
|
|
2350
2432
|
t.on("data", (e) => {
|
|
2351
2433
|
l += e.length;
|
|
2352
2434
|
}), t.on("error", (t) => {
|
|
2353
|
-
c(`reading ${
|
|
2435
|
+
c(`reading ${F(e.stdinFile)}: ${t.message}`), r.stdin?.end();
|
|
2354
2436
|
}), r.stdin.on("error", (t) => {
|
|
2355
|
-
t.code !== "EPIPE" && c(`feeding ${
|
|
2437
|
+
t.code !== "EPIPE" && c(`feeding ${F(e.stdinFile)} to ${e.tool}: ${t.message}`);
|
|
2356
2438
|
}), t.pipe(r.stdin);
|
|
2357
2439
|
}
|
|
2358
2440
|
let u = () => {
|
|
2359
2441
|
if (e.stdoutFile !== void 0) try {
|
|
2360
|
-
|
|
2442
|
+
he(e.stdoutFile);
|
|
2361
2443
|
} catch {}
|
|
2362
2444
|
};
|
|
2363
2445
|
r.on("error", (t) => {
|
|
2364
|
-
u(), o(n.fail(new
|
|
2446
|
+
u(), o(n.fail(new W({
|
|
2365
2447
|
tool: e.tool,
|
|
2366
2448
|
reason: `failed to launch (is '${e.tool}' installed + on PATH?): ${t.message}`,
|
|
2367
2449
|
...e.hint === void 0 ? {} : { hint: e.hint }
|
|
@@ -2372,25 +2454,25 @@ var Rr = (e, t) => ({
|
|
|
2372
2454
|
return;
|
|
2373
2455
|
}
|
|
2374
2456
|
u();
|
|
2375
|
-
let r = e.stdinFile === void 0 ? "" : ` — ${l} of ${
|
|
2376
|
-
o(n.fail(new
|
|
2457
|
+
let r = e.stdinFile === void 0 ? "" : ` — ${l} of ${ci(e.stdinFile)} byte(s) of ${F(e.stdinFile)} had been fed to it`;
|
|
2458
|
+
o(n.fail(new W({
|
|
2377
2459
|
tool: e.tool,
|
|
2378
|
-
reason: (t === 0 ? `exited cleanly, but ${s}` : `exited with code ${t}${s === void 0 ? "" : ` (${s})`}`) + r + (e.stdoutFile === void 0 ? "" : ` — the partial ${
|
|
2460
|
+
reason: (t === 0 ? `exited cleanly, but ${s}` : `exited with code ${t}${s === void 0 ? "" : ` (${s})`}`) + r + (e.stdoutFile === void 0 ? "" : ` — the partial ${F(e.stdoutFile)} was removed, so it cannot be mistaken for a backup`),
|
|
2379
2461
|
stderr: i.trim() === "" ? `(${e.tool} printed nothing to stderr)` : i.slice(-2e3),
|
|
2380
2462
|
...e.hint === void 0 ? {} : { hint: e.hint }
|
|
2381
2463
|
})));
|
|
2382
2464
|
});
|
|
2383
|
-
}),
|
|
2465
|
+
}), ci = (e) => {
|
|
2384
2466
|
try {
|
|
2385
|
-
return String(
|
|
2467
|
+
return String(me(e).size);
|
|
2386
2468
|
} catch {
|
|
2387
2469
|
return "?";
|
|
2388
2470
|
}
|
|
2389
|
-
},
|
|
2390
|
-
let t = yield*
|
|
2471
|
+
}, li = (e) => typeof e == "object" && e ? "fake" in e ? `fake:${e.fake}` : "custom" : String(e), ui = (e) => n.gen(function* () {
|
|
2472
|
+
let t = yield* lt(e.scope ?? { kind: "all" }, e.snapshot, {
|
|
2391
2473
|
store: e.store,
|
|
2392
2474
|
...e.tenantTables ? { tenantTables: e.tenantTables } : {}
|
|
2393
|
-
}), r =
|
|
2475
|
+
}), r = sn(t.tables, e.snapshot), i = e.classification ?? Oe(e.snapshot), a = e.sampleSize ?? 20, o = He(r.map((t) => ({
|
|
2394
2476
|
name: t,
|
|
2395
2477
|
columns: (e.snapshot.tables.find((e) => e.name === t)?.columns ?? []).map((e) => ({
|
|
2396
2478
|
name: e.name,
|
|
@@ -2398,19 +2480,19 @@ var Rr = (e, t) => ({
|
|
|
2398
2480
|
}))
|
|
2399
2481
|
})), i, e.masking), s = [], c = [];
|
|
2400
2482
|
for (let i of r) {
|
|
2401
|
-
let r = t.predicateFor(i), u = yield*
|
|
2483
|
+
let r = t.predicateFor(i), u = yield* C(e.store, {
|
|
2402
2484
|
table: i,
|
|
2403
2485
|
chunkSize: a,
|
|
2404
2486
|
...r === void 0 ? {} : { where: r }
|
|
2405
|
-
}).pipe(l.take(a), l.runCollect, n.map((e) => [...e])), d = u.map((t) =>
|
|
2406
|
-
c.push(...
|
|
2487
|
+
}).pipe(l.take(a), l.runCollect, n.map((e) => [...e])), d = u.map((t) => Ge(t, i, o.actions, e.masking.seed));
|
|
2488
|
+
c.push(...We(d, i, o.actions));
|
|
2407
2489
|
let f = u[0], p = d[0], m = [];
|
|
2408
2490
|
if (f && p) for (let [e, t] of Object.entries(o.actions)) {
|
|
2409
2491
|
if (!e.startsWith(`${i}.`) || t === "keep") continue;
|
|
2410
2492
|
let n = e.slice(i.length + 1);
|
|
2411
2493
|
m.push({
|
|
2412
2494
|
column: n,
|
|
2413
|
-
action:
|
|
2495
|
+
action: li(t),
|
|
2414
2496
|
before: f[n],
|
|
2415
2497
|
after: p[n]
|
|
2416
2498
|
});
|
|
@@ -2425,7 +2507,7 @@ var Rr = (e, t) => ({
|
|
|
2425
2507
|
leaks: c,
|
|
2426
2508
|
unclassified: o.unclassified
|
|
2427
2509
|
};
|
|
2428
|
-
}),
|
|
2510
|
+
}), di = (e, t) => {
|
|
2429
2511
|
let n = new Map(t.map((e) => [e.name, e])), r = [], i = {};
|
|
2430
2512
|
for (let t of e) {
|
|
2431
2513
|
let e = n.get(t.name);
|
|
@@ -2480,7 +2562,7 @@ var Rr = (e, t) => ({
|
|
|
2480
2562
|
skipColumns: i,
|
|
2481
2563
|
refuse: r.some((e) => e.verdict === "refuse")
|
|
2482
2564
|
};
|
|
2483
|
-
},
|
|
2565
|
+
}, fi = (e) => {
|
|
2484
2566
|
if (e.findings.length === 0) return [" schema matches the bundle"];
|
|
2485
2567
|
let t = {
|
|
2486
2568
|
safe: "✓",
|
|
@@ -2491,4 +2573,4 @@ var Rr = (e, t) => ({
|
|
|
2491
2573
|
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;
|
|
2492
2574
|
};
|
|
2493
2575
|
//#endregion
|
|
2494
|
-
export {
|
|
2576
|
+
export { Pt as ASSETS_DIR, Ft as ASSET_INDEX_FILE, H as BundleError, Xe as CodecError, Qe as CompressionError, rt as CrossDialectError, Nt as DATA_DIR, De as DEFAULT_CLASS_ACTIONS, Ke as ENVIRONMENT_LOCAL_TABLES, qe as ENVIRONMENT_PORTABLE_TABLES, Yr as EXCLUDED_FROM_DUMP, wt as FORMAT_VERSION, nt as ImportModeError, Ze as IntegrityError, It as LEDGER_FILE, jt as MANIFEST_FILE, tt as MaskingError, W as NativeToolError, $e as RowsRefusedError, ar as SAVEPOINT_BATCH_SIZE, Nn as STAGING_PREFIX, et as SchemaDriftError, U as ScopeError, B as applyAction, sr as asImportError, fr as assessLiveImport, Kt as assetDone, Gr as backupArtifactName, Jr as backupCommand, Pn as canStage, xn as canonicalType, gt as captureAssetsToCas, wn as checkPortability, nr as checkSchemaDrift, Oe as classificationFromSnapshot, di as classifyImportDrift, xt as compressionExt, ot as computeSubsetIds, Yn as decideStaging, At as decodeManifest, nn as decodeRow, en as decodeValue, zr as decryptStream, dr as defineDataProfile, tr as diffSnapshots, Er as dirBlobSink, Rn as dropStagingSql, Zr as dumpExcludedTables, Ut as emptyLedger, kt as encodeManifest, tn as encodeRow, Qt as encodeValue, Rr as encryptStream, Ye as environmentLocalNotice, Je as environmentLocalReason, Wn as execStatements, fi as formatImportDrift, Tn as formatIssue, yt as hasZstd, V as isEnvironmentLocal, St as makeCompressor, Ct as makeDecompressor, Ge as maskRow, ii as mssqlReplaceStatements, ei as mssqlScratchName, on as ndjsonToRows, mt as noAssetProgress, bn as outsideReferenceRefusal, yn as outsideReferencesInto, br as packBundle, wr as peekBundle, bt as pickCompression, He as planMasking, ui as previewMasking, _t as readAssetIndex, Wt as readLedger, ke as resolveAction, lt as resolveScope, pt as restoreAssetFromCas, vt as restoreAssetsFromCas, Qr as restoreCommand, an as rowsToNdjson, vn as runExport, ur as runImport, si as runNativeStep, We as scanForLeaks, J as stagingNameFor, dt as storageAssetSink, ut as storageAssetSource, Hr as storageBlobSink, Br as storageBlobSource, Vr as storageRefsBlobSource, st as subsetToScope, Gt as tableDone, sn as topoSortTables, Cr as unpackBundle, Tr as unpackBundleToDir, ft as writeAssetToCas, K as writeLedger };
|