@sqlite-sync/core 0.11.0 → 0.12.1
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/README.md +17 -21
- package/dist/{crdt-sync-remote-source-CugbiosG.js → crdt-sync-remote-source-CPXzmSIS.js} +131 -96
- package/dist/crdt-sync-remote-source-CPXzmSIS.js.map +1 -0
- package/dist/{crdt-table-schema-2w_AIpsV.js → crdt-table-schema-BRm_WdcW.js} +19 -2
- package/dist/crdt-table-schema-BRm_WdcW.js.map +1 -0
- package/dist/heartbeat-CJWQAoGP.js +7 -0
- package/dist/heartbeat-CJWQAoGP.js.map +1 -0
- package/dist/{index-UfgvV97h.d.ts → index-BHsKLqcK.d.ts} +25 -15
- package/dist/index.d.ts +1 -1
- package/dist/index.js +213 -181
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +3 -3
- package/dist/{make-crdt-table-D8VQ-ptj.js → make-crdt-table-C6l0F-o_.js} +2 -2
- package/dist/{make-crdt-table-D8VQ-ptj.js.map → make-crdt-table-C6l0F-o_.js.map} +1 -1
- package/dist/{reset-state-CchMrdoA.js → reset-state-t0tTGqoh.js} +23 -342
- package/dist/reset-state-t0tTGqoh.js.map +1 -0
- package/dist/server.d.ts +6 -2
- package/dist/server.js +4 -3
- package/dist/server.js.map +1 -1
- package/dist/system-schema-Dvl_BLId.js +523 -0
- package/dist/system-schema-Dvl_BLId.js.map +1 -0
- package/dist/worker.d.ts +2 -1
- package/dist/worker.js +73 -90
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
- package/dist/crdt-sync-remote-source-CugbiosG.js.map +0 -1
- package/dist/crdt-table-schema-2w_AIpsV.js.map +0 -1
- package/dist/reset-state-CchMrdoA.js.map +0 -1
- package/dist/system-schema-C2JZDv6L.js +0 -178
- package/dist/system-schema-C2JZDv6L.js.map +0 -1
|
@@ -415,6 +415,10 @@ type TypedStatement<TParams extends Record<string, unknown>, TResult> = {
|
|
|
415
415
|
};
|
|
416
416
|
type KyselyStatementFactory<TParams extends Record<string, unknown>, TDatabase, TQuery extends Compilable<TResult>, TResult = QueryBuilderOutput<TQuery>> = (kysely: Kysely<TDatabase>, params: ParamsGetter<TParams>) => TQuery;
|
|
417
417
|
type KyselyQueryFactory<TDatabase, TQuery extends Compilable<TResult>, TResult = QueryBuilderOutput<TQuery>> = (kysely: Kysely<TDatabase>) => TQuery;
|
|
418
|
+
declare function compileKyselyStatement<TParams extends Record<string, unknown>, TDatabase>(factory: KyselyStatementFactory<TParams, TDatabase, Compilable<unknown>>): {
|
|
419
|
+
sql: string;
|
|
420
|
+
bindParameters: (parameters: TParams) => unknown[];
|
|
421
|
+
};
|
|
418
422
|
//#endregion
|
|
419
423
|
//#region src/sqlite-kv-store.d.ts
|
|
420
424
|
type KvStoreItem = {
|
|
@@ -949,7 +953,7 @@ type WorkerNotificationMessage = {
|
|
|
949
953
|
localSchemaVersion: number;
|
|
950
954
|
};
|
|
951
955
|
type WorkerState = {
|
|
952
|
-
remoteState: "online" | "offline" | "
|
|
956
|
+
remoteState: "online" | "offline" | "connecting";
|
|
953
957
|
deSynced: boolean;
|
|
954
958
|
schemaVersionMismatched: boolean;
|
|
955
959
|
};
|
|
@@ -1004,24 +1008,26 @@ type EventsAvailable = {
|
|
|
1004
1008
|
remoteEventHlcSum: string | null;
|
|
1005
1009
|
};
|
|
1006
1010
|
/**
|
|
1007
|
-
* Opens
|
|
1008
|
-
* `
|
|
1009
|
-
*
|
|
1010
|
-
*
|
|
1011
|
-
*
|
|
1011
|
+
* Opens one connection to the remote. Each call must return a new source: the library calls `disconnect` on every
|
|
1012
|
+
* returned source exactly once. Call `onClosed` when the connection ends on its own, at any time including during
|
|
1013
|
+
* this call; the library then reconnects with backoff. Requests may wait for the connection to open and should
|
|
1014
|
+
* reject once it closes. The library times requests out and shows the remote as online after the first one succeeds.
|
|
1015
|
+
* With `ping`, the library also checks idle connections and replaces one whose ping fails or times out. It calls `ping`
|
|
1016
|
+
* only on an online connection, one at a time, and never after the connection closes; a ping does not need to settle
|
|
1017
|
+
* once the source has closed.
|
|
1012
1018
|
*/
|
|
1013
1019
|
type CreateRemoteSourceFactory = (opts: {
|
|
1014
1020
|
onEventsAvailable: (event: EventsAvailable) => void;
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
}) => RemoteSource | Promise<RemoteSource>;
|
|
1021
|
+
onClosed: (error?: unknown) => void;
|
|
1022
|
+
}) => RemoteSource;
|
|
1018
1023
|
type RemoteSource = {
|
|
1019
1024
|
pullEvents: (request: EventsPullRequest) => Promise<EventsPullResponse>;
|
|
1020
1025
|
pushEvents: (request: EventsPushRequest) => Promise<EventsPushResponse>;
|
|
1026
|
+
ping?: () => Promise<void>;
|
|
1021
1027
|
disconnect?: () => void | Promise<void>;
|
|
1022
1028
|
};
|
|
1023
1029
|
type RemoteSourceState = {
|
|
1024
|
-
type: "
|
|
1030
|
+
type: "connecting";
|
|
1025
1031
|
deSynced: boolean;
|
|
1026
1032
|
schemaVersionMismatched: boolean;
|
|
1027
1033
|
} | {
|
|
@@ -1034,11 +1040,12 @@ type RemoteSourceState = {
|
|
|
1034
1040
|
deSynced: boolean;
|
|
1035
1041
|
schemaVersionMismatched: boolean;
|
|
1036
1042
|
};
|
|
1037
|
-
type OfflineReason = "NOT_INITIALIZED" | "INITIALIZATION_FAILED" | "REMOTE_PUSH_ERROR" | "REMOTE_PULL_ERROR" | "DISCONNECTED";
|
|
1043
|
+
type OfflineReason = "NOT_INITIALIZED" | "INITIALIZATION_FAILED" | "REMOTE_PUSH_ERROR" | "REMOTE_PULL_ERROR" | "CONNECTION_LOST" | "NETWORK_OFFLINE" | "DISCONNECTED";
|
|
1038
1044
|
type DeSyncDetectedReason = "CHECKSUM_MISMATCH" | "ERROR_APPLYING_REMOTE_EVENT";
|
|
1039
1045
|
declare const createCrdtSyncRemoteSource: ({ bufferSize, storage, migrator, pullSyncId, pushSyncId, nodeId, remoteFactory }: CrdtSyncRemoteSourceConfig) => {
|
|
1040
1046
|
goOnline: () => Promise<void>;
|
|
1041
1047
|
goOffline: (reason: OfflineReason) => Promise<void>;
|
|
1048
|
+
dropConnection: (reason: OfflineReason) => void;
|
|
1042
1049
|
syncWithRemote: () => Promise<void>;
|
|
1043
1050
|
getState: () => WorkerState;
|
|
1044
1051
|
dispose: () => Promise<void>;
|
|
@@ -1092,9 +1099,12 @@ declare function drainCrdtChangeIntents({ tx, storage }: {
|
|
|
1092
1099
|
type SyncedDbOptions<Database, Props = undefined> = {
|
|
1093
1100
|
dbId: string;
|
|
1094
1101
|
worker: Worker;
|
|
1095
|
-
workerProps: Props;
|
|
1096
1102
|
syncDbSchema: SyncDbSchema<Database>;
|
|
1097
|
-
}
|
|
1103
|
+
} & (undefined extends Props ? {
|
|
1104
|
+
workerProps?: Props;
|
|
1105
|
+
} : {
|
|
1106
|
+
workerProps: Props;
|
|
1107
|
+
});
|
|
1098
1108
|
/** SQL execution that participates in CRDT intent draining. */
|
|
1099
1109
|
type SyncedDbSqlExecutor<Database> = {
|
|
1100
1110
|
execute<TResult = unknown>(query: ExecuteParams | string | CompiledQuery<TResult>): ExecuteResult<TResult>;
|
|
@@ -1218,5 +1228,5 @@ type ResetStore = {
|
|
|
1218
1228
|
*/
|
|
1219
1229
|
declare const RESET_REQUEST_TTL_MS: number;
|
|
1220
1230
|
//#endregion
|
|
1221
|
-
export { createExportData as $,
|
|
1222
|
-
//# sourceMappingURL=index-
|
|
1231
|
+
export { createExportData as $, ReadonlyTable as $t, PendingCrdtEvent as A, CrdtUpdateLogPayload as An, ExecuteParams as At, DefinedSyncSchema as B, LogLevel as Bt, WorkerConfig as C, StoredValue as Cn, jsonSafeParse as Ct, CrdtStorageMutator as D, CrdtEventStatus as Dn, KvStoreItem as Dt, createCrdtSyncProducer as E, CrdtEventOrigin as En, tryCatchAsync as Et, verifySyncSchema as F, PreparedStatement as Ft, SQLiteReactiveDb as G, TableMetadata as Gt, AdmitClientEventsResult as H, startPerformanceLogger as Ht, CrdtEventValidationError as I, QueryBuilderOutput as It, parametersAreEqual as J, HLCCounter as Jt, SharedLiveQuery as K, introspectDb as Kt, NewCrdtEventValidationResult as L, SQLiteDbWrapper as Lt, createSQLiteCrdtApplyFunction as M, isNoOpCrdtEventPayload as Mn, InternalSQLiteWrapper as Mt, SchemaVerificationIssue as N, dummyKysely as Nn, KyselyQueryFactory as Nt, SnapshotOptions as O, CrdtEventType as On, createKvStoreTableQuery as Ot, formatSchemaVerificationIssues as P, KyselyStatementFactory as Pt, SyncedDbExport as Q, CrdtTableConfig as Qt, validateNewCrdtEvent as R, SQLiteTransactionWrapper as Rt, EventsPullResponse as S, createMigrator as Sn, generateId as St, WorkerState as T, CRDT_EVENT_NO_OP_PAYLOAD as Tn, tryCatch as Tt, ClientDatasetRejectionReason as U, ColumnMetadata as Ut, defineSyncSchema as V, Logger as Vt, admitClientEvents as W, DatabaseIntrospection as Wt, ImportDataOptions as X, deserializeHLC as Xt, xxhash as Y, compareHLC as Yt, ImportDataResult as Z, serializeHLC as Zt, CreateRemoteSourceFactory as _, MigratableEvent as _n, TypedBroadcastChannel as _t, SyncedDbDatabase as a, ColumnKind as an, OwnCrdtSnapshot as at, EventsPushResponse as b, SyncDbMigrator as bn, createDeferredPromise as bt, SyncedDbTransaction as c, InferRow as cn, SystemMigration as ct, CRDT_CHANGE_INTENTS_TABLE as d, SyncSchemaTables as dn, applyWorkerDbSchema as dt, SyncDbSchema as en, createImportData as et, crdtViewColumnsFromTable as f, TableBuilder as fn, baseSystemMigrations as ft, CrdtSyncRemoteSource as g, t as gn, DistributiveOmit as gt, makeCrdtTable as h, WriteOrigin as hn, DeferredPromise as ht, SyncedDb as i, ColumnBuilder as in, OwnCrdtEvent as it, createCrdtApplyFunction as j, PersistedCrdtEvent as jn, ExecuteResult as jt, createCrdtStorageMutator as k, CrdtUpdateLogItem as kn, createSQLiteKvStore as kt, UnsafeSyncedDbSqlExecutor as l, PayloadValidationResult as ln, SystemMigrationContext as lt, drainCrdtChangeIntents as m, TableOptions as mn, runSystemMigrations as mt, ResetRequest as n, AnyColumnBuilder as nn, CrdtStorage as nt, SyncedDbOptions as o, ColumnMeta as on, createCrdtStorage as ot, createCrdtViewStatements as p, TableColumns as pn, createSystemDbConfig as pt, SharedLiveQuerySnapshot as q, HLC as qt, ResetStore as r, AnyTableBuilder as rn, GetEventsBatch as rt, SyncedDbSqlExecutor as s, ExportImportMode as sn, SystemDbConfig as st, RESET_REQUEST_TTL_MS as t, AiAccess as tn, CrdtChangeIntent as tt, createSyncedDb as u, SqliteStorageType as un, applyMemoryDbSchema as ut, EventsPullRequest as v, Migrations as vn, TypedEvent as vt, WorkerNotificationMessage as w, createStoredValue as wn, quoteId as wt, createCrdtSyncRemoteSource as x, createMigrations as xn, createTypedEventTarget as xt, EventsPushRequest as y, MigrationsDb as yn, TypedEventTarget as yt, DefineSyncSchemaConfig as z, compileKyselyStatement as zt };
|
|
1232
|
+
//# sourceMappingURL=index-BHsKLqcK.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as createExportData, $t as
|
|
1
|
+
import { $ as createExportData, $t as ReadonlyTable, A as PendingCrdtEvent, An as CrdtUpdateLogPayload, At as ExecuteParams, B as DefinedSyncSchema, Bt as LogLevel, C as WorkerConfig, Cn as StoredValue, Ct as jsonSafeParse, D as CrdtStorageMutator, Dn as CrdtEventStatus, Dt as KvStoreItem, E as createCrdtSyncProducer, En as CrdtEventOrigin, Et as tryCatchAsync, F as verifySyncSchema, Ft as PreparedStatement, G as SQLiteReactiveDb, Gt as TableMetadata, H as AdmitClientEventsResult, Ht as startPerformanceLogger, I as CrdtEventValidationError, It as QueryBuilderOutput, J as parametersAreEqual, Jt as HLCCounter, K as SharedLiveQuery, Kt as introspectDb, L as NewCrdtEventValidationResult, Lt as SQLiteDbWrapper, M as createSQLiteCrdtApplyFunction, Mn as isNoOpCrdtEventPayload, N as SchemaVerificationIssue, Nn as dummyKysely, Nt as KyselyQueryFactory, O as SnapshotOptions, On as CrdtEventType, Ot as createKvStoreTableQuery, P as formatSchemaVerificationIssues, Q as SyncedDbExport, Qt as CrdtTableConfig, R as validateNewCrdtEvent, Rt as SQLiteTransactionWrapper, Sn as createMigrator, St as generateId, T as WorkerState, Tn as CRDT_EVENT_NO_OP_PAYLOAD, Tt as tryCatch, Ut as ColumnMetadata, V as defineSyncSchema, Vt as Logger, W as admitClientEvents, Wt as DatabaseIntrospection, X as ImportDataOptions, Xt as deserializeHLC, Y as xxhash, Yt as compareHLC, Z as ImportDataResult, Zt as serializeHLC, _n as MigratableEvent, _t as TypedBroadcastChannel, a as SyncedDbDatabase, an as ColumnKind, at as OwnCrdtSnapshot, b as EventsPushResponse, bn as SyncDbMigrator, bt as createDeferredPromise, c as SyncedDbTransaction, cn as InferRow, ct as SystemMigration, dn as SyncSchemaTables, dt as applyWorkerDbSchema, en as SyncDbSchema, et as createImportData, fn as TableBuilder, g as CrdtSyncRemoteSource, gn as t, gt as DistributiveOmit, h as makeCrdtTable, hn as WriteOrigin, ht as DeferredPromise, i as SyncedDb, in as ColumnBuilder, it as OwnCrdtEvent, j as createCrdtApplyFunction, jn as PersistedCrdtEvent, jt as ExecuteResult, k as createCrdtStorageMutator, kn as CrdtUpdateLogItem, kt as createSQLiteKvStore, l as UnsafeSyncedDbSqlExecutor, ln as PayloadValidationResult, lt as SystemMigrationContext, mn as TableOptions, n as ResetRequest, nn as AnyColumnBuilder, nt as CrdtStorage, o as SyncedDbOptions, on as ColumnMeta, ot as createCrdtStorage, pn as TableColumns, q as SharedLiveQuerySnapshot, qt as HLC, r as ResetStore, rn as AnyTableBuilder, s as SyncedDbSqlExecutor, sn as ExportImportMode, st as SystemDbConfig, t as RESET_REQUEST_TTL_MS, tn as AiAccess, u as createSyncedDb, un as SqliteStorageType, ut as applyMemoryDbSchema, v as EventsPullRequest, vn as Migrations, vt as TypedEvent, w as WorkerNotificationMessage, wn as createStoredValue, wt as quoteId, x as createCrdtSyncRemoteSource, xn as createMigrations, xt as createTypedEventTarget, y as EventsPushRequest, yn as MigrationsDb, yt as TypedEventTarget, z as DefineSyncSchemaConfig } from "./index-BHsKLqcK.js";
|
|
2
2
|
export { type AdmitClientEventsResult, type AiAccess, type AnyColumnBuilder, type AnyTableBuilder, CRDT_EVENT_NO_OP_PAYLOAD, ColumnBuilder, type ColumnKind, type ColumnMeta, type ColumnMetadata, type CrdtEventOrigin, type CrdtEventStatus, type CrdtEventType, CrdtEventValidationError, type CrdtStorage, type CrdtStorageMutator, type CrdtSyncRemoteSource, type CrdtTableConfig, type CrdtUpdateLogItem, type CrdtUpdateLogPayload, type DatabaseIntrospection, type DeferredPromise, type DefineSyncSchemaConfig, type DefinedSyncSchema, type DistributiveOmit, type EventsPullRequest, type EventsPushRequest, type EventsPushResponse, type ExecuteParams, type ExecuteResult, type ExportImportMode, type HLC, HLCCounter, type ImportDataOptions, type ImportDataResult, type InferRow, type KvStoreItem, type KyselyQueryFactory, type LogLevel, type Logger, type MigratableEvent, type Migrations, type MigrationsDb, type NewCrdtEventValidationResult, type OwnCrdtEvent, type OwnCrdtSnapshot, type PayloadValidationResult, type PendingCrdtEvent, type PersistedCrdtEvent, type PreparedStatement, type QueryBuilderOutput, RESET_REQUEST_TTL_MS, type ReadonlyTable, type ResetRequest, type ResetStore, SQLiteDbWrapper, SQLiteReactiveDb, type SQLiteTransactionWrapper, type SchemaVerificationIssue, type SharedLiveQuery, type SharedLiveQuerySnapshot, type SnapshotOptions, type SqliteStorageType, type StoredValue, type SyncDbMigrator, type SyncDbSchema, type SyncSchemaTables, type SyncedDb, type SyncedDbDatabase, type SyncedDbExport, type SyncedDbOptions, type SyncedDbSqlExecutor, type SyncedDbTransaction, type SystemDbConfig, type SystemMigration, type SystemMigrationContext, TableBuilder, type TableColumns, type TableMetadata, type TableOptions, TypedBroadcastChannel, TypedEvent, type TypedEventTarget, type UnsafeSyncedDbSqlExecutor, type WorkerConfig, type WorkerNotificationMessage, type WorkerState, type WriteOrigin, admitClientEvents, applyMemoryDbSchema, applyWorkerDbSchema, compareHLC, createCrdtApplyFunction, createCrdtStorage, createCrdtStorageMutator, createCrdtSyncProducer, createCrdtSyncRemoteSource, createDeferredPromise, createExportData, createImportData, createKvStoreTableQuery, createMigrations, createMigrator, createSQLiteCrdtApplyFunction, createSQLiteKvStore, createStoredValue, createSyncedDb, createTypedEventTarget, defineSyncSchema, deserializeHLC, dummyKysely, formatSchemaVerificationIssues, generateId, introspectDb, isNoOpCrdtEventPayload, jsonSafeParse, makeCrdtTable, parametersAreEqual, quoteId, serializeHLC, startPerformanceLogger, t, tryCatch, tryCatchAsync, validateNewCrdtEvent, verifySyncSchema, xxhash };
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as
|
|
3
|
-
import { a as
|
|
4
|
-
import { a as
|
|
1
|
+
import { a as memoryDbConfig, c as createKvStoreTableQuery, d as SQLiteDbWrapper, h as dummyKysely, l as createSQLiteKvStore, m as introspectDb, n as applyWorkerDbSchema, p as startPerformanceLogger, t as applyMemoryDbSchema, u as createStoredValue } from "./system-schema-Dvl_BLId.js";
|
|
2
|
+
import { a as acquireLock, d as noop, h as tryCatchAsync, i as TypedEvent, l as generateId, m as tryCatch, n as isNoOpCrdtEventPayload, o as createDeferredPromise, p as quoteId, r as TypedBroadcastChannel, s as createTypedEventTarget, t as CRDT_EVENT_NO_OP_PAYLOAD, u as jsonSafeParse } from "./crdt-table-schema-BRm_WdcW.js";
|
|
3
|
+
import { C as xxhash, S as createMigrator, T as createImportData, _ as createCrdtApplyFunction, a as acquireReplicaLock, b as verifySyncSchema, c as isWorkerErrorResponseMessage, f as isWorkerResponseMessage, g as createCrdtStorage, h as createCrdtSyncProducer, p as syncDbClientLockName, s as createBroadcastChannels, t as RESET_REQUEST_TTL_MS, u as isWorkerNotificationMessage, v as createSQLiteCrdtApplyFunction, w as createExportData, x as createMigrations, y as formatSchemaVerificationIssues } from "./reset-state-t0tTGqoh.js";
|
|
4
|
+
import { a as HLCCounter, c as serializeHLC, n as CrdtEventValidationError, o as compareHLC, r as validateNewCrdtEvent, s as deserializeHLC, t as createCrdtSyncRemoteSource } from "./crdt-sync-remote-source-CPXzmSIS.js";
|
|
5
5
|
import { n as buildWriteOriginByName, t as admitClientEvents } from "./admit-client-events-BDrJw4SK.js";
|
|
6
|
-
import { a as makeCrdtTable, o as registerCrdtIntentDrainer } from "./make-crdt-table-
|
|
6
|
+
import { a as makeCrdtTable, o as registerCrdtIntentDrainer } from "./make-crdt-table-C6l0F-o_.js";
|
|
7
7
|
import sqlite3InitModule from "@sqlite.org/sqlite-wasm";
|
|
8
8
|
//#region src/bound-map.ts
|
|
9
9
|
var BoundMap = class {
|
|
@@ -689,18 +689,22 @@ const createWorkerDbClient = async ({ broadcastChannels, worker, config }) => {
|
|
|
689
689
|
const queryWorker = (method, args) => {
|
|
690
690
|
if (isDisposed) return Promise.reject(/* @__PURE__ */ new Error("Worker client disposed"));
|
|
691
691
|
const requestId = crypto.randomUUID();
|
|
692
|
-
const promise = createDeferredPromise({
|
|
693
|
-
timeout: 3e4,
|
|
694
|
-
onTimeout: () => workerRequestsMap.delete(requestId)
|
|
695
|
-
});
|
|
696
|
-
workerRequestsMap.set(requestId, promise);
|
|
697
692
|
const request = {
|
|
698
693
|
type: "request",
|
|
699
694
|
requestId,
|
|
700
695
|
method,
|
|
701
696
|
args
|
|
702
697
|
};
|
|
703
|
-
|
|
698
|
+
try {
|
|
699
|
+
broadcastChannels.requests.postMessage(request);
|
|
700
|
+
} catch (error) {
|
|
701
|
+
return Promise.reject(error);
|
|
702
|
+
}
|
|
703
|
+
const promise = createDeferredPromise({
|
|
704
|
+
timeout: 3e4,
|
|
705
|
+
onTimeout: () => workerRequestsMap.delete(requestId)
|
|
706
|
+
});
|
|
707
|
+
workerRequestsMap.set(requestId, promise);
|
|
704
708
|
return promise.promise;
|
|
705
709
|
};
|
|
706
710
|
const handleWorkerResponse = (message) => {
|
|
@@ -730,17 +734,10 @@ const createWorkerDbClient = async ({ broadcastChannels, worker, config }) => {
|
|
|
730
734
|
postState: () => queryWorker("postState", []),
|
|
731
735
|
goOnline: () => queryWorker("goOnline", []),
|
|
732
736
|
goOffline: () => queryWorker("goOffline", []),
|
|
737
|
+
dropConnection: () => queryWorker("dropConnection", []),
|
|
733
738
|
sync: () => queryWorker("sync", []),
|
|
734
739
|
requestReload: (options) => queryWorker("requestReload", [options])
|
|
735
740
|
};
|
|
736
|
-
const statePromise = awaitWorkerState(eventTarget);
|
|
737
|
-
postWorkerConfig(worker, config);
|
|
738
|
-
rpc.postState().catch(noop);
|
|
739
|
-
let { state: workerState, storageGeneration } = await statePromise;
|
|
740
|
-
eventTarget.addEventListener("state-changed", (event) => {
|
|
741
|
-
workerState = event.payload.state;
|
|
742
|
-
storageGeneration = event.payload.storageGeneration;
|
|
743
|
-
});
|
|
744
741
|
const dispose = () => {
|
|
745
742
|
isDisposed = true;
|
|
746
743
|
broadcastChannels.responses.onmessage = null;
|
|
@@ -749,13 +746,25 @@ const createWorkerDbClient = async ({ broadcastChannels, worker, config }) => {
|
|
|
749
746
|
workerRequestsMap.delete(id);
|
|
750
747
|
}
|
|
751
748
|
};
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
749
|
+
try {
|
|
750
|
+
postWorkerConfig(worker, config);
|
|
751
|
+
rpc.postState().catch(noop);
|
|
752
|
+
let { state: workerState, storageGeneration } = await awaitWorkerState(eventTarget);
|
|
753
|
+
eventTarget.addEventListener("state-changed", (event) => {
|
|
754
|
+
workerState = event.payload.state;
|
|
755
|
+
storageGeneration = event.payload.storageGeneration;
|
|
756
|
+
});
|
|
757
|
+
return {
|
|
758
|
+
...rpc,
|
|
759
|
+
subscribe: eventTarget.addEventListener,
|
|
760
|
+
getState: () => workerState,
|
|
761
|
+
getStorageGeneration: () => storageGeneration,
|
|
762
|
+
dispose
|
|
763
|
+
};
|
|
764
|
+
} catch (error) {
|
|
765
|
+
dispose();
|
|
766
|
+
throw error;
|
|
767
|
+
}
|
|
759
768
|
};
|
|
760
769
|
function awaitWorkerState(eventTarget) {
|
|
761
770
|
const promise = createDeferredPromise({ timeout: 15e3 });
|
|
@@ -821,168 +830,191 @@ async function createSyncedDb(options) {
|
|
|
821
830
|
const instanceId = generateId();
|
|
822
831
|
const tabId = generateId();
|
|
823
832
|
const broadcastChannels = createBroadcastChannels(options.dbId);
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
await clientLockAcquired.promise;
|
|
831
|
-
const workerClient = await createWorkerDbClient({
|
|
832
|
-
worker: options.worker,
|
|
833
|
-
config: {
|
|
834
|
-
clientId: generateId(),
|
|
835
|
-
dbId: options.dbId,
|
|
836
|
-
props: options.workerProps
|
|
837
|
-
},
|
|
838
|
-
broadcastChannels
|
|
839
|
-
});
|
|
840
|
-
const hlcCounter = new HLCCounter(tabId, () => Date.now());
|
|
841
|
-
const workerClientSnapshot = await workerClient.getSnapshot();
|
|
842
|
-
const reactiveDb = await createSQLiteReactiveDb({
|
|
843
|
-
snapshot: workerClientSnapshot.file,
|
|
844
|
-
logger: defaultLogger
|
|
845
|
-
});
|
|
846
|
-
const memoryDbMigrator = {
|
|
847
|
-
currentSchemaVersion: workerClientSnapshot.schemaVersion,
|
|
848
|
-
latestSchemaVersion: workerClientSnapshot.schemaVersion,
|
|
849
|
-
migrateDbToLatest: () => {
|
|
850
|
-
throw new Error("Memory DB migrations are not implemented");
|
|
851
|
-
},
|
|
852
|
-
migrateEvent: (event, targetVersion) => {
|
|
853
|
-
if (event.schema_version === targetVersion) return event;
|
|
854
|
-
throw new Error("Memory DB migrations are not implemented");
|
|
855
|
-
},
|
|
856
|
-
migrateEvents: (events) => events
|
|
857
|
-
};
|
|
858
|
-
const { crdtStorage } = await createMemoryDb({
|
|
859
|
-
nodeId: tabId,
|
|
860
|
-
migrator: memoryDbMigrator,
|
|
861
|
-
reactiveDb,
|
|
862
|
-
hlcCounter,
|
|
863
|
-
crdtTables: options.syncDbSchema.tablesConfig,
|
|
864
|
-
syncDbSchema: options.syncDbSchema
|
|
865
|
-
});
|
|
866
|
-
const pullSyncId = createStoredValue({ initialValue: workerClientSnapshot.syncId });
|
|
867
|
-
const pushSyncId = createStoredValue({ initialValue: 0 });
|
|
868
|
-
const tabRemoteSource = createCrdtSyncRemoteSource({
|
|
869
|
-
bufferSize: 500,
|
|
870
|
-
pullSyncId,
|
|
871
|
-
pushSyncId,
|
|
872
|
-
storage: crdtStorage,
|
|
873
|
-
nodeId: tabId,
|
|
874
|
-
migrator: memoryDbMigrator,
|
|
875
|
-
remoteFactory: ({ onEventsAvailable }) => {
|
|
876
|
-
const subscription = workerClient.subscribe("new-event-chunk-applied", (event) => {
|
|
877
|
-
onEventsAvailable({
|
|
878
|
-
newSyncId: event.payload.newSyncId,
|
|
879
|
-
remoteEventHlcSum: event.payload.eventHlcSum
|
|
880
|
-
});
|
|
881
|
-
});
|
|
882
|
-
return {
|
|
883
|
-
pullEvents: (request) => workerClient.pullEvents(request),
|
|
884
|
-
pushEvents: (request) => workerClient.pushTabEvents(request),
|
|
885
|
-
disconnect: () => {
|
|
886
|
-
subscription.unsubscribe();
|
|
887
|
-
}
|
|
888
|
-
};
|
|
889
|
-
}
|
|
890
|
-
});
|
|
891
|
-
tabRemoteSource.goOnline();
|
|
892
|
-
const reloadRequestedSubscription = workerClient.subscribe("reload-requested", () => {
|
|
893
|
-
globalThis.location?.reload();
|
|
894
|
-
});
|
|
895
|
-
const reloadIfStorageReplaced = (storageGeneration) => {
|
|
896
|
-
if (storageGeneration !== workerClientSnapshot.storageGeneration) {
|
|
897
|
-
storageReplacedSubscription.unsubscribe();
|
|
898
|
-
globalThis.location?.reload();
|
|
899
|
-
}
|
|
900
|
-
};
|
|
901
|
-
const storageReplacedSubscription = workerClient.subscribe("state-changed", (event) => {
|
|
902
|
-
reloadIfStorageReplaced(event.payload.storageGeneration);
|
|
903
|
-
});
|
|
904
|
-
reloadIfStorageReplaced(workerClient.getStorageGeneration());
|
|
905
|
-
const sync = () => {
|
|
906
|
-
workerClient.sync().catch((error) => console.warn("Failed to start sync", error));
|
|
907
|
-
};
|
|
908
|
-
const syncWhenVisible = () => {
|
|
909
|
-
if (globalThis.document?.visibilityState === "visible") sync();
|
|
910
|
-
};
|
|
911
|
-
globalThis.document?.addEventListener("visibilitychange", syncWhenVisible);
|
|
912
|
-
globalThis.addEventListener?.("online", sync);
|
|
913
|
-
perf.logEnd("createSyncedDb", "initialized", "info");
|
|
914
|
-
const exportData = createExportData({
|
|
915
|
-
reactiveDb,
|
|
916
|
-
tablesConfig: options.syncDbSchema.tablesConfig,
|
|
917
|
-
schemaVersion: workerClientSnapshot.schemaVersion
|
|
918
|
-
});
|
|
919
|
-
const importData = (data, opts) => workerClient.importData(data, opts);
|
|
920
|
-
let isDisposed = false;
|
|
833
|
+
let releaseClientLock;
|
|
834
|
+
let disposeWorkerClient;
|
|
835
|
+
let releaseReplicaLock;
|
|
836
|
+
let disposeReactiveDb;
|
|
837
|
+
let disposeRemoteSource;
|
|
838
|
+
const cleanupCallbacks = [];
|
|
921
839
|
let unregisterDevtools;
|
|
840
|
+
let isDisposed = false;
|
|
922
841
|
const dispose = async () => {
|
|
923
842
|
if (isDisposed) return;
|
|
924
843
|
isDisposed = true;
|
|
925
844
|
unregisterDevtools?.();
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
db: createSyncedDbDatabase(reactiveDb),
|
|
939
|
-
state: {
|
|
940
|
-
getState: workerClient.getState.bind(workerClient),
|
|
941
|
-
subscribe: (onChange) => {
|
|
942
|
-
const { unsubscribe } = workerClient.subscribe("state-changed", onChange);
|
|
943
|
-
return unsubscribe;
|
|
944
|
-
},
|
|
945
|
-
goOnline: workerClient.goOnline.bind(workerClient),
|
|
946
|
-
goOffline: workerClient.goOffline.bind(workerClient),
|
|
947
|
-
sync
|
|
948
|
-
},
|
|
949
|
-
/**
|
|
950
|
-
* Ask the elected worker to broadcast a page reload to all tabs for this dbId.
|
|
951
|
-
*
|
|
952
|
-
* With `clean: true` the worker durably records a reset request epoch before
|
|
953
|
-
* broadcasting, so the worker elected on the next startup initializes with
|
|
954
|
-
* `clearOnInit: true` and wipes the persisted DB. Destructive — use as a
|
|
955
|
-
* recovery path when the durable worker DB may be de-synced.
|
|
956
|
-
*
|
|
957
|
-
* Pending in-memory tab events are not preserved, and the returned promise
|
|
958
|
-
* may never settle in the caller — the page typically unloads first.
|
|
959
|
-
*/
|
|
960
|
-
requestReload: async (options) => {
|
|
961
|
-
await workerClient.requestReload(options);
|
|
962
|
-
setTimeout(() => globalThis.location?.reload(), 250);
|
|
963
|
-
},
|
|
964
|
-
subscribe: workerClient.subscribe,
|
|
965
|
-
exportData,
|
|
966
|
-
importData,
|
|
967
|
-
dispose,
|
|
968
|
-
_internal: {
|
|
969
|
-
executeAsync: workerClient.execute.bind(workerClient),
|
|
970
|
-
getMemoryQueryTables: reactiveDb.getTablesUsed.bind(reactiveDb),
|
|
971
|
-
getSharedLiveQueriesSnapshot: reactiveDb.getSharedLiveQueriesSnapshot.bind(reactiveDb),
|
|
972
|
-
crdtTableNames: options.syncDbSchema.tablesConfig.map((table) => table.crdtTableName),
|
|
973
|
-
crdtTablesConfig: options.syncDbSchema.tablesConfig,
|
|
974
|
-
tables: options.syncDbSchema.tables,
|
|
975
|
-
schemaVersion: workerClientSnapshot.schemaVersion,
|
|
976
|
-
migrationVersions: Object.keys(options.syncDbSchema.migrations).map(Number).sort((a, b) => a - b)
|
|
845
|
+
for (const cleanup of cleanupCallbacks) cleanup();
|
|
846
|
+
try {
|
|
847
|
+
await disposeRemoteSource?.();
|
|
848
|
+
} finally {
|
|
849
|
+
broadcastChannels.requests.close();
|
|
850
|
+
broadcastChannels.responses.close();
|
|
851
|
+
disposeWorkerClient?.();
|
|
852
|
+
try {
|
|
853
|
+
disposeReactiveDb?.();
|
|
854
|
+
} finally {
|
|
855
|
+
await Promise.all([releaseClientLock?.(), releaseReplicaLock?.()]);
|
|
856
|
+
}
|
|
977
857
|
}
|
|
978
858
|
};
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
859
|
+
try {
|
|
860
|
+
releaseClientLock = await acquireLock(`${syncDbClientLockName}-${options.dbId}`, { mode: "shared" });
|
|
861
|
+
const workerClient = await createWorkerDbClient({
|
|
862
|
+
worker: options.worker,
|
|
863
|
+
config: {
|
|
864
|
+
clientId: generateId(),
|
|
865
|
+
dbId: options.dbId,
|
|
866
|
+
props: options.workerProps
|
|
867
|
+
},
|
|
868
|
+
broadcastChannels
|
|
869
|
+
});
|
|
870
|
+
disposeWorkerClient = () => workerClient.dispose();
|
|
871
|
+
const hlcCounter = new HLCCounter(tabId, () => Date.now());
|
|
872
|
+
releaseReplicaLock = await acquireReplicaLock({ dbId: options.dbId });
|
|
873
|
+
const workerClientSnapshot = await workerClient.getSnapshot();
|
|
874
|
+
const reactiveDb = await createSQLiteReactiveDb({
|
|
875
|
+
snapshot: workerClientSnapshot.file,
|
|
876
|
+
logger: defaultLogger
|
|
877
|
+
});
|
|
878
|
+
disposeReactiveDb = () => reactiveDb.dispose();
|
|
879
|
+
const memoryDbMigrator = {
|
|
880
|
+
currentSchemaVersion: workerClientSnapshot.schemaVersion,
|
|
881
|
+
latestSchemaVersion: workerClientSnapshot.schemaVersion,
|
|
882
|
+
migrateDbToLatest: () => {
|
|
883
|
+
throw new Error("Memory DB migrations are not implemented");
|
|
884
|
+
},
|
|
885
|
+
migrateEvent: (event, targetVersion) => {
|
|
886
|
+
if (event.schema_version === targetVersion) return event;
|
|
887
|
+
throw new Error("Memory DB migrations are not implemented");
|
|
888
|
+
},
|
|
889
|
+
migrateEvents: (events) => events
|
|
890
|
+
};
|
|
891
|
+
const { crdtStorage } = await createMemoryDb({
|
|
892
|
+
nodeId: tabId,
|
|
893
|
+
migrator: memoryDbMigrator,
|
|
894
|
+
reactiveDb,
|
|
895
|
+
hlcCounter,
|
|
896
|
+
crdtTables: options.syncDbSchema.tablesConfig,
|
|
897
|
+
syncDbSchema: options.syncDbSchema
|
|
898
|
+
});
|
|
899
|
+
const pullSyncId = createStoredValue({ initialValue: workerClientSnapshot.syncId });
|
|
900
|
+
const pushSyncId = createStoredValue({ initialValue: 0 });
|
|
901
|
+
const tabRemoteSource = createCrdtSyncRemoteSource({
|
|
902
|
+
bufferSize: 500,
|
|
903
|
+
pullSyncId,
|
|
904
|
+
pushSyncId,
|
|
905
|
+
storage: crdtStorage,
|
|
906
|
+
nodeId: tabId,
|
|
907
|
+
migrator: memoryDbMigrator,
|
|
908
|
+
remoteFactory: ({ onEventsAvailable }) => {
|
|
909
|
+
const subscription = workerClient.subscribe("new-event-chunk-applied", (event) => {
|
|
910
|
+
onEventsAvailable({
|
|
911
|
+
newSyncId: event.payload.newSyncId,
|
|
912
|
+
remoteEventHlcSum: event.payload.eventHlcSum
|
|
913
|
+
});
|
|
914
|
+
});
|
|
915
|
+
return {
|
|
916
|
+
pullEvents: (request) => workerClient.pullEvents(request),
|
|
917
|
+
pushEvents: (request) => workerClient.pushTabEvents(request),
|
|
918
|
+
disconnect: () => {
|
|
919
|
+
subscription.unsubscribe();
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
});
|
|
924
|
+
disposeRemoteSource = () => tabRemoteSource.dispose();
|
|
925
|
+
tabRemoteSource.goOnline();
|
|
926
|
+
const reloadRequestedSubscription = workerClient.subscribe("reload-requested", () => {
|
|
927
|
+
globalThis.location?.reload();
|
|
928
|
+
});
|
|
929
|
+
cleanupCallbacks.push(reloadRequestedSubscription.unsubscribe);
|
|
930
|
+
const reloadIfStorageReplaced = (storageGeneration) => {
|
|
931
|
+
if (storageGeneration !== workerClientSnapshot.storageGeneration) {
|
|
932
|
+
storageReplacedSubscription.unsubscribe();
|
|
933
|
+
globalThis.location?.reload();
|
|
934
|
+
}
|
|
935
|
+
};
|
|
936
|
+
const storageReplacedSubscription = workerClient.subscribe("state-changed", (event) => {
|
|
937
|
+
reloadIfStorageReplaced(event.payload.storageGeneration);
|
|
938
|
+
});
|
|
939
|
+
cleanupCallbacks.push(storageReplacedSubscription.unsubscribe);
|
|
940
|
+
reloadIfStorageReplaced(workerClient.getStorageGeneration());
|
|
941
|
+
const sync = () => {
|
|
942
|
+
workerClient.sync().catch((error) => console.warn("Failed to start sync", error));
|
|
943
|
+
};
|
|
944
|
+
const syncWhenVisible = () => {
|
|
945
|
+
if (globalThis.document?.visibilityState === "visible") sync();
|
|
946
|
+
};
|
|
947
|
+
const dropConnection = () => {
|
|
948
|
+
workerClient.dropConnection().catch((error) => console.warn("Failed to drop connection", error));
|
|
949
|
+
};
|
|
950
|
+
cleanupCallbacks.push(() => {
|
|
951
|
+
globalThis.document?.removeEventListener("visibilitychange", syncWhenVisible);
|
|
952
|
+
globalThis.removeEventListener?.("online", sync);
|
|
953
|
+
globalThis.removeEventListener?.("offline", dropConnection);
|
|
954
|
+
});
|
|
955
|
+
globalThis.document?.addEventListener("visibilitychange", syncWhenVisible);
|
|
956
|
+
globalThis.addEventListener?.("online", sync);
|
|
957
|
+
globalThis.addEventListener?.("offline", dropConnection);
|
|
958
|
+
perf.logEnd("createSyncedDb", "initialized", "info");
|
|
959
|
+
const exportData = createExportData({
|
|
960
|
+
reactiveDb,
|
|
961
|
+
tablesConfig: options.syncDbSchema.tablesConfig,
|
|
962
|
+
schemaVersion: workerClientSnapshot.schemaVersion
|
|
963
|
+
});
|
|
964
|
+
const importData = (data, opts) => workerClient.importData(data, opts);
|
|
965
|
+
const syncedDb = {
|
|
966
|
+
db: createSyncedDbDatabase(reactiveDb),
|
|
967
|
+
state: {
|
|
968
|
+
getState: workerClient.getState.bind(workerClient),
|
|
969
|
+
subscribe: (onChange) => {
|
|
970
|
+
const { unsubscribe } = workerClient.subscribe("state-changed", onChange);
|
|
971
|
+
return unsubscribe;
|
|
972
|
+
},
|
|
973
|
+
goOnline: workerClient.goOnline.bind(workerClient),
|
|
974
|
+
goOffline: workerClient.goOffline.bind(workerClient),
|
|
975
|
+
sync
|
|
976
|
+
},
|
|
977
|
+
/**
|
|
978
|
+
* Ask the elected worker to broadcast a page reload to all tabs for this dbId.
|
|
979
|
+
*
|
|
980
|
+
* With `clean: true` the worker durably records a reset request epoch before
|
|
981
|
+
* broadcasting, so the worker elected on the next startup initializes with
|
|
982
|
+
* `clearOnInit: true` and wipes the persisted DB. Destructive — use as a
|
|
983
|
+
* recovery path when the durable worker DB may be de-synced.
|
|
984
|
+
*
|
|
985
|
+
* Pending in-memory tab events are not preserved, and the returned promise
|
|
986
|
+
* may never settle in the caller — the page typically unloads first.
|
|
987
|
+
*/
|
|
988
|
+
requestReload: async (options) => {
|
|
989
|
+
await workerClient.requestReload(options);
|
|
990
|
+
setTimeout(() => globalThis.location?.reload(), 250);
|
|
991
|
+
},
|
|
992
|
+
subscribe: workerClient.subscribe,
|
|
993
|
+
exportData,
|
|
994
|
+
importData,
|
|
995
|
+
dispose,
|
|
996
|
+
_internal: {
|
|
997
|
+
executeAsync: workerClient.execute.bind(workerClient),
|
|
998
|
+
getMemoryQueryTables: reactiveDb.getTablesUsed.bind(reactiveDb),
|
|
999
|
+
getSharedLiveQueriesSnapshot: reactiveDb.getSharedLiveQueriesSnapshot.bind(reactiveDb),
|
|
1000
|
+
crdtTableNames: options.syncDbSchema.tablesConfig.map((table) => table.crdtTableName),
|
|
1001
|
+
crdtTablesConfig: options.syncDbSchema.tablesConfig,
|
|
1002
|
+
tables: options.syncDbSchema.tables,
|
|
1003
|
+
schemaVersion: workerClientSnapshot.schemaVersion,
|
|
1004
|
+
migrationVersions: Object.keys(options.syncDbSchema.migrations).map(Number).sort((a, b) => a - b)
|
|
1005
|
+
}
|
|
1006
|
+
};
|
|
1007
|
+
unregisterDevtools = getOrCreateSQLiteSyncDevtoolsRegistry().register({
|
|
1008
|
+
instanceId,
|
|
1009
|
+
dbId: options.dbId,
|
|
1010
|
+
createdAt: Date.now(),
|
|
1011
|
+
instance: syncedDb
|
|
1012
|
+
});
|
|
1013
|
+
return syncedDb;
|
|
1014
|
+
} catch (error) {
|
|
1015
|
+
await dispose();
|
|
1016
|
+
throw error;
|
|
1017
|
+
}
|
|
986
1018
|
}
|
|
987
1019
|
//#endregion
|
|
988
1020
|
export { CRDT_EVENT_NO_OP_PAYLOAD, ColumnBuilder, CrdtEventValidationError, HLCCounter, RESET_REQUEST_TTL_MS, SQLiteDbWrapper, SQLiteReactiveDb, TableBuilder, TypedBroadcastChannel, TypedEvent, admitClientEvents, applyMemoryDbSchema, applyWorkerDbSchema, compareHLC, createCrdtApplyFunction, createCrdtStorage, createCrdtStorageMutator, createCrdtSyncProducer, createCrdtSyncRemoteSource, createDeferredPromise, createExportData, createImportData, createKvStoreTableQuery, createMigrations, createMigrator, createSQLiteCrdtApplyFunction, createSQLiteKvStore, createStoredValue, createSyncedDb, createTypedEventTarget, defineSyncSchema, deserializeHLC, dummyKysely, formatSchemaVerificationIssues, generateId, introspectDb, isNoOpCrdtEventPayload, jsonSafeParse, makeCrdtTable, parametersAreEqual, quoteId, serializeHLC, startPerformanceLogger, t, tryCatch, tryCatchAsync, validateNewCrdtEvent, verifySyncSchema, xxhash };
|