@sqlite-sync/core 0.4.3 → 0.4.5
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/index.d.ts +32 -1
- package/dist/index.js +124 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,21 @@ type EventsMap = {
|
|
|
24
24
|
"transaction-rolled-back": undefined;
|
|
25
25
|
"any-table-changed": undefined;
|
|
26
26
|
} & Record<`table:${string}`, void>;
|
|
27
|
+
type LiveQuery<TResult> = {
|
|
28
|
+
getRows: () => TResult[];
|
|
29
|
+
refresh: () => void;
|
|
30
|
+
subscribe: (onchange: () => void) => () => void;
|
|
31
|
+
};
|
|
32
|
+
type SharedLiveQuery<TResult> = LiveQuery<TResult> & {
|
|
33
|
+
readonly sql: string;
|
|
34
|
+
readonly parameters: readonly unknown[];
|
|
35
|
+
getSubscriberCount: () => number;
|
|
36
|
+
};
|
|
37
|
+
type SharedLiveQuerySnapshot = {
|
|
38
|
+
sql: string;
|
|
39
|
+
parameters: readonly unknown[];
|
|
40
|
+
subscriberCount: number;
|
|
41
|
+
};
|
|
27
42
|
declare class SQLiteReactiveDb<Database> {
|
|
28
43
|
readonly db: SQLiteDbWrapper<Database>;
|
|
29
44
|
private sqlite3;
|
|
@@ -33,6 +48,7 @@ declare class SQLiteReactiveDb<Database> {
|
|
|
33
48
|
private constructor();
|
|
34
49
|
static create<Database>(opts: SQLiteReactiveDbOptions): Promise<SQLiteReactiveDb<Database>>;
|
|
35
50
|
private liveQueryStatements;
|
|
51
|
+
private sharedLiveQueries;
|
|
36
52
|
createLiveQuery<TResult>(query: {
|
|
37
53
|
sql: string;
|
|
38
54
|
parameters: readonly unknown[];
|
|
@@ -41,6 +57,15 @@ declare class SQLiteReactiveDb<Database> {
|
|
|
41
57
|
refresh: (parameters?: readonly unknown[]) => void;
|
|
42
58
|
subscribe: (onchange: () => void) => () => void;
|
|
43
59
|
};
|
|
60
|
+
getSharedLiveQuery<TResult>(query: {
|
|
61
|
+
sql: string;
|
|
62
|
+
parameters: readonly unknown[];
|
|
63
|
+
}): SharedLiveQuery<TResult>;
|
|
64
|
+
private registerSharedLiveQueryEntry;
|
|
65
|
+
getSharedLiveQueriesSnapshot(): SharedLiveQuerySnapshot[];
|
|
66
|
+
private scheduleSharedLiveQueryCleanup;
|
|
67
|
+
private cancelSharedLiveQueryCleanup;
|
|
68
|
+
private releaseSharedLiveQuery;
|
|
44
69
|
subscribeToQueryChanges(params: {
|
|
45
70
|
sql: string;
|
|
46
71
|
onDataChange: () => void;
|
|
@@ -63,6 +88,7 @@ declare class SQLiteReactiveDb<Database> {
|
|
|
63
88
|
useSnapshot(snapshot: Uint8Array<ArrayBufferLike>): void;
|
|
64
89
|
dispose(): void;
|
|
65
90
|
}
|
|
91
|
+
declare function parametersAreEqual(a: readonly unknown[] | undefined, b: readonly unknown[] | undefined): boolean;
|
|
66
92
|
|
|
67
93
|
type KvStoreItem = {
|
|
68
94
|
key: string;
|
|
@@ -144,6 +170,10 @@ declare function createSyncedDb<Database, Props = undefined>(options: SyncedDbOp
|
|
|
144
170
|
refresh: (parameters?: readonly unknown[]) => void;
|
|
145
171
|
subscribe: (onchange: () => void) => () => void;
|
|
146
172
|
};
|
|
173
|
+
getSharedLiveQuery: <TResult>(query: {
|
|
174
|
+
sql: string;
|
|
175
|
+
parameters: readonly unknown[];
|
|
176
|
+
}) => SharedLiveQuery<TResult>;
|
|
147
177
|
};
|
|
148
178
|
state: {
|
|
149
179
|
getState: () => WorkerState;
|
|
@@ -199,6 +229,7 @@ declare function createSyncedDb<Database, Props = undefined>(options: SyncedDbOp
|
|
|
199
229
|
name: string;
|
|
200
230
|
isWrite: boolean;
|
|
201
231
|
}[];
|
|
232
|
+
getSharedLiveQueriesSnapshot: () => SharedLiveQuerySnapshot[];
|
|
202
233
|
crdtTableNames: string[];
|
|
203
234
|
crdtTablesConfig: CrdtTableConfig[];
|
|
204
235
|
schemaVersion: number;
|
|
@@ -207,4 +238,4 @@ declare function createSyncedDb<Database, Props = undefined>(options: SyncedDbOp
|
|
|
207
238
|
}>;
|
|
208
239
|
type SyncedDb<Database> = Awaited<ReturnType<typeof createSyncedDb<Database>>>;
|
|
209
240
|
|
|
210
|
-
export { CrdtStorage, type CrdtStorageMutator, ExecuteParams, ExecuteResult, InternalSQLiteWrapper, type KvStoreItem, KyselyQueryFactory, Logger, QueryBuilderOutput, SQLiteDbWrapper, SQLiteReactiveDb, SQLiteTransactionWrapper, StoredValue, SyncDbSchema, type SyncedDb, TypedEvent, WorkerState, createCrdtStorageMutator, createCrdtSyncProducer, createKvStoreTableQuery, createSQLiteKvStore, createSyncedDb, dummyKysely, makeCrdtTable, xxhash };
|
|
241
|
+
export { CrdtStorage, type CrdtStorageMutator, ExecuteParams, ExecuteResult, InternalSQLiteWrapper, type KvStoreItem, KyselyQueryFactory, Logger, QueryBuilderOutput, SQLiteDbWrapper, SQLiteReactiveDb, SQLiteTransactionWrapper, type SharedLiveQuery, type SharedLiveQuerySnapshot, StoredValue, SyncDbSchema, type SyncedDb, TypedEvent, WorkerState, createCrdtStorageMutator, createCrdtSyncProducer, createKvStoreTableQuery, createSQLiteKvStore, createSyncedDb, dummyKysely, makeCrdtTable, parametersAreEqual, xxhash };
|
package/dist/index.js
CHANGED
|
@@ -135,6 +135,7 @@ var SQLiteReactiveDb = class _SQLiteReactiveDb {
|
|
|
135
135
|
value.finalize();
|
|
136
136
|
}
|
|
137
137
|
});
|
|
138
|
+
sharedLiveQueries = /* @__PURE__ */ new Map();
|
|
138
139
|
createLiveQuery(query) {
|
|
139
140
|
const fetchRows = (parameters) => {
|
|
140
141
|
let statement = this.liveQueryStatements.get(query.sql);
|
|
@@ -176,6 +177,105 @@ var SQLiteReactiveDb = class _SQLiteReactiveDb {
|
|
|
176
177
|
};
|
|
177
178
|
return { getRows, refresh, subscribe };
|
|
178
179
|
}
|
|
180
|
+
getSharedLiveQuery(query) {
|
|
181
|
+
const existingEntry = this.sharedLiveQueries.get(query.sql)?.find((entry2) => parametersAreEqual(entry2.parameters, query.parameters));
|
|
182
|
+
if (existingEntry) {
|
|
183
|
+
if (existingEntry.listeners.size === 0) {
|
|
184
|
+
this.scheduleSharedLiveQueryCleanup(existingEntry);
|
|
185
|
+
}
|
|
186
|
+
return existingEntry;
|
|
187
|
+
}
|
|
188
|
+
const liveQuery = this.createLiveQuery(query);
|
|
189
|
+
let hasDetachedFromLiveQuery = false;
|
|
190
|
+
const entry = {
|
|
191
|
+
sql: query.sql,
|
|
192
|
+
parameters: query.parameters,
|
|
193
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
194
|
+
unsubscribeFromLiveQuery: null,
|
|
195
|
+
cleanupTimeout: null,
|
|
196
|
+
getRows: () => liveQuery.getRows(),
|
|
197
|
+
refresh: () => {
|
|
198
|
+
liveQuery.refresh();
|
|
199
|
+
},
|
|
200
|
+
getSubscriberCount: () => entry.listeners.size,
|
|
201
|
+
subscribe: (onchange) => {
|
|
202
|
+
this.cancelSharedLiveQueryCleanup(entry);
|
|
203
|
+
this.registerSharedLiveQueryEntry(entry);
|
|
204
|
+
entry.listeners.add(onchange);
|
|
205
|
+
if (!entry.unsubscribeFromLiveQuery) {
|
|
206
|
+
entry.unsubscribeFromLiveQuery = liveQuery.subscribe(() => {
|
|
207
|
+
for (const listener of entry.listeners) {
|
|
208
|
+
listener();
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
if (hasDetachedFromLiveQuery) {
|
|
212
|
+
hasDetachedFromLiveQuery = false;
|
|
213
|
+
liveQuery.refresh();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return () => {
|
|
217
|
+
entry.listeners.delete(onchange);
|
|
218
|
+
if (entry.listeners.size === 0) {
|
|
219
|
+
entry.unsubscribeFromLiveQuery?.();
|
|
220
|
+
entry.unsubscribeFromLiveQuery = null;
|
|
221
|
+
hasDetachedFromLiveQuery = true;
|
|
222
|
+
this.scheduleSharedLiveQueryCleanup(entry);
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
this.registerSharedLiveQueryEntry(entry);
|
|
228
|
+
this.scheduleSharedLiveQueryCleanup(entry);
|
|
229
|
+
return entry;
|
|
230
|
+
}
|
|
231
|
+
registerSharedLiveQueryEntry(entry) {
|
|
232
|
+
const matchingSqlEntries = this.sharedLiveQueries.get(entry.sql) ?? [];
|
|
233
|
+
if (!matchingSqlEntries.includes(entry)) {
|
|
234
|
+
matchingSqlEntries.push(entry);
|
|
235
|
+
this.sharedLiveQueries.set(entry.sql, matchingSqlEntries);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
getSharedLiveQueriesSnapshot() {
|
|
239
|
+
const snapshot = [];
|
|
240
|
+
for (const entries of this.sharedLiveQueries.values()) {
|
|
241
|
+
for (const entry of entries) {
|
|
242
|
+
snapshot.push({
|
|
243
|
+
sql: entry.sql,
|
|
244
|
+
parameters: entry.parameters,
|
|
245
|
+
subscriberCount: entry.listeners.size
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return snapshot;
|
|
250
|
+
}
|
|
251
|
+
scheduleSharedLiveQueryCleanup(entry) {
|
|
252
|
+
this.cancelSharedLiveQueryCleanup(entry);
|
|
253
|
+
entry.cleanupTimeout = setTimeout(() => {
|
|
254
|
+
entry.cleanupTimeout = null;
|
|
255
|
+
this.releaseSharedLiveQuery(entry);
|
|
256
|
+
}, 0);
|
|
257
|
+
}
|
|
258
|
+
cancelSharedLiveQueryCleanup(entry) {
|
|
259
|
+
if (entry.cleanupTimeout) {
|
|
260
|
+
clearTimeout(entry.cleanupTimeout);
|
|
261
|
+
entry.cleanupTimeout = null;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
releaseSharedLiveQuery(entry) {
|
|
265
|
+
if (entry.listeners.size > 0 || entry.unsubscribeFromLiveQuery) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const matchingSqlEntries = this.sharedLiveQueries.get(entry.sql);
|
|
269
|
+
if (!matchingSqlEntries) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
const nextEntries = matchingSqlEntries.filter((candidate) => candidate !== entry);
|
|
273
|
+
if (nextEntries.length > 0) {
|
|
274
|
+
this.sharedLiveQueries.set(entry.sql, nextEntries);
|
|
275
|
+
} else {
|
|
276
|
+
this.sharedLiveQueries.delete(entry.sql);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
179
279
|
subscribeToQueryChanges(params) {
|
|
180
280
|
const { sql, onDataChange } = params;
|
|
181
281
|
const tables = this.getTablesUsed(sql);
|
|
@@ -309,6 +409,15 @@ var SQLiteReactiveDb = class _SQLiteReactiveDb {
|
|
|
309
409
|
this.notifyTableSubscribers();
|
|
310
410
|
}
|
|
311
411
|
dispose() {
|
|
412
|
+
for (const entries of this.sharedLiveQueries.values()) {
|
|
413
|
+
for (const entry of entries) {
|
|
414
|
+
this.cancelSharedLiveQueryCleanup(entry);
|
|
415
|
+
entry.unsubscribeFromLiveQuery?.();
|
|
416
|
+
entry.unsubscribeFromLiveQuery = null;
|
|
417
|
+
entry.listeners.clear();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
this.sharedLiveQueries.clear();
|
|
312
421
|
this.liveQueryStatements.clear();
|
|
313
422
|
if (this.tablesUsedStatement) {
|
|
314
423
|
this.tablesUsedStatement.finalize();
|
|
@@ -337,6 +446,17 @@ function createDebouncedCallback(callback, delay) {
|
|
|
337
446
|
timeout = setTimeout(effect, delay);
|
|
338
447
|
};
|
|
339
448
|
}
|
|
449
|
+
function parametersAreEqual(a, b) {
|
|
450
|
+
if (a === b) return true;
|
|
451
|
+
if (!a || !b) return false;
|
|
452
|
+
if (a.length !== b.length) return false;
|
|
453
|
+
for (let i = 0; i < a.length; i++) {
|
|
454
|
+
if (!Object.is(a[i], b[i])) {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return true;
|
|
459
|
+
}
|
|
340
460
|
|
|
341
461
|
// src/sqlite-crdt/crdt-schema.ts
|
|
342
462
|
function createSyncDbSchema({ migrations }) {
|
|
@@ -936,7 +1056,8 @@ async function createSyncedDb(options) {
|
|
|
936
1056
|
execute: reactiveDb.db.execute.bind(reactiveDb.db),
|
|
937
1057
|
executeKysely: reactiveDb.db.executeKysely.bind(reactiveDb.db),
|
|
938
1058
|
executeTransaction: reactiveDb.db.executeTransaction.bind(reactiveDb.db),
|
|
939
|
-
createLiveQuery: reactiveDb.createLiveQuery.bind(reactiveDb)
|
|
1059
|
+
createLiveQuery: reactiveDb.createLiveQuery.bind(reactiveDb),
|
|
1060
|
+
getSharedLiveQuery: reactiveDb.getSharedLiveQuery.bind(reactiveDb)
|
|
940
1061
|
},
|
|
941
1062
|
state: {
|
|
942
1063
|
getState: workerClient.getState.bind(workerClient),
|
|
@@ -967,6 +1088,7 @@ async function createSyncedDb(options) {
|
|
|
967
1088
|
_internal: {
|
|
968
1089
|
executeAsync: workerClient.execute.bind(workerClient),
|
|
969
1090
|
getMemoryQueryTables: reactiveDb.getTablesUsed.bind(reactiveDb),
|
|
1091
|
+
getSharedLiveQueriesSnapshot: reactiveDb.getSharedLiveQueriesSnapshot.bind(reactiveDb),
|
|
970
1092
|
crdtTableNames: options.syncDbSchema.tablesConfig.map((table) => table.crdtTableName),
|
|
971
1093
|
crdtTablesConfig: options.syncDbSchema.tablesConfig,
|
|
972
1094
|
schemaVersion: workerClientSnapshot.schemaVersion,
|
|
@@ -1016,6 +1138,7 @@ export {
|
|
|
1016
1138
|
isNoOpCrdtEventPayload,
|
|
1017
1139
|
jsonSafeParse,
|
|
1018
1140
|
makeCrdtTable,
|
|
1141
|
+
parametersAreEqual,
|
|
1019
1142
|
quoteId,
|
|
1020
1143
|
runSystemMigrations,
|
|
1021
1144
|
serializeHLC,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/memory-db/sqlite-reactive-db.ts","../src/bound-map.ts","../src/sqlite-crdt/crdt-schema.ts","../src/sqlite-crdt/crdt-storage-mutator.ts","../src/sqlite-crdt/make-crdt-table.ts","../src/db-id.ts","../src/devtools-registry.ts","../src/memory-db/memory-db.ts","../src/worker-db/db-worker-client.ts","../src/sync-db.ts"],"sourcesContent":["import sqlite3InitModule, { type Sqlite3Static } from \"@sqlite.org/sqlite-wasm\";\nimport { BoundMap } from \"../bound-map\";\nimport { type Logger, startPerformanceLogger } from \"../logger\";\nimport { type PreparedStatement, SQLiteDbWrapper } from \"../sqlite-db-wrapper\";\nimport { createTypedEventTarget, type TypedEvent } from \"../utils\";\n\nlet sqliteModule: Sqlite3Static | null = null;\n\ntype TableName<Database> = keyof Database extends string ? keyof Database : never;\n\ntype SQLiteReactiveDbOptions = {\n snapshot: Uint8Array<ArrayBufferLike>;\n logger: Logger;\n};\n\ntype EventsMap = {\n \"transaction-committed\": undefined;\n \"transaction-rolled-back\": undefined;\n \"any-table-changed\": undefined;\n} & Record<`table:${string}`, void>;\n\nexport function createSQLiteReactiveDb<Database>(opts: SQLiteReactiveDbOptions) {\n return SQLiteReactiveDb.create<Database>(opts);\n}\n\nexport class SQLiteReactiveDb<Database> {\n readonly db: SQLiteDbWrapper<Database>;\n private sqlite3: Sqlite3Static;\n\n private readonly logger: Logger;\n\n private tablesUsedStatement: PreparedStatement<[string], { name: string; isWrite: boolean }> | null = null;\n\n private eventTarget = createTypedEventTarget<EventsMap>();\n\n private constructor(sqlite3: Sqlite3Static, logger: Logger) {\n this.sqlite3 = sqlite3;\n this.logger = logger;\n\n this.db = new SQLiteDbWrapper({\n db: () => new sqlite3.oo1.DB({ filename: \":memory:\" }),\n logger: this.logger,\n loggerPrefix: \"memory\",\n sqlite3,\n });\n }\n\n static async create<Database>(opts: SQLiteReactiveDbOptions) {\n const logger = opts.logger;\n const perf = startPerformanceLogger(logger);\n if (!sqliteModule) {\n sqliteModule = await sqlite3InitModule();\n }\n\n const db = new SQLiteReactiveDb<Database>(sqliteModule, logger);\n\n if (opts.snapshot) {\n db.useSnapshot(opts.snapshot);\n }\n db.registerDbHooks();\n\n perf.logEnd(\"createSQLiteMemoryDb\", \"success\", \"system\");\n\n return db;\n }\n\n private liveQueryStatements = new BoundMap<string, PreparedStatement<any[], unknown>>({\n maxSize: 100,\n onRemove(_, value) {\n value.finalize();\n },\n });\n\n createLiveQuery<TResult>(query: { sql: string; parameters: readonly unknown[] }) {\n const fetchRows = (parameters: readonly unknown[]) => {\n let statement = this.liveQueryStatements.get(query.sql);\n if (!statement) {\n statement = this.db.prepare<any[], any>(query.sql);\n this.liveQueryStatements.set(query.sql, statement);\n }\n return statement.execute(parameters as any) as TResult[];\n };\n\n let rows: TResult[] | null = null;\n\n const getRows = () => {\n if (!rows) {\n rows = fetchRows(query.parameters);\n }\n return rows;\n };\n\n let subscriber: (() => void) | null = null;\n\n let lastParameters: readonly unknown[] = query.parameters;\n const refresh = (parameters?: readonly unknown[]) => {\n if (parameters) {\n lastParameters = parameters;\n }\n rows = fetchRows(lastParameters);\n subscriber?.();\n };\n\n const subscribe = (onchange: () => void) => {\n if (subscriber) {\n throw new Error(\"Subscriber already exists\");\n }\n\n subscriber = onchange;\n const subscription = this.subscribeToQueryChanges({\n sql: query.sql,\n onDataChange: refresh,\n });\n\n return () => {\n subscription.unsubscribe();\n subscriber = null;\n };\n };\n\n return { getRows, refresh, subscribe };\n }\n\n subscribeToQueryChanges(params: { sql: string; onDataChange: () => void }) {\n const { sql, onDataChange } = params;\n\n const tables = this.getTablesUsed(sql);\n const readTables = new Set<string>();\n for (const table of tables) {\n if (!readTables.has(table.name)) {\n readTables.add(table.name);\n } else if (table.isWrite) {\n throw new Error(\"This query writes and reads from the same table. This may cause infinite loops.\");\n }\n }\n\n const notifyDataChange = createDebouncedCallback(() => {\n onDataChange();\n }, 30);\n\n for (const table of readTables) {\n this.eventTarget.addEventListener(`table:${table}`, notifyDataChange);\n }\n this.eventTarget.addEventListener(\"any-table-changed\", notifyDataChange);\n\n return {\n unsubscribe: () => {\n for (const table of readTables) {\n this.eventTarget.removeEventListener(`table:${table}`, notifyDataChange);\n }\n this.eventTarget.removeEventListener(\"any-table-changed\", notifyDataChange);\n },\n };\n }\n\n subscribeToTableChanges(table: string, onChanges: () => void) {\n this.eventTarget.addEventListener(`table:${table}`, onChanges);\n this.eventTarget.addEventListener(\"any-table-changed\", onChanges);\n return {\n unsubscribe: () => {\n this.eventTarget.removeEventListener(`table:${table}`, onChanges);\n this.eventTarget.removeEventListener(\"any-table-changed\", onChanges);\n },\n };\n }\n\n getTablesUsed(query: string) {\n if (!this.tablesUsedStatement) {\n this.tablesUsedStatement = this.db.prepare<[string], { name: string; isWrite: boolean }>(\n \"select t.tbl_name as name, u.wr as isWrite from tables_used(?) as u inner join sqlite_master as t on t.name = u.name where u.schema = 'main'\",\n { loggerLevel: \"system\" },\n );\n }\n\n const tables = this.tablesUsedStatement.execute([query]);\n\n if (tables.length === 0 && query.toLowerCase().includes(\"delete\")) {\n // tables_used function does not work with delete queries that clear entire tables\n tables.push(...this.getClearedTables(query));\n }\n\n return tables;\n }\n\n private getClearedTables(query: string) {\n const operations = this.db.execute<{\n opcode: string;\n p1: number;\n p2: number;\n }>(`EXPLAIN ${query.split(\";\")[0]}`, { loggerLevel: \"system\" }).rows;\n\n const clearedTablesRootPages = new Set<number>();\n for (const operation of operations) {\n if (operation.opcode === \"Clear\" && operation.p2 === 0) {\n clearedTablesRootPages.add(operation.p1);\n }\n }\n\n if (clearedTablesRootPages.size === 0) {\n return [];\n }\n\n const tableNames = this.db.execute<{ name: string; isWrite: boolean }>(\n `select t.tbl_name as name, true as isWrite from sqlite_master as t where t.rootpage in (${Array.from(\n clearedTablesRootPages,\n ).join(\",\")})`,\n { loggerLevel: \"system\" },\n ).rows;\n\n return tableNames;\n }\n\n addEventListener<K extends keyof EventsMap>(type: K, listener: (event: TypedEvent<EventsMap[K]>) => void) {\n this.eventTarget.addEventListener(type, listener);\n }\n\n removeEventListener<K extends keyof EventsMap>(type: K, listener: (event: TypedEvent<EventsMap[K]>) => void) {\n this.eventTarget.removeEventListener(type, listener);\n }\n\n private notifyTableSubscribers(tables: (TableName<Database> | (string & {}))[] | Set<string> | null = null) {\n if (!tables) {\n this.eventTarget.dispatchEvent(\"any-table-changed\", undefined);\n return;\n }\n\n for (const table of tables) {\n this.eventTarget.dispatchEvent(`table:${table}`, undefined);\n }\n }\n\n private registerDbHooks() {\n let updateQueue = new Set<string>();\n\n this.sqlite3.capi.sqlite3_update_hook(\n this.db.ensureDb,\n (_ctx, _opId, _db, table) => {\n updateQueue.add(table);\n },\n 0,\n );\n\n this.sqlite3.capi.sqlite3_rollback_hook(\n this.db.ensureDb,\n () => {\n if (updateQueue.size === 0) {\n return 0;\n }\n\n updateQueue.clear();\n this.eventTarget.dispatchEvent(\"transaction-rolled-back\", undefined);\n\n return 0;\n },\n 0,\n );\n\n this.sqlite3.capi.sqlite3_commit_hook(\n this.db.ensureDb,\n () => {\n if (updateQueue.size === 0) {\n return 0;\n }\n\n const tables = updateQueue;\n updateQueue = new Set<string>();\n this.eventTarget.dispatchEvent(\"transaction-committed\", undefined);\n\n queueMicrotask(() => {\n this.notifyTableSubscribers(tables);\n });\n return 0;\n },\n 0,\n );\n }\n\n createSnapshot() {\n const perf = startPerformanceLogger(this.logger);\n const snapshot = this.sqlite3.capi.sqlite3_js_db_export(this.db.ensureDb);\n perf.logEnd(\"createSnapshot\", `snapshot size: ${snapshot.byteLength}`, \"info\");\n\n return snapshot;\n }\n\n useSnapshot(snapshot: Uint8Array<ArrayBufferLike>) {\n this.db.useSnapshot(snapshot);\n this.notifyTableSubscribers();\n }\n\n dispose() {\n this.liveQueryStatements.clear();\n if (this.tablesUsedStatement) {\n this.tablesUsedStatement.finalize();\n this.tablesUsedStatement = null;\n }\n this.db.close();\n }\n}\n\nfunction createDebouncedCallback<TArgs extends unknown[]>(callback: (...args: TArgs) => void, delay: number) {\n let timeout: unknown | null = null;\n let shouldCallWithoutDelay = true;\n\n return (...args: TArgs) => {\n if (shouldCallWithoutDelay) {\n callback(...args);\n shouldCallWithoutDelay = false;\n return;\n }\n\n const effect = () => {\n timeout = null;\n shouldCallWithoutDelay = true;\n return callback(...args);\n };\n\n if (timeout) {\n clearTimeout(timeout as any);\n }\n\n timeout = setTimeout(effect, delay);\n };\n}\n","interface BoundMapOptions<K, V> {\n maxSize: number;\n onRemove: ((key: K, value: V) => void) | undefined;\n}\n\nexport class BoundMap<K, V> {\n private map = new Map<K, V>();\n private maxSize: number;\n private onRemove: ((key: K, value: V) => void) | undefined;\n\n constructor(opts: BoundMapOptions<K, V>) {\n this.maxSize = opts.maxSize;\n this.onRemove = opts.onRemove;\n }\n\n set = (key: K, value: V) => {\n if (this.onRemove && this.map.has(key)) {\n const old = this.map.get(key) as V;\n this.map.set(key, value);\n this.onRemove(key, old);\n } else {\n this.map.set(key, value);\n }\n if (this.map.size > this.maxSize) {\n const firstKey = this.map.keys().next().value as K;\n this.delete(firstKey);\n }\n };\n\n get = (key: K): V | undefined => {\n return this.map.get(key);\n };\n\n delete = (key: K) => {\n if (this.onRemove && this.map.has(key)) {\n const value = this.map.get(key) as V;\n this.map.delete(key);\n this.onRemove(key, value);\n } else {\n this.map.delete(key);\n }\n };\n\n clear = () => {\n const onRemove = this.onRemove;\n if (onRemove) {\n this.map.forEach((value, key) => {\n onRemove(key, value);\n });\n }\n this.map.clear();\n };\n}\n","import type { ColumnType } from \"kysely\";\nimport type { Migrations } from \"../migrations/migrator\";\n\nexport type CrdtTableConfig = {\n baseTableName: string;\n crdtTableName: string;\n};\n\nexport function createSyncDbSchema({ migrations }: { migrations: Migrations }) {\n return new CrdtSchemaBuilder({ tables: [], migrations });\n}\n\nexport interface CreateCrdtSchemaOptions {\n tables: CrdtTableConfig[];\n migrations: Migrations;\n}\n\n// biome-ignore lint/complexity/noBannedTypes: required generic\nclass CrdtSchemaBuilder<ClientDB = {}, ServerDB = {}, MutationsDB = {}>\n implements SyncDbSchema<ClientDB, ServerDB, MutationsDB>\n{\n constructor(private config: CreateCrdtSchemaOptions) {}\n\n get tablesConfig() {\n return this.config.tables;\n }\n\n get migrations() {\n return this.config.migrations;\n }\n\n get \"~clientSchema\"() {\n console.warn(\"~clientSchema should not be accessed on the client\");\n return null as any;\n }\n\n get \"~serverSchema\"() {\n console.warn(\"~serverSchema should not be accessed on the server\");\n return null as any;\n }\n\n get \"~mutationsSchema\"() {\n console.warn(\"~mutationsSchema should not be accessed on the client\");\n return null as any;\n }\n\n addTable<Table extends Record<string, unknown>>() {\n const withConfig = <const CrdtTable extends string, const BaseTable extends string>({\n baseTableName,\n crdtTableName,\n }: {\n baseTableName: BaseTable;\n crdtTableName: CrdtTable;\n }) => {\n this.config.tables.push({ baseTableName, crdtTableName });\n return new CrdtSchemaBuilder<\n ClientDB & { [K in CrdtTable]: Table } & { [K in BaseTable]: ReadonlyTable<Table> },\n ServerDB & { [K in BaseTable]: ReadonlyTable<Table> },\n MutationsDB & { [K in BaseTable]: Table }\n >(this.config);\n };\n\n return { withConfig };\n }\n\n build() {\n return this as SyncDbSchema<ClientDB, ServerDB, MutationsDB>;\n }\n}\n\n// biome-ignore lint/complexity/noBannedTypes: required generic\nexport interface SyncDbSchema<ClientDB = {}, ServerDB = {}, MutationsDB = {}> {\n get tablesConfig(): CrdtTableConfig[];\n get migrations(): Migrations;\n \"~clientSchema\": ClientDB;\n \"~serverSchema\": ServerDB;\n \"~mutationsSchema\": MutationsDB;\n}\n\ntype ReadonlyTable<Table extends Record<string, unknown>> = {\n [K in keyof Table]: ColumnType<Table[K], never, never>;\n};\n","import type { CrdtStorage, OwnCrdtEvent } from \"./crdt-storage\";\n\nexport type CrdtStorageMutator<Database> = ReturnType<typeof createCrdtStorageMutator<Database>>;\n\ntype CommitEventOptions<Database, Table extends keyof Database & string> =\n | {\n type: \"item-created\";\n dataset: Table;\n item_id: string;\n payload: CreateEventPayload<Database, Table>;\n }\n | {\n type: \"item-updated\";\n dataset: Table;\n item_id: string;\n payload: UpdateEventPayload<Database, Table>;\n }\n | {\n type: \"item-deleted\";\n dataset: Table;\n item_id: string;\n };\n\ntype CreateEventPayload<Database, Table extends keyof Database> = Omit<Database[Table], \"tombstone\">;\ntype UpdateEventPayload<Database, Table extends keyof Database> = Omit<Partial<Database[Table]>, \"id\" | \"tombstone\">;\n\nexport function createCrdtStorageMutator<Database>({ storage }: { storage: CrdtStorage }) {\n const mapToStorageEvent = (event: CommitEventOptions<Database, keyof Database & string>): OwnCrdtEvent => {\n switch (event.type) {\n case \"item-created\":\n return {\n type: \"item-created\",\n dataset: event.dataset,\n item_id: event.item_id,\n payload: JSON.stringify(event.payload),\n };\n case \"item-updated\":\n return {\n type: \"item-updated\",\n dataset: event.dataset,\n item_id: event.item_id,\n payload: JSON.stringify(event.payload),\n };\n case \"item-deleted\":\n return {\n type: \"item-deleted\",\n dataset: event.dataset,\n item_id: event.item_id,\n payload: \"{}\",\n };\n }\n };\n\n const enqueueEvents = (events: CommitEventOptions<Database, keyof Database & string>[]) => {\n storage.enqueueOwnEvents(events.map(mapToStorageEvent));\n };\n\n const createEvent = <Table extends keyof Database & string>(event: CommitEventOptions<Database, Table>) => {\n return event;\n };\n\n const enqueueEvent = (event: CommitEventOptions<Database, keyof Database & string>) => {\n storage.enqueueOwnEvents([mapToStorageEvent(event)]);\n };\n\n return {\n enqueueEvents,\n createEvent,\n enqueueEvent,\n };\n}\n","import type { SQLiteReactiveDb } from \"../memory-db/sqlite-reactive-db\";\nimport type { SQLiteDbWrapper } from \"../sqlite-db-wrapper\";\nimport { quoteId } from \"../utils\";\nimport type { CrdtStorage } from \"./crdt-storage\";\n\nexport function makeCrdtTable({\n db,\n baseTableName,\n crdtTableName,\n}: {\n db: SQLiteDbWrapper<any>;\n baseTableName: string;\n crdtTableName: string;\n}) {\n const tableSchema = db.dbSchema[baseTableName];\n\n if (!tableSchema) {\n throw new Error(`Table ${baseTableName} not found`);\n }\n\n const columns = new Map(tableSchema.columns.map((c) => [c.name, c]));\n\n const idColumn = columns.get(\"id\");\n if (!idColumn) {\n throw new Error(\n `Table \"${baseTableName}\" is missing a required \"id\" column. CRDT tables must have an \"id\" column to identify items.`,\n );\n }\n if (idColumn.dataType.toUpperCase() !== \"TEXT\") {\n throw new Error(\n `Table \"${baseTableName}\": \"id\" column must be of type TEXT, got \"${idColumn.dataType}\". CRDT item IDs are stored as strings.`,\n );\n }\n\n const tombstoneColumn = columns.get(\"tombstone\");\n if (!tombstoneColumn) {\n throw new Error(\n `Table \"${baseTableName}\" is missing a required \"tombstone\" column. CRDT tables must have a \"tombstone\" INTEGER column for soft deletes.`,\n );\n }\n const tombstoneType = tombstoneColumn.dataType.toUpperCase();\n if (tombstoneType !== \"INTEGER\" && tombstoneType !== \"BOOLEAN\") {\n throw new Error(\n `Table \"${baseTableName}\": \"tombstone\" column must be of type INTEGER or BOOLEAN, got \"${tombstoneColumn.dataType}\". It is compared as 0/1 for soft deletes.`,\n );\n }\n\n db.execute(\n `\ncreate view ${quoteId(crdtTableName)} as\nselect * from ${quoteId(baseTableName)}\nwhere tombstone = 0;`,\n { loggerLevel: \"system\" },\n );\n\n const allColumnNames = tableSchema.columns.map((column) => column.name);\n\n const jsonPayload = (from: \"new\" | \"old\") =>\n `'{'||${allColumnNames.map((col) => `'\"${col}\":'||json_quote(${from}.${quoteId(col)})`).join(\"||','||\")}||'}'`;\n\n db.execute(\n `\ncreate trigger ${quoteId(`${crdtTableName}_created`)}\ninstead of insert on ${quoteId(crdtTableName)}\nfor each row\nbegin\nselect handle_item_created('${baseTableName}', ${jsonPayload(\"new\")});\nend;\n`,\n { loggerLevel: \"system\" },\n );\n\n db.execute(\n `\ncreate trigger ${quoteId(`${crdtTableName}_updated`)}\ninstead of update on ${quoteId(crdtTableName)}\nfor each row\nbegin\nselect handle_item_updated(\n '${baseTableName}',\n ${jsonPayload(\"old\")},\n ${jsonPayload(\"new\")}\n);\nend;\n`,\n { loggerLevel: \"system\" },\n );\n\n db.execute(\n `\ncreate trigger ${quoteId(`${crdtTableName}_deleted`)}\ninstead of delete on ${quoteId(crdtTableName)}\nfor each row\nwhen old.tombstone = 0\nbegin\nselect handle_item_deleted('${baseTableName}', old.id);\nend;\n`,\n { loggerLevel: \"system\" },\n );\n}\n\nexport function registerCrdtFunctions({\n reactiveDb,\n storage,\n}: {\n reactiveDb: SQLiteReactiveDb<any>;\n storage: CrdtStorage;\n}) {\n let eventApplied = false;\n\n reactiveDb.db.createScalarFunction({\n name: \"handle_item_created\",\n deterministic: false,\n directOnly: false,\n innocuous: false,\n callback: (dataset: string, payloadRaw: string) => {\n const payload = JSON.parse(payloadRaw) as { id: string };\n\n storage.applyOwnEvent(\n {\n type: \"item-created\",\n dataset,\n item_id: payload.id,\n payload: payloadRaw,\n },\n {\n wrapInTransaction: false,\n },\n );\n\n eventApplied = true;\n return undefined;\n },\n });\n\n reactiveDb.db.createScalarFunction({\n name: \"handle_item_updated\",\n deterministic: false,\n directOnly: false,\n innocuous: false,\n callback: (dataset: string, oldPayloadRaw: string, newPayloadRaw: string) => {\n if (oldPayloadRaw === newPayloadRaw) {\n return undefined;\n }\n\n const tableSchema = reactiveDb.db.dbSchema[dataset];\n\n if (!tableSchema?.columns) {\n throw new Error(`Schema not found for dataset: ${dataset}`);\n }\n\n const oldPayload = JSON.parse(oldPayloadRaw);\n const newPayload = JSON.parse(newPayloadRaw);\n\n let hasDiff = false;\n const updatePayload = {} as Record<string, unknown>;\n\n for (const column of tableSchema.columns) {\n const oldValue = oldPayload[column.name];\n const newValue = newPayload[column.name];\n if (oldValue === newValue) {\n continue;\n }\n\n if (column.name === \"id\") {\n throw new Error(\n `Cannot update the \"id\" column of an item. It is used to identify the item and must be immutable.`,\n );\n }\n\n hasDiff = true;\n updatePayload[column.name] = newValue;\n }\n\n if (!hasDiff) {\n return;\n }\n\n storage.applyOwnEvent(\n {\n type: \"item-updated\",\n dataset,\n item_id: oldPayload.id,\n payload: JSON.stringify(updatePayload),\n },\n {\n wrapInTransaction: false,\n },\n );\n\n eventApplied = true;\n return undefined;\n },\n });\n\n reactiveDb.db.createScalarFunction({\n name: \"handle_item_deleted\",\n deterministic: false,\n directOnly: false,\n innocuous: false,\n callback: (dataset: string, itemId: string) => {\n storage.applyOwnEvent(\n {\n type: \"item-deleted\",\n dataset,\n item_id: itemId,\n payload: \"{}\",\n },\n {\n wrapInTransaction: false,\n },\n );\n\n eventApplied = true;\n return undefined;\n },\n });\n\n reactiveDb.addEventListener(\"transaction-committed\", () => {\n if (eventApplied) {\n eventApplied = false;\n storage.dispatchEventsApplied();\n }\n });\n\n reactiveDb.addEventListener(\"transaction-rolled-back\", () => {\n eventApplied = false;\n });\n}\n","const dbIdRegex = /^[a-zA-Z][a-zA-Z\\-0-9]{2,63}$/;\n\nexport function validateDbId(dbId: string) {\n if (!dbIdRegex.test(dbId)) {\n throw new Error(\"Invalid dbId. Must be between 3 and 64 characters long and start with a letter.\");\n }\n}\n","import type { SyncedDb } from \"./sync-db\";\n\nconst devtoolsRegistrySymbol = Symbol.for(\"@sqlite-sync/devtools\");\n\nexport type SQLiteSyncDevtoolsInstance = {\n instanceId: string;\n dbId: string;\n createdAt: number;\n instance: SyncedDb<any>;\n};\n\nexport type SQLiteSyncDevtoolsSnapshot = {\n instances: readonly SQLiteSyncDevtoolsInstance[];\n};\n\nexport type SQLiteSyncDevtoolsRegistry = {\n version: 1;\n instances: Map<string, SQLiteSyncDevtoolsInstance>;\n subscribe(listener: () => void): () => void;\n getSnapshot(): SQLiteSyncDevtoolsSnapshot;\n register(instance: SQLiteSyncDevtoolsInstance): () => void;\n};\n\ntype RegistryGlobal = typeof globalThis & {\n [key: symbol]: SQLiteSyncDevtoolsRegistry | undefined;\n};\n\nfunction createSQLiteSyncDevtoolsRegistry(): SQLiteSyncDevtoolsRegistry {\n const instances = new Map<string, SQLiteSyncDevtoolsInstance>();\n const listeners = new Set<() => void>();\n let snapshot: SQLiteSyncDevtoolsSnapshot = {\n instances: [],\n };\n\n const notify = () => {\n for (const listener of listeners) {\n listener();\n }\n };\n\n const updateSnapshot = () => {\n snapshot = {\n instances: Array.from(instances.values()),\n };\n notify();\n };\n\n return {\n version: 1,\n instances,\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n getSnapshot() {\n return snapshot;\n },\n register(instance) {\n instances.set(instance.instanceId, instance);\n updateSnapshot();\n\n let isUnregistered = false;\n return () => {\n if (isUnregistered) return;\n isUnregistered = true;\n\n if (!instances.delete(instance.instanceId)) return;\n updateSnapshot();\n };\n },\n };\n}\n\nexport function getOrCreateSQLiteSyncDevtoolsRegistry(): SQLiteSyncDevtoolsRegistry {\n const registryGlobal = globalThis as RegistryGlobal;\n\n registryGlobal[devtoolsRegistrySymbol] ??= createSQLiteSyncDevtoolsRegistry();\n\n return registryGlobal[devtoolsRegistrySymbol];\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 } from \"../sqlite-crdt/crdt-schema\";\nimport { createCrdtStorage } from \"../sqlite-crdt/crdt-storage\";\nimport { makeCrdtTable, registerCrdtFunctions } from \"../sqlite-crdt/make-crdt-table\";\nimport type { StoredValue } from \"../sqlite-crdt/stored-value\";\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 eventHlcAccumulator?: StoredValue<string>;\n};\n\nexport async function createMemoryDb<Database>({\n nodeId,\n migrator,\n reactiveDb: _reactiveDb,\n hlcCounter,\n crdtTables,\n initializeSchema = true,\n initialSyncId,\n eventHlcAccumulator,\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 eventHlcAccumulator,\n });\n\n registerCrdtFunctions({\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 WorkerNotificationMessage,\n WorkerRequestMessage,\n WorkerRequestMethod,\n WorkerResponseMessage,\n WorkerRpc,\n WorkerState,\n} from \"./worker-common\";\nimport { isWorkerErrorResponseMessage, isWorkerNotificationMessage, isWorkerResponseMessage } from \"./worker-common\";\n\ntype NotificationEvents = {\n [K in WorkerNotificationMessage[\"notificationType\"]]: Extract<WorkerNotificationMessage, { notificationType: K }>;\n};\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 promise = createDeferredPromise<unknown>({\n timeout: 30_000,\n onTimeout: () => workerRequestsMap.delete(requestId),\n });\n workerRequestsMap.set(requestId, promise);\n\n const request: WorkerRequestMessage<TMethod> = {\n type: \"request\",\n requestId,\n method,\n args,\n };\n\n broadcastChannels.requests.postMessage(request);\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 pushTabEvents: (request) => queryWorker(\"pushTabEvents\", [request]),\n pullEvents: (params) => queryWorker(\"pullEvents\", [params]),\n postState: () => queryWorker(\"postState\", []),\n goOnline: () => queryWorker(\"goOnline\", []),\n goOffline: () => queryWorker(\"goOffline\", []),\n requestReload: (options) => queryWorker(\"requestReload\", [options]),\n };\n\n const statePromise = awaitWorkerState(eventTarget);\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 workerState = await statePromise;\n\n eventTarget.addEventListener(\"state-changed\", (event) => {\n workerState = event.payload.state;\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 return {\n ...rpc,\n subscribe: eventTarget.addEventListener,\n getState: () => workerState,\n dispose,\n };\n};\n\nfunction awaitWorkerState(eventTarget: TypedEventTarget<NotificationEvents>) {\n const promise = createDeferredPromise<WorkerState>({ timeout: 15_000 });\n\n const subscription = eventTarget.addEventListener(\"state-changed\", (event) => {\n promise.resolve(event.payload.state);\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 { HLCCounter } from \"./hlc\";\nimport { type Logger, startPerformanceLogger } from \"./logger\";\nimport { createMemoryDb } from \"./memory-db/memory-db\";\nimport { createSQLiteReactiveDb } from \"./memory-db/sqlite-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 { createDeferredPromise, generateId } from \"./utils\";\nimport { createWorkerDbClient } from \"./worker-db/db-worker-client\";\nimport { createBroadcastChannels, syncDbClientLockName } from \"./worker-db/worker-common\";\n\ntype SyncedDbOptions<Database, Props = undefined> = {\n dbId: string;\n worker: Worker;\n workerProps: Props;\n syncDbSchema: SyncDbSchema<Database>;\n};\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 const clientLockAcquired = createDeferredPromise<void>();\n const clientLockRelease = createDeferredPromise<void>();\n navigator.locks.request(`${syncDbClientLockName}-${options.dbId}`, { mode: \"shared\" }, () => {\n clientLockAcquired.resolve();\n return clientLockRelease.promise;\n });\n await clientLockAcquired.promise;\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\n const hlcCounter = new HLCCounter(tabId, () => Date.now());\n\n const workerClientSnapshot = await workerClient.getSnapshot();\n const reactiveDb = await createSQLiteReactiveDb<Database>({\n snapshot: workerClientSnapshot.file,\n logger: defaultLogger,\n });\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 });\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, remoteEventHlcSum: event.payload.eventHlcSum });\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 tabRemoteSource.goOnline();\n\n const reloadRequestedSubscription = workerClient.subscribe(\"reload-requested\", () => {\n globalThis.location?.reload();\n });\n\n perf.logEnd(\"createSyncedDb\", \"initialized\", \"info\");\n\n let isDisposed = false;\n let unregisterDevtools: (() => void) | undefined;\n const dispose = async () => {\n if (isDisposed) return;\n isDisposed = true;\n\n unregisterDevtools?.();\n reloadRequestedSubscription.unsubscribe();\n clientLockRelease.resolve();\n await tabRemoteSource.dispose();\n broadcastChannels.requests.close();\n broadcastChannels.responses.close();\n workerClient.dispose();\n reactiveDb.dispose();\n };\n\n const syncedDb = {\n db: {\n execute: reactiveDb.db.execute.bind(reactiveDb.db),\n executeKysely: reactiveDb.db.executeKysely.bind(reactiveDb.db),\n executeTransaction: reactiveDb.db.executeTransaction.bind(reactiveDb.db),\n createLiveQuery: reactiveDb.createLiveQuery.bind(reactiveDb),\n },\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 },\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 dispose,\n _internal: {\n executeAsync: workerClient.execute.bind(workerClient),\n getMemoryQueryTables: reactiveDb.getTablesUsed.bind(reactiveDb),\n crdtTableNames: options.syncDbSchema.tablesConfig.map((table) => table.crdtTableName),\n crdtTablesConfig: options.syncDbSchema.tablesConfig,\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}\n\nexport type SyncedDb<Database> = Awaited<ReturnType<typeof createSyncedDb<Database>>>;\n"],"mappings":"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","names":["options"]}
|
|
1
|
+
{"version":3,"sources":["../src/memory-db/sqlite-reactive-db.ts","../src/bound-map.ts","../src/sqlite-crdt/crdt-schema.ts","../src/sqlite-crdt/crdt-storage-mutator.ts","../src/sqlite-crdt/make-crdt-table.ts","../src/db-id.ts","../src/devtools-registry.ts","../src/memory-db/memory-db.ts","../src/worker-db/db-worker-client.ts","../src/sync-db.ts"],"sourcesContent":["import sqlite3InitModule, { type Sqlite3Static } from \"@sqlite.org/sqlite-wasm\";\nimport { BoundMap } from \"../bound-map\";\nimport { type Logger, startPerformanceLogger } from \"../logger\";\nimport { type PreparedStatement, SQLiteDbWrapper } from \"../sqlite-db-wrapper\";\nimport { createTypedEventTarget, type TypedEvent } from \"../utils\";\n\nlet sqliteModule: Sqlite3Static | null = null;\n\ntype TableName<Database> = keyof Database extends string ? keyof Database : never;\n\ntype SQLiteReactiveDbOptions = {\n snapshot: Uint8Array<ArrayBufferLike>;\n logger: Logger;\n};\n\ntype EventsMap = {\n \"transaction-committed\": undefined;\n \"transaction-rolled-back\": undefined;\n \"any-table-changed\": undefined;\n} & Record<`table:${string}`, void>;\n\ntype LiveQuery<TResult> = {\n getRows: () => TResult[];\n refresh: () => void;\n subscribe: (onchange: () => void) => () => void;\n};\n\nexport type SharedLiveQuery<TResult> = LiveQuery<TResult> & {\n readonly sql: string;\n readonly parameters: readonly unknown[];\n getSubscriberCount: () => number;\n};\n\ntype SharedLiveQueryEntry<TResult> = SharedLiveQuery<TResult> & {\n listeners: Set<() => void>;\n unsubscribeFromLiveQuery: (() => void) | null;\n cleanupTimeout: ReturnType<typeof setTimeout> | null;\n};\n\nexport type SharedLiveQuerySnapshot = {\n sql: string;\n parameters: readonly unknown[];\n subscriberCount: number;\n};\n\nexport function createSQLiteReactiveDb<Database>(opts: SQLiteReactiveDbOptions) {\n return SQLiteReactiveDb.create<Database>(opts);\n}\n\nexport class SQLiteReactiveDb<Database> {\n readonly db: SQLiteDbWrapper<Database>;\n private sqlite3: Sqlite3Static;\n\n private readonly logger: Logger;\n\n private tablesUsedStatement: PreparedStatement<[string], { name: string; isWrite: boolean }> | null = null;\n\n private eventTarget = createTypedEventTarget<EventsMap>();\n\n private constructor(sqlite3: Sqlite3Static, logger: Logger) {\n this.sqlite3 = sqlite3;\n this.logger = logger;\n\n this.db = new SQLiteDbWrapper({\n db: () => new sqlite3.oo1.DB({ filename: \":memory:\" }),\n logger: this.logger,\n loggerPrefix: \"memory\",\n sqlite3,\n });\n }\n\n static async create<Database>(opts: SQLiteReactiveDbOptions) {\n const logger = opts.logger;\n const perf = startPerformanceLogger(logger);\n if (!sqliteModule) {\n sqliteModule = await sqlite3InitModule();\n }\n\n const db = new SQLiteReactiveDb<Database>(sqliteModule, logger);\n\n if (opts.snapshot) {\n db.useSnapshot(opts.snapshot);\n }\n db.registerDbHooks();\n\n perf.logEnd(\"createSQLiteMemoryDb\", \"success\", \"system\");\n\n return db;\n }\n\n private liveQueryStatements = new BoundMap<string, PreparedStatement<any[], unknown>>({\n maxSize: 100,\n onRemove(_, value) {\n value.finalize();\n },\n });\n\n private sharedLiveQueries = new Map<string, SharedLiveQueryEntry<unknown>[]>();\n\n createLiveQuery<TResult>(query: { sql: string; parameters: readonly unknown[] }) {\n const fetchRows = (parameters: readonly unknown[]) => {\n let statement = this.liveQueryStatements.get(query.sql);\n if (!statement) {\n statement = this.db.prepare<any[], any>(query.sql);\n this.liveQueryStatements.set(query.sql, statement);\n }\n return statement.execute(parameters as any) as TResult[];\n };\n\n let rows: TResult[] | null = null;\n\n const getRows = () => {\n if (!rows) {\n rows = fetchRows(query.parameters);\n }\n return rows;\n };\n\n let subscriber: (() => void) | null = null;\n\n let lastParameters: readonly unknown[] = query.parameters;\n const refresh = (parameters?: readonly unknown[]) => {\n if (parameters) {\n lastParameters = parameters;\n }\n rows = fetchRows(lastParameters);\n subscriber?.();\n };\n\n const subscribe = (onchange: () => void) => {\n if (subscriber) {\n throw new Error(\"Subscriber already exists\");\n }\n\n subscriber = onchange;\n const subscription = this.subscribeToQueryChanges({\n sql: query.sql,\n onDataChange: refresh,\n });\n\n return () => {\n subscription.unsubscribe();\n subscriber = null;\n };\n };\n\n return { getRows, refresh, subscribe };\n }\n\n getSharedLiveQuery<TResult>(query: { sql: string; parameters: readonly unknown[] }) {\n const existingEntry = this.sharedLiveQueries\n .get(query.sql)\n ?.find((entry) => parametersAreEqual(entry.parameters, query.parameters));\n if (existingEntry) {\n if (existingEntry.listeners.size === 0) {\n this.scheduleSharedLiveQueryCleanup(existingEntry);\n }\n return existingEntry as SharedLiveQuery<TResult>;\n }\n\n const liveQuery = this.createLiveQuery<TResult>(query);\n let hasDetachedFromLiveQuery = false;\n const entry: SharedLiveQueryEntry<TResult> = {\n sql: query.sql,\n parameters: query.parameters,\n listeners: new Set(),\n unsubscribeFromLiveQuery: null,\n cleanupTimeout: null,\n getRows: () => liveQuery.getRows(),\n refresh: () => {\n liveQuery.refresh();\n },\n getSubscriberCount: () => entry.listeners.size,\n subscribe: (onchange) => {\n this.cancelSharedLiveQueryCleanup(entry);\n this.registerSharedLiveQueryEntry(entry as SharedLiveQueryEntry<unknown>);\n entry.listeners.add(onchange);\n\n if (!entry.unsubscribeFromLiveQuery) {\n entry.unsubscribeFromLiveQuery = liveQuery.subscribe(() => {\n for (const listener of entry.listeners) {\n listener();\n }\n });\n\n // Rows may have gone stale while no subscriber was listening\n // for table changes.\n if (hasDetachedFromLiveQuery) {\n hasDetachedFromLiveQuery = false;\n liveQuery.refresh();\n }\n }\n\n return () => {\n entry.listeners.delete(onchange);\n\n if (entry.listeners.size === 0) {\n entry.unsubscribeFromLiveQuery?.();\n entry.unsubscribeFromLiveQuery = null;\n hasDetachedFromLiveQuery = true;\n this.scheduleSharedLiveQueryCleanup(entry);\n }\n };\n },\n };\n\n this.registerSharedLiveQueryEntry(entry as SharedLiveQueryEntry<unknown>);\n\n // Evict the entry if no subscriber attaches by the next tick.\n this.scheduleSharedLiveQueryCleanup(entry as SharedLiveQueryEntry<unknown>);\n\n return entry;\n }\n\n private registerSharedLiveQueryEntry(entry: SharedLiveQueryEntry<unknown>) {\n const matchingSqlEntries = this.sharedLiveQueries.get(entry.sql) ?? [];\n if (!matchingSqlEntries.includes(entry)) {\n matchingSqlEntries.push(entry);\n this.sharedLiveQueries.set(entry.sql, matchingSqlEntries);\n }\n }\n\n getSharedLiveQueriesSnapshot(): SharedLiveQuerySnapshot[] {\n const snapshot: SharedLiveQuerySnapshot[] = [];\n for (const entries of this.sharedLiveQueries.values()) {\n for (const entry of entries) {\n snapshot.push({\n sql: entry.sql,\n parameters: entry.parameters,\n subscriberCount: entry.listeners.size,\n });\n }\n }\n return snapshot;\n }\n\n private scheduleSharedLiveQueryCleanup(entry: SharedLiveQueryEntry<unknown>) {\n this.cancelSharedLiveQueryCleanup(entry);\n entry.cleanupTimeout = setTimeout(() => {\n entry.cleanupTimeout = null;\n this.releaseSharedLiveQuery(entry);\n }, 0);\n }\n\n private cancelSharedLiveQueryCleanup(entry: SharedLiveQueryEntry<unknown>) {\n if (entry.cleanupTimeout) {\n clearTimeout(entry.cleanupTimeout);\n entry.cleanupTimeout = null;\n }\n }\n\n private releaseSharedLiveQuery(entry: SharedLiveQueryEntry<unknown>) {\n if (entry.listeners.size > 0 || entry.unsubscribeFromLiveQuery) {\n return;\n }\n\n const matchingSqlEntries = this.sharedLiveQueries.get(entry.sql);\n if (!matchingSqlEntries) {\n return;\n }\n\n const nextEntries = matchingSqlEntries.filter((candidate) => candidate !== entry);\n if (nextEntries.length > 0) {\n this.sharedLiveQueries.set(entry.sql, nextEntries);\n } else {\n this.sharedLiveQueries.delete(entry.sql);\n }\n }\n\n subscribeToQueryChanges(params: { sql: string; onDataChange: () => void }) {\n const { sql, onDataChange } = params;\n\n const tables = this.getTablesUsed(sql);\n const readTables = new Set<string>();\n for (const table of tables) {\n if (!readTables.has(table.name)) {\n readTables.add(table.name);\n } else if (table.isWrite) {\n throw new Error(\"This query writes and reads from the same table. This may cause infinite loops.\");\n }\n }\n\n const notifyDataChange = createDebouncedCallback(() => {\n onDataChange();\n }, 30);\n\n for (const table of readTables) {\n this.eventTarget.addEventListener(`table:${table}`, notifyDataChange);\n }\n this.eventTarget.addEventListener(\"any-table-changed\", notifyDataChange);\n\n return {\n unsubscribe: () => {\n for (const table of readTables) {\n this.eventTarget.removeEventListener(`table:${table}`, notifyDataChange);\n }\n this.eventTarget.removeEventListener(\"any-table-changed\", notifyDataChange);\n },\n };\n }\n\n subscribeToTableChanges(table: string, onChanges: () => void) {\n this.eventTarget.addEventListener(`table:${table}`, onChanges);\n this.eventTarget.addEventListener(\"any-table-changed\", onChanges);\n return {\n unsubscribe: () => {\n this.eventTarget.removeEventListener(`table:${table}`, onChanges);\n this.eventTarget.removeEventListener(\"any-table-changed\", onChanges);\n },\n };\n }\n\n getTablesUsed(query: string) {\n if (!this.tablesUsedStatement) {\n this.tablesUsedStatement = this.db.prepare<[string], { name: string; isWrite: boolean }>(\n \"select t.tbl_name as name, u.wr as isWrite from tables_used(?) as u inner join sqlite_master as t on t.name = u.name where u.schema = 'main'\",\n { loggerLevel: \"system\" },\n );\n }\n\n const tables = this.tablesUsedStatement.execute([query]);\n\n if (tables.length === 0 && query.toLowerCase().includes(\"delete\")) {\n // tables_used function does not work with delete queries that clear entire tables\n tables.push(...this.getClearedTables(query));\n }\n\n return tables;\n }\n\n private getClearedTables(query: string) {\n const operations = this.db.execute<{\n opcode: string;\n p1: number;\n p2: number;\n }>(`EXPLAIN ${query.split(\";\")[0]}`, { loggerLevel: \"system\" }).rows;\n\n const clearedTablesRootPages = new Set<number>();\n for (const operation of operations) {\n if (operation.opcode === \"Clear\" && operation.p2 === 0) {\n clearedTablesRootPages.add(operation.p1);\n }\n }\n\n if (clearedTablesRootPages.size === 0) {\n return [];\n }\n\n const tableNames = this.db.execute<{ name: string; isWrite: boolean }>(\n `select t.tbl_name as name, true as isWrite from sqlite_master as t where t.rootpage in (${Array.from(\n clearedTablesRootPages,\n ).join(\",\")})`,\n { loggerLevel: \"system\" },\n ).rows;\n\n return tableNames;\n }\n\n addEventListener<K extends keyof EventsMap>(type: K, listener: (event: TypedEvent<EventsMap[K]>) => void) {\n this.eventTarget.addEventListener(type, listener);\n }\n\n removeEventListener<K extends keyof EventsMap>(type: K, listener: (event: TypedEvent<EventsMap[K]>) => void) {\n this.eventTarget.removeEventListener(type, listener);\n }\n\n private notifyTableSubscribers(tables: (TableName<Database> | (string & {}))[] | Set<string> | null = null) {\n if (!tables) {\n this.eventTarget.dispatchEvent(\"any-table-changed\", undefined);\n return;\n }\n\n for (const table of tables) {\n this.eventTarget.dispatchEvent(`table:${table}`, undefined);\n }\n }\n\n private registerDbHooks() {\n let updateQueue = new Set<string>();\n\n this.sqlite3.capi.sqlite3_update_hook(\n this.db.ensureDb,\n (_ctx, _opId, _db, table) => {\n updateQueue.add(table);\n },\n 0,\n );\n\n this.sqlite3.capi.sqlite3_rollback_hook(\n this.db.ensureDb,\n () => {\n if (updateQueue.size === 0) {\n return 0;\n }\n\n updateQueue.clear();\n this.eventTarget.dispatchEvent(\"transaction-rolled-back\", undefined);\n\n return 0;\n },\n 0,\n );\n\n this.sqlite3.capi.sqlite3_commit_hook(\n this.db.ensureDb,\n () => {\n if (updateQueue.size === 0) {\n return 0;\n }\n\n const tables = updateQueue;\n updateQueue = new Set<string>();\n this.eventTarget.dispatchEvent(\"transaction-committed\", undefined);\n\n queueMicrotask(() => {\n this.notifyTableSubscribers(tables);\n });\n return 0;\n },\n 0,\n );\n }\n\n createSnapshot() {\n const perf = startPerformanceLogger(this.logger);\n const snapshot = this.sqlite3.capi.sqlite3_js_db_export(this.db.ensureDb);\n perf.logEnd(\"createSnapshot\", `snapshot size: ${snapshot.byteLength}`, \"info\");\n\n return snapshot;\n }\n\n useSnapshot(snapshot: Uint8Array<ArrayBufferLike>) {\n this.db.useSnapshot(snapshot);\n this.notifyTableSubscribers();\n }\n\n dispose() {\n for (const entries of this.sharedLiveQueries.values()) {\n for (const entry of entries) {\n this.cancelSharedLiveQueryCleanup(entry);\n entry.unsubscribeFromLiveQuery?.();\n entry.unsubscribeFromLiveQuery = null;\n entry.listeners.clear();\n }\n }\n this.sharedLiveQueries.clear();\n this.liveQueryStatements.clear();\n if (this.tablesUsedStatement) {\n this.tablesUsedStatement.finalize();\n this.tablesUsedStatement = null;\n }\n this.db.close();\n }\n}\n\nfunction createDebouncedCallback<TArgs extends unknown[]>(callback: (...args: TArgs) => void, delay: number) {\n let timeout: unknown | null = null;\n let shouldCallWithoutDelay = true;\n\n return (...args: TArgs) => {\n if (shouldCallWithoutDelay) {\n callback(...args);\n shouldCallWithoutDelay = false;\n return;\n }\n\n const effect = () => {\n timeout = null;\n shouldCallWithoutDelay = true;\n return callback(...args);\n };\n\n if (timeout) {\n clearTimeout(timeout as any);\n }\n\n timeout = setTimeout(effect, delay);\n };\n}\n\nexport function parametersAreEqual(a: readonly unknown[] | undefined, b: readonly unknown[] | undefined): boolean {\n if (a === b) return true;\n if (!a || !b) return false;\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!Object.is(a[i], b[i])) {\n return false;\n }\n }\n return true;\n}\n","interface BoundMapOptions<K, V> {\n maxSize: number;\n onRemove: ((key: K, value: V) => void) | undefined;\n}\n\nexport class BoundMap<K, V> {\n private map = new Map<K, V>();\n private maxSize: number;\n private onRemove: ((key: K, value: V) => void) | undefined;\n\n constructor(opts: BoundMapOptions<K, V>) {\n this.maxSize = opts.maxSize;\n this.onRemove = opts.onRemove;\n }\n\n set = (key: K, value: V) => {\n if (this.onRemove && this.map.has(key)) {\n const old = this.map.get(key) as V;\n this.map.set(key, value);\n this.onRemove(key, old);\n } else {\n this.map.set(key, value);\n }\n if (this.map.size > this.maxSize) {\n const firstKey = this.map.keys().next().value as K;\n this.delete(firstKey);\n }\n };\n\n get = (key: K): V | undefined => {\n return this.map.get(key);\n };\n\n delete = (key: K) => {\n if (this.onRemove && this.map.has(key)) {\n const value = this.map.get(key) as V;\n this.map.delete(key);\n this.onRemove(key, value);\n } else {\n this.map.delete(key);\n }\n };\n\n clear = () => {\n const onRemove = this.onRemove;\n if (onRemove) {\n this.map.forEach((value, key) => {\n onRemove(key, value);\n });\n }\n this.map.clear();\n };\n}\n","import type { ColumnType } from \"kysely\";\nimport type { Migrations } from \"../migrations/migrator\";\n\nexport type CrdtTableConfig = {\n baseTableName: string;\n crdtTableName: string;\n};\n\nexport function createSyncDbSchema({ migrations }: { migrations: Migrations }) {\n return new CrdtSchemaBuilder({ tables: [], migrations });\n}\n\nexport interface CreateCrdtSchemaOptions {\n tables: CrdtTableConfig[];\n migrations: Migrations;\n}\n\n// biome-ignore lint/complexity/noBannedTypes: required generic\nclass CrdtSchemaBuilder<ClientDB = {}, ServerDB = {}, MutationsDB = {}>\n implements SyncDbSchema<ClientDB, ServerDB, MutationsDB>\n{\n constructor(private config: CreateCrdtSchemaOptions) {}\n\n get tablesConfig() {\n return this.config.tables;\n }\n\n get migrations() {\n return this.config.migrations;\n }\n\n get \"~clientSchema\"() {\n console.warn(\"~clientSchema should not be accessed on the client\");\n return null as any;\n }\n\n get \"~serverSchema\"() {\n console.warn(\"~serverSchema should not be accessed on the server\");\n return null as any;\n }\n\n get \"~mutationsSchema\"() {\n console.warn(\"~mutationsSchema should not be accessed on the client\");\n return null as any;\n }\n\n addTable<Table extends Record<string, unknown>>() {\n const withConfig = <const CrdtTable extends string, const BaseTable extends string>({\n baseTableName,\n crdtTableName,\n }: {\n baseTableName: BaseTable;\n crdtTableName: CrdtTable;\n }) => {\n this.config.tables.push({ baseTableName, crdtTableName });\n return new CrdtSchemaBuilder<\n ClientDB & { [K in CrdtTable]: Table } & { [K in BaseTable]: ReadonlyTable<Table> },\n ServerDB & { [K in BaseTable]: ReadonlyTable<Table> },\n MutationsDB & { [K in BaseTable]: Table }\n >(this.config);\n };\n\n return { withConfig };\n }\n\n build() {\n return this as SyncDbSchema<ClientDB, ServerDB, MutationsDB>;\n }\n}\n\n// biome-ignore lint/complexity/noBannedTypes: required generic\nexport interface SyncDbSchema<ClientDB = {}, ServerDB = {}, MutationsDB = {}> {\n get tablesConfig(): CrdtTableConfig[];\n get migrations(): Migrations;\n \"~clientSchema\": ClientDB;\n \"~serverSchema\": ServerDB;\n \"~mutationsSchema\": MutationsDB;\n}\n\ntype ReadonlyTable<Table extends Record<string, unknown>> = {\n [K in keyof Table]: ColumnType<Table[K], never, never>;\n};\n","import type { CrdtStorage, OwnCrdtEvent } from \"./crdt-storage\";\n\nexport type CrdtStorageMutator<Database> = ReturnType<typeof createCrdtStorageMutator<Database>>;\n\ntype CommitEventOptions<Database, Table extends keyof Database & string> =\n | {\n type: \"item-created\";\n dataset: Table;\n item_id: string;\n payload: CreateEventPayload<Database, Table>;\n }\n | {\n type: \"item-updated\";\n dataset: Table;\n item_id: string;\n payload: UpdateEventPayload<Database, Table>;\n }\n | {\n type: \"item-deleted\";\n dataset: Table;\n item_id: string;\n };\n\ntype CreateEventPayload<Database, Table extends keyof Database> = Omit<Database[Table], \"tombstone\">;\ntype UpdateEventPayload<Database, Table extends keyof Database> = Omit<Partial<Database[Table]>, \"id\" | \"tombstone\">;\n\nexport function createCrdtStorageMutator<Database>({ storage }: { storage: CrdtStorage }) {\n const mapToStorageEvent = (event: CommitEventOptions<Database, keyof Database & string>): OwnCrdtEvent => {\n switch (event.type) {\n case \"item-created\":\n return {\n type: \"item-created\",\n dataset: event.dataset,\n item_id: event.item_id,\n payload: JSON.stringify(event.payload),\n };\n case \"item-updated\":\n return {\n type: \"item-updated\",\n dataset: event.dataset,\n item_id: event.item_id,\n payload: JSON.stringify(event.payload),\n };\n case \"item-deleted\":\n return {\n type: \"item-deleted\",\n dataset: event.dataset,\n item_id: event.item_id,\n payload: \"{}\",\n };\n }\n };\n\n const enqueueEvents = (events: CommitEventOptions<Database, keyof Database & string>[]) => {\n storage.enqueueOwnEvents(events.map(mapToStorageEvent));\n };\n\n const createEvent = <Table extends keyof Database & string>(event: CommitEventOptions<Database, Table>) => {\n return event;\n };\n\n const enqueueEvent = (event: CommitEventOptions<Database, keyof Database & string>) => {\n storage.enqueueOwnEvents([mapToStorageEvent(event)]);\n };\n\n return {\n enqueueEvents,\n createEvent,\n enqueueEvent,\n };\n}\n","import type { SQLiteReactiveDb } from \"../memory-db/sqlite-reactive-db\";\nimport type { SQLiteDbWrapper } from \"../sqlite-db-wrapper\";\nimport { quoteId } from \"../utils\";\nimport type { CrdtStorage } from \"./crdt-storage\";\n\nexport function makeCrdtTable({\n db,\n baseTableName,\n crdtTableName,\n}: {\n db: SQLiteDbWrapper<any>;\n baseTableName: string;\n crdtTableName: string;\n}) {\n const tableSchema = db.dbSchema[baseTableName];\n\n if (!tableSchema) {\n throw new Error(`Table ${baseTableName} not found`);\n }\n\n const columns = new Map(tableSchema.columns.map((c) => [c.name, c]));\n\n const idColumn = columns.get(\"id\");\n if (!idColumn) {\n throw new Error(\n `Table \"${baseTableName}\" is missing a required \"id\" column. CRDT tables must have an \"id\" column to identify items.`,\n );\n }\n if (idColumn.dataType.toUpperCase() !== \"TEXT\") {\n throw new Error(\n `Table \"${baseTableName}\": \"id\" column must be of type TEXT, got \"${idColumn.dataType}\". CRDT item IDs are stored as strings.`,\n );\n }\n\n const tombstoneColumn = columns.get(\"tombstone\");\n if (!tombstoneColumn) {\n throw new Error(\n `Table \"${baseTableName}\" is missing a required \"tombstone\" column. CRDT tables must have a \"tombstone\" INTEGER column for soft deletes.`,\n );\n }\n const tombstoneType = tombstoneColumn.dataType.toUpperCase();\n if (tombstoneType !== \"INTEGER\" && tombstoneType !== \"BOOLEAN\") {\n throw new Error(\n `Table \"${baseTableName}\": \"tombstone\" column must be of type INTEGER or BOOLEAN, got \"${tombstoneColumn.dataType}\". It is compared as 0/1 for soft deletes.`,\n );\n }\n\n db.execute(\n `\ncreate view ${quoteId(crdtTableName)} as\nselect * from ${quoteId(baseTableName)}\nwhere tombstone = 0;`,\n { loggerLevel: \"system\" },\n );\n\n const allColumnNames = tableSchema.columns.map((column) => column.name);\n\n const jsonPayload = (from: \"new\" | \"old\") =>\n `'{'||${allColumnNames.map((col) => `'\"${col}\":'||json_quote(${from}.${quoteId(col)})`).join(\"||','||\")}||'}'`;\n\n db.execute(\n `\ncreate trigger ${quoteId(`${crdtTableName}_created`)}\ninstead of insert on ${quoteId(crdtTableName)}\nfor each row\nbegin\nselect handle_item_created('${baseTableName}', ${jsonPayload(\"new\")});\nend;\n`,\n { loggerLevel: \"system\" },\n );\n\n db.execute(\n `\ncreate trigger ${quoteId(`${crdtTableName}_updated`)}\ninstead of update on ${quoteId(crdtTableName)}\nfor each row\nbegin\nselect handle_item_updated(\n '${baseTableName}',\n ${jsonPayload(\"old\")},\n ${jsonPayload(\"new\")}\n);\nend;\n`,\n { loggerLevel: \"system\" },\n );\n\n db.execute(\n `\ncreate trigger ${quoteId(`${crdtTableName}_deleted`)}\ninstead of delete on ${quoteId(crdtTableName)}\nfor each row\nwhen old.tombstone = 0\nbegin\nselect handle_item_deleted('${baseTableName}', old.id);\nend;\n`,\n { loggerLevel: \"system\" },\n );\n}\n\nexport function registerCrdtFunctions({\n reactiveDb,\n storage,\n}: {\n reactiveDb: SQLiteReactiveDb<any>;\n storage: CrdtStorage;\n}) {\n let eventApplied = false;\n\n reactiveDb.db.createScalarFunction({\n name: \"handle_item_created\",\n deterministic: false,\n directOnly: false,\n innocuous: false,\n callback: (dataset: string, payloadRaw: string) => {\n const payload = JSON.parse(payloadRaw) as { id: string };\n\n storage.applyOwnEvent(\n {\n type: \"item-created\",\n dataset,\n item_id: payload.id,\n payload: payloadRaw,\n },\n {\n wrapInTransaction: false,\n },\n );\n\n eventApplied = true;\n return undefined;\n },\n });\n\n reactiveDb.db.createScalarFunction({\n name: \"handle_item_updated\",\n deterministic: false,\n directOnly: false,\n innocuous: false,\n callback: (dataset: string, oldPayloadRaw: string, newPayloadRaw: string) => {\n if (oldPayloadRaw === newPayloadRaw) {\n return undefined;\n }\n\n const tableSchema = reactiveDb.db.dbSchema[dataset];\n\n if (!tableSchema?.columns) {\n throw new Error(`Schema not found for dataset: ${dataset}`);\n }\n\n const oldPayload = JSON.parse(oldPayloadRaw);\n const newPayload = JSON.parse(newPayloadRaw);\n\n let hasDiff = false;\n const updatePayload = {} as Record<string, unknown>;\n\n for (const column of tableSchema.columns) {\n const oldValue = oldPayload[column.name];\n const newValue = newPayload[column.name];\n if (oldValue === newValue) {\n continue;\n }\n\n if (column.name === \"id\") {\n throw new Error(\n `Cannot update the \"id\" column of an item. It is used to identify the item and must be immutable.`,\n );\n }\n\n hasDiff = true;\n updatePayload[column.name] = newValue;\n }\n\n if (!hasDiff) {\n return;\n }\n\n storage.applyOwnEvent(\n {\n type: \"item-updated\",\n dataset,\n item_id: oldPayload.id,\n payload: JSON.stringify(updatePayload),\n },\n {\n wrapInTransaction: false,\n },\n );\n\n eventApplied = true;\n return undefined;\n },\n });\n\n reactiveDb.db.createScalarFunction({\n name: \"handle_item_deleted\",\n deterministic: false,\n directOnly: false,\n innocuous: false,\n callback: (dataset: string, itemId: string) => {\n storage.applyOwnEvent(\n {\n type: \"item-deleted\",\n dataset,\n item_id: itemId,\n payload: \"{}\",\n },\n {\n wrapInTransaction: false,\n },\n );\n\n eventApplied = true;\n return undefined;\n },\n });\n\n reactiveDb.addEventListener(\"transaction-committed\", () => {\n if (eventApplied) {\n eventApplied = false;\n storage.dispatchEventsApplied();\n }\n });\n\n reactiveDb.addEventListener(\"transaction-rolled-back\", () => {\n eventApplied = false;\n });\n}\n","const dbIdRegex = /^[a-zA-Z][a-zA-Z\\-0-9]{2,63}$/;\n\nexport function validateDbId(dbId: string) {\n if (!dbIdRegex.test(dbId)) {\n throw new Error(\"Invalid dbId. Must be between 3 and 64 characters long and start with a letter.\");\n }\n}\n","import type { SyncedDb } from \"./sync-db\";\n\nconst devtoolsRegistrySymbol = Symbol.for(\"@sqlite-sync/devtools\");\n\nexport type SQLiteSyncDevtoolsInstance = {\n instanceId: string;\n dbId: string;\n createdAt: number;\n instance: SyncedDb<any>;\n};\n\nexport type SQLiteSyncDevtoolsSnapshot = {\n instances: readonly SQLiteSyncDevtoolsInstance[];\n};\n\nexport type SQLiteSyncDevtoolsRegistry = {\n version: 1;\n instances: Map<string, SQLiteSyncDevtoolsInstance>;\n subscribe(listener: () => void): () => void;\n getSnapshot(): SQLiteSyncDevtoolsSnapshot;\n register(instance: SQLiteSyncDevtoolsInstance): () => void;\n};\n\ntype RegistryGlobal = typeof globalThis & {\n [key: symbol]: SQLiteSyncDevtoolsRegistry | undefined;\n};\n\nfunction createSQLiteSyncDevtoolsRegistry(): SQLiteSyncDevtoolsRegistry {\n const instances = new Map<string, SQLiteSyncDevtoolsInstance>();\n const listeners = new Set<() => void>();\n let snapshot: SQLiteSyncDevtoolsSnapshot = {\n instances: [],\n };\n\n const notify = () => {\n for (const listener of listeners) {\n listener();\n }\n };\n\n const updateSnapshot = () => {\n snapshot = {\n instances: Array.from(instances.values()),\n };\n notify();\n };\n\n return {\n version: 1,\n instances,\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n getSnapshot() {\n return snapshot;\n },\n register(instance) {\n instances.set(instance.instanceId, instance);\n updateSnapshot();\n\n let isUnregistered = false;\n return () => {\n if (isUnregistered) return;\n isUnregistered = true;\n\n if (!instances.delete(instance.instanceId)) return;\n updateSnapshot();\n };\n },\n };\n}\n\nexport function getOrCreateSQLiteSyncDevtoolsRegistry(): SQLiteSyncDevtoolsRegistry {\n const registryGlobal = globalThis as RegistryGlobal;\n\n registryGlobal[devtoolsRegistrySymbol] ??= createSQLiteSyncDevtoolsRegistry();\n\n return registryGlobal[devtoolsRegistrySymbol];\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 } from \"../sqlite-crdt/crdt-schema\";\nimport { createCrdtStorage } from \"../sqlite-crdt/crdt-storage\";\nimport { makeCrdtTable, registerCrdtFunctions } from \"../sqlite-crdt/make-crdt-table\";\nimport type { StoredValue } from \"../sqlite-crdt/stored-value\";\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 eventHlcAccumulator?: StoredValue<string>;\n};\n\nexport async function createMemoryDb<Database>({\n nodeId,\n migrator,\n reactiveDb: _reactiveDb,\n hlcCounter,\n crdtTables,\n initializeSchema = true,\n initialSyncId,\n eventHlcAccumulator,\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 eventHlcAccumulator,\n });\n\n registerCrdtFunctions({\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 WorkerNotificationMessage,\n WorkerRequestMessage,\n WorkerRequestMethod,\n WorkerResponseMessage,\n WorkerRpc,\n WorkerState,\n} from \"./worker-common\";\nimport { isWorkerErrorResponseMessage, isWorkerNotificationMessage, isWorkerResponseMessage } from \"./worker-common\";\n\ntype NotificationEvents = {\n [K in WorkerNotificationMessage[\"notificationType\"]]: Extract<WorkerNotificationMessage, { notificationType: K }>;\n};\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 promise = createDeferredPromise<unknown>({\n timeout: 30_000,\n onTimeout: () => workerRequestsMap.delete(requestId),\n });\n workerRequestsMap.set(requestId, promise);\n\n const request: WorkerRequestMessage<TMethod> = {\n type: \"request\",\n requestId,\n method,\n args,\n };\n\n broadcastChannels.requests.postMessage(request);\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 pushTabEvents: (request) => queryWorker(\"pushTabEvents\", [request]),\n pullEvents: (params) => queryWorker(\"pullEvents\", [params]),\n postState: () => queryWorker(\"postState\", []),\n goOnline: () => queryWorker(\"goOnline\", []),\n goOffline: () => queryWorker(\"goOffline\", []),\n requestReload: (options) => queryWorker(\"requestReload\", [options]),\n };\n\n const statePromise = awaitWorkerState(eventTarget);\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 workerState = await statePromise;\n\n eventTarget.addEventListener(\"state-changed\", (event) => {\n workerState = event.payload.state;\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 return {\n ...rpc,\n subscribe: eventTarget.addEventListener,\n getState: () => workerState,\n dispose,\n };\n};\n\nfunction awaitWorkerState(eventTarget: TypedEventTarget<NotificationEvents>) {\n const promise = createDeferredPromise<WorkerState>({ timeout: 15_000 });\n\n const subscription = eventTarget.addEventListener(\"state-changed\", (event) => {\n promise.resolve(event.payload.state);\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 { HLCCounter } from \"./hlc\";\nimport { type Logger, startPerformanceLogger } from \"./logger\";\nimport { createMemoryDb } from \"./memory-db/memory-db\";\nimport { createSQLiteReactiveDb } from \"./memory-db/sqlite-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 { createDeferredPromise, generateId } from \"./utils\";\nimport { createWorkerDbClient } from \"./worker-db/db-worker-client\";\nimport { createBroadcastChannels, syncDbClientLockName } from \"./worker-db/worker-common\";\n\ntype SyncedDbOptions<Database, Props = undefined> = {\n dbId: string;\n worker: Worker;\n workerProps: Props;\n syncDbSchema: SyncDbSchema<Database>;\n};\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 const clientLockAcquired = createDeferredPromise<void>();\n const clientLockRelease = createDeferredPromise<void>();\n navigator.locks.request(`${syncDbClientLockName}-${options.dbId}`, { mode: \"shared\" }, () => {\n clientLockAcquired.resolve();\n return clientLockRelease.promise;\n });\n await clientLockAcquired.promise;\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\n const hlcCounter = new HLCCounter(tabId, () => Date.now());\n\n const workerClientSnapshot = await workerClient.getSnapshot();\n const reactiveDb = await createSQLiteReactiveDb<Database>({\n snapshot: workerClientSnapshot.file,\n logger: defaultLogger,\n });\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 });\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, remoteEventHlcSum: event.payload.eventHlcSum });\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 tabRemoteSource.goOnline();\n\n const reloadRequestedSubscription = workerClient.subscribe(\"reload-requested\", () => {\n globalThis.location?.reload();\n });\n\n perf.logEnd(\"createSyncedDb\", \"initialized\", \"info\");\n\n let isDisposed = false;\n let unregisterDevtools: (() => void) | undefined;\n const dispose = async () => {\n if (isDisposed) return;\n isDisposed = true;\n\n unregisterDevtools?.();\n reloadRequestedSubscription.unsubscribe();\n clientLockRelease.resolve();\n await tabRemoteSource.dispose();\n broadcastChannels.requests.close();\n broadcastChannels.responses.close();\n workerClient.dispose();\n reactiveDb.dispose();\n };\n\n const syncedDb = {\n db: {\n execute: reactiveDb.db.execute.bind(reactiveDb.db),\n executeKysely: reactiveDb.db.executeKysely.bind(reactiveDb.db),\n executeTransaction: reactiveDb.db.executeTransaction.bind(reactiveDb.db),\n createLiveQuery: reactiveDb.createLiveQuery.bind(reactiveDb),\n getSharedLiveQuery: reactiveDb.getSharedLiveQuery.bind(reactiveDb),\n },\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 },\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 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 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}\n\nexport type SyncedDb<Database> = Awaited<ReturnType<typeof createSyncedDb<Database>>>;\n"],"mappings":"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","names":["entry","options"]}
|