@sqlite-sync/cloudflare 0.1.1 → 0.3.0

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _sqlite_sync_core from '@sqlite-sync/core';
2
- import { SyncDbSchema, CrdtStorageMutator, TypedEventTarget, CrdtEventStatus, CrdtEventType, CrdtEventOrigin, Migrations } from '@sqlite-sync/core';
2
+ import { InternalSQLiteWrapper, SyncDbSchema, CrdtStorageMutator, TypedEventTarget, CrdtEventStatus, CrdtEventType, CrdtEventOrigin, Migrations } from '@sqlite-sync/core';
3
3
  import { Compilable, Kysely } from 'kysely';
4
4
 
5
5
  type ExecuteParams = {
@@ -17,6 +17,7 @@ type KyselyExecutor<TDatabase> = {
17
17
  transaction: (callback: (tx: Pick<KyselyExecutor<TDatabase>, "execute" | "executeKysely">) => void) => void;
18
18
  };
19
19
  declare function createKyselyExecutor<TDatabase>(db: DurableObjectStorage): KyselyExecutor<TDatabase>;
20
+ declare function createCrdtStorageDb(executor: KyselyExecutor<any>): InternalSQLiteWrapper<any>;
20
21
 
21
22
  type TypedPersistedCrdtEvent<Schema extends SyncDbSchema> = {
22
23
  schema_version: number;
@@ -41,10 +42,10 @@ declare function createDurableObjectCrdtStorage<Schema extends SyncDbSchema>({ s
41
42
  crdtEventsTable: string;
42
43
  batchSize?: number;
43
44
  broadcastPayload: (payload: string) => void;
44
- }): {
45
+ }): Promise<{
45
46
  syncDb: ServerSyncDb<Schema>;
46
47
  remoteHandler: RemoteHandler;
47
- };
48
+ }>;
48
49
  type MessageResult = {
49
50
  success: true;
50
51
  payload: string;
@@ -68,4 +69,4 @@ declare function createMigrator(kv: SyncKvStorage, sqlExecutor: KyselyExecutor<a
68
69
  };
69
70
  type SyncDbMigrator = ReturnType<typeof createMigrator>;
70
71
 
71
- export { type KyselyExecutor, type RemoteHandler, type ServerSyncDb, type SyncDbMigrator, type TypedPersistedCrdtEvent, createKyselyExecutor, createMigrator, durableObjectAdapter };
72
+ export { type KyselyExecutor, type RemoteHandler, type ServerSyncDb, type SyncDbMigrator, type TypedPersistedCrdtEvent, createCrdtStorageDb, createKyselyExecutor, createMigrator, durableObjectAdapter };
package/dist/index.js CHANGED
@@ -1,17 +1,16 @@
1
1
  // src/durable-object-adapter.ts
2
2
  import {
3
- applyKyselyEventsBatchFilters,
4
3
  baseSystemMigrations,
5
- createCrdtApplyFunction,
6
4
  createCrdtStorage,
7
5
  createCrdtStorageMutator,
8
6
  createCrdtSyncProducer,
9
7
  createStoredValue as createStoredValue2,
8
+ createSystemDbConfig,
10
9
  createTypedEventTarget,
11
10
  HLCCounter,
12
11
  jsonSafeParse,
13
- quoteId,
14
- runSystemMigrations
12
+ runSystemMigrations,
13
+ xxhash
15
14
  } from "@sqlite-sync/core";
16
15
  import {
17
16
  syncServerZodSchema
@@ -38,6 +37,32 @@ function createKyselyExecutor(db) {
38
37
  };
39
38
  return executor;
40
39
  }
40
+ function createCrdtStorageDb(executor) {
41
+ const wrapper = {
42
+ executePreparedRaw: ({
43
+ sql,
44
+ params
45
+ }) => executor.execute({
46
+ sql,
47
+ parameters: params ?? []
48
+ }).rows,
49
+ executePrepared: (_, params, factory) => {
50
+ const query = factory(dummyKysely, (key) => key).compile();
51
+ const parameters = query.parameters.map((param) => params[param]);
52
+ const result = executor.execute({
53
+ sql: query.sql,
54
+ parameters
55
+ });
56
+ return result.rows;
57
+ }
58
+ };
59
+ return {
60
+ ...wrapper,
61
+ executeTransaction: (callback) => executor.transaction(() => {
62
+ callback(wrapper);
63
+ })
64
+ };
65
+ }
41
66
 
42
67
  // src/migrator.ts
43
68
  import { createMigrator as createBaseMigrator, createStoredValue } from "@sqlite-sync/core";
@@ -72,21 +97,7 @@ function createMigrator(kv, sqlExecutor, migrations, updateLogTableName2) {
72
97
 
73
98
  // src/durable-object-adapter.ts
74
99
  var updateLogTableName = "__crdt_update_log";
75
- var durableObjectMigrations = [
76
- ...baseSystemMigrations,
77
- {
78
- version: 2,
79
- up: (ctx) => {
80
- ctx.execute(
81
- `DELETE FROM ${ctx.eventsTableName} WHERE "sync_id" NOT IN (SELECT MIN("sync_id") FROM ${ctx.eventsTableName} GROUP BY "timestamp", "source_node_id")`
82
- );
83
- ctx.execute(
84
- `CREATE UNIQUE INDEX IF NOT EXISTS "idx_crdt_events_dedup" ON ${ctx.eventsTableName} ("timestamp", "source_node_id")`
85
- );
86
- }
87
- }
88
- ];
89
- function createDurableObjectCrdtStorage({
100
+ async function createDurableObjectCrdtStorage({
90
101
  storage,
91
102
  syncDbSchema,
92
103
  nodeId,
@@ -94,98 +105,49 @@ function createDurableObjectCrdtStorage({
94
105
  batchSize = 50,
95
106
  broadcastPayload
96
107
  }) {
108
+ await xxhash.ensureLoaded();
109
+ const dbConfig = createSystemDbConfig({
110
+ eventsTableName: crdtEventsTable,
111
+ updateLogTableName
112
+ });
97
113
  const eventTarget = createTypedEventTarget();
98
114
  const sqlExecutor = createKyselyExecutor(storage);
115
+ const crdtStorageDb = createCrdtStorageDb(sqlExecutor);
99
116
  runSystemMigrations({
100
- migrations: durableObjectMigrations,
117
+ migrations: baseSystemMigrations,
101
118
  version: createStoredValue2({
102
119
  initialValue: storage.kv.get("internal-schema-version") ?? -1,
103
120
  saveToStorage: (val) => storage.kv.put("internal-schema-version", val)
104
121
  }),
105
- eventsTableName: quoteId(crdtEventsTable),
106
- updateLogTableName: quoteId(updateLogTableName),
122
+ dbConfig,
107
123
  execute: (sql) => sqlExecutor.execute({ sql, parameters: [] }),
108
124
  transaction: (callback) => sqlExecutor.transaction(callback)
109
125
  });
110
- const syncId = createStoredValue2({
111
- initialValue: getLatestSyncId(sqlExecutor)
112
- });
113
- const migrator = createMigrator(storage.kv, sqlExecutor, syncDbSchema.migrations, quoteId(updateLogTableName));
126
+ const migrator = createMigrator(
127
+ storage.kv,
128
+ sqlExecutor,
129
+ syncDbSchema.migrations,
130
+ dbConfig.updateLogTable.fullIdentifier
131
+ );
114
132
  migrator.migrateDbToLatest();
115
- const baseApply = createCrdtApplyFunction({
116
- getCrdtUpdateLog(opts) {
117
- const [metaRow] = sqlExecutor.executeKysely(
118
- (db) => db.selectFrom(updateLogTableName).select("payload").where("item_id", "=", opts.itemId).where("dataset", "=", opts.dataset)
119
- ).rows;
120
- return metaRow ? JSON.parse(metaRow.payload) : null;
121
- },
122
- insertCrdtUpdateLog(opts) {
123
- sqlExecutor.executeKysely(
124
- (db) => db.insertInto(updateLogTableName).values({
125
- item_id: opts.itemId,
126
- dataset: opts.dataset,
127
- payload: opts.payload
128
- })
129
- );
130
- },
131
- updateCrdtUpdateLog(opts) {
132
- sqlExecutor.executeKysely(
133
- (db) => db.updateTable(updateLogTableName).set({
134
- payload: opts.payload
135
- }).where("item_id", "=", opts.itemId).where("dataset", "=", opts.dataset)
136
- );
137
- },
138
- insertItem(opts) {
139
- sqlExecutor.executeKysely((db) => db.insertInto(opts.dataset).values(opts.payload));
140
- },
141
- updateItem(opts) {
142
- const keys = Array.from(Object.keys(opts.payload));
143
- sqlExecutor.execute({
144
- sql: `update ${quoteId(opts.dataset)} set ${keys.map((key) => `${quoteId(key)} = ?`).join(",")} where id = ?`,
145
- parameters: [...keys.map((key) => opts.payload[key]), opts.itemId]
146
- });
147
- }
148
- });
149
- const handleCrdtEventApply = (event) => {
150
- sqlExecutor.transaction(() => {
151
- baseApply(event);
152
- });
153
- queueMicrotask(() => {
154
- eventTarget.dispatchEvent("event-applied", event);
155
- });
156
- };
157
133
  const truncatedNodeId = nodeId.slice(0, 12);
158
134
  const hlc = new HLCCounter(truncatedNodeId, () => Date.now());
159
135
  const crdtStorage = createCrdtStorage({
160
136
  nodeId: truncatedNodeId,
161
- syncId,
137
+ initialLocalSyncId: getLatestSyncId(sqlExecutor),
162
138
  hlc,
163
139
  migrator,
164
- handleCrdtEventApply,
165
- transaction: (callback) => sqlExecutor.transaction(callback),
166
- getEventsBatch: (opts) => {
167
- return sqlExecutor.executeKysely(
168
- (db) => applyKyselyEventsBatchFilters(db.selectFrom(crdtEventsTable).selectAll(), {
169
- ...opts,
170
- limit: opts.limit ?? batchSize
171
- })
172
- ).rows;
173
- },
174
- persistEvent: (event) => {
175
- sqlExecutor.executeKysely(
176
- (db) => db.insertInto(crdtEventsTable).values(event).onConflict((oc) => oc.columns(["timestamp", "source_node_id"]).doNothing())
177
- );
178
- },
179
- updateEvent: (syncId2, event) => sqlExecutor.executeKysely(
180
- (db) => db.updateTable(crdtEventsTable).set({
181
- status: event.status,
182
- dataset: event.dataset,
183
- item_id: event.item_id,
184
- schema_version: event.schema_version,
185
- type: event.type,
186
- payload: event.payload
187
- }).where("sync_id", "=", syncId2)
188
- )
140
+ db: crdtStorageDb,
141
+ dbConfig,
142
+ eventHlcAccumulator: createStoredValue2({
143
+ initialValue: storage.kv.get("crdt.consistency.event_hlc_sum.v3") ?? "",
144
+ saveToStorage: (val) => storage.kv.put("crdt.consistency.event_hlc_sum.v3", val)
145
+ }),
146
+ onEventApplied: (event) => {
147
+ queueMicrotask(() => {
148
+ eventTarget.dispatchEvent("event-applied", event);
149
+ });
150
+ }
189
151
  });
190
152
  const remoteHandler = createDurableObjectRemoteHandler({
191
153
  bufferSize: batchSize,
@@ -218,7 +180,8 @@ function createDurableObjectRemoteHandler({
218
180
  broadcastPayload(
219
181
  JSON.stringify({
220
182
  type: "events-applied",
221
- newSyncId: chunk.newSyncId
183
+ newSyncId: chunk.newSyncId,
184
+ eventHlcSum: chunk.eventHlcSum
222
185
  })
223
186
  );
224
187
  }
@@ -249,7 +212,7 @@ function createDurableObjectRemoteHandler({
249
212
  limit: bufferSize,
250
213
  status: "applied",
251
214
  afterSyncId: request.afterSyncId,
252
- excludeNodeId: request.excludeNodeId
215
+ excludeNodeId: request.excludeNodeId ?? ""
253
216
  });
254
217
  const eventsPullMessage = {
255
218
  type: "events-pull-response",
@@ -273,12 +236,14 @@ function createDurableObjectRemoteHandler({
273
236
  };
274
237
  };
275
238
  const handlePushEvents = (request) => {
276
- crdtStorage.enqueueLocalEvents(request.events, request.nodeId);
239
+ const { beforeSyncId, afterSyncId } = crdtStorage.enqueueLocalEvents(request.events, request.nodeId);
277
240
  const eventsAppliedMessage = {
278
241
  type: "events-push-response",
279
242
  requestId: request.requestId,
280
243
  data: {
281
- ok: true
244
+ ok: true,
245
+ beforeSyncId,
246
+ afterSyncId
282
247
  }
283
248
  };
284
249
  return {
@@ -298,6 +263,7 @@ var durableObjectAdapter = {
298
263
  createCrdtStorage: createDurableObjectCrdtStorage
299
264
  };
300
265
  export {
266
+ createCrdtStorageDb,
301
267
  createKyselyExecutor,
302
268
  createMigrator,
303
269
  durableObjectAdapter
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/durable-object-adapter.ts","../src/kysely-executor.ts","../src/migrator.ts"],"sourcesContent":["import {\n applyKyselyEventsBatchFilters,\n baseSystemMigrations,\n type CrdtEventOrigin,\n type CrdtEventStatus,\n type CrdtEventType,\n type CrdtStorage,\n type CrdtStorageMutator,\n type CrdtUpdateLogItem,\n type CrdtUpdateLogPayload,\n createCrdtApplyFunction,\n createCrdtStorage,\n createCrdtStorageMutator,\n createCrdtSyncProducer,\n createStoredValue,\n createTypedEventTarget,\n HLCCounter,\n jsonSafeParse,\n type PersistedCrdtEvent,\n quoteId,\n runSystemMigrations,\n type SyncDbSchema,\n type SystemMigration,\n type TypedEventTarget,\n} from \"@sqlite-sync/core\";\nimport {\n type ExtractSyncServerRequest,\n type SyncServerMessage,\n type SyncServerRequest,\n syncServerZodSchema,\n} from \"@sqlite-sync/core/server\";\nimport { createKyselyExecutor, type KyselyExecutor } from \"./kysely-executor\";\nimport { createMigrator } from \"./migrator\";\n\nconst updateLogTableName = \"__crdt_update_log\";\n\nconst durableObjectMigrations: SystemMigration[] = [\n ...baseSystemMigrations,\n {\n version: 2,\n up: (ctx) => {\n ctx.execute(\n `DELETE FROM ${ctx.eventsTableName} WHERE \"sync_id\" NOT IN ` +\n `(SELECT MIN(\"sync_id\") FROM ${ctx.eventsTableName} GROUP BY \"timestamp\", \"source_node_id\")`,\n );\n ctx.execute(\n `CREATE UNIQUE INDEX IF NOT EXISTS \"idx_crdt_events_dedup\" ` +\n `ON ${ctx.eventsTableName} (\"timestamp\", \"source_node_id\")`,\n );\n },\n },\n];\n\ntype AdapterDb = {\n crdtEvents: PersistedCrdtEvent;\n [updateLogTableName]: CrdtUpdateLogItem;\n};\n\nexport type TypedPersistedCrdtEvent<Schema extends SyncDbSchema> = {\n schema_version: number;\n sync_id: number;\n status: CrdtEventStatus;\n type: CrdtEventType;\n timestamp: string;\n origin: CrdtEventOrigin;\n source_node_id: string;\n dataset: keyof Schema[`~mutationsSchema`];\n item_id: string;\n payload: string;\n};\n\ntype ServerSyncDbEvents<Schema extends SyncDbSchema> = {\n \"event-applied\": TypedPersistedCrdtEvent<Schema>;\n};\n\nexport type ServerSyncDb<Schema extends SyncDbSchema> = Pick<\n KyselyExecutor<Schema[`~serverSchema`]>,\n \"execute\" | \"executeKysely\"\n> &\n CrdtStorageMutator<Schema[`~mutationsSchema`]> &\n Pick<TypedEventTarget<ServerSyncDbEvents<Schema>>, \"addEventListener\" | \"removeEventListener\">;\n\nfunction createDurableObjectCrdtStorage<Schema extends SyncDbSchema>({\n storage,\n syncDbSchema,\n nodeId,\n crdtEventsTable = \"crdt_events\",\n batchSize = 50,\n broadcastPayload,\n}: {\n storage: DurableObjectStorage;\n syncDbSchema: Schema;\n nodeId: string;\n crdtEventsTable: string;\n batchSize?: number;\n broadcastPayload: (payload: string) => void;\n}): {\n syncDb: ServerSyncDb<Schema>;\n remoteHandler: RemoteHandler;\n} {\n const eventTarget = createTypedEventTarget<ServerSyncDbEvents<Schema>>();\n const sqlExecutor = createKyselyExecutor<AdapterDb>(storage);\n\n runSystemMigrations({\n migrations: durableObjectMigrations,\n version: createStoredValue<number>({\n initialValue: storage.kv.get(\"internal-schema-version\") ?? -1,\n saveToStorage: (val) => storage.kv.put(\"internal-schema-version\", val),\n }),\n eventsTableName: quoteId(crdtEventsTable),\n updateLogTableName: quoteId(updateLogTableName),\n execute: (sql) => sqlExecutor.execute({ sql, parameters: [] }),\n transaction: (callback) => sqlExecutor.transaction(callback),\n });\n\n const syncId = createStoredValue({\n initialValue: getLatestSyncId(sqlExecutor),\n });\n\n const migrator = createMigrator(storage.kv, sqlExecutor, syncDbSchema.migrations, quoteId(updateLogTableName));\n migrator.migrateDbToLatest();\n\n const baseApply = createCrdtApplyFunction({\n getCrdtUpdateLog(opts) {\n const [metaRow] = sqlExecutor.executeKysely((db) =>\n db\n .selectFrom(updateLogTableName)\n .select(\"payload\")\n .where(\"item_id\", \"=\", opts.itemId)\n .where(\"dataset\", \"=\", opts.dataset),\n ).rows;\n return metaRow ? (JSON.parse(metaRow.payload) as CrdtUpdateLogPayload) : null;\n },\n insertCrdtUpdateLog(opts) {\n sqlExecutor.executeKysely((db) =>\n db.insertInto(updateLogTableName).values({\n item_id: opts.itemId,\n dataset: opts.dataset,\n payload: opts.payload,\n }),\n );\n },\n updateCrdtUpdateLog(opts) {\n sqlExecutor.executeKysely((db) =>\n db\n .updateTable(updateLogTableName)\n .set({\n payload: opts.payload,\n })\n .where(\"item_id\", \"=\", opts.itemId)\n .where(\"dataset\", \"=\", opts.dataset),\n );\n },\n insertItem(opts) {\n sqlExecutor.executeKysely((db) => db.insertInto(opts.dataset as any).values(opts.payload));\n },\n updateItem(opts) {\n const keys = Array.from(Object.keys(opts.payload));\n sqlExecutor.execute({\n sql: `update ${quoteId(opts.dataset)} set ${keys.map((key) => `${quoteId(key)} = ?`).join(\",\")} where id = ?`,\n parameters: [...keys.map((key) => opts.payload[key]), opts.itemId],\n });\n },\n });\n\n const handleCrdtEventApply = (event: PersistedCrdtEvent) => {\n sqlExecutor.transaction(() => {\n baseApply(event);\n });\n\n queueMicrotask(() => {\n eventTarget.dispatchEvent(\"event-applied\", event as TypedPersistedCrdtEvent<Schema>);\n });\n };\n\n const truncatedNodeId = nodeId.slice(0, 12);\n const hlc = new HLCCounter(truncatedNodeId, () => Date.now());\n\n const crdtStorage = createCrdtStorage({\n nodeId: truncatedNodeId,\n syncId,\n hlc,\n migrator: migrator,\n handleCrdtEventApply,\n transaction: (callback) => sqlExecutor.transaction(callback),\n getEventsBatch: (opts) => {\n return sqlExecutor.executeKysely((db) =>\n applyKyselyEventsBatchFilters(db.selectFrom(crdtEventsTable as \"crdtEvents\").selectAll(), {\n ...opts,\n limit: opts.limit ?? batchSize,\n }),\n ).rows;\n },\n persistEvent: (event) => {\n sqlExecutor.executeKysely((db) =>\n db\n .insertInto(crdtEventsTable as \"crdtEvents\")\n .values(event)\n .onConflict((oc) => oc.columns([\"timestamp\", \"source_node_id\"]).doNothing()),\n );\n },\n updateEvent: (syncId, event) =>\n sqlExecutor.executeKysely((db) =>\n db\n .updateTable(crdtEventsTable as \"crdtEvents\")\n .set({\n status: event.status,\n dataset: event.dataset,\n item_id: event.item_id,\n schema_version: event.schema_version,\n type: event.type,\n payload: event.payload,\n })\n .where(\"sync_id\", \"=\", syncId),\n ),\n });\n\n const remoteHandler = createDurableObjectRemoteHandler({\n bufferSize: batchSize,\n crdtStorage,\n broadcastPayload,\n });\n\n const syncDbMutator = createCrdtStorageMutator<Schema[`~mutationsSchema`]>({\n storage: crdtStorage,\n });\n\n const syncDbExecutor = sqlExecutor as unknown as KyselyExecutor<Schema[`~serverSchema`]>;\n const syncDb: ServerSyncDb<Schema> = {\n ...syncDbExecutor,\n ...syncDbMutator,\n addEventListener: eventTarget.addEventListener,\n removeEventListener: eventTarget.removeEventListener,\n };\n\n return {\n syncDb,\n remoteHandler,\n };\n}\n\ntype MessageResult = { success: true; payload: string } | { success: false; error: unknown };\nexport type RemoteHandler = {\n handleMessage: (message: string) => MessageResult;\n};\n\nfunction createDurableObjectRemoteHandler({\n bufferSize = 50,\n crdtStorage,\n broadcastPayload,\n}: {\n bufferSize?: number;\n crdtStorage: CrdtStorage;\n broadcastPayload: (payload: string) => void;\n}): RemoteHandler {\n createCrdtSyncProducer({\n storage: crdtStorage,\n broadcastEvents: (chunk) => {\n broadcastPayload(\n JSON.stringify({\n type: \"events-applied\",\n newSyncId: chunk.newSyncId,\n }),\n );\n },\n });\n\n const handleMessage = (message: string): MessageResult => {\n const requestRaw = jsonSafeParse<SyncServerRequest>(message);\n\n if (!requestRaw.success) {\n return { success: false, error: requestRaw.error };\n }\n\n const requestResult = syncServerZodSchema.request.safeParse(requestRaw.data);\n\n if (!requestResult.success) {\n console.log(\"Invalid request\", requestResult.error);\n return { success: false, error: requestResult.error };\n }\n\n const request = requestResult.data;\n\n switch (request.type) {\n case \"pull-events\":\n return handlePullEvents(request);\n case \"push-events\":\n return handlePushEvents(request);\n default:\n request satisfies never;\n return { success: false, error: new Error(\"Invalid request type\") };\n }\n };\n\n const handlePullEvents = (request: ExtractSyncServerRequest<\"pull-events\">): MessageResult => {\n const batch = crdtStorage.getEventsBatch({\n limit: bufferSize,\n status: \"applied\",\n afterSyncId: request.afterSyncId,\n excludeNodeId: request.excludeNodeId,\n });\n\n const eventsPullMessage: SyncServerMessage = {\n type: \"events-pull-response\",\n requestId: request.requestId,\n data: {\n hasMore: batch.hasMore,\n nextSyncId: batch.nextSyncId,\n events: batch.events.map((x) => ({\n schema_version: x.schema_version,\n timestamp: x.timestamp,\n type: x.type,\n dataset: x.dataset,\n item_id: x.item_id,\n payload: x.payload,\n })),\n },\n };\n\n return {\n success: true,\n payload: JSON.stringify(eventsPullMessage),\n };\n };\n\n const handlePushEvents = (request: ExtractSyncServerRequest<\"push-events\">): MessageResult => {\n crdtStorage.enqueueLocalEvents(request.events, request.nodeId);\n const eventsAppliedMessage: SyncServerMessage = {\n type: \"events-push-response\",\n requestId: request.requestId,\n data: {\n ok: true,\n },\n };\n\n return {\n success: true,\n payload: JSON.stringify(eventsAppliedMessage),\n };\n };\n\n return { handleMessage };\n}\n\nfunction getLatestSyncId(executor: KyselyExecutor<any>) {\n const result = executor.executeKysely((db) =>\n db.selectFrom(\"crdt_events\").select((eb) => eb.fn.max(\"sync_id\").as(\"sync_id\")),\n );\n return result.rows[0]?.sync_id ?? 0;\n}\n\nexport const durableObjectAdapter = {\n createCrdtStorage: createDurableObjectCrdtStorage,\n};\n","import { dummyKysely } from \"@sqlite-sync/core\";\nimport type { Compilable, Kysely } from \"kysely\";\n\ntype ExecuteParams = {\n sql: string;\n parameters: readonly unknown[];\n};\n\ntype ExecuteResult<T> = {\n rows: T[];\n};\n\ntype QueryBuilderOutput<QB> = QB extends Compilable<infer O> ? O : never;\n\ntype KyselyQueryFactory<TDatabase, TQuery extends Compilable<TResult>, TResult = QueryBuilderOutput<TQuery>> = (\n kysely: Kysely<TDatabase>,\n) => TQuery;\n\nexport type KyselyExecutor<TDatabase> = {\n execute<TResult = unknown>(query: ExecuteParams): ExecuteResult<TResult>;\n executeKysely<TQuery extends Compilable<TResult>, TResult = QueryBuilderOutput<TQuery>>(\n factory: KyselyQueryFactory<TDatabase, TQuery, TResult>,\n ): ExecuteResult<TResult>;\n transaction: (callback: (tx: Pick<KyselyExecutor<TDatabase>, \"execute\" | \"executeKysely\">) => void) => void;\n};\n\nexport function createKyselyExecutor<TDatabase>(db: DurableObjectStorage): KyselyExecutor<TDatabase> {\n const execute = <TResult = unknown>(query: ExecuteParams): ExecuteResult<TResult> => {\n const rows = db.sql.exec(query.sql, ...query.parameters).toArray();\n return { rows: rows as TResult[] };\n };\n\n const executeKysely = <TQuery extends Compilable<TResult>, TResult = QueryBuilderOutput<TQuery>>(\n factory: KyselyQueryFactory<TDatabase, TQuery, TResult>,\n ): ExecuteResult<TResult> => {\n const query = factory(dummyKysely as any).compile();\n return execute(query);\n };\n\n const transaction = (callback: (tx: Pick<KyselyExecutor<TDatabase>, \"execute\" | \"executeKysely\">) => void) => {\n db.transactionSync(() => callback(executor));\n };\n\n const executor = {\n execute,\n executeKysely,\n transaction,\n };\n\n return executor;\n}\n","import { createMigrator as createBaseMigrator, createStoredValue, type Migrations } from \"@sqlite-sync/core\";\nimport type { KyselyExecutor } from \"./kysely-executor\";\n\nexport function createMigrator(\n kv: SyncKvStorage,\n sqlExecutor: KyselyExecutor<any>,\n migrations: Migrations,\n updateLogTableName?: string,\n) {\n const schemaVersion = createStoredValue<number>({\n initialValue: kv.get(\"schema-version\") ?? -1,\n saveToStorage: (val) => kv.put(\"schema-version\", val),\n });\n\n const baseMigrator = createBaseMigrator({\n migrations,\n schemaVersion,\n updateLogTableName,\n });\n\n return {\n ...baseMigrator,\n migrateDbToLatest: () => {\n baseMigrator.migrateDbToLatest({\n startTransaction: (callback) => {\n sqlExecutor.transaction(() => {\n return callback({\n execute: (sql, parameters) =>\n sqlExecutor.execute({\n sql,\n parameters,\n }),\n });\n });\n },\n });\n },\n };\n}\n\nexport type SyncDbMigrator = ReturnType<typeof createMigrator>;\n"],"mappings":"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","names":["createStoredValue","updateLogTableName","createStoredValue","syncId"]}
1
+ {"version":3,"sources":["../src/durable-object-adapter.ts","../src/kysely-executor.ts","../src/migrator.ts"],"sourcesContent":["import {\n baseSystemMigrations,\n type CrdtEventOrigin,\n type CrdtEventStatus,\n type CrdtEventType,\n type CrdtStorage,\n type CrdtStorageMutator,\n type CrdtUpdateLogItem,\n createCrdtStorage,\n createCrdtStorageMutator,\n createCrdtSyncProducer,\n createStoredValue,\n createSystemDbConfig,\n createTypedEventTarget,\n HLCCounter,\n jsonSafeParse,\n type PersistedCrdtEvent,\n runSystemMigrations,\n type SyncDbSchema,\n type TypedEventTarget,\n xxhash,\n} from \"@sqlite-sync/core\";\nimport {\n type ExtractSyncServerRequest,\n type SyncServerMessage,\n type SyncServerRequest,\n syncServerZodSchema,\n} from \"@sqlite-sync/core/server\";\nimport { createCrdtStorageDb, createKyselyExecutor, type KyselyExecutor } from \"./kysely-executor\";\nimport { createMigrator } from \"./migrator\";\n\nconst updateLogTableName = \"__crdt_update_log\";\n\ntype AdapterDb = {\n crdtEvents: PersistedCrdtEvent;\n [updateLogTableName]: CrdtUpdateLogItem;\n};\n\nexport type TypedPersistedCrdtEvent<Schema extends SyncDbSchema> = {\n schema_version: number;\n sync_id: number;\n status: CrdtEventStatus;\n type: CrdtEventType;\n timestamp: string;\n origin: CrdtEventOrigin;\n source_node_id: string;\n dataset: keyof Schema[`~mutationsSchema`];\n item_id: string;\n payload: string;\n};\n\ntype ServerSyncDbEvents<Schema extends SyncDbSchema> = {\n \"event-applied\": TypedPersistedCrdtEvent<Schema>;\n};\n\nexport type ServerSyncDb<Schema extends SyncDbSchema> = Pick<\n KyselyExecutor<Schema[`~serverSchema`]>,\n \"execute\" | \"executeKysely\"\n> &\n CrdtStorageMutator<Schema[`~mutationsSchema`]> &\n Pick<TypedEventTarget<ServerSyncDbEvents<Schema>>, \"addEventListener\" | \"removeEventListener\">;\n\nasync function createDurableObjectCrdtStorage<Schema extends SyncDbSchema>({\n storage,\n syncDbSchema,\n nodeId,\n crdtEventsTable = \"crdt_events\",\n batchSize = 50,\n broadcastPayload,\n}: {\n storage: DurableObjectStorage;\n syncDbSchema: Schema;\n nodeId: string;\n crdtEventsTable: string;\n batchSize?: number;\n broadcastPayload: (payload: string) => void;\n}): Promise<{\n syncDb: ServerSyncDb<Schema>;\n remoteHandler: RemoteHandler;\n}> {\n await xxhash.ensureLoaded();\n\n const dbConfig = createSystemDbConfig({\n eventsTableName: crdtEventsTable,\n updateLogTableName: updateLogTableName,\n });\n\n const eventTarget = createTypedEventTarget<ServerSyncDbEvents<Schema>>();\n const sqlExecutor = createKyselyExecutor<AdapterDb>(storage);\n const crdtStorageDb = createCrdtStorageDb(sqlExecutor);\n\n runSystemMigrations({\n migrations: baseSystemMigrations,\n version: createStoredValue<number>({\n initialValue: storage.kv.get(\"internal-schema-version\") ?? -1,\n saveToStorage: (val) => storage.kv.put(\"internal-schema-version\", val),\n }),\n dbConfig,\n execute: (sql) => sqlExecutor.execute({ sql, parameters: [] }),\n transaction: (callback) => sqlExecutor.transaction(callback),\n });\n\n const migrator = createMigrator(\n storage.kv,\n sqlExecutor,\n syncDbSchema.migrations,\n dbConfig.updateLogTable.fullIdentifier,\n );\n migrator.migrateDbToLatest();\n\n const truncatedNodeId = nodeId.slice(0, 12);\n const hlc = new HLCCounter(truncatedNodeId, () => Date.now());\n\n const crdtStorage = createCrdtStorage({\n nodeId: truncatedNodeId,\n initialLocalSyncId: getLatestSyncId(sqlExecutor),\n hlc,\n migrator: migrator,\n db: crdtStorageDb,\n dbConfig,\n eventHlcAccumulator: createStoredValue<string>({\n initialValue: storage.kv.get(\"crdt.consistency.event_hlc_sum.v3\") ?? \"\",\n saveToStorage: (val) => storage.kv.put(\"crdt.consistency.event_hlc_sum.v3\", val),\n }),\n onEventApplied: (event) => {\n queueMicrotask(() => {\n eventTarget.dispatchEvent(\"event-applied\", event as TypedPersistedCrdtEvent<Schema>);\n });\n },\n });\n\n const remoteHandler = createDurableObjectRemoteHandler({\n bufferSize: batchSize,\n crdtStorage,\n broadcastPayload,\n });\n\n const syncDbMutator = createCrdtStorageMutator<Schema[`~mutationsSchema`]>({\n storage: crdtStorage,\n });\n\n const syncDbExecutor = sqlExecutor as unknown as KyselyExecutor<Schema[`~serverSchema`]>;\n const syncDb: ServerSyncDb<Schema> = {\n ...syncDbExecutor,\n ...syncDbMutator,\n addEventListener: eventTarget.addEventListener,\n removeEventListener: eventTarget.removeEventListener,\n };\n\n return {\n syncDb,\n remoteHandler,\n };\n}\n\ntype MessageResult = { success: true; payload: string } | { success: false; error: unknown };\nexport type RemoteHandler = {\n handleMessage: (message: string) => MessageResult;\n};\n\nfunction createDurableObjectRemoteHandler({\n bufferSize = 50,\n crdtStorage,\n broadcastPayload,\n}: {\n bufferSize?: number;\n crdtStorage: CrdtStorage;\n broadcastPayload: (payload: string) => void;\n}): RemoteHandler {\n createCrdtSyncProducer({\n storage: crdtStorage,\n broadcastEvents: (chunk) => {\n broadcastPayload(\n JSON.stringify({\n type: \"events-applied\",\n newSyncId: chunk.newSyncId,\n eventHlcSum: chunk.eventHlcSum,\n }),\n );\n },\n });\n\n const handleMessage = (message: string): MessageResult => {\n const requestRaw = jsonSafeParse<SyncServerRequest>(message);\n\n if (!requestRaw.success) {\n return { success: false, error: requestRaw.error };\n }\n\n const requestResult = syncServerZodSchema.request.safeParse(requestRaw.data);\n\n if (!requestResult.success) {\n console.log(\"Invalid request\", requestResult.error);\n return { success: false, error: requestResult.error };\n }\n\n const request = requestResult.data;\n\n switch (request.type) {\n case \"pull-events\":\n return handlePullEvents(request);\n case \"push-events\":\n return handlePushEvents(request);\n default:\n request satisfies never;\n return { success: false, error: new Error(\"Invalid request type\") };\n }\n };\n\n const handlePullEvents = (request: ExtractSyncServerRequest<\"pull-events\">): MessageResult => {\n const batch = crdtStorage.getEventsBatch({\n limit: bufferSize,\n status: \"applied\",\n afterSyncId: request.afterSyncId,\n excludeNodeId: request.excludeNodeId ?? \"\",\n });\n\n const eventsPullMessage: SyncServerMessage = {\n type: \"events-pull-response\",\n requestId: request.requestId,\n data: {\n hasMore: batch.hasMore,\n nextSyncId: batch.nextSyncId,\n events: batch.events.map((x) => ({\n schema_version: x.schema_version,\n timestamp: x.timestamp,\n type: x.type,\n dataset: x.dataset,\n item_id: x.item_id,\n payload: x.payload,\n })),\n },\n };\n\n return {\n success: true,\n payload: JSON.stringify(eventsPullMessage),\n };\n };\n\n const handlePushEvents = (request: ExtractSyncServerRequest<\"push-events\">): MessageResult => {\n const { beforeSyncId, afterSyncId } = crdtStorage.enqueueLocalEvents(request.events, request.nodeId);\n const eventsAppliedMessage: SyncServerMessage = {\n type: \"events-push-response\",\n requestId: request.requestId,\n data: {\n ok: true,\n beforeSyncId,\n afterSyncId,\n },\n };\n\n return {\n success: true,\n payload: JSON.stringify(eventsAppliedMessage),\n };\n };\n\n return { handleMessage };\n}\n\nfunction getLatestSyncId(executor: KyselyExecutor<any>) {\n const result = executor.executeKysely((db) =>\n db.selectFrom(\"crdt_events\").select((eb) => eb.fn.max(\"sync_id\").as(\"sync_id\")),\n );\n return result.rows[0]?.sync_id ?? 0;\n}\n\nexport const durableObjectAdapter = {\n createCrdtStorage: createDurableObjectCrdtStorage,\n};\n","import { dummyKysely, type InternalSQLiteWrapper, type KyselyStatementFactory } from \"@sqlite-sync/core\";\nimport type { Compilable, Kysely } from \"kysely\";\n\ntype ExecuteParams = {\n sql: string;\n parameters: readonly unknown[];\n};\n\ntype ExecuteResult<T> = {\n rows: T[];\n};\n\ntype QueryBuilderOutput<QB> = QB extends Compilable<infer O> ? O : never;\n\ntype KyselyQueryFactory<TDatabase, TQuery extends Compilable<TResult>, TResult = QueryBuilderOutput<TQuery>> = (\n kysely: Kysely<TDatabase>,\n) => TQuery;\n\nexport type KyselyExecutor<TDatabase> = {\n execute<TResult = unknown>(query: ExecuteParams): ExecuteResult<TResult>;\n executeKysely<TQuery extends Compilable<TResult>, TResult = QueryBuilderOutput<TQuery>>(\n factory: KyselyQueryFactory<TDatabase, TQuery, TResult>,\n ): ExecuteResult<TResult>;\n transaction: (callback: (tx: Pick<KyselyExecutor<TDatabase>, \"execute\" | \"executeKysely\">) => void) => void;\n};\n\nexport function createKyselyExecutor<TDatabase>(db: DurableObjectStorage): KyselyExecutor<TDatabase> {\n const execute = <TResult = unknown>(query: ExecuteParams): ExecuteResult<TResult> => {\n const rows = db.sql.exec(query.sql, ...query.parameters).toArray();\n return { rows: rows as TResult[] };\n };\n\n const executeKysely = <TQuery extends Compilable<TResult>, TResult = QueryBuilderOutput<TQuery>>(\n factory: KyselyQueryFactory<TDatabase, TQuery, TResult>,\n ): ExecuteResult<TResult> => {\n const query = factory(dummyKysely as any).compile();\n return execute(query);\n };\n\n const transaction = (callback: (tx: Pick<KyselyExecutor<TDatabase>, \"execute\" | \"executeKysely\">) => void) => {\n db.transactionSync(() => callback(executor));\n };\n\n const executor = {\n execute,\n executeKysely,\n transaction,\n };\n\n return executor;\n}\n\nexport function createCrdtStorageDb(executor: KyselyExecutor<any>): InternalSQLiteWrapper<any> {\n const wrapper: Omit<InternalSQLiteWrapper<any>, \"executeTransaction\"> = {\n executePreparedRaw: <TParams extends unknown[], TResult>({\n sql,\n params,\n }: {\n sql: string;\n params?: TParams | undefined;\n }) =>\n executor.execute<TResult>({\n sql,\n parameters: params ?? [],\n }).rows,\n\n executePrepared: <\n TParams extends Record<string, unknown>,\n TQuery extends Compilable<TResult>,\n TResult = QueryBuilderOutput<TQuery>,\n >(\n _: string,\n params: TParams,\n factory: KyselyStatementFactory<TParams, any, TQuery, TResult>,\n ) => {\n const query = factory(dummyKysely as any, (key) => key as any).compile();\n const parameters = query.parameters.map((param) => params[param as keyof TParams]);\n const result = executor.execute<TResult>({\n sql: query.sql,\n parameters,\n });\n return result.rows;\n },\n };\n\n return {\n ...wrapper,\n executeTransaction: (callback) =>\n executor.transaction(() => {\n callback(wrapper);\n }),\n };\n}\n","import { createMigrator as createBaseMigrator, createStoredValue, type Migrations } from \"@sqlite-sync/core\";\nimport type { KyselyExecutor } from \"./kysely-executor\";\n\nexport function createMigrator(\n kv: SyncKvStorage,\n sqlExecutor: KyselyExecutor<any>,\n migrations: Migrations,\n updateLogTableName?: string,\n) {\n const schemaVersion = createStoredValue<number>({\n initialValue: kv.get(\"schema-version\") ?? -1,\n saveToStorage: (val) => kv.put(\"schema-version\", val),\n });\n\n const baseMigrator = createBaseMigrator({\n migrations,\n schemaVersion,\n updateLogTableName,\n });\n\n return {\n ...baseMigrator,\n migrateDbToLatest: () => {\n baseMigrator.migrateDbToLatest({\n startTransaction: (callback) => {\n sqlExecutor.transaction(() => {\n return callback({\n execute: (sql, parameters) =>\n sqlExecutor.execute({\n sql,\n parameters,\n }),\n });\n });\n },\n });\n },\n };\n}\n\nexport type SyncDbMigrator = ReturnType<typeof createMigrator>;\n"],"mappings":"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","names":["createStoredValue","updateLogTableName","createStoredValue"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sqlite-sync/cloudflare",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Cloudflare utilities for @sqlite-sync/core",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -30,7 +30,7 @@
30
30
  "dist"
31
31
  ],
32
32
  "dependencies": {
33
- "@sqlite-sync/core": "0.1.1"
33
+ "@sqlite-sync/core": "0.3.0"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "@cloudflare/workers-types": "^4.0.0",
@@ -45,6 +45,6 @@
45
45
  "scripts": {
46
46
  "build": "tsup",
47
47
  "dev": "tsup --watch",
48
- "typecheck": "tsc --noEmit"
48
+ "typecheck": "tsgo --noEmit"
49
49
  }
50
50
  }