@delali/sirannon-db 0.3.5 → 0.3.6-next.78
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/dist/backup/index.d.ts +5 -5
- package/dist/backup/index.mjs +5 -3
- package/dist/backup-scheduler/index.d.ts +2 -2
- package/dist/backup-scheduler/index.mjs +2 -2
- package/dist/chunk-22TYGH7J.mjs +55 -0
- package/dist/{chunk-SB3MIFLG.mjs → chunk-2ZQOZFX7.mjs} +29 -6
- package/dist/{chunk-UIDQGPJY.mjs → chunk-4O7WYZHN.mjs} +38 -3
- package/dist/{chunk-ZFFUVYYE.mjs → chunk-5DKWHT6K.mjs} +109 -1
- package/dist/chunk-5O4J6LQQ.mjs +35 -0
- package/dist/{chunk-CZL4D3BM.mjs → chunk-6CABU54O.mjs} +2 -2
- package/dist/{chunk-JAQ2I4OT.mjs → chunk-A5ULJVK7.mjs} +11 -11
- package/dist/{chunk-RLBKZZ24.mjs → chunk-AC7TKWNH.mjs} +1 -0
- package/dist/chunk-BKO4SCEC.mjs +99 -0
- package/dist/{chunk-KOTBP4AW.mjs → chunk-C7E4H6UN.mjs} +24 -4
- package/dist/{chunk-G4AG3ESO.mjs → chunk-FBA7P4ZA.mjs} +114 -149
- package/dist/{chunk-DKML5425.mjs → chunk-GBVB6WSC.mjs} +2 -2
- package/dist/chunk-I4JY5QPA.mjs +51 -0
- package/dist/{chunk-L6EX6K27.mjs → chunk-MO4APBYG.mjs} +54 -13
- package/dist/{chunk-RPWBYASV.mjs → chunk-MTOQ6QIS.mjs} +1 -1
- package/dist/chunk-MX77PGEN.mjs +60 -0
- package/dist/{chunk-BTUD6XQO.mjs → chunk-N3MHZV3B.mjs} +11 -29
- package/dist/{chunk-UHUDPQFI.mjs → chunk-OJXV4L3N.mjs} +1 -3
- package/dist/chunk-QF7WF7RJ.mjs +34 -0
- package/dist/chunk-RLBV4YTB.mjs +22 -0
- package/dist/{chunk-ISDT4RBD.mjs → chunk-ULUZUBON.mjs} +1 -1
- package/dist/{chunk-AP4367HK.mjs → chunk-VGRAAQX3.mjs} +4 -4
- package/dist/chunk-W74HFQFD.mjs +153 -0
- package/dist/chunk-Y4SP7CRF.mjs +9 -0
- package/dist/{chunk-JFVEGN7J.mjs → chunk-ZAUHAJ4G.mjs} +2 -1
- package/dist/{chunk-DDIHBUEN.mjs → chunk-ZWW53O5P.mjs} +19 -7
- package/dist/client/index.d.ts +8 -8
- package/dist/client/topology.d.ts +4 -4
- package/dist/{client-base-Doaqwrx3.d.ts → client-base-DJZbSY55.d.ts} +2 -2
- package/dist/{client-streams-MKPE4MXW.mjs → client-streams-F7IG3PTU.mjs} +13 -16
- package/dist/core/index.d.ts +48 -12
- package/dist/core/index.mjs +1812 -107
- package/dist/core/writer-worker.mjs +28 -4
- package/dist/{database-fz-8CJBP.d.ts → database-BZ96ZzAx.d.ts} +411 -184
- package/dist/{database-backup-BwTNiBm2.d.ts → database-backup-BhM8yJ1A.d.ts} +32 -2
- package/dist/driver/better-sqlite3.d.ts +11 -1
- package/dist/driver/better-sqlite3.mjs +212 -23
- package/dist/driver/bun.d.ts +1 -1
- package/dist/driver/bun.mjs +15 -22
- package/dist/driver/expo.d.ts +1 -1
- package/dist/driver/expo.mjs +185 -16
- package/dist/driver/node.d.ts +1 -1
- package/dist/driver/node.mjs +15 -62
- package/dist/driver/wa-sqlite.d.ts +1 -1
- package/dist/driver/wa-sqlite.mjs +14 -153
- package/dist/{change-tracker-Dpo99EI-.d.ts → errors-DLMAGQFb.d.ts} +200 -2
- package/dist/file-migrations/index.d.ts +1 -1
- package/dist/peer-refusal-RR37UOLV.mjs +1 -0
- package/dist/{protocol-DZSYSv0S.d.ts → protocol-DE10taas.d.ts} +1 -1
- package/dist/replication/coordinator/etcd.mjs +1 -1
- package/dist/replication/index.d.ts +7 -7
- package/dist/replication/index.mjs +66 -9
- package/dist/{restore-options-CcMukOLO.d.ts → restore-options-B6HV_5XT.d.ts} +6 -1
- package/dist/server/index.d.ts +10 -10
- package/dist/server/index.mjs +506 -350
- package/dist/{server-options-B9CsAZp5.d.ts → server-options-Bhdlvehe.d.ts} +14 -1
- package/dist/{server-streams-SBYCHWWM.mjs → server-streams-Q2AZAW3N.mjs} +6 -30
- package/dist/{sirannon-D0CjDULa.d.ts → sirannon-Ba1o2HUQ.d.ts} +5 -5
- package/dist/transport/grpc.d.ts +15 -4
- package/dist/transport/grpc.mjs +34 -37
- package/dist/transport/memory.d.ts +4 -3
- package/dist/transport/memory.mjs +8 -26
- package/dist/{types-DTmi7pXp.d.ts → types-BWyv_N18.d.ts} +189 -1
- package/dist/{types-BlZ9GG1a.d.ts → types-CDnlkVRK.d.ts} +8 -2
- package/package.json +17 -9
- package/dist/chunk-DBN57KVR.mjs +0 -171
- package/dist/chunk-W67A4H2E.mjs +0 -23
- package/dist/chunk-YW7IKQ7T.mjs +0 -62
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as ChangeTracker } from './
|
|
2
|
-
import {
|
|
1
|
+
import { S as SirannonError, C as ChangeTracker } from './errors-DLMAGQFb.js';
|
|
2
|
+
import { L as SQLiteConnection, N as NodeHealth } from './types-BWyv_N18.js';
|
|
3
3
|
import { S as SyncTableManifest, R as ReplicationBatch, C as ConflictResolver } from './types-BG31TtrQ.js';
|
|
4
4
|
import { C as ClusterCoordinator, n as CoordinatorCompatibilityMetadata, e as ReplicationGroupState } from './types-MczwKtul.js';
|
|
5
5
|
import { W as WriteConcern } from './query-types-5B02ixH0.js';
|
|
@@ -20,6 +20,8 @@ interface NodeInfo {
|
|
|
20
20
|
primaryTerm?: bigint;
|
|
21
21
|
/** Holds the replication protocol version that the peer uses. */
|
|
22
22
|
protocolVersion?: string;
|
|
23
|
+
/** Records whether the peer announces an encrypted database. A peer that announces nothing counts as plaintext. */
|
|
24
|
+
encrypted: boolean;
|
|
23
25
|
/** Holds the time, in milliseconds since the Unix epoch, at which the peer connected. */
|
|
24
26
|
joinedAt: number;
|
|
25
27
|
/** Holds the time, in milliseconds since the Unix epoch, of the last message from the peer. The bundled transports set it only when the peer connects. */
|
|
@@ -293,6 +295,8 @@ interface TransportConfig {
|
|
|
293
295
|
primaryTerm?: bigint;
|
|
294
296
|
/** Sets the replication protocol version that this node announces. */
|
|
295
297
|
protocolVersion?: string;
|
|
298
|
+
/** Sets whether this node announces an encrypted database. The replication engine fills it in when it starts. */
|
|
299
|
+
encrypted?: boolean;
|
|
296
300
|
/** Holds any other data for the transport to announce about this node. The bundled transports ignore it. */
|
|
297
301
|
metadata?: Record<string, unknown>;
|
|
298
302
|
}
|
|
@@ -346,6 +350,8 @@ interface ReplicationTransport {
|
|
|
346
350
|
peers(): ReadonlyMap<string, NodeInfo>;
|
|
347
351
|
/** Dials the replication address of every peer in the map, keyed by node ID, and stops dialling any other address. In coordinator mode the engine calls it with the addresses in the members' sessions whenever those addresses change. */
|
|
348
352
|
setPeerEndpoints?(endpoints: ReadonlyMap<string, string>): void;
|
|
353
|
+
/** Ends every stream to one peer with the error's code, so that the peer learns why this node sends it nothing. The engine calls it when its database is encrypted and the peer's is plaintext. */
|
|
354
|
+
refusePeer?(peerId: string, error: SirannonError): Promise<void>;
|
|
349
355
|
}
|
|
350
356
|
/**
|
|
351
357
|
* Configures this node's part in the group's controller loop and the lease that makes a node the controller.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@delali/sirannon-db",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.6-next.78",
|
|
5
5
|
"description": "A production-grade library that turns SQLite databases into a networked data layer with real-time subscriptions.",
|
|
6
6
|
"author": "Delali (https://sondelali.com)",
|
|
7
7
|
"license": "Apache-2.0",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"build": "rm -rf dist && tsup",
|
|
32
32
|
"build:vfs": "node ../../native/vfs/build.mjs",
|
|
33
33
|
"build:sqlite": "node ../../native/sqlite/build.mjs",
|
|
34
|
+
"build:expo-sqlcipher": "node ../../native/sqlite/build-expo-sqlcipher.mjs",
|
|
34
35
|
"assemble:sqlite": "node ../../native/sqlite/assemble.mjs",
|
|
35
36
|
"check:sqlite": "node ../../native/sqlite/check.mjs",
|
|
36
37
|
"check:bundle": "node scripts/assert-browser-bundle.mjs",
|
|
@@ -149,10 +150,11 @@
|
|
|
149
150
|
},
|
|
150
151
|
"peerDependencies": {
|
|
151
152
|
"@bufbuild/protobuf": ">=2.0.0",
|
|
152
|
-
"@delali/sirannon-sqlite": "0.3.
|
|
153
|
+
"@delali/sirannon-sqlite": "0.3.6-next.78",
|
|
153
154
|
"@grpc/grpc-js": ">=1.10.0",
|
|
154
155
|
"better-sqlite3": ">=12.0.0",
|
|
155
156
|
"etcd3": ">=1.1.2",
|
|
157
|
+
"expo-file-system": ">=19.0.0",
|
|
156
158
|
"expo-sqlite": ">=14.0.0",
|
|
157
159
|
"grpc-health-check": ">=2.0.0",
|
|
158
160
|
"react": ">=19.0.0",
|
|
@@ -172,6 +174,9 @@
|
|
|
172
174
|
"better-sqlite3": {
|
|
173
175
|
"optional": true
|
|
174
176
|
},
|
|
177
|
+
"expo-file-system": {
|
|
178
|
+
"optional": true
|
|
179
|
+
},
|
|
175
180
|
"expo-sqlite": {
|
|
176
181
|
"optional": true
|
|
177
182
|
},
|
|
@@ -193,7 +198,7 @@
|
|
|
193
198
|
},
|
|
194
199
|
"devDependencies": {
|
|
195
200
|
"@bufbuild/protobuf": "2.11.0",
|
|
196
|
-
"@delali/sirannon-sqlite": "0.3.
|
|
201
|
+
"@delali/sirannon-sqlite": "0.3.6-next.78",
|
|
197
202
|
"@grpc/grpc-js": "1.14.4",
|
|
198
203
|
"@microsoft/api-extractor": "7.58.12",
|
|
199
204
|
"@types/better-sqlite3": "7.6.13",
|
|
@@ -202,12 +207,15 @@
|
|
|
202
207
|
"@types/react-dom": "19.2.3",
|
|
203
208
|
"@vitest/coverage-v8": "4.0.18",
|
|
204
209
|
"better-sqlite3": "13.0.2",
|
|
210
|
+
"better-sqlite3-multiple-ciphers": "13.0.3",
|
|
205
211
|
"etcd3": "1.1.2",
|
|
212
|
+
"expo-file-system": "55.0.22",
|
|
206
213
|
"expo-sqlite": "55.0.10",
|
|
207
214
|
"fake-indexeddb": "6.2.5",
|
|
208
215
|
"grpc-health-check": "2.1.0",
|
|
209
216
|
"grpc-tools": "1.13.1",
|
|
210
217
|
"jsdom": "29.1.1",
|
|
218
|
+
"libsodium-wrappers": "0.8.4",
|
|
211
219
|
"node-api-headers": "1.9.0",
|
|
212
220
|
"react": "19.2.6",
|
|
213
221
|
"react-dom": "19.2.6",
|
|
@@ -221,11 +229,11 @@
|
|
|
221
229
|
"vitest": "4.0.18"
|
|
222
230
|
},
|
|
223
231
|
"optionalDependencies": {
|
|
224
|
-
"@delali/sirannon-vfs-darwin-arm64": "0.3.
|
|
225
|
-
"@delali/sirannon-vfs-darwin-x64": "0.3.
|
|
226
|
-
"@delali/sirannon-vfs-linux-arm64": "0.3.
|
|
227
|
-
"@delali/sirannon-vfs-linux-x64": "0.3.
|
|
228
|
-
"@delali/sirannon-vfs-win32-arm64": "0.3.
|
|
229
|
-
"@delali/sirannon-vfs-win32-x64": "0.3.
|
|
232
|
+
"@delali/sirannon-vfs-darwin-arm64": "0.3.6-next.78",
|
|
233
|
+
"@delali/sirannon-vfs-darwin-x64": "0.3.6-next.78",
|
|
234
|
+
"@delali/sirannon-vfs-linux-arm64": "0.3.6-next.78",
|
|
235
|
+
"@delali/sirannon-vfs-linux-x64": "0.3.6-next.78",
|
|
236
|
+
"@delali/sirannon-vfs-win32-arm64": "0.3.6-next.78",
|
|
237
|
+
"@delali/sirannon-vfs-win32-x64": "0.3.6-next.78"
|
|
230
238
|
}
|
|
231
239
|
}
|
package/dist/chunk-DBN57KVR.mjs
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
// src/core/errors.ts
|
|
2
|
-
var SirannonError = class extends Error {
|
|
3
|
-
constructor(message, code) {
|
|
4
|
-
super(message);
|
|
5
|
-
this.code = code;
|
|
6
|
-
this.name = "SirannonError";
|
|
7
|
-
}
|
|
8
|
-
};
|
|
9
|
-
var ExtensionError = class extends SirannonError {
|
|
10
|
-
constructor(path, cause) {
|
|
11
|
-
super(
|
|
12
|
-
cause ? `Failed to load extension '${path}': ${cause}` : `Failed to load extension '${path}'`,
|
|
13
|
-
"EXTENSION_ERROR"
|
|
14
|
-
);
|
|
15
|
-
this.name = "ExtensionError";
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
// src/core/driver/define.ts
|
|
20
|
-
function defineDriver(config) {
|
|
21
|
-
if (!config.capabilities || typeof config.open !== "function") {
|
|
22
|
-
throw new SirannonError("Driver must define capabilities and open()", "INVALID_DRIVER");
|
|
23
|
-
}
|
|
24
|
-
if (config.worker !== void 0 && typeof config.worker.specifier !== "string") {
|
|
25
|
-
throw new SirannonError("Driver worker entry must define a string specifier", "INVALID_DRIVER");
|
|
26
|
-
}
|
|
27
|
-
return Object.freeze({
|
|
28
|
-
capabilities: Object.freeze({ ...config.capabilities }),
|
|
29
|
-
open: config.open.bind(config),
|
|
30
|
-
...config.worker ? { worker: Object.freeze({ ...config.worker }) } : {},
|
|
31
|
-
...config.startWriterHost ? { startWriterHost: config.startWriterHost.bind(config) } : {},
|
|
32
|
-
...config.createWriterContext ? { createWriterContext: config.createWriterContext.bind(config) } : {},
|
|
33
|
-
...config.createBackupEngine ? { createBackupEngine: config.createBackupEngine.bind(config) } : {},
|
|
34
|
-
...config.resolveExtensionPath ? { resolveExtensionPath: config.resolveExtensionPath.bind(config) } : {}
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// src/core/driver/statement-text.ts
|
|
39
|
-
var SPACE = 32;
|
|
40
|
-
var TAB = 9;
|
|
41
|
-
var LINE_FEED = 10;
|
|
42
|
-
var VERTICAL_TAB = 11;
|
|
43
|
-
var FORM_FEED = 12;
|
|
44
|
-
var CARRIAGE_RETURN = 13;
|
|
45
|
-
var SEMICOLON = 59;
|
|
46
|
-
var HYPHEN = 45;
|
|
47
|
-
var SLASH = 47;
|
|
48
|
-
var ASTERISK = 42;
|
|
49
|
-
var NO_STATEMENT_MESSAGE = "The supplied SQL string contains no statements";
|
|
50
|
-
function startsSqliteSpace(code) {
|
|
51
|
-
return code === SPACE || code === TAB || code === LINE_FEED || code === FORM_FEED || code === CARRIAGE_RETURN;
|
|
52
|
-
}
|
|
53
|
-
function continuesSqliteSpace(code) {
|
|
54
|
-
return startsSqliteSpace(code) || code === VERTICAL_TAB;
|
|
55
|
-
}
|
|
56
|
-
function holdsNoStatement(sql) {
|
|
57
|
-
const firstNul = sql.indexOf("\0");
|
|
58
|
-
const text = firstNul === -1 ? sql : sql.slice(0, firstNul);
|
|
59
|
-
let index = 0;
|
|
60
|
-
while (index < text.length) {
|
|
61
|
-
const code = text.charCodeAt(index);
|
|
62
|
-
if (startsSqliteSpace(code)) {
|
|
63
|
-
index++;
|
|
64
|
-
while (index < text.length && continuesSqliteSpace(text.charCodeAt(index))) index++;
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
if (code === SEMICOLON) {
|
|
68
|
-
index++;
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
const next = text.charCodeAt(index + 1);
|
|
72
|
-
if (code === HYPHEN && next === HYPHEN) {
|
|
73
|
-
const lineEnd = text.indexOf("\n", index + 2);
|
|
74
|
-
if (lineEnd === -1) return true;
|
|
75
|
-
index = lineEnd;
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
if (code === SLASH && next === ASTERISK && index + 2 < text.length) {
|
|
79
|
-
const commentEnd = text.indexOf("*/", index + 2);
|
|
80
|
-
if (commentEnd === -1) return true;
|
|
81
|
-
index = commentEnd + 2;
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
return true;
|
|
87
|
-
}
|
|
88
|
-
function assertHoldsStatement(sql) {
|
|
89
|
-
if (holdsNoStatement(sql)) throw new RangeError(NO_STATEMENT_MESSAGE);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// src/core/driver/synchronous.ts
|
|
93
|
-
var DEFAULT_SYNCHRONOUS = "normal";
|
|
94
|
-
var SYNCHRONOUS_PRAGMA_VALUES = {
|
|
95
|
-
off: "OFF",
|
|
96
|
-
normal: "NORMAL",
|
|
97
|
-
full: "FULL",
|
|
98
|
-
extra: "EXTRA"
|
|
99
|
-
};
|
|
100
|
-
function synchronousPragmaValue(level) {
|
|
101
|
-
const resolved = level ?? DEFAULT_SYNCHRONOUS;
|
|
102
|
-
const value = SYNCHRONOUS_PRAGMA_VALUES[resolved];
|
|
103
|
-
if (value === void 0) {
|
|
104
|
-
throw new SirannonError(
|
|
105
|
-
`Invalid synchronous level '${String(resolved)}': expected 'off', 'normal', 'full', or 'extra'`,
|
|
106
|
-
"INVALID_SYNCHRONOUS"
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
return value;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// src/core/driver/values.ts
|
|
113
|
-
var SAFE_INT_BOUND = 9007199254740991n;
|
|
114
|
-
function narrowSafeBigInt(value) {
|
|
115
|
-
if (typeof value === "bigint" && value >= -SAFE_INT_BOUND && value <= SAFE_INT_BOUND) {
|
|
116
|
-
return Number(value);
|
|
117
|
-
}
|
|
118
|
-
return value;
|
|
119
|
-
}
|
|
120
|
-
function narrowRowIntegers(row) {
|
|
121
|
-
if (row === null || typeof row !== "object") return row;
|
|
122
|
-
const obj = row;
|
|
123
|
-
for (const key of Object.keys(obj)) {
|
|
124
|
-
const value = obj[key];
|
|
125
|
-
if (typeof value === "bigint" && value >= -SAFE_INT_BOUND && value <= SAFE_INT_BOUND) {
|
|
126
|
-
obj[key] = Number(value);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return row;
|
|
130
|
-
}
|
|
131
|
-
function narrowRowsIntegers(rows) {
|
|
132
|
-
for (const row of rows) {
|
|
133
|
-
narrowRowIntegers(row);
|
|
134
|
-
}
|
|
135
|
-
return rows;
|
|
136
|
-
}
|
|
137
|
-
var EMPTY_BLOB_WITH_ALLOCATED_STORAGE = new Uint8Array(new ArrayBuffer(1), 0, 0);
|
|
138
|
-
function bindableValue(value) {
|
|
139
|
-
if (typeof value === "boolean") return value ? 1n : 0n;
|
|
140
|
-
if (ArrayBuffer.isView(value) && value.byteLength === 0) return EMPTY_BLOB_WITH_ALLOCATED_STORAGE;
|
|
141
|
-
return value;
|
|
142
|
-
}
|
|
143
|
-
function isNamedParams(value) {
|
|
144
|
-
if (value === null || typeof value !== "object") return false;
|
|
145
|
-
const prototype = Object.getPrototypeOf(value);
|
|
146
|
-
return prototype === Object.prototype || prototype === null;
|
|
147
|
-
}
|
|
148
|
-
function bindableNamedParams(params) {
|
|
149
|
-
let bound;
|
|
150
|
-
for (const key of Object.keys(params)) {
|
|
151
|
-
const value = params[key];
|
|
152
|
-
const replacement = bindableValue(value);
|
|
153
|
-
if (replacement === value) continue;
|
|
154
|
-
bound ??= { ...params };
|
|
155
|
-
bound[key] = replacement;
|
|
156
|
-
}
|
|
157
|
-
return bound ?? params;
|
|
158
|
-
}
|
|
159
|
-
function bindableParams(params) {
|
|
160
|
-
let bound;
|
|
161
|
-
for (let index = 0; index < params.length; index++) {
|
|
162
|
-
const value = params[index];
|
|
163
|
-
const replacement = isNamedParams(value) ? bindableNamedParams(value) : bindableValue(value);
|
|
164
|
-
if (replacement === value) continue;
|
|
165
|
-
bound ??= [...params];
|
|
166
|
-
bound[index] = replacement;
|
|
167
|
-
}
|
|
168
|
-
return bound ?? params;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export { ExtensionError, SirannonError, assertHoldsStatement, bindableParams, defineDriver, isNamedParams, narrowRowIntegers, narrowRowsIntegers, narrowSafeBigInt, synchronousPragmaValue };
|
package/dist/chunk-W67A4H2E.mjs
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// src/core/backup/start-guard.ts
|
|
2
|
-
async function startCopyWithoutHoldingWriter(runExclusive, start) {
|
|
3
|
-
let begin;
|
|
4
|
-
let release;
|
|
5
|
-
const writerHeld = new Promise((resolve) => {
|
|
6
|
-
begin = resolve;
|
|
7
|
-
});
|
|
8
|
-
const firstStepDone = new Promise((resolve) => {
|
|
9
|
-
release = resolve;
|
|
10
|
-
});
|
|
11
|
-
const run = (async () => {
|
|
12
|
-
await writerHeld;
|
|
13
|
-
return start(release);
|
|
14
|
-
})();
|
|
15
|
-
run.then(release, release);
|
|
16
|
-
await runExclusive(async () => {
|
|
17
|
-
begin();
|
|
18
|
-
await firstStepDone;
|
|
19
|
-
});
|
|
20
|
-
return run;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export { startCopyWithoutHoldingWriter };
|
package/dist/chunk-YW7IKQ7T.mjs
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { SirannonError } from './chunk-KINDFBQP.mjs';
|
|
2
|
-
|
|
3
|
-
// src/core/backup/chain-queries.ts
|
|
4
|
-
function chainError(message) {
|
|
5
|
-
return new SirannonError(message, "BACKUP_CHAIN_BROKEN");
|
|
6
|
-
}
|
|
7
|
-
function firstMissingSequence(changes) {
|
|
8
|
-
for (let expected = 1; expected <= changes.length; expected++) {
|
|
9
|
-
if (changes[expected - 1]?.sequence !== expected) return expected;
|
|
10
|
-
}
|
|
11
|
-
return void 0;
|
|
12
|
-
}
|
|
13
|
-
function withBase(chains) {
|
|
14
|
-
return chains.filter((chain) => chain.base !== void 0);
|
|
15
|
-
}
|
|
16
|
-
function planBackupRestore(chains, moment) {
|
|
17
|
-
const candidates = withBase(chains).filter((chain2) => chain2.base.finishedAt <= moment).sort((left, right) => right.base.finishedAt - left.base.finishedAt);
|
|
18
|
-
const chain = candidates[0];
|
|
19
|
-
if (!chain) {
|
|
20
|
-
const earliest = withBase(chains).map((candidate) => candidate.base.finishedAt).sort((left, right) => left - right)[0];
|
|
21
|
-
throw chainError(
|
|
22
|
-
earliest === void 0 ? "The destination holds no full copy, so no moment can be restored" : `The destination holds no full copy finished at or before ${new Date(moment).toISOString()}; the earliest moment it can restore is ${new Date(earliest).toISOString()}`
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
const changes = chain.changes.filter((change) => change.capturedAt <= moment);
|
|
26
|
-
const missing = firstMissingSequence(changes);
|
|
27
|
-
if (missing !== void 0) {
|
|
28
|
-
throw chainError(
|
|
29
|
-
`Chain '${chain.chainId}' is missing change piece ${missing}, so it cannot be applied past piece ${missing - 1}`
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
const last = changes[changes.length - 1];
|
|
33
|
-
return {
|
|
34
|
-
chainId: chain.chainId,
|
|
35
|
-
base: chain.base,
|
|
36
|
-
changes,
|
|
37
|
-
restoresTo: last ? last.capturedAt : chain.base.finishedAt
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
function backupPiecesSafeToDelete(chains, options) {
|
|
41
|
-
const restorableFrom = options?.restorableFrom;
|
|
42
|
-
const superseded = restorableFrom === void 0 ? void 0 : withBase(chains).filter((chain) => chain.base.finishedAt <= restorableFrom).sort((left, right) => right.base.finishedAt - left.base.finishedAt)[0];
|
|
43
|
-
const oldestFirst = [...chains].sort((left, right) => left.startedAt - right.startedAt);
|
|
44
|
-
const deletable = [];
|
|
45
|
-
for (const chain of oldestFirst) {
|
|
46
|
-
if (!chain.base) {
|
|
47
|
-
deletable.push(...chain.changes);
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
if (superseded && chain.base.finishedAt < superseded.base.finishedAt) {
|
|
51
|
-
deletable.push(chain.base, ...chain.changes);
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
const missing = firstMissingSequence(chain.changes);
|
|
55
|
-
if (missing !== void 0) {
|
|
56
|
-
deletable.push(...chain.changes.filter((change) => change.sequence > missing));
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return deletable;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export { backupPiecesSafeToDelete, planBackupRestore };
|