@korajs/store 1.0.0-beta.13 → 1.0.0-beta.14
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/adapters/better-sqlite3.cjs.map +1 -1
- package/dist/adapters/better-sqlite3.js +1 -1
- package/dist/adapters/indexeddb.cjs.map +1 -1
- package/dist/adapters/indexeddb.js +4 -4
- package/dist/adapters/sqlite-wasm-worker.cjs +67 -15
- package/dist/adapters/sqlite-wasm-worker.cjs.map +1 -1
- package/dist/adapters/sqlite-wasm-worker.js +65 -17
- package/dist/adapters/sqlite-wasm-worker.js.map +1 -1
- package/dist/adapters/sqlite-wasm.cjs.map +1 -1
- package/dist/adapters/sqlite-wasm.js +5 -5
- package/dist/{backup-4NUPDEMB.js → backup-IHKVMUAM.js} +5 -5
- package/dist/{chunk-Y5LRH7KI.js → chunk-5AQSGMJV.js} +151 -21
- package/dist/chunk-5AQSGMJV.js.map +1 -0
- package/dist/{chunk-W5F2LWG6.js → chunk-5JMGMPUE.js} +2 -2
- package/dist/{chunk-HZTDBLDB.js → chunk-BILSA6XZ.js} +4 -3
- package/dist/{chunk-HZTDBLDB.js.map → chunk-BILSA6XZ.js.map} +1 -1
- package/dist/{chunk-QDUSJMFV.js → chunk-BQSIL6TT.js} +5 -5
- package/dist/{chunk-MCQKEHOD.js → chunk-KK3GBONL.js} +2 -2
- package/dist/{chunk-32EDKWMI.js → chunk-KTVNANUH.js} +2 -2
- package/dist/{chunk-SJP2HTYZ.js → chunk-QW4UU7NG.js} +2 -2
- package/dist/{chunk-DUKTWVZW.js → chunk-SRHDJF5B.js} +13 -2
- package/dist/{chunk-DUKTWVZW.js.map → chunk-SRHDJF5B.js.map} +1 -1
- package/dist/{chunk-P4V375FY.js → chunk-UC2LGFPV.js} +4 -4
- package/dist/index.cjs +203 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +96 -6
- package/dist/index.d.ts +96 -6
- package/dist/index.js +55 -39
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +1 -0
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +2 -2
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +3 -3
- package/dist/{restore-FR7XIKT2.js → restore-MNDPR557.js} +4 -4
- package/dist/{sql-builder-C4u55jKW.d.cts → sql-builder-D0tC3sv9.d.cts} +8 -1
- package/dist/{sql-builder-CGckdBDL.d.ts → sql-builder-D5UMzHEo.d.ts} +8 -1
- package/dist/sqlite-wasm-channel-QCCNBYCU.js +12 -0
- package/dist/store-HNGX4KTT.js +16 -0
- package/package.json +2 -2
- package/dist/chunk-Y5LRH7KI.js.map +0 -1
- package/dist/sqlite-wasm-channel-MLHLKEED.js +0 -12
- package/dist/store-IMWKZLWB.js +0 -16
- /package/dist/{backup-4NUPDEMB.js.map → backup-IHKVMUAM.js.map} +0 -0
- /package/dist/{chunk-W5F2LWG6.js.map → chunk-5JMGMPUE.js.map} +0 -0
- /package/dist/{chunk-QDUSJMFV.js.map → chunk-BQSIL6TT.js.map} +0 -0
- /package/dist/{chunk-MCQKEHOD.js.map → chunk-KK3GBONL.js.map} +0 -0
- /package/dist/{chunk-32EDKWMI.js.map → chunk-KTVNANUH.js.map} +0 -0
- /package/dist/{chunk-SJP2HTYZ.js.map → chunk-QW4UU7NG.js.map} +0 -0
- /package/dist/{chunk-P4V375FY.js.map → chunk-UC2LGFPV.js.map} +0 -0
- /package/dist/{restore-FR7XIKT2.js.map → restore-MNDPR557.js.map} +0 -0
- /package/dist/{sqlite-wasm-channel-MLHLKEED.js.map → sqlite-wasm-channel-QCCNBYCU.js.map} +0 -0
- /package/dist/{store-IMWKZLWB.js.map → store-HNGX4KTT.js.map} +0 -0
|
@@ -6,22 +6,22 @@ import {
|
|
|
6
6
|
loadDumpFromIndexedDB,
|
|
7
7
|
readManifestRecord,
|
|
8
8
|
restoreDumpStatements
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-BQSIL6TT.js";
|
|
10
10
|
import {
|
|
11
11
|
WebWorkerBridge
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-KK3GBONL.js";
|
|
13
13
|
import {
|
|
14
14
|
Mutex
|
|
15
15
|
} from "../chunk-TVJEC5S2.js";
|
|
16
16
|
import {
|
|
17
17
|
leaderLockName,
|
|
18
18
|
opfsPoolNameFor
|
|
19
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-5JMGMPUE.js";
|
|
20
20
|
import {
|
|
21
21
|
AdapterError,
|
|
22
22
|
StorageInUseError,
|
|
23
23
|
UnsyncedDataError
|
|
24
|
-
} from "../chunk-
|
|
24
|
+
} from "../chunk-SRHDJF5B.js";
|
|
25
25
|
|
|
26
26
|
// src/adapters/local-databases.ts
|
|
27
27
|
async function listLocalDatabases() {
|
|
@@ -52,7 +52,7 @@ async function deleteLocalDatabase(dbName, options) {
|
|
|
52
52
|
const record = await readManifestRecord(dbName);
|
|
53
53
|
const backend = record?.backend ?? "opfs";
|
|
54
54
|
return withExclusiveDatabase(dbName, async () => {
|
|
55
|
-
const { WebWorkerBridge: WebWorkerBridge2 } = await import("../sqlite-wasm-channel-
|
|
55
|
+
const { WebWorkerBridge: WebWorkerBridge2 } = await import("../sqlite-wasm-channel-QCCNBYCU.js");
|
|
56
56
|
const worker = new WebWorkerBridge2(options.workerUrl, options.workerResponseTimeoutMs ?? 3e4);
|
|
57
57
|
const send = async (request) => worker.send(request);
|
|
58
58
|
const reader = {
|
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
readBackupManifest,
|
|
8
8
|
restoreBackup,
|
|
9
9
|
verifyBackupChecksum
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-UC2LGFPV.js";
|
|
11
|
+
import "./chunk-KTVNANUH.js";
|
|
12
|
+
import "./chunk-QW4UU7NG.js";
|
|
13
13
|
import "./chunk-J5AGXF3D.js";
|
|
14
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-SRHDJF5B.js";
|
|
15
15
|
export {
|
|
16
16
|
BACKUP_VERSION,
|
|
17
17
|
BackupFormatError,
|
|
@@ -22,4 +22,4 @@ export {
|
|
|
22
22
|
restoreBackup,
|
|
23
23
|
verifyBackupChecksum
|
|
24
24
|
};
|
|
25
|
-
//# sourceMappingURL=backup-
|
|
25
|
+
//# sourceMappingURL=backup-IHKVMUAM.js.map
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
writeDeleteInTx,
|
|
17
17
|
writeInsertInTx,
|
|
18
18
|
writeUpdateInTx
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-BILSA6XZ.js";
|
|
20
20
|
import {
|
|
21
21
|
STORED_SCHEMA_VERSION_SQL,
|
|
22
22
|
parseSchemaAhead,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
LOG_QUARANTINE_TABLE,
|
|
28
28
|
readBackupManifest,
|
|
29
29
|
scanLogIntegrity
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-UC2LGFPV.js";
|
|
31
31
|
import {
|
|
32
32
|
COMPACTED_THROUGH_TABLE,
|
|
33
33
|
FOLD_MATERIALIZATION_CURRENT,
|
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
renumberOperationRow,
|
|
48
48
|
repairSequenceUniqueness,
|
|
49
49
|
rewriteDependentsInTx
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-KTVNANUH.js";
|
|
51
51
|
import {
|
|
52
52
|
DELIVERY_WATERMARK_META_KEY,
|
|
53
53
|
DELTA_CURSOR_META_KEY,
|
|
@@ -99,7 +99,7 @@ import {
|
|
|
99
99
|
seedTerminalRejectionsOnce,
|
|
100
100
|
serializeRowVersion,
|
|
101
101
|
setLocalNodePrincipal
|
|
102
|
-
} from "./chunk-
|
|
102
|
+
} from "./chunk-QW4UU7NG.js";
|
|
103
103
|
import {
|
|
104
104
|
decodeRichtextFieldsFromOpData,
|
|
105
105
|
deserializeOperationWithCollection,
|
|
@@ -110,12 +110,13 @@ import {
|
|
|
110
110
|
toRichtextReadShape
|
|
111
111
|
} from "./chunk-J5AGXF3D.js";
|
|
112
112
|
import {
|
|
113
|
+
NodeOwnedByAnotherUserError,
|
|
113
114
|
OptimisticLockError,
|
|
114
115
|
QueryError,
|
|
115
116
|
RecordNotFoundError,
|
|
116
117
|
SchemaVersionAheadError,
|
|
117
118
|
StoreNotOpenError
|
|
118
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-SRHDJF5B.js";
|
|
119
120
|
|
|
120
121
|
// src/store/store.ts
|
|
121
122
|
import {
|
|
@@ -140,7 +141,7 @@ import {
|
|
|
140
141
|
// src/collection/collection.ts
|
|
141
142
|
import { quoteIdent } from "@korajs/core";
|
|
142
143
|
var Collection = class {
|
|
143
|
-
constructor(name, definition, schema, adapter, clock, nodeId, onMutation, relationEnforcer, mutationHandler, causalTracker, secretKeyProvider, onStorageError, fold, maxOperationBytes) {
|
|
144
|
+
constructor(name, definition, schema, adapter, clock, nodeId, onMutation, relationEnforcer, mutationHandler, causalTracker, secretKeyProvider, onStorageError, fold, maxOperationBytes, assertLocalWriteAllowed) {
|
|
144
145
|
this.name = name;
|
|
145
146
|
this.definition = definition;
|
|
146
147
|
this.schema = schema;
|
|
@@ -155,6 +156,7 @@ var Collection = class {
|
|
|
155
156
|
this.onStorageError = onStorageError;
|
|
156
157
|
this.fold = fold;
|
|
157
158
|
this.maxOperationBytes = maxOperationBytes;
|
|
159
|
+
this.assertLocalWriteAllowed = assertLocalWriteAllowed;
|
|
158
160
|
}
|
|
159
161
|
name;
|
|
160
162
|
definition;
|
|
@@ -170,6 +172,7 @@ var Collection = class {
|
|
|
170
172
|
onStorageError;
|
|
171
173
|
fold;
|
|
172
174
|
maxOperationBytes;
|
|
175
|
+
assertLocalWriteAllowed;
|
|
173
176
|
/**
|
|
174
177
|
* Point this collection at the store's new device identity after a node-id
|
|
175
178
|
* rotation (RT-21). Internal: called by the owning Store only.
|
|
@@ -197,7 +200,8 @@ var Collection = class {
|
|
|
197
200
|
causalTracker: this.causalTracker,
|
|
198
201
|
...this.secretKeyProvider ? { secretKeyProvider: this.secretKeyProvider } : {},
|
|
199
202
|
...this.onStorageError ? { onStorageError: this.onStorageError } : {},
|
|
200
|
-
...this.maxOperationBytes !== void 0 ? { maxOperationBytes: this.maxOperationBytes } : {}
|
|
203
|
+
...this.maxOperationBytes !== void 0 ? { maxOperationBytes: this.maxOperationBytes } : {},
|
|
204
|
+
...this.assertLocalWriteAllowed ? { assertLocalWriteAllowed: this.assertLocalWriteAllowed } : {}
|
|
201
205
|
};
|
|
202
206
|
}
|
|
203
207
|
async insert(data) {
|
|
@@ -2250,7 +2254,8 @@ async function rebaseUnsyncedOperationsInLog(adapter, schema, unsyncedOpIds, cor
|
|
|
2250
2254
|
|
|
2251
2255
|
// src/sync/rotate-node-id.ts
|
|
2252
2256
|
import { quoteIdent as quoteIdent11 } from "@korajs/core";
|
|
2253
|
-
async function rotateUnsyncedOperationsInLog(adapter, schema, unsyncedOpIds, oldNodeId, newNodeId) {
|
|
2257
|
+
async function rotateUnsyncedOperationsInLog(adapter, schema, unsyncedOpIds, oldNodeId, newNodeId, options = {}) {
|
|
2258
|
+
const moveDatabaseNode = options.moveDatabaseNode !== false;
|
|
2254
2259
|
const rotateIds = new Set(unsyncedOpIds);
|
|
2255
2260
|
const idMapping = {};
|
|
2256
2261
|
const rewritten = [];
|
|
@@ -2320,10 +2325,12 @@ async function rotateUnsyncedOperationsInLog(adapter, schema, unsyncedOpIds, old
|
|
|
2320
2325
|
);
|
|
2321
2326
|
}
|
|
2322
2327
|
}
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2328
|
+
if (moveDatabaseNode) {
|
|
2329
|
+
await tx.execute("INSERT OR REPLACE INTO _kora_meta (key, value) VALUES ('node_id', ?)", [
|
|
2330
|
+
newNodeId
|
|
2331
|
+
]);
|
|
2332
|
+
await tx.execute("DELETE FROM _kora_meta WHERE key = ?", [NODE_TOKEN_META_KEY]);
|
|
2333
|
+
}
|
|
2327
2334
|
if (rewritten.length > 0) {
|
|
2328
2335
|
await tx.execute(
|
|
2329
2336
|
`INSERT INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)
|
|
@@ -2469,7 +2476,9 @@ var TransactionContext = class {
|
|
|
2469
2476
|
...this.config.secretKeyProvider ? { secretKeyProvider: this.config.secretKeyProvider } : {},
|
|
2470
2477
|
...this.mutationName !== void 0 ? { mutationName: this.mutationName } : {},
|
|
2471
2478
|
...this.config.beforeLocalDelete ? { beforeLocalDelete: this.config.beforeLocalDelete } : {},
|
|
2472
|
-
...this.config.fold ? { fold: this.config.fold } : {}
|
|
2479
|
+
...this.config.fold ? { fold: this.config.fold } : {},
|
|
2480
|
+
...this.config.maxOperationBytes !== void 0 ? { maxOperationBytes: this.config.maxOperationBytes } : {},
|
|
2481
|
+
...this.config.assertLocalWriteAllowed ? { assertLocalWriteAllowed: this.config.assertLocalWriteAllowed } : {}
|
|
2473
2482
|
};
|
|
2474
2483
|
}
|
|
2475
2484
|
ensureActive() {
|
|
@@ -2831,6 +2840,12 @@ var Store = class {
|
|
|
2831
2840
|
schema;
|
|
2832
2841
|
adapter;
|
|
2833
2842
|
configNodeId;
|
|
2843
|
+
/** The owner of the pinned node while it belongs to another user than the signed-in one (F9). */
|
|
2844
|
+
pinnedNodeOwnedBy = null;
|
|
2845
|
+
/** The sync server refused the pinned node as another user's (F9). */
|
|
2846
|
+
pinnedNodeRefusedByServer = false;
|
|
2847
|
+
/** The user of the last {@link bindPrincipal}. */
|
|
2848
|
+
signedInPrincipal = null;
|
|
2834
2849
|
dbName;
|
|
2835
2850
|
isolation;
|
|
2836
2851
|
emitter;
|
|
@@ -2905,8 +2920,10 @@ var Store = class {
|
|
|
2905
2920
|
this.foldActive = false;
|
|
2906
2921
|
await relaxValueDomainConstraints(this.adapter, this.schema);
|
|
2907
2922
|
await dropLegacyIndexes(this.adapter, this.schema);
|
|
2923
|
+
const persistedNodeId = await this.readPersistedNodeId();
|
|
2908
2924
|
this.nodeId = await this.loadOrGenerateNodeId();
|
|
2909
2925
|
await registerLocalNode(this.adapter, this.nodeId);
|
|
2926
|
+
await this.registerUnregisteredAuthors(persistedNodeId);
|
|
2910
2927
|
await this.scanLog("quick");
|
|
2911
2928
|
await repairSequenceUniqueness(this.adapter, this.schema, this.nodeId);
|
|
2912
2929
|
await seedTerminalRejectionsOnce(this.adapter);
|
|
@@ -2950,7 +2967,8 @@ var Store = class {
|
|
|
2950
2967
|
this.secretKeyProvider,
|
|
2951
2968
|
(error) => this.reportStorageError(error),
|
|
2952
2969
|
() => this.activeFold(),
|
|
2953
|
-
this.maxOperationBytes
|
|
2970
|
+
this.maxOperationBytes,
|
|
2971
|
+
() => this.assertLocalWriteAllowed()
|
|
2954
2972
|
);
|
|
2955
2973
|
this.collections.set(name, col);
|
|
2956
2974
|
}
|
|
@@ -4242,6 +4260,7 @@ var Store = class {
|
|
|
4242
4260
|
...options?.extraCausalDeps ? { extraCausalDeps: options.extraCausalDeps } : {},
|
|
4243
4261
|
...this.secretKeyProvider ? { secretKeyProvider: this.secretKeyProvider } : {},
|
|
4244
4262
|
...this.maxOperationBytes !== void 0 ? { maxOperationBytes: this.maxOperationBytes } : {},
|
|
4263
|
+
assertLocalWriteAllowed: () => this.assertLocalWriteAllowed(),
|
|
4245
4264
|
...beforeLocalDelete ? { beforeLocalDelete: beforeLocalDelete.bind(this.localMutationHandler) } : {},
|
|
4246
4265
|
onStorageError: (error) => this.reportStorageError(error)
|
|
4247
4266
|
};
|
|
@@ -4511,6 +4530,46 @@ var Store = class {
|
|
|
4511
4530
|
await this.refoldRecordsOf(result.operations.map((op) => op.id));
|
|
4512
4531
|
return result;
|
|
4513
4532
|
}
|
|
4533
|
+
/**
|
|
4534
|
+
* Re-author another local node's never-acknowledged operations under a fresh node id
|
|
4535
|
+
* bound to `principal` (the user they belong to). Used when the sync server refuses an
|
|
4536
|
+
* adopted node whose writes belong to the signed-in user (the app assigned them, or
|
|
4537
|
+
* the node was created for them) but which no claims-aware server ever accepted: a
|
|
4538
|
+
* beta.12 database's node with history the server recorded no owner for. The store's
|
|
4539
|
+
* own node id, clock and counters are untouched; the fresh node is registered, so the
|
|
4540
|
+
* sync engine adopts it like any other local node.
|
|
4541
|
+
*
|
|
4542
|
+
* @param fromNodeId - The refused local node (never the store's own)
|
|
4543
|
+
* @param unsyncedOpIds - Ids of its operations the server never acknowledged
|
|
4544
|
+
* @param principal - The user the writes belong to (the fresh node's binding)
|
|
4545
|
+
* @returns The fresh node id and the rewritten operations (for the outbound queue)
|
|
4546
|
+
* @throws {KoraError} `NODE_ID_UNKNOWN` when `fromNodeId` is the store's own node or
|
|
4547
|
+
* not a local node
|
|
4548
|
+
*/
|
|
4549
|
+
async reauthorLocalNode(fromNodeId, unsyncedOpIds, principal) {
|
|
4550
|
+
this.ensureOpen();
|
|
4551
|
+
const from = (await listLocalNodes(this.adapter)).find((node) => node.nodeId === fromNodeId);
|
|
4552
|
+
if (fromNodeId === this.nodeId || !from) {
|
|
4553
|
+
throw new KoraError4(
|
|
4554
|
+
`Node id "${fromNodeId}" is not another local node of this database, so its writes cannot be re-authored.`,
|
|
4555
|
+
"NODE_ID_UNKNOWN",
|
|
4556
|
+
{ nodeId: fromNodeId, storeNodeId: this.nodeId }
|
|
4557
|
+
);
|
|
4558
|
+
}
|
|
4559
|
+
const result = await rotateUnsyncedOperationsInLog(
|
|
4560
|
+
this.adapter,
|
|
4561
|
+
this.schema,
|
|
4562
|
+
unsyncedOpIds,
|
|
4563
|
+
fromNodeId,
|
|
4564
|
+
generateUUIDv73(),
|
|
4565
|
+
{ moveDatabaseNode: false }
|
|
4566
|
+
);
|
|
4567
|
+
await registerLocalNode(this.adapter, result.nodeId);
|
|
4568
|
+
await setLocalNodePrincipal(this.adapter, result.nodeId, principal, "fresh");
|
|
4569
|
+
this.versionVector = await this.loadVersionVector();
|
|
4570
|
+
await this.refoldRecordsOf(result.operations.map((op) => op.id));
|
|
4571
|
+
return result;
|
|
4572
|
+
}
|
|
4514
4573
|
/**
|
|
4515
4574
|
* Move this database back to a node id it authored under before (RT-38): after the
|
|
4516
4575
|
* sync server refused the current node, the device tries a node a returning user
|
|
@@ -4590,6 +4649,31 @@ var Store = class {
|
|
|
4590
4649
|
* @returns The node now in use and whether it changed
|
|
4591
4650
|
*/
|
|
4592
4651
|
async bindPrincipal(principal) {
|
|
4652
|
+
const binding = await this.bindPrincipalToNode(principal);
|
|
4653
|
+
if (principal !== this.signedInPrincipal) this.pinnedNodeRefusedByServer = false;
|
|
4654
|
+
this.pinnedNodeOwnedBy = binding.conflict ? (await listLocalNodes(this.adapter)).find((node) => node.nodeId === this.nodeId)?.principal ?? null : null;
|
|
4655
|
+
this.signedInPrincipal = principal;
|
|
4656
|
+
return binding;
|
|
4657
|
+
}
|
|
4658
|
+
/**
|
|
4659
|
+
* The sync server refused this store's pinned node id because another user owns it
|
|
4660
|
+
* (`owned: true`), or later accepted it (`false`). A pinned node cannot move to a fresh
|
|
4661
|
+
* id, so writes made under it could only ever upload as its owner: while the server
|
|
4662
|
+
* says so, local writes are refused (F9). A no-op for a store whose node is not pinned
|
|
4663
|
+
* (it moves to a fresh node instead).
|
|
4664
|
+
*
|
|
4665
|
+
* @param owned - Whether the server reported the node owned by another user
|
|
4666
|
+
*/
|
|
4667
|
+
setPinnedNodeOwnedElsewhere(owned) {
|
|
4668
|
+
if (!this.configNodeId) return;
|
|
4669
|
+
this.pinnedNodeRefusedByServer = owned;
|
|
4670
|
+
}
|
|
4671
|
+
/** Refuse a local write while the pinned node belongs to another user (F9). */
|
|
4672
|
+
assertLocalWriteAllowed() {
|
|
4673
|
+
if (this.pinnedNodeOwnedBy === null && !this.pinnedNodeRefusedByServer) return;
|
|
4674
|
+
throw new NodeOwnedByAnotherUserError(this.nodeId, this.signedInPrincipal);
|
|
4675
|
+
}
|
|
4676
|
+
async bindPrincipalToNode(principal) {
|
|
4593
4677
|
this.ensureOpen();
|
|
4594
4678
|
const previousNodeId = this.nodeId;
|
|
4595
4679
|
const nodes = await listLocalNodes(this.adapter);
|
|
@@ -4969,6 +5053,8 @@ var Store = class {
|
|
|
4969
5053
|
const beforeLocalDelete = this.localMutationHandler?.beforeLocalDelete;
|
|
4970
5054
|
const fold = this.activeFold();
|
|
4971
5055
|
return new TransactionContext({
|
|
5056
|
+
...this.maxOperationBytes !== void 0 ? { maxOperationBytes: this.maxOperationBytes } : {},
|
|
5057
|
+
assertLocalWriteAllowed: () => this.assertLocalWriteAllowed(),
|
|
4972
5058
|
...fold ? { fold } : {},
|
|
4973
5059
|
schema: this.schema,
|
|
4974
5060
|
adapter: this.adapter,
|
|
@@ -5014,7 +5100,7 @@ var Store = class {
|
|
|
5014
5100
|
*/
|
|
5015
5101
|
async exportBackup(options) {
|
|
5016
5102
|
this.ensureOpen();
|
|
5017
|
-
const { exportBackup: doExport } = await import("./backup-
|
|
5103
|
+
const { exportBackup: doExport } = await import("./backup-IHKVMUAM.js");
|
|
5018
5104
|
return doExport(this.adapter, this.schema, this.nodeId, this.schema.version, options);
|
|
5019
5105
|
}
|
|
5020
5106
|
/**
|
|
@@ -5028,8 +5114,9 @@ var Store = class {
|
|
|
5028
5114
|
* move backwards, and unsynced own writes are kept (see
|
|
5029
5115
|
* `RestoreOptions.keepUnsyncedWrites`). Then {@link reloadFromDisk} runs.
|
|
5030
5116
|
*
|
|
5031
|
-
* A version-1 file
|
|
5032
|
-
* `convertBackupV1
|
|
5117
|
+
* A version-1 file (Kora 1.0.0-beta.12 and earlier) is converted first, exactly as
|
|
5118
|
+
* `convertBackupV1` does (`result.convertedFromVersion: 1`); one holding an operation
|
|
5119
|
+
* whose timestamp cannot be recovered is refused (`BACKUP_OPERATION_INVALID`).
|
|
5033
5120
|
*
|
|
5034
5121
|
* @param data - The backup data
|
|
5035
5122
|
* @param options - Restore options (merge, collections, keepUnsyncedWrites, onProgress)
|
|
@@ -5042,13 +5129,19 @@ var Store = class {
|
|
|
5042
5129
|
const started = Date.now();
|
|
5043
5130
|
const onProgress = options?.onProgress ?? (() => {
|
|
5044
5131
|
});
|
|
5045
|
-
const { BackupFormatError, parseBackup } = await import("./backup-
|
|
5046
|
-
const { restoreMerge, restoreReplace } = await import("./restore-
|
|
5132
|
+
const { BackupFormatError, convertBackupV1, parseBackup, readBackupManifest: readBackupManifest2 } = await import("./backup-IHKVMUAM.js");
|
|
5133
|
+
const { restoreMerge, restoreReplace } = await import("./restore-MNDPR557.js");
|
|
5047
5134
|
onProgress({ phase: "verifying", progress: 0, message: "Verifying backup" });
|
|
5048
5135
|
let parsed;
|
|
5136
|
+
let convertedFromVersion;
|
|
5049
5137
|
try {
|
|
5138
|
+
let bytes = data;
|
|
5139
|
+
if (readBackupManifest2(data).version === 1) {
|
|
5140
|
+
bytes = await convertBackupV1(data);
|
|
5141
|
+
convertedFromVersion = 1;
|
|
5142
|
+
}
|
|
5050
5143
|
parsed = await parseBackup(
|
|
5051
|
-
|
|
5144
|
+
bytes,
|
|
5052
5145
|
options?.collections ? { collections: options.collections } : void 0
|
|
5053
5146
|
);
|
|
5054
5147
|
} catch (error) {
|
|
@@ -5100,6 +5193,7 @@ var Store = class {
|
|
|
5100
5193
|
recordsRestored: counts.recordsRestored,
|
|
5101
5194
|
...options?.merge ? {} : { unsyncedWritesKept: counts.unsyncedWritesKept },
|
|
5102
5195
|
...counts.serverOperationsSkipped ? { serverOperationsSkipped: counts.serverOperationsSkipped } : {},
|
|
5196
|
+
...convertedFromVersion ? { convertedFromVersion } : {},
|
|
5103
5197
|
success: true,
|
|
5104
5198
|
duration: Date.now() - started
|
|
5105
5199
|
};
|
|
@@ -5262,6 +5356,42 @@ var Store = class {
|
|
|
5262
5356
|
onOperation: (operation) => this.publishLocalOperation(operation.collection, operation)
|
|
5263
5357
|
});
|
|
5264
5358
|
}
|
|
5359
|
+
/** The node id the database persisted before this open, if any. */
|
|
5360
|
+
async readPersistedNodeId() {
|
|
5361
|
+
const rows = await this.adapter.query(
|
|
5362
|
+
"SELECT value FROM _kora_meta WHERE key = 'node_id'"
|
|
5363
|
+
);
|
|
5364
|
+
return rows[0]?.value ?? null;
|
|
5365
|
+
}
|
|
5366
|
+
/**
|
|
5367
|
+
* Register node ids this database authored under that the registry does not know
|
|
5368
|
+
* yet: the node id a pinned `nodeId` (the auth device id) just replaced, and the
|
|
5369
|
+
* authors of queued operations. A beta.12 database had no registry, and a template
|
|
5370
|
+
* app created before its user signed in authored under a random node; once the
|
|
5371
|
+
* store is pinned to the device id, that node's queued writes would otherwise sit in
|
|
5372
|
+
* the queue forever, neither uploaded nor reported. Registered, they are adopted or
|
|
5373
|
+
* held (`status.heldNodes`) like any other local node's writes. Only the outbound
|
|
5374
|
+
* queue is read: received operations never enter it.
|
|
5375
|
+
*/
|
|
5376
|
+
async registerUnregisteredAuthors(persistedNodeId) {
|
|
5377
|
+
const authors = /* @__PURE__ */ new Set();
|
|
5378
|
+
if (persistedNodeId !== null && persistedNodeId !== this.nodeId) authors.add(persistedNodeId);
|
|
5379
|
+
const queued = await this.adapter.query(
|
|
5380
|
+
"SELECT payload FROM _kora_sync_queue"
|
|
5381
|
+
);
|
|
5382
|
+
for (const row of queued) {
|
|
5383
|
+
try {
|
|
5384
|
+
const nodeId = JSON.parse(row.payload).node_id;
|
|
5385
|
+
if (typeof nodeId === "string" && nodeId.length > 0) authors.add(nodeId);
|
|
5386
|
+
} catch {
|
|
5387
|
+
}
|
|
5388
|
+
}
|
|
5389
|
+
authors.delete(this.nodeId);
|
|
5390
|
+
for (const nodeId of authors) {
|
|
5391
|
+
if (isReservedNodeId(nodeId)) continue;
|
|
5392
|
+
await registerLocalNode(this.adapter, nodeId);
|
|
5393
|
+
}
|
|
5394
|
+
}
|
|
5265
5395
|
async loadOrGenerateNodeId() {
|
|
5266
5396
|
if (this.configNodeId && isReservedNodeId(this.configNodeId)) {
|
|
5267
5397
|
throw new ReservedNodeIdError(this.configNodeId, "StoreConfig.nodeId");
|
|
@@ -5338,4 +5468,4 @@ export {
|
|
|
5338
5468
|
ReservedNodeIdError,
|
|
5339
5469
|
Store
|
|
5340
5470
|
};
|
|
5341
|
-
//# sourceMappingURL=chunk-
|
|
5471
|
+
//# sourceMappingURL=chunk-5AQSGMJV.js.map
|