@sqlite-sync/core 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,490 +0,0 @@
1
- // src/utils.ts
2
- function createDeferredPromise() {
3
- let resolve;
4
- let reject;
5
- const promise = new Promise((_resolve, _reject) => {
6
- resolve = _resolve;
7
- reject = _reject;
8
- });
9
- return { promise, resolve, reject };
10
- }
11
- var generateId = () => {
12
- return crypto.randomUUID();
13
- };
14
- function ensureSingletonExecution(fn) {
15
- let isExecuting = false;
16
- let shouldReExecute = false;
17
- const wrappedFn = () => {
18
- if (isExecuting) {
19
- shouldReExecute = true;
20
- return;
21
- }
22
- isExecuting = true;
23
- fn().finally(() => {
24
- isExecuting = false;
25
- if (shouldReExecute) {
26
- shouldReExecute = false;
27
- wrappedFn();
28
- }
29
- });
30
- };
31
- wrappedFn.isExecuting = () => isExecuting;
32
- return wrappedFn;
33
- }
34
- function orderBy(inputArray, picker, opts) {
35
- const array = opts?.inPlace ? inputArray : [...inputArray];
36
- const direction = opts?.direction ?? "asc";
37
- return array.sort((a, b) => {
38
- const aVal = picker(a);
39
- const bVal = picker(b);
40
- if (aVal < bVal) return direction === "asc" ? -1 : 1;
41
- if (aVal > bVal) return direction === "asc" ? 1 : -1;
42
- return 0;
43
- });
44
- }
45
- function createAutoFlushBuffer({
46
- size,
47
- flush
48
- }) {
49
- const buffer = [];
50
- return {
51
- add(item) {
52
- buffer.push(item);
53
- if (buffer.length >= size) {
54
- flush(buffer);
55
- buffer.length = 0;
56
- }
57
- },
58
- flush() {
59
- flush(buffer);
60
- buffer.length = 0;
61
- }
62
- };
63
- }
64
- function createAsyncAutoFlushBuffer({
65
- size,
66
- flush
67
- }) {
68
- const buffer = [];
69
- return {
70
- async add(item) {
71
- buffer.push(item);
72
- if (buffer.length >= size) {
73
- await this.flush();
74
- }
75
- },
76
- async flush() {
77
- const itemsToFlush = buffer.splice(0);
78
- if (itemsToFlush.length === 0) {
79
- return;
80
- }
81
- await flush(itemsToFlush);
82
- }
83
- };
84
- }
85
- var TypedBroadcastChannel = class {
86
- channel;
87
- constructor(name) {
88
- this.channel = new BroadcastChannel(name);
89
- }
90
- postMessage(message) {
91
- this.channel.postMessage(message);
92
- }
93
- set onmessage(callback) {
94
- this.channel.onmessage = callback;
95
- }
96
- };
97
- var TypedEvent = class extends Event {
98
- payload;
99
- constructor(type, payload) {
100
- super(type);
101
- this.payload = payload;
102
- }
103
- };
104
- var createTypedEventTarget = () => {
105
- const eventTarget = new EventTarget();
106
- const addEventListener = (type, listener) => {
107
- eventTarget.addEventListener(type, listener);
108
- };
109
- const removeEventListener = (type, listener) => {
110
- eventTarget.removeEventListener(type, listener);
111
- };
112
- const dispatchEvent = (type, payload) => {
113
- eventTarget.dispatchEvent(new TypedEvent(type, payload));
114
- };
115
- return {
116
- addEventListener,
117
- removeEventListener,
118
- dispatchEvent
119
- };
120
- };
121
- function jsonSafeParse(json) {
122
- try {
123
- return {
124
- status: "ok",
125
- data: JSON.parse(json)
126
- };
127
- } catch (error) {
128
- return {
129
- status: "error",
130
- error
131
- };
132
- }
133
- }
134
-
135
- // src/dummy-kysely.ts
136
- import {
137
- DummyDriver,
138
- Kysely,
139
- SqliteAdapter,
140
- SqliteIntrospector,
141
- SqliteQueryCompiler
142
- } from "kysely";
143
- var dummyKysely = new Kysely({
144
- dialect: {
145
- createAdapter: () => new SqliteAdapter(),
146
- createDriver: () => new DummyDriver(),
147
- createQueryCompiler: () => new SqliteQueryCompiler(),
148
- createIntrospector: (db) => new SqliteIntrospector(db)
149
- }
150
- });
151
-
152
- // src/sqlite-crdt/apply-crdt-event.ts
153
- function applyCrdtEventMutations({
154
- db,
155
- event,
156
- updateLogTableName
157
- }) {
158
- const eventPayload = JSON.parse(event.payload);
159
- const [metaRow] = db.executePrepared(
160
- "get-item-crdt-meta",
161
- {
162
- item_id: event.item_id,
163
- dataset: event.dataset
164
- },
165
- (db2, params) => {
166
- return db2.selectFrom(updateLogTableName).select("payload").where("item_id", "=", params("item_id")).where("dataset", "=", params("dataset"));
167
- }
168
- );
169
- const meta = metaRow ? JSON.parse(metaRow.payload) : null;
170
- const context = {
171
- db,
172
- updateLogTableName,
173
- event,
174
- meta,
175
- eventPayload
176
- };
177
- switch (event.type) {
178
- case "item-created": {
179
- applyItemCreated(context);
180
- break;
181
- }
182
- case "item-updated": {
183
- applyItemUpdated(context);
184
- break;
185
- }
186
- default:
187
- event.type;
188
- }
189
- }
190
- function applyItemCreated(context) {
191
- if (context.meta) {
192
- applyItemUpdated(context);
193
- return;
194
- }
195
- const keys = Array.from(Object.keys(context.eventPayload));
196
- context.db.execute({
197
- sql: `insert into ${context.event.dataset} (${keys.join(
198
- ","
199
- )}) values (${keys.map(() => "?").join(",")})`,
200
- parameters: keys.map((key) => context.eventPayload[key])
201
- });
202
- const newUpdateLog = Object.fromEntries(
203
- keys.map((key) => [key, context.event.timestamp])
204
- );
205
- insertCrdtUpdateLog(context, newUpdateLog);
206
- }
207
- function insertCrdtUpdateLog(context, log) {
208
- context.db.executePrepared(
209
- "insert-crdt-update-log",
210
- {
211
- item_id: context.event.item_id,
212
- dataset: context.event.dataset,
213
- payload: JSON.stringify(log)
214
- },
215
- (db, params) => db.insertInto(context.updateLogTableName).values({
216
- item_id: params("item_id"),
217
- dataset: params("dataset"),
218
- payload: params("payload")
219
- })
220
- );
221
- }
222
- function applyItemUpdated(context) {
223
- const meta = context.meta;
224
- if (!meta) {
225
- throw new Error(
226
- `Item ${context.event.item_id} in dataset ${context.event.dataset} not found`
227
- );
228
- }
229
- const keys = Array.from(Object.keys(context.eventPayload)).filter((key) => {
230
- const lastUpdateTimestamp = meta[key];
231
- if (!lastUpdateTimestamp) {
232
- return true;
233
- }
234
- const currentUpdateTimestamp = context.event.timestamp;
235
- return currentUpdateTimestamp > lastUpdateTimestamp;
236
- });
237
- if (keys.length > 0) {
238
- context.db.execute({
239
- sql: `update ${context.event.dataset} set ${keys.map((key) => `${key} = ?`).join(",")} where id = ?`,
240
- parameters: [
241
- ...keys.map((key) => context.eventPayload[key]),
242
- context.event.item_id
243
- ]
244
- });
245
- keys.forEach((key) => {
246
- meta[key] = context.event.timestamp;
247
- });
248
- updateCrdtUpdateLog(context, meta);
249
- }
250
- }
251
- function updateCrdtUpdateLog(context, log) {
252
- context.db.executePrepared(
253
- "update-crdt-update-log",
254
- {
255
- item_id: context.event.item_id,
256
- dataset: context.event.dataset,
257
- payload: JSON.stringify(log)
258
- },
259
- (db, params) => db.updateTable(context.updateLogTableName).set({
260
- payload: params("payload")
261
- }).where("item_id", "=", params("item_id")).where("dataset", "=", params("dataset"))
262
- );
263
- }
264
-
265
- // src/sqlite-crdt/crdt-table-schema.ts
266
- var crdtSchema = {
267
- metaTable: createMetaTableQuery,
268
- persistedEventsTable: createPersistedEventsTable,
269
- crdtUpdateLogTable: createCrdtUpdateLogTableQuery
270
- };
271
- function createMetaTableQuery(schema, tableName) {
272
- return schema.createTable(tableName).ifNotExists().addColumn("key", "text", (col) => col.notNull().primaryKey()).addColumn("value", "text", (col) => col.notNull());
273
- }
274
- function createPersistedEventsTable(schema, tableName) {
275
- return schema.createTable(tableName).ifNotExists().addColumn("sync_id", "integer", (col) => col.notNull().primaryKey()).addColumn("status", "text", (col) => col.notNull()).addColumn("type", "text", (col) => col.notNull()).addColumn("timestamp", "text", (col) => col.notNull()).addColumn("origin", "text", (col) => col.notNull()).addColumn("dataset", "text", (col) => col.notNull()).addColumn("item_id", "text", (col) => col.notNull()).addColumn("payload", "text", (col) => col.notNull());
276
- }
277
- function createCrdtUpdateLogTableQuery(schema, tableName) {
278
- return schema.createTable(tableName).ifNotExists().addColumn("dataset", "text", (col) => col.notNull()).addColumn("item_id", "text", (col) => col.notNull()).addColumn("payload", "text", (col) => col.notNull()).addPrimaryKeyConstraint(`pk_${tableName}`, ["item_id", "dataset"]);
279
- }
280
- function registerCrdtFunctions({
281
- db,
282
- onEventApplied,
283
- getNextTimestamp,
284
- getTableSchema,
285
- updateLogTableName
286
- }) {
287
- db.createScalarFunction({
288
- name: "handle_item_created",
289
- deterministic: false,
290
- directOnly: false,
291
- innocuous: false,
292
- callback: (dataset, payloadRaw) => {
293
- const payload = JSON.parse(payloadRaw);
294
- const event = {
295
- timestamp: getNextTimestamp(),
296
- type: "item-created",
297
- dataset,
298
- item_id: payload.id,
299
- payload: payloadRaw
300
- };
301
- applyCrdtEventMutations({
302
- db,
303
- event,
304
- updateLogTableName
305
- });
306
- onEventApplied(event);
307
- }
308
- });
309
- db.createScalarFunction({
310
- name: "handle_item_updated",
311
- deterministic: false,
312
- directOnly: false,
313
- innocuous: false,
314
- callback: (dataset, oldPayloadRaw, newPayloadRaw) => {
315
- const tableSchema = getTableSchema(dataset);
316
- const oldPayload = JSON.parse(oldPayloadRaw);
317
- const newPayload = JSON.parse(newPayloadRaw);
318
- let hasDiff = false;
319
- const payload = Object.fromEntries(
320
- tableSchema.columns.map((column) => {
321
- const oldValue = oldPayload[column.name];
322
- const newValue = newPayload[column.name];
323
- if (oldValue === newValue) {
324
- return null;
325
- }
326
- hasDiff = true;
327
- return [column.name, newValue];
328
- }).filter(Boolean)
329
- );
330
- const event = {
331
- timestamp: getNextTimestamp(),
332
- type: "item-updated",
333
- dataset,
334
- item_id: oldPayload.id,
335
- payload: JSON.stringify(payload)
336
- };
337
- if (!hasDiff) {
338
- return;
339
- }
340
- applyCrdtEventMutations({
341
- db,
342
- event,
343
- updateLogTableName
344
- });
345
- onEventApplied(event);
346
- }
347
- });
348
- db.createScalarFunction({
349
- name: "handle_item_deleted",
350
- deterministic: false,
351
- directOnly: false,
352
- innocuous: false,
353
- callback: (dataset, itemId) => {
354
- const event = {
355
- timestamp: getNextTimestamp(),
356
- type: "item-updated",
357
- dataset,
358
- item_id: itemId,
359
- payload: JSON.stringify({ tombstone: 1 })
360
- };
361
- applyCrdtEventMutations({
362
- db,
363
- event,
364
- updateLogTableName
365
- });
366
- onEventApplied(event);
367
- }
368
- });
369
- }
370
-
371
- // src/sqlite-crdt/sync-id-counter.ts
372
- function createSyncIdCounter({
373
- initialSyncId,
374
- saveToStorage
375
- }) {
376
- let currentSyncId = initialSyncId;
377
- return {
378
- get current() {
379
- return currentSyncId;
380
- },
381
- set current(newSyncId) {
382
- saveToStorage?.(newSyncId);
383
- currentSyncId = newSyncId;
384
- }
385
- };
386
- }
387
-
388
- // src/sqlite-crdt/crdt-storage.ts
389
- function createCrdtStorage(storage) {
390
- const eventTarget = createTypedEventTarget();
391
- const enqueueEvents = (events) => {
392
- const firstEventSyncId = storage.syncId.current + 1;
393
- storage.persistEvents(
394
- events.map((x) => ({
395
- timestamp: x.timestamp,
396
- type: x.type,
397
- dataset: x.dataset,
398
- item_id: x.item_id,
399
- origin: x.origin,
400
- payload: x.payload,
401
- sync_id: ++storage.syncId.current,
402
- status: "pending"
403
- }))
404
- );
405
- const lastEventSyncId = storage.syncId.current;
406
- processEnqueuedEvents();
407
- return {
408
- firstEventSyncId,
409
- lastEventSyncId
410
- };
411
- };
412
- const processEnqueuedEvents = ensureSingletonExecution(async () => {
413
- await Promise.resolve();
414
- let hasMore = true;
415
- while (hasMore) {
416
- const batch = storage.popPendingEventsBatch();
417
- const events = batch.events;
418
- hasMore = batch.hasMore;
419
- if (events.length === 0) {
420
- break;
421
- }
422
- for (const event of events) {
423
- try {
424
- storage.applyCrdtEventMutations(event);
425
- event.status = "applied";
426
- } catch (error) {
427
- console.error("Error applying enqueued CRDT event", error);
428
- event.status = "failed";
429
- } finally {
430
- storage.updateEventStatus(event.sync_id, event.status);
431
- eventTarget.dispatchEvent("event-applied", event);
432
- }
433
- }
434
- }
435
- eventTarget.dispatchEvent("event-processing-done", void 0);
436
- });
437
- return {
438
- enqueueEvents,
439
- addEventListener: eventTarget.addEventListener,
440
- removeEventListener: eventTarget.removeEventListener,
441
- dispatchEvent: eventTarget.dispatchEvent
442
- };
443
- }
444
-
445
- // src/sqlite-crdt/crdt-sync-producer.ts
446
- var createCrdtSyncProducer = ({
447
- bufferSize,
448
- storage,
449
- broadcastEvents
450
- }) => {
451
- const eventsBuffer = createAutoFlushBuffer({
452
- size: bufferSize,
453
- flush: (events) => {
454
- if (events.length === 0) {
455
- return;
456
- }
457
- broadcastEvents({ newSyncId: events[events.length - 1].sync_id });
458
- }
459
- });
460
- storage.addEventListener("event-applied", (event) => {
461
- if (event.payload.status !== "applied") {
462
- return;
463
- }
464
- eventsBuffer.add(event.payload);
465
- });
466
- storage.addEventListener("event-processing-done", () => {
467
- eventsBuffer.flush();
468
- });
469
- };
470
-
471
- export {
472
- createDeferredPromise,
473
- generateId,
474
- ensureSingletonExecution,
475
- orderBy,
476
- createAutoFlushBuffer,
477
- createAsyncAutoFlushBuffer,
478
- TypedBroadcastChannel,
479
- TypedEvent,
480
- createTypedEventTarget,
481
- jsonSafeParse,
482
- dummyKysely,
483
- applyCrdtEventMutations,
484
- crdtSchema,
485
- registerCrdtFunctions,
486
- createSyncIdCounter,
487
- createCrdtStorage,
488
- createCrdtSyncProducer
489
- };
490
- //# sourceMappingURL=chunk-YLXMST5Z.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils.ts","../src/dummy-kysely.ts","../src/sqlite-crdt/apply-crdt-event.ts","../src/sqlite-crdt/crdt-table-schema.ts","../src/sqlite-crdt/sync-id-counter.ts","../src/sqlite-crdt/crdt-storage.ts","../src/sqlite-crdt/crdt-sync-producer.ts"],"sourcesContent":["export type DeferredPromise<T> = {\n promise: Promise<T>;\n resolve: (value: T) => void;\n reject: (error: Error) => void;\n};\n\nexport function createDeferredPromise<T>(): DeferredPromise<T> {\n let resolve!: (value: T) => void;\n let reject!: (error: Error) => void;\n const promise = new Promise<T>((_resolve, _reject) => {\n resolve = _resolve;\n reject = _reject;\n });\n return { promise, resolve, reject };\n}\n\nexport const generateId = () => {\n return crypto.randomUUID();\n};\n\nexport type DistributiveOmit<T, K extends keyof T> = T extends any\n ? Omit<T, K>\n : never;\n\nexport function ensureSingletonExecution(fn: () => Promise<void>) {\n let isExecuting = false;\n let shouldReExecute = false;\n\n const wrappedFn = () => {\n if (isExecuting) {\n shouldReExecute = true;\n return;\n }\n\n isExecuting = true;\n fn().finally(() => {\n isExecuting = false;\n\n if (shouldReExecute) {\n shouldReExecute = false;\n wrappedFn();\n }\n });\n };\n\n wrappedFn.isExecuting = () => isExecuting;\n\n return wrappedFn;\n}\n\nexport function orderBy<T>(\n inputArray: T[],\n picker: (item: T) => any,\n opts?: {\n direction?: \"asc\" | \"desc\";\n inPlace?: boolean;\n }\n): T[] {\n const array = opts?.inPlace ? inputArray : [...inputArray];\n const direction = opts?.direction ?? \"asc\";\n return array.sort((a, b) => {\n const aVal = picker(a);\n const bVal = picker(b);\n\n if (aVal < bVal) return direction === \"asc\" ? -1 : 1;\n if (aVal > bVal) return direction === \"asc\" ? 1 : -1;\n return 0;\n });\n}\n\nexport function createAutoFlushBuffer<T>({\n size,\n flush,\n}: {\n size: number;\n flush: (items: T[]) => void;\n}) {\n const buffer: T[] = [];\n\n return {\n add(item: T) {\n buffer.push(item);\n if (buffer.length >= size) {\n flush(buffer);\n buffer.length = 0;\n }\n },\n flush() {\n flush(buffer);\n buffer.length = 0;\n },\n };\n}\n\nexport function createAsyncAutoFlushBuffer<T>({\n size,\n flush,\n}: {\n size: number;\n flush: (items: T[]) => void | Promise<void>;\n}) {\n const buffer: T[] = [];\n\n return {\n async add(item: T) {\n buffer.push(item);\n if (buffer.length >= size) {\n await this.flush();\n }\n },\n async flush() {\n const itemsToFlush = buffer.splice(0);\n if (itemsToFlush.length === 0) {\n return;\n }\n await flush(itemsToFlush);\n },\n };\n}\n\nexport class TypedBroadcastChannel<TMessage> {\n private readonly channel: BroadcastChannel;\n\n constructor(name: string) {\n this.channel = new BroadcastChannel(name);\n }\n\n postMessage(message: TMessage) {\n this.channel.postMessage(message);\n }\n\n set onmessage(callback: (event: MessageEvent<TMessage>) => void) {\n this.channel.onmessage = callback;\n }\n}\n\nexport class TypedEvent<T = unknown> extends Event {\n readonly payload: T;\n constructor(type: string, payload: T) {\n super(type);\n this.payload = payload;\n }\n}\n\nexport const createTypedEventTarget = <T extends Record<string, unknown>>() => {\n const eventTarget = new EventTarget();\n\n const addEventListener = <K extends keyof T & string>(\n type: K,\n listener: (event: TypedEvent<T[K]>) => void\n ) => {\n eventTarget.addEventListener(type, listener as (e: Event) => void);\n };\n\n const removeEventListener = <K extends keyof T & string>(\n type: K,\n listener: (event: TypedEvent<T[K]>) => void\n ) => {\n eventTarget.removeEventListener(type, listener as (e: Event) => void);\n };\n\n const dispatchEvent = <K extends keyof T & string>(\n type: K,\n payload: T[K]\n ) => {\n eventTarget.dispatchEvent(new TypedEvent(type, payload));\n };\n\n return {\n addEventListener,\n removeEventListener,\n dispatchEvent,\n };\n};\n\nexport function jsonSafeParse<T>(json: string):\n | {\n status: \"ok\";\n data: T;\n }\n | {\n status: \"error\";\n error: unknown;\n } {\n try {\n return {\n status: \"ok\",\n data: JSON.parse(json),\n };\n } catch (error) {\n return {\n status: \"error\",\n error,\n };\n }\n}\n\n","import {\n DummyDriver,\n Kysely,\n SqliteAdapter,\n SqliteIntrospector,\n SqliteQueryCompiler,\n} from \"kysely\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const dummyKysely: Kysely<any> = new Kysely({\n dialect: {\n createAdapter: () => new SqliteAdapter(),\n createDriver: () => new DummyDriver(),\n createQueryCompiler: () => new SqliteQueryCompiler(),\n createIntrospector: (db) => new SqliteIntrospector(db),\n },\n});\n\n","import { type Kysely } from \"kysely\";\nimport type { SQLiteTransactionWrapper } from \"../sqlite-db-wrapper\";\nimport type {\n CrdtEventType,\n CrdtUpdateLogItem,\n CrdtUpdateLogPayload,\n} from \"./crdt-table-schema\";\n\nexport type PendingCrdtEvent = {\n type: CrdtEventType;\n dataset: string;\n item_id: string;\n timestamp: string;\n payload: string;\n};\n\ntype ApplyCrdtParams = {\n updateLogTableName: string;\n db: SQLiteTransactionWrapper<any>;\n event: PendingCrdtEvent;\n};\n\ntype ApplyCrdtContext = {\n db: SQLiteTransactionWrapper<unknown>;\n updateLogTableName: string;\n event: PendingCrdtEvent;\n eventPayload: Record<string, unknown>;\n meta: CrdtUpdateLogPayload | null;\n};\n\nexport function applyCrdtEventMutations({\n db,\n event,\n updateLogTableName,\n}: ApplyCrdtParams) {\n const eventPayload = JSON.parse(event.payload);\n\n const [metaRow] = db.executePrepared(\n \"get-item-crdt-meta\",\n {\n item_id: event.item_id,\n dataset: event.dataset,\n },\n (db, params) => {\n return (db as unknown as Kysely<{ table: CrdtUpdateLogItem }>)\n .selectFrom(updateLogTableName as \"table\")\n .select(\"payload\")\n .where(\"item_id\", \"=\", params(\"item_id\"))\n .where(\"dataset\", \"=\", params(\"dataset\"));\n }\n );\n\n const meta = metaRow\n ? (JSON.parse(metaRow.payload) as CrdtUpdateLogPayload)\n : null;\n\n // TODO Check primary key / unique constraints\n\n const context: ApplyCrdtContext = {\n db: db as SQLiteTransactionWrapper<unknown>,\n updateLogTableName,\n event,\n meta,\n eventPayload,\n };\n\n switch (event.type) {\n case \"item-created\": {\n applyItemCreated(context);\n break;\n }\n case \"item-updated\": {\n applyItemUpdated(context);\n break;\n }\n default:\n event.type satisfies never;\n }\n}\n\nfunction applyItemCreated(context: ApplyCrdtContext) {\n if (context.meta) {\n // Item already exists\n applyItemUpdated(context);\n return;\n }\n\n // TODO SQL sanitization\n\n const keys = Array.from(Object.keys(context.eventPayload));\n context.db.execute({\n sql: `insert into ${context.event.dataset} (${keys.join(\n \",\"\n )}) values (${keys.map(() => \"?\").join(\",\")})`,\n parameters: keys.map((key) => context.eventPayload[key]),\n });\n\n const newUpdateLog = Object.fromEntries(\n keys.map((key) => [key, context.event.timestamp])\n );\n insertCrdtUpdateLog(context, newUpdateLog);\n}\n\nfunction insertCrdtUpdateLog(\n context: ApplyCrdtContext,\n log: Record<string, string>\n) {\n context.db.executePrepared(\n \"insert-crdt-update-log\",\n {\n item_id: context.event.item_id,\n dataset: context.event.dataset,\n payload: JSON.stringify(log),\n },\n (db, params) =>\n (db as unknown as Kysely<{ table: CrdtUpdateLogItem }>)\n .insertInto(context.updateLogTableName as \"table\")\n .values({\n item_id: params(\"item_id\"),\n dataset: params(\"dataset\"),\n payload: params(\"payload\"),\n })\n );\n}\n\nfunction applyItemUpdated(context: ApplyCrdtContext) {\n const meta = context.meta;\n if (!meta) {\n throw new Error(\n `Item ${context.event.item_id} in dataset ${context.event.dataset} not found`\n );\n }\n\n const keys = Array.from(Object.keys(context.eventPayload)).filter((key) => {\n const lastUpdateTimestamp = meta[key];\n if (!lastUpdateTimestamp) {\n return true;\n }\n\n const currentUpdateTimestamp = context.event.timestamp;\n return currentUpdateTimestamp > lastUpdateTimestamp;\n });\n\n if (keys.length > 0) {\n context.db.execute({\n sql: `update ${context.event.dataset} set ${keys\n .map((key) => `${key} = ?`)\n .join(\",\")} where id = ?`,\n parameters: [\n ...keys.map((key) => context.eventPayload[key]),\n context.event.item_id,\n ],\n });\n\n keys.forEach((key) => {\n meta[key] = context.event.timestamp;\n });\n updateCrdtUpdateLog(context, meta);\n }\n}\n\nfunction updateCrdtUpdateLog(\n context: ApplyCrdtContext,\n log: Record<string, string>\n) {\n context.db.executePrepared(\n \"update-crdt-update-log\",\n {\n item_id: context.event.item_id,\n dataset: context.event.dataset,\n payload: JSON.stringify(log),\n },\n (db, params) =>\n (db as unknown as Kysely<{ table: CrdtUpdateLogItem }>)\n .updateTable(context.updateLogTableName as \"table\")\n .set({\n payload: params(\"payload\"),\n })\n .where(\"item_id\", \"=\", params(\"item_id\"))\n .where(\"dataset\", \"=\", params(\"dataset\"))\n );\n}\n\n","import type { SchemaModule } from \"kysely\";\nimport type { SQLiteDbWrapper } from \"../sqlite-db-wrapper\";\nimport type { TableMetadata } from \"../introspection\";\nimport {\n applyCrdtEventMutations,\n type PendingCrdtEvent,\n} from \"./apply-crdt-event\";\n\nexport type CrdtEventType = \"item-created\" | \"item-updated\";\n\nexport type CrdtEventStatus = \"pending\" | \"applied\" | \"failed\";\n\nexport type CrdtEventOrigin = \"remote\" | (string & {});\n\nexport type PersistedCrdtEvent = {\n sync_id: number;\n status: CrdtEventStatus;\n type: CrdtEventType;\n timestamp: string;\n origin: CrdtEventOrigin;\n dataset: string;\n item_id: string;\n payload: string;\n};\n\nexport type CrdtUpdateLogItem = {\n dataset: string;\n item_id: string;\n payload: string;\n};\n\nexport type CrdtUpdateLogPayload = Record<string, string>;\n\nexport type MetaItem = {\n key: string;\n value: string;\n};\n\nexport const crdtSchema = {\n metaTable: createMetaTableQuery,\n persistedEventsTable: createPersistedEventsTable,\n crdtUpdateLogTable: createCrdtUpdateLogTableQuery,\n};\n\nfunction createMetaTableQuery(schema: SchemaModule, tableName: string) {\n return schema\n .createTable(tableName)\n .ifNotExists()\n .addColumn(\"key\", \"text\", (col) => col.notNull().primaryKey())\n .addColumn(\"value\", \"text\", (col) => col.notNull());\n}\n\nfunction createPersistedEventsTable(schema: SchemaModule, tableName: string) {\n return schema\n .createTable(tableName)\n .ifNotExists()\n .addColumn(\"sync_id\", \"integer\", (col) => col.notNull().primaryKey())\n .addColumn(\"status\", \"text\", (col) => col.notNull())\n .addColumn(\"type\", \"text\", (col) => col.notNull())\n .addColumn(\"timestamp\", \"text\", (col) => col.notNull())\n .addColumn(\"origin\", \"text\", (col) => col.notNull())\n .addColumn(\"dataset\", \"text\", (col) => col.notNull())\n .addColumn(\"item_id\", \"text\", (col) => col.notNull())\n .addColumn(\"payload\", \"text\", (col) => col.notNull());\n}\n\nfunction createCrdtUpdateLogTableQuery(\n schema: SchemaModule,\n tableName: string\n) {\n return schema\n .createTable(tableName)\n .ifNotExists()\n .addColumn(\"dataset\", \"text\", (col) => col.notNull())\n .addColumn(\"item_id\", \"text\", (col) => col.notNull())\n .addColumn(\"payload\", \"text\", (col) => col.notNull())\n .addPrimaryKeyConstraint(`pk_${tableName}`, [\"item_id\", \"dataset\"]);\n}\n\nexport function registerCrdtFunctions({\n db,\n onEventApplied,\n getNextTimestamp,\n getTableSchema,\n updateLogTableName,\n}: {\n db: SQLiteDbWrapper<any>;\n onEventApplied: (event: PendingCrdtEvent) => void;\n getNextTimestamp: () => string;\n getTableSchema: (dataset: string) => TableMetadata;\n updateLogTableName: string;\n}) {\n 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 const event: PendingCrdtEvent = {\n timestamp: getNextTimestamp(),\n type: \"item-created\",\n dataset,\n item_id: payload.id,\n payload: payloadRaw,\n };\n\n applyCrdtEventMutations({\n db,\n event,\n updateLogTableName,\n });\n\n onEventApplied(event);\n },\n });\n\n db.createScalarFunction({\n name: \"handle_item_updated\",\n deterministic: false,\n directOnly: false,\n innocuous: false,\n callback: (\n dataset: string,\n oldPayloadRaw: string,\n newPayloadRaw: string\n ) => {\n const tableSchema = getTableSchema(dataset);\n const oldPayload = JSON.parse(oldPayloadRaw);\n const newPayload = JSON.parse(newPayloadRaw);\n\n let hasDiff = false;\n const payload = Object.fromEntries(\n tableSchema.columns\n .map((column) => {\n const oldValue = oldPayload[column.name];\n const newValue = newPayload[column.name];\n if (oldValue === newValue) {\n return null as unknown as [string, unknown];\n }\n hasDiff = true;\n return [column.name, newValue] as const;\n })\n .filter(Boolean)\n );\n\n const event: PendingCrdtEvent = {\n timestamp: getNextTimestamp(),\n type: \"item-updated\",\n dataset,\n item_id: oldPayload.id,\n payload: JSON.stringify(payload),\n };\n\n if (!hasDiff) {\n return;\n }\n\n applyCrdtEventMutations({\n db,\n event,\n updateLogTableName,\n });\n onEventApplied(event);\n },\n });\n\n db.createScalarFunction({\n name: \"handle_item_deleted\",\n deterministic: false,\n directOnly: false,\n innocuous: false,\n callback: (dataset: string, itemId: string) => {\n const event: PendingCrdtEvent = {\n timestamp: getNextTimestamp(),\n type: \"item-updated\",\n dataset,\n item_id: itemId,\n payload: JSON.stringify({ tombstone: 1 }),\n };\n\n applyCrdtEventMutations({\n db,\n event,\n updateLogTableName,\n });\n onEventApplied(event);\n },\n });\n}\n\n","export type SyncIdCounter = {\n get current(): number;\n set current(newSyncId: number);\n};\n\nexport function createSyncIdCounter({\n initialSyncId,\n saveToStorage,\n}: {\n initialSyncId: number;\n saveToStorage?: (syncId: number) => void;\n}): SyncIdCounter {\n let currentSyncId = initialSyncId;\n\n return {\n get current() {\n return currentSyncId;\n },\n set current(newSyncId: number) {\n saveToStorage?.(newSyncId);\n currentSyncId = newSyncId;\n },\n };\n}\n\n","import { createTypedEventTarget, ensureSingletonExecution } from \"../utils\";\nimport type {\n CrdtEventOrigin,\n CrdtEventStatus,\n CrdtEventType,\n PersistedCrdtEvent,\n} from \"./crdt-table-schema\";\nimport type { SyncIdCounter } from \"./sync-id-counter\";\n\ntype LocalCrdtEvent = {\n type: CrdtEventType;\n timestamp: string;\n dataset: string;\n item_id: string;\n payload: string;\n origin: CrdtEventOrigin;\n};\n\ntype PendingEventsBatch = {\n events: PersistedCrdtEvent[];\n hasMore: boolean;\n};\n\ntype DbSyncerStorage = {\n syncId: SyncIdCounter;\n persistEvents: (events: PersistedCrdtEvent[]) => void;\n popPendingEventsBatch: () => PendingEventsBatch;\n updateEventStatus: (syncId: number, status: CrdtEventStatus) => void;\n applyCrdtEventMutations: (event: PersistedCrdtEvent) => void;\n};\n\nexport type CrdtStorage = ReturnType<typeof createCrdtStorage>;\n\nexport function createCrdtStorage(storage: DbSyncerStorage) {\n const eventTarget = createTypedEventTarget<{\n \"event-applied\": PersistedCrdtEvent;\n \"event-processing-done\": void;\n }>();\n\n const enqueueEvents = (events: LocalCrdtEvent[]) => {\n const firstEventSyncId = storage.syncId.current + 1;\n storage.persistEvents(\n events.map((x) => ({\n timestamp: x.timestamp,\n type: x.type,\n dataset: x.dataset,\n item_id: x.item_id,\n origin: x.origin,\n payload: x.payload,\n sync_id: ++storage.syncId.current,\n status: \"pending\",\n }))\n );\n const lastEventSyncId = storage.syncId.current;\n\n processEnqueuedEvents();\n\n return {\n firstEventSyncId,\n lastEventSyncId,\n };\n };\n\n const processEnqueuedEvents = ensureSingletonExecution(async () => {\n await Promise.resolve();\n\n let hasMore = true;\n while (hasMore) {\n const batch = storage.popPendingEventsBatch();\n const events = batch.events;\n hasMore = batch.hasMore;\n\n if (events.length === 0) {\n break;\n }\n\n for (const event of events) {\n try {\n storage.applyCrdtEventMutations(event);\n event.status = \"applied\";\n } catch (error) {\n console.error(\"Error applying enqueued CRDT event\", error);\n event.status = \"failed\";\n } finally {\n storage.updateEventStatus(event.sync_id, event.status);\n eventTarget.dispatchEvent(\"event-applied\", event);\n }\n }\n }\n eventTarget.dispatchEvent(\"event-processing-done\", undefined);\n });\n\n return {\n enqueueEvents,\n addEventListener: eventTarget.addEventListener,\n removeEventListener: eventTarget.removeEventListener,\n dispatchEvent: eventTarget.dispatchEvent,\n };\n}\n\n","import { createAutoFlushBuffer } from \"../utils\";\nimport type { CrdtStorage } from \"./crdt-storage\";\nimport type { PersistedCrdtEvent } from \"./crdt-table-schema\";\n\ntype CrdtSyncProducer = {\n bufferSize: number;\n storage: CrdtStorage;\n broadcastEvents: (request: { newSyncId: number }) => void;\n};\n\nexport const createCrdtSyncProducer = ({\n bufferSize,\n storage,\n broadcastEvents,\n}: CrdtSyncProducer) => {\n const eventsBuffer = createAutoFlushBuffer<PersistedCrdtEvent>({\n size: bufferSize,\n flush: (events) => {\n if (events.length === 0) {\n return;\n }\n\n broadcastEvents({ newSyncId: events[events.length - 1].sync_id });\n },\n });\n\n storage.addEventListener(\"event-applied\", (event) => {\n if (event.payload.status !== \"applied\") {\n return;\n }\n eventsBuffer.add(event.payload);\n });\n\n storage.addEventListener(\"event-processing-done\", () => {\n eventsBuffer.flush();\n });\n};\n\n"],"mappings":"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","names":["db"]}
@@ -1,15 +0,0 @@
1
- import { Kysely } from 'kysely';
2
- import { m as CrdtStorage } from './crdt-sync-remote-source-rrqinqLn.js';
3
-
4
- declare const dummyKysely: Kysely<any>;
5
-
6
- type CrdtSyncProducer = {
7
- bufferSize: number;
8
- storage: CrdtStorage;
9
- broadcastEvents: (request: {
10
- newSyncId: number;
11
- }) => void;
12
- };
13
- declare const createCrdtSyncProducer: ({ bufferSize, storage, broadcastEvents, }: CrdtSyncProducer) => void;
14
-
15
- export { createCrdtSyncProducer as c, dummyKysely as d };