@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
package/dist/backup/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { B as BackupDestination, g as BackupRunReport } from '../types-
|
|
2
|
-
export { h as BackupChain, i as BackupChainBase, j as BackupChainChange, k as BackupChainPosition, l as BackupChainRecord, m as BackupCycle, n as BackupCycleError, o as BackupCycleOptions, p as BackupCycleStatus, q as BackupFileReport, r as BackupGroupMembership, s as BackupGroupSource, t as BackupLogPosition, u as BackupNodePreference, v as BackupPiece, w as BackupProgress, x as BackupSkip, y as BackupSkipReason, z as BackupToDestinationOptions, C as BackupVerifyResult,
|
|
3
|
-
export { B as BackupCapabilities, a as BackupChainLocation, b as BackupRestorePlan, c as BackupSafeToDeleteOptions, d as backupPiecesSafeToDelete, p as planBackupRestore } from '../database-backup-
|
|
4
|
-
import { B as BackupRestoreOptions, a as BackupRestoreReport } from '../restore-options-
|
|
5
|
-
export { b as BackupRestoreProgress } from '../restore-options-
|
|
1
|
+
import { B as BackupDestination, g as BackupRunReport } from '../types-BWyv_N18.js';
|
|
2
|
+
export { h as BackupChain, i as BackupChainBase, j as BackupChainChange, k as BackupChainPosition, l as BackupChainRecord, m as BackupCycle, n as BackupCycleError, o as BackupCycleOptions, p as BackupCycleStatus, q as BackupFileReport, r as BackupGroupMembership, s as BackupGroupSource, t as BackupLogPosition, u as BackupNodePreference, v as BackupPiece, w as BackupProgress, x as BackupSkip, y as BackupSkipReason, z as BackupToDestinationOptions, C as BackupVerifyResult, F as DEFAULT_CHAIN_NAME, G as chainLogName, H as readBackupChains, I as verifyBackupRecord } from '../types-BWyv_N18.js';
|
|
3
|
+
export { B as BackupCapabilities, a as BackupChainLocation, b as BackupRestorePlan, c as BackupSafeToDeleteOptions, d as backupPiecesSafeToDelete, p as planBackupRestore } from '../database-backup-BhM8yJ1A.js';
|
|
4
|
+
import { B as BackupRestoreOptions, a as BackupRestoreReport } from '../restore-options-B6HV_5XT.js';
|
|
5
|
+
export { b as BackupRestoreProgress } from '../restore-options-B6HV_5XT.js';
|
|
6
6
|
import '../query-types-5B02ixH0.js';
|
|
7
7
|
|
|
8
8
|
/** The byte and piece counts for one file that Sirannon assembles from a destination.
|
package/dist/backup/index.mjs
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
export { assembleFromDestination, restoreBackup } from '../chunk-
|
|
2
|
-
export { backupPiecesSafeToDelete, planBackupRestore } from '../chunk-
|
|
1
|
+
export { assembleFromDestination, restoreBackup } from '../chunk-MO4APBYG.mjs';
|
|
2
|
+
export { backupPiecesSafeToDelete, planBackupRestore } from '../chunk-W74HFQFD.mjs';
|
|
3
|
+
import '../chunk-5DKWHT6K.mjs';
|
|
3
4
|
export { verifyBackupRecord } from '../chunk-DX4WGJL7.mjs';
|
|
4
5
|
import '../chunk-QGVRRKB2.mjs';
|
|
5
6
|
import '../chunk-BUWJH3D3.mjs';
|
|
6
|
-
export { DEFAULT_CHAIN_NAME, chainLogName, readBackupChains } from '../chunk-
|
|
7
|
+
export { DEFAULT_CHAIN_NAME, chainLogName, readBackupChains } from '../chunk-6CABU54O.mjs';
|
|
7
8
|
import '../chunk-BGJ5JVYL.mjs';
|
|
8
9
|
import '../chunk-HO2XTXVX.mjs';
|
|
10
|
+
import '../chunk-5O4J6LQQ.mjs';
|
|
9
11
|
import '../chunk-KINDFBQP.mjs';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { q as BackupFileReport,
|
|
1
|
+
import { L as SQLiteConnection, O as BackupFileCopy, P as BackupRunRequest, g as BackupRunReport, Q as BackupScheduleRequest } from '../types-BWyv_N18.js';
|
|
2
|
+
export { q as BackupFileReport, R as BackupScheduleOptions, U as RunExclusive } from '../types-BWyv_N18.js';
|
|
3
3
|
import '../query-types-5B02ixH0.js';
|
|
4
4
|
|
|
5
5
|
/** What a runtime supplies so that Sirannon can send a copy to a destination without writing a local file.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { BackupScheduler } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
1
|
+
export { BackupScheduler } from '../chunk-N3MHZV3B.mjs';
|
|
2
|
+
import '../chunk-I4JY5QPA.mjs';
|
|
3
3
|
import '../chunk-AHCMO4YL.mjs';
|
|
4
4
|
import '../chunk-BUWJH3D3.mjs';
|
|
5
5
|
import '../chunk-BGJ5JVYL.mjs';
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// src/core/driver/statement-text.ts
|
|
2
|
+
var SPACE = 32;
|
|
3
|
+
var TAB = 9;
|
|
4
|
+
var LINE_FEED = 10;
|
|
5
|
+
var VERTICAL_TAB = 11;
|
|
6
|
+
var FORM_FEED = 12;
|
|
7
|
+
var CARRIAGE_RETURN = 13;
|
|
8
|
+
var SEMICOLON = 59;
|
|
9
|
+
var HYPHEN = 45;
|
|
10
|
+
var SLASH = 47;
|
|
11
|
+
var ASTERISK = 42;
|
|
12
|
+
var NO_STATEMENT_MESSAGE = "The supplied SQL string contains no statements";
|
|
13
|
+
function startsSqliteSpace(code) {
|
|
14
|
+
return code === SPACE || code === TAB || code === LINE_FEED || code === FORM_FEED || code === CARRIAGE_RETURN;
|
|
15
|
+
}
|
|
16
|
+
function continuesSqliteSpace(code) {
|
|
17
|
+
return startsSqliteSpace(code) || code === VERTICAL_TAB;
|
|
18
|
+
}
|
|
19
|
+
function holdsNoStatement(sql) {
|
|
20
|
+
const firstNul = sql.indexOf("\0");
|
|
21
|
+
const text = firstNul === -1 ? sql : sql.slice(0, firstNul);
|
|
22
|
+
let index = 0;
|
|
23
|
+
while (index < text.length) {
|
|
24
|
+
const code = text.charCodeAt(index);
|
|
25
|
+
if (startsSqliteSpace(code)) {
|
|
26
|
+
index++;
|
|
27
|
+
while (index < text.length && continuesSqliteSpace(text.charCodeAt(index))) index++;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (code === SEMICOLON) {
|
|
31
|
+
index++;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const next = text.charCodeAt(index + 1);
|
|
35
|
+
if (code === HYPHEN && next === HYPHEN) {
|
|
36
|
+
const lineEnd = text.indexOf("\n", index + 2);
|
|
37
|
+
if (lineEnd === -1) return true;
|
|
38
|
+
index = lineEnd;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (code === SLASH && next === ASTERISK && index + 2 < text.length) {
|
|
42
|
+
const commentEnd = text.indexOf("*/", index + 2);
|
|
43
|
+
if (commentEnd === -1) return true;
|
|
44
|
+
index = commentEnd + 2;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
function assertHoldsStatement(sql) {
|
|
52
|
+
if (holdsNoStatement(sql)) throw new RangeError(NO_STATEMENT_MESSAGE);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export { assertHoldsStatement };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { selectOrdinaryTableName, deleteReplacedRowsOfTable, selectMinChangeSeqSql, selectMaxChangeSeq, deleteChangesBeforeUpToSeqSql, deleteAllReplacedRows, selectTableExists, ensureChangesTable, ensureReplacedRowsTable, ensureMetaTable, insertMetaValueIfAbsent, selectMetaValue, selectTriggerSql, selectChangesAfterSeqSql, selectTablesChangesInRangeSql, tableInfoRows, primaryKeyColumns, tableColumnsWithGenerated, tableIndexList, indexColumns, selectTableSql, TABLE_XINFO_HIDDEN, deleteExpiredDeviceCursors, selectMinDeviceCursorBoundary, SEQ_STRING_RE, selectIndexSql } from './chunk-
|
|
2
|
-
import { CDC_TRIGGER_PREFIX, CHANGES_TABLE, isReservedIdentifier, META_TABLE, encodeTaggedValues, REPLACED_ROWS_TABLE, changedAtToEventTimestamp, decodeTaggedValues, DEVICE_CURSORS_TABLE, SAFE_INT_BOUND_TEXT } from './chunk-
|
|
1
|
+
import { selectOrdinaryTableName, deleteReplacedRowsOfTable, selectMinChangeSeqSql, selectMaxChangeSeq, deleteChangesBeforeUpToSeqSql, deleteAllReplacedRows, selectTableExists, ensureChangesTable, ensureReplacedRowsTable, ensureMetaTable, insertMetaValueIfAbsent, selectMetaValue, selectTriggerSql, selectChangesAfterSeqSql, selectTablesChangesInRangeSql, tableInfoRows, primaryKeyColumns, tableColumnsWithGenerated, tableIndexList, indexColumns, selectTableSql, TABLE_XINFO_HIDDEN, deleteExpiredDeviceCursors, selectMinDeviceCursorBoundary, SEQ_STRING_RE, selectIndexSql } from './chunk-MTOQ6QIS.mjs';
|
|
2
|
+
import { CDC_TRIGGER_PREFIX, CHANGES_TABLE, isReservedIdentifier, META_TABLE, encodeTaggedValues, REPLACED_ROWS_TABLE, changedAtToEventTimestamp, decodeTaggedValues, DEVICE_CURSORS_TABLE, SAFE_INT_BOUND_TEXT } from './chunk-ZAUHAJ4G.mjs';
|
|
3
3
|
import { tokenizeSql, isKeyword } from './chunk-SEL4A4WT.mjs';
|
|
4
|
-
import { synchronousPragmaValue } from './chunk-YCMB6GR4.mjs';
|
|
5
4
|
import { randomHex } from './chunk-BGJ5JVYL.mjs';
|
|
6
5
|
import { invokeCallerCallback, reportCallerFailure, toError } from './chunk-HO2XTXVX.mjs';
|
|
6
|
+
import { synchronousPragmaValue } from './chunk-YCMB6GR4.mjs';
|
|
7
7
|
import { SirannonError, ForbiddenSqlError, CDCError, MigrationError } from './chunk-KINDFBQP.mjs';
|
|
8
8
|
|
|
9
9
|
// src/core/bulk-load.ts
|
|
@@ -666,6 +666,28 @@ function buildJsonObject(columns, ref) {
|
|
|
666
666
|
function escStr(name) {
|
|
667
667
|
return name.replace(/'/g, "''");
|
|
668
668
|
}
|
|
669
|
+
async function installKeyChangeCaptureTriggers(conn, triggers, table, log, keys) {
|
|
670
|
+
const logOf = (row) => `INSERT INTO "${escId(log)}" VALUES (${keys.map((key) => `${row}.${key}`).join(", ")});`;
|
|
671
|
+
const on = `main."${escId(table)}"`;
|
|
672
|
+
await conn.exec(`CREATE TEMP TRIGGER "${escId(triggers.insert)}" AFTER INSERT ON ${on} BEGIN ${logOf("NEW")} END`);
|
|
673
|
+
await conn.exec(
|
|
674
|
+
`CREATE TEMP TRIGGER "${escId(triggers.update)}" AFTER UPDATE ON ${on} BEGIN ${logOf("OLD")} ${logOf("NEW")} END`
|
|
675
|
+
);
|
|
676
|
+
await conn.exec(`CREATE TEMP TRIGGER "${escId(triggers.delete)}" AFTER DELETE ON ${on} BEGIN ${logOf("OLD")} END`);
|
|
677
|
+
}
|
|
678
|
+
async function dropKeyChangeCaptureTriggers(conn, triggers) {
|
|
679
|
+
for (const name of [triggers.insert, triggers.update, triggers.delete]) {
|
|
680
|
+
await conn.exec(`DROP TRIGGER IF EXISTS temp."${escId(name)}"`);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
async function dropMainSchemaTriggers(conn) {
|
|
684
|
+
const triggers = await (await conn.prepare("SELECT name, sql FROM main.sqlite_schema WHERE type = 'trigger' AND sql IS NOT NULL")).all();
|
|
685
|
+
for (const trigger of triggers) await conn.exec(`DROP TRIGGER main."${escId(trigger.name)}"`);
|
|
686
|
+
return triggers.map((trigger) => trigger.sql);
|
|
687
|
+
}
|
|
688
|
+
async function createMainSchemaTriggers(conn, statements) {
|
|
689
|
+
for (const statement of statements) await conn.exec(statement);
|
|
690
|
+
}
|
|
669
691
|
|
|
670
692
|
// src/core/cdc/change-tracker.ts
|
|
671
693
|
var DEFAULT_RETENTION_MS = 36e5;
|
|
@@ -1155,7 +1177,7 @@ var SubscriptionBuilderImpl = class {
|
|
|
1155
1177
|
return this.manager.subscribe(this.table, this.conditions, callback, options);
|
|
1156
1178
|
}
|
|
1157
1179
|
};
|
|
1158
|
-
function startPolling(
|
|
1180
|
+
function startPolling(connection, tracker, manager, intervalMs, onError, runExclusive, deviceRetention = {
|
|
1159
1181
|
cursorRetentionMs: DEFAULT_DEVICE_CURSOR_RETENTION_MS,
|
|
1160
1182
|
maxChangesHeldForDevice: 0
|
|
1161
1183
|
}) {
|
|
@@ -1170,7 +1192,7 @@ function startPolling(conn, tracker, manager, intervalMs, onError, runExclusive,
|
|
|
1170
1192
|
if (polling) return;
|
|
1171
1193
|
polling = true;
|
|
1172
1194
|
try {
|
|
1173
|
-
const events = await exclusive(() => tracker.poll(
|
|
1195
|
+
const events = await exclusive(() => tracker.poll(connection()));
|
|
1174
1196
|
if (events.length > 0) {
|
|
1175
1197
|
manager.dispatch(events);
|
|
1176
1198
|
}
|
|
@@ -1180,6 +1202,7 @@ function startPolling(conn, tracker, manager, intervalMs, onError, runExclusive,
|
|
|
1180
1202
|
if (tickCount >= CLEANUP_INTERVAL_TICKS) {
|
|
1181
1203
|
tickCount = 0;
|
|
1182
1204
|
await exclusive(async () => {
|
|
1205
|
+
const conn = connection();
|
|
1183
1206
|
await applyDeviceCursorBoundary(conn, tracker, deviceRetention);
|
|
1184
1207
|
await tracker.cleanup(conn);
|
|
1185
1208
|
});
|
|
@@ -1371,4 +1394,4 @@ var TransactionGrouper = class {
|
|
|
1371
1394
|
}
|
|
1372
1395
|
};
|
|
1373
1396
|
|
|
1374
|
-
export { ChangeTracker, DEVICE_SYNC_PUSHED_SEQ_META_KEY, PrimedSubscription, ROWID_ALIASES, SubscriptionBuilderImpl, SubscriptionManager, TransactionGrouper, applyDeviceCursorBoundary, dropCdcTriggers, ensureCdcEpoch, filteredChange, isBulkLoadDurability, migrationChecksum, migrationContentChecksum, needsResync, parseColumnDefinitions, reconcileMigrationChecksums, resolveDeviceRetentionPolicy, runBulkLoad, startPolling };
|
|
1397
|
+
export { ChangeTracker, DEVICE_SYNC_PUSHED_SEQ_META_KEY, PrimedSubscription, ROWID_ALIASES, SubscriptionBuilderImpl, SubscriptionManager, TransactionGrouper, applyDeviceCursorBoundary, createMainSchemaTriggers, dropCdcTriggers, dropKeyChangeCaptureTriggers, dropMainSchemaTriggers, ensureCdcEpoch, escId, filteredChange, installKeyChangeCaptureTriggers, isBulkLoadDurability, migrationChecksum, migrationContentChecksum, needsResync, parseColumnDefinitions, reconcileMigrationChecksums, resolveDeviceRetentionPolicy, runBulkLoad, startPolling };
|
|
@@ -883,7 +883,7 @@ var AckPayload = {
|
|
|
883
883
|
}
|
|
884
884
|
};
|
|
885
885
|
function createBaseHello() {
|
|
886
|
-
return { nodeId: "", role: "", groupId: "", primaryTerm: 0n, protocolVersion: "" };
|
|
886
|
+
return { nodeId: "", role: "", groupId: "", primaryTerm: 0n, protocolVersion: "", encrypted: false };
|
|
887
887
|
}
|
|
888
888
|
var Hello = {
|
|
889
889
|
encode(message, writer = new BinaryWriter()) {
|
|
@@ -905,6 +905,9 @@ var Hello = {
|
|
|
905
905
|
if (message.protocolVersion !== "") {
|
|
906
906
|
writer.uint32(42).string(message.protocolVersion);
|
|
907
907
|
}
|
|
908
|
+
if (message.encrypted !== false) {
|
|
909
|
+
writer.uint32(48).bool(message.encrypted);
|
|
910
|
+
}
|
|
908
911
|
return writer;
|
|
909
912
|
},
|
|
910
913
|
decode(input, length) {
|
|
@@ -949,6 +952,13 @@ var Hello = {
|
|
|
949
952
|
message.protocolVersion = reader.string();
|
|
950
953
|
continue;
|
|
951
954
|
}
|
|
955
|
+
case 6: {
|
|
956
|
+
if (tag !== 48) {
|
|
957
|
+
break;
|
|
958
|
+
}
|
|
959
|
+
message.encrypted = reader.bool();
|
|
960
|
+
continue;
|
|
961
|
+
}
|
|
952
962
|
}
|
|
953
963
|
if ((tag & 7) === 4 || tag === 0) {
|
|
954
964
|
break;
|
|
@@ -963,7 +973,8 @@ var Hello = {
|
|
|
963
973
|
role: isSet(object.role) ? globalThis.String(object.role) : "",
|
|
964
974
|
groupId: isSet(object.groupId) ? globalThis.String(object.groupId) : isSet(object.group_id) ? globalThis.String(object.group_id) : "",
|
|
965
975
|
primaryTerm: isSet(object.primaryTerm) ? BigInt(object.primaryTerm) : isSet(object.primary_term) ? BigInt(object.primary_term) : 0n,
|
|
966
|
-
protocolVersion: isSet(object.protocolVersion) ? globalThis.String(object.protocolVersion) : isSet(object.protocol_version) ? globalThis.String(object.protocol_version) : ""
|
|
976
|
+
protocolVersion: isSet(object.protocolVersion) ? globalThis.String(object.protocolVersion) : isSet(object.protocol_version) ? globalThis.String(object.protocol_version) : "",
|
|
977
|
+
encrypted: isSet(object.encrypted) ? globalThis.Boolean(object.encrypted) : false
|
|
967
978
|
};
|
|
968
979
|
},
|
|
969
980
|
toJSON(message) {
|
|
@@ -983,6 +994,9 @@ var Hello = {
|
|
|
983
994
|
if (message.protocolVersion !== "") {
|
|
984
995
|
obj.protocolVersion = message.protocolVersion;
|
|
985
996
|
}
|
|
997
|
+
if (message.encrypted !== false) {
|
|
998
|
+
obj.encrypted = message.encrypted;
|
|
999
|
+
}
|
|
986
1000
|
return obj;
|
|
987
1001
|
},
|
|
988
1002
|
create(base) {
|
|
@@ -995,6 +1009,7 @@ var Hello = {
|
|
|
995
1009
|
message.groupId = object.groupId ?? "";
|
|
996
1010
|
message.primaryTerm = object.primaryTerm ?? 0n;
|
|
997
1011
|
message.protocolVersion = object.protocolVersion ?? "";
|
|
1012
|
+
message.encrypted = object.encrypted ?? false;
|
|
998
1013
|
return message;
|
|
999
1014
|
}
|
|
1000
1015
|
};
|
|
@@ -2639,4 +2654,24 @@ function buildChannelCreds(options) {
|
|
|
2639
2654
|
return credentials.createSsl(ca, key, cert);
|
|
2640
2655
|
}
|
|
2641
2656
|
|
|
2642
|
-
|
|
2657
|
+
// src/transport/grpc/hello.ts
|
|
2658
|
+
function localHello(t) {
|
|
2659
|
+
return {
|
|
2660
|
+
nodeId: t.localNodeId,
|
|
2661
|
+
role: t.localRole,
|
|
2662
|
+
groupId: t.localGroupId ?? "",
|
|
2663
|
+
primaryTerm: t.localPrimaryTerm ?? 0n,
|
|
2664
|
+
protocolVersion: t.localProtocolVersion ?? "",
|
|
2665
|
+
encrypted: t.localEncrypted
|
|
2666
|
+
};
|
|
2667
|
+
}
|
|
2668
|
+
function peerHelloFields(hello) {
|
|
2669
|
+
return {
|
|
2670
|
+
groupId: hello.groupId || void 0,
|
|
2671
|
+
primaryTerm: hello.primaryTerm === 0n ? void 0 : hello.primaryTerm,
|
|
2672
|
+
protocolVersion: hello.protocolVersion || void 0,
|
|
2673
|
+
encrypted: hello.encrypted === true
|
|
2674
|
+
};
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2677
|
+
export { ReplicationClient, ReplicationService, buildChannelCreds, buildServerCreds, localHello, peerHelloFields };
|
|
@@ -94,6 +94,54 @@ function getDotPath(issue) {
|
|
|
94
94
|
return null;
|
|
95
95
|
}
|
|
96
96
|
// @__NO_SIDE_EFFECTS__
|
|
97
|
+
function check(requirement, message$1) {
|
|
98
|
+
return {
|
|
99
|
+
kind: "validation",
|
|
100
|
+
type: "check",
|
|
101
|
+
reference: check,
|
|
102
|
+
async: false,
|
|
103
|
+
expects: null,
|
|
104
|
+
requirement,
|
|
105
|
+
message: message$1,
|
|
106
|
+
"~run"(dataset, config$1) {
|
|
107
|
+
if (dataset.typed && !this.requirement(dataset.value)) _addIssue(this, "input", dataset, config$1);
|
|
108
|
+
return dataset;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// @__NO_SIDE_EFFECTS__
|
|
113
|
+
function maxLength(requirement, message$1) {
|
|
114
|
+
return {
|
|
115
|
+
kind: "validation",
|
|
116
|
+
type: "max_length",
|
|
117
|
+
reference: maxLength,
|
|
118
|
+
async: false,
|
|
119
|
+
expects: `<=${requirement}`,
|
|
120
|
+
requirement,
|
|
121
|
+
message: message$1,
|
|
122
|
+
"~run"(dataset, config$1) {
|
|
123
|
+
if (dataset.typed && dataset.value.length > this.requirement) _addIssue(this, "length", dataset, config$1, { received: `${dataset.value.length}` });
|
|
124
|
+
return dataset;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
// @__NO_SIDE_EFFECTS__
|
|
129
|
+
function minLength(requirement, message$1) {
|
|
130
|
+
return {
|
|
131
|
+
kind: "validation",
|
|
132
|
+
type: "min_length",
|
|
133
|
+
reference: minLength,
|
|
134
|
+
async: false,
|
|
135
|
+
expects: `>=${requirement}`,
|
|
136
|
+
requirement,
|
|
137
|
+
message: message$1,
|
|
138
|
+
"~run"(dataset, config$1) {
|
|
139
|
+
if (dataset.typed && dataset.value.length < this.requirement) _addIssue(this, "length", dataset, config$1, { received: `${dataset.value.length}` });
|
|
140
|
+
return dataset;
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
// @__NO_SIDE_EFFECTS__
|
|
97
145
|
function regex(requirement, message$1) {
|
|
98
146
|
return {
|
|
99
147
|
kind: "validation",
|
|
@@ -163,6 +211,23 @@ function array(item, message$1) {
|
|
|
163
211
|
});
|
|
164
212
|
}
|
|
165
213
|
// @__NO_SIDE_EFFECTS__
|
|
214
|
+
function instance(class_, message$1) {
|
|
215
|
+
return _standardSchema({
|
|
216
|
+
kind: "schema",
|
|
217
|
+
type: "instance",
|
|
218
|
+
reference: instance,
|
|
219
|
+
expects: class_.name,
|
|
220
|
+
async: false,
|
|
221
|
+
class: class_,
|
|
222
|
+
message: message$1,
|
|
223
|
+
"~run"(dataset, config$1) {
|
|
224
|
+
if (dataset.value instanceof this.class) dataset.typed = true;
|
|
225
|
+
else _addIssue(this, "type", dataset, config$1);
|
|
226
|
+
return dataset;
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
// @__NO_SIDE_EFFECTS__
|
|
166
231
|
function nullable(wrapped, default_) {
|
|
167
232
|
return _standardSchema({
|
|
168
233
|
kind: "schema",
|
|
@@ -383,6 +448,49 @@ function string(message$1) {
|
|
|
383
448
|
});
|
|
384
449
|
}
|
|
385
450
|
// @__NO_SIDE_EFFECTS__
|
|
451
|
+
function _subIssues(datasets) {
|
|
452
|
+
let issues;
|
|
453
|
+
if (datasets) for (const dataset of datasets) if (issues) for (const issue of dataset.issues) issues.push(issue);
|
|
454
|
+
else issues = dataset.issues;
|
|
455
|
+
return issues;
|
|
456
|
+
}
|
|
457
|
+
// @__NO_SIDE_EFFECTS__
|
|
458
|
+
function union(options, message$1) {
|
|
459
|
+
return _standardSchema({
|
|
460
|
+
kind: "schema",
|
|
461
|
+
type: "union",
|
|
462
|
+
reference: union,
|
|
463
|
+
expects: /* @__PURE__ */ _joinExpects(options.map((option) => option.expects), "|"),
|
|
464
|
+
async: false,
|
|
465
|
+
options,
|
|
466
|
+
message: message$1,
|
|
467
|
+
"~run"(dataset, config$1) {
|
|
468
|
+
let validDataset;
|
|
469
|
+
let typedDatasets;
|
|
470
|
+
let untypedDatasets;
|
|
471
|
+
for (const schema of this.options) {
|
|
472
|
+
const optionDataset = schema["~run"]({ value: dataset.value }, config$1);
|
|
473
|
+
if (optionDataset.typed) if (optionDataset.issues) if (typedDatasets) typedDatasets.push(optionDataset);
|
|
474
|
+
else typedDatasets = [optionDataset];
|
|
475
|
+
else {
|
|
476
|
+
validDataset = optionDataset;
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
else if (untypedDatasets) untypedDatasets.push(optionDataset);
|
|
480
|
+
else untypedDatasets = [optionDataset];
|
|
481
|
+
}
|
|
482
|
+
if (validDataset) return validDataset;
|
|
483
|
+
if (typedDatasets) {
|
|
484
|
+
if (typedDatasets.length === 1) return typedDatasets[0];
|
|
485
|
+
_addIssue(this, "type", dataset, config$1, { issues: /* @__PURE__ */ _subIssues(typedDatasets) });
|
|
486
|
+
dataset.typed = true;
|
|
487
|
+
} else if (untypedDatasets?.length === 1) return untypedDatasets[0];
|
|
488
|
+
else _addIssue(this, "type", dataset, config$1, { issues: /* @__PURE__ */ _subIssues(untypedDatasets) });
|
|
489
|
+
return dataset;
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
// @__NO_SIDE_EFFECTS__
|
|
386
494
|
function unknown() {
|
|
387
495
|
return _standardSchema({
|
|
388
496
|
kind: "schema",
|
|
@@ -436,4 +544,4 @@ function summarize(issues) {
|
|
|
436
544
|
return summary;
|
|
437
545
|
}
|
|
438
546
|
|
|
439
|
-
export { array, getDotPath, nullable, number, object, optional, picklist, pipe, record, regex, safeParse, string, summarize, unknown };
|
|
547
|
+
export { array, check, getDotPath, instance, maxLength, minLength, nullable, number, object, optional, picklist, pipe, record, regex, safeParse, string, summarize, union, unknown };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { SirannonError } from './chunk-KINDFBQP.mjs';
|
|
2
|
+
|
|
3
|
+
// src/core/encryption/errors.ts
|
|
4
|
+
var EncryptionError = class extends SirannonError {
|
|
5
|
+
/**
|
|
6
|
+
* Returns an error with an encryption code, and the failure that caused it when there is one.
|
|
7
|
+
*
|
|
8
|
+
* @param message - What failed, written without the key.
|
|
9
|
+
* @param code - The machine-readable code.
|
|
10
|
+
* @param cause - The failure that caused this error, such as the error that a key function threw.
|
|
11
|
+
*/
|
|
12
|
+
constructor(message, code, cause) {
|
|
13
|
+
super(message, code);
|
|
14
|
+
this.name = "EncryptionError";
|
|
15
|
+
if (cause !== void 0) {
|
|
16
|
+
Object.defineProperty(this, "cause", { value: cause, enumerable: false, writable: true, configurable: true });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
function keyRejected(path, cause) {
|
|
21
|
+
return new EncryptionError(
|
|
22
|
+
`The key failed the authentication check of the first page of the database ${path}. Either the key is wrong, or the file comes from another encryption scheme: the better-sqlite3 driver encrypts with AEGIS-256 and the Expo driver encrypts with SQLCipher 4, and neither opens the other's files`,
|
|
23
|
+
"ENCRYPTION_KEY_REJECTED",
|
|
24
|
+
cause
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
function refuseEncryptedOpen(driverName, options) {
|
|
28
|
+
if (options?.encryption === void 0) return;
|
|
29
|
+
throw new EncryptionError(
|
|
30
|
+
`The ${driverName} driver opens SQLite through a library that Sirannon cannot replace with an encrypting build, so it cannot open an encrypted database`,
|
|
31
|
+
"ENCRYPTION_UNSUPPORTED"
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export { EncryptionError, keyRejected, refuseEncryptedOpen };
|
|
@@ -20,11 +20,11 @@ function isBackupChainHead(value) {
|
|
|
20
20
|
}
|
|
21
21
|
function isBackupChainBase(value) {
|
|
22
22
|
const base = value;
|
|
23
|
-
return base?.kind === "full" && typeof base.chainId === "string" && typeof base.name === "string" && typeof base.runId === "string" && isWholeNumber(base.finishedAt) && isWholeNumber(base.pieceCount) && isAtLeastOne(base.pieceBytes) && isWholeNumber(base.bytesWritten) && isTextOrAbsent(base.fingerprint);
|
|
23
|
+
return base?.kind === "full" && typeof base.chainId === "string" && typeof base.name === "string" && typeof base.runId === "string" && isWholeNumber(base.finishedAt) && isWholeNumber(base.pieceCount) && isAtLeastOne(base.pieceBytes) && isWholeNumber(base.bytesWritten) && isTextOrAbsent(base.fingerprint) && isTextOrAbsent(base.keyId);
|
|
24
24
|
}
|
|
25
25
|
function isBackupChainChange(value) {
|
|
26
26
|
const change = value;
|
|
27
|
-
return change?.kind === "change" && typeof change.chainId === "string" && typeof change.name === "string" && typeof change.runId === "string" && isAtLeastOne(change.sequence) && isBackupChainPosition(change.position) && isWholeNumber(change.capturedAt) && isAtLeastOne(change.frameCount) && isWholeNumber(change.pieceCount) && isAtLeastOne(change.pieceBytes) && isWholeNumber(change.bytesWritten) && typeof change.checkpointed === "boolean" && isTextOrAbsent(change.fingerprint);
|
|
27
|
+
return change?.kind === "change" && typeof change.chainId === "string" && typeof change.name === "string" && typeof change.runId === "string" && isAtLeastOne(change.sequence) && isBackupChainPosition(change.position) && isWholeNumber(change.capturedAt) && isAtLeastOne(change.frameCount) && isWholeNumber(change.pieceCount) && isAtLeastOne(change.pieceBytes) && isWholeNumber(change.bytesWritten) && typeof change.checkpointed === "boolean" && isTextOrAbsent(change.fingerprint) && isTextOrAbsent(change.keyId);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
// src/core/backup/chain.ts
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { SirannonError } from './chunk-KINDFBQP.mjs';
|
|
2
2
|
|
|
3
3
|
// src/core/driver/define.ts
|
|
4
|
+
function boundFileSystem(files) {
|
|
5
|
+
return Object.freeze({
|
|
6
|
+
readStart: files.readStart.bind(files),
|
|
7
|
+
remove: files.remove.bind(files),
|
|
8
|
+
rename: files.rename.bind(files)
|
|
9
|
+
});
|
|
10
|
+
}
|
|
4
11
|
function defineDriver(config) {
|
|
5
12
|
if (!config.capabilities || typeof config.open !== "function") {
|
|
6
13
|
throw new SirannonError("Driver must define capabilities and open()", "INVALID_DRIVER");
|
|
@@ -9,22 +16,15 @@ function defineDriver(config) {
|
|
|
9
16
|
throw new SirannonError("Driver worker entry must define a string specifier", "INVALID_DRIVER");
|
|
10
17
|
}
|
|
11
18
|
return Object.freeze({
|
|
12
|
-
capabilities: Object.freeze({ ...config.capabilities }),
|
|
19
|
+
capabilities: Object.freeze({ ...config.capabilities, encryption: config.capabilities.encryption === true }),
|
|
13
20
|
open: config.open.bind(config),
|
|
14
21
|
...config.worker ? { worker: Object.freeze({ ...config.worker }) } : {},
|
|
15
22
|
...config.startWriterHost ? { startWriterHost: config.startWriterHost.bind(config) } : {},
|
|
16
23
|
...config.createWriterContext ? { createWriterContext: config.createWriterContext.bind(config) } : {},
|
|
17
24
|
...config.createBackupEngine ? { createBackupEngine: config.createBackupEngine.bind(config) } : {},
|
|
18
|
-
...config.resolveExtensionPath ? { resolveExtensionPath: config.resolveExtensionPath.bind(config) } : {}
|
|
25
|
+
...config.resolveExtensionPath ? { resolveExtensionPath: config.resolveExtensionPath.bind(config) } : {},
|
|
26
|
+
...config.files ? { files: boundFileSystem(config.files) } : {}
|
|
19
27
|
});
|
|
20
28
|
}
|
|
21
29
|
|
|
22
|
-
|
|
23
|
-
var DEFAULT_CAPTURE_INTERVAL_MS = 6e4;
|
|
24
|
-
var DEFAULT_FULL_COPY_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
25
|
-
var DEFAULT_BACKUP_NAME_PREFIX = "sirannon-backup";
|
|
26
|
-
function defaultStagingDir(sourcePath) {
|
|
27
|
-
return `${sourcePath}-backup`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export { DEFAULT_BACKUP_NAME_PREFIX, DEFAULT_CAPTURE_INTERVAL_MS, DEFAULT_FULL_COPY_INTERVAL_MS, defaultStagingDir, defineDriver };
|
|
30
|
+
export { defineDriver };
|
|
@@ -19,6 +19,7 @@ function registerPeer(connectedPeers, peerConnectedHandler, nodeId, role, metada
|
|
|
19
19
|
role,
|
|
20
20
|
primaryTerm: metadata.primaryTerm,
|
|
21
21
|
protocolVersion: metadata.protocolVersion,
|
|
22
|
+
encrypted: metadata.encrypted === true,
|
|
22
23
|
joinedAt: Date.now(),
|
|
23
24
|
lastSeenAt: Date.now(),
|
|
24
25
|
lastAckedSeq: 0n
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { withRowCounts, rowCountsOf } from './chunk-E2GRX4ZD.mjs';
|
|
2
|
+
import { EncryptionError } from './chunk-5O4J6LQQ.mjs';
|
|
3
|
+
import { SirannonError } from './chunk-KINDFBQP.mjs';
|
|
4
|
+
|
|
5
|
+
// src/core/encryption/page-errors.ts
|
|
6
|
+
var PAGE_AUTHENTICATION_FAILURE_CODE = /^SQLITE_(CORRUPT|NOTADB)/;
|
|
7
|
+
var PAGE_AUTHENTICATION_FAILURE_MESSAGE = /database disk image is malformed|file is not a database/i;
|
|
8
|
+
var PAGE_CORRUPT_MESSAGE = "A page of the encrypted database failed its authentication check, so Sirannon returned no rows from it. The file was changed or damaged outside SQLite; restore it from a backup";
|
|
9
|
+
function failsPageAuthentication(err) {
|
|
10
|
+
if (err instanceof SirannonError || typeof err !== "object" || err === null) return false;
|
|
11
|
+
const { code, message } = err;
|
|
12
|
+
if (typeof code === "string" && PAGE_AUTHENTICATION_FAILURE_CODE.test(code)) return true;
|
|
13
|
+
return typeof message === "string" && PAGE_AUTHENTICATION_FAILURE_MESSAGE.test(message);
|
|
14
|
+
}
|
|
15
|
+
function asPageError(err) {
|
|
16
|
+
if (!failsPageAuthentication(err)) return err;
|
|
17
|
+
return withRowCounts(new EncryptionError(PAGE_CORRUPT_MESSAGE, "ENCRYPTED_PAGE_CORRUPT", err), rowCountsOf(err));
|
|
18
|
+
}
|
|
19
|
+
async function guarded(call) {
|
|
20
|
+
try {
|
|
21
|
+
return await call();
|
|
22
|
+
} catch (err) {
|
|
23
|
+
throw asPageError(err);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function guardedStatement(statement) {
|
|
27
|
+
const { allRaw, allCounted, getCounted, allRawCounted } = statement;
|
|
28
|
+
const result = {
|
|
29
|
+
all: (...params) => guarded(() => statement.all(...params)),
|
|
30
|
+
get: (...params) => guarded(() => statement.get(...params)),
|
|
31
|
+
run: (...params) => guarded(() => statement.run(...params))
|
|
32
|
+
};
|
|
33
|
+
if (allRaw)
|
|
34
|
+
result.allRaw = (...params) => guarded(() => allRaw.call(statement, ...params));
|
|
35
|
+
if (allCounted) {
|
|
36
|
+
result.allCounted = (...params) => guarded(() => allCounted.call(statement, ...params));
|
|
37
|
+
}
|
|
38
|
+
if (getCounted) {
|
|
39
|
+
result.getCounted = (...params) => guarded(() => getCounted.call(statement, ...params));
|
|
40
|
+
}
|
|
41
|
+
if (allRawCounted) {
|
|
42
|
+
result.allRawCounted = (...params) => guarded(() => allRawCounted.call(statement, ...params));
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
function guardedOutcomes(outcomes) {
|
|
47
|
+
return outcomes.map((outcome) => {
|
|
48
|
+
if (outcome.ok || !failsPageAuthentication(outcome.error)) return outcome;
|
|
49
|
+
return {
|
|
50
|
+
...outcome,
|
|
51
|
+
error: {
|
|
52
|
+
...outcome.error,
|
|
53
|
+
message: PAGE_CORRUPT_MESSAGE,
|
|
54
|
+
name: "EncryptionError",
|
|
55
|
+
code: "ENCRYPTED_PAGE_CORRUPT"
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function reportEncryptedPageFailures(connection) {
|
|
61
|
+
const guardedConnection = {
|
|
62
|
+
exec: (sql) => guarded(() => connection.exec(sql)),
|
|
63
|
+
prepare: async (sql) => guardedStatement(await guarded(() => connection.prepare(sql))),
|
|
64
|
+
transaction: (fn) => guarded(() => connection.transaction(() => fn(guardedConnection))),
|
|
65
|
+
close: () => connection.close(),
|
|
66
|
+
...connection.copyRunsOffCallerThread === void 0 ? {} : { copyRunsOffCallerThread: connection.copyRunsOffCallerThread }
|
|
67
|
+
};
|
|
68
|
+
const {
|
|
69
|
+
loadExtension,
|
|
70
|
+
copyDatabase,
|
|
71
|
+
runBatch,
|
|
72
|
+
runBatchSummary,
|
|
73
|
+
runGroup,
|
|
74
|
+
startChangeCapture,
|
|
75
|
+
takeCapturedChanges,
|
|
76
|
+
stopChangeCapture,
|
|
77
|
+
applyCapturedChanges
|
|
78
|
+
} = connection;
|
|
79
|
+
if (loadExtension) guardedConnection.loadExtension = (path) => loadExtension.call(connection, path);
|
|
80
|
+
if (copyDatabase) guardedConnection.copyDatabase = (request) => guarded(() => copyDatabase.call(connection, request));
|
|
81
|
+
if (runBatch) guardedConnection.runBatch = (sql, batch) => guarded(() => runBatch.call(connection, sql, batch));
|
|
82
|
+
if (runBatchSummary) {
|
|
83
|
+
guardedConnection.runBatchSummary = (sql, batch) => guarded(() => runBatchSummary.call(connection, sql, batch));
|
|
84
|
+
}
|
|
85
|
+
if (runGroup) {
|
|
86
|
+
guardedConnection.runGroup = async (units, opening) => guardedOutcomes(await guarded(() => runGroup.call(connection, units, opening)));
|
|
87
|
+
}
|
|
88
|
+
if (startChangeCapture) guardedConnection.startChangeCapture = () => startChangeCapture.call(connection);
|
|
89
|
+
if (takeCapturedChanges) {
|
|
90
|
+
guardedConnection.takeCapturedChanges = () => guarded(() => takeCapturedChanges.call(connection));
|
|
91
|
+
}
|
|
92
|
+
if (stopChangeCapture) guardedConnection.stopChangeCapture = () => stopChangeCapture.call(connection);
|
|
93
|
+
if (applyCapturedChanges) {
|
|
94
|
+
guardedConnection.applyCapturedChanges = (changes) => guarded(() => applyCapturedChanges.call(connection, changes));
|
|
95
|
+
}
|
|
96
|
+
return guardedConnection;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export { reportEncryptedPageFailures };
|
|
@@ -5,7 +5,13 @@ var stateByTransport = /* @__PURE__ */ new WeakMap();
|
|
|
5
5
|
function stateFor(transport) {
|
|
6
6
|
const existing = stateByTransport.get(transport);
|
|
7
7
|
if (existing) return existing;
|
|
8
|
-
const created = {
|
|
8
|
+
const created = {
|
|
9
|
+
timers: /* @__PURE__ */ new Map(),
|
|
10
|
+
delays: /* @__PURE__ */ new Map(),
|
|
11
|
+
refusalDelays: /* @__PURE__ */ new Map(),
|
|
12
|
+
dialled: /* @__PURE__ */ new Map(),
|
|
13
|
+
wanted: null
|
|
14
|
+
};
|
|
9
15
|
stateByTransport.set(transport, created);
|
|
10
16
|
return created;
|
|
11
17
|
}
|
|
@@ -21,6 +27,7 @@ function replaceWantedEndpoints(transport, endpoints) {
|
|
|
21
27
|
clearTimeout(timer);
|
|
22
28
|
state.timers.delete(endpoint);
|
|
23
29
|
state.delays.delete(endpoint);
|
|
30
|
+
state.refusalDelays.delete(endpoint);
|
|
24
31
|
}
|
|
25
32
|
const aborts = [];
|
|
26
33
|
for (const [endpoint, abort] of state.dialled) {
|
|
@@ -48,12 +55,24 @@ function releaseEndpoint(transport, endpoint) {
|
|
|
48
55
|
function noteEndpointReachable(transport, endpoint) {
|
|
49
56
|
stateFor(transport).delays.delete(endpoint);
|
|
50
57
|
}
|
|
58
|
+
function noteEndpointRefused(transport, endpoint) {
|
|
59
|
+
const state = stateFor(transport);
|
|
60
|
+
const previous = state.refusalDelays.get(endpoint);
|
|
61
|
+
state.refusalDelays.set(
|
|
62
|
+
endpoint,
|
|
63
|
+
previous === void 0 ? RECONNECT_MIN_DELAY_MS * 2 : Math.min(previous * 2, RECONNECT_MAX_DELAY_MS)
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
function noteEndpointServing(transport, endpoint) {
|
|
67
|
+
stateFor(transport).refusalDelays.delete(endpoint);
|
|
68
|
+
}
|
|
51
69
|
function scheduleEndpointRedial(transport, endpoint, redial) {
|
|
52
70
|
if (!transport.connected) return;
|
|
53
71
|
const state = stateFor(transport);
|
|
54
72
|
if (state.timers.has(endpoint) || !isWanted(state, endpoint)) return;
|
|
55
|
-
const
|
|
56
|
-
state.delays.set(endpoint, Math.min(
|
|
73
|
+
const backoffMs = state.delays.get(endpoint) ?? RECONNECT_MIN_DELAY_MS;
|
|
74
|
+
state.delays.set(endpoint, Math.min(backoffMs * 2, RECONNECT_MAX_DELAY_MS));
|
|
75
|
+
const delayMs = Math.max(backoffMs, state.refusalDelays.get(endpoint) ?? 0);
|
|
57
76
|
const timer = setTimeout(() => {
|
|
58
77
|
state.timers.delete(endpoint);
|
|
59
78
|
if (!transport.connected || !isWanted(state, endpoint)) return;
|
|
@@ -69,6 +88,7 @@ function stopEndpointDialling(transport) {
|
|
|
69
88
|
}
|
|
70
89
|
state.timers.clear();
|
|
71
90
|
state.delays.clear();
|
|
91
|
+
state.refusalDelays.clear();
|
|
72
92
|
state.wanted = null;
|
|
73
93
|
const aborts = [...state.dialled.values()];
|
|
74
94
|
state.dialled.clear();
|
|
@@ -77,4 +97,4 @@ function stopEndpointDialling(transport) {
|
|
|
77
97
|
}
|
|
78
98
|
}
|
|
79
99
|
|
|
80
|
-
export { claimEndpoint, noteEndpointReachable, registerEndpointAbort, releaseEndpoint, replaceWantedEndpoints, scheduleEndpointRedial, stopEndpointDialling };
|
|
100
|
+
export { claimEndpoint, noteEndpointReachable, noteEndpointRefused, noteEndpointServing, registerEndpointAbort, releaseEndpoint, replaceWantedEndpoints, scheduleEndpointRedial, stopEndpointDialling };
|