@sqlite-sync/core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,710 @@
1
+ import {
2
+ SQLiteDbWrapper,
3
+ SqliteDriver,
4
+ applyMemoryDbSchema,
5
+ applyWorkerDbSchema,
6
+ broadcastChannelNames,
7
+ createBroadcastChannels,
8
+ createCrdtSyncRemoteSource,
9
+ createSQLiteKysely,
10
+ createSyncDbMigrations,
11
+ createSyncDbMigrator,
12
+ introspectDb,
13
+ isWorkerInitMessage,
14
+ isWorkerInitResponse,
15
+ isWorkerNotificationMessage,
16
+ isWorkerRequestMessage,
17
+ isWorkerResponseMessage,
18
+ startPerformanceLogger,
19
+ syncDbWorkerLockName
20
+ } from "./chunk-LK5FJCUD.js";
21
+ import {
22
+ TypedBroadcastChannel,
23
+ TypedEvent,
24
+ applyCrdtEventMutations,
25
+ crdtSchema,
26
+ createAsyncAutoFlushBuffer,
27
+ createAutoFlushBuffer,
28
+ createCrdtStorage,
29
+ createCrdtSyncProducer,
30
+ createDeferredPromise,
31
+ createSyncIdCounter,
32
+ createTypedEventTarget,
33
+ dummyKysely,
34
+ ensureSingletonExecution,
35
+ generateId,
36
+ jsonSafeParse,
37
+ orderBy,
38
+ registerCrdtFunctions
39
+ } from "./chunk-YLXMST5Z.js";
40
+
41
+ // src/hlc.ts
42
+ var HLCCounter = class {
43
+ timestamp;
44
+ counter;
45
+ nodeId;
46
+ getTimestamp;
47
+ constructor(nodeId, getTimestamp) {
48
+ this.timestamp = getTimestamp();
49
+ this.counter = 0;
50
+ this.nodeId = nodeId;
51
+ this.getTimestamp = getTimestamp;
52
+ }
53
+ getCurrentHLC() {
54
+ return {
55
+ timestamp: this.timestamp,
56
+ counter: this.counter,
57
+ nodeId: this.nodeId
58
+ };
59
+ }
60
+ getNextHLC() {
61
+ const now = this.getTimestamp();
62
+ if (now > this.timestamp) {
63
+ this.timestamp = now;
64
+ this.counter = 0;
65
+ return this.getCurrentHLC();
66
+ }
67
+ this.counter++;
68
+ return this.getCurrentHLC();
69
+ }
70
+ mergeHLC(hlc) {
71
+ if (this.timestamp === hlc.timestamp) {
72
+ this.counter = Math.max(this.counter, hlc.counter) + 1;
73
+ } else if (this.timestamp > hlc.timestamp) {
74
+ this.counter++;
75
+ } else {
76
+ this.timestamp = hlc.timestamp;
77
+ this.counter = hlc.counter + 1;
78
+ }
79
+ }
80
+ };
81
+ function serializeHLC(hlc) {
82
+ return hlc.timestamp.toString().padStart(15, "0") + ":" + hlc.counter.toString(36).padStart(5, "0") + ":" + hlc.nodeId;
83
+ }
84
+ function deserializeHLC(serialized) {
85
+ const [ts, count, ...node] = serialized.split(":");
86
+ return {
87
+ timestamp: parseInt(ts),
88
+ counter: parseInt(count, 36),
89
+ nodeId: node.join(":")
90
+ };
91
+ }
92
+ function compareHLC(one, two) {
93
+ if (one.timestamp == two.timestamp) {
94
+ if (one.counter === two.counter) {
95
+ if (one.nodeId === two.nodeId) {
96
+ return 0;
97
+ }
98
+ return one.nodeId < two.nodeId ? -1 : 1;
99
+ }
100
+ return one.counter - two.counter;
101
+ }
102
+ return one.timestamp - two.timestamp;
103
+ }
104
+
105
+ // src/worker-db/db-worker-client.ts
106
+ var createWorkerDbClient = ({
107
+ broadcastChannels
108
+ }) => {
109
+ const eventTarget = createTypedEventTarget();
110
+ const workerRequestsMap = /* @__PURE__ */ new Map();
111
+ const queryWorker = (method, args) => {
112
+ const requestId = crypto.randomUUID();
113
+ const promise = createDeferredPromise();
114
+ workerRequestsMap.set(requestId, promise);
115
+ const request = {
116
+ type: "request",
117
+ requestId,
118
+ method,
119
+ args
120
+ };
121
+ broadcastChannels.requests.postMessage(request);
122
+ return promise.promise;
123
+ };
124
+ const handleWorkerResponse = (message) => {
125
+ const promise = workerRequestsMap.get(message.requestId);
126
+ if (!promise) {
127
+ return;
128
+ }
129
+ promise.resolve(message.data);
130
+ workerRequestsMap.delete(message.requestId);
131
+ };
132
+ broadcastChannels.responses.onmessage = (event) => {
133
+ const message = event.data;
134
+ if (isWorkerResponseMessage(message)) {
135
+ handleWorkerResponse(message);
136
+ } else if (isWorkerNotificationMessage(message)) {
137
+ eventTarget.dispatchEvent("new-notification", message);
138
+ }
139
+ };
140
+ const rpc = {
141
+ execute: (query) => queryWorker("execute", [query]),
142
+ getSnapshot: () => queryWorker("getSnapshot", []),
143
+ pushTabEvents: (request) => queryWorker("pushTabEvents", [request]),
144
+ pullEvents: (params) => queryWorker("pullEvents", [params]),
145
+ postInitReady: () => queryWorker("postInitReady", [])
146
+ };
147
+ return {
148
+ ...rpc,
149
+ addEventListener: eventTarget.addEventListener,
150
+ removeEventListener: eventTarget.removeEventListener
151
+ };
152
+ };
153
+ function initializeWorkerDb({
154
+ worker,
155
+ broadcastChannels,
156
+ config
157
+ }) {
158
+ const promise = createDeferredPromise();
159
+ broadcastChannels.responses.onmessage = (event) => {
160
+ const message = event.data;
161
+ if (!isWorkerInitResponse(message)) {
162
+ return;
163
+ }
164
+ promise.resolve();
165
+ worker.onmessage = null;
166
+ };
167
+ const configMessage = {
168
+ type: "init",
169
+ config
170
+ };
171
+ worker.postMessage(configMessage);
172
+ broadcastChannels.requests.postMessage({
173
+ type: "request",
174
+ requestId: crypto.randomUUID(),
175
+ method: "postInitReady",
176
+ args: []
177
+ });
178
+ return promise.promise;
179
+ }
180
+
181
+ // src/memory-db/sqlite-reactive-db.ts
182
+ import sqlite3InitModule from "@sqlite.org/sqlite-wasm";
183
+ var sqliteModule = null;
184
+ function createSQLiteReactiveDb(opts) {
185
+ return SQLiteReactiveDb.create(opts);
186
+ }
187
+ var defaultLogger = (type, message, level = "info") => {
188
+ const logMessage = `[${type}] ${message}`;
189
+ switch (level) {
190
+ case "info":
191
+ console.log(logMessage);
192
+ break;
193
+ case "warning":
194
+ console.warn(logMessage);
195
+ break;
196
+ case "error":
197
+ console.error(logMessage);
198
+ break;
199
+ case "trace":
200
+ console.trace(logMessage);
201
+ break;
202
+ }
203
+ };
204
+ var SQLiteReactiveDb = class _SQLiteReactiveDb {
205
+ db;
206
+ sqlite3;
207
+ logger;
208
+ tablesUsedStatement = null;
209
+ eventTarget = createTypedEventTarget();
210
+ constructor(sqlite3, logger) {
211
+ this.sqlite3 = sqlite3;
212
+ this.logger = logger;
213
+ this.db = new SQLiteDbWrapper({
214
+ db: new sqlite3.oo1.DB({ filename: ":memory:" }),
215
+ logger: this.logger,
216
+ loggerPrefix: "memory",
217
+ sqlite3
218
+ });
219
+ }
220
+ static async create(opts) {
221
+ const logger = opts.logger ?? defaultLogger;
222
+ const perf = startPerformanceLogger(logger);
223
+ if (!sqliteModule) {
224
+ sqliteModule = await sqlite3InitModule();
225
+ }
226
+ const db = new _SQLiteReactiveDb(sqliteModule, logger);
227
+ if (opts.snapshot) {
228
+ db.useSnapshot(opts.snapshot);
229
+ }
230
+ db.registerDbHooks();
231
+ perf.logEnd("createSQLiteMemoryDb", "success", "info");
232
+ return db;
233
+ }
234
+ createLiveQuery(query) {
235
+ const fetchRows = () => this.db.execute({
236
+ sql: query.sql,
237
+ parameters: query.parameters ?? []
238
+ }).rows;
239
+ let rows = null;
240
+ const getRows = () => {
241
+ if (!rows) {
242
+ rows = fetchRows();
243
+ }
244
+ return rows;
245
+ };
246
+ let subscriber = null;
247
+ const refresh = () => {
248
+ rows = fetchRows();
249
+ subscriber?.();
250
+ };
251
+ const subscribe = (onchange) => {
252
+ if (subscriber) {
253
+ throw new Error("Subscriber already exists");
254
+ }
255
+ subscriber = onchange;
256
+ const subscription = this.subscribeToQueryChanges({
257
+ sql: query.sql,
258
+ onDataChange: refresh
259
+ });
260
+ return () => {
261
+ subscription.unsubscribe();
262
+ subscriber = null;
263
+ };
264
+ };
265
+ return { getRows, refresh, subscribe };
266
+ }
267
+ subscribeToQueryChanges(params) {
268
+ const { sql: sql2, onDataChange } = params;
269
+ const tables = this.getTablesUsed(sql2);
270
+ const readTables = /* @__PURE__ */ new Set();
271
+ for (const table of tables) {
272
+ if (!readTables.has(table.name)) {
273
+ readTables.add(table.name);
274
+ } else if (table.isWrite) {
275
+ throw new Error(
276
+ "This query writes and reads from the same table. This may cause infinite loops."
277
+ );
278
+ }
279
+ }
280
+ const notifyDataChange = createDebouncedCallback(() => {
281
+ onDataChange();
282
+ }, 30);
283
+ for (const table of readTables) {
284
+ this.eventTarget.addEventListener(`table:${table}`, notifyDataChange);
285
+ }
286
+ this.eventTarget.addEventListener("any-table-changed", notifyDataChange);
287
+ return {
288
+ unsubscribe: () => {
289
+ for (const table of readTables) {
290
+ this.eventTarget.removeEventListener(
291
+ `table:${table}`,
292
+ notifyDataChange
293
+ );
294
+ this.eventTarget.removeEventListener(
295
+ "any-table-changed",
296
+ notifyDataChange
297
+ );
298
+ }
299
+ }
300
+ };
301
+ }
302
+ subscribeToTableChanges(table, onChanges) {
303
+ this.eventTarget.addEventListener(`table:${table}`, onChanges);
304
+ this.eventTarget.addEventListener("any-table-changed", onChanges);
305
+ return {
306
+ unsubscribe: () => {
307
+ this.eventTarget.removeEventListener(`table:${table}`, onChanges);
308
+ this.eventTarget.removeEventListener("any-table-changed", onChanges);
309
+ }
310
+ };
311
+ }
312
+ getTablesUsed(query) {
313
+ if (!this.tablesUsedStatement) {
314
+ this.tablesUsedStatement = this.db.prepare(
315
+ "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'"
316
+ );
317
+ }
318
+ const tables = this.tablesUsedStatement.execute([query]);
319
+ if (tables.length == 0 && query.toLowerCase().includes("delete")) {
320
+ tables.push(...this.getClearedTables(query));
321
+ }
322
+ return tables;
323
+ }
324
+ getClearedTables(query) {
325
+ const operations = this.db.execute(`EXPLAIN ${query.split(";")[0]}`).rows;
326
+ const clearedTablesRootPages = /* @__PURE__ */ new Set();
327
+ for (const operation of operations) {
328
+ if (operation.opcode === "Clear" && operation.p2 === 0) {
329
+ clearedTablesRootPages.add(operation.p1);
330
+ }
331
+ }
332
+ if (clearedTablesRootPages.size === 0) {
333
+ return [];
334
+ }
335
+ const tableNames = this.db.execute(
336
+ `select t.tbl_name as name, true as isWrite from sqlite_master as t where t.rootpage in (${Array.from(
337
+ clearedTablesRootPages
338
+ ).join(",")})`
339
+ ).rows;
340
+ return tableNames;
341
+ }
342
+ addEventListener(type, listener) {
343
+ this.eventTarget.addEventListener(type, listener);
344
+ }
345
+ removeEventListener(type, listener) {
346
+ this.eventTarget.removeEventListener(type, listener);
347
+ }
348
+ notifyTableSubscribers(tables = []) {
349
+ if (tables.length === 0) {
350
+ this.eventTarget.dispatchEvent("any-table-changed", void 0);
351
+ return;
352
+ }
353
+ for (const table of tables) {
354
+ this.eventTarget.dispatchEvent(`table:${table}`, void 0);
355
+ }
356
+ }
357
+ registerDbHooks() {
358
+ const updateQueue = /* @__PURE__ */ new Set();
359
+ this.sqlite3.capi.sqlite3_update_hook(
360
+ this.db.ensureDb,
361
+ (_ctx, _opId, _db, table) => {
362
+ updateQueue.add(table);
363
+ },
364
+ 0
365
+ );
366
+ this.sqlite3.capi.sqlite3_rollback_hook(
367
+ this.db.ensureDb,
368
+ () => {
369
+ if (updateQueue.size === 0) {
370
+ return 0;
371
+ }
372
+ updateQueue.clear();
373
+ this.eventTarget.dispatchEvent("transaction-rolled-back", void 0);
374
+ return 0;
375
+ },
376
+ 0
377
+ );
378
+ this.sqlite3.capi.sqlite3_commit_hook(
379
+ this.db.ensureDb,
380
+ () => {
381
+ if (updateQueue.size === 0) {
382
+ return 0;
383
+ }
384
+ const tables = Array.from(updateQueue);
385
+ updateQueue.clear();
386
+ this.eventTarget.dispatchEvent("transaction-committed", void 0);
387
+ queueMicrotask(() => {
388
+ this.notifyTableSubscribers(tables);
389
+ });
390
+ return 0;
391
+ },
392
+ 0
393
+ );
394
+ }
395
+ createSnapshot() {
396
+ const perf = startPerformanceLogger(this.logger);
397
+ const snapshot = this.sqlite3.capi.sqlite3_js_db_export(this.db.ensureDb);
398
+ perf.logEnd(
399
+ "createSnapshot",
400
+ `snapshot size: ${snapshot.byteLength}`,
401
+ "info"
402
+ );
403
+ return snapshot;
404
+ }
405
+ useSnapshot(snapshot) {
406
+ this.db.useSnapshot(snapshot);
407
+ this.notifyTableSubscribers();
408
+ }
409
+ };
410
+ function createDebouncedCallback(callback, delay) {
411
+ let timeout = null;
412
+ let shouldCallWithoutDelay = true;
413
+ return (...args) => {
414
+ if (shouldCallWithoutDelay) {
415
+ callback(...args);
416
+ shouldCallWithoutDelay = false;
417
+ return;
418
+ }
419
+ const effect = () => {
420
+ timeout = null;
421
+ shouldCallWithoutDelay = true;
422
+ return callback(...args);
423
+ };
424
+ if (timeout) {
425
+ clearTimeout(timeout);
426
+ }
427
+ timeout = setTimeout(effect, delay);
428
+ };
429
+ }
430
+
431
+ // src/memory-db/memory-db.ts
432
+ import { sql } from "kysely";
433
+
434
+ // src/sqlite-crdt/make-crdt-table.ts
435
+ function makeCrdtTable({
436
+ db,
437
+ baseTableName,
438
+ crdtTableName
439
+ }) {
440
+ const tableSchema = db.dbSchema[baseTableName];
441
+ if (!tableSchema) {
442
+ throw new Error(`Table ${baseTableName} not found`);
443
+ }
444
+ db.execute(`
445
+ create view ${crdtTableName} as
446
+ select * from ${baseTableName}
447
+ where tombstone = 0;`);
448
+ const allColumnNames = tableSchema.columns.map((column) => column.name);
449
+ const jsonPayload = (from) => "'{'||" + allColumnNames.map((col) => `'"${col}":'||json_quote(${from}.${col})`).join("||','||") + "||'}'";
450
+ db.execute(`
451
+ create trigger ${crdtTableName}_created
452
+ instead of insert on ${crdtTableName}
453
+ for each row
454
+ begin
455
+ select handle_item_created('${baseTableName}', ${jsonPayload("new")});
456
+ end;
457
+ `);
458
+ db.execute(`
459
+ create trigger ${crdtTableName}_updated
460
+ instead of update on ${crdtTableName}
461
+ for each row
462
+ begin
463
+ select handle_item_updated(
464
+ '${baseTableName}',
465
+ ${jsonPayload("old")},
466
+ ${jsonPayload("new")}
467
+ );
468
+ end;
469
+ `);
470
+ db.execute(`
471
+ create trigger ${crdtTableName}_deleted
472
+ instead of delete on ${crdtTableName}
473
+ for each row
474
+ when old.tombstone = 0
475
+ begin
476
+ select handle_item_deleted('${baseTableName}', old.id);
477
+ end;
478
+ `);
479
+ }
480
+
481
+ // src/memory-db/memory-db.ts
482
+ async function createMemoryDb({
483
+ reactiveDb: _reactiveDb,
484
+ hlcCounter,
485
+ tabId,
486
+ crdtTables
487
+ }) {
488
+ const reactiveDb = _reactiveDb;
489
+ const db = reactiveDb.db;
490
+ applyMemoryDbSchema(db);
491
+ for (const table of crdtTables) {
492
+ makeCrdtTable({
493
+ db,
494
+ baseTableName: table.baseTableName,
495
+ crdtTableName: table.crdtTableName
496
+ });
497
+ }
498
+ const localSyncId = createSyncIdCounter({
499
+ initialSyncId: 0
500
+ });
501
+ const pendingLocalEvents = [];
502
+ registerCrdtFunctions({
503
+ db,
504
+ getTableSchema: (dataset) => db.dbSchema[dataset],
505
+ getNextTimestamp: () => serializeHLC(hlcCounter.getNextHLC()),
506
+ updateLogTableName: "crdt_update_log",
507
+ onEventApplied: (event) => {
508
+ const persistedEvent = {
509
+ ...event,
510
+ origin: tabId,
511
+ sync_id: ++localSyncId.current,
512
+ status: "applied"
513
+ };
514
+ enqueueCrdtEvent(db, persistedEvent);
515
+ pendingLocalEvents.push(persistedEvent);
516
+ }
517
+ });
518
+ db.createScalarFunction({
519
+ name: "gen_id",
520
+ callback: () => generateId(),
521
+ deterministic: false,
522
+ directOnly: false,
523
+ innocuous: true
524
+ });
525
+ reactiveDb.addEventListener("transaction-rolled-back", () => {
526
+ pendingLocalEvents.length = 0;
527
+ });
528
+ reactiveDb.addEventListener("transaction-committed", () => {
529
+ const appliedEvents = pendingLocalEvents.splice(0);
530
+ queueMicrotask(() => {
531
+ for (const event of appliedEvents) {
532
+ crdtStorage.dispatchEvent("event-applied", event);
533
+ }
534
+ crdtStorage.dispatchEvent("event-processing-done", void 0);
535
+ });
536
+ });
537
+ const crdtStorage = createCrdtStorage({
538
+ syncId: localSyncId,
539
+ persistEvents: (events) => persistEvents(db, events),
540
+ popPendingEventsBatch: () => popPendingEventsBatch(db, 50),
541
+ applyCrdtEventMutations: (event) => applyCrdtEventMutations({
542
+ db,
543
+ event,
544
+ updateLogTableName: "crdt_update_log"
545
+ }),
546
+ updateEventStatus: (syncId, status) => updateEventStatus(db, syncId, status)
547
+ });
548
+ return {
549
+ crdtStorage
550
+ };
551
+ }
552
+ function enqueueCrdtEvent(db, event) {
553
+ db.executePrepared(
554
+ "enqueue-crdt-events",
555
+ event,
556
+ (db2, params) => db2.insertInto("persisted_crdt_events").values({
557
+ status: params("status"),
558
+ sync_id: params("sync_id"),
559
+ type: params("type"),
560
+ timestamp: params("timestamp"),
561
+ dataset: params("dataset"),
562
+ item_id: params("item_id"),
563
+ payload: params("payload"),
564
+ origin: params("origin")
565
+ })
566
+ );
567
+ }
568
+ function persistEvents(db, events) {
569
+ db.executeTransaction((db2) => {
570
+ const chunkSize = 100;
571
+ for (let i = 0; i < events.length; i += chunkSize) {
572
+ const chunk = events.slice(i, i + chunkSize);
573
+ db2.executeKysely(
574
+ (db3) => db3.insertInto("persisted_crdt_events").values(chunk)
575
+ );
576
+ }
577
+ });
578
+ }
579
+ function popPendingEventsBatch(db, limit) {
580
+ const events = db.executePrepared(
581
+ "pop-enqueued-crdt-events",
582
+ {
583
+ limit
584
+ },
585
+ (db2, param) => db2.selectFrom("persisted_crdt_events").where("status", "=", sql.lit("pending")).limit(param("limit")).orderBy("sync_id", "asc").selectAll()
586
+ );
587
+ return {
588
+ events,
589
+ hasMore: events.length === limit
590
+ };
591
+ }
592
+ function updateEventStatus(db, syncId, status) {
593
+ db.executePrepared(
594
+ "update-crdt-event-status",
595
+ { syncId, status },
596
+ (db2, params) => db2.updateTable("persisted_crdt_events").set({ status: params("status") }).where("sync_id", "=", params("syncId"))
597
+ );
598
+ }
599
+
600
+ // src/sync-db.ts
601
+ async function createSyncedDb(options) {
602
+ if (!options.dbPath.startsWith("/")) {
603
+ throw new Error("dbPath must be an absolute path");
604
+ }
605
+ const tabId = generateId();
606
+ const broadcastChannels = createBroadcastChannels();
607
+ await initializeWorkerDb({
608
+ worker: options.worker,
609
+ broadcastChannels,
610
+ config: {
611
+ clientId: generateId(),
612
+ dbPath: options.dbPath,
613
+ clearOnInit: options.clearOnInit,
614
+ syncServer: {
615
+ host: "",
616
+ room: ""
617
+ }
618
+ }
619
+ });
620
+ const workerClient = createWorkerDbClient({
621
+ broadcastChannels
622
+ });
623
+ const hlcCounter = new HLCCounter(tabId, () => Date.now());
624
+ const workerClientSnapshot = await workerClient.getSnapshot();
625
+ const reactiveDb = await createSQLiteReactiveDb({
626
+ snapshot: workerClientSnapshot.file
627
+ });
628
+ const { crdtStorage } = await createMemoryDb({
629
+ reactiveDb,
630
+ hlcCounter,
631
+ tabId,
632
+ crdtTables: options.crdtTables
633
+ });
634
+ const remoteSyncId = createSyncIdCounter({
635
+ initialSyncId: workerClientSnapshot.syncId
636
+ });
637
+ const remoteSyncSource = createCrdtSyncRemoteSource({
638
+ bufferSize: 100,
639
+ syncId: remoteSyncId,
640
+ storage: crdtStorage,
641
+ nodeId: tabId,
642
+ pullEvents: (request) => workerClient.pullEvents(request),
643
+ pushEvents: (request) => workerClient.pushTabEvents(request)
644
+ });
645
+ workerClient.addEventListener("new-notification", (event) => {
646
+ const notification = event.payload;
647
+ if (notification.notificationType === "new-event-chunk-applied" && notification.newSyncId > remoteSyncId.current) {
648
+ remoteSyncSource.pullEvents();
649
+ }
650
+ });
651
+ crdtStorage.addEventListener("event-applied", (event) => {
652
+ if (event.payload.origin === "remote") {
653
+ hlcCounter.mergeHLC(deserializeHLC(event.payload.timestamp));
654
+ }
655
+ });
656
+ return {
657
+ db: reactiveDb.db,
658
+ reactiveDb,
659
+ workerDb: workerClient
660
+ };
661
+ }
662
+ export {
663
+ HLCCounter,
664
+ SQLiteDbWrapper,
665
+ SQLiteReactiveDb,
666
+ SqliteDriver,
667
+ TypedBroadcastChannel,
668
+ TypedEvent,
669
+ applyCrdtEventMutations,
670
+ applyMemoryDbSchema,
671
+ applyWorkerDbSchema,
672
+ broadcastChannelNames,
673
+ compareHLC,
674
+ crdtSchema,
675
+ createAsyncAutoFlushBuffer,
676
+ createAutoFlushBuffer,
677
+ createBroadcastChannels,
678
+ createCrdtStorage,
679
+ createCrdtSyncProducer,
680
+ createCrdtSyncRemoteSource,
681
+ createDeferredPromise,
682
+ createMemoryDb,
683
+ createSQLiteKysely,
684
+ createSQLiteReactiveDb,
685
+ createSyncDbMigrations,
686
+ createSyncDbMigrator,
687
+ createSyncIdCounter,
688
+ createSyncedDb,
689
+ createTypedEventTarget,
690
+ createWorkerDbClient,
691
+ deserializeHLC,
692
+ dummyKysely,
693
+ ensureSingletonExecution,
694
+ generateId,
695
+ initializeWorkerDb,
696
+ introspectDb,
697
+ isWorkerInitMessage,
698
+ isWorkerInitResponse,
699
+ isWorkerNotificationMessage,
700
+ isWorkerRequestMessage,
701
+ isWorkerResponseMessage,
702
+ jsonSafeParse,
703
+ makeCrdtTable,
704
+ orderBy,
705
+ registerCrdtFunctions,
706
+ serializeHLC,
707
+ startPerformanceLogger,
708
+ syncDbWorkerLockName
709
+ };
710
+ //# sourceMappingURL=index.js.map