@sqlite-sync/core 0.14.1 → 0.14.3
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/{crdt-sync-producer-BQkuzCBM.js → crdt-sync-producer-CUXiu4X3.js} +2 -2
- package/dist/{crdt-sync-producer-BQkuzCBM.js.map → crdt-sync-producer-CUXiu4X3.js.map} +1 -1
- package/dist/{crdt-sync-remote-source-yeTEkOjH.js → crdt-sync-remote-source-CH2bsr-x.js} +63 -16
- package/dist/crdt-sync-remote-source-CH2bsr-x.js.map +1 -0
- package/dist/{index-BgkTUdlX.d.ts → index-C1E8xMH1.d.ts} +21 -2
- package/dist/{index.common-DIN0mZxR.js → index.common-c-Je9hVa.js} +3 -3
- package/dist/{index.common-DIN0mZxR.js.map → index.common-c-Je9hVa.js.map} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +48 -5
- package/dist/index.js.map +1 -1
- package/dist/index.native.d.ts +2 -2
- package/dist/index.native.js +3 -3
- package/dist/internal.d.ts +1 -1
- package/dist/local.d.ts +6 -6
- package/dist/local.js +6 -5
- package/dist/local.js.map +1 -1
- package/dist/{reset-state-DAPyJglN.js → reset-state-BeJZaX-W.js} +2 -2
- package/dist/reset-state-BeJZaX-W.js.map +1 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +1 -1
- package/dist/worker.d.ts +4 -4
- package/dist/worker.js +6 -5
- package/dist/worker.js.map +1 -1
- package/dist/{ws-remote-source-BJFkwEyQ.d.ts → ws-remote-source-Bk6NYwML.d.ts} +2 -2
- package/dist/{ws-remote-source-BbPWrHB6.js → ws-remote-source-CliRqkIW.js} +60 -14
- package/dist/{ws-remote-source-BbPWrHB6.js.map → ws-remote-source-CliRqkIW.js.map} +1 -1
- package/package.json +1 -1
- package/dist/crdt-sync-remote-source-yeTEkOjH.js.map +0 -1
- package/dist/reset-state-DAPyJglN.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { b as introspectDb, c as memoryDbConfig, g as SQLiteDbWrapper, h as createStoredValue, i as applyWorkerDbSchema, m as createSQLiteKvStore, p as createKvStoreTableQuery, r as applyMemoryDbSchema, x as dummyKysely, y as startPerformanceLogger } from "./system-schema-B8hbFl7o.js";
|
|
2
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-D6Yf61Ex.js";
|
|
3
|
-
import { a as formatSchemaVerificationIssues, c as createMigrator, i as createSQLiteCrdtApplyFunction, l as createExportData, n as createCrdtStorage, o as verifySyncSchemaWithDriver, r as createCrdtApplyFunction, s as createMigrations, t as createCrdtSyncProducer, u as createImportData } from "./crdt-sync-producer-
|
|
4
|
-
import { c as deserializeHLC, i as validateNewCrdtEvent, l as serializeHLC, o as HLCCounter, r as CrdtEventValidationError, s as compareHLC, t as createCrdtSyncRemoteSource, u as xxhash } from "./crdt-sync-remote-source-
|
|
3
|
+
import { a as formatSchemaVerificationIssues, c as createMigrator, i as createSQLiteCrdtApplyFunction, l as createExportData, n as createCrdtStorage, o as verifySyncSchemaWithDriver, r as createCrdtApplyFunction, s as createMigrations, t as createCrdtSyncProducer, u as createImportData } from "./crdt-sync-producer-CUXiu4X3.js";
|
|
4
|
+
import { c as deserializeHLC, i as validateNewCrdtEvent, l as serializeHLC, o as HLCCounter, r as CrdtEventValidationError, s as compareHLC, t as createCrdtSyncRemoteSource, u as xxhash } from "./crdt-sync-remote-source-CH2bsr-x.js";
|
|
5
5
|
import { n as parametersAreEqual, t as SQLiteReactiveDb } from "./sqlite-reactive-db-DLTvpGzO.js";
|
|
6
6
|
import { t as admitClientEvents } from "./admit-client-events-BDrJw4SK.js";
|
|
7
|
-
import { a as defineSyncSchema, i as t, n as ColumnBuilder, r as TableBuilder, t as createCrdtStorageMutator } from "./index.common-
|
|
7
|
+
import { a as defineSyncSchema, i as t, n as ColumnBuilder, r as TableBuilder, t as createCrdtStorageMutator } from "./index.common-c-Je9hVa.js";
|
|
8
8
|
import { a as makeCrdtTable, o as registerCrdtIntentDrainer } from "./make-crdt-table-Cu8WhRBk.js";
|
|
9
|
-
import { _ as createWasmSqliteDriver, a as acquireReplicaLock, c as isWorkerErrorResponseMessage, f as isWorkerResponseMessage, g as createWasmMemoryDriver, h as verifySyncSchema, p as syncDbClientLockName, s as createBroadcastChannels, t as RESET_REQUEST_TTL_MS, u as isWorkerNotificationMessage, v as loadSqliteWasm } from "./reset-state-
|
|
9
|
+
import { _ as createWasmSqliteDriver, a as acquireReplicaLock, c as isWorkerErrorResponseMessage, f as isWorkerResponseMessage, g as createWasmMemoryDriver, h as verifySyncSchema, p as syncDbClientLockName, s as createBroadcastChannels, t as RESET_REQUEST_TTL_MS, u as isWorkerNotificationMessage, v as loadSqliteWasm } from "./reset-state-BeJZaX-W.js";
|
|
10
10
|
import { n as getOrCreateSQLiteSyncDevtoolsRegistry, r as validateDbId, t as createSyncedDbDatabase } from "./synced-db-database-B5M7MrBD.js";
|
|
11
11
|
//#region src/memory-db/wasm-reactive-db.ts
|
|
12
12
|
async function createSQLiteReactiveDb(opts) {
|
|
@@ -105,6 +105,7 @@ const createWorkerDbClient = async ({ broadcastChannels, worker, config }) => {
|
|
|
105
105
|
goOffline: () => queryWorker("goOffline", []),
|
|
106
106
|
dropConnection: () => queryWorker("dropConnection", []),
|
|
107
107
|
sync: () => queryWorker("sync", []),
|
|
108
|
+
catchUp: (options) => queryWorker("catchUp", [options]),
|
|
108
109
|
requestReload: (options) => queryWorker("requestReload", [options])
|
|
109
110
|
};
|
|
110
111
|
const dispose = () => {
|
|
@@ -284,6 +285,42 @@ async function createSyncedDb(options) {
|
|
|
284
285
|
const sync = () => {
|
|
285
286
|
workerClient.sync().catch((error) => console.warn("Failed to start sync", error));
|
|
286
287
|
};
|
|
288
|
+
const catchUp = async ({ timeoutMs = 1e4 } = {}) => {
|
|
289
|
+
const deadline = Date.now() + timeoutMs;
|
|
290
|
+
const timedOut = {
|
|
291
|
+
pulled: false,
|
|
292
|
+
pushed: false,
|
|
293
|
+
timedOut: true
|
|
294
|
+
};
|
|
295
|
+
const step = async (run) => {
|
|
296
|
+
const remaining = deadline - Date.now();
|
|
297
|
+
if (remaining <= 0) return timedOut;
|
|
298
|
+
let timer;
|
|
299
|
+
const timeout = new Promise((resolve) => {
|
|
300
|
+
timer = setTimeout(() => resolve(timedOut), remaining);
|
|
301
|
+
});
|
|
302
|
+
try {
|
|
303
|
+
return await Promise.race([run(remaining), timeout]);
|
|
304
|
+
} finally {
|
|
305
|
+
clearTimeout(timer);
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
const toWorker = await step((remaining) => tabRemoteSource.catchUp({ timeoutMs: remaining }));
|
|
309
|
+
const remote = await step((remaining) => workerClient.catchUp({ timeoutMs: Math.min(remaining, 25e3) }).catch((error) => {
|
|
310
|
+
console.warn("Failed to catch up with the remote", error);
|
|
311
|
+
return {
|
|
312
|
+
pulled: false,
|
|
313
|
+
pushed: false,
|
|
314
|
+
timedOut: false
|
|
315
|
+
};
|
|
316
|
+
}));
|
|
317
|
+
const fromWorker = await step((remaining) => tabRemoteSource.catchUp({ timeoutMs: remaining }));
|
|
318
|
+
return {
|
|
319
|
+
pulled: remote.pulled && fromWorker.pulled,
|
|
320
|
+
pushed: toWorker.pushed && remote.pushed,
|
|
321
|
+
timedOut: toWorker.timedOut || remote.timedOut || fromWorker.timedOut
|
|
322
|
+
};
|
|
323
|
+
};
|
|
287
324
|
const syncWhenVisible = () => {
|
|
288
325
|
if (globalThis.document?.visibilityState === "visible") sync();
|
|
289
326
|
};
|
|
@@ -315,7 +352,13 @@ async function createSyncedDb(options) {
|
|
|
315
352
|
},
|
|
316
353
|
goOnline: workerClient.goOnline.bind(workerClient),
|
|
317
354
|
goOffline: workerClient.goOffline.bind(workerClient),
|
|
318
|
-
sync
|
|
355
|
+
sync,
|
|
356
|
+
/**
|
|
357
|
+
* Pulls what the remote has now and pushes pending local events, and resolves once that
|
|
358
|
+
* is done or `timeoutMs` (10 seconds by default) runs out. Best effort: it never rejects,
|
|
359
|
+
* does not wait for other clients to stop writing, and the result tells how far it got.
|
|
360
|
+
*/
|
|
361
|
+
catchUp
|
|
319
362
|
},
|
|
320
363
|
/**
|
|
321
364
|
* Ask the elected worker to broadcast a page reload to all tabs for this dbId.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/memory-db/wasm-reactive-db.ts","../src/memory-db/memory-db.ts","../src/worker-db/db-worker-client.ts","../src/sync-db.ts"],"sourcesContent":["import { createWasmMemoryDriver } from \"../wasm-driver\";\nimport { SQLiteReactiveDb, type SQLiteReactiveDbOptions } from \"./sqlite-reactive-db\";\n\nexport async function createSQLiteReactiveDb<Database>(opts: Omit<SQLiteReactiveDbOptions, \"driver\">) {\n const driver = await createWasmMemoryDriver();\n return SQLiteReactiveDb.create<Database>({ ...opts, driver });\n}\n","import { xxhash } from \"../hash\";\nimport type { HLCCounter } from \"../hlc\";\nimport type { SyncDbMigrator } from \"../migrations/migrator\";\nimport { applyMemoryDbSchema, type MemoryDbSchema, memoryDbConfig } from \"../migrations/system-schema\";\nimport type { CrdtTableConfig, SyncDbSchema } from \"../sqlite-crdt/crdt-schema\";\nimport { createCrdtStorage } from \"../sqlite-crdt/crdt-storage\";\nimport { makeCrdtTable, registerCrdtIntentDrainer } from \"../sqlite-crdt/make-crdt-table\";\nimport type { StateHashStore } from \"../sqlite-crdt/state-hash\";\nimport type { SQLiteDbWrapper } from \"../sqlite-db-wrapper\";\nimport type { SQLiteReactiveDb } from \"./sqlite-reactive-db\";\n\ntype MemoryDbOptions<Database> = {\n nodeId: string;\n migrator: SyncDbMigrator;\n reactiveDb: SQLiteReactiveDb<Database>;\n hlcCounter: HLCCounter;\n crdtTables: CrdtTableConfig[];\n initializeSchema?: boolean;\n initialSyncId?: number;\n stateHash?: StateHashStore;\n syncDbSchema: Pick<SyncDbSchema, \"tables\" | \"tablesConfig\">;\n};\n\nexport async function createMemoryDb<Database>({\n nodeId,\n migrator,\n reactiveDb: _reactiveDb,\n hlcCounter,\n crdtTables,\n initializeSchema = true,\n initialSyncId,\n stateHash,\n syncDbSchema,\n}: MemoryDbOptions<Database>) {\n await xxhash.ensureLoaded();\n\n const reactiveDb = _reactiveDb as unknown as SQLiteReactiveDb<MemoryDbSchema>;\n const db = reactiveDb.db;\n\n if (initializeSchema) {\n applyMemoryDbSchema(db);\n for (const table of crdtTables) {\n makeCrdtTable({\n db,\n baseTableName: table.baseTableName,\n crdtTableName: table.crdtTableName,\n });\n }\n }\n\n const crdtStorage = createCrdtStorage({\n nodeId,\n initialLocalSyncId: initialSyncId ?? getCurrentSyncId(db),\n hlc: hlcCounter,\n migrator,\n db,\n dbConfig: memoryDbConfig,\n stateHash,\n schema: syncDbSchema,\n });\n\n registerCrdtIntentDrainer({\n reactiveDb,\n storage: crdtStorage,\n });\n\n return {\n crdtStorage,\n };\n}\n\nfunction getCurrentSyncId(db: SQLiteDbWrapper<MemoryDbSchema>) {\n return (\n db.execute<{ syncId: number }>(\"SELECT coalesce(max(sync_id), 0) AS syncId FROM persisted_crdt_events\", {\n loggerLevel: \"system\",\n }).rows[0]?.syncId ?? 0\n );\n}\n","import {\n createDeferredPromise,\n createTypedEventTarget,\n type DeferredPromise,\n noop,\n type TypedEventTarget,\n} from \"../utils\";\nimport type {\n AsyncRpc,\n WorkerBroadcastChannels,\n WorkerConfig,\n WorkerErrorResponseMessage,\n WorkerInitMessage,\n WorkerNotificationEvents,\n WorkerRequestMessage,\n WorkerRequestMethod,\n WorkerResponseMessage,\n WorkerRpc,\n} from \"./worker-common\";\nimport { isWorkerErrorResponseMessage, isWorkerNotificationMessage, isWorkerResponseMessage } from \"./worker-common\";\n\ntype NotificationEvents = WorkerNotificationEvents;\n\nexport const createWorkerDbClient = async ({\n broadcastChannels,\n worker,\n config,\n}: {\n broadcastChannels: WorkerBroadcastChannels;\n worker: Worker;\n config: WorkerConfig;\n}) => {\n const eventTarget = createTypedEventTarget<NotificationEvents>();\n const workerRequestsMap = new Map<string, DeferredPromise<unknown>>();\n let isDisposed = false;\n\n const queryWorker = <TMethod extends WorkerRequestMethod>(\n method: TMethod,\n args: Parameters<WorkerRpc[TMethod]>,\n ): Promise<Awaited<ReturnType<WorkerRpc[TMethod]>>> => {\n if (isDisposed) {\n return Promise.reject(new Error(\"Worker client disposed\"));\n }\n const requestId = crypto.randomUUID();\n const request: WorkerRequestMessage<TMethod> = {\n type: \"request\",\n requestId,\n method,\n args,\n };\n\n try {\n broadcastChannels.requests.postMessage(request);\n } catch (error) {\n return Promise.reject(error);\n }\n\n const promise = createDeferredPromise<unknown>({\n timeout: 30_000,\n onTimeout: () => workerRequestsMap.delete(requestId),\n });\n workerRequestsMap.set(requestId, promise);\n\n return promise.promise as Promise<Awaited<ReturnType<WorkerRpc[TMethod]>>>;\n };\n\n const handleWorkerResponse = (message: WorkerResponseMessage) => {\n const promise = workerRequestsMap.get(message.requestId);\n if (!promise) {\n return;\n }\n\n promise.resolve(message.data);\n workerRequestsMap.delete(message.requestId);\n };\n\n const handleWorkerError = (message: WorkerErrorResponseMessage) => {\n const promise = workerRequestsMap.get(message.requestId);\n if (!promise) {\n return;\n }\n\n promise.reject(new Error(message.error));\n workerRequestsMap.delete(message.requestId);\n };\n\n broadcastChannels.responses.onmessage = (event) => {\n const message = event.data;\n\n if (isWorkerResponseMessage(message)) {\n handleWorkerResponse(message);\n } else if (isWorkerErrorResponseMessage(message)) {\n handleWorkerError(message);\n } else if (isWorkerNotificationMessage(message)) {\n eventTarget.dispatchEvent(message.notificationType, message);\n }\n };\n\n const rpc: AsyncRpc<WorkerRpc> = {\n execute: (query) => queryWorker(\"execute\", [query]),\n getSnapshot: () => queryWorker(\"getSnapshot\", []),\n importData: (data, opts) => queryWorker(\"importData\", [data, opts]),\n pushTabEvents: (request) => queryWorker(\"pushTabEvents\", [request]),\n pullEvents: (params) => queryWorker(\"pullEvents\", [params]),\n postState: () => queryWorker(\"postState\", []),\n goOnline: () => queryWorker(\"goOnline\", []),\n goOffline: () => queryWorker(\"goOffline\", []),\n dropConnection: () => queryWorker(\"dropConnection\", []),\n sync: () => queryWorker(\"sync\", []),\n requestReload: (options) => queryWorker(\"requestReload\", [options]),\n };\n\n const dispose = () => {\n isDisposed = true;\n broadcastChannels.responses.onmessage = null;\n for (const [id, deferred] of workerRequestsMap) {\n deferred.reject(new Error(\"Worker client disposed\"));\n workerRequestsMap.delete(id);\n }\n };\n\n try {\n postWorkerConfig(worker, config);\n // On first tab, the worker may not have its BroadcastChannel listener ready yet,\n // so this request can be silently dropped and timeout. The worker will independently\n // post state at the end of init. For subsequent tabs, this triggers the already-running\n // worker to send its current state.\n rpc.postState().catch(noop);\n\n let { state: workerState, storageGeneration } = await awaitWorkerState(eventTarget);\n\n eventTarget.addEventListener(\"state-changed\", (event) => {\n workerState = event.payload.state;\n storageGeneration = event.payload.storageGeneration;\n });\n\n return {\n ...rpc,\n subscribe: eventTarget.addEventListener,\n getState: () => workerState,\n getStorageGeneration: () => storageGeneration,\n dispose,\n };\n } catch (error) {\n dispose();\n throw error;\n }\n};\n\nfunction awaitWorkerState(eventTarget: TypedEventTarget<NotificationEvents>) {\n const promise = createDeferredPromise<NotificationEvents[\"state-changed\"]>({ timeout: 15_000 });\n\n const subscription = eventTarget.addEventListener(\"state-changed\", (event) => {\n promise.resolve(event.payload);\n subscription.unsubscribe();\n });\n\n return promise.promise;\n}\n\nfunction postWorkerConfig(worker: Worker, config: WorkerConfig) {\n const configMessage: WorkerInitMessage = {\n type: \"init\",\n config,\n };\n worker.postMessage(configMessage);\n}\n","import { validateDbId } from \"./db-id\";\nimport { getOrCreateSQLiteSyncDevtoolsRegistry } from \"./devtools-registry\";\nimport { createExportData, type ImportDataOptions, type SyncedDbExport } from \"./export-import\";\nimport { HLCCounter } from \"./hlc\";\nimport { type Logger, startPerformanceLogger } from \"./logger\";\nimport { createMemoryDb } from \"./memory-db/memory-db\";\nimport { createSQLiteReactiveDb } from \"./memory-db/wasm-reactive-db\";\nimport type { SyncDbMigrator } from \"./migrations/migrator\";\nimport type { SyncDbSchema } from \"./sqlite-crdt/crdt-schema\";\nimport { createCrdtSyncRemoteSource } from \"./sqlite-crdt/crdt-sync-remote-source\";\nimport { createStoredValue } from \"./sqlite-crdt/stored-value\";\nimport { createSyncedDbDatabase } from \"./synced-db-database\";\nimport { acquireLock, generateId } from \"./utils\";\nimport { createWorkerDbClient } from \"./worker-db/db-worker-client\";\nimport { acquireReplicaLock } from \"./worker-db/replica-lock\";\nimport { createBroadcastChannels, syncDbClientLockName } from \"./worker-db/worker-common\";\n\nexport {\n createSyncedDbDatabase,\n type SyncedDbDatabase,\n type SyncedDbSqlExecutor,\n type SyncedDbTransaction,\n type UnsafeSyncedDbSqlExecutor,\n} from \"./synced-db-database\";\n\nexport type SyncedDbOptions<Database, Props = undefined> = {\n dbId: string;\n worker: Worker;\n syncDbSchema: SyncDbSchema<Database>;\n} & (undefined extends Props ? { workerProps?: Props } : { workerProps: Props });\n\nconst defaultLogger: Logger = (type, message, level = \"info\") => {\n const logMessage = `[${type}] ${message}`;\n switch (level) {\n case \"info\":\n console.log(logMessage);\n break;\n case \"warning\":\n console.warn(logMessage);\n break;\n case \"error\":\n console.error(logMessage);\n break;\n case \"trace\":\n console.trace(logMessage);\n break;\n }\n};\n\nexport async function createSyncedDb<Database, Props = undefined>(options: SyncedDbOptions<Database, Props>) {\n validateDbId(options.dbId);\n\n const perf = startPerformanceLogger(defaultLogger);\n\n const instanceId = generateId();\n const tabId = generateId();\n\n const broadcastChannels = createBroadcastChannels(options.dbId);\n\n let releaseClientLock: (() => Promise<void>) | undefined;\n let disposeWorkerClient: (() => void) | undefined;\n let releaseReplicaLock: (() => Promise<void>) | undefined;\n let disposeReactiveDb: (() => void) | undefined;\n let disposeRemoteSource: (() => Promise<void>) | undefined;\n const cleanupCallbacks: (() => void)[] = [];\n let unregisterDevtools: (() => void) | undefined;\n let isDisposed = false;\n const dispose = async () => {\n if (isDisposed) return;\n isDisposed = true;\n\n unregisterDevtools?.();\n for (const cleanup of cleanupCallbacks) {\n cleanup();\n }\n try {\n await disposeRemoteSource?.();\n } finally {\n broadcastChannels.requests.close();\n broadcastChannels.responses.close();\n disposeWorkerClient?.();\n try {\n disposeReactiveDb?.();\n } finally {\n await Promise.all([releaseClientLock?.(), releaseReplicaLock?.()]);\n }\n }\n };\n\n try {\n releaseClientLock = await acquireLock(`${syncDbClientLockName}-${options.dbId}`, { mode: \"shared\" });\n\n const workerClient = await createWorkerDbClient({\n worker: options.worker,\n config: {\n clientId: generateId(),\n dbId: options.dbId,\n props: options.workerProps as never,\n },\n broadcastChannels,\n });\n disposeWorkerClient = () => workerClient.dispose();\n\n const hlcCounter = new HLCCounter(tabId, () => Date.now());\n\n releaseReplicaLock = await acquireReplicaLock({ dbId: options.dbId });\n const workerClientSnapshot = await workerClient.getSnapshot();\n const reactiveDb = await createSQLiteReactiveDb<Database>({\n snapshot: workerClientSnapshot.file,\n logger: defaultLogger,\n });\n disposeReactiveDb = () => reactiveDb.dispose();\n\n const memoryDbMigrator: SyncDbMigrator = {\n currentSchemaVersion: workerClientSnapshot.schemaVersion,\n latestSchemaVersion: workerClientSnapshot.schemaVersion,\n migrateDbToLatest: () => {\n throw new Error(\"Memory DB migrations are not implemented\");\n },\n migrateEvent: (event, targetVersion) => {\n if (event.schema_version === targetVersion) {\n return event;\n }\n throw new Error(\"Memory DB migrations are not implemented\");\n },\n migrateEvents: (events) => events,\n };\n const { crdtStorage } = await createMemoryDb({\n nodeId: tabId,\n migrator: memoryDbMigrator,\n reactiveDb: reactiveDb,\n hlcCounter,\n crdtTables: options.syncDbSchema.tablesConfig,\n syncDbSchema: options.syncDbSchema,\n });\n\n const pullSyncId = createStoredValue({\n initialValue: workerClientSnapshot.syncId,\n });\n const pushSyncId = createStoredValue({\n initialValue: 0,\n });\n const tabRemoteSource = createCrdtSyncRemoteSource({\n bufferSize: 500,\n pullSyncId,\n pushSyncId,\n storage: crdtStorage,\n nodeId: tabId,\n migrator: memoryDbMigrator,\n remoteFactory: ({ onEventsAvailable }) => {\n const subscription = workerClient.subscribe(\"new-event-chunk-applied\", (event) => {\n onEventsAvailable({ newSyncId: event.payload.newSyncId, remoteStateHash: event.payload.stateHash ?? null });\n });\n\n return {\n pullEvents: (request) => workerClient.pullEvents(request),\n pushEvents: (request) => workerClient.pushTabEvents(request),\n disconnect: () => {\n subscription.unsubscribe();\n },\n };\n },\n });\n disposeRemoteSource = () => tabRemoteSource.dispose();\n tabRemoteSource.goOnline();\n\n const reloadRequestedSubscription = workerClient.subscribe(\"reload-requested\", () => {\n globalThis.location?.reload();\n });\n\n cleanupCallbacks.push(reloadRequestedSubscription.unsubscribe);\n\n // A worker elected after this tab's snapshot may have wiped the database the snapshot came from.\n const reloadIfStorageReplaced = (storageGeneration: string) => {\n if (storageGeneration !== workerClientSnapshot.storageGeneration) {\n storageReplacedSubscription.unsubscribe();\n globalThis.location?.reload();\n }\n };\n const storageReplacedSubscription = workerClient.subscribe(\"state-changed\", (event) => {\n reloadIfStorageReplaced(event.payload.storageGeneration);\n });\n cleanupCallbacks.push(storageReplacedSubscription.unsubscribe);\n reloadIfStorageReplaced(workerClient.getStorageGeneration());\n\n const sync = () => {\n workerClient.sync().catch((error) => console.warn(\"Failed to start sync\", error));\n };\n\n // Mobile browsers suspend background pages, and the socket can reconnect or die unnoticed meanwhile.\n const syncWhenVisible = () => {\n if (globalThis.document?.visibilityState === \"visible\") {\n sync();\n }\n };\n // Browsers can keep a socket open long after the network is gone.\n const dropConnection = () => {\n workerClient.dropConnection().catch((error) => console.warn(\"Failed to drop connection\", error));\n };\n cleanupCallbacks.push(() => {\n globalThis.document?.removeEventListener(\"visibilitychange\", syncWhenVisible);\n globalThis.removeEventListener?.(\"online\", sync);\n globalThis.removeEventListener?.(\"offline\", dropConnection);\n });\n globalThis.document?.addEventListener(\"visibilitychange\", syncWhenVisible);\n globalThis.addEventListener?.(\"online\", sync);\n globalThis.addEventListener?.(\"offline\", dropConnection);\n\n perf.logEnd(\"createSyncedDb\", \"initialized\", \"info\");\n\n const exportData = createExportData({\n reactiveDb,\n tablesConfig: options.syncDbSchema.tablesConfig,\n schemaVersion: workerClientSnapshot.schemaVersion,\n });\n const importData = (data: SyncedDbExport, opts?: ImportDataOptions) => workerClient.importData(data, opts);\n\n const syncedDb = {\n db: createSyncedDbDatabase(reactiveDb),\n state: {\n getState: workerClient.getState.bind(workerClient),\n subscribe: (onChange: () => void) => {\n const { unsubscribe } = workerClient.subscribe(\"state-changed\", onChange);\n return unsubscribe;\n },\n goOnline: workerClient.goOnline.bind(workerClient),\n goOffline: workerClient.goOffline.bind(workerClient),\n sync,\n },\n /**\n * Ask the elected worker to broadcast a page reload to all tabs for this dbId.\n *\n * With `clean: true` the worker durably records a reset request epoch before\n * broadcasting, so the worker elected on the next startup initializes with\n * `clearOnInit: true` and wipes the persisted DB. Destructive — use as a\n * recovery path when the durable worker DB may be de-synced.\n *\n * Pending in-memory tab events are not preserved, and the returned promise\n * may never settle in the caller — the page typically unloads first.\n */\n requestReload: async (options: { clean: boolean }) => {\n await workerClient.requestReload(options);\n // Primary path: this tab receives the worker's \"reload-requested\" broadcast\n // like every other tab. Fallback in case the broadcast is missed — in the\n // normal case the page is already unloading and this timeout never fires.\n setTimeout(() => globalThis.location?.reload(), 250);\n },\n subscribe: workerClient.subscribe,\n exportData,\n importData,\n dispose,\n _internal: {\n executeAsync: workerClient.execute.bind(workerClient),\n getMemoryQueryTables: reactiveDb.getTablesUsed.bind(reactiveDb),\n getSharedLiveQueriesSnapshot: reactiveDb.getSharedLiveQueriesSnapshot.bind(reactiveDb),\n crdtTableNames: options.syncDbSchema.tablesConfig.map((table) => table.crdtTableName),\n crdtTablesConfig: options.syncDbSchema.tablesConfig,\n tables: options.syncDbSchema.tables,\n schemaVersion: workerClientSnapshot.schemaVersion,\n migrationVersions: Object.keys(options.syncDbSchema.migrations)\n .map(Number)\n .sort((a, b) => a - b),\n },\n };\n\n unregisterDevtools = getOrCreateSQLiteSyncDevtoolsRegistry().register({\n instanceId,\n dbId: options.dbId,\n createdAt: Date.now(),\n instance: syncedDb,\n });\n\n return syncedDb;\n } catch (error) {\n await dispose();\n throw error;\n }\n}\n\nexport type SyncedDb<Database> = Awaited<ReturnType<typeof createSyncedDb<Database>>>;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/memory-db/wasm-reactive-db.ts","../src/memory-db/memory-db.ts","../src/worker-db/db-worker-client.ts","../src/sync-db.ts"],"sourcesContent":["import { createWasmMemoryDriver } from \"../wasm-driver\";\nimport { SQLiteReactiveDb, type SQLiteReactiveDbOptions } from \"./sqlite-reactive-db\";\n\nexport async function createSQLiteReactiveDb<Database>(opts: Omit<SQLiteReactiveDbOptions, \"driver\">) {\n const driver = await createWasmMemoryDriver();\n return SQLiteReactiveDb.create<Database>({ ...opts, driver });\n}\n","import { xxhash } from \"../hash\";\nimport type { HLCCounter } from \"../hlc\";\nimport type { SyncDbMigrator } from \"../migrations/migrator\";\nimport { applyMemoryDbSchema, type MemoryDbSchema, memoryDbConfig } from \"../migrations/system-schema\";\nimport type { CrdtTableConfig, SyncDbSchema } from \"../sqlite-crdt/crdt-schema\";\nimport { createCrdtStorage } from \"../sqlite-crdt/crdt-storage\";\nimport { makeCrdtTable, registerCrdtIntentDrainer } from \"../sqlite-crdt/make-crdt-table\";\nimport type { StateHashStore } from \"../sqlite-crdt/state-hash\";\nimport type { SQLiteDbWrapper } from \"../sqlite-db-wrapper\";\nimport type { SQLiteReactiveDb } from \"./sqlite-reactive-db\";\n\ntype MemoryDbOptions<Database> = {\n nodeId: string;\n migrator: SyncDbMigrator;\n reactiveDb: SQLiteReactiveDb<Database>;\n hlcCounter: HLCCounter;\n crdtTables: CrdtTableConfig[];\n initializeSchema?: boolean;\n initialSyncId?: number;\n stateHash?: StateHashStore;\n syncDbSchema: Pick<SyncDbSchema, \"tables\" | \"tablesConfig\">;\n};\n\nexport async function createMemoryDb<Database>({\n nodeId,\n migrator,\n reactiveDb: _reactiveDb,\n hlcCounter,\n crdtTables,\n initializeSchema = true,\n initialSyncId,\n stateHash,\n syncDbSchema,\n}: MemoryDbOptions<Database>) {\n await xxhash.ensureLoaded();\n\n const reactiveDb = _reactiveDb as unknown as SQLiteReactiveDb<MemoryDbSchema>;\n const db = reactiveDb.db;\n\n if (initializeSchema) {\n applyMemoryDbSchema(db);\n for (const table of crdtTables) {\n makeCrdtTable({\n db,\n baseTableName: table.baseTableName,\n crdtTableName: table.crdtTableName,\n });\n }\n }\n\n const crdtStorage = createCrdtStorage({\n nodeId,\n initialLocalSyncId: initialSyncId ?? getCurrentSyncId(db),\n hlc: hlcCounter,\n migrator,\n db,\n dbConfig: memoryDbConfig,\n stateHash,\n schema: syncDbSchema,\n });\n\n registerCrdtIntentDrainer({\n reactiveDb,\n storage: crdtStorage,\n });\n\n return {\n crdtStorage,\n };\n}\n\nfunction getCurrentSyncId(db: SQLiteDbWrapper<MemoryDbSchema>) {\n return (\n db.execute<{ syncId: number }>(\"SELECT coalesce(max(sync_id), 0) AS syncId FROM persisted_crdt_events\", {\n loggerLevel: \"system\",\n }).rows[0]?.syncId ?? 0\n );\n}\n","import {\n createDeferredPromise,\n createTypedEventTarget,\n type DeferredPromise,\n noop,\n type TypedEventTarget,\n} from \"../utils\";\nimport type {\n AsyncRpc,\n WorkerBroadcastChannels,\n WorkerConfig,\n WorkerErrorResponseMessage,\n WorkerInitMessage,\n WorkerNotificationEvents,\n WorkerRequestMessage,\n WorkerRequestMethod,\n WorkerResponseMessage,\n WorkerRpc,\n} from \"./worker-common\";\nimport { isWorkerErrorResponseMessage, isWorkerNotificationMessage, isWorkerResponseMessage } from \"./worker-common\";\n\ntype NotificationEvents = WorkerNotificationEvents;\n\nexport const createWorkerDbClient = async ({\n broadcastChannels,\n worker,\n config,\n}: {\n broadcastChannels: WorkerBroadcastChannels;\n worker: Worker;\n config: WorkerConfig;\n}) => {\n const eventTarget = createTypedEventTarget<NotificationEvents>();\n const workerRequestsMap = new Map<string, DeferredPromise<unknown>>();\n let isDisposed = false;\n\n const queryWorker = <TMethod extends WorkerRequestMethod>(\n method: TMethod,\n args: Parameters<WorkerRpc[TMethod]>,\n ): Promise<Awaited<ReturnType<WorkerRpc[TMethod]>>> => {\n if (isDisposed) {\n return Promise.reject(new Error(\"Worker client disposed\"));\n }\n const requestId = crypto.randomUUID();\n const request: WorkerRequestMessage<TMethod> = {\n type: \"request\",\n requestId,\n method,\n args,\n };\n\n try {\n broadcastChannels.requests.postMessage(request);\n } catch (error) {\n return Promise.reject(error);\n }\n\n const promise = createDeferredPromise<unknown>({\n timeout: 30_000,\n onTimeout: () => workerRequestsMap.delete(requestId),\n });\n workerRequestsMap.set(requestId, promise);\n\n return promise.promise as Promise<Awaited<ReturnType<WorkerRpc[TMethod]>>>;\n };\n\n const handleWorkerResponse = (message: WorkerResponseMessage) => {\n const promise = workerRequestsMap.get(message.requestId);\n if (!promise) {\n return;\n }\n\n promise.resolve(message.data);\n workerRequestsMap.delete(message.requestId);\n };\n\n const handleWorkerError = (message: WorkerErrorResponseMessage) => {\n const promise = workerRequestsMap.get(message.requestId);\n if (!promise) {\n return;\n }\n\n promise.reject(new Error(message.error));\n workerRequestsMap.delete(message.requestId);\n };\n\n broadcastChannels.responses.onmessage = (event) => {\n const message = event.data;\n\n if (isWorkerResponseMessage(message)) {\n handleWorkerResponse(message);\n } else if (isWorkerErrorResponseMessage(message)) {\n handleWorkerError(message);\n } else if (isWorkerNotificationMessage(message)) {\n eventTarget.dispatchEvent(message.notificationType, message);\n }\n };\n\n const rpc: AsyncRpc<WorkerRpc> = {\n execute: (query) => queryWorker(\"execute\", [query]),\n getSnapshot: () => queryWorker(\"getSnapshot\", []),\n importData: (data, opts) => queryWorker(\"importData\", [data, opts]),\n pushTabEvents: (request) => queryWorker(\"pushTabEvents\", [request]),\n pullEvents: (params) => queryWorker(\"pullEvents\", [params]),\n postState: () => queryWorker(\"postState\", []),\n goOnline: () => queryWorker(\"goOnline\", []),\n goOffline: () => queryWorker(\"goOffline\", []),\n dropConnection: () => queryWorker(\"dropConnection\", []),\n sync: () => queryWorker(\"sync\", []),\n catchUp: (options) => queryWorker(\"catchUp\", [options]),\n requestReload: (options) => queryWorker(\"requestReload\", [options]),\n };\n\n const dispose = () => {\n isDisposed = true;\n broadcastChannels.responses.onmessage = null;\n for (const [id, deferred] of workerRequestsMap) {\n deferred.reject(new Error(\"Worker client disposed\"));\n workerRequestsMap.delete(id);\n }\n };\n\n try {\n postWorkerConfig(worker, config);\n // On first tab, the worker may not have its BroadcastChannel listener ready yet,\n // so this request can be silently dropped and timeout. The worker will independently\n // post state at the end of init. For subsequent tabs, this triggers the already-running\n // worker to send its current state.\n rpc.postState().catch(noop);\n\n let { state: workerState, storageGeneration } = await awaitWorkerState(eventTarget);\n\n eventTarget.addEventListener(\"state-changed\", (event) => {\n workerState = event.payload.state;\n storageGeneration = event.payload.storageGeneration;\n });\n\n return {\n ...rpc,\n subscribe: eventTarget.addEventListener,\n getState: () => workerState,\n getStorageGeneration: () => storageGeneration,\n dispose,\n };\n } catch (error) {\n dispose();\n throw error;\n }\n};\n\nfunction awaitWorkerState(eventTarget: TypedEventTarget<NotificationEvents>) {\n const promise = createDeferredPromise<NotificationEvents[\"state-changed\"]>({ timeout: 15_000 });\n\n const subscription = eventTarget.addEventListener(\"state-changed\", (event) => {\n promise.resolve(event.payload);\n subscription.unsubscribe();\n });\n\n return promise.promise;\n}\n\nfunction postWorkerConfig(worker: Worker, config: WorkerConfig) {\n const configMessage: WorkerInitMessage = {\n type: \"init\",\n config,\n };\n worker.postMessage(configMessage);\n}\n","import { validateDbId } from \"./db-id\";\nimport { getOrCreateSQLiteSyncDevtoolsRegistry } from \"./devtools-registry\";\nimport { createExportData, type ImportDataOptions, type SyncedDbExport } from \"./export-import\";\nimport { HLCCounter } from \"./hlc\";\nimport { type Logger, startPerformanceLogger } from \"./logger\";\nimport { createMemoryDb } from \"./memory-db/memory-db\";\nimport { createSQLiteReactiveDb } from \"./memory-db/wasm-reactive-db\";\nimport type { SyncDbMigrator } from \"./migrations/migrator\";\nimport type { SyncDbSchema } from \"./sqlite-crdt/crdt-schema\";\nimport {\n type CatchUpOptions,\n type CatchUpResult,\n createCrdtSyncRemoteSource,\n} from \"./sqlite-crdt/crdt-sync-remote-source\";\nimport { createStoredValue } from \"./sqlite-crdt/stored-value\";\nimport { createSyncedDbDatabase } from \"./synced-db-database\";\nimport { acquireLock, generateId } from \"./utils\";\nimport { createWorkerDbClient } from \"./worker-db/db-worker-client\";\nimport { acquireReplicaLock } from \"./worker-db/replica-lock\";\nimport { createBroadcastChannels, syncDbClientLockName } from \"./worker-db/worker-common\";\n\nexport {\n createSyncedDbDatabase,\n type SyncedDbDatabase,\n type SyncedDbSqlExecutor,\n type SyncedDbTransaction,\n type UnsafeSyncedDbSqlExecutor,\n} from \"./synced-db-database\";\n\nexport type SyncedDbOptions<Database, Props = undefined> = {\n dbId: string;\n worker: Worker;\n syncDbSchema: SyncDbSchema<Database>;\n} & (undefined extends Props ? { workerProps?: Props } : { workerProps: Props });\n\nconst defaultLogger: Logger = (type, message, level = \"info\") => {\n const logMessage = `[${type}] ${message}`;\n switch (level) {\n case \"info\":\n console.log(logMessage);\n break;\n case \"warning\":\n console.warn(logMessage);\n break;\n case \"error\":\n console.error(logMessage);\n break;\n case \"trace\":\n console.trace(logMessage);\n break;\n }\n};\n\nexport async function createSyncedDb<Database, Props = undefined>(options: SyncedDbOptions<Database, Props>) {\n validateDbId(options.dbId);\n\n const perf = startPerformanceLogger(defaultLogger);\n\n const instanceId = generateId();\n const tabId = generateId();\n\n const broadcastChannels = createBroadcastChannels(options.dbId);\n\n let releaseClientLock: (() => Promise<void>) | undefined;\n let disposeWorkerClient: (() => void) | undefined;\n let releaseReplicaLock: (() => Promise<void>) | undefined;\n let disposeReactiveDb: (() => void) | undefined;\n let disposeRemoteSource: (() => Promise<void>) | undefined;\n const cleanupCallbacks: (() => void)[] = [];\n let unregisterDevtools: (() => void) | undefined;\n let isDisposed = false;\n const dispose = async () => {\n if (isDisposed) return;\n isDisposed = true;\n\n unregisterDevtools?.();\n for (const cleanup of cleanupCallbacks) {\n cleanup();\n }\n try {\n await disposeRemoteSource?.();\n } finally {\n broadcastChannels.requests.close();\n broadcastChannels.responses.close();\n disposeWorkerClient?.();\n try {\n disposeReactiveDb?.();\n } finally {\n await Promise.all([releaseClientLock?.(), releaseReplicaLock?.()]);\n }\n }\n };\n\n try {\n releaseClientLock = await acquireLock(`${syncDbClientLockName}-${options.dbId}`, { mode: \"shared\" });\n\n const workerClient = await createWorkerDbClient({\n worker: options.worker,\n config: {\n clientId: generateId(),\n dbId: options.dbId,\n props: options.workerProps as never,\n },\n broadcastChannels,\n });\n disposeWorkerClient = () => workerClient.dispose();\n\n const hlcCounter = new HLCCounter(tabId, () => Date.now());\n\n releaseReplicaLock = await acquireReplicaLock({ dbId: options.dbId });\n const workerClientSnapshot = await workerClient.getSnapshot();\n const reactiveDb = await createSQLiteReactiveDb<Database>({\n snapshot: workerClientSnapshot.file,\n logger: defaultLogger,\n });\n disposeReactiveDb = () => reactiveDb.dispose();\n\n const memoryDbMigrator: SyncDbMigrator = {\n currentSchemaVersion: workerClientSnapshot.schemaVersion,\n latestSchemaVersion: workerClientSnapshot.schemaVersion,\n migrateDbToLatest: () => {\n throw new Error(\"Memory DB migrations are not implemented\");\n },\n migrateEvent: (event, targetVersion) => {\n if (event.schema_version === targetVersion) {\n return event;\n }\n throw new Error(\"Memory DB migrations are not implemented\");\n },\n migrateEvents: (events) => events,\n };\n const { crdtStorage } = await createMemoryDb({\n nodeId: tabId,\n migrator: memoryDbMigrator,\n reactiveDb: reactiveDb,\n hlcCounter,\n crdtTables: options.syncDbSchema.tablesConfig,\n syncDbSchema: options.syncDbSchema,\n });\n\n const pullSyncId = createStoredValue({\n initialValue: workerClientSnapshot.syncId,\n });\n const pushSyncId = createStoredValue({\n initialValue: 0,\n });\n const tabRemoteSource = createCrdtSyncRemoteSource({\n bufferSize: 500,\n pullSyncId,\n pushSyncId,\n storage: crdtStorage,\n nodeId: tabId,\n migrator: memoryDbMigrator,\n remoteFactory: ({ onEventsAvailable }) => {\n const subscription = workerClient.subscribe(\"new-event-chunk-applied\", (event) => {\n onEventsAvailable({ newSyncId: event.payload.newSyncId, remoteStateHash: event.payload.stateHash ?? null });\n });\n\n return {\n pullEvents: (request) => workerClient.pullEvents(request),\n pushEvents: (request) => workerClient.pushTabEvents(request),\n disconnect: () => {\n subscription.unsubscribe();\n },\n };\n },\n });\n disposeRemoteSource = () => tabRemoteSource.dispose();\n tabRemoteSource.goOnline();\n\n const reloadRequestedSubscription = workerClient.subscribe(\"reload-requested\", () => {\n globalThis.location?.reload();\n });\n\n cleanupCallbacks.push(reloadRequestedSubscription.unsubscribe);\n\n // A worker elected after this tab's snapshot may have wiped the database the snapshot came from.\n const reloadIfStorageReplaced = (storageGeneration: string) => {\n if (storageGeneration !== workerClientSnapshot.storageGeneration) {\n storageReplacedSubscription.unsubscribe();\n globalThis.location?.reload();\n }\n };\n const storageReplacedSubscription = workerClient.subscribe(\"state-changed\", (event) => {\n reloadIfStorageReplaced(event.payload.storageGeneration);\n });\n cleanupCallbacks.push(storageReplacedSubscription.unsubscribe);\n reloadIfStorageReplaced(workerClient.getStorageGeneration());\n\n const sync = () => {\n workerClient.sync().catch((error) => console.warn(\"Failed to start sync\", error));\n };\n\n // The tab talks to the worker and the worker to the remote, so new remote events reach the tab\n // only after the tab hands its writes to the worker, the worker syncs, and the tab pulls again.\n const catchUp = async ({ timeoutMs = 10_000 }: CatchUpOptions = {}): Promise<CatchUpResult> => {\n const deadline = Date.now() + timeoutMs;\n const timedOut: CatchUpResult = { pulled: false, pushed: false, timedOut: true };\n // The worker may take up to 30 seconds to answer, or never answer while one is being elected.\n const step = async (run: (remaining: number) => Promise<CatchUpResult>) => {\n const remaining = deadline - Date.now();\n if (remaining <= 0) {\n return timedOut;\n }\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<CatchUpResult>((resolve) => {\n timer = setTimeout(() => resolve(timedOut), remaining);\n });\n try {\n return await Promise.race([run(remaining), timeout]);\n } finally {\n clearTimeout(timer);\n }\n };\n\n const toWorker = await step((remaining) => tabRemoteSource.catchUp({ timeoutMs: remaining }));\n const remote = await step((remaining) =>\n workerClient.catchUp({ timeoutMs: Math.min(remaining, 25_000) }).catch((error) => {\n console.warn(\"Failed to catch up with the remote\", error);\n return { pulled: false, pushed: false, timedOut: false };\n }),\n );\n const fromWorker = await step((remaining) => tabRemoteSource.catchUp({ timeoutMs: remaining }));\n\n return {\n pulled: remote.pulled && fromWorker.pulled,\n pushed: toWorker.pushed && remote.pushed,\n timedOut: toWorker.timedOut || remote.timedOut || fromWorker.timedOut,\n };\n };\n\n // Mobile browsers suspend background pages, and the socket can reconnect or die unnoticed meanwhile.\n const syncWhenVisible = () => {\n if (globalThis.document?.visibilityState === \"visible\") {\n sync();\n }\n };\n // Browsers can keep a socket open long after the network is gone.\n const dropConnection = () => {\n workerClient.dropConnection().catch((error) => console.warn(\"Failed to drop connection\", error));\n };\n cleanupCallbacks.push(() => {\n globalThis.document?.removeEventListener(\"visibilitychange\", syncWhenVisible);\n globalThis.removeEventListener?.(\"online\", sync);\n globalThis.removeEventListener?.(\"offline\", dropConnection);\n });\n globalThis.document?.addEventListener(\"visibilitychange\", syncWhenVisible);\n globalThis.addEventListener?.(\"online\", sync);\n globalThis.addEventListener?.(\"offline\", dropConnection);\n\n perf.logEnd(\"createSyncedDb\", \"initialized\", \"info\");\n\n const exportData = createExportData({\n reactiveDb,\n tablesConfig: options.syncDbSchema.tablesConfig,\n schemaVersion: workerClientSnapshot.schemaVersion,\n });\n const importData = (data: SyncedDbExport, opts?: ImportDataOptions) => workerClient.importData(data, opts);\n\n const syncedDb = {\n db: createSyncedDbDatabase(reactiveDb),\n state: {\n getState: workerClient.getState.bind(workerClient),\n subscribe: (onChange: () => void) => {\n const { unsubscribe } = workerClient.subscribe(\"state-changed\", onChange);\n return unsubscribe;\n },\n goOnline: workerClient.goOnline.bind(workerClient),\n goOffline: workerClient.goOffline.bind(workerClient),\n sync,\n /**\n * Pulls what the remote has now and pushes pending local events, and resolves once that\n * is done or `timeoutMs` (10 seconds by default) runs out. Best effort: it never rejects,\n * does not wait for other clients to stop writing, and the result tells how far it got.\n */\n catchUp,\n },\n /**\n * Ask the elected worker to broadcast a page reload to all tabs for this dbId.\n *\n * With `clean: true` the worker durably records a reset request epoch before\n * broadcasting, so the worker elected on the next startup initializes with\n * `clearOnInit: true` and wipes the persisted DB. Destructive — use as a\n * recovery path when the durable worker DB may be de-synced.\n *\n * Pending in-memory tab events are not preserved, and the returned promise\n * may never settle in the caller — the page typically unloads first.\n */\n requestReload: async (options: { clean: boolean }) => {\n await workerClient.requestReload(options);\n // Primary path: this tab receives the worker's \"reload-requested\" broadcast\n // like every other tab. Fallback in case the broadcast is missed — in the\n // normal case the page is already unloading and this timeout never fires.\n setTimeout(() => globalThis.location?.reload(), 250);\n },\n subscribe: workerClient.subscribe,\n exportData,\n importData,\n dispose,\n _internal: {\n executeAsync: workerClient.execute.bind(workerClient),\n getMemoryQueryTables: reactiveDb.getTablesUsed.bind(reactiveDb),\n getSharedLiveQueriesSnapshot: reactiveDb.getSharedLiveQueriesSnapshot.bind(reactiveDb),\n crdtTableNames: options.syncDbSchema.tablesConfig.map((table) => table.crdtTableName),\n crdtTablesConfig: options.syncDbSchema.tablesConfig,\n tables: options.syncDbSchema.tables,\n schemaVersion: workerClientSnapshot.schemaVersion,\n migrationVersions: Object.keys(options.syncDbSchema.migrations)\n .map(Number)\n .sort((a, b) => a - b),\n },\n };\n\n unregisterDevtools = getOrCreateSQLiteSyncDevtoolsRegistry().register({\n instanceId,\n dbId: options.dbId,\n createdAt: Date.now(),\n instance: syncedDb,\n });\n\n return syncedDb;\n } catch (error) {\n await dispose();\n throw error;\n }\n}\n\nexport type SyncedDb<Database> = Awaited<ReturnType<typeof createSyncedDb<Database>>>;\n"],"mappings":";;;;;;;;;;;AAGA,eAAsB,uBAAiC,MAA+C;CACpG,MAAM,SAAS,MAAM,uBAAuB;CAC5C,OAAO,iBAAiB,OAAiB;EAAE,GAAG;EAAM;CAAO,CAAC;AAC9D;;;ACiBA,eAAsB,eAAyB,EAC7C,QACA,UACA,YAAY,aACZ,YACA,YACA,mBAAmB,MACnB,eACA,WACA,gBAC4B;CAC5B,MAAM,OAAO,aAAa;CAE1B,MAAM,aAAa;CACnB,MAAM,KAAK,WAAW;CAEtB,IAAI,kBAAkB;EACpB,oBAAoB,EAAE;EACtB,KAAK,MAAM,SAAS,YAClB,cAAc;GACZ;GACA,eAAe,MAAM;GACrB,eAAe,MAAM;EACvB,CAAC;CAEL;CAEA,MAAM,cAAc,kBAAkB;EACpC;EACA,oBAAoB,iBAAiB,iBAAiB,EAAE;EACxD,KAAK;EACL;EACA;EACA,UAAU;EACV;EACA,QAAQ;CACV,CAAC;CAED,0BAA0B;EACxB;EACA,SAAS;CACX,CAAC;CAED,OAAO,EACL,YACF;AACF;AAEA,SAAS,iBAAiB,IAAqC;CAC7D,OACE,GAAG,QAA4B,yEAAyE,EACtG,aAAa,SACf,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,UAAU;AAE1B;;;ACtDA,MAAa,uBAAuB,OAAO,EACzC,mBACA,QACA,aAKI;CACJ,MAAM,cAAc,uBAA2C;CAC/D,MAAM,oCAAoB,IAAI,IAAsC;CACpE,IAAI,aAAa;CAEjB,MAAM,eACJ,QACA,SACqD;EACrD,IAAI,YACF,OAAO,QAAQ,uBAAO,IAAI,MAAM,wBAAwB,CAAC;EAE3D,MAAM,YAAY,OAAO,WAAW;EACpC,MAAM,UAAyC;GAC7C,MAAM;GACN;GACA;GACA;EACF;EAEA,IAAI;GACF,kBAAkB,SAAS,YAAY,OAAO;EAChD,SAAS,OAAO;GACd,OAAO,QAAQ,OAAO,KAAK;EAC7B;EAEA,MAAM,UAAU,sBAA+B;GAC7C,SAAS;GACT,iBAAiB,kBAAkB,OAAO,SAAS;EACrD,CAAC;EACD,kBAAkB,IAAI,WAAW,OAAO;EAExC,OAAO,QAAQ;CACjB;CAEA,MAAM,wBAAwB,YAAmC;EAC/D,MAAM,UAAU,kBAAkB,IAAI,QAAQ,SAAS;EACvD,IAAI,CAAC,SACH;EAGF,QAAQ,QAAQ,QAAQ,IAAI;EAC5B,kBAAkB,OAAO,QAAQ,SAAS;CAC5C;CAEA,MAAM,qBAAqB,YAAwC;EACjE,MAAM,UAAU,kBAAkB,IAAI,QAAQ,SAAS;EACvD,IAAI,CAAC,SACH;EAGF,QAAQ,OAAO,IAAI,MAAM,QAAQ,KAAK,CAAC;EACvC,kBAAkB,OAAO,QAAQ,SAAS;CAC5C;CAEA,kBAAkB,UAAU,aAAa,UAAU;EACjD,MAAM,UAAU,MAAM;EAEtB,IAAI,wBAAwB,OAAO,GACjC,qBAAqB,OAAO;OACvB,IAAI,6BAA6B,OAAO,GAC7C,kBAAkB,OAAO;OACpB,IAAI,4BAA4B,OAAO,GAC5C,YAAY,cAAc,QAAQ,kBAAkB,OAAO;CAE/D;CAEA,MAAM,MAA2B;EAC/B,UAAU,UAAU,YAAY,WAAW,CAAC,KAAK,CAAC;EAClD,mBAAmB,YAAY,eAAe,CAAC,CAAC;EAChD,aAAa,MAAM,SAAS,YAAY,cAAc,CAAC,MAAM,IAAI,CAAC;EAClE,gBAAgB,YAAY,YAAY,iBAAiB,CAAC,OAAO,CAAC;EAClE,aAAa,WAAW,YAAY,cAAc,CAAC,MAAM,CAAC;EAC1D,iBAAiB,YAAY,aAAa,CAAC,CAAC;EAC5C,gBAAgB,YAAY,YAAY,CAAC,CAAC;EAC1C,iBAAiB,YAAY,aAAa,CAAC,CAAC;EAC5C,sBAAsB,YAAY,kBAAkB,CAAC,CAAC;EACtD,YAAY,YAAY,QAAQ,CAAC,CAAC;EAClC,UAAU,YAAY,YAAY,WAAW,CAAC,OAAO,CAAC;EACtD,gBAAgB,YAAY,YAAY,iBAAiB,CAAC,OAAO,CAAC;CACpE;CAEA,MAAM,gBAAgB;EACpB,aAAa;EACb,kBAAkB,UAAU,YAAY;EACxC,KAAK,MAAM,CAAC,IAAI,aAAa,mBAAmB;GAC9C,SAAS,uBAAO,IAAI,MAAM,wBAAwB,CAAC;GACnD,kBAAkB,OAAO,EAAE;EAC7B;CACF;CAEA,IAAI;EACF,iBAAiB,QAAQ,MAAM;EAK/B,IAAI,UAAU,CAAC,CAAC,MAAM,IAAI;EAE1B,IAAI,EAAE,OAAO,aAAa,sBAAsB,MAAM,iBAAiB,WAAW;EAElF,YAAY,iBAAiB,kBAAkB,UAAU;GACvD,cAAc,MAAM,QAAQ;GAC5B,oBAAoB,MAAM,QAAQ;EACpC,CAAC;EAED,OAAO;GACL,GAAG;GACH,WAAW,YAAY;GACvB,gBAAgB;GAChB,4BAA4B;GAC5B;EACF;CACF,SAAS,OAAO;EACd,QAAQ;EACR,MAAM;CACR;AACF;AAEA,SAAS,iBAAiB,aAAmD;CAC3E,MAAM,UAAU,sBAA2D,EAAE,SAAS,KAAO,CAAC;CAE9F,MAAM,eAAe,YAAY,iBAAiB,kBAAkB,UAAU;EAC5E,QAAQ,QAAQ,MAAM,OAAO;EAC7B,aAAa,YAAY;CAC3B,CAAC;CAED,OAAO,QAAQ;AACjB;AAEA,SAAS,iBAAiB,QAAgB,QAAsB;CAC9D,MAAM,gBAAmC;EACvC,MAAM;EACN;CACF;CACA,OAAO,YAAY,aAAa;AAClC;;;ACpIA,MAAM,iBAAyB,MAAM,SAAS,QAAQ,WAAW;CAC/D,MAAM,aAAa,IAAI,KAAK,IAAI;CAChC,QAAQ,OAAR;EACE,KAAK;GACH,QAAQ,IAAI,UAAU;GACtB;EACF,KAAK;GACH,QAAQ,KAAK,UAAU;GACvB;EACF,KAAK;GACH,QAAQ,MAAM,UAAU;GACxB;EACF,KAAK,SACH,QAAQ,MAAM,UAAU;CAE5B;AACF;AAEA,eAAsB,eAA4C,SAA2C;CAC3G,aAAa,QAAQ,IAAI;CAEzB,MAAM,OAAO,uBAAuB,aAAa;CAEjD,MAAM,aAAa,WAAW;CAC9B,MAAM,QAAQ,WAAW;CAEzB,MAAM,oBAAoB,wBAAwB,QAAQ,IAAI;CAE9D,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,MAAM,mBAAmC,CAAC;CAC1C,IAAI;CACJ,IAAI,aAAa;CACjB,MAAM,UAAU,YAAY;EAC1B,IAAI,YAAY;EAChB,aAAa;EAEb,qBAAqB;EACrB,KAAK,MAAM,WAAW,kBACpB,QAAQ;EAEV,IAAI;GACF,MAAM,sBAAsB;EAC9B,UAAU;GACR,kBAAkB,SAAS,MAAM;GACjC,kBAAkB,UAAU,MAAM;GAClC,sBAAsB;GACtB,IAAI;IACF,oBAAoB;GACtB,UAAU;IACR,MAAM,QAAQ,IAAI,CAAC,oBAAoB,GAAG,qBAAqB,CAAC,CAAC;GACnE;EACF;CACF;CAEA,IAAI;EACF,oBAAoB,MAAM,YAAY,GAAG,qBAAqB,GAAG,QAAQ,QAAQ,EAAE,MAAM,SAAS,CAAC;EAEnG,MAAM,eAAe,MAAM,qBAAqB;GAC9C,QAAQ,QAAQ;GAChB,QAAQ;IACN,UAAU,WAAW;IACrB,MAAM,QAAQ;IACd,OAAO,QAAQ;GACjB;GACA;EACF,CAAC;EACD,4BAA4B,aAAa,QAAQ;EAEjD,MAAM,aAAa,IAAI,WAAW,aAAa,KAAK,IAAI,CAAC;EAEzD,qBAAqB,MAAM,mBAAmB,EAAE,MAAM,QAAQ,KAAK,CAAC;EACpE,MAAM,uBAAuB,MAAM,aAAa,YAAY;EAC5D,MAAM,aAAa,MAAM,uBAAiC;GACxD,UAAU,qBAAqB;GAC/B,QAAQ;EACV,CAAC;EACD,0BAA0B,WAAW,QAAQ;EAE7C,MAAM,mBAAmC;GACvC,sBAAsB,qBAAqB;GAC3C,qBAAqB,qBAAqB;GAC1C,yBAAyB;IACvB,MAAM,IAAI,MAAM,0CAA0C;GAC5D;GACA,eAAe,OAAO,kBAAkB;IACtC,IAAI,MAAM,mBAAmB,eAC3B,OAAO;IAET,MAAM,IAAI,MAAM,0CAA0C;GAC5D;GACA,gBAAgB,WAAW;EAC7B;EACA,MAAM,EAAE,gBAAgB,MAAM,eAAe;GAC3C,QAAQ;GACR,UAAU;GACE;GACZ;GACA,YAAY,QAAQ,aAAa;GACjC,cAAc,QAAQ;EACxB,CAAC;EAED,MAAM,aAAa,kBAAkB,EACnC,cAAc,qBAAqB,OACrC,CAAC;EACD,MAAM,aAAa,kBAAkB,EACnC,cAAc,EAChB,CAAC;EACD,MAAM,kBAAkB,2BAA2B;GACjD,YAAY;GACZ;GACA;GACA,SAAS;GACT,QAAQ;GACR,UAAU;GACV,gBAAgB,EAAE,wBAAwB;IACxC,MAAM,eAAe,aAAa,UAAU,4BAA4B,UAAU;KAChF,kBAAkB;MAAE,WAAW,MAAM,QAAQ;MAAW,iBAAiB,MAAM,QAAQ,aAAa;KAAK,CAAC;IAC5G,CAAC;IAED,OAAO;KACL,aAAa,YAAY,aAAa,WAAW,OAAO;KACxD,aAAa,YAAY,aAAa,cAAc,OAAO;KAC3D,kBAAkB;MAChB,aAAa,YAAY;KAC3B;IACF;GACF;EACF,CAAC;EACD,4BAA4B,gBAAgB,QAAQ;EACpD,gBAAgB,SAAS;EAEzB,MAAM,8BAA8B,aAAa,UAAU,0BAA0B;GACnF,WAAW,UAAU,OAAO;EAC9B,CAAC;EAED,iBAAiB,KAAK,4BAA4B,WAAW;EAG7D,MAAM,2BAA2B,sBAA8B;GAC7D,IAAI,sBAAsB,qBAAqB,mBAAmB;IAChE,4BAA4B,YAAY;IACxC,WAAW,UAAU,OAAO;GAC9B;EACF;EACA,MAAM,8BAA8B,aAAa,UAAU,kBAAkB,UAAU;GACrF,wBAAwB,MAAM,QAAQ,iBAAiB;EACzD,CAAC;EACD,iBAAiB,KAAK,4BAA4B,WAAW;EAC7D,wBAAwB,aAAa,qBAAqB,CAAC;EAE3D,MAAM,aAAa;GACjB,aAAa,KAAK,CAAC,CAAC,OAAO,UAAU,QAAQ,KAAK,wBAAwB,KAAK,CAAC;EAClF;EAIA,MAAM,UAAU,OAAO,EAAE,YAAY,QAA2B,CAAC,MAA8B;GAC7F,MAAM,WAAW,KAAK,IAAI,IAAI;GAC9B,MAAM,WAA0B;IAAE,QAAQ;IAAO,QAAQ;IAAO,UAAU;GAAK;GAE/E,MAAM,OAAO,OAAO,QAAuD;IACzE,MAAM,YAAY,WAAW,KAAK,IAAI;IACtC,IAAI,aAAa,GACf,OAAO;IAET,IAAI;IACJ,MAAM,UAAU,IAAI,SAAwB,YAAY;KACtD,QAAQ,iBAAiB,QAAQ,QAAQ,GAAG,SAAS;IACvD,CAAC;IACD,IAAI;KACF,OAAO,MAAM,QAAQ,KAAK,CAAC,IAAI,SAAS,GAAG,OAAO,CAAC;IACrD,UAAU;KACR,aAAa,KAAK;IACpB;GACF;GAEA,MAAM,WAAW,MAAM,MAAM,cAAc,gBAAgB,QAAQ,EAAE,WAAW,UAAU,CAAC,CAAC;GAC5F,MAAM,SAAS,MAAM,MAAM,cACzB,aAAa,QAAQ,EAAE,WAAW,KAAK,IAAI,WAAW,IAAM,EAAE,CAAC,CAAC,CAAC,OAAO,UAAU;IAChF,QAAQ,KAAK,sCAAsC,KAAK;IACxD,OAAO;KAAE,QAAQ;KAAO,QAAQ;KAAO,UAAU;IAAM;GACzD,CAAC,CACH;GACA,MAAM,aAAa,MAAM,MAAM,cAAc,gBAAgB,QAAQ,EAAE,WAAW,UAAU,CAAC,CAAC;GAE9F,OAAO;IACL,QAAQ,OAAO,UAAU,WAAW;IACpC,QAAQ,SAAS,UAAU,OAAO;IAClC,UAAU,SAAS,YAAY,OAAO,YAAY,WAAW;GAC/D;EACF;EAGA,MAAM,wBAAwB;GAC5B,IAAI,WAAW,UAAU,oBAAoB,WAC3C,KAAK;EAET;EAEA,MAAM,uBAAuB;GAC3B,aAAa,eAAe,CAAC,CAAC,OAAO,UAAU,QAAQ,KAAK,6BAA6B,KAAK,CAAC;EACjG;EACA,iBAAiB,WAAW;GAC1B,WAAW,UAAU,oBAAoB,oBAAoB,eAAe;GAC5E,WAAW,sBAAsB,UAAU,IAAI;GAC/C,WAAW,sBAAsB,WAAW,cAAc;EAC5D,CAAC;EACD,WAAW,UAAU,iBAAiB,oBAAoB,eAAe;EACzE,WAAW,mBAAmB,UAAU,IAAI;EAC5C,WAAW,mBAAmB,WAAW,cAAc;EAEvD,KAAK,OAAO,kBAAkB,eAAe,MAAM;EAEnD,MAAM,aAAa,iBAAiB;GAClC;GACA,cAAc,QAAQ,aAAa;GACnC,eAAe,qBAAqB;EACtC,CAAC;EACD,MAAM,cAAc,MAAsB,SAA6B,aAAa,WAAW,MAAM,IAAI;EAEzG,MAAM,WAAW;GACf,IAAI,uBAAuB,UAAU;GACrC,OAAO;IACL,UAAU,aAAa,SAAS,KAAK,YAAY;IACjD,YAAY,aAAyB;KACnC,MAAM,EAAE,gBAAgB,aAAa,UAAU,iBAAiB,QAAQ;KACxE,OAAO;IACT;IACA,UAAU,aAAa,SAAS,KAAK,YAAY;IACjD,WAAW,aAAa,UAAU,KAAK,YAAY;IACnD;;;;;;IAMA;GACF;;;;;;;;;;;;GAYA,eAAe,OAAO,YAAgC;IACpD,MAAM,aAAa,cAAc,OAAO;IAIxC,iBAAiB,WAAW,UAAU,OAAO,GAAG,GAAG;GACrD;GACA,WAAW,aAAa;GACxB;GACA;GACA;GACA,WAAW;IACT,cAAc,aAAa,QAAQ,KAAK,YAAY;IACpD,sBAAsB,WAAW,cAAc,KAAK,UAAU;IAC9D,8BAA8B,WAAW,6BAA6B,KAAK,UAAU;IACrF,gBAAgB,QAAQ,aAAa,aAAa,KAAK,UAAU,MAAM,aAAa;IACpF,kBAAkB,QAAQ,aAAa;IACvC,QAAQ,QAAQ,aAAa;IAC7B,eAAe,qBAAqB;IACpC,mBAAmB,OAAO,KAAK,QAAQ,aAAa,UAAU,CAAC,CAC5D,IAAI,MAAM,CAAC,CACX,MAAM,GAAG,MAAM,IAAI,CAAC;GACzB;EACF;EAEA,qBAAqB,sCAAsC,CAAC,CAAC,SAAS;GACpE;GACA,MAAM,QAAQ;GACd,WAAW,KAAK,IAAI;GACpB,UAAU;EACZ,CAAC;EAED,OAAO;CACT,SAAS,OAAO;EACd,MAAM,QAAQ;EACd,MAAM;CACR;AACF"}
|
package/dist/index.native.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as
|
|
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, type ReadonlyTable, type ResetRequest, type ResetStore, SQLiteDbWrapper, SQLiteReactiveDb, type SQLiteTransactionWrapper, type SchemaVerificationIssue, type SharedLiveQuery, type SharedLiveQuerySnapshot, type SnapshotOptions, type SqliteDriver, type SqliteDriverHooks, type SqliteDriverRows, type SqliteDriverStatement, type SqliteDriverValue, 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, createTypedEventTarget, defineSyncSchema, deserializeHLC, dummyKysely, formatSchemaVerificationIssues, generateId, introspectDb, isNoOpCrdtEventPayload, jsonSafeParse, makeCrdtTable, parametersAreEqual, quoteId, serializeHLC, startPerformanceLogger, t, tryCatch, tryCatchAsync, validateNewCrdtEvent, verifySyncSchemaWithDriver, xxhash };
|
|
1
|
+
import { $ as SharedLiveQuery, $t as LogLevel, A as WorkerConfig, An as MigratableEvent, At as jsonSafeParse, B as SchemaVerificationIssue, Bn as CrdtEventStatus, C as CrdtSyncRemoteSource, Cn as SqliteStorageType, Ct as DistributiveOmit, D as EventsPushResponse, Dn as TableOptions, Dt as createDeferredPromise, E as EventsPushRequest, En as TableColumns, Et as TypedEventTarget, F as SnapshotOptions, Fn as createMigrator, G as validateNewCrdtEvent, Gn as isNoOpCrdtEventPayload, Gt as SQLiteDbWrapper, H as verifySyncSchemaWithDriver, Hn as CrdtUpdateLogItem, I as createCrdtStorageMutator, In as StoredValue, It as createKvStoreTableQuery, J as defineSyncSchema, Jt as SqliteDriver, K as DefineSyncSchemaConfig, Kn as dummyKysely, Kt as SQLiteTransactionWrapper, L as PendingCrdtEvent, Ln as createStoredValue, Lt as createSQLiteKvStore, M as WorkerState, Mn as MigrationsDb, Mt as tryCatch, N as createCrdtSyncProducer, Nn as SyncDbMigrator, Nt as tryCatchAsync, O as createCrdtSyncRemoteSource, On as WriteOrigin, Ot as createTypedEventTarget, P as CrdtStorageMutator, Pn as createMigrations, Pt as KvStoreItem, Q as SQLiteReactiveDb, Qt as SqliteDriverValue, R as createCrdtApplyFunction, Rn as CRDT_EVENT_NO_OP_PAYLOAD, Rt as ExecuteParams, S as CatchUpResult, Sn as PayloadValidationResult, St as DeferredPromise, T as EventsPullRequest, Tn as TableBuilder, Tt as TypedEvent, U as CrdtEventValidationError, Un as CrdtUpdateLogPayload, Ut as PreparedStatement, V as formatSchemaVerificationIssues, Vn as CrdtEventType, Vt as KyselyQueryFactory, W as NewCrdtEventValidationResult, Wn as PersistedCrdtEvent, Wt as QueryBuilderOutput, Xt as SqliteDriverRows, Y as AdmitClientEventsResult, Yt as SqliteDriverHooks, Z as admitClientEvents, Zt as SqliteDriverStatement, _n as ColumnBuilder, _t as applyMemoryDbSchema, an as introspectDb, at as SyncedDbExport, b as makeCrdtTable, bn as ExportImportMode, c as ResetStore, cn as compareHLC, dn as CrdtTableConfig, dt as OwnCrdtEvent, en as Logger, et as SharedLiveQuerySnapshot, f as SyncedDbDatabase, fn as ReadonlyTable, ft as OwnCrdtSnapshot, gn as AnyTableBuilder, gt as SystemMigrationContext, h as UnsafeSyncedDbSqlExecutor, hn as AnyColumnBuilder, ht as SystemMigration, in as TableMetadata, it as ImportDataResult, j as WorkerNotificationMessage, jn as Migrations, jt as quoteId, kn as t, kt as generateId, l as SyncedDb, ln as deserializeHLC, lt as CrdtStorage, m as SyncedDbTransaction, mn as AiAccess, mt as SystemDbConfig, nn as ColumnMetadata, nt as xxhash, on as HLC, ot as createExportData, p as SyncedDbSqlExecutor, pn as SyncDbSchema, pt as createCrdtStorage, q as DefinedSyncSchema, rn as DatabaseIntrospection, rt as ImportDataOptions, s as ResetRequest, sn as HLCCounter, st as createImportData, tn as startPerformanceLogger, tt as parametersAreEqual, u as SyncedDbOptions, un as serializeHLC, vn as ColumnKind, vt as applyWorkerDbSchema, wn as SyncSchemaTables, wt as TypedBroadcastChannel, x as CatchUpOptions, xn as InferRow, yn as ColumnMeta, z as createSQLiteCrdtApplyFunction, zn as CrdtEventOrigin, zt as ExecuteResult } from "./index-C1E8xMH1.js";
|
|
2
|
+
export { type AdmitClientEventsResult, type AiAccess, type AnyColumnBuilder, type AnyTableBuilder, CRDT_EVENT_NO_OP_PAYLOAD, type CatchUpOptions, type CatchUpResult, 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, type ReadonlyTable, type ResetRequest, type ResetStore, SQLiteDbWrapper, SQLiteReactiveDb, type SQLiteTransactionWrapper, type SchemaVerificationIssue, type SharedLiveQuery, type SharedLiveQuerySnapshot, type SnapshotOptions, type SqliteDriver, type SqliteDriverHooks, type SqliteDriverRows, type SqliteDriverStatement, type SqliteDriverValue, 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, createTypedEventTarget, defineSyncSchema, deserializeHLC, dummyKysely, formatSchemaVerificationIssues, generateId, introspectDb, isNoOpCrdtEventPayload, jsonSafeParse, makeCrdtTable, parametersAreEqual, quoteId, serializeHLC, startPerformanceLogger, t, tryCatch, tryCatchAsync, validateNewCrdtEvent, verifySyncSchemaWithDriver, xxhash };
|
package/dist/index.native.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { b as introspectDb, g as SQLiteDbWrapper, h as createStoredValue, i as applyWorkerDbSchema, m as createSQLiteKvStore, p as createKvStoreTableQuery, r as applyMemoryDbSchema, x as dummyKysely, y as startPerformanceLogger } from "./system-schema-B8hbFl7o.js";
|
|
2
2
|
import { 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-D6Yf61Ex.js";
|
|
3
|
-
import { a as formatSchemaVerificationIssues, c as createMigrator, i as createSQLiteCrdtApplyFunction, l as createExportData, n as createCrdtStorage, o as verifySyncSchemaWithDriver, r as createCrdtApplyFunction, s as createMigrations, t as createCrdtSyncProducer, u as createImportData } from "./crdt-sync-producer-
|
|
4
|
-
import { c as deserializeHLC, i as validateNewCrdtEvent, l as serializeHLC, o as HLCCounter, r as CrdtEventValidationError, s as compareHLC, t as createCrdtSyncRemoteSource, u as xxhash } from "./crdt-sync-remote-source-
|
|
3
|
+
import { a as formatSchemaVerificationIssues, c as createMigrator, i as createSQLiteCrdtApplyFunction, l as createExportData, n as createCrdtStorage, o as verifySyncSchemaWithDriver, r as createCrdtApplyFunction, s as createMigrations, t as createCrdtSyncProducer, u as createImportData } from "./crdt-sync-producer-CUXiu4X3.js";
|
|
4
|
+
import { c as deserializeHLC, i as validateNewCrdtEvent, l as serializeHLC, o as HLCCounter, r as CrdtEventValidationError, s as compareHLC, t as createCrdtSyncRemoteSource, u as xxhash } from "./crdt-sync-remote-source-CH2bsr-x.js";
|
|
5
5
|
import { n as parametersAreEqual, t as SQLiteReactiveDb } from "./sqlite-reactive-db-DLTvpGzO.js";
|
|
6
6
|
import { t as admitClientEvents } from "./admit-client-events-BDrJw4SK.js";
|
|
7
|
-
import { a as defineSyncSchema, i as t, n as ColumnBuilder, r as TableBuilder, t as createCrdtStorageMutator } from "./index.common-
|
|
7
|
+
import { a as defineSyncSchema, i as t, n as ColumnBuilder, r as TableBuilder, t as createCrdtStorageMutator } from "./index.common-c-Je9hVa.js";
|
|
8
8
|
import { a as makeCrdtTable } from "./make-crdt-table-Cu8WhRBk.js";
|
|
9
9
|
export { CRDT_EVENT_NO_OP_PAYLOAD, ColumnBuilder, CrdtEventValidationError, HLCCounter, SQLiteDbWrapper, SQLiteReactiveDb, TableBuilder, TypedBroadcastChannel, TypedEvent, admitClientEvents, applyMemoryDbSchema, applyWorkerDbSchema, compareHLC, createCrdtApplyFunction, createCrdtStorage, createCrdtStorageMutator, createCrdtSyncProducer, createCrdtSyncRemoteSource, createDeferredPromise, createExportData, createImportData, createKvStoreTableQuery, createMigrations, createMigrator, createSQLiteCrdtApplyFunction, createSQLiteKvStore, createStoredValue, createTypedEventTarget, defineSyncSchema, deserializeHLC, dummyKysely, formatSchemaVerificationIssues, generateId, introspectDb, isNoOpCrdtEventPayload, jsonSafeParse, makeCrdtTable, parametersAreEqual, quoteId, serializeHLC, startPerformanceLogger, t, tryCatch, tryCatchAsync, validateNewCrdtEvent, verifySyncSchemaWithDriver, xxhash };
|
package/dist/internal.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Bt as
|
|
1
|
+
import { Bt as InternalSQLiteWrapper, Ft as STATE_HASH_KV_KEY, Ht as KyselyStatementFactory, _ as crdtViewColumnsFromTable, bt as createSystemDbConfig, ct as CrdtChangeIntent, g as CRDT_CHANGE_INTENTS_TABLE, qt as compileKyselyStatement, v as createCrdtViewStatements, xt as runSystemMigrations, y as drainCrdtChangeIntents, yt as baseSystemMigrations } from "./index-C1E8xMH1.js";
|
|
2
2
|
export { CRDT_CHANGE_INTENTS_TABLE, type CrdtChangeIntent, type InternalSQLiteWrapper, type KyselyStatementFactory, STATE_HASH_KV_KEY, baseSystemMigrations, compileKyselyStatement, crdtViewColumnsFromTable, createCrdtViewStatements, createSystemDbConfig, drainCrdtChangeIntents, runSystemMigrations };
|
package/dist/local.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as createWsRemoteSource } from "./ws-remote-source-
|
|
1
|
+
import { D as EventsPushResponse, E as EventsPushRequest, Jt as SqliteDriver, Qt as SqliteDriverValue, S as CatchUpResult, T as EventsPullRequest, Xt as SqliteDriverRows, Yt as SqliteDriverHooks, Zt as SqliteDriverStatement, en as Logger, l as SyncedDb, pn as SyncDbSchema, w as CreateRemoteSourceFactory, x as CatchUpOptions } from "./index-C1E8xMH1.js";
|
|
2
|
+
import { t as createWsRemoteSource } from "./ws-remote-source-Bk6NYwML.js";
|
|
3
3
|
//#region src/local/local-synced-db.d.ts
|
|
4
4
|
type LocalSyncedDbOptions<Database> = {
|
|
5
5
|
dbId: string;
|
|
@@ -23,9 +23,9 @@ type LocalSyncedDbOptions<Database> = {
|
|
|
23
23
|
*/
|
|
24
24
|
verifySchemaDriver?: () => SqliteDriver | Promise<SqliteDriver>;
|
|
25
25
|
/**
|
|
26
|
-
* Runs event-log garbage collection on startup.
|
|
27
|
-
* latest event rows and never removes pending events or local
|
|
28
|
-
* been pushed to the remote.
|
|
26
|
+
* Runs event-log garbage collection on startup. Enabled by default; set `false` to
|
|
27
|
+
* disable. GC keeps the latest event rows and never removes pending events or local
|
|
28
|
+
* rows that have not been pushed to the remote.
|
|
29
29
|
*/
|
|
30
30
|
eventLogGc?: boolean;
|
|
31
31
|
/** Runs once when the instance is disposed, including by `requestReload`. */
|
|
@@ -44,5 +44,5 @@ type LocalSyncedDb<Database> = SyncedDb<Database> & {
|
|
|
44
44
|
*/
|
|
45
45
|
declare function createLocalSyncedDb<Database>(options: LocalSyncedDbOptions<Database>): Promise<LocalSyncedDb<Database>>;
|
|
46
46
|
//#endregion
|
|
47
|
-
export { type CreateRemoteSourceFactory, type EventsPullRequest, type EventsPushRequest, type EventsPushResponse, type LocalSyncedDb, type LocalSyncedDbOptions, type SqliteDriver, type SqliteDriverHooks, type SqliteDriverRows, type SqliteDriverStatement, type SqliteDriverValue, createLocalSyncedDb, createWsRemoteSource };
|
|
47
|
+
export { type CatchUpOptions, type CatchUpResult, type CreateRemoteSourceFactory, type EventsPullRequest, type EventsPushRequest, type EventsPushResponse, type LocalSyncedDb, type LocalSyncedDbOptions, type SqliteDriver, type SqliteDriverHooks, type SqliteDriverRows, type SqliteDriverStatement, type SqliteDriverValue, createLocalSyncedDb, createWsRemoteSource };
|
|
48
48
|
//# sourceMappingURL=local.d.ts.map
|
package/dist/local.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { f as createKvStateHashStore, m as createSQLiteKvStore, n as applyLocalDbSchema, p as createKvStoreTableQuery, s as localDbConfig, t as LOCAL_KV_TABLE_NAME } from "./system-schema-B8hbFl7o.js";
|
|
2
2
|
import { l as generateId, s as createTypedEventTarget } from "./crdt-table-schema-D6Yf61Ex.js";
|
|
3
|
-
import { a as formatSchemaVerificationIssues, c as createMigrator, l as createExportData, n as createCrdtStorage, o as verifySyncSchemaWithDriver, t as createCrdtSyncProducer, u as createImportData } from "./crdt-sync-producer-
|
|
4
|
-
import { o as HLCCounter, t as createCrdtSyncRemoteSource, u as xxhash } from "./crdt-sync-remote-source-
|
|
3
|
+
import { a as formatSchemaVerificationIssues, c as createMigrator, l as createExportData, n as createCrdtStorage, o as verifySyncSchemaWithDriver, t as createCrdtSyncProducer, u as createImportData } from "./crdt-sync-producer-CUXiu4X3.js";
|
|
4
|
+
import { o as HLCCounter, t as createCrdtSyncRemoteSource, u as xxhash } from "./crdt-sync-remote-source-CH2bsr-x.js";
|
|
5
5
|
import { t as SQLiteReactiveDb } from "./sqlite-reactive-db-DLTvpGzO.js";
|
|
6
6
|
import { a as makeCrdtTable, o as registerCrdtIntentDrainer } from "./make-crdt-table-Cu8WhRBk.js";
|
|
7
7
|
import { n as getOrCreateSQLiteSyncDevtoolsRegistry, r as validateDbId, t as createSyncedDbDatabase } from "./synced-db-database-B5M7MrBD.js";
|
|
8
|
-
import { i as runWorkerEventLogGc, r as formatStorageVersion, t as createWsRemoteSource } from "./ws-remote-source-
|
|
8
|
+
import { i as runWorkerEventLogGc, r as formatStorageVersion, t as createWsRemoteSource } from "./ws-remote-source-CliRqkIW.js";
|
|
9
9
|
//#region src/local/local-synced-db.ts
|
|
10
10
|
const STORAGE_VERSION_KEY = "storage-version";
|
|
11
11
|
const defaultLogger = (type, message, level = "info") => {
|
|
@@ -58,7 +58,7 @@ async function createLocalSyncedDb(options) {
|
|
|
58
58
|
const stateHash = createKvStateHashStore(kvStore);
|
|
59
59
|
const storageGeneration = kvStore.createStringStoredValue("storage-generation", "");
|
|
60
60
|
if (!storageGeneration.current) storageGeneration.current = generateId();
|
|
61
|
-
if (options.eventLogGc
|
|
61
|
+
if (options.eventLogGc !== false) runWorkerEventLogGc({
|
|
62
62
|
db,
|
|
63
63
|
dbConfig: localDbConfig,
|
|
64
64
|
pushSyncId,
|
|
@@ -169,7 +169,8 @@ async function createLocalSyncedDb(options) {
|
|
|
169
169
|
goOnline: () => remoteSource.goOnline(),
|
|
170
170
|
goOffline: () => remoteSource.goOffline("DISCONNECTED"),
|
|
171
171
|
dropConnection: () => remoteSource.dropConnection("NETWORK_OFFLINE"),
|
|
172
|
-
sync
|
|
172
|
+
sync,
|
|
173
|
+
catchUp: (options) => remoteSource.catchUp(options, () => crdtStorage.internal.processEnqueuedEvents())
|
|
173
174
|
},
|
|
174
175
|
/**
|
|
175
176
|
* Disposes this instance and notifies `reload-requested` subscribers, which are
|
package/dist/local.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.js","names":[],"sources":["../src/local/local-synced-db.ts"],"sourcesContent":["import { validateDbId } from \"../db-id\";\nimport { getOrCreateSQLiteSyncDevtoolsRegistry } from \"../devtools-registry\";\nimport { createExportData, createImportData } from \"../export-import\";\nimport { xxhash } from \"../hash\";\nimport { HLCCounter } from \"../hlc\";\nimport type { Logger } from \"../logger\";\nimport { SQLiteReactiveDb } from \"../memory-db/sqlite-reactive-db\";\nimport { createMigrator } from \"../migrations/migrator\";\nimport {\n applyLocalDbSchema,\n LOCAL_KV_TABLE_NAME,\n type LocalDbSchema,\n localDbConfig,\n} from \"../migrations/system-schema\";\nimport { formatSchemaVerificationIssues, verifySyncSchemaWithDriver } from \"../schema/verify-sync-schema\";\nimport type { SyncDbSchema } from \"../sqlite-crdt/crdt-schema\";\nimport { createCrdtStorage } from \"../sqlite-crdt/crdt-storage\";\nimport { createCrdtSyncProducer } from \"../sqlite-crdt/crdt-sync-producer\";\nimport {\n type CreateRemoteSourceFactory,\n createCrdtSyncRemoteSource,\n PUSH_BATCH_SIZE,\n} from \"../sqlite-crdt/crdt-sync-remote-source\";\nimport { makeCrdtTable, registerCrdtIntentDrainer } from \"../sqlite-crdt/make-crdt-table\";\nimport type { SqliteDriver } from \"../sqlite-driver\";\nimport { createKvStateHashStore, createKvStoreTableQuery, createSQLiteKvStore } from \"../sqlite-kv-store\";\nimport type { SyncedDb } from \"../sync-db\";\nimport { createSyncedDbDatabase } from \"../synced-db-database\";\nimport { createTypedEventTarget, generateId } from \"../utils\";\nimport { runWorkerEventLogGc } from \"../worker-db/event-log-gc\";\nimport { formatStorageVersion } from \"../worker-db/storage-version\";\nimport type { WorkerNotificationEvents, WorkerNotificationMessage } from \"../worker-db/worker-common\";\n\nexport type LocalSyncedDbOptions<Database> = {\n dbId: string;\n syncDbSchema: SyncDbSchema<Database>;\n /** Opens the persisted database. Called again after a reset deleted it. */\n openDriver: () => SqliteDriver | Promise<SqliteDriver>;\n /** Deletes the persisted database. Only called while no connection to it is open. */\n deleteDatabase: () => void | Promise<void>;\n createRemoteSource?: CreateRemoteSourceFactory;\n logger?: Logger;\n /**\n * App-provided storage version, combined with the library's internal storage\n * version. Bump it when deploying a code change that old persisted local DBs\n * cannot survive — on mismatch the local DB is deleted on startup.\n */\n storageVersion?: string;\n /**\n * Dev-time drift check: replays the full migration history on a throwaway\n * database opened by this callback and verifies the result matches the schema\n * declared with `defineSyncSchema`. On mismatch startup throws.\n */\n verifySchemaDriver?: () => SqliteDriver | Promise<SqliteDriver>;\n /**\n * Runs event-log garbage collection on startup. Disabled by default. GC keeps the\n * latest event rows and never removes pending events or local rows that have not\n * been pushed to the remote.\n */\n eventLogGc?: boolean;\n /** Runs once when the instance is disposed, including by `requestReload`. */\n onDispose?: () => void;\n};\n\nexport type LocalSyncedDb<Database> = SyncedDb<Database> & {\n state: SyncedDb<Database>[\"state\"] & {\n /** Drops the remote connection without retrying; call `sync` once the network is back. */\n dropConnection: () => void;\n };\n};\n\nconst STORAGE_VERSION_KEY = \"storage-version\";\n\nconst defaultLogger: Logger = (type, message, level = \"info\") => {\n const logMessage = `[${type}] ${message}`;\n switch (level) {\n case \"info\":\n console.log(logMessage);\n break;\n case \"warning\":\n console.warn(logMessage);\n break;\n case \"error\":\n console.error(logMessage);\n break;\n case \"trace\":\n console.trace(logMessage);\n break;\n }\n};\n\n/**\n * A synced DB backed by a single persisted SQLite connection, for runtimes with one\n * JS context per database (React Native, Electron, Node). Reads and writes go to the\n * persisted database directly; there is no worker, tab coordination or in-memory copy.\n */\nexport async function createLocalSyncedDb<Database>(\n options: LocalSyncedDbOptions<Database>,\n): Promise<LocalSyncedDb<Database>> {\n validateDbId(options.dbId);\n const logger = options.logger ?? defaultLogger;\n\n if (options.verifySchemaDriver) {\n const issues = verifySyncSchemaWithDriver(options.syncDbSchema as SyncDbSchema, await options.verifySchemaDriver());\n if (issues.length > 0) {\n throw new Error(formatSchemaVerificationIssues(issues));\n }\n logger(\"local\", \"Schema verification passed: migrations match the declared schema\", \"info\");\n }\n\n await xxhash.ensureLoaded();\n\n const reactiveDb = await openLocalReactiveDb(options, logger);\n const db = reactiveDb.db as unknown as SQLiteReactiveDb<LocalDbSchema>[\"db\"];\n\n try {\n const { kvStore } = applyLocalDbSchema(db);\n\n const migrator = createMigrator({\n migrations: options.syncDbSchema.migrations,\n schemaVersion: kvStore.createNumberStoredValue(\"schema-version\", -1),\n updateLogTableName: localDbConfig.updateLogTable.fullIdentifier,\n });\n migrator.migrateDbToLatest({\n startTransaction: (callback) => {\n db.executeTransaction((tx) =>\n callback({ execute: (sql, parameters, meta) => tx.execute({ sql, parameters }, meta) }),\n );\n },\n });\n db.invalidateDbSchema();\n\n const pullSyncId = kvStore.createNumberStoredValue(\"pull-sync-id\", -1);\n const pushSyncId = kvStore.createNumberStoredValue(\"push-sync-id\", -1);\n const stateHash = createKvStateHashStore(kvStore);\n const storageGeneration = kvStore.createStringStoredValue(\"storage-generation\", \"\");\n if (!storageGeneration.current) {\n storageGeneration.current = generateId();\n }\n\n if (options.eventLogGc === true) {\n runWorkerEventLogGc({ db, dbConfig: localDbConfig, pushSyncId, logger });\n }\n\n for (const table of options.syncDbSchema.tablesConfig) {\n makeCrdtTable({ db, baseTableName: table.baseTableName, crdtTableName: table.crdtTableName, temp: true });\n }\n\n const nodeId = generateId();\n const crdtStorage = createCrdtStorage({\n nodeId,\n initialLocalSyncId: Math.max(getMaxSyncId(db), pushSyncId.current),\n migrator,\n hlc: new HLCCounter(nodeId, () => Date.now()),\n db,\n dbConfig: localDbConfig,\n stateHash,\n schema: options.syncDbSchema,\n });\n registerCrdtIntentDrainer({ reactiveDb, storage: crdtStorage });\n\n kvStore.set(STORAGE_VERSION_KEY, formatStorageVersion(options.storageVersion));\n\n const eventTarget = createTypedEventTarget<WorkerNotificationEvents>();\n const notify = (notification: WorkerNotificationMessage) => {\n eventTarget.dispatchEvent(notification.notificationType, notification as never);\n };\n\n createCrdtSyncProducer({\n storage: crdtStorage,\n broadcastEvents: (chunk) => {\n notify({\n notificationType: \"new-event-chunk-applied\",\n newSyncId: chunk.newSyncId,\n stateHash: chunk.stateHash,\n });\n },\n });\n\n const remoteSource = createCrdtSyncRemoteSource({\n bufferSize: PUSH_BATCH_SIZE,\n pullSyncId,\n pushSyncId,\n nodeId,\n storage: crdtStorage,\n migrator,\n remoteFactory: options.createRemoteSource,\n });\n\n let stateSnapshot = remoteSource.getState();\n remoteSource.addEventListener(\"state-changed\", () => {\n stateSnapshot = remoteSource.getState();\n notify({\n notificationType: \"state-changed\",\n state: stateSnapshot,\n storageGeneration: storageGeneration.current,\n });\n });\n remoteSource.addEventListener(\"de-sync-detected\", (event) => {\n notify({ notificationType: \"de-sync-detected\", reason: event.payload.reason });\n });\n remoteSource.addEventListener(\"remote-schema-version-mismatch\", (event) => {\n notify({\n notificationType: \"remote-schema-version-mismatch\",\n remoteSchemaVersion: event.payload.remoteSchemaVersion,\n localSchemaVersion: event.payload.localSchemaVersion,\n });\n });\n remoteSource.goOnline();\n\n let unregisterDevtools: (() => void) | undefined;\n let disposePromise: Promise<void> | null = null;\n const dispose = () => {\n disposePromise ??= (async () => {\n options.onDispose?.();\n unregisterDevtools?.();\n try {\n await remoteSource.dispose();\n await crdtStorage.internal.processEnqueuedEvents();\n } finally {\n reactiveDb.dispose();\n }\n })();\n return disposePromise;\n };\n\n const importData = createImportData({\n migrator,\n tablesConfig: options.syncDbSchema.tablesConfig,\n applyEvents: async (events) => {\n crdtStorage.applyOwnEvents(events);\n await crdtStorage.internal.processEnqueuedEvents();\n },\n });\n\n const sync = () => {\n remoteSource.syncWithRemote().catch((error) => console.warn(\"Failed to start sync\", error));\n };\n\n const syncedDb: LocalSyncedDb<Database> = {\n db: createSyncedDbDatabase(reactiveDb),\n state: {\n getState: () => stateSnapshot,\n subscribe: (onChange: () => void) => {\n const { unsubscribe } = eventTarget.addEventListener(\"state-changed\", onChange);\n return unsubscribe;\n },\n goOnline: () => remoteSource.goOnline(),\n goOffline: () => remoteSource.goOffline(\"DISCONNECTED\"),\n dropConnection: () => remoteSource.dropConnection(\"NETWORK_OFFLINE\"),\n sync,\n },\n /**\n * Disposes this instance and notifies `reload-requested` subscribers, which are\n * expected to create a new instance. With `clean: true` the persisted database is\n * deleted first, so the next instance starts empty and re-syncs from the remote.\n * Pending local events that were not pushed yet are lost with a clean reload.\n */\n requestReload: async ({ clean }: { clean: boolean }) => {\n await dispose();\n if (clean) {\n await options.deleteDatabase();\n }\n notify({ notificationType: \"reload-requested\", reloadEpoch: generateId(), clean });\n },\n subscribe: eventTarget.addEventListener,\n exportData: createExportData({\n reactiveDb,\n tablesConfig: options.syncDbSchema.tablesConfig,\n schemaVersion: migrator.currentSchemaVersion,\n }),\n importData: async (data, opts) => importData(data, opts),\n dispose,\n _internal: {\n executeAsync: async (query) => reactiveDb.db.execute(query),\n getMemoryQueryTables: reactiveDb.getTablesUsed.bind(reactiveDb),\n getSharedLiveQueriesSnapshot: reactiveDb.getSharedLiveQueriesSnapshot.bind(reactiveDb),\n crdtTableNames: options.syncDbSchema.tablesConfig.map((table) => table.crdtTableName),\n crdtTablesConfig: options.syncDbSchema.tablesConfig,\n tables: options.syncDbSchema.tables,\n schemaVersion: migrator.currentSchemaVersion,\n migrationVersions: Object.keys(options.syncDbSchema.migrations)\n .map(Number)\n .sort((a, b) => a - b),\n },\n };\n\n unregisterDevtools = getOrCreateSQLiteSyncDevtoolsRegistry().register({\n instanceId: generateId(),\n dbId: options.dbId,\n createdAt: Date.now(),\n instance: syncedDb,\n });\n\n return syncedDb;\n } catch (error) {\n reactiveDb.dispose();\n throw error;\n }\n}\n\nasync function openLocalReactiveDb<Database>(options: LocalSyncedDbOptions<Database>, logger: Logger) {\n const open = async () => {\n const driver = await options.openDriver();\n const reactiveDb = SQLiteReactiveDb.create<Database>({ driver, logger, loggerPrefix: \"local\" });\n try {\n reactiveDb.db.execute(\"PRAGMA journal_mode=WAL\", { loggerLevel: \"system\" });\n reactiveDb.db.execute(\"PRAGMA synchronous=NORMAL\", { loggerLevel: \"system\" });\n reactiveDb.db.executeKysely((kysely) => createKvStoreTableQuery(kysely.schema, LOCAL_KV_TABLE_NAME), {\n loggerLevel: \"system\",\n });\n } catch (error) {\n reactiveDb.dispose();\n throw error;\n }\n return reactiveDb;\n };\n\n const reactiveDb = await open();\n const currentVersion = formatStorageVersion(options.storageVersion);\n const storedVersion = createSQLiteKvStore({ db: reactiveDb.db, metaTableName: LOCAL_KV_TABLE_NAME }).get(\n STORAGE_VERSION_KEY,\n );\n if (storedVersion === null || storedVersion === currentVersion) {\n return reactiveDb;\n }\n\n logger(\"local\", `Storage version mismatch — resetting local DB to ${currentVersion}`, \"warning\");\n reactiveDb.dispose();\n await options.deleteDatabase();\n return open();\n}\n\nfunction getMaxSyncId(db: SQLiteReactiveDb<LocalDbSchema>[\"db\"]) {\n const [result] = db.executePrepared(\n \"get-max-sync-id\",\n {},\n (db) => db.selectFrom(\"crdt_events\").select((eb) => eb.fn.max(\"sync_id\").as(\"sync_id\")),\n { loggerLevel: \"system\" },\n );\n\n return result?.sync_id ?? 0;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"local.js","names":[],"sources":["../src/local/local-synced-db.ts"],"sourcesContent":["import { validateDbId } from \"../db-id\";\nimport { getOrCreateSQLiteSyncDevtoolsRegistry } from \"../devtools-registry\";\nimport { createExportData, createImportData } from \"../export-import\";\nimport { xxhash } from \"../hash\";\nimport { HLCCounter } from \"../hlc\";\nimport type { Logger } from \"../logger\";\nimport { SQLiteReactiveDb } from \"../memory-db/sqlite-reactive-db\";\nimport { createMigrator } from \"../migrations/migrator\";\nimport {\n applyLocalDbSchema,\n LOCAL_KV_TABLE_NAME,\n type LocalDbSchema,\n localDbConfig,\n} from \"../migrations/system-schema\";\nimport { formatSchemaVerificationIssues, verifySyncSchemaWithDriver } from \"../schema/verify-sync-schema\";\nimport type { SyncDbSchema } from \"../sqlite-crdt/crdt-schema\";\nimport { createCrdtStorage } from \"../sqlite-crdt/crdt-storage\";\nimport { createCrdtSyncProducer } from \"../sqlite-crdt/crdt-sync-producer\";\nimport {\n type CreateRemoteSourceFactory,\n createCrdtSyncRemoteSource,\n PUSH_BATCH_SIZE,\n} from \"../sqlite-crdt/crdt-sync-remote-source\";\nimport { makeCrdtTable, registerCrdtIntentDrainer } from \"../sqlite-crdt/make-crdt-table\";\nimport type { SqliteDriver } from \"../sqlite-driver\";\nimport { createKvStateHashStore, createKvStoreTableQuery, createSQLiteKvStore } from \"../sqlite-kv-store\";\nimport type { SyncedDb } from \"../sync-db\";\nimport { createSyncedDbDatabase } from \"../synced-db-database\";\nimport { createTypedEventTarget, generateId } from \"../utils\";\nimport { runWorkerEventLogGc } from \"../worker-db/event-log-gc\";\nimport { formatStorageVersion } from \"../worker-db/storage-version\";\nimport type { WorkerNotificationEvents, WorkerNotificationMessage } from \"../worker-db/worker-common\";\n\nexport type LocalSyncedDbOptions<Database> = {\n dbId: string;\n syncDbSchema: SyncDbSchema<Database>;\n /** Opens the persisted database. Called again after a reset deleted it. */\n openDriver: () => SqliteDriver | Promise<SqliteDriver>;\n /** Deletes the persisted database. Only called while no connection to it is open. */\n deleteDatabase: () => void | Promise<void>;\n createRemoteSource?: CreateRemoteSourceFactory;\n logger?: Logger;\n /**\n * App-provided storage version, combined with the library's internal storage\n * version. Bump it when deploying a code change that old persisted local DBs\n * cannot survive — on mismatch the local DB is deleted on startup.\n */\n storageVersion?: string;\n /**\n * Dev-time drift check: replays the full migration history on a throwaway\n * database opened by this callback and verifies the result matches the schema\n * declared with `defineSyncSchema`. On mismatch startup throws.\n */\n verifySchemaDriver?: () => SqliteDriver | Promise<SqliteDriver>;\n /**\n * Runs event-log garbage collection on startup. Enabled by default; set `false` to\n * disable. GC keeps the latest event rows and never removes pending events or local\n * rows that have not been pushed to the remote.\n */\n eventLogGc?: boolean;\n /** Runs once when the instance is disposed, including by `requestReload`. */\n onDispose?: () => void;\n};\n\nexport type LocalSyncedDb<Database> = SyncedDb<Database> & {\n state: SyncedDb<Database>[\"state\"] & {\n /** Drops the remote connection without retrying; call `sync` once the network is back. */\n dropConnection: () => void;\n };\n};\n\nconst STORAGE_VERSION_KEY = \"storage-version\";\n\nconst defaultLogger: Logger = (type, message, level = \"info\") => {\n const logMessage = `[${type}] ${message}`;\n switch (level) {\n case \"info\":\n console.log(logMessage);\n break;\n case \"warning\":\n console.warn(logMessage);\n break;\n case \"error\":\n console.error(logMessage);\n break;\n case \"trace\":\n console.trace(logMessage);\n break;\n }\n};\n\n/**\n * A synced DB backed by a single persisted SQLite connection, for runtimes with one\n * JS context per database (React Native, Electron, Node). Reads and writes go to the\n * persisted database directly; there is no worker, tab coordination or in-memory copy.\n */\nexport async function createLocalSyncedDb<Database>(\n options: LocalSyncedDbOptions<Database>,\n): Promise<LocalSyncedDb<Database>> {\n validateDbId(options.dbId);\n const logger = options.logger ?? defaultLogger;\n\n if (options.verifySchemaDriver) {\n const issues = verifySyncSchemaWithDriver(options.syncDbSchema as SyncDbSchema, await options.verifySchemaDriver());\n if (issues.length > 0) {\n throw new Error(formatSchemaVerificationIssues(issues));\n }\n logger(\"local\", \"Schema verification passed: migrations match the declared schema\", \"info\");\n }\n\n await xxhash.ensureLoaded();\n\n const reactiveDb = await openLocalReactiveDb(options, logger);\n const db = reactiveDb.db as unknown as SQLiteReactiveDb<LocalDbSchema>[\"db\"];\n\n try {\n const { kvStore } = applyLocalDbSchema(db);\n\n const migrator = createMigrator({\n migrations: options.syncDbSchema.migrations,\n schemaVersion: kvStore.createNumberStoredValue(\"schema-version\", -1),\n updateLogTableName: localDbConfig.updateLogTable.fullIdentifier,\n });\n migrator.migrateDbToLatest({\n startTransaction: (callback) => {\n db.executeTransaction((tx) =>\n callback({ execute: (sql, parameters, meta) => tx.execute({ sql, parameters }, meta) }),\n );\n },\n });\n db.invalidateDbSchema();\n\n const pullSyncId = kvStore.createNumberStoredValue(\"pull-sync-id\", -1);\n const pushSyncId = kvStore.createNumberStoredValue(\"push-sync-id\", -1);\n const stateHash = createKvStateHashStore(kvStore);\n const storageGeneration = kvStore.createStringStoredValue(\"storage-generation\", \"\");\n if (!storageGeneration.current) {\n storageGeneration.current = generateId();\n }\n\n if (options.eventLogGc !== false) {\n runWorkerEventLogGc({ db, dbConfig: localDbConfig, pushSyncId, logger });\n }\n\n for (const table of options.syncDbSchema.tablesConfig) {\n makeCrdtTable({ db, baseTableName: table.baseTableName, crdtTableName: table.crdtTableName, temp: true });\n }\n\n const nodeId = generateId();\n const crdtStorage = createCrdtStorage({\n nodeId,\n initialLocalSyncId: Math.max(getMaxSyncId(db), pushSyncId.current),\n migrator,\n hlc: new HLCCounter(nodeId, () => Date.now()),\n db,\n dbConfig: localDbConfig,\n stateHash,\n schema: options.syncDbSchema,\n });\n registerCrdtIntentDrainer({ reactiveDb, storage: crdtStorage });\n\n kvStore.set(STORAGE_VERSION_KEY, formatStorageVersion(options.storageVersion));\n\n const eventTarget = createTypedEventTarget<WorkerNotificationEvents>();\n const notify = (notification: WorkerNotificationMessage) => {\n eventTarget.dispatchEvent(notification.notificationType, notification as never);\n };\n\n createCrdtSyncProducer({\n storage: crdtStorage,\n broadcastEvents: (chunk) => {\n notify({\n notificationType: \"new-event-chunk-applied\",\n newSyncId: chunk.newSyncId,\n stateHash: chunk.stateHash,\n });\n },\n });\n\n const remoteSource = createCrdtSyncRemoteSource({\n bufferSize: PUSH_BATCH_SIZE,\n pullSyncId,\n pushSyncId,\n nodeId,\n storage: crdtStorage,\n migrator,\n remoteFactory: options.createRemoteSource,\n });\n\n let stateSnapshot = remoteSource.getState();\n remoteSource.addEventListener(\"state-changed\", () => {\n stateSnapshot = remoteSource.getState();\n notify({\n notificationType: \"state-changed\",\n state: stateSnapshot,\n storageGeneration: storageGeneration.current,\n });\n });\n remoteSource.addEventListener(\"de-sync-detected\", (event) => {\n notify({ notificationType: \"de-sync-detected\", reason: event.payload.reason });\n });\n remoteSource.addEventListener(\"remote-schema-version-mismatch\", (event) => {\n notify({\n notificationType: \"remote-schema-version-mismatch\",\n remoteSchemaVersion: event.payload.remoteSchemaVersion,\n localSchemaVersion: event.payload.localSchemaVersion,\n });\n });\n remoteSource.goOnline();\n\n let unregisterDevtools: (() => void) | undefined;\n let disposePromise: Promise<void> | null = null;\n const dispose = () => {\n disposePromise ??= (async () => {\n options.onDispose?.();\n unregisterDevtools?.();\n try {\n await remoteSource.dispose();\n await crdtStorage.internal.processEnqueuedEvents();\n } finally {\n reactiveDb.dispose();\n }\n })();\n return disposePromise;\n };\n\n const importData = createImportData({\n migrator,\n tablesConfig: options.syncDbSchema.tablesConfig,\n applyEvents: async (events) => {\n crdtStorage.applyOwnEvents(events);\n await crdtStorage.internal.processEnqueuedEvents();\n },\n });\n\n const sync = () => {\n remoteSource.syncWithRemote().catch((error) => console.warn(\"Failed to start sync\", error));\n };\n\n const syncedDb: LocalSyncedDb<Database> = {\n db: createSyncedDbDatabase(reactiveDb),\n state: {\n getState: () => stateSnapshot,\n subscribe: (onChange: () => void) => {\n const { unsubscribe } = eventTarget.addEventListener(\"state-changed\", onChange);\n return unsubscribe;\n },\n goOnline: () => remoteSource.goOnline(),\n goOffline: () => remoteSource.goOffline(\"DISCONNECTED\"),\n dropConnection: () => remoteSource.dropConnection(\"NETWORK_OFFLINE\"),\n sync,\n // With asynchronous driver hooks, a write that just returned is not yet ready to push.\n catchUp: (options) => remoteSource.catchUp(options, () => crdtStorage.internal.processEnqueuedEvents()),\n },\n /**\n * Disposes this instance and notifies `reload-requested` subscribers, which are\n * expected to create a new instance. With `clean: true` the persisted database is\n * deleted first, so the next instance starts empty and re-syncs from the remote.\n * Pending local events that were not pushed yet are lost with a clean reload.\n */\n requestReload: async ({ clean }: { clean: boolean }) => {\n await dispose();\n if (clean) {\n await options.deleteDatabase();\n }\n notify({ notificationType: \"reload-requested\", reloadEpoch: generateId(), clean });\n },\n subscribe: eventTarget.addEventListener,\n exportData: createExportData({\n reactiveDb,\n tablesConfig: options.syncDbSchema.tablesConfig,\n schemaVersion: migrator.currentSchemaVersion,\n }),\n importData: async (data, opts) => importData(data, opts),\n dispose,\n _internal: {\n executeAsync: async (query) => reactiveDb.db.execute(query),\n getMemoryQueryTables: reactiveDb.getTablesUsed.bind(reactiveDb),\n getSharedLiveQueriesSnapshot: reactiveDb.getSharedLiveQueriesSnapshot.bind(reactiveDb),\n crdtTableNames: options.syncDbSchema.tablesConfig.map((table) => table.crdtTableName),\n crdtTablesConfig: options.syncDbSchema.tablesConfig,\n tables: options.syncDbSchema.tables,\n schemaVersion: migrator.currentSchemaVersion,\n migrationVersions: Object.keys(options.syncDbSchema.migrations)\n .map(Number)\n .sort((a, b) => a - b),\n },\n };\n\n unregisterDevtools = getOrCreateSQLiteSyncDevtoolsRegistry().register({\n instanceId: generateId(),\n dbId: options.dbId,\n createdAt: Date.now(),\n instance: syncedDb,\n });\n\n return syncedDb;\n } catch (error) {\n reactiveDb.dispose();\n throw error;\n }\n}\n\nasync function openLocalReactiveDb<Database>(options: LocalSyncedDbOptions<Database>, logger: Logger) {\n const open = async () => {\n const driver = await options.openDriver();\n const reactiveDb = SQLiteReactiveDb.create<Database>({ driver, logger, loggerPrefix: \"local\" });\n try {\n reactiveDb.db.execute(\"PRAGMA journal_mode=WAL\", { loggerLevel: \"system\" });\n reactiveDb.db.execute(\"PRAGMA synchronous=NORMAL\", { loggerLevel: \"system\" });\n reactiveDb.db.executeKysely((kysely) => createKvStoreTableQuery(kysely.schema, LOCAL_KV_TABLE_NAME), {\n loggerLevel: \"system\",\n });\n } catch (error) {\n reactiveDb.dispose();\n throw error;\n }\n return reactiveDb;\n };\n\n const reactiveDb = await open();\n const currentVersion = formatStorageVersion(options.storageVersion);\n const storedVersion = createSQLiteKvStore({ db: reactiveDb.db, metaTableName: LOCAL_KV_TABLE_NAME }).get(\n STORAGE_VERSION_KEY,\n );\n if (storedVersion === null || storedVersion === currentVersion) {\n return reactiveDb;\n }\n\n logger(\"local\", `Storage version mismatch — resetting local DB to ${currentVersion}`, \"warning\");\n reactiveDb.dispose();\n await options.deleteDatabase();\n return open();\n}\n\nfunction getMaxSyncId(db: SQLiteReactiveDb<LocalDbSchema>[\"db\"]) {\n const [result] = db.executePrepared(\n \"get-max-sync-id\",\n {},\n (db) => db.selectFrom(\"crdt_events\").select((eb) => eb.fn.max(\"sync_id\").as(\"sync_id\")),\n { loggerLevel: \"system\" },\n );\n\n return result?.sync_id ?? 0;\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as acquireLock, l as generateId, r as TypedBroadcastChannel } from "./crdt-table-schema-D6Yf61Ex.js";
|
|
2
|
-
import { o as verifySyncSchemaWithDriver } from "./crdt-sync-producer-
|
|
2
|
+
import { o as verifySyncSchemaWithDriver } from "./crdt-sync-producer-CUXiu4X3.js";
|
|
3
3
|
import sqlite3InitModule from "@sqlite.org/sqlite-wasm";
|
|
4
4
|
import { createStore, del, get, set } from "idb-keyval";
|
|
5
5
|
//#region src/wasm-driver.ts
|
|
@@ -217,4 +217,4 @@ function createReloadRequestHandler({ resetState, broadcast, generateEpoch = gen
|
|
|
217
217
|
//#endregion
|
|
218
218
|
export { createWasmSqliteDriver as _, acquireReplicaLock as a, isWorkerErrorResponseMessage as c, isWorkerRequestMessage as d, isWorkerResponseMessage as f, createWasmMemoryDriver as g, verifySyncSchema as h, createResetStateStore as i, isWorkerInitMessage as l, syncDbWorkerLockName as m, createIdbResetStore as n, runWithNoActiveReplicas as o, syncDbClientLockName as p, createReloadRequestHandler as r, createBroadcastChannels as s, RESET_REQUEST_TTL_MS as t, isWorkerNotificationMessage as u, loadSqliteWasm as v };
|
|
219
219
|
|
|
220
|
-
//# sourceMappingURL=reset-state-
|
|
220
|
+
//# sourceMappingURL=reset-state-BeJZaX-W.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reset-state-BeJZaX-W.js","names":[],"sources":["../src/wasm-driver.ts","../src/schema/verify-sync-schema-wasm.ts","../src/worker-db/worker-common.ts","../src/worker-db/replica-lock.ts","../src/worker-db/reset-state.ts"],"sourcesContent":["import sqlite3InitModule, {\n type BindableValue,\n type Database,\n type Sqlite3Static,\n type SqlValue,\n} from \"@sqlite.org/sqlite-wasm\";\nimport type { SqliteDriver, SqliteDriverStatement, SqliteDriverValue } from \"./sqlite-driver\";\n\nlet sqliteModulePromise: Promise<Sqlite3Static> | null = null;\n\nexport function loadSqliteWasm() {\n sqliteModulePromise ??= sqlite3InitModule();\n return sqliteModulePromise;\n}\n\nexport async function createWasmMemoryDriver() {\n const sqlite3 = await loadSqliteWasm();\n return createWasmSqliteDriver(sqlite3, new sqlite3.oo1.DB({ filename: \":memory:\" }));\n}\n\nexport function createWasmSqliteDriver(sqlite3: Sqlite3Static, db: Database): SqliteDriver {\n const { capi } = sqlite3;\n\n const prepare = (sql: string): SqliteDriverStatement => {\n const statement = db.prepare(sql);\n const pointer = statement.pointer;\n if (!pointer) {\n throw new Error(\"Prepared statement is already finalized\");\n }\n\n return {\n readonly: capi.sqlite3_stmt_readonly(pointer) !== 0,\n run: (parameters) => {\n try {\n if (parameters.length > 0) {\n statement.bind(parameters as BindableValue[]);\n }\n\n const rows: SqliteDriverValue[][] = [];\n let columns: string[] | undefined;\n while (statement.step()) {\n columns ??= statement.getColumnNames([]);\n rows.push(statement.get([]) as SqliteDriverValue[]);\n }\n return { columns: columns ?? [], rows };\n } finally {\n statement.reset(true);\n }\n },\n finalize: () => {\n statement.finalize();\n },\n };\n };\n\n return {\n prepare,\n synchronousHooks: true,\n totalChanges: () => capi.sqlite3_total_changes(db),\n setHooks: (hooks) => {\n if (!hooks) {\n capi.sqlite3_update_hook(db, 0 as never, 0);\n capi.sqlite3_rollback_hook(db, 0, 0);\n capi.sqlite3_commit_hook(db, 0, 0);\n return;\n }\n\n capi.sqlite3_update_hook(db, (_ctx, _opId, _db, table) => hooks.onUpdate(table), 0);\n capi.sqlite3_rollback_hook(\n db,\n () => {\n hooks.onRollback();\n return 0;\n },\n 0,\n );\n capi.sqlite3_commit_hook(\n db,\n () => {\n hooks.onCommit();\n return 0;\n },\n 0,\n );\n },\n serialize: () => capi.sqlite3_js_db_export(db),\n deserialize: (snapshot) => {\n const dataPointer = sqlite3.wasm.allocFromTypedArray(snapshot);\n const resultCode = capi.sqlite3_deserialize(\n db,\n \"main\",\n dataPointer,\n snapshot.byteLength,\n snapshot.byteLength,\n capi.SQLITE_DESERIALIZE_FREEONCLOSE | capi.SQLITE_DESERIALIZE_RESIZEABLE,\n );\n db.checkRc(resultCode);\n },\n createScalarFunction: ({ name, callback, arity, deterministic, directOnly, innocuous }) => {\n db.createFunction({\n name,\n xFunc: (_, ...args) => callback(...(args as SqliteDriverValue[])) as SqlValue,\n arity,\n deterministic,\n directOnly,\n innocuous,\n });\n },\n close: () => {\n db.close();\n },\n };\n}\n","import type { SyncDbSchema } from \"../sqlite-crdt/crdt-schema\";\nimport { createWasmMemoryDriver } from \"../wasm-driver\";\nimport { type SchemaVerificationIssue, verifySyncSchemaWithDriver } from \"./verify-sync-schema\";\n\n/** {@link verifySyncSchemaWithDriver} on a throwaway in-memory sqlite-wasm database. */\nexport async function verifySyncSchema(schema: SyncDbSchema): Promise<SchemaVerificationIssue[]> {\n return verifySyncSchemaWithDriver(schema, await createWasmMemoryDriver());\n}\n","import type { ImportDataOptions, ImportDataResult, SyncedDbExport } from \"../export-import\";\nimport type {\n CatchUpOptions,\n CatchUpResult,\n DeSyncDetectedReason,\n EventsPullRequest,\n EventsPushRequest,\n EventsPushResponse,\n} from \"../sqlite-crdt/crdt-sync-remote-source\";\nimport type { CrdtEventType } from \"../sqlite-crdt/crdt-table-schema\";\nimport type { ExecuteParams, ExecuteResult } from \"../sqlite-db-wrapper\";\nimport { TypedBroadcastChannel } from \"../utils\";\n\nexport const syncDbWorkerLockName = \"sync-db-worker-lock\";\nexport const syncDbClientLockName = \"sync-db-client-lock\";\n\nexport type WorkerNotificationMessage =\n | {\n notificationType: \"new-event-chunk-applied\";\n newSyncId: number;\n /** Worker's state hash after applying up to `newSyncId`. */\n stateHash: string | null;\n }\n | {\n notificationType: \"state-changed\";\n state: WorkerState;\n /** Id of the worker's persisted database. A wiped database gets a new one. */\n storageGeneration: string;\n }\n | {\n notificationType: \"reload-requested\";\n reloadEpoch: string;\n clean: boolean;\n }\n | {\n notificationType: \"de-sync-detected\";\n reason: DeSyncDetectedReason;\n }\n | {\n notificationType: \"remote-schema-version-mismatch\";\n remoteSchemaVersion: number;\n localSchemaVersion: number;\n };\n\nexport type WorkerNotificationEvents = {\n [K in WorkerNotificationMessage[\"notificationType\"]]: Extract<WorkerNotificationMessage, { notificationType: K }>;\n};\n\nexport type WorkerState = {\n remoteState: \"online\" | \"offline\" | \"connecting\";\n deSynced: boolean;\n schemaVersionMismatched: boolean;\n};\n\nexport type GetSnapshotResponse = {\n file: Uint8Array<ArrayBufferLike>;\n syncId: number;\n schemaVersion: number;\n storageGeneration: string;\n};\n\nexport type EventsPullResponse = {\n events: {\n schema_version: number;\n type: CrdtEventType;\n timestamp: string;\n dataset: string;\n item_id: string;\n payload: string;\n }[];\n hasMore: boolean;\n nextSyncId: number;\n};\n\nexport interface WorkerRpc {\n getSnapshot: () => GetSnapshotResponse;\n importData: (data: SyncedDbExport, opts?: ImportDataOptions) => ImportDataResult | Promise<ImportDataResult>;\n pushTabEvents: (request: EventsPushRequest) => EventsPushResponse;\n execute: (query: ExecuteParams) => ExecuteResult<unknown>;\n pullEvents: (params: EventsPullRequest) => EventsPullResponse;\n postState: () => void;\n goOnline: () => Promise<void>;\n goOffline: () => void;\n dropConnection: () => void;\n sync: () => void;\n catchUp: (options?: CatchUpOptions) => CatchUpResult | Promise<CatchUpResult>;\n requestReload: (options: { clean: boolean }) => Promise<void>;\n}\n\nexport type WorkerRequestMethod = keyof WorkerRpc;\n\nexport type WorkerRequestMessage<TMethod extends WorkerRequestMethod = WorkerRequestMethod> = {\n type: \"request\";\n requestId: string;\n method: TMethod;\n args: Parameters<WorkerRpc[TMethod]>;\n};\n\nexport type WorkerResponseMessage<TMethod extends WorkerRequestMethod = WorkerRequestMethod> = {\n type: \"response\";\n requestId: string;\n data: ReturnType<WorkerRpc[TMethod]>;\n};\n\nexport type WorkerErrorResponseMessage = {\n type: \"error-response\";\n requestId: string;\n error: string;\n};\n\nexport type AsyncRpc<T> = {\n [K in keyof T]: T[K] extends (...args: infer U) => infer V ? (...args: U) => Promise<Awaited<V>> : never;\n};\n\nexport const broadcastChannelNames = {\n requests: \"sync-db-worker-requests\",\n responses: \"sync-db-worker-responses\",\n} as const;\n\nexport type WorkerBroadcastChannels = {\n requests: TypedBroadcastChannel<WorkerRequestMessage>;\n responses: TypedBroadcastChannel<WorkerResponseMessage | WorkerErrorResponseMessage | WorkerNotificationMessage>;\n};\n\nexport const createBroadcastChannels = (prefix: string): WorkerBroadcastChannels => {\n return {\n requests: new TypedBroadcastChannel(`${prefix}-${broadcastChannelNames.requests}`),\n responses: new TypedBroadcastChannel(`${prefix}-${broadcastChannelNames.responses}`),\n };\n};\n\nexport type WorkerConfig<Props = any> = {\n dbId: string;\n clientId: string;\n props: Props;\n};\n\nexport type WorkerInitMessage = {\n type: \"init\";\n config: WorkerConfig;\n};\n\nexport function isWorkerInitMessage(message: unknown): message is WorkerInitMessage {\n return typeof message === \"object\" && message !== null && \"type\" in message && message.type === \"init\";\n}\n\nexport function isWorkerRequestMessage(message: unknown): message is WorkerRequestMessage {\n return typeof message === \"object\" && message !== null && \"type\" in message && message.type === \"request\";\n}\n\nexport function isWorkerResponseMessage(message: unknown): message is WorkerResponseMessage {\n return (\n typeof message === \"object\" && message !== null && \"type\" in message && \"requestId\" in message && \"data\" in message\n );\n}\n\nexport function isWorkerErrorResponseMessage(message: unknown): message is WorkerErrorResponseMessage {\n return typeof message === \"object\" && message !== null && \"type\" in message && message.type === \"error-response\";\n}\n\nexport function isWorkerNotificationMessage(message: unknown): message is WorkerNotificationMessage {\n return typeof message === \"object\" && message !== null && \"notificationType\" in message && !!message.notificationType;\n}\n","import { acquireLock } from \"../utils\";\n\nconst replicaLockName = (dbId: string) => `sync-db-replica-lock-${dbId}`;\n\nexport function acquireReplicaLock({ dbId }: { dbId: string }) {\n return acquireLock(replicaLockName(dbId), { mode: \"shared\" });\n}\n\nexport function runWithNoActiveReplicas({ dbId, run }: { dbId: string; run: () => void | Promise<void> }) {\n return navigator.locks.request(replicaLockName(dbId), { mode: \"exclusive\", ifAvailable: true }, async (lock) => {\n if (!lock) {\n return false;\n }\n await run();\n return true;\n });\n}\n","import { createStore, del, get, set } from \"idb-keyval\";\nimport { generateId } from \"../utils\";\nimport type { WorkerNotificationMessage } from \"./worker-common\";\n\nexport type ResetRequest = {\n epoch: string;\n requestedAt: number;\n};\n\n/** Durable async key-value storage for reset state. Injectable for tests. */\nexport type ResetStore = {\n get: <T>(key: string) => Promise<T | undefined>;\n set: (key: string, value: unknown) => Promise<void>;\n delete: (key: string) => Promise<void>;\n};\n\n/** Default IndexedDB-backed reset store (idb-keyval over a dedicated database). */\nexport function createIdbResetStore(): ResetStore {\n const store = createStore(\"sqlite-sync\", \"kv\");\n return {\n get: (key) => get(key, store),\n set: (key, value) => set(key, value, store),\n delete: (key) => del(key, store),\n };\n}\n\n/**\n * A clean reset is a recovery action for a de-sync detected now. If the reload\n * never happens (broadcast lost, tab crashed mid-reload, browser killed the page),\n * the request must not fire on an arbitrary later cold start and silently wipe\n * local-only writes accumulated since.\n */\nexport const RESET_REQUEST_TTL_MS = 10 * 60 * 1000; // 10 minutes\n\nconst resetRequestKey = (dbId: string) => `sqlite-sync-reset-request-${dbId}`;\nconst resetAppliedKey = (dbId: string) => `sqlite-sync-reset-applied-${dbId}`;\n\ntype ResetStateStoreOptions = {\n store: ResetStore;\n dbId: string;\n now?: () => number;\n};\n\nexport type ResetStateStore = ReturnType<typeof createResetStateStore>;\n\n/**\n * Worker-owned durable reset state. The reset decision must be owned by the\n * elected worker, not by tabs during `createSyncedDb` — otherwise a later\n * worker election could repeat an already-applied wipe.\n */\nexport function createResetStateStore({ store, dbId, now = () => Date.now() }: ResetStateStoreOptions) {\n const requestKey = resetRequestKey(dbId);\n const appliedKey = resetAppliedKey(dbId);\n\n return {\n async writeResetRequest(epoch: string): Promise<ResetRequest> {\n const request: ResetRequest = { epoch, requestedAt: now() };\n await store.set(requestKey, request);\n return request;\n },\n /**\n * Read the pending reset request after winning the worker election.\n * Returns the request only when it has not been applied yet and is within\n * the TTL. Stale requests are deleted so they cannot fire on a later cold start.\n */\n async resolvePendingReset(): Promise<ResetRequest | undefined> {\n const request = await store.get<ResetRequest>(requestKey);\n if (!request) {\n return undefined;\n }\n\n if (now() - request.requestedAt > RESET_REQUEST_TTL_MS) {\n await store.delete(requestKey);\n return undefined;\n }\n\n const appliedEpoch = await store.get<string>(appliedKey);\n if (request.epoch === appliedEpoch) {\n return undefined;\n }\n\n return request;\n },\n /**\n * Record the epoch as applied. Must be called only after the worker has\n * successfully initialized with `clearOnInit: true`, so a failed init can\n * be retried by a later elected worker.\n */\n async markResetApplied(epoch: string): Promise<void> {\n await store.set(appliedKey, epoch);\n },\n };\n}\n\ntype ReloadRequestHandlerOptions = {\n resetState: ResetStateStore;\n broadcast: (message: WorkerNotificationMessage) => void;\n generateEpoch?: () => string;\n};\n\n/**\n * Worker-side `requestReload` RPC implementation. For `clean: true` the reset\n * request is durably stored before broadcasting and before the RPC resolves,\n * so the epoch survives no matter which path triggers the reload.\n */\nexport function createReloadRequestHandler({\n resetState,\n broadcast,\n generateEpoch = generateId,\n}: ReloadRequestHandlerOptions) {\n return async (options: { clean: boolean }): Promise<void> => {\n const reloadEpoch = generateEpoch();\n\n if (options.clean) {\n await resetState.writeResetRequest(reloadEpoch);\n }\n\n broadcast({\n notificationType: \"reload-requested\",\n reloadEpoch,\n clean: options.clean,\n });\n };\n}\n"],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { An as MigratableEvent, At as jsonSafeParse, D as EventsPushResponse, Nn as SyncDbMigrator, X as ClientDatasetRejectionReason, k as EventsPullResponse, pn as SyncDbSchema } from "./index-C1E8xMH1.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
//#region src/server/admit-client-push.d.ts
|
|
4
4
|
type PushedCrdtEvent = MigratableEvent & {
|
package/dist/server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as isNoOpCrdtEventPayload, t as CRDT_EVENT_NO_OP_PAYLOAD, u as jsonSafeParse } from "./crdt-table-schema-D6Yf61Ex.js";
|
|
2
|
-
import { i as validateNewCrdtEvent } from "./crdt-sync-remote-source-
|
|
2
|
+
import { i as validateNewCrdtEvent } from "./crdt-sync-remote-source-CH2bsr-x.js";
|
|
3
3
|
import { r as getClientDatasetRejection } from "./admit-client-events-BDrJw4SK.js";
|
|
4
4
|
import { n as HEARTBEAT_PONG, t as HEARTBEAT_PING } from "./heartbeat-CJWQAoGP.js";
|
|
5
5
|
import { z } from "zod";
|
package/dist/worker.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as createWsRemoteSource } from "./ws-remote-source-
|
|
1
|
+
import { A as WorkerConfig, D as EventsPushResponse, E as EventsPushRequest, T as EventsPullRequest, c as ResetStore, en as Logger, pn as SyncDbSchema, ut as GetEventsBatch, w as CreateRemoteSourceFactory } from "./index-C1E8xMH1.js";
|
|
2
|
+
import { t as createWsRemoteSource } from "./ws-remote-source-Bk6NYwML.js";
|
|
3
3
|
//#region src/worker-db/db-worker.d.ts
|
|
4
4
|
declare function getWorkerConfig<Props = never>(): Promise<WorkerConfig<Props>>;
|
|
5
5
|
type WorkerOptions = {
|
|
@@ -23,8 +23,8 @@ type WorkerOptions = {
|
|
|
23
23
|
*/
|
|
24
24
|
verifySchema?: boolean;
|
|
25
25
|
/**
|
|
26
|
-
* Runs local worker event-log garbage collection on startup.
|
|
27
|
-
* set `eventLogGc:
|
|
26
|
+
* Runs local worker event-log garbage collection on startup. Enabled by default;
|
|
27
|
+
* set `eventLogGc: false` to disable. GC keeps the latest event rows and never removes
|
|
28
28
|
* pending events or local rows that have not been pushed to the remote.
|
|
29
29
|
* Skipped while an existing tab holds an in-memory replica of this DB.
|
|
30
30
|
*/
|
package/dist/worker.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { f as createKvStateHashStore, g as SQLiteDbWrapper, i as applyWorkerDbSchema, u as workerDbConfig } from "./system-schema-B8hbFl7o.js";
|
|
2
2
|
import { l as generateId, o as createDeferredPromise } from "./crdt-table-schema-D6Yf61Ex.js";
|
|
3
|
-
import { a as formatSchemaVerificationIssues, c as createMigrator, n as createCrdtStorage, t as createCrdtSyncProducer, u as createImportData } from "./crdt-sync-producer-
|
|
4
|
-
import { o as HLCCounter, t as createCrdtSyncRemoteSource, u as xxhash } from "./crdt-sync-remote-source-
|
|
5
|
-
import { _ as createWasmSqliteDriver, d as isWorkerRequestMessage, h as verifySyncSchema, i as createResetStateStore, l as isWorkerInitMessage, m as syncDbWorkerLockName, n as createIdbResetStore, o as runWithNoActiveReplicas, p as syncDbClientLockName, r as createReloadRequestHandler, s as createBroadcastChannels } from "./reset-state-
|
|
6
|
-
import { i as runWorkerEventLogGc, n as createStorageVersionStore, t as createWsRemoteSource } from "./ws-remote-source-
|
|
3
|
+
import { a as formatSchemaVerificationIssues, c as createMigrator, n as createCrdtStorage, t as createCrdtSyncProducer, u as createImportData } from "./crdt-sync-producer-CUXiu4X3.js";
|
|
4
|
+
import { o as HLCCounter, t as createCrdtSyncRemoteSource, u as xxhash } from "./crdt-sync-remote-source-CH2bsr-x.js";
|
|
5
|
+
import { _ as createWasmSqliteDriver, d as isWorkerRequestMessage, h as verifySyncSchema, i as createResetStateStore, l as isWorkerInitMessage, m as syncDbWorkerLockName, n as createIdbResetStore, o as runWithNoActiveReplicas, p as syncDbClientLockName, r as createReloadRequestHandler, s as createBroadcastChannels } from "./reset-state-BeJZaX-W.js";
|
|
6
|
+
import { i as runWorkerEventLogGc, n as createStorageVersionStore, t as createWsRemoteSource } from "./ws-remote-source-CliRqkIW.js";
|
|
7
7
|
import sqlite3InitModule from "@sqlite.org/sqlite-wasm";
|
|
8
8
|
//#region src/worker-db/db-worker.ts
|
|
9
9
|
const defaultLogger = (type, message, level = "info") => {
|
|
@@ -82,7 +82,7 @@ async function createDbWorker(config, opts) {
|
|
|
82
82
|
if (!storageGeneration.current) storageGeneration.current = generateId();
|
|
83
83
|
if (pendingReset) await resetState.markResetApplied(pendingReset.epoch);
|
|
84
84
|
if (isVersionMismatch) await storageVersion.markCurrentVersionApplied();
|
|
85
|
-
if (opts.eventLogGc
|
|
85
|
+
if (opts.eventLogGc !== false) await runWithNoActiveReplicas({
|
|
86
86
|
dbId: config.dbId,
|
|
87
87
|
run: () => {
|
|
88
88
|
runWorkerEventLogGc({
|
|
@@ -193,6 +193,7 @@ async function createDbWorker(config, opts) {
|
|
|
193
193
|
sync: () => {
|
|
194
194
|
remoteSource.syncWithRemote().catch((error) => console.warn("Sync failed", error));
|
|
195
195
|
},
|
|
196
|
+
catchUp: (options) => remoteSource.catchUp(options, () => crdtStorage.internal.processEnqueuedEvents()),
|
|
196
197
|
requestReload: createReloadRequestHandler({
|
|
197
198
|
resetState,
|
|
198
199
|
broadcast: broadcastNotification
|