@sqlite-sync/core 0.13.2 → 0.13.4

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.
@@ -643,6 +643,17 @@ function createCrdtStorage(storage) {
643
643
  meta: { loggerLevel: "system" }
644
644
  });
645
645
  if (persistedClock?.timestamp) storage.hlc.restoreHLC(deserializeHLC(persistedClock.timestamp));
646
+ const readPersistedSyncId = (executor) => {
647
+ const [row] = executor.executePreparedRaw({
648
+ key: "get-max-persisted-sync-id",
649
+ sql: `select max("sync_id") as "sync_id" from ${quotedEventsTable}`,
650
+ meta: { loggerLevel: "system" }
651
+ });
652
+ return Math.max(storage.initialLocalSyncId, row?.sync_id ?? 0);
653
+ };
654
+ const refreshLocalSyncId = () => {
655
+ localSyncId = readPersistedSyncId(db);
656
+ };
646
657
  const getInitialSequentialSyncId = () => {
647
658
  const [firstPendingEvent] = db.executePrepared("get-first-pending-event", { status: "pending" }, (db, params) => db.selectFrom(crdtEventsTable).select("sync_id").where("status", "=", params("status")).orderBy("sync_id", "asc").limit(sql.lit(1)), { loggerLevel: "system" });
648
659
  return firstPendingEvent ? firstPendingEvent.sync_id - 1 : localSyncId;
@@ -710,13 +721,19 @@ function createCrdtStorage(storage) {
710
721
  return JSON.parse(row.batch).map(rowToEvent);
711
722
  };
712
723
  const enqueueEvents = (origin, sourceNodeId, events) => {
713
- const beforeSyncId = localSyncId;
714
- if (events.length === 0) return {
715
- beforeSyncId,
716
- afterSyncId: beforeSyncId,
717
- processed: Promise.resolve()
718
- };
724
+ if (events.length === 0) {
725
+ refreshLocalSyncId();
726
+ return {
727
+ beforeSyncId: localSyncId,
728
+ afterSyncId: localSyncId,
729
+ processed: Promise.resolve()
730
+ };
731
+ }
732
+ let beforeSyncId = 0;
733
+ let syncId = 0;
719
734
  db.executeTransaction((tx) => {
735
+ beforeSyncId = readPersistedSyncId(tx);
736
+ syncId = beforeSyncId;
720
737
  const persistedEvents = events.map((event) => ({
721
738
  schema_version: event.schema_version ?? storage.migrator.currentSchemaVersion,
722
739
  timestamp: event.timestamp ?? serializeHLC(storage.hlc.getNextHLC()),
@@ -726,14 +743,15 @@ function createCrdtStorage(storage) {
726
743
  origin,
727
744
  source_node_id: sourceNodeId,
728
745
  payload: event.payload,
729
- sync_id: ++localSyncId,
746
+ sync_id: ++syncId,
730
747
  status: "pending"
731
748
  }));
732
749
  persistEvents(tx, persistedEvents);
733
750
  });
751
+ localSyncId = syncId;
734
752
  return {
735
753
  beforeSyncId,
736
- afterSyncId: localSyncId,
754
+ afterSyncId: syncId,
737
755
  processed: processEnqueuedEvents()
738
756
  };
739
757
  };
@@ -783,7 +801,9 @@ function createCrdtStorage(storage) {
783
801
  validatedEvents.push(result.event);
784
802
  }
785
803
  if (errors.length > 0) throw new CrdtEventValidationError(errors);
804
+ let syncId = 0;
786
805
  db.executeTransaction((tx) => {
806
+ syncId = readPersistedSyncId(tx);
787
807
  const persistedEvents = validatedEvents.map((event) => ({
788
808
  schema_version: storage.migrator.currentSchemaVersion,
789
809
  timestamp: serializeHLC(storage.hlc.getNextHLC()),
@@ -793,7 +813,7 @@ function createCrdtStorage(storage) {
793
813
  origin: "own-applied",
794
814
  source_node_id: storage.nodeId,
795
815
  payload: JSON.stringify(event.payload),
796
- sync_id: ++localSyncId,
816
+ sync_id: ++syncId,
797
817
  status: "pending"
798
818
  }));
799
819
  persistEvents(tx, persistedEvents);
@@ -801,11 +821,13 @@ function createCrdtStorage(storage) {
801
821
  for (const persistedEvent of persistedEvents) applyCrdtEvent(persistedEvent);
802
822
  });
803
823
  });
824
+ localSyncId = syncId;
804
825
  processEnqueuedEvents();
805
826
  };
806
827
  const applyOwnSnapshot = (snapshot) => {
807
- const syncId = localSyncId + 1;
828
+ let syncId = 0;
808
829
  db.executeTransaction((tx) => {
830
+ syncId = readPersistedSyncId(tx) + 1;
809
831
  const [currentRow] = tx.executePreparedRaw({
810
832
  key: `get-crdt-snapshot-row-${snapshot.dataset}`,
811
833
  sql: `select * from ${quoteId(snapshot.dataset)} where "id" = ? limit 1`,
@@ -869,7 +891,7 @@ where "dataset" = ? and "item_id" = ? and "payload" <> ${noOpPayloadSqlLiteral}`
869
891
  origin: "own-applied",
870
892
  source_node_id: storage.nodeId,
871
893
  payload: event.payload,
872
- sync_id: ++localSyncId,
894
+ sync_id: readPersistedSyncId(tx) + 1,
873
895
  status: "pending"
874
896
  };
875
897
  persistEvents(tx, [persistedEvent]);
@@ -1055,6 +1077,7 @@ where "dataset" = ? and "item_id" = ? and "payload" <> ${noOpPayloadSqlLiteral}`
1055
1077
  let hasMore = true;
1056
1078
  while (hasMore) {
1057
1079
  await Promise.resolve();
1080
+ refreshLocalSyncId();
1058
1081
  const batchSize = 100;
1059
1082
  const events = readPendingEvents(101);
1060
1083
  hasMore = events.length > batchSize;
@@ -1126,4 +1149,4 @@ const createCrdtSyncProducer = ({ storage, broadcastEvents }) => {
1126
1149
  //#endregion
1127
1150
  export { formatSchemaVerificationIssues as a, createMigrator as c, createSQLiteCrdtApplyFunction as i, createExportData as l, createCrdtStorage as n, verifySyncSchemaWithDriver as o, createCrdtApplyFunction as r, createMigrations as s, createCrdtSyncProducer as t, createImportData as u };
1128
1151
 
1129
- //# sourceMappingURL=crdt-sync-producer-DVEWad4t.js.map
1152
+ //# sourceMappingURL=crdt-sync-producer-t2jHxO38.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crdt-sync-producer-t2jHxO38.js","names":["_exhaustive"],"sources":["../src/export-import.ts","../src/migrations/migrator.ts","../src/schema/verify-sync-schema.ts","../src/sqlite-crdt/apply-crdt-event.ts","../src/sqlite-crdt/crdt-storage.ts","../src/sqlite-crdt/crdt-sync-producer.ts"],"sourcesContent":["import type { MigratableEvent, SyncDbMigrator } from \"./migrations/migrator\";\nimport type { CrdtTableConfig } from \"./sqlite-crdt/crdt-schema\";\nimport type { OwnCrdtEvent } from \"./sqlite-crdt/crdt-storage\";\nimport type { ExecuteResult } from \"./sqlite-db-wrapper\";\nimport { quoteId } from \"./utils\";\n\n/**\n * A portable, schema-version-aware dump of every active entity in a synced DB.\n * Unlike a raw SQLite snapshot, it carries no event history — just the current\n * `tombstone = 0` rows, ready to be replayed as fresh create events on import.\n */\nexport type SyncedDbExport = {\n schemaVersion: number;\n exportedAt: string;\n /** base table name -> active rows (each includes `id`, excludes `tombstone`). */\n tables: Record<string, Array<Record<string, unknown>>>;\n};\n\nexport type ImportDataOptions = { validate?: boolean };\nexport type ImportDataResult = { imported: number };\n\ntype ExportImportReactiveDb = {\n db: { execute<T>(sql: string, meta: { loggerLevel: \"system\" }): ExecuteResult<T> };\n};\n\ntype ApplyImportEvents = (events: OwnCrdtEvent[]) => void | Promise<void>;\n\ntype ImportMigrator = Pick<SyncDbMigrator, \"currentSchemaVersion\" | \"migrateEvents\">;\n\ntype CreateExportDataOptions = {\n reactiveDb: ExportImportReactiveDb;\n tablesConfig: CrdtTableConfig[];\n schemaVersion: number;\n};\n\ntype CreateImportDataOptions = {\n migrator: ImportMigrator;\n tablesConfig?: CrdtTableConfig[];\n applyEvents: ApplyImportEvents;\n};\n\nfunction createTableNameNormalizer(tablesConfig: CrdtTableConfig[] | undefined) {\n const tablesByAlias = new Map<string, CrdtTableConfig>();\n for (const table of tablesConfig ?? []) {\n const { baseTableName, crdtTableName } = table;\n tablesByAlias.set(baseTableName, table);\n tablesByAlias.set(crdtTableName, table);\n }\n return (tableName: string) => {\n const table = tablesByAlias.get(tableName);\n if (table?.exportImport === \"ignore\") {\n return null;\n }\n return table?.baseTableName ?? tableName;\n };\n}\n\nexport function createImportData({ migrator, tablesConfig, applyEvents }: CreateImportDataOptions) {\n const normalizeTableName = createTableNameNormalizer(tablesConfig);\n\n /**\n * Replay an export as a sequence of `item-created` CRDT events, seeding the\n * rows through the provided CRDT event applicator.\n *\n * Schema migration: a dump exported at an older schema version is forward-\n * migrated up to the DB's current version (running the same event transformers\n * remote events go through) before being authored — so an old backup can be\n * restored into an upgraded app. Rows in tables removed by a later migration\n * are dropped. The reverse (a dump from a *newer* version than this DB) cannot\n * be down-migrated and is rejected.\n *\n * Overwrite-by-default: because the generated events carry fresh (newest) HLC\n * timestamps, importing a row whose `id` already exists overwrites every field\n * under last-write-wins, while new ids are inserted. Existing rows absent from\n * the dump are never touched. This is a restore/seed, not a CRDT merge —\n * original timestamps are not preserved.\n *\n * @param opts.validate When `false`, skip the too-new guard and author the rows\n * as-is at the current version (footgun — payloads are not down-migrated).\n * Forward migration and per-row payload validation always run regardless.\n */\n return (data: SyncedDbExport, opts?: ImportDataOptions): ImportDataResult | Promise<ImportDataResult> => {\n const validate = opts?.validate ?? true;\n const currentVersion = migrator.currentSchemaVersion;\n\n if (validate && data.schemaVersion > currentVersion) {\n throw new Error(\n `Cannot import data from schema version ${data.schemaVersion} into a database at older schema version ${currentVersion}. Exports migrate forward to newer schema versions, not backward.`,\n );\n }\n\n const sourceEvents: MigratableEvent[] = [];\n for (const [tableName, rows] of Object.entries(data.tables)) {\n const normalizedTableName = normalizeTableName(tableName);\n if (normalizedTableName === null) {\n continue;\n }\n for (const row of rows) {\n sourceEvents.push({\n schema_version: data.schemaVersion,\n type: \"item-created\",\n dataset: normalizedTableName,\n item_id: row.id as string,\n payload: JSON.stringify(row),\n });\n }\n }\n\n // Forward-migrate the historical export up to the current schema version\n // before authoring it: own events are always written at the current version.\n const events: OwnCrdtEvent[] = migrator.migrateEvents(sourceEvents, currentVersion).map((event) => ({\n type: event.type,\n dataset: event.dataset,\n item_id: event.item_id,\n payload: event.payload,\n }));\n\n const applied = applyEvents(events);\n if (applied instanceof Promise) {\n return applied.then(() => ({ imported: events.length }));\n }\n\n return { imported: events.length };\n };\n}\n\nexport function createExportData({ reactiveDb, tablesConfig, schemaVersion }: CreateExportDataOptions) {\n const tableNames = tablesConfig.flatMap((config) => [config.crdtTableName, config.baseTableName]);\n\n const resolveTables = (requested: string[] | undefined): CrdtTableConfig[] => {\n if (!requested) {\n return tablesConfig;\n }\n\n const seenBaseTableNames = new Set<string>();\n const resolved: CrdtTableConfig[] = [];\n for (const name of requested) {\n const config = tablesConfig.find(\n (tableConfig) => tableConfig.crdtTableName === name || tableConfig.baseTableName === name,\n );\n if (!config) {\n throw new Error(`Unknown table \"${name}\". Known synced tables: ${tableNames.join(\", \")}`);\n }\n if (!seenBaseTableNames.has(config.baseTableName)) {\n seenBaseTableNames.add(config.baseTableName);\n resolved.push(config);\n }\n }\n return resolved;\n };\n\n /**\n * Dump every active entity (the `tombstone = 0` rows) from the synced tables.\n *\n * Reads this tab's reactive (in-memory) DB — the state the user currently sees,\n * which may differ slightly from the worker's authoritative DB while local\n * writes are in flight.\n */\n return (opts?: { tables?: string[] }): SyncedDbExport => {\n const tables: Record<string, Array<Record<string, unknown>>> = {};\n\n for (const { baseTableName, crdtTableName, exportImport } of resolveTables(opts?.tables)) {\n if (exportImport === \"ignore\") {\n continue;\n }\n const { rows } = reactiveDb.db.execute<Record<string, unknown>>(`select * from ${quoteId(crdtTableName)}`, {\n loggerLevel: \"system\",\n });\n tables[baseTableName] = rows.map(({ tombstone: _tombstone, ...rest }) => rest);\n }\n\n return {\n schemaVersion,\n exportedAt: new Date().toISOString(),\n tables,\n };\n };\n}\n","import type {\n ColumnDataType,\n ColumnDefinitionBuilderCallback,\n Compilable,\n CreateIndexBuilder,\n CreateTableBuilder,\n Expression,\n Kysely,\n} from \"kysely\";\nimport { dummyKysely } from \"../dummy-kysely\";\nimport { type CrdtEventType, isNoOpCrdtEventPayload, type NewCrdtEvent } from \"../sqlite-crdt/crdt-table-schema\";\nimport type { StoredValue } from \"../sqlite-crdt/stored-value\";\n\nexport type MigratableEvent = {\n schema_version: number;\n type: CrdtEventType;\n dataset: string;\n item_id: string;\n payload: string;\n};\n\ntype CrdtEventTransformer = (event: NewCrdtEvent) => NewCrdtEvent | null;\n\ntype MigrationStepSql =\n | {\n sql: string;\n parameters?: readonly unknown[];\n }\n | Compilable\n | ((db: Kysely<unknown>) => Compilable);\n\ntype UpdateLogMutation =\n | { type: \"rename-table\"; oldTable: string; newTable: string }\n | { type: \"drop-table\"; table: string }\n | { type: \"rename-column\"; table: string; oldColumn: string; newColumn: string }\n | { type: \"add-column\"; table: string; column: string }\n | { type: \"drop-column\"; table: string; column: string };\n\ntype MigrationStep = {\n sql: MigrationStepSql | MigrationStepSql[];\n eventTransformer?: MigrationEventTransformers;\n updateLogMutations?: UpdateLogMutation[];\n};\n\ntype RawMigrationStep = {\n sql: MigrationSql[];\n eventTransformer?: CompiledMigrationEventTransformer;\n updateLogMutations?: UpdateLogMutation[];\n};\n\ntype MigrationSql = { sql: string; parameters: readonly unknown[] };\n\ntype DataTypeExpression = ColumnDataType | Expression<any>;\n\nconst protectedColumns = [\"id\", \"tombstone\"];\n\nfunction assertColumnNotProtected(column: string, operation: string) {\n if (protectedColumns.includes(column)) {\n throw new Error(`Cannot ${operation} protected column \"${column}\"`);\n }\n}\n\nconst migrationSteps = {\n createTable: (table: string, build: (table: CreateTableBuilder<string, never>) => Compilable): MigrationStep => ({\n sql: (db) => build(db.schema.createTable(table)),\n }),\n\n dropTable: (table: string): MigrationStep => ({\n sql: (db) => db.schema.dropTable(table),\n eventTransformer: {\n [table]: () => null,\n },\n updateLogMutations: [{ type: \"drop-table\", table }],\n }),\n\n createIndex: (indexName: string, build: (index: CreateIndexBuilder) => Compilable): MigrationStep => ({\n sql: (db) => build(db.schema.createIndex(indexName)),\n }),\n\n dropIndex: (indexName: string): MigrationStep => ({\n sql: (db) => db.schema.dropIndex(indexName),\n }),\n\n renameTable: ({ oldTable, newTable }: { oldTable: string; newTable: string }): MigrationStep => ({\n sql: (db) => db.schema.alterTable(oldTable).renameTo(newTable),\n eventTransformer: {\n [oldTable]: (event) => {\n event.dataset = newTable;\n return event;\n },\n },\n updateLogMutations: [{ type: \"rename-table\", oldTable, newTable }],\n }),\n\n renameColumn: ({\n table,\n oldColumn,\n newColumn,\n }: {\n table: string;\n oldColumn: string;\n newColumn: string;\n }): MigrationStep => {\n assertColumnNotProtected(oldColumn, \"rename\");\n assertColumnNotProtected(newColumn, \"rename to\");\n return {\n sql: (db) => db.schema.alterTable(table).renameColumn(oldColumn, newColumn),\n eventTransformer: {\n [table]: (event) => {\n if ((event.type !== \"item-updated\" && event.type !== \"item-created\") || !(oldColumn in event.payload)) {\n return event;\n }\n\n const oldVal = event.payload[oldColumn];\n delete event.payload[oldColumn];\n event.payload[newColumn] = oldVal;\n\n return event;\n },\n },\n updateLogMutations: [{ type: \"rename-column\", table, oldColumn, newColumn }],\n };\n },\n\n addColumn: ({\n table,\n column,\n type,\n defaultValue,\n build = (e) => e,\n }: {\n table: string;\n column: string;\n type: DataTypeExpression;\n defaultValue: number | boolean | string | null;\n build?: ColumnDefinitionBuilderCallback;\n }): MigrationStep => ({\n // Older creates are not given the default: the column default fills it on insert, and a\n // replayed create must not write a cell that replicas which applied it earlier never had.\n sql: (db) => db.schema.alterTable(table).addColumn(column, type, (x) => build(x).defaultTo(defaultValue)),\n updateLogMutations: [{ type: \"add-column\", table, column }],\n }),\n\n dropColumn: ({ table, column }: { table: string; column: string }): MigrationStep => {\n assertColumnNotProtected(column, \"drop\");\n return {\n sql: (db) => db.schema.alterTable(table).dropColumn(column),\n eventTransformer: {\n [table]: (event) => {\n if (!(column in event.payload)) {\n return event;\n }\n\n delete event.payload[column];\n\n if (event.type === \"item-updated\" && Object.keys(event.payload).length === 0) {\n return null;\n }\n\n return event;\n },\n },\n updateLogMutations: [{ type: \"drop-column\", table, column }],\n };\n },\n};\n\ntype MigrationEventTransformers = Record<string, CrdtEventTransformer>;\ntype CompiledMigrationEventTransformer = (event: NewCrdtEvent) => NewCrdtEvent | null;\n\nfunction buildMigrationSql(steps: MigrationStep[]): MigrationSql[] {\n return steps\n .flatMap((step) => (Array.isArray(step.sql) ? step.sql : [step.sql]))\n .map((sql): MigrationSql => {\n if (typeof sql === \"string\") {\n return { sql, parameters: [] };\n }\n\n if (typeof sql === \"function\") {\n const query = sql(dummyKysely).compile();\n return { sql: query.sql, parameters: query.parameters };\n }\n\n if (\"compile\" in sql) {\n const query = sql.compile();\n return { sql: query.sql, parameters: query.parameters };\n }\n\n return {\n sql: sql.sql,\n parameters: sql.parameters ?? [],\n };\n });\n}\n\nfunction buildMigrationEventTransformer(steps: MigrationStep[]): CompiledMigrationEventTransformer | undefined {\n const transformers: Array<[string, CrdtEventTransformer]> = [];\n\n for (const step of steps) {\n if (step.eventTransformer) {\n transformers.push(...Object.entries(step.eventTransformer));\n }\n }\n\n if (transformers.length === 0) {\n return undefined;\n }\n\n return (event: NewCrdtEvent) => {\n let transformedEvent: NewCrdtEvent | null = event;\n\n for (const [table, transformer] of transformers) {\n if (transformedEvent === null) {\n return null;\n }\n if (transformedEvent.dataset !== table) {\n continue;\n }\n transformedEvent = transformer(transformedEvent);\n if (transformedEvent === null) {\n return null;\n }\n }\n\n return transformedEvent;\n };\n}\n\nexport function createMigrations(buildMigrations: (builder: typeof migrationSteps) => Record<number, MigrationStep[]>) {\n const migrations: Record<number, RawMigrationStep> = Object.fromEntries(\n Object.entries(buildMigrations(migrationSteps)).map(([version, steps]) => {\n const versionNumber = Number(version);\n\n if (Number.isNaN(versionNumber)) {\n throw new Error(`Invalid migration version: ${version}`);\n }\n\n if (versionNumber < 0) {\n throw new Error(`Migration version cannot be negative: ${version}`);\n }\n\n const updateLogMutations = steps.flatMap((step) => step.updateLogMutations ?? []);\n\n return [\n version,\n {\n sql: buildMigrationSql(steps),\n eventTransformer: buildMigrationEventTransformer(steps),\n ...(updateLogMutations.length > 0 && { updateLogMutations }),\n },\n ];\n }),\n );\n\n return migrations;\n}\n\nexport type Migrations = ReturnType<typeof createMigrations>;\n\nexport type MigrationsDb = {\n startTransaction: (callback: (tx: MigrationsTransaction) => void) => void;\n};\n\ntype MigrationsTransaction = {\n execute: (sql: string, parameters: readonly unknown[], meta?: { loggerLevel?: \"system\" }) => void;\n};\n\nexport function createMigrator({\n migrations,\n schemaVersion,\n updateLogTableName,\n}: {\n migrations: Migrations;\n schemaVersion: StoredValue<number>;\n updateLogTableName?: string;\n}) {\n const latestSchemaVersion = Math.max(...Object.keys(migrations).map(Number));\n\n // Pre-sort migrations once for efficient range lookups\n const sortedMigrations = Object.entries(migrations)\n .map(([v, m]) => [Number(v), m] as const)\n .sort((a, b) => a[0] - b[0]);\n\n const applyMigration = (db: MigrationsDb, version: number, migration: RawMigrationStep) => {\n if (version <= schemaVersion.current) {\n throw new Error(`Cannot apply migration ${version} to schema version ${schemaVersion.current}`);\n }\n\n db.startTransaction((tx) => {\n for (const statement of migration.sql) {\n tx.execute(statement.sql, statement.parameters);\n }\n if (updateLogTableName && migration.updateLogMutations) {\n for (const mutation of migration.updateLogMutations) {\n switch (mutation.type) {\n case \"rename-table\": {\n tx.execute(`DELETE FROM ${updateLogTableName} WHERE \"dataset\" = ?`, [mutation.newTable], {\n loggerLevel: \"system\",\n });\n tx.execute(\n `UPDATE ${updateLogTableName} SET \"dataset\" = ? WHERE \"dataset\" = ?`,\n [mutation.newTable, mutation.oldTable],\n { loggerLevel: \"system\" },\n );\n break;\n }\n case \"drop-table\": {\n tx.execute(`DELETE FROM ${updateLogTableName} WHERE \"dataset\" = ?`, [mutation.table], {\n loggerLevel: \"system\",\n });\n break;\n }\n case \"rename-column\": {\n tx.execute(\n `UPDATE ${updateLogTableName}\nSET \"payload\" = COALESCE(\n (\n SELECT json_group_object(CASE WHEN \"key\" = ? THEN ? ELSE \"key\" END, \"value\")\n FROM json_each(\"payload\")\n WHERE \"key\" != ?\n ),\n '{}'\n)\nWHERE \"dataset\" = ?\n AND EXISTS (SELECT 1 FROM json_each(\"payload\") WHERE \"key\" = ? OR \"key\" = ?)`,\n [\n mutation.oldColumn,\n mutation.newColumn,\n mutation.newColumn,\n mutation.table,\n mutation.oldColumn,\n mutation.newColumn,\n ],\n { loggerLevel: \"system\" },\n );\n break;\n }\n case \"add-column\":\n case \"drop-column\": {\n tx.execute(\n `UPDATE ${updateLogTableName}\nSET \"payload\" = COALESCE(\n (SELECT json_group_object(\"key\", \"value\") FROM json_each(\"payload\") WHERE \"key\" != ?),\n '{}'\n)\nWHERE \"dataset\" = ?\n AND EXISTS (SELECT 1 FROM json_each(\"payload\") WHERE \"key\" = ?)`,\n [mutation.column, mutation.table, mutation.column],\n { loggerLevel: \"system\" },\n );\n break;\n }\n default: {\n const _exhaustive: never = mutation;\n throw new Error(`Unsupported update-log mutation: ${JSON.stringify(_exhaustive)}`);\n }\n }\n }\n }\n schemaVersion.current = version;\n });\n };\n\n const migrateEvent = <Event extends MigratableEvent>(event: Event, targetVersion?: number): Event | null => {\n targetVersion ??= latestSchemaVersion;\n if (targetVersion > schemaVersion.current) {\n throw new Error(\n `Target schema version ${targetVersion} is greater than current schema version ${schemaVersion.current}`,\n );\n }\n\n if (isNoOpCrdtEventPayload(event.payload)) {\n if (event.schema_version < targetVersion) {\n event.schema_version = targetVersion;\n }\n return event;\n }\n\n if (event.schema_version >= targetVersion) {\n return event;\n }\n\n const fromVersion = event.schema_version;\n\n let crdtEvent: NewCrdtEvent | null = {\n dataset: event.dataset,\n item_id: event.item_id,\n type: event.type,\n payload: JSON.parse(event.payload),\n };\n\n for (let i = 0; i < sortedMigrations.length; i++) {\n const [version, migration] = sortedMigrations[i];\n if (version <= fromVersion) continue;\n if (version > targetVersion) break;\n\n const transformer = migration.eventTransformer;\n if (transformer) {\n crdtEvent = transformer(crdtEvent);\n if (crdtEvent === null) return null;\n }\n }\n\n if (crdtEvent === null) {\n return null;\n }\n\n event.schema_version = targetVersion;\n event.dataset = crdtEvent.dataset;\n event.item_id = crdtEvent.item_id;\n event.type = crdtEvent.type;\n event.payload = JSON.stringify(crdtEvent.payload);\n\n return event;\n };\n\n const migrateEvents = <Event extends MigratableEvent>(events: Event[], targetVersion?: number): Event[] => {\n return events\n .map((event) => migrateEvent(event, targetVersion ?? latestSchemaVersion))\n .filter((event): event is NonNullable<typeof event> => event !== null);\n };\n\n return {\n latestSchemaVersion,\n get currentSchemaVersion() {\n return schemaVersion.current;\n },\n migrateDbToLatest: (db: MigrationsDb) => {\n const currentSchemaVersion = schemaVersion.current;\n\n if (currentSchemaVersion >= latestSchemaVersion) {\n return;\n }\n\n for (let i = 0; i < sortedMigrations.length; i++) {\n const [version, migration] = sortedMigrations[i];\n if (version <= currentSchemaVersion) continue;\n applyMigration(db, version, migration);\n }\n },\n migrateEvent,\n migrateEvents,\n };\n}\n\nexport type SyncDbMigrator = ReturnType<typeof createMigrator>;\n","import { introspectDb, type TableMetadata } from \"../introspection\";\nimport { createMigrator } from \"../migrations/migrator\";\nimport type { SyncDbSchema } from \"../sqlite-crdt/crdt-schema\";\nimport { createStoredValue } from \"../sqlite-crdt/stored-value\";\nimport { SQLiteDbWrapper } from \"../sqlite-db-wrapper\";\nimport type { SqliteDriver } from \"../sqlite-driver\";\nimport type { ColumnKind, ColumnMeta } from \"./table-builder\";\n\nexport type SchemaVerificationIssue = {\n table: string;\n column?: string;\n message: string;\n};\n\nconst acceptedDataTypes: Record<ColumnKind, string[]> = {\n text: [\"TEXT\"],\n integer: [\"INTEGER\", \"INT\"],\n real: [\"REAL\", \"DOUBLE\", \"FLOAT\"],\n boolean: [\"BOOLEAN\", \"INTEGER\", \"INT\"],\n enum: [\"TEXT\"],\n};\n\n/**\n * Verify that replaying the full migration history on a fresh database produces\n * exactly the declared table schema. Applies all migrations to `driver`, which\n * must be an empty throwaway database (it is closed afterwards), introspects the\n * result, and diffs it against the `t.table()` declarations.\n *\n * Returns an empty array when migrations and schema agree. Intended for dev-time\n * checks (`startDbWorker({ verifySchema: true })`) and tests:\n * `expect(await verifySyncSchema(syncDbSchema)).toEqual([])`.\n */\nexport function verifySyncSchemaWithDriver(schema: SyncDbSchema, driver: SqliteDriver): SchemaVerificationIssue[] {\n const db = new SQLiteDbWrapper({\n driver,\n logger: () => {},\n loggerPrefix: \"schema-verify\",\n });\n\n try {\n const migrator = createMigrator({\n migrations: schema.migrations,\n schemaVersion: createStoredValue({ initialValue: -1 }),\n });\n\n try {\n migrator.migrateDbToLatest({\n startTransaction: (callback) => {\n db.executeTransaction((tx) =>\n callback({ execute: (sql, parameters, meta) => tx.execute({ sql, parameters }, meta) }),\n );\n },\n });\n } catch (error) {\n return [\n {\n table: \"(migrations)\",\n message: `migration replay failed on an empty database: ${error instanceof Error ? error.message : String(error)}`,\n },\n ];\n }\n\n const introspection = introspectDb(db);\n\n const issues: SchemaVerificationIssue[] = [];\n for (const { crdtTableName, baseTableName } of schema.tablesConfig) {\n const declared = schema.tables[crdtTableName];\n if (!declared) continue;\n verifyTable(db, baseTableName, declared.columns, introspection[baseTableName], issues);\n }\n return issues;\n } finally {\n db.close();\n }\n}\n\nexport function formatSchemaVerificationIssues(issues: SchemaVerificationIssue[]): string {\n const lines = issues.map(\n (issue) => ` - table \"${issue.table}\"${issue.column ? ` column \"${issue.column}\"` : \"\"}: ${issue.message}`,\n );\n return `sync schema verification failed (${issues.length} issue${issues.length === 1 ? \"\" : \"s\"}):\\n${lines.join(\"\\n\")}`;\n}\n\nfunction verifyTable(\n db: SQLiteDbWrapper,\n table: string,\n declaredColumns: Record<string, ColumnMeta>,\n actual: TableMetadata | undefined,\n issues: SchemaVerificationIssue[],\n) {\n if (!actual) {\n issues.push({\n table,\n message: \"declared in the schema but missing after migrations — add a createTable step in a new version\",\n });\n return;\n }\n if (actual.isView) {\n issues.push({ table, message: \"expected a base table, but migrations created a view with this name\" });\n return;\n }\n\n const actualColumns = new Map(actual.columns.map((column) => [column.name, column]));\n\n for (const [name, meta] of Object.entries(declaredColumns)) {\n const column = actualColumns.get(name);\n if (!column) {\n issues.push({\n table,\n column: name,\n message: \"declared in the schema but missing after migrations — add an addColumn step in a new version\",\n });\n continue;\n }\n\n const accepted = acceptedDataTypes[meta.kind];\n if (!accepted.includes(column.dataType.toUpperCase())) {\n issues.push({\n table,\n column: name,\n message: `type mismatch — schema declares ${meta.kind} (${accepted.join(\"/\")}), migrated column is ${column.dataType.toUpperCase()}`,\n });\n }\n\n if (column.isNullable !== meta.nullable) {\n issues.push({\n table,\n column: name,\n message: meta.nullable\n ? \"schema declares the column nullable, but the migrated column is NOT NULL\"\n : \"schema declares the column NOT NULL, but the migrated column is nullable\",\n });\n }\n\n if (name === \"id\" && !column.isPrimaryKey) {\n issues.push({ table, column: name, message: \"the id column must be the PRIMARY KEY\" });\n }\n\n verifyDefault(db, table, name, meta, column.defaultValueSql, issues);\n }\n\n for (const column of actual.columns) {\n if (!(column.name in declaredColumns)) {\n issues.push({\n table,\n column: column.name,\n message:\n \"created by migrations but not declared in the schema — sync event payloads include every column, so declare it (or drop it in a new version)\",\n });\n }\n }\n}\n\nfunction verifyDefault(\n db: SQLiteDbWrapper,\n table: string,\n column: string,\n meta: ColumnMeta,\n defaultValueSql: string | null,\n issues: SchemaVerificationIssue[],\n) {\n // A declared `null` default and an absent DEFAULT clause are equivalent in SQLite\n // (a column with no DEFAULT defaults to NULL), so don't flag that pairing.\n if (meta.hasDefault && meta.defaultValue !== null && defaultValueSql === null) {\n issues.push({\n table,\n column,\n message: `schema declares default ${formatExpected(meta)}, but the migrated column has no default`,\n });\n return;\n }\n if (!meta.hasDefault && defaultValueSql !== null) {\n issues.push({\n table,\n column,\n message: `migrated column has default ${defaultValueSql}, but the schema declares none`,\n });\n return;\n }\n if (!meta.hasDefault || defaultValueSql === null) {\n return;\n }\n\n // Declared defaults are always constants (ColumnBuilder.default takes a JS value),\n // so a non-constant migrated default (e.g. strftime(...)) is always a real mismatch.\n let actual: unknown;\n try {\n actual = db.execute<{ value: unknown }>({\n sql: `SELECT (${defaultValueSql}) AS value`,\n parameters: [],\n }).rows[0]?.value;\n } catch {\n actual = undefined;\n }\n\n if (actual !== expectedDefaultValue(meta)) {\n issues.push({\n table,\n column,\n message: `default mismatch — schema declares ${formatExpected(meta)}, migrated column default is ${defaultValueSql}`,\n });\n }\n}\n\n/** The declared default normalized to how SQLite stores it (booleans as 0/1). */\nfunction expectedDefaultValue(meta: ColumnMeta): string | number | null {\n if (meta.defaultValue === null) return null;\n switch (meta.kind) {\n case \"boolean\":\n return meta.defaultValue ? 1 : 0;\n case \"integer\":\n case \"real\":\n return Number(meta.defaultValue);\n case \"text\":\n case \"enum\":\n return String(meta.defaultValue);\n }\n}\n\nfunction formatExpected(meta: ColumnMeta): string {\n const expected = expectedDefaultValue(meta);\n return typeof expected === \"string\" ? `'${expected}'` : String(expected);\n}\n","import type { Kysely } from \"kysely\";\nimport type { SystemDbConfig } from \"../migrations/system-schema\";\nimport type { InternalSQLiteWrapper } from \"../sqlite-db-wrapper\";\nimport type { SqliteDriverValue } from \"../sqlite-driver\";\nimport { quoteId } from \"../utils\";\nimport {\n type CrdtEventType,\n type CrdtUpdateLogItem,\n type CrdtUpdateLogPayload,\n isNoOpCrdtEventPayload,\n} from \"./crdt-table-schema\";\nimport type { StateHashAccumulator } from \"./state-hash\";\n\nexport type PendingCrdtEvent = {\n type: CrdtEventType;\n dataset: string;\n item_id: string;\n timestamp: string;\n payload: string;\n};\n\nexport const createSQLiteCrdtApplyFunction = ({\n db,\n dbConfig,\n getStateHash,\n}: {\n db: InternalSQLiteWrapper<any>;\n dbConfig: SystemDbConfig;\n getStateHash?: () => StateHashAccumulator | null;\n}) => {\n const applyCrdtEvent = createCrdtApplyFunction({\n getStateHash,\n getCrdtUpdateLog(opts) {\n const [metaRow] = db.executePrepared(\n \"get-item-crdt-meta\",\n {\n item_id: opts.itemId,\n dataset: opts.dataset,\n },\n (db, params) => {\n return (db as unknown as Kysely<{ table: CrdtUpdateLogItem }>)\n .selectFrom(dbConfig.updateLogTable.fullIdentifier as \"table\")\n .select(\"payload\")\n .where(\"item_id\", \"=\", params(\"item_id\"))\n .where(\"dataset\", \"=\", params(\"dataset\"));\n },\n { loggerLevel: \"system\" },\n );\n const meta = metaRow ? (JSON.parse(metaRow.payload) as CrdtUpdateLogPayload) : null;\n return meta;\n },\n insertCrdtUpdateLog(opts) {\n db.executePrepared(\n \"insert-crdt-update-log\",\n {\n item_id: opts.itemId,\n dataset: opts.dataset,\n payload: opts.payload,\n },\n (db, params) =>\n (db as unknown as Kysely<{ table: CrdtUpdateLogItem }>)\n .insertInto(dbConfig.updateLogTable.fullIdentifier as \"table\")\n .values({\n item_id: params(\"item_id\"),\n dataset: params(\"dataset\"),\n payload: params(\"payload\"),\n }),\n { loggerLevel: \"system\" },\n );\n },\n updateCrdtUpdateLog(opts) {\n db.executePrepared(\n \"update-crdt-update-log\",\n {\n item_id: opts.itemId,\n dataset: opts.dataset,\n payload: opts.payload,\n },\n (db, params) =>\n (db as unknown as Kysely<{ table: CrdtUpdateLogItem }>)\n .updateTable(dbConfig.updateLogTable.fullIdentifier as \"table\")\n .set({\n payload: params(\"payload\"),\n })\n .where(\"item_id\", \"=\", params(\"item_id\"))\n .where(\"dataset\", \"=\", params(\"dataset\")),\n { loggerLevel: \"system\" },\n );\n },\n insertItem(opts) {\n // Key by the sorted column set, not just the dataset: executePrepared caches\n // the compiled INSERT forever, freezing its column list. A later create event\n // omitting a column would otherwise bind undefined (-> NULL) against the stale\n // statement, bypassing the table DEFAULT. Sorting makes the key canonical so\n // events with the same columns in any order share one statement.\n const keys = Object.keys(opts.payload).sort();\n db.executePrepared(\n `crdt-insert-item-${opts.dataset}-${keys.join(\"-\")}`,\n opts.payload,\n (db, params) => db.insertInto(opts.dataset).values(Object.fromEntries(keys.map((key) => [key, params(key)]))),\n { loggerLevel: \"system\" },\n );\n },\n updateItem(opts) {\n const keys = Array.from(Object.keys(opts.payload));\n keys.sort();\n db.executePreparedRaw({\n key: `update-item-${opts.dataset}-${keys.join(\"-\")}`,\n sql: `update ${quoteId(opts.dataset)} set ${keys.map((key) => `${quoteId(key)} = ?`).join(\",\")} where id = ?`,\n params: [...keys.map((key) => opts.payload[key]), opts.itemId] as SqliteDriverValue[],\n meta: { loggerLevel: \"system\" },\n });\n },\n });\n\n return applyCrdtEvent;\n};\n\ntype CreateCrdtApplyOpts = {\n getStateHash?: () => StateHashAccumulator | null;\n getCrdtUpdateLog: (opts: { itemId: string; dataset: string }) => CrdtUpdateLogPayload | null;\n insertItem: (opts: { dataset: string; payload: Record<string, unknown> }) => void;\n insertCrdtUpdateLog: (opts: { dataset: string; itemId: string; payload: string }) => void;\n updateItem: (opts: { dataset: string; itemId: string; payload: Record<string, unknown> }) => void;\n updateCrdtUpdateLog: (opts: { dataset: string; itemId: string; payload: string }) => void;\n};\n\nexport function createCrdtApplyFunction({\n getStateHash,\n getCrdtUpdateLog,\n insertItem,\n insertCrdtUpdateLog,\n updateItem,\n updateCrdtUpdateLog,\n}: CreateCrdtApplyOpts) {\n type ItemCreatedOpts = {\n event: PendingCrdtEvent;\n };\n const applyItemCreated = ({ event }: ItemCreatedOpts) => {\n const eventPayload = JSON.parse(event.payload);\n\n eventPayload.tombstone = 0;\n insertItem({ dataset: event.dataset, payload: eventPayload });\n\n const newUpdateLog = {} as Record<string, string>;\n for (const key of Object.keys(eventPayload)) {\n newUpdateLog[key] = event.timestamp;\n }\n\n insertCrdtUpdateLog({\n dataset: event.dataset,\n itemId: event.item_id,\n payload: JSON.stringify(newUpdateLog),\n });\n getStateHash?.()?.addItem(event.dataset, event.item_id, newUpdateLog);\n };\n\n type ItemUpdatedOpts = {\n event: PendingCrdtEvent;\n meta: CrdtUpdateLogPayload;\n };\n const applyItemUpdated = ({ event, meta }: ItemUpdatedOpts) => {\n if (!meta) {\n throw new Error(`Item ${event.item_id} in dataset ${event.dataset} not found`);\n }\n // A delete carries no field data on the wire — the tombstone is a local\n // materialization of the soft-delete, stamped here with the event's HLC so\n // it competes with concurrent field edits under the same last-write-wins rule.\n const eventPayload = event.type === \"item-deleted\" ? { tombstone: 1 } : JSON.parse(event.payload);\n if (event.type === \"item-created\") {\n eventPayload.tombstone = 0;\n }\n\n const updatePayload = {} as Record<string, unknown>;\n const replacedCells: [column: string, previousHlc: string | undefined][] = [];\n const previousCreateHlc = meta.id;\n\n for (const [key, value] of Object.entries(eventPayload)) {\n if (key === \"id\") {\n continue;\n }\n\n const lastUpdateTimestamp = meta[key];\n const currentUpdateTimestamp = event.timestamp;\n\n if (!lastUpdateTimestamp || !currentUpdateTimestamp || currentUpdateTimestamp > lastUpdateTimestamp) {\n updatePayload[key] = value;\n replacedCells.push([key, lastUpdateTimestamp]);\n meta[key] = currentUpdateTimestamp;\n }\n }\n\n const isLatestCreate = event.type === \"item-created\" && (!previousCreateHlc || event.timestamp > previousCreateHlc);\n if (isLatestCreate) {\n meta.id = event.timestamp;\n }\n\n if (replacedCells.length === 0 && !isLatestCreate) {\n return;\n }\n\n if (replacedCells.length > 0) {\n updateItem({\n dataset: event.dataset,\n itemId: event.item_id,\n payload: updatePayload,\n });\n }\n updateCrdtUpdateLog({\n dataset: event.dataset,\n itemId: event.item_id,\n payload: JSON.stringify(meta),\n });\n getStateHash?.()?.updateItem(event.dataset, event.item_id, meta, previousCreateHlc, replacedCells);\n };\n\n return (event: PendingCrdtEvent) => {\n if (isNoOpCrdtEventPayload(event.payload)) {\n return;\n }\n\n const meta = getCrdtUpdateLog({\n itemId: event.item_id,\n dataset: event.dataset,\n });\n\n // TODO Check primary key / unique constraints\n\n if (event.type !== \"item-created\" && event.type !== \"item-updated\" && event.type !== \"item-deleted\") {\n throw new Error(`Unknown event type: ${event.type}`);\n }\n\n if (meta) {\n applyItemUpdated({ event, meta });\n return;\n }\n\n if (event.type === \"item-created\") {\n applyItemCreated({ event });\n return;\n }\n\n throw new Error(`Item ${event.item_id} in dataset ${event.dataset} not found`);\n };\n}\n","import { sql } from \"kysely\";\nimport { deserializeHLC, type HLCCounter, serializeHLC } from \"../hlc\";\nimport type { SyncDbMigrator } from \"../migrations/migrator\";\nimport type { SystemDbConfig } from \"../migrations/system-schema\";\nimport { CrdtEventValidationError, validateNewCrdtEvent } from \"../schema/validate-crdt-event\";\nimport type { InternalSQLiteTransactionWrapper, InternalSQLiteWrapper } from \"../sqlite-db-wrapper\";\nimport { createTypedEventTarget, ensureSingletonExecution, quoteId } from \"../utils\";\nimport { createSQLiteCrdtApplyFunction } from \"./apply-crdt-event\";\nimport type { SyncDbSchema } from \"./crdt-schema\";\nimport {\n CRDT_EVENT_NO_OP_PAYLOAD,\n type CrdtEventOrigin,\n type CrdtEventStatus,\n type CrdtEventType,\n type CrdtUpdateLogItem,\n isNoOpCrdtEventPayload,\n type NewCrdtEvent,\n type PersistedCrdtEvent,\n} from \"./crdt-table-schema\";\nimport { createStateHashTracker, type StateHashStore } from \"./state-hash\";\n\ntype LocalCrdtEvent = {\n type: CrdtEventType;\n dataset: string;\n item_id: string;\n payload: string;\n timestamp: string;\n schema_version: number;\n};\n\nexport type OwnCrdtEvent = {\n type: CrdtEventType;\n dataset: string;\n item_id: string;\n payload: string;\n timestamp?: undefined;\n schema_version?: undefined;\n};\n\nexport type OwnCrdtSnapshot = {\n dataset: string;\n item_id: string;\n patch: Record<string, unknown>;\n};\n\nexport type CrdtChangeIntent = {\n seq: number;\n dataset: string;\n type: CrdtEventType;\n item_id: string;\n new_item_id: string | null;\n payload_json: string;\n};\n\ntype RemoteCrdtEvent = {\n type: CrdtEventType;\n dataset: string;\n item_id: string;\n payload: string;\n timestamp: string;\n schema_version: number;\n};\n\ntype EnqueuedCrdtEvent = LocalCrdtEvent | OwnCrdtEvent | RemoteCrdtEvent;\n\nexport type GetEventsOptions = {\n afterSyncId?: number;\n status?: CrdtEventStatus;\n excludeOrigin?: string;\n excludeNodeId?: string;\n limit?: number;\n};\n\nexport type GetEventsBatchQuery = {\n afterSyncId: number;\n status: CrdtEventStatus;\n limit: number;\n} & (\n | { excludeOrigin: CrdtEventOrigin; excludeNodeId?: undefined }\n | { excludeOrigin?: undefined; excludeNodeId: string }\n);\n\nexport type GetEventsBatch = {\n events: PersistedCrdtEvent[];\n hasMore: boolean;\n nextSyncId: number;\n};\n\nexport type EnqueueEventsResult = {\n beforeSyncId: number;\n afterSyncId: number;\n /** Resolves when the enqueued events have been processed (applied/deduped/failed). */\n processed: Promise<void>;\n};\n\nexport type EventUpdate = {\n status: CrdtEventStatus;\n schema_version: number;\n type: CrdtEventType;\n dataset: string;\n item_id: string;\n payload: string;\n};\n\ntype StorageHLC = Pick<HLCCounter, \"getNextHLC\" | \"mergeHLC\" | \"restoreHLC\">;\n\ntype DbSyncerStorage = {\n nodeId: string;\n initialLocalSyncId: number;\n migrator: SyncDbMigrator;\n db: InternalSQLiteWrapper<any>;\n dbConfig: SystemDbConfig;\n hlc: StorageHLC;\n stateHash?: StateHashStore;\n onEventApplied?: (event: PersistedCrdtEvent) => void;\n schema: Pick<SyncDbSchema, \"tables\" | \"tablesConfig\">;\n};\n\nexport type CrdtStorage = Omit<ReturnType<typeof createCrdtStorage>, \"internal\">;\n\nexport type InternalCrdtStorage = ReturnType<typeof createCrdtStorage>;\n\ntype EventsAppliedPayload = {\n syncId: number;\n stateHash: string | null;\n};\n\ntype InternalDbSchema = {\n _crdt_events: PersistedCrdtEvent;\n _crdt_update_log: CrdtUpdateLogItem;\n};\n\ntype FirstAcceptedSyncIdRow = { timestamp: string; first_sync_id: number };\n\nexport function createCrdtStorage(storage: DbSyncerStorage) {\n let localSyncId = storage.initialLocalSyncId;\n\n const db = storage.db as InternalSQLiteWrapper<InternalDbSchema>;\n\n const crdtEventsTable = storage.dbConfig.eventsTable.fullIdentifier as \"_crdt_events\";\n const quotedEventsTable = quoteId(storage.dbConfig.eventsTable.fullIdentifier);\n const noOpPayloadSqlLiteral = `'${CRDT_EVENT_NO_OP_PAYLOAD}'`;\n\n const [persistedClock] = db.executePreparedRaw<[], { timestamp: string | null }>({\n key: \"get-persisted-hlc\",\n sql: `select max(\"timestamp\") as \"timestamp\" from (\n select max(\"timestamp\") as \"timestamp\" from ${quotedEventsTable} where \"status\" = 'applied'\n union all\n select max(fields.value) as \"timestamp\"\n from ${quoteId(storage.dbConfig.updateLogTable.fullIdentifier)} as updates, json_each(updates.payload) as fields\n )`,\n meta: { loggerLevel: \"system\" },\n });\n if (persistedClock?.timestamp) {\n storage.hlc.restoreHLC(deserializeHLC(persistedClock.timestamp));\n }\n\n const readPersistedSyncId = (executor: Pick<InternalSQLiteWrapper<InternalDbSchema>, \"executePreparedRaw\">) => {\n const [row] = executor.executePreparedRaw<[], { sync_id: number | null }>({\n key: \"get-max-persisted-sync-id\",\n sql: `select max(\"sync_id\") as \"sync_id\" from ${quotedEventsTable}`,\n meta: { loggerLevel: \"system\" },\n });\n return Math.max(storage.initialLocalSyncId, row?.sync_id ?? 0);\n };\n\n const refreshLocalSyncId = () => {\n localSyncId = readPersistedSyncId(db);\n };\n\n const getInitialSequentialSyncId = () => {\n const [firstPendingEvent] = db.executePrepared(\n \"get-first-pending-event\",\n { status: \"pending\" as const },\n (db, params) =>\n db\n .selectFrom(crdtEventsTable)\n .select(\"sync_id\")\n .where(\"status\", \"=\", params(\"status\"))\n .orderBy(\"sync_id\", \"asc\")\n .limit(sql.lit(1)),\n { loggerLevel: \"system\" },\n );\n\n return firstPendingEvent ? firstPendingEvent.sync_id - 1 : localSyncId;\n };\n\n let sequentialSyncId = getInitialSequentialSyncId();\n\n const eventTarget = createTypedEventTarget<{\n \"events-applied\": EventsAppliedPayload;\n \"remote-event-apply-failed\": { syncId: number };\n }>();\n\n // Column order is the JSON array order for persist/read.\n const EVENT_COLUMNS = [\n \"sync_id\",\n \"schema_version\",\n \"status\",\n \"type\",\n \"timestamp\",\n \"origin\",\n \"source_node_id\",\n \"dataset\",\n \"item_id\",\n \"payload\",\n ] as const;\n\n const quotedEventColumns = EVENT_COLUMNS.map((column) => quoteId(column)).join(\", \");\n\n const persistEventsSql = `insert into ${quotedEventsTable} (${quotedEventColumns}) select ${EVENT_COLUMNS.map(\n (_, index) => `\"value\"->>${index}`,\n ).join(\", \")} from json_each(?)`;\n\n const pendingEventsSql = `select json_group_array(json_array(${quotedEventColumns})) as \"batch\" from (select ${quotedEventColumns} from ${quotedEventsTable} where \"status\" = ? order by \"sync_id\" asc limit ?)`;\n\n const PERSIST_EVENTS_CHUNK_SIZE = 100;\n\n const eventToRow = (event: PersistedCrdtEvent) => [\n event.sync_id,\n event.schema_version,\n event.status,\n event.type,\n event.timestamp,\n event.origin,\n event.source_node_id,\n event.dataset,\n event.item_id,\n event.payload,\n ];\n\n type EventRow = [\n number,\n number,\n CrdtEventStatus,\n CrdtEventType,\n string,\n CrdtEventOrigin,\n string,\n string,\n string,\n string,\n ];\n\n const rowToEvent = (row: EventRow): PersistedCrdtEvent => ({\n sync_id: row[0],\n schema_version: row[1],\n status: row[2],\n type: row[3],\n timestamp: row[4],\n origin: row[5],\n source_node_id: row[6],\n dataset: row[7],\n item_id: row[8],\n payload: row[9],\n });\n\n const persistEvents = (tx: InternalSQLiteTransactionWrapper<InternalDbSchema>, events: PersistedCrdtEvent[]) => {\n for (let offset = 0; offset < events.length; offset += PERSIST_EVENTS_CHUNK_SIZE) {\n const chunk = events.slice(offset, offset + PERSIST_EVENTS_CHUNK_SIZE);\n tx.executePreparedRaw<[string], never>({\n key: \"persist-crdt-events\",\n sql: persistEventsSql,\n params: [JSON.stringify(chunk.map(eventToRow))],\n meta: { loggerLevel: \"system\" },\n });\n }\n };\n\n const readPendingEvents = (limit: number): PersistedCrdtEvent[] => {\n const [row] = db.executePreparedRaw<[string, number], { batch: string }>({\n key: \"get-enqueued-pending-events\",\n sql: pendingEventsSql,\n params: [\"pending\", limit],\n meta: { loggerLevel: \"system\" },\n });\n\n return (JSON.parse(row.batch) as EventRow[]).map(rowToEvent);\n };\n\n const enqueueEvents = (\n origin: CrdtEventOrigin,\n sourceNodeId: string,\n events: EnqueuedCrdtEvent[],\n ): EnqueueEventsResult => {\n if (events.length === 0) {\n refreshLocalSyncId();\n return { beforeSyncId: localSyncId, afterSyncId: localSyncId, processed: Promise.resolve() };\n }\n\n let beforeSyncId = 0;\n let syncId = 0;\n db.executeTransaction((tx) => {\n beforeSyncId = readPersistedSyncId(tx);\n syncId = beforeSyncId;\n const persistedEvents = events.map(\n (event): PersistedCrdtEvent => ({\n schema_version: event.schema_version ?? storage.migrator.currentSchemaVersion,\n timestamp: event.timestamp ?? serializeHLC(storage.hlc.getNextHLC()),\n type: event.type,\n dataset: event.dataset,\n item_id: event.item_id,\n origin: origin,\n source_node_id: sourceNodeId,\n payload: event.payload,\n sync_id: ++syncId,\n status: \"pending\",\n }),\n );\n persistEvents(tx, persistedEvents);\n });\n localSyncId = syncId;\n\n return { beforeSyncId, afterSyncId: syncId, processed: processEnqueuedEvents() };\n };\n\n const enqueueLocalEvents = (events: LocalCrdtEvent[], sourceNodeId: string): EnqueueEventsResult => {\n const known = getFirstAcceptedSyncIdsByTimestamp(db, events);\n const newEvents = events.filter((event) => {\n if (known.has(event.timestamp)) {\n return false;\n }\n known.set(event.timestamp, 0);\n return true;\n });\n return enqueueEvents(\"local\", sourceNodeId, newEvents);\n };\n\n const enqueueRemoteEvents = (events: RemoteCrdtEvent[]): EnqueueEventsResult => {\n return enqueueEvents(\"remote\", \"\", events);\n };\n\n const notifyEventsApplied = (events: PersistedCrdtEvent[]) => {\n const onEventApplied = storage.onEventApplied;\n if (!onEventApplied || events.length === 0) {\n return;\n }\n\n queueMicrotask(() => {\n let callbackFailed = false;\n let firstError: unknown;\n for (const event of events) {\n try {\n onEventApplied(event);\n } catch (error) {\n callbackFailed = true;\n firstError ??= error;\n }\n }\n if (callbackFailed) {\n throw firstError;\n }\n });\n };\n\n const applyOwnEvents = (events: OwnCrdtEvent[]) => {\n const schema = storage.schema;\n if (!schema) {\n throw new Error(\"applyOwnEvents requires a sync schema; none was provided to createCrdtStorage\");\n }\n\n const validatedEvents: NewCrdtEvent[] = [];\n const errors: string[] = [];\n\n for (const [index, event] of events.entries()) {\n const result = validateNewCrdtEvent(schema, {\n type: event.type,\n dataset: event.dataset,\n item_id: event.item_id,\n payload: event.payload,\n });\n\n if (!result.success) {\n errors.push(...result.errors.map((error) => `[${index}] ${error}`));\n continue;\n }\n\n validatedEvents.push(result.event);\n }\n\n if (errors.length > 0) {\n throw new CrdtEventValidationError(errors);\n }\n\n let syncId = 0;\n db.executeTransaction((tx) => {\n syncId = readPersistedSyncId(tx);\n const persistedEvents = validatedEvents.map(\n (event): PersistedCrdtEvent => ({\n schema_version: storage.migrator.currentSchemaVersion,\n timestamp: serializeHLC(storage.hlc.getNextHLC()),\n type: event.type,\n dataset: event.dataset,\n item_id: event.item_id,\n origin: \"own-applied\",\n source_node_id: storage.nodeId,\n payload: JSON.stringify(event.payload),\n sync_id: ++syncId,\n status: \"pending\",\n }),\n );\n persistEvents(tx, persistedEvents);\n withStateHash(() => {\n for (const persistedEvent of persistedEvents) {\n applyCrdtEvent(persistedEvent);\n }\n });\n });\n localSyncId = syncId;\n\n void processEnqueuedEvents();\n };\n\n const applyOwnSnapshot = (snapshot: OwnCrdtSnapshot) => {\n let syncId = 0;\n db.executeTransaction((tx) => {\n syncId = readPersistedSyncId(tx) + 1;\n const [currentRow] = tx.executePreparedRaw<[string], Record<string, unknown>>({\n key: `get-crdt-snapshot-row-${snapshot.dataset}`,\n sql: `select * from ${quoteId(snapshot.dataset)} where \"id\" = ? limit 1`,\n params: [snapshot.item_id],\n meta: { loggerLevel: \"system\" },\n });\n\n const event: PersistedCrdtEvent = {\n schema_version: storage.migrator.currentSchemaVersion,\n timestamp: serializeHLC(storage.hlc.getNextHLC()),\n type: \"item-created\",\n dataset: snapshot.dataset,\n item_id: snapshot.item_id,\n origin: \"own-applied\",\n source_node_id: storage.nodeId,\n payload: JSON.stringify({\n ...(currentRow ?? {}),\n ...snapshot.patch,\n id: snapshot.item_id,\n tombstone: false,\n }),\n sync_id: syncId,\n status: \"pending\",\n };\n\n // An event newer than the snapshot (e.g. a pending remote event stamped by a clock ahead of\n // ours) still wins LWW, and fresh replicas can only replay it on top of the row's original\n // history, so the history is kept intact until a later snapshot outranks every event.\n const [newerEvent] = tx.executePreparedRaw<[string, string, string], { sync_id: number }>({\n key: \"get-crdt-row-event-newer-than-snapshot\",\n sql: `select \"sync_id\" from ${quotedEventsTable}\nwhere \"dataset\" = ? and \"item_id\" = ? and \"timestamp\" > ? and \"payload\" <> ${noOpPayloadSqlLiteral}\nlimit 1`,\n params: [event.dataset, event.item_id, event.timestamp],\n meta: { loggerLevel: \"system\" },\n });\n\n if (!newerEvent) {\n tx.executePreparedRaw<[string, string, string], never>({\n key: \"replace-crdt-row-history-with-no-ops\",\n // Keep the no-op sentinel literal in this predicate so SQLite can use the\n // matching partial index. A bound parameter does not imply its predicate.\n sql: `update ${quotedEventsTable}\nset \"payload\" = ?\nwhere \"dataset\" = ? and \"item_id\" = ? and \"payload\" <> ${noOpPayloadSqlLiteral}`,\n params: [CRDT_EVENT_NO_OP_PAYLOAD, event.dataset, event.item_id],\n meta: { loggerLevel: \"system\" },\n });\n }\n persistEvents(tx, [event]);\n applyCrdtEvent(event);\n });\n localSyncId = syncId;\n\n void processEnqueuedEvents();\n };\n\n const applyOwnEventFromTransaction = (\n tx: InternalSQLiteTransactionWrapper<InternalDbSchema>,\n event: OwnCrdtEvent,\n ) => {\n const persistedEvent: PersistedCrdtEvent = {\n schema_version: storage.migrator.currentSchemaVersion,\n timestamp: serializeHLC(storage.hlc.getNextHLC()),\n type: event.type,\n dataset: event.dataset,\n item_id: event.item_id,\n origin: \"own-applied\",\n source_node_id: storage.nodeId,\n payload: event.payload,\n sync_id: readPersistedSyncId(tx) + 1,\n status: \"pending\",\n };\n\n persistEvents(tx, [persistedEvent]);\n applyCrdtEvent(persistedEvent);\n };\n\n const applyOwnIntentsFromTransaction = (\n tx: InternalSQLiteTransactionWrapper<InternalDbSchema>,\n intents: CrdtChangeIntent[],\n ) =>\n withStateHash(() => {\n let appliedEvents = 0;\n\n for (const intent of intents) {\n if (intent.type === \"item-updated\") {\n if (intent.item_id !== intent.new_item_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 if (intent.payload_json === \"{}\") {\n continue;\n }\n }\n\n applyOwnEventFromTransaction(tx, {\n type: intent.type,\n dataset: intent.dataset,\n item_id: intent.item_id,\n payload: intent.payload_json,\n });\n appliedEvents++;\n }\n\n return { appliedEvents };\n });\n\n const dispatchEventsApplied = (previousSequentialSyncId: number) => {\n if (sequentialSyncId <= previousSequentialSyncId) {\n return;\n }\n eventTarget.dispatchEvent(\"events-applied\", {\n syncId: sequentialSyncId,\n stateHash: sequentialSyncId === localSyncId ? getStateHash() : null,\n });\n };\n\n const publishProcessedBatch = ({\n previousSequentialSyncId,\n nextSequentialSyncId,\n appliedEvents,\n }: {\n previousSequentialSyncId: number;\n nextSequentialSyncId: number;\n appliedEvents: PersistedCrdtEvent[];\n }) => {\n sequentialSyncId = nextSequentialSyncId;\n\n // Schedule per-event observers before dispatching cursor progress, matching\n // the previous ordering while keeping both signals behind one post-commit API.\n notifyEventsApplied(appliedEvents);\n dispatchEventsApplied(previousSequentialSyncId);\n };\n\n const hasPendingEvents = (): boolean => {\n const events = db.executePrepared(\n \"has-pending-events\",\n { status: \"pending\" as const },\n (db, params) =>\n db.selectFrom(crdtEventsTable).select(\"sync_id\").where(\"status\", \"=\", params(\"status\")).limit(sql.lit(1)),\n { loggerLevel: \"system\" },\n );\n return events.length > 0;\n };\n\n const getEventsBatch = (options: GetEventsBatchQuery): GetEventsBatch => {\n const limit = options.limit ?? 50;\n\n const queryParams = {\n limit: limit + 1,\n status: options.status ?? null,\n afterSyncId: options.afterSyncId ?? null,\n excludeOrigin: options.excludeOrigin ?? null,\n excludeNodeId: options.excludeNodeId ?? null,\n maxSyncId: options.status === \"applied\" ? sequentialSyncId : localSyncId,\n };\n\n const filterKeys = [\n queryParams.excludeNodeId ? \"nodeid\" : \"no-nodeid\",\n queryParams.excludeOrigin ? \"origin\" : \"no-origin\",\n ];\n\n const events = db.executePrepared(\n `get-events-batch-${filterKeys.join(\"-\")}`,\n queryParams,\n (db, params) =>\n db\n .selectFrom(crdtEventsTable)\n .where(\"sync_id\", \">\", params(\"afterSyncId\"))\n .where(\"sync_id\", \"<=\", params(\"maxSyncId\"))\n .where(\"status\", \"=\", params(\"status\"))\n .$if(!!queryParams.excludeNodeId, (qb) => qb.where(\"source_node_id\", \"!=\", params(\"excludeNodeId\")))\n .$if(!!queryParams.excludeOrigin, (qb) => qb.where(\"origin\", \"!=\", params(\"excludeOrigin\")))\n .selectAll()\n .limit(params(\"limit\"))\n .orderBy(\"sync_id\", \"asc\"),\n { loggerLevel: \"system\" },\n );\n\n const hasMore = events.length > limit;\n if (hasMore) {\n events.pop();\n }\n\n const lastReturnedSyncId = events[events.length - 1]?.sync_id ?? options.afterSyncId ?? 0;\n let nextSyncId = lastReturnedSyncId;\n if (!hasMore && options.status === \"applied\") {\n nextSyncId = Math.max(lastReturnedSyncId, queryParams.maxSyncId);\n }\n\n return {\n events,\n hasMore,\n nextSyncId,\n };\n };\n\n // Storage is quiescent when there is nothing left to converge: no events waiting\n // to be applied, and no local applied events past `pushedSyncId` still waiting to\n // be pushed to the remote. When quiescent and caught up, the local and remote node\n // share the exact same set of applied events, so their HLC checksums must match.\n const checkIsQuiescent = (pushedSyncId: number): boolean => {\n if (hasPendingEvents()) {\n return false;\n }\n\n const unpushed = getEventsBatch({\n status: \"applied\",\n afterSyncId: pushedSyncId,\n excludeOrigin: \"remote\",\n limit: 1,\n });\n\n return unpushed.events.length === 0;\n };\n\n const stateHash = createStateHashTracker({\n db,\n updateLogTable: storage.dbConfig.updateLogTable.fullIdentifier,\n schema: storage.schema,\n getSchemaVersion: () => storage.migrator.currentSchemaVersion,\n store: storage.stateHash ?? null,\n });\n const withStateHash = stateHash.track;\n const getStateHash = stateHash.read;\n\n const applyCrdtEventWithoutStateHash = createSQLiteCrdtApplyFunction({\n db,\n dbConfig: storage.dbConfig,\n getStateHash: () => stateHash.active,\n });\n const applyCrdtEvent = (event: Parameters<typeof applyCrdtEventWithoutStateHash>[0]) =>\n withStateHash(() => applyCrdtEventWithoutStateHash(event));\n\n const getFirstAcceptedSyncIdsByTimestamp = (\n tx: InternalSQLiteTransactionWrapper<InternalDbSchema>,\n events: { timestamp: string }[],\n ) => {\n const timestamps = Array.from(new Set(events.map((event) => event.timestamp)));\n if (timestamps.length === 0) {\n return new Map<string, number>();\n }\n\n const rows =\n timestamps.length === 1\n ? tx.executePreparedRaw<string[], FirstAcceptedSyncIdRow>({\n key: \"get-first-accepted-sync-id-by-timestamp\",\n sql: `select \"timestamp\", min(\"sync_id\") as \"first_sync_id\" from ${quotedEventsTable} where \"status\" = 'applied' and \"timestamp\" = ? group by \"timestamp\"`,\n params: timestamps,\n meta: { loggerLevel: \"system\" },\n })\n : tx.executePreparedRaw<string[], FirstAcceptedSyncIdRow>({\n key: \"get-first-accepted-sync-ids-by-timestamp\",\n sql: `select \"timestamp\", min(\"sync_id\") as \"first_sync_id\" from ${quotedEventsTable} where \"status\" = 'applied' and \"timestamp\" in (select \"value\" from json_each(?)) group by \"timestamp\"`,\n params: [JSON.stringify(timestamps)],\n meta: { loggerLevel: \"system\" },\n });\n\n return new Map(rows.map((row) => [row.timestamp, row.first_sync_id]));\n };\n\n const updateEventStatuses = (\n tx: InternalSQLiteTransactionWrapper<InternalDbSchema>,\n events: PersistedCrdtEvent[],\n ) => {\n const syncIdsByStatus = new Map<Exclude<CrdtEventStatus, \"pending\">, number[]>();\n for (const event of events) {\n if (event.status === \"pending\") {\n throw new Error(`Event ${event.sync_id} is still pending after processing`);\n }\n\n const syncIds = syncIdsByStatus.get(event.status) ?? [];\n syncIds.push(event.sync_id);\n syncIdsByStatus.set(event.status, syncIds);\n }\n\n for (const [status, syncIds] of syncIdsByStatus) {\n if (syncIds.length === 1) {\n tx.executePreparedRaw<[string, number], never>({\n key: \"update-crdt-event-status\",\n sql: `update ${quotedEventsTable} set \"status\" = ? where \"sync_id\" = ?`,\n params: [status, syncIds[0]],\n meta: { loggerLevel: \"system\" },\n });\n continue;\n }\n\n tx.executePreparedRaw<[string, string], never>({\n key: \"update-crdt-event-status-batch\",\n sql: `update ${quotedEventsTable} set \"status\" = ? where \"sync_id\" in (select \"value\" from json_each(?))`,\n params: [status, JSON.stringify(syncIds)],\n meta: { loggerLevel: \"system\" },\n });\n }\n };\n\n const processPersistedEvent = (\n tx: InternalSQLiteTransactionWrapper<InternalDbSchema>,\n event: PersistedCrdtEvent,\n firstAcceptedSyncIdByTimestamp: Map<string, number>,\n statusOnlyEvents: PersistedCrdtEvent[],\n ) => {\n if (event.status !== \"pending\") {\n throw new Error(`Event ${event.sync_id} is not pending`);\n }\n\n const persistedEventData = {\n schema_version: event.schema_version,\n type: event.type,\n dataset: event.dataset,\n item_id: event.item_id,\n payload: event.payload,\n };\n\n try {\n if (event.origin === \"own-applied\") {\n event.status = \"applied\";\n return event;\n }\n\n const firstAcceptedSyncId = firstAcceptedSyncIdByTimestamp.get(event.timestamp);\n if (firstAcceptedSyncId !== undefined && firstAcceptedSyncId < event.sync_id) {\n event.status = \"deduped\";\n return event;\n }\n\n // Always advance HLC, even for no-op events, to maintain monotonic ordering\n if (event.origin === \"local\" || event.origin === \"remote\") {\n storage.hlc.mergeHLC(deserializeHLC(event.timestamp));\n }\n\n if (isNoOpCrdtEventPayload(event.payload)) {\n applyCrdtEvent(event);\n event.status = \"applied\";\n return event;\n }\n\n const migratedEvent = storage.migrator.migrateEvent(event, storage.migrator.latestSchemaVersion);\n\n if (migratedEvent === null) {\n // Event was dropped during migration (e.g., table was deleted)\n event.schema_version = storage.migrator.latestSchemaVersion;\n event.payload = CRDT_EVENT_NO_OP_PAYLOAD;\n\n applyCrdtEvent(event);\n event.status = \"applied\";\n return event;\n }\n\n event.schema_version = migratedEvent.schema_version;\n event.type = migratedEvent.type;\n event.dataset = migratedEvent.dataset;\n event.item_id = migratedEvent.item_id;\n event.payload = migratedEvent.payload;\n\n applyCrdtEvent(event);\n event.status = \"applied\";\n } catch (error) {\n console.error(\"Error applying enqueued CRDT event\", error);\n event.status = \"failed\";\n } finally {\n const eventDataChanged =\n event.schema_version !== persistedEventData.schema_version ||\n event.type !== persistedEventData.type ||\n event.dataset !== persistedEventData.dataset ||\n event.item_id !== persistedEventData.item_id ||\n event.payload !== persistedEventData.payload;\n\n if (eventDataChanged) {\n tx.executePrepared(\n \"update-crdt-event-full\",\n event,\n (db, params) =>\n db\n .updateTable(crdtEventsTable)\n .set({\n status: params(\"status\"),\n schema_version: params(\"schema_version\"),\n type: params(\"type\"),\n dataset: params(\"dataset\"),\n item_id: params(\"item_id\"),\n payload: params(\"payload\"),\n })\n .where(\"sync_id\", \"=\", params(\"sync_id\")),\n { loggerLevel: \"system\" },\n );\n } else {\n statusOnlyEvents.push(event);\n }\n }\n };\n\n const processEnqueuedEvents = ensureSingletonExecution(async () => {\n let hasMore = true;\n while (hasMore) {\n await Promise.resolve();\n refreshLocalSyncId();\n\n const batchSize = 100;\n\n const events = readPendingEvents(batchSize + 1);\n hasMore = events.length > batchSize;\n if (hasMore) {\n events.pop();\n }\n\n const previousSequentialSyncId = sequentialSyncId;\n if (events.length === 0) {\n publishProcessedBatch({\n previousSequentialSyncId,\n nextSequentialSyncId: localSyncId,\n appliedEvents: [],\n });\n break;\n }\n\n const failedRemoteSyncIds: number[] = [];\n const appliedEventsToNotify: PersistedCrdtEvent[] = [];\n\n db.executeTransaction((tx) => {\n const firstAcceptedSyncIdByTimestamp = getFirstAcceptedSyncIdsByTimestamp(\n tx,\n events.filter((event) => event.origin !== \"own-applied\"),\n );\n const statusOnlyEvents: PersistedCrdtEvent[] = [];\n\n withStateHash(() => {\n for (const event of events) {\n processPersistedEvent(tx, event, firstAcceptedSyncIdByTimestamp, statusOnlyEvents);\n if (event.status === \"applied\") {\n const firstAcceptedSyncId = firstAcceptedSyncIdByTimestamp.get(event.timestamp);\n if (firstAcceptedSyncId === undefined || event.sync_id < firstAcceptedSyncId) {\n firstAcceptedSyncIdByTimestamp.set(event.timestamp, event.sync_id);\n }\n if (storage.onEventApplied) {\n appliedEventsToNotify.push(event);\n }\n }\n if (event.status === \"failed\" && event.origin === \"remote\") {\n failedRemoteSyncIds.push(event.sync_id);\n }\n }\n });\n updateEventStatuses(tx, statusOnlyEvents);\n });\n publishProcessedBatch({\n previousSequentialSyncId,\n nextSequentialSyncId: hasMore ? (events[events.length - 1]?.sync_id ?? sequentialSyncId) : localSyncId,\n appliedEvents: appliedEventsToNotify,\n });\n\n // A remote event was accepted by the server but could not be applied\n // locally, which means our local state has diverged from the server.\n for (const syncId of failedRemoteSyncIds) {\n eventTarget.dispatchEvent(\"remote-event-apply-failed\", { syncId });\n }\n }\n });\n\n if (storage.stateHash) {\n db.executeTransaction(stateHash.initialize);\n }\n\n void processEnqueuedEvents();\n\n return {\n getEventsBatch,\n enqueueLocalEvents,\n enqueueRemoteEvents,\n applyOwnEvents,\n applyOwnSnapshot,\n checkIsQuiescent,\n getStateHash,\n\n addEventListener: eventTarget.addEventListener,\n removeEventListener: eventTarget.removeEventListener,\n\n internal: {\n applyOwnEventFromTransaction,\n applyOwnIntentsFromTransaction,\n processEnqueuedEvents,\n },\n };\n}\n","import type { CrdtStorage } from \"./crdt-storage\";\n\ntype CrdtSyncProducer = {\n storage: CrdtStorage;\n broadcastEvents: (request: { newSyncId: number; stateHash: string | null }) => void;\n};\n\nexport const createCrdtSyncProducer = ({ storage, broadcastEvents }: CrdtSyncProducer) => {\n storage.addEventListener(\"events-applied\", (event) => {\n broadcastEvents({\n newSyncId: event.payload.syncId,\n stateHash: event.payload.stateHash,\n });\n });\n};\n"],"mappings":"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"}
@@ -787,8 +787,6 @@ type SQLiteReactiveDbOptions = {
787
787
  loggerPrefix?: string;
788
788
  };
789
789
  type EventsMap = {
790
- "transaction-committed": undefined;
791
- "transaction-rolled-back": undefined;
792
790
  "any-table-changed": undefined;
793
791
  } & Record<`table:${string}`, void>;
794
792
  type LiveQuery<TResult> = {
@@ -815,6 +813,8 @@ declare class SQLiteReactiveDb<Database> {
815
813
  private isDisposed;
816
814
  private mutationVersion;
817
815
  private tableMutationVersions;
816
+ /** Runs inside the commit hook after a transaction that changed rows, so it must not use the database. */
817
+ afterCommit: (() => void) | null;
818
818
  private constructor();
819
819
  static create<Database>(opts: SQLiteReactiveDbOptions): SQLiteReactiveDb<Database>;
820
820
  /**
@@ -1327,4 +1327,4 @@ declare function createWasmMemoryDriver(): Promise<SqliteDriver>;
1327
1327
  declare function createWasmSqliteDriver(sqlite3: Sqlite3Static, db: Database): SqliteDriver;
1328
1328
  //#endregion
1329
1329
  export { parametersAreEqual as $, startPerformanceLogger as $t, WorkerState as A, MigrationsDb as An, tryCatch as At, verifySyncSchemaWithDriver as B, CrdtUpdateLogItem as Bn, KyselyStatementFactory as Bt, EventsPullRequest as C, TableBuilder as Cn, TypedEvent as Ct, EventsPullResponse as D, t as Dn, generateId as Dt, createCrdtSyncRemoteSource as E, WriteOrigin as En, createTypedEventTarget as Et, PendingCrdtEvent as F, createStoredValue as Fn, createSQLiteKvStore as Ft, DefinedSyncSchema as G, compileKyselyStatement as Gt, NewCrdtEventValidationResult as H, PersistedCrdtEvent as Hn, QueryBuilderOutput as Ht, createCrdtApplyFunction as I, CRDT_EVENT_NO_OP_PAYLOAD as In, ExecuteParams as It, ClientDatasetRejectionReason as J, SqliteDriverRows as Jt, defineSyncSchema as K, SqliteDriver as Kt, createSQLiteCrdtApplyFunction as L, CrdtEventOrigin as Ln, ExecuteResult as Lt, CrdtStorageMutator as M, createMigrations as Mn, KvStoreItem as Mt, SnapshotOptions as N, createMigrator as Nn, STATE_HASH_KV_KEY as Nt, WorkerConfig as O, MigratableEvent as On, jsonSafeParse as Ot, createCrdtStorageMutator as P, StoredValue as Pn, createKvStoreTableQuery as Pt, SharedLiveQuerySnapshot as Q, Logger as Qt, SchemaVerificationIssue as R, CrdtEventStatus as Rn, InternalSQLiteWrapper as Rt, CreateRemoteSourceFactory as S, SyncSchemaTables as Sn, TypedBroadcastChannel as St, EventsPushResponse as T, TableOptions as Tn, createDeferredPromise as Tt, validateNewCrdtEvent as U, isNoOpCrdtEventPayload as Un, SQLiteDbWrapper as Ut, CrdtEventValidationError as V, CrdtUpdateLogPayload as Vn, PreparedStatement as Vt, DefineSyncSchemaConfig as W, dummyKysely as Wn, SQLiteTransactionWrapper as Wt, SQLiteReactiveDb as X, SqliteDriverValue as Xt, admitClientEvents as Y, SqliteDriverStatement as Yt, SharedLiveQuery as Z, LogLevel as Zt, crdtViewColumnsFromTable as _, ColumnMeta as _n, baseSystemMigrations as _t, createSQLiteReactiveDb as a, HLCCounter as an, createImportData as at, makeCrdtTable as b, PayloadValidationResult as bn, DeferredPromise as bt, ResetStore as c, serializeHLC as cn, GetEventsBatch as ct, createSyncedDb as d, SyncDbSchema as dn, createCrdtStorage as dt, ColumnMetadata as en, xxhash as et, SyncedDbDatabase as f, AiAccess as fn, SystemDbConfig as ft, CRDT_CHANGE_INTENTS_TABLE as g, ColumnKind as gn, applyWorkerDbSchema as gt, UnsafeSyncedDbSqlExecutor as h, ColumnBuilder as hn, applyMemoryDbSchema as ht, verifySyncSchema as i, HLC as in, createExportData as it, createCrdtSyncProducer as j, SyncDbMigrator as jn, tryCatchAsync as jt, WorkerNotificationMessage as k, Migrations as kn, quoteId as kt, SyncedDb as l, CrdtTableConfig as ln, OwnCrdtEvent as lt, SyncedDbTransaction as m, AnyTableBuilder as mn, SystemMigrationContext as mt, createWasmSqliteDriver as n, TableMetadata as nn, ImportDataResult as nt, RESET_REQUEST_TTL_MS as o, compareHLC as on, CrdtChangeIntent as ot, SyncedDbSqlExecutor as p, AnyColumnBuilder as pn, SystemMigration as pt, AdmitClientEventsResult as q, SqliteDriverHooks as qt, loadSqliteWasm as r, introspectDb as rn, SyncedDbExport as rt, ResetRequest as s, deserializeHLC as sn, CrdtStorage as st, createWasmMemoryDriver as t, DatabaseIntrospection as tn, ImportDataOptions as tt, SyncedDbOptions as u, ReadonlyTable as un, OwnCrdtSnapshot as ut, createCrdtViewStatements as v, ExportImportMode as vn, createSystemDbConfig as vt, EventsPushRequest as w, TableColumns as wn, TypedEventTarget as wt, CrdtSyncRemoteSource as x, SqliteStorageType as xn, DistributiveOmit as xt, drainCrdtChangeIntents as y, InferRow as yn, runSystemMigrations as yt, formatSchemaVerificationIssues as z, CrdtEventType as zn, KyselyQueryFactory as zt };
1330
- //# sourceMappingURL=index-B3s_6aG6.d.ts.map
1330
+ //# sourceMappingURL=index-ChmCuLQU.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import "./system-schema-uHQdQTCk.js";
2
- import "./crdt-sync-producer-DVEWad4t.js";
2
+ import "./crdt-sync-producer-t2jHxO38.js";
3
3
  import "./crdt-sync-remote-source-yeTEkOjH.js";
4
- import "./sqlite-reactive-db-BwY3FoIy.js";
4
+ import "./sqlite-reactive-db-C2BtEAeE.js";
5
5
  import { n as buildWriteOriginByName } from "./admit-client-events-BDrJw4SK.js";
6
6
  //#region src/schema/define-sync-schema.ts
7
7
  const RESERVED_TABLE_NAMES = /* @__PURE__ */ new Set([
@@ -273,4 +273,4 @@ function createCrdtStorageMutator({ storage }) {
273
273
  //#endregion
274
274
  export { defineSyncSchema as a, t as i, ColumnBuilder as n, TableBuilder as r, createCrdtStorageMutator as t };
275
275
 
276
- //# sourceMappingURL=index.common-DZM6WeOn.js.map
276
+ //# sourceMappingURL=index.common-B9n2FOmn.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.common-DZM6WeOn.js","names":[],"sources":["../src/schema/define-sync-schema.ts","../src/schema/table-builder.ts","../src/sqlite-crdt/crdt-storage-mutator.ts"],"sourcesContent":["import type { Migrations } from \"../migrations/migrator\";\nimport type { CrdtTableConfig, ReadonlyTable, SyncDbSchema } from \"../sqlite-crdt/crdt-schema\";\nimport { buildWriteOriginByName } from \"./admit-client-events\";\nimport type {\n AnyTableBuilder,\n InferRow,\n SyncSchemaTables,\n TableBuilder,\n TableColumns,\n WriteOrigin,\n} from \"./table-builder\";\n\ntype Simplify<T> = { [K in keyof T]: T[K] } & {};\n\n// Names sqlite-sync uses for its own tables/views, so a user schema can't shadow them.\nconst RESERVED_TABLE_NAMES = new Set<string>([\n \"change_history\",\n \"crdt_events\",\n \"worker.crdt_events\",\n \"persisted_crdt_events\",\n \"crdt_update_log\",\n \"crdt_change_intents\",\n \"worker.kv\",\n \"sync_kv\",\n]);\n\ntype RowOf<Table extends AnyTableBuilder> =\n Table extends TableBuilder<infer Cols extends TableColumns, any, WriteOrigin> ? InferRow<Cols> : never;\n\n// Falls back to the \"_\" convention unless ~baseName is a string *literal* — inference can\n// resolve an omitted override to its constraint (string | undefined) rather than undefined.\ntype BaseNameOf<CrdtName, Table extends AnyTableBuilder> = string extends Table[\"~baseName\"]\n ? `_${CrdtName & string}`\n : [Table[\"~baseName\"]] extends [string]\n ? Table[\"~baseName\"]\n : `_${CrdtName & string}`;\n\ntype ClientSchemaOf<Tables extends SyncSchemaTables> = Simplify<\n {\n [K in keyof Tables]: Tables[K][\"~writeOrigin\"] extends \"server\"\n ? ReadonlyTable<RowOf<Tables[K]>>\n : RowOf<Tables[K]>;\n } & {\n [K in keyof Tables as BaseNameOf<K, Tables[K]>]: ReadonlyTable<RowOf<Tables[K]>>;\n }\n>;\n\ntype ServerSchemaOf<Tables extends SyncSchemaTables> = Simplify<\n { [K in keyof Tables]: RowOf<Tables[K]> } & {\n [K in keyof Tables as BaseNameOf<K, Tables[K]>]: ReadonlyTable<RowOf<Tables[K]>>;\n }\n>;\n\ntype MutationsSchemaOf<Tables extends SyncSchemaTables> = Simplify<{\n [K in keyof Tables as BaseNameOf<K, Tables[K]>]: RowOf<Tables[K]>;\n}>;\n\nexport interface DefinedSyncSchema<Tables extends SyncSchemaTables>\n extends SyncDbSchema<ClientSchemaOf<Tables>, ServerSchemaOf<Tables>, MutationsSchemaOf<Tables>> {\n /** The table builders, for type extraction (`typeof schema.tables.item.$row`) and runtime metadata. */\n tables: Tables;\n /** Write origin keyed by crdt and base table name. */\n writeOriginByName: ReadonlyMap<string, WriteOrigin>;\n}\n\nexport type DefineSyncSchemaConfig<Tables extends SyncSchemaTables> = {\n tables: Tables;\n /** Full migration history (including the initial createTable version), built with `createMigrations`. */\n migrations: Migrations;\n};\n\n/**\n * Define a sync database schema from `t.table()` builders.\n *\n * Record keys are the crdt (view) table names; base table names default to the key\n * prefixed with \"_\", overridable per table via `t.table(cols, { baseName })`.\n */\nexport function defineSyncSchema<Tables extends SyncSchemaTables>({\n tables,\n migrations,\n}: DefineSyncSchemaConfig<Tables>): DefinedSyncSchema<Tables> {\n const tablesConfig: CrdtTableConfig[] = Object.entries(tables).map(([crdtTableName, table]) => ({\n crdtTableName,\n baseTableName: table.baseName ?? `_${crdtTableName}`,\n ...(table.exportImport === \"ignore\" ? { exportImport: \"ignore\" } : {}),\n }));\n\n const seenNames = new Set<string>();\n for (const { crdtTableName, baseTableName } of tablesConfig) {\n for (const name of [crdtTableName, baseTableName]) {\n const normalizedName = name.toLowerCase();\n if (RESERVED_TABLE_NAMES.has(normalizedName)) {\n throw new Error(`Table name \"${name}\" is reserved by sqlite-sync and cannot be used in a sync schema`);\n }\n if (seenNames.has(normalizedName)) {\n throw new Error(`Duplicate table name \"${name}\" in sync schema`);\n }\n seenNames.add(normalizedName);\n }\n }\n\n const writeOriginByName = buildWriteOriginByName({ tables, tablesConfig });\n\n return {\n tables,\n get tablesConfig() {\n return tablesConfig;\n },\n get writeOriginByName() {\n return writeOriginByName;\n },\n get migrations() {\n return migrations;\n },\n get \"~clientSchema\"(): never {\n throw new Error(\"~clientSchema is type-only and cannot be accessed at runtime\");\n },\n get \"~serverSchema\"(): never {\n throw new Error(\"~serverSchema is type-only and cannot be accessed at runtime\");\n },\n get \"~mutationsSchema\"(): never {\n throw new Error(\"~mutationsSchema is type-only and cannot be accessed at runtime\");\n },\n };\n}\n","export type ColumnKind = \"text\" | \"integer\" | \"real\" | \"boolean\" | \"enum\";\n\nexport type SqliteStorageType = \"text\" | \"integer\" | \"real\";\n\n/**\n * What `@sqlite-sync/ai` may do with a table.\n * `read-only`: documented and queryable; mutations rejected.\n * `hidden`: omitted from the schema doc; reads rejected.\n */\nexport type AiAccess = \"read-write\" | \"read-only\" | \"hidden\";\n\n/**\n * Who may author CRDT events for a table.\n * `\"any\"` (default): every replica. `\"server\"`: client pushes drop these events.\n */\nexport type WriteOrigin = \"any\" | \"server\";\n\n/** Whether backup and restore include a table. */\nexport type ExportImportMode = \"include\" | \"ignore\";\n\nexport type ColumnMeta = {\n kind: ColumnKind;\n /** Storage type used in generated DDL. Booleans store as integer 0/1. */\n sqlType: SqliteStorageType;\n nullable: boolean;\n hasDefault: boolean;\n /** Declared default in JS form (booleans as booleans). */\n defaultValue?: unknown;\n /** Allowed values for `enum` columns. */\n enumValues?: readonly string[];\n description?: string;\n};\n\nexport class ColumnBuilder<Value, HasDefault extends boolean = false> {\n declare readonly \"~types\": { value: Value; hasDefault: HasDefault };\n\n constructor(readonly meta: ColumnMeta) {}\n\n /** Allow SQL NULL; widens the value type with `null`. */\n nullable(): ColumnBuilder<Value | null, HasDefault> {\n return new ColumnBuilder({ ...this.meta, nullable: true });\n }\n\n /** Declare a column default. Creates may omit the column; it must match the migrated DDL default. */\n default(value: Value): ColumnBuilder<Value, true> {\n return new ColumnBuilder({ ...this.meta, hasDefault: true, defaultValue: value });\n }\n\n /** Narrow the TypeScript value type without changing storage, e.g. `t.text().$type<\"movie\" | \"tv\">()`. */\n $type<Narrowed extends Value>(): ColumnBuilder<Narrowed, HasDefault> {\n return this as unknown as ColumnBuilder<Narrowed, HasDefault>;\n }\n\n /** Human/AI-readable description, surfaced in generated schema docs. */\n describe(description: string): ColumnBuilder<Value, HasDefault> {\n return new ColumnBuilder({ ...this.meta, description });\n }\n}\n\nexport type AnyColumnBuilder = ColumnBuilder<any, boolean>;\n\nexport type TableColumns = Record<string, AnyColumnBuilder>;\n\nexport type AnyTableBuilder = TableBuilder<any, any, WriteOrigin>;\n\nexport type SyncSchemaTables = Record<string, AnyTableBuilder>;\n\nexport type TableOptions<\n BaseName extends string | undefined = string | undefined,\n Writes extends WriteOrigin = \"any\",\n> = {\n /** Override the materialized base table name (defaults to the crdt table name prefixed with \"_\"). */\n baseName?: BaseName;\n description?: string;\n /** Defaults to `\"read-write\"`. See {@link AiAccess}. */\n ai?: AiAccess;\n /** Defaults to `\"any\"`. See {@link WriteOrigin}. */\n writes?: Writes;\n /** Defaults to `\"include\"`. Ignored tables are omitted from export and skipped on import. */\n exportImport?: ExportImportMode;\n};\n\ntype Simplify<T> = { [K in keyof T]: T[K] } & {};\n\ntype ColumnValue<Column> = Column extends ColumnBuilder<infer Value, boolean> ? Value : never;\n\nexport type InferRow<Cols extends TableColumns> = Simplify<\n { id: string } & { [K in keyof Cols]: ColumnValue<Cols[K]> } & { tombstone?: boolean }\n>;\n\nexport type PayloadValidationResult = { success: true } | { success: false; errors: string[] };\n\nconst RESERVED_COLUMNS = [\"id\", \"tombstone\"] as const;\n\nconst idColumnMeta: ColumnMeta = {\n kind: \"text\",\n sqlType: \"text\",\n nullable: false,\n hasDefault: false,\n description: \"Unique immutable item id\",\n};\n\nconst tombstoneColumnMeta: ColumnMeta = {\n kind: \"boolean\",\n sqlType: \"integer\",\n nullable: false,\n hasDefault: true,\n defaultValue: false,\n description: \"Soft-delete marker\",\n};\n\nexport class TableBuilder<\n Cols extends TableColumns,\n BaseName extends string | undefined = undefined,\n Writes extends WriteOrigin = \"any\",\n> {\n declare readonly \"~baseName\": BaseName;\n declare readonly \"~writeOrigin\": Writes;\n\n /** All columns in DDL order, including the auto-injected `id` and `tombstone`. */\n readonly columns: Record<string, ColumnMeta>;\n readonly baseName: BaseName;\n readonly description: string | undefined;\n /** Resolved {@link AiAccess}; defaults to `\"read-write\"`. */\n readonly aiAccess: AiAccess;\n /** Resolved {@link WriteOrigin}; defaults to `\"any\"`. */\n readonly writeOrigin: Writes;\n /** Resolved {@link ExportImportMode}; defaults to `\"include\"`. */\n readonly exportImport: ExportImportMode;\n\n constructor(\n readonly userColumns: Cols,\n options?: TableOptions<BaseName, Writes>,\n ) {\n for (const reserved of RESERVED_COLUMNS) {\n if (reserved in userColumns) {\n throw new Error(`Column \"${reserved}\" is added automatically to every synced table and cannot be declared`);\n }\n }\n\n this.columns = {\n id: idColumnMeta,\n ...Object.fromEntries(Object.entries(userColumns).map(([name, column]) => [name, column.meta])),\n tombstone: tombstoneColumnMeta,\n };\n this.baseName = options?.baseName as BaseName;\n this.description = options?.description;\n this.aiAccess = options?.ai ?? \"read-write\";\n this.writeOrigin = (options?.writes ?? \"any\") as Writes;\n this.exportImport = options?.exportImport ?? \"include\";\n }\n\n describe(description: string): TableBuilder<Cols, BaseName, Writes> {\n return new TableBuilder<Cols, BaseName, Writes>(this.userColumns, {\n baseName: this.baseName,\n description,\n ai: this.aiAccess,\n writes: this.writeOrigin,\n exportImport: this.exportImport,\n });\n }\n\n /** Type-only: the row shape returned by queries. Do not access at runtime. */\n get $row(): InferRow<Cols> {\n return null as never;\n }\n\n /**\n * Validate a CRDT event payload against the declared columns.\n * `item-created` payloads must contain every column without a default (nullable columns may be omitted)\n * and their `tombstone` value is ignored, since applying a create always sets it to 0;\n * `item-updated` payloads are partial and must not touch `id` or set `tombstone` to a deleted value.\n */\n validatePayload(\n payload: Record<string, unknown>,\n options?: { event?: \"item-created\" | \"item-updated\" },\n ): PayloadValidationResult {\n const event = options?.event ?? \"item-created\";\n const errors: string[] = [];\n\n for (const key of Object.keys(payload)) {\n if (!Object.hasOwn(this.columns, key)) {\n errors.push(`Unknown column \"${key}\"`);\n }\n }\n\n if (event === \"item-updated\") {\n if (\"id\" in payload) {\n errors.push(`Column \"id\" is immutable and cannot appear in an update payload`);\n }\n if (payload.tombstone === true || payload.tombstone === 1) {\n errors.push(`Column \"tombstone\" cannot be set to true/1 in an update payload; use an item-deleted event`);\n }\n }\n\n if (event === \"item-created\") {\n for (const [name, meta] of Object.entries(this.columns)) {\n if (Object.hasOwn(payload, name) || name === \"tombstone\" || meta.nullable || meta.hasDefault) {\n continue;\n }\n errors.push(`Missing required column \"${name}\"`);\n }\n }\n\n for (const [name, value] of Object.entries(payload)) {\n const meta = Object.hasOwn(this.columns, name) ? this.columns[name] : undefined;\n if (!meta || (event === \"item-updated\" && name === \"id\") || (event === \"item-created\" && name === \"tombstone\")) {\n continue;\n }\n const error = validateValue(name, value, meta);\n if (error) {\n errors.push(error);\n }\n }\n\n return errors.length === 0 ? { success: true } : { success: false, errors };\n }\n}\n\nfunction describeValue(value: unknown): string {\n if (value === null) return \"null\";\n if (Array.isArray(value)) return \"array\";\n return typeof value;\n}\n\nfunction validateValue(name: string, value: unknown, meta: ColumnMeta): string | null {\n if (value === null) {\n return meta.nullable ? null : `Column \"${name}\" is not nullable, got null`;\n }\n\n switch (meta.kind) {\n case \"text\":\n return typeof value === \"string\" ? null : `Column \"${name}\" expects text, got ${describeValue(value)}`;\n case \"integer\":\n return typeof value === \"number\" && Number.isInteger(value)\n ? null\n : `Column \"${name}\" expects an integer, got ${describeValue(value)}`;\n case \"real\":\n return typeof value === \"number\" && Number.isFinite(value)\n ? null\n : `Column \"${name}\" expects a number, got ${describeValue(value)}`;\n case \"boolean\":\n return typeof value === \"boolean\" || value === 0 || value === 1\n ? null\n : `Column \"${name}\" expects a boolean (true/false or 0/1), got ${describeValue(value)}`;\n case \"enum\": {\n if (typeof value !== \"string\") {\n return `Column \"${name}\" expects one of ${formatEnumValues(meta)}, got ${describeValue(value)}`;\n }\n return meta.enumValues?.includes(value)\n ? null\n : `Column \"${name}\" expects one of ${formatEnumValues(meta)}, got \"${value}\"`;\n }\n }\n}\n\nfunction formatEnumValues(meta: ColumnMeta): string {\n return (meta.enumValues ?? []).map((value) => `\"${value}\"`).join(\" | \");\n}\n\nfunction column<Value>(kind: ColumnKind, sqlType: SqliteStorageType): ColumnBuilder<Value> {\n return new ColumnBuilder<Value>({ kind, sqlType, nullable: false, hasDefault: false });\n}\n\nexport const t = {\n text: () => column<string>(\"text\", \"text\"),\n integer: () => column<number>(\"integer\", \"integer\"),\n real: () => column<number>(\"real\", \"real\"),\n /** Stored as INTEGER 0/1; always bind booleans as 0/1 when writing raw SQL. */\n boolean: () => column<boolean>(\"boolean\", \"integer\"),\n /**\n * Union of string literals stored as TEXT, e.g. `t.enum([\"movie\", \"tv\"])`. Unlike `$type`, the\n * allowed values are kept as runtime metadata, so payloads are validated against them.\n * For an open-ended set, use `t.text().$type<\"idle\" | (string & {})>()` instead.\n */\n enum: <const Values extends readonly [string, ...string[]]>(values: Values) =>\n new ColumnBuilder<Values[number]>({\n kind: \"enum\",\n sqlType: \"text\",\n nullable: false,\n hasDefault: false,\n enumValues: values,\n }),\n table: <\n Cols extends TableColumns,\n const BaseName extends string | undefined = undefined,\n const Writes extends WriteOrigin = \"any\",\n >(\n columns: Cols,\n options?: TableOptions<BaseName, Writes>,\n ) => new TableBuilder(columns, options),\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 AnyCommitEventOptions<Database> = {\n [Table in keyof Database & string]: CommitEventOptions<Database, Table>;\n}[keyof Database & string];\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 type SnapshotOptions<Database, Table extends keyof Database & string> = {\n dataset: Table;\n id: string;\n patch: UpdateEventPayload<Database, Table>;\n};\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 applyEvents = (events: AnyCommitEventOptions<Database>[]) => {\n storage.applyOwnEvents(events.map(mapToStorageEvent));\n };\n\n const applyEvent = <Table extends keyof Database & string>(event: CommitEventOptions<Database, Table>) => {\n storage.applyOwnEvents([mapToStorageEvent(event)]);\n };\n\n const applySnapshot = <Table extends keyof Database & string>(snapshot: SnapshotOptions<Database, Table>) => {\n storage.applyOwnSnapshot({\n dataset: snapshot.dataset,\n item_id: snapshot.id,\n patch: { ...snapshot.patch },\n });\n };\n\n return {\n applyEvent,\n applyEvents,\n applySnapshot,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.common-B9n2FOmn.js","names":[],"sources":["../src/schema/define-sync-schema.ts","../src/schema/table-builder.ts","../src/sqlite-crdt/crdt-storage-mutator.ts"],"sourcesContent":["import type { Migrations } from \"../migrations/migrator\";\nimport type { CrdtTableConfig, ReadonlyTable, SyncDbSchema } from \"../sqlite-crdt/crdt-schema\";\nimport { buildWriteOriginByName } from \"./admit-client-events\";\nimport type {\n AnyTableBuilder,\n InferRow,\n SyncSchemaTables,\n TableBuilder,\n TableColumns,\n WriteOrigin,\n} from \"./table-builder\";\n\ntype Simplify<T> = { [K in keyof T]: T[K] } & {};\n\n// Names sqlite-sync uses for its own tables/views, so a user schema can't shadow them.\nconst RESERVED_TABLE_NAMES = new Set<string>([\n \"change_history\",\n \"crdt_events\",\n \"worker.crdt_events\",\n \"persisted_crdt_events\",\n \"crdt_update_log\",\n \"crdt_change_intents\",\n \"worker.kv\",\n \"sync_kv\",\n]);\n\ntype RowOf<Table extends AnyTableBuilder> =\n Table extends TableBuilder<infer Cols extends TableColumns, any, WriteOrigin> ? InferRow<Cols> : never;\n\n// Falls back to the \"_\" convention unless ~baseName is a string *literal* — inference can\n// resolve an omitted override to its constraint (string | undefined) rather than undefined.\ntype BaseNameOf<CrdtName, Table extends AnyTableBuilder> = string extends Table[\"~baseName\"]\n ? `_${CrdtName & string}`\n : [Table[\"~baseName\"]] extends [string]\n ? Table[\"~baseName\"]\n : `_${CrdtName & string}`;\n\ntype ClientSchemaOf<Tables extends SyncSchemaTables> = Simplify<\n {\n [K in keyof Tables]: Tables[K][\"~writeOrigin\"] extends \"server\"\n ? ReadonlyTable<RowOf<Tables[K]>>\n : RowOf<Tables[K]>;\n } & {\n [K in keyof Tables as BaseNameOf<K, Tables[K]>]: ReadonlyTable<RowOf<Tables[K]>>;\n }\n>;\n\ntype ServerSchemaOf<Tables extends SyncSchemaTables> = Simplify<\n { [K in keyof Tables]: RowOf<Tables[K]> } & {\n [K in keyof Tables as BaseNameOf<K, Tables[K]>]: ReadonlyTable<RowOf<Tables[K]>>;\n }\n>;\n\ntype MutationsSchemaOf<Tables extends SyncSchemaTables> = Simplify<{\n [K in keyof Tables as BaseNameOf<K, Tables[K]>]: RowOf<Tables[K]>;\n}>;\n\nexport interface DefinedSyncSchema<Tables extends SyncSchemaTables>\n extends SyncDbSchema<ClientSchemaOf<Tables>, ServerSchemaOf<Tables>, MutationsSchemaOf<Tables>> {\n /** The table builders, for type extraction (`typeof schema.tables.item.$row`) and runtime metadata. */\n tables: Tables;\n /** Write origin keyed by crdt and base table name. */\n writeOriginByName: ReadonlyMap<string, WriteOrigin>;\n}\n\nexport type DefineSyncSchemaConfig<Tables extends SyncSchemaTables> = {\n tables: Tables;\n /** Full migration history (including the initial createTable version), built with `createMigrations`. */\n migrations: Migrations;\n};\n\n/**\n * Define a sync database schema from `t.table()` builders.\n *\n * Record keys are the crdt (view) table names; base table names default to the key\n * prefixed with \"_\", overridable per table via `t.table(cols, { baseName })`.\n */\nexport function defineSyncSchema<Tables extends SyncSchemaTables>({\n tables,\n migrations,\n}: DefineSyncSchemaConfig<Tables>): DefinedSyncSchema<Tables> {\n const tablesConfig: CrdtTableConfig[] = Object.entries(tables).map(([crdtTableName, table]) => ({\n crdtTableName,\n baseTableName: table.baseName ?? `_${crdtTableName}`,\n ...(table.exportImport === \"ignore\" ? { exportImport: \"ignore\" } : {}),\n }));\n\n const seenNames = new Set<string>();\n for (const { crdtTableName, baseTableName } of tablesConfig) {\n for (const name of [crdtTableName, baseTableName]) {\n const normalizedName = name.toLowerCase();\n if (RESERVED_TABLE_NAMES.has(normalizedName)) {\n throw new Error(`Table name \"${name}\" is reserved by sqlite-sync and cannot be used in a sync schema`);\n }\n if (seenNames.has(normalizedName)) {\n throw new Error(`Duplicate table name \"${name}\" in sync schema`);\n }\n seenNames.add(normalizedName);\n }\n }\n\n const writeOriginByName = buildWriteOriginByName({ tables, tablesConfig });\n\n return {\n tables,\n get tablesConfig() {\n return tablesConfig;\n },\n get writeOriginByName() {\n return writeOriginByName;\n },\n get migrations() {\n return migrations;\n },\n get \"~clientSchema\"(): never {\n throw new Error(\"~clientSchema is type-only and cannot be accessed at runtime\");\n },\n get \"~serverSchema\"(): never {\n throw new Error(\"~serverSchema is type-only and cannot be accessed at runtime\");\n },\n get \"~mutationsSchema\"(): never {\n throw new Error(\"~mutationsSchema is type-only and cannot be accessed at runtime\");\n },\n };\n}\n","export type ColumnKind = \"text\" | \"integer\" | \"real\" | \"boolean\" | \"enum\";\n\nexport type SqliteStorageType = \"text\" | \"integer\" | \"real\";\n\n/**\n * What `@sqlite-sync/ai` may do with a table.\n * `read-only`: documented and queryable; mutations rejected.\n * `hidden`: omitted from the schema doc; reads rejected.\n */\nexport type AiAccess = \"read-write\" | \"read-only\" | \"hidden\";\n\n/**\n * Who may author CRDT events for a table.\n * `\"any\"` (default): every replica. `\"server\"`: client pushes drop these events.\n */\nexport type WriteOrigin = \"any\" | \"server\";\n\n/** Whether backup and restore include a table. */\nexport type ExportImportMode = \"include\" | \"ignore\";\n\nexport type ColumnMeta = {\n kind: ColumnKind;\n /** Storage type used in generated DDL. Booleans store as integer 0/1. */\n sqlType: SqliteStorageType;\n nullable: boolean;\n hasDefault: boolean;\n /** Declared default in JS form (booleans as booleans). */\n defaultValue?: unknown;\n /** Allowed values for `enum` columns. */\n enumValues?: readonly string[];\n description?: string;\n};\n\nexport class ColumnBuilder<Value, HasDefault extends boolean = false> {\n declare readonly \"~types\": { value: Value; hasDefault: HasDefault };\n\n constructor(readonly meta: ColumnMeta) {}\n\n /** Allow SQL NULL; widens the value type with `null`. */\n nullable(): ColumnBuilder<Value | null, HasDefault> {\n return new ColumnBuilder({ ...this.meta, nullable: true });\n }\n\n /** Declare a column default. Creates may omit the column; it must match the migrated DDL default. */\n default(value: Value): ColumnBuilder<Value, true> {\n return new ColumnBuilder({ ...this.meta, hasDefault: true, defaultValue: value });\n }\n\n /** Narrow the TypeScript value type without changing storage, e.g. `t.text().$type<\"movie\" | \"tv\">()`. */\n $type<Narrowed extends Value>(): ColumnBuilder<Narrowed, HasDefault> {\n return this as unknown as ColumnBuilder<Narrowed, HasDefault>;\n }\n\n /** Human/AI-readable description, surfaced in generated schema docs. */\n describe(description: string): ColumnBuilder<Value, HasDefault> {\n return new ColumnBuilder({ ...this.meta, description });\n }\n}\n\nexport type AnyColumnBuilder = ColumnBuilder<any, boolean>;\n\nexport type TableColumns = Record<string, AnyColumnBuilder>;\n\nexport type AnyTableBuilder = TableBuilder<any, any, WriteOrigin>;\n\nexport type SyncSchemaTables = Record<string, AnyTableBuilder>;\n\nexport type TableOptions<\n BaseName extends string | undefined = string | undefined,\n Writes extends WriteOrigin = \"any\",\n> = {\n /** Override the materialized base table name (defaults to the crdt table name prefixed with \"_\"). */\n baseName?: BaseName;\n description?: string;\n /** Defaults to `\"read-write\"`. See {@link AiAccess}. */\n ai?: AiAccess;\n /** Defaults to `\"any\"`. See {@link WriteOrigin}. */\n writes?: Writes;\n /** Defaults to `\"include\"`. Ignored tables are omitted from export and skipped on import. */\n exportImport?: ExportImportMode;\n};\n\ntype Simplify<T> = { [K in keyof T]: T[K] } & {};\n\ntype ColumnValue<Column> = Column extends ColumnBuilder<infer Value, boolean> ? Value : never;\n\nexport type InferRow<Cols extends TableColumns> = Simplify<\n { id: string } & { [K in keyof Cols]: ColumnValue<Cols[K]> } & { tombstone?: boolean }\n>;\n\nexport type PayloadValidationResult = { success: true } | { success: false; errors: string[] };\n\nconst RESERVED_COLUMNS = [\"id\", \"tombstone\"] as const;\n\nconst idColumnMeta: ColumnMeta = {\n kind: \"text\",\n sqlType: \"text\",\n nullable: false,\n hasDefault: false,\n description: \"Unique immutable item id\",\n};\n\nconst tombstoneColumnMeta: ColumnMeta = {\n kind: \"boolean\",\n sqlType: \"integer\",\n nullable: false,\n hasDefault: true,\n defaultValue: false,\n description: \"Soft-delete marker\",\n};\n\nexport class TableBuilder<\n Cols extends TableColumns,\n BaseName extends string | undefined = undefined,\n Writes extends WriteOrigin = \"any\",\n> {\n declare readonly \"~baseName\": BaseName;\n declare readonly \"~writeOrigin\": Writes;\n\n /** All columns in DDL order, including the auto-injected `id` and `tombstone`. */\n readonly columns: Record<string, ColumnMeta>;\n readonly baseName: BaseName;\n readonly description: string | undefined;\n /** Resolved {@link AiAccess}; defaults to `\"read-write\"`. */\n readonly aiAccess: AiAccess;\n /** Resolved {@link WriteOrigin}; defaults to `\"any\"`. */\n readonly writeOrigin: Writes;\n /** Resolved {@link ExportImportMode}; defaults to `\"include\"`. */\n readonly exportImport: ExportImportMode;\n\n constructor(\n readonly userColumns: Cols,\n options?: TableOptions<BaseName, Writes>,\n ) {\n for (const reserved of RESERVED_COLUMNS) {\n if (reserved in userColumns) {\n throw new Error(`Column \"${reserved}\" is added automatically to every synced table and cannot be declared`);\n }\n }\n\n this.columns = {\n id: idColumnMeta,\n ...Object.fromEntries(Object.entries(userColumns).map(([name, column]) => [name, column.meta])),\n tombstone: tombstoneColumnMeta,\n };\n this.baseName = options?.baseName as BaseName;\n this.description = options?.description;\n this.aiAccess = options?.ai ?? \"read-write\";\n this.writeOrigin = (options?.writes ?? \"any\") as Writes;\n this.exportImport = options?.exportImport ?? \"include\";\n }\n\n describe(description: string): TableBuilder<Cols, BaseName, Writes> {\n return new TableBuilder<Cols, BaseName, Writes>(this.userColumns, {\n baseName: this.baseName,\n description,\n ai: this.aiAccess,\n writes: this.writeOrigin,\n exportImport: this.exportImport,\n });\n }\n\n /** Type-only: the row shape returned by queries. Do not access at runtime. */\n get $row(): InferRow<Cols> {\n return null as never;\n }\n\n /**\n * Validate a CRDT event payload against the declared columns.\n * `item-created` payloads must contain every column without a default (nullable columns may be omitted)\n * and their `tombstone` value is ignored, since applying a create always sets it to 0;\n * `item-updated` payloads are partial and must not touch `id` or set `tombstone` to a deleted value.\n */\n validatePayload(\n payload: Record<string, unknown>,\n options?: { event?: \"item-created\" | \"item-updated\" },\n ): PayloadValidationResult {\n const event = options?.event ?? \"item-created\";\n const errors: string[] = [];\n\n for (const key of Object.keys(payload)) {\n if (!Object.hasOwn(this.columns, key)) {\n errors.push(`Unknown column \"${key}\"`);\n }\n }\n\n if (event === \"item-updated\") {\n if (\"id\" in payload) {\n errors.push(`Column \"id\" is immutable and cannot appear in an update payload`);\n }\n if (payload.tombstone === true || payload.tombstone === 1) {\n errors.push(`Column \"tombstone\" cannot be set to true/1 in an update payload; use an item-deleted event`);\n }\n }\n\n if (event === \"item-created\") {\n for (const [name, meta] of Object.entries(this.columns)) {\n if (Object.hasOwn(payload, name) || name === \"tombstone\" || meta.nullable || meta.hasDefault) {\n continue;\n }\n errors.push(`Missing required column \"${name}\"`);\n }\n }\n\n for (const [name, value] of Object.entries(payload)) {\n const meta = Object.hasOwn(this.columns, name) ? this.columns[name] : undefined;\n if (!meta || (event === \"item-updated\" && name === \"id\") || (event === \"item-created\" && name === \"tombstone\")) {\n continue;\n }\n const error = validateValue(name, value, meta);\n if (error) {\n errors.push(error);\n }\n }\n\n return errors.length === 0 ? { success: true } : { success: false, errors };\n }\n}\n\nfunction describeValue(value: unknown): string {\n if (value === null) return \"null\";\n if (Array.isArray(value)) return \"array\";\n return typeof value;\n}\n\nfunction validateValue(name: string, value: unknown, meta: ColumnMeta): string | null {\n if (value === null) {\n return meta.nullable ? null : `Column \"${name}\" is not nullable, got null`;\n }\n\n switch (meta.kind) {\n case \"text\":\n return typeof value === \"string\" ? null : `Column \"${name}\" expects text, got ${describeValue(value)}`;\n case \"integer\":\n return typeof value === \"number\" && Number.isInteger(value)\n ? null\n : `Column \"${name}\" expects an integer, got ${describeValue(value)}`;\n case \"real\":\n return typeof value === \"number\" && Number.isFinite(value)\n ? null\n : `Column \"${name}\" expects a number, got ${describeValue(value)}`;\n case \"boolean\":\n return typeof value === \"boolean\" || value === 0 || value === 1\n ? null\n : `Column \"${name}\" expects a boolean (true/false or 0/1), got ${describeValue(value)}`;\n case \"enum\": {\n if (typeof value !== \"string\") {\n return `Column \"${name}\" expects one of ${formatEnumValues(meta)}, got ${describeValue(value)}`;\n }\n return meta.enumValues?.includes(value)\n ? null\n : `Column \"${name}\" expects one of ${formatEnumValues(meta)}, got \"${value}\"`;\n }\n }\n}\n\nfunction formatEnumValues(meta: ColumnMeta): string {\n return (meta.enumValues ?? []).map((value) => `\"${value}\"`).join(\" | \");\n}\n\nfunction column<Value>(kind: ColumnKind, sqlType: SqliteStorageType): ColumnBuilder<Value> {\n return new ColumnBuilder<Value>({ kind, sqlType, nullable: false, hasDefault: false });\n}\n\nexport const t = {\n text: () => column<string>(\"text\", \"text\"),\n integer: () => column<number>(\"integer\", \"integer\"),\n real: () => column<number>(\"real\", \"real\"),\n /** Stored as INTEGER 0/1; always bind booleans as 0/1 when writing raw SQL. */\n boolean: () => column<boolean>(\"boolean\", \"integer\"),\n /**\n * Union of string literals stored as TEXT, e.g. `t.enum([\"movie\", \"tv\"])`. Unlike `$type`, the\n * allowed values are kept as runtime metadata, so payloads are validated against them.\n * For an open-ended set, use `t.text().$type<\"idle\" | (string & {})>()` instead.\n */\n enum: <const Values extends readonly [string, ...string[]]>(values: Values) =>\n new ColumnBuilder<Values[number]>({\n kind: \"enum\",\n sqlType: \"text\",\n nullable: false,\n hasDefault: false,\n enumValues: values,\n }),\n table: <\n Cols extends TableColumns,\n const BaseName extends string | undefined = undefined,\n const Writes extends WriteOrigin = \"any\",\n >(\n columns: Cols,\n options?: TableOptions<BaseName, Writes>,\n ) => new TableBuilder(columns, options),\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 AnyCommitEventOptions<Database> = {\n [Table in keyof Database & string]: CommitEventOptions<Database, Table>;\n}[keyof Database & string];\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 type SnapshotOptions<Database, Table extends keyof Database & string> = {\n dataset: Table;\n id: string;\n patch: UpdateEventPayload<Database, Table>;\n};\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 applyEvents = (events: AnyCommitEventOptions<Database>[]) => {\n storage.applyOwnEvents(events.map(mapToStorageEvent));\n };\n\n const applyEvent = <Table extends keyof Database & string>(event: CommitEventOptions<Database, Table>) => {\n storage.applyOwnEvents([mapToStorageEvent(event)]);\n };\n\n const applySnapshot = <Table extends keyof Database & string>(snapshot: SnapshotOptions<Database, Table>) => {\n storage.applyOwnSnapshot({\n dataset: snapshot.dataset,\n item_id: snapshot.id,\n patch: { ...snapshot.patch },\n });\n };\n\n return {\n applyEvent,\n applyEvents,\n applySnapshot,\n };\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { $ as parametersAreEqual, $t as startPerformanceLogger, A as WorkerState, An as MigrationsDb, At as tryCatch, B as verifySyncSchemaWithDriver, Bn as CrdtUpdateLogItem, C as EventsPullRequest, Cn as TableBuilder, Ct as TypedEvent, Dn as t, Dt as generateId, E as createCrdtSyncRemoteSource, En as WriteOrigin, Et as createTypedEventTarget, F as PendingCrdtEvent, Fn as createStoredValue, Ft as createSQLiteKvStore, G as DefinedSyncSchema, H as NewCrdtEventValidationResult, Hn as PersistedCrdtEvent, Ht as QueryBuilderOutput, I as createCrdtApplyFunction, In as CRDT_EVENT_NO_OP_PAYLOAD, It as ExecuteParams, Jt as SqliteDriverRows, K as defineSyncSchema, Kt as SqliteDriver, L as createSQLiteCrdtApplyFunction, Ln as CrdtEventOrigin, Lt as ExecuteResult, M as CrdtStorageMutator, Mn as createMigrations, Mt as KvStoreItem, N as SnapshotOptions, Nn as createMigrator, O as WorkerConfig, On as MigratableEvent, Ot as jsonSafeParse, P as createCrdtStorageMutator, Pn as StoredValue, Pt as createKvStoreTableQuery, Q as SharedLiveQuerySnapshot, Qt as Logger, R as SchemaVerificationIssue, Rn as CrdtEventStatus, Sn as SyncSchemaTables, St as TypedBroadcastChannel, T as EventsPushResponse, Tn as TableOptions, Tt as createDeferredPromise, U as validateNewCrdtEvent, Un as isNoOpCrdtEventPayload, Ut as SQLiteDbWrapper, V as CrdtEventValidationError, Vn as CrdtUpdateLogPayload, Vt as PreparedStatement, W as DefineSyncSchemaConfig, Wn as dummyKysely, Wt as SQLiteTransactionWrapper, X as SQLiteReactiveDb, Xt as SqliteDriverValue, Y as admitClientEvents, Yt as SqliteDriverStatement, Z as SharedLiveQuery, Zt as LogLevel, _n as ColumnMeta, a as createSQLiteReactiveDb, an as HLCCounter, at as createImportData, b as makeCrdtTable, bn as PayloadValidationResult, bt as DeferredPromise, c as ResetStore, cn as serializeHLC, d as createSyncedDb, dn as SyncDbSchema, dt as createCrdtStorage, en as ColumnMetadata, et as xxhash, f as SyncedDbDatabase, fn as AiAccess, ft as SystemDbConfig, gn as ColumnKind, gt as applyWorkerDbSchema, h as UnsafeSyncedDbSqlExecutor, hn as ColumnBuilder, ht as applyMemoryDbSchema, i as verifySyncSchema, in as HLC, it as createExportData, j as createCrdtSyncProducer, jn as SyncDbMigrator, jt as tryCatchAsync, k as WorkerNotificationMessage, kn as Migrations, kt as quoteId, l as SyncedDb, ln as CrdtTableConfig, lt as OwnCrdtEvent, m as SyncedDbTransaction, mn as AnyTableBuilder, mt as SystemMigrationContext, n as createWasmSqliteDriver, nn as TableMetadata, nt as ImportDataResult, o as RESET_REQUEST_TTL_MS, on as compareHLC, p as SyncedDbSqlExecutor, pn as AnyColumnBuilder, pt as SystemMigration, q as AdmitClientEventsResult, qt as SqliteDriverHooks, r as loadSqliteWasm, rn as introspectDb, rt as SyncedDbExport, s as ResetRequest, sn as deserializeHLC, st as CrdtStorage, t as createWasmMemoryDriver, tn as DatabaseIntrospection, tt as ImportDataOptions, u as SyncedDbOptions, un as ReadonlyTable, ut as OwnCrdtSnapshot, vn as ExportImportMode, w as EventsPushRequest, wn as TableColumns, wt as TypedEventTarget, x as CrdtSyncRemoteSource, xn as SqliteStorageType, xt as DistributiveOmit, yn as InferRow, z as formatSchemaVerificationIssues, zn as CrdtEventType, zt as KyselyQueryFactory } from "./index-B3s_6aG6.js";
1
+ import { $ as parametersAreEqual, $t as startPerformanceLogger, A as WorkerState, An as MigrationsDb, At as tryCatch, B as verifySyncSchemaWithDriver, Bn as CrdtUpdateLogItem, C as EventsPullRequest, Cn as TableBuilder, Ct as TypedEvent, Dn as t, Dt as generateId, E as createCrdtSyncRemoteSource, En as WriteOrigin, Et as createTypedEventTarget, F as PendingCrdtEvent, Fn as createStoredValue, Ft as createSQLiteKvStore, G as DefinedSyncSchema, H as NewCrdtEventValidationResult, Hn as PersistedCrdtEvent, Ht as QueryBuilderOutput, I as createCrdtApplyFunction, In as CRDT_EVENT_NO_OP_PAYLOAD, It as ExecuteParams, Jt as SqliteDriverRows, K as defineSyncSchema, Kt as SqliteDriver, L as createSQLiteCrdtApplyFunction, Ln as CrdtEventOrigin, Lt as ExecuteResult, M as CrdtStorageMutator, Mn as createMigrations, Mt as KvStoreItem, N as SnapshotOptions, Nn as createMigrator, O as WorkerConfig, On as MigratableEvent, Ot as jsonSafeParse, P as createCrdtStorageMutator, Pn as StoredValue, Pt as createKvStoreTableQuery, Q as SharedLiveQuerySnapshot, Qt as Logger, R as SchemaVerificationIssue, Rn as CrdtEventStatus, Sn as SyncSchemaTables, St as TypedBroadcastChannel, T as EventsPushResponse, Tn as TableOptions, Tt as createDeferredPromise, U as validateNewCrdtEvent, Un as isNoOpCrdtEventPayload, Ut as SQLiteDbWrapper, V as CrdtEventValidationError, Vn as CrdtUpdateLogPayload, Vt as PreparedStatement, W as DefineSyncSchemaConfig, Wn as dummyKysely, Wt as SQLiteTransactionWrapper, X as SQLiteReactiveDb, Xt as SqliteDriverValue, Y as admitClientEvents, Yt as SqliteDriverStatement, Z as SharedLiveQuery, Zt as LogLevel, _n as ColumnMeta, a as createSQLiteReactiveDb, an as HLCCounter, at as createImportData, b as makeCrdtTable, bn as PayloadValidationResult, bt as DeferredPromise, c as ResetStore, cn as serializeHLC, d as createSyncedDb, dn as SyncDbSchema, dt as createCrdtStorage, en as ColumnMetadata, et as xxhash, f as SyncedDbDatabase, fn as AiAccess, ft as SystemDbConfig, gn as ColumnKind, gt as applyWorkerDbSchema, h as UnsafeSyncedDbSqlExecutor, hn as ColumnBuilder, ht as applyMemoryDbSchema, i as verifySyncSchema, in as HLC, it as createExportData, j as createCrdtSyncProducer, jn as SyncDbMigrator, jt as tryCatchAsync, k as WorkerNotificationMessage, kn as Migrations, kt as quoteId, l as SyncedDb, ln as CrdtTableConfig, lt as OwnCrdtEvent, m as SyncedDbTransaction, mn as AnyTableBuilder, mt as SystemMigrationContext, n as createWasmSqliteDriver, nn as TableMetadata, nt as ImportDataResult, o as RESET_REQUEST_TTL_MS, on as compareHLC, p as SyncedDbSqlExecutor, pn as AnyColumnBuilder, pt as SystemMigration, q as AdmitClientEventsResult, qt as SqliteDriverHooks, r as loadSqliteWasm, rn as introspectDb, rt as SyncedDbExport, s as ResetRequest, sn as deserializeHLC, st as CrdtStorage, t as createWasmMemoryDriver, tn as DatabaseIntrospection, tt as ImportDataOptions, u as SyncedDbOptions, un as ReadonlyTable, ut as OwnCrdtSnapshot, vn as ExportImportMode, w as EventsPushRequest, wn as TableColumns, wt as TypedEventTarget, x as CrdtSyncRemoteSource, xn as SqliteStorageType, xt as DistributiveOmit, yn as InferRow, z as formatSchemaVerificationIssues, zn as CrdtEventType, zt as KyselyQueryFactory } from "./index-ChmCuLQU.js";
2
2
  export { type AdmitClientEventsResult, type AiAccess, type AnyColumnBuilder, type AnyTableBuilder, CRDT_EVENT_NO_OP_PAYLOAD, ColumnBuilder, type ColumnKind, type ColumnMeta, type ColumnMetadata, type CrdtEventOrigin, type CrdtEventStatus, type CrdtEventType, CrdtEventValidationError, type CrdtStorage, type CrdtStorageMutator, type CrdtSyncRemoteSource, type CrdtTableConfig, type CrdtUpdateLogItem, type CrdtUpdateLogPayload, type DatabaseIntrospection, type DeferredPromise, type DefineSyncSchemaConfig, type DefinedSyncSchema, type DistributiveOmit, type EventsPullRequest, type EventsPushRequest, type EventsPushResponse, type ExecuteParams, type ExecuteResult, type ExportImportMode, type HLC, HLCCounter, type ImportDataOptions, type ImportDataResult, type InferRow, type KvStoreItem, type KyselyQueryFactory, type LogLevel, type Logger, type MigratableEvent, type Migrations, type MigrationsDb, type NewCrdtEventValidationResult, type OwnCrdtEvent, type OwnCrdtSnapshot, type PayloadValidationResult, type PendingCrdtEvent, type PersistedCrdtEvent, type PreparedStatement, type QueryBuilderOutput, RESET_REQUEST_TTL_MS, type ReadonlyTable, type ResetRequest, type ResetStore, SQLiteDbWrapper, SQLiteReactiveDb, type SQLiteTransactionWrapper, type SchemaVerificationIssue, type SharedLiveQuery, type SharedLiveQuerySnapshot, type SnapshotOptions, type SqliteDriver, type SqliteDriverHooks, type SqliteDriverRows, type SqliteDriverStatement, type SqliteDriverValue, type SqliteStorageType, type StoredValue, type SyncDbMigrator, type SyncDbSchema, type SyncSchemaTables, type SyncedDb, type SyncedDbDatabase, type SyncedDbExport, type SyncedDbOptions, type SyncedDbSqlExecutor, type SyncedDbTransaction, type SystemDbConfig, type SystemMigration, type SystemMigrationContext, TableBuilder, type TableColumns, type TableMetadata, type TableOptions, TypedBroadcastChannel, TypedEvent, type TypedEventTarget, type UnsafeSyncedDbSqlExecutor, type WorkerConfig, type WorkerNotificationMessage, type WorkerState, type WriteOrigin, admitClientEvents, applyMemoryDbSchema, applyWorkerDbSchema, compareHLC, createCrdtApplyFunction, createCrdtStorage, createCrdtStorageMutator, createCrdtSyncProducer, createCrdtSyncRemoteSource, createDeferredPromise, createExportData, createImportData, createKvStoreTableQuery, createMigrations, createMigrator, createSQLiteCrdtApplyFunction, createSQLiteKvStore, createSQLiteReactiveDb, createStoredValue, createSyncedDb, createTypedEventTarget, createWasmMemoryDriver, createWasmSqliteDriver, defineSyncSchema, deserializeHLC, dummyKysely, formatSchemaVerificationIssues, generateId, introspectDb, isNoOpCrdtEventPayload, jsonSafeParse, loadSqliteWasm, makeCrdtTable, parametersAreEqual, quoteId, serializeHLC, startPerformanceLogger, t, tryCatch, tryCatchAsync, validateNewCrdtEvent, verifySyncSchema, verifySyncSchemaWithDriver, xxhash };
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { b as introspectDb, c as memoryDbConfig, g as SQLiteDbWrapper, h as createStoredValue, i as applyWorkerDbSchema, m as createSQLiteKvStore, p as createKvStoreTableQuery, r as applyMemoryDbSchema, x as dummyKysely, y as startPerformanceLogger } from "./system-schema-uHQdQTCk.js";
2
2
  import { a as acquireLock, d as noop, h as tryCatchAsync, i as TypedEvent, l as generateId, m as tryCatch, n as isNoOpCrdtEventPayload, o as createDeferredPromise, p as quoteId, r as TypedBroadcastChannel, s as createTypedEventTarget, t as CRDT_EVENT_NO_OP_PAYLOAD, u as jsonSafeParse } from "./crdt-table-schema-D6Yf61Ex.js";
3
- import { a as formatSchemaVerificationIssues, c as createMigrator, i as createSQLiteCrdtApplyFunction, l as createExportData, n as createCrdtStorage, o as verifySyncSchemaWithDriver, r as createCrdtApplyFunction, s as createMigrations, t as createCrdtSyncProducer, u as createImportData } from "./crdt-sync-producer-DVEWad4t.js";
3
+ import { a as formatSchemaVerificationIssues, c as createMigrator, i as createSQLiteCrdtApplyFunction, l as createExportData, n as createCrdtStorage, o as verifySyncSchemaWithDriver, r as createCrdtApplyFunction, s as createMigrations, t as createCrdtSyncProducer, u as createImportData } from "./crdt-sync-producer-t2jHxO38.js";
4
4
  import { c as deserializeHLC, i as validateNewCrdtEvent, l as serializeHLC, o as HLCCounter, r as CrdtEventValidationError, s as compareHLC, t as createCrdtSyncRemoteSource, u as xxhash } from "./crdt-sync-remote-source-yeTEkOjH.js";
5
- import { n as parametersAreEqual, t as SQLiteReactiveDb } from "./sqlite-reactive-db-BwY3FoIy.js";
5
+ import { n as parametersAreEqual, t as SQLiteReactiveDb } from "./sqlite-reactive-db-C2BtEAeE.js";
6
6
  import { t as admitClientEvents } from "./admit-client-events-BDrJw4SK.js";
7
- import { a as defineSyncSchema, i as t, n as ColumnBuilder, r as TableBuilder, t as createCrdtStorageMutator } from "./index.common-DZM6WeOn.js";
8
- import { a as makeCrdtTable, o as registerCrdtIntentDrainer } from "./make-crdt-table-DYCXOYB7.js";
9
- import { _ as createWasmSqliteDriver, a as acquireReplicaLock, c as isWorkerErrorResponseMessage, f as isWorkerResponseMessage, g as createWasmMemoryDriver, h as verifySyncSchema, p as syncDbClientLockName, s as createBroadcastChannels, t as RESET_REQUEST_TTL_MS, u as isWorkerNotificationMessage, v as loadSqliteWasm } from "./reset-state-DiuE5Yuu.js";
7
+ import { a as defineSyncSchema, i as t, n as ColumnBuilder, r as TableBuilder, t as createCrdtStorageMutator } from "./index.common-B9n2FOmn.js";
8
+ import { a as makeCrdtTable, o as registerCrdtIntentDrainer } from "./make-crdt-table-Cu8WhRBk.js";
9
+ import { _ as createWasmSqliteDriver, a as acquireReplicaLock, c as isWorkerErrorResponseMessage, f as isWorkerResponseMessage, g as createWasmMemoryDriver, h as verifySyncSchema, p as syncDbClientLockName, s as createBroadcastChannels, t as RESET_REQUEST_TTL_MS, u as isWorkerNotificationMessage, v as loadSqliteWasm } from "./reset-state-Bz1sfbf3.js";
10
10
  import { n as getOrCreateSQLiteSyncDevtoolsRegistry, r as validateDbId, t as createSyncedDbDatabase } from "./synced-db-database-B5M7MrBD.js";
11
11
  //#region src/memory-db/wasm-reactive-db.ts
12
12
  async function createSQLiteReactiveDb(opts) {
@@ -1,2 +1,2 @@
1
- import { $ as parametersAreEqual, $t as startPerformanceLogger, A as WorkerState, An as MigrationsDb, At as tryCatch, B as verifySyncSchemaWithDriver, Bn as CrdtUpdateLogItem, C as EventsPullRequest, Cn as TableBuilder, Ct as TypedEvent, Dn as t, Dt as generateId, E as createCrdtSyncRemoteSource, En as WriteOrigin, Et as createTypedEventTarget, F as PendingCrdtEvent, Fn as createStoredValue, Ft as createSQLiteKvStore, G as DefinedSyncSchema, H as NewCrdtEventValidationResult, Hn as PersistedCrdtEvent, Ht as QueryBuilderOutput, I as createCrdtApplyFunction, In as CRDT_EVENT_NO_OP_PAYLOAD, It as ExecuteParams, Jt as SqliteDriverRows, K as defineSyncSchema, Kt as SqliteDriver, L as createSQLiteCrdtApplyFunction, Ln as CrdtEventOrigin, Lt as ExecuteResult, M as CrdtStorageMutator, Mn as createMigrations, Mt as KvStoreItem, N as SnapshotOptions, Nn as createMigrator, O as WorkerConfig, On as MigratableEvent, Ot as jsonSafeParse, P as createCrdtStorageMutator, Pn as StoredValue, Pt as createKvStoreTableQuery, Q as SharedLiveQuerySnapshot, Qt as Logger, R as SchemaVerificationIssue, Rn as CrdtEventStatus, Sn as SyncSchemaTables, St as TypedBroadcastChannel, T as EventsPushResponse, Tn as TableOptions, Tt as createDeferredPromise, U as validateNewCrdtEvent, Un as isNoOpCrdtEventPayload, Ut as SQLiteDbWrapper, V as CrdtEventValidationError, Vn as CrdtUpdateLogPayload, Vt as PreparedStatement, W as DefineSyncSchemaConfig, Wn as dummyKysely, Wt as SQLiteTransactionWrapper, X as SQLiteReactiveDb, Xt as SqliteDriverValue, Y as admitClientEvents, Yt as SqliteDriverStatement, Z as SharedLiveQuery, Zt as LogLevel, _n as ColumnMeta, an as HLCCounter, at as createImportData, b as makeCrdtTable, bn as PayloadValidationResult, bt as DeferredPromise, c as ResetStore, cn as serializeHLC, dn as SyncDbSchema, dt as createCrdtStorage, en as ColumnMetadata, et as xxhash, f as SyncedDbDatabase, fn as AiAccess, ft as SystemDbConfig, gn as ColumnKind, gt as applyWorkerDbSchema, h as UnsafeSyncedDbSqlExecutor, hn as ColumnBuilder, ht as applyMemoryDbSchema, in as HLC, it as createExportData, j as createCrdtSyncProducer, jn as SyncDbMigrator, jt as tryCatchAsync, k as WorkerNotificationMessage, kn as Migrations, kt as quoteId, l as SyncedDb, ln as CrdtTableConfig, lt as OwnCrdtEvent, m as SyncedDbTransaction, mn as AnyTableBuilder, mt as SystemMigrationContext, nn as TableMetadata, nt as ImportDataResult, on as compareHLC, p as SyncedDbSqlExecutor, pn as AnyColumnBuilder, pt as SystemMigration, q as AdmitClientEventsResult, qt as SqliteDriverHooks, rn as introspectDb, rt as SyncedDbExport, s as ResetRequest, sn as deserializeHLC, st as CrdtStorage, tn as DatabaseIntrospection, tt as ImportDataOptions, u as SyncedDbOptions, un as ReadonlyTable, ut as OwnCrdtSnapshot, vn as ExportImportMode, w as EventsPushRequest, wn as TableColumns, wt as TypedEventTarget, x as CrdtSyncRemoteSource, xn as SqliteStorageType, xt as DistributiveOmit, yn as InferRow, z as formatSchemaVerificationIssues, zn as CrdtEventType, zt as KyselyQueryFactory } from "./index-B3s_6aG6.js";
1
+ import { $ as parametersAreEqual, $t as startPerformanceLogger, A as WorkerState, An as MigrationsDb, At as tryCatch, B as verifySyncSchemaWithDriver, Bn as CrdtUpdateLogItem, C as EventsPullRequest, Cn as TableBuilder, Ct as TypedEvent, Dn as t, Dt as generateId, E as createCrdtSyncRemoteSource, En as WriteOrigin, Et as createTypedEventTarget, F as PendingCrdtEvent, Fn as createStoredValue, Ft as createSQLiteKvStore, G as DefinedSyncSchema, H as NewCrdtEventValidationResult, Hn as PersistedCrdtEvent, Ht as QueryBuilderOutput, I as createCrdtApplyFunction, In as CRDT_EVENT_NO_OP_PAYLOAD, It as ExecuteParams, Jt as SqliteDriverRows, K as defineSyncSchema, Kt as SqliteDriver, L as createSQLiteCrdtApplyFunction, Ln as CrdtEventOrigin, Lt as ExecuteResult, M as CrdtStorageMutator, Mn as createMigrations, Mt as KvStoreItem, N as SnapshotOptions, Nn as createMigrator, O as WorkerConfig, On as MigratableEvent, Ot as jsonSafeParse, P as createCrdtStorageMutator, Pn as StoredValue, Pt as createKvStoreTableQuery, Q as SharedLiveQuerySnapshot, Qt as Logger, R as SchemaVerificationIssue, Rn as CrdtEventStatus, Sn as SyncSchemaTables, St as TypedBroadcastChannel, T as EventsPushResponse, Tn as TableOptions, Tt as createDeferredPromise, U as validateNewCrdtEvent, Un as isNoOpCrdtEventPayload, Ut as SQLiteDbWrapper, V as CrdtEventValidationError, Vn as CrdtUpdateLogPayload, Vt as PreparedStatement, W as DefineSyncSchemaConfig, Wn as dummyKysely, Wt as SQLiteTransactionWrapper, X as SQLiteReactiveDb, Xt as SqliteDriverValue, Y as admitClientEvents, Yt as SqliteDriverStatement, Z as SharedLiveQuery, Zt as LogLevel, _n as ColumnMeta, an as HLCCounter, at as createImportData, b as makeCrdtTable, bn as PayloadValidationResult, bt as DeferredPromise, c as ResetStore, cn as serializeHLC, dn as SyncDbSchema, dt as createCrdtStorage, en as ColumnMetadata, et as xxhash, f as SyncedDbDatabase, fn as AiAccess, ft as SystemDbConfig, gn as ColumnKind, gt as applyWorkerDbSchema, h as UnsafeSyncedDbSqlExecutor, hn as ColumnBuilder, ht as applyMemoryDbSchema, in as HLC, it as createExportData, j as createCrdtSyncProducer, jn as SyncDbMigrator, jt as tryCatchAsync, k as WorkerNotificationMessage, kn as Migrations, kt as quoteId, l as SyncedDb, ln as CrdtTableConfig, lt as OwnCrdtEvent, m as SyncedDbTransaction, mn as AnyTableBuilder, mt as SystemMigrationContext, nn as TableMetadata, nt as ImportDataResult, on as compareHLC, p as SyncedDbSqlExecutor, pn as AnyColumnBuilder, pt as SystemMigration, q as AdmitClientEventsResult, qt as SqliteDriverHooks, rn as introspectDb, rt as SyncedDbExport, s as ResetRequest, sn as deserializeHLC, st as CrdtStorage, tn as DatabaseIntrospection, tt as ImportDataOptions, u as SyncedDbOptions, un as ReadonlyTable, ut as OwnCrdtSnapshot, vn as ExportImportMode, w as EventsPushRequest, wn as TableColumns, wt as TypedEventTarget, x as CrdtSyncRemoteSource, xn as SqliteStorageType, xt as DistributiveOmit, yn as InferRow, z as formatSchemaVerificationIssues, zn as CrdtEventType, zt as KyselyQueryFactory } from "./index-ChmCuLQU.js";
2
2
  export { type AdmitClientEventsResult, type AiAccess, type AnyColumnBuilder, type AnyTableBuilder, CRDT_EVENT_NO_OP_PAYLOAD, ColumnBuilder, type ColumnKind, type ColumnMeta, type ColumnMetadata, type CrdtEventOrigin, type CrdtEventStatus, type CrdtEventType, CrdtEventValidationError, type CrdtStorage, type CrdtStorageMutator, type CrdtSyncRemoteSource, type CrdtTableConfig, type CrdtUpdateLogItem, type CrdtUpdateLogPayload, type DatabaseIntrospection, type DeferredPromise, type DefineSyncSchemaConfig, type DefinedSyncSchema, type DistributiveOmit, type EventsPullRequest, type EventsPushRequest, type EventsPushResponse, type ExecuteParams, type ExecuteResult, type ExportImportMode, type HLC, HLCCounter, type ImportDataOptions, type ImportDataResult, type InferRow, type KvStoreItem, type KyselyQueryFactory, type LogLevel, type Logger, type MigratableEvent, type Migrations, type MigrationsDb, type NewCrdtEventValidationResult, type OwnCrdtEvent, type OwnCrdtSnapshot, type PayloadValidationResult, type PendingCrdtEvent, type PersistedCrdtEvent, type PreparedStatement, type QueryBuilderOutput, type ReadonlyTable, type ResetRequest, type ResetStore, SQLiteDbWrapper, SQLiteReactiveDb, type SQLiteTransactionWrapper, type SchemaVerificationIssue, type SharedLiveQuery, type SharedLiveQuerySnapshot, type SnapshotOptions, type SqliteDriver, type SqliteDriverHooks, type SqliteDriverRows, type SqliteDriverStatement, type SqliteDriverValue, type SqliteStorageType, type StoredValue, type SyncDbMigrator, type SyncDbSchema, type SyncSchemaTables, type SyncedDb, type SyncedDbDatabase, type SyncedDbExport, type SyncedDbOptions, type SyncedDbSqlExecutor, type SyncedDbTransaction, type SystemDbConfig, type SystemMigration, type SystemMigrationContext, TableBuilder, type TableColumns, type TableMetadata, type TableOptions, TypedBroadcastChannel, TypedEvent, type TypedEventTarget, type UnsafeSyncedDbSqlExecutor, type WorkerConfig, type WorkerNotificationMessage, type WorkerState, type WriteOrigin, admitClientEvents, applyMemoryDbSchema, applyWorkerDbSchema, compareHLC, createCrdtApplyFunction, createCrdtStorage, createCrdtStorageMutator, createCrdtSyncProducer, createCrdtSyncRemoteSource, createDeferredPromise, createExportData, createImportData, createKvStoreTableQuery, createMigrations, createMigrator, createSQLiteCrdtApplyFunction, createSQLiteKvStore, createStoredValue, createTypedEventTarget, defineSyncSchema, deserializeHLC, dummyKysely, formatSchemaVerificationIssues, generateId, introspectDb, isNoOpCrdtEventPayload, jsonSafeParse, makeCrdtTable, parametersAreEqual, quoteId, serializeHLC, startPerformanceLogger, t, tryCatch, tryCatchAsync, validateNewCrdtEvent, verifySyncSchemaWithDriver, xxhash };
@@ -1,9 +1,9 @@
1
1
  import { b as introspectDb, g as SQLiteDbWrapper, h as createStoredValue, i as applyWorkerDbSchema, m as createSQLiteKvStore, p as createKvStoreTableQuery, r as applyMemoryDbSchema, x as dummyKysely, y as startPerformanceLogger } from "./system-schema-uHQdQTCk.js";
2
2
  import { h as tryCatchAsync, i as TypedEvent, l as generateId, m as tryCatch, n as isNoOpCrdtEventPayload, o as createDeferredPromise, p as quoteId, r as TypedBroadcastChannel, s as createTypedEventTarget, t as CRDT_EVENT_NO_OP_PAYLOAD, u as jsonSafeParse } from "./crdt-table-schema-D6Yf61Ex.js";
3
- import { a as formatSchemaVerificationIssues, c as createMigrator, i as createSQLiteCrdtApplyFunction, l as createExportData, n as createCrdtStorage, o as verifySyncSchemaWithDriver, r as createCrdtApplyFunction, s as createMigrations, t as createCrdtSyncProducer, u as createImportData } from "./crdt-sync-producer-DVEWad4t.js";
3
+ import { a as formatSchemaVerificationIssues, c as createMigrator, i as createSQLiteCrdtApplyFunction, l as createExportData, n as createCrdtStorage, o as verifySyncSchemaWithDriver, r as createCrdtApplyFunction, s as createMigrations, t as createCrdtSyncProducer, u as createImportData } from "./crdt-sync-producer-t2jHxO38.js";
4
4
  import { c as deserializeHLC, i as validateNewCrdtEvent, l as serializeHLC, o as HLCCounter, r as CrdtEventValidationError, s as compareHLC, t as createCrdtSyncRemoteSource, u as xxhash } from "./crdt-sync-remote-source-yeTEkOjH.js";
5
- import { n as parametersAreEqual, t as SQLiteReactiveDb } from "./sqlite-reactive-db-BwY3FoIy.js";
5
+ import { n as parametersAreEqual, t as SQLiteReactiveDb } from "./sqlite-reactive-db-C2BtEAeE.js";
6
6
  import { t as admitClientEvents } from "./admit-client-events-BDrJw4SK.js";
7
- import { a as defineSyncSchema, i as t, n as ColumnBuilder, r as TableBuilder, t as createCrdtStorageMutator } from "./index.common-DZM6WeOn.js";
8
- import { a as makeCrdtTable } from "./make-crdt-table-DYCXOYB7.js";
7
+ import { a as defineSyncSchema, i as t, n as ColumnBuilder, r as TableBuilder, t as createCrdtStorageMutator } from "./index.common-B9n2FOmn.js";
8
+ import { a as makeCrdtTable } from "./make-crdt-table-Cu8WhRBk.js";
9
9
  export { CRDT_EVENT_NO_OP_PAYLOAD, ColumnBuilder, CrdtEventValidationError, HLCCounter, SQLiteDbWrapper, SQLiteReactiveDb, TableBuilder, TypedBroadcastChannel, TypedEvent, admitClientEvents, applyMemoryDbSchema, applyWorkerDbSchema, compareHLC, createCrdtApplyFunction, createCrdtStorage, createCrdtStorageMutator, createCrdtSyncProducer, createCrdtSyncRemoteSource, createDeferredPromise, createExportData, createImportData, createKvStoreTableQuery, createMigrations, createMigrator, createSQLiteCrdtApplyFunction, createSQLiteKvStore, createStoredValue, createTypedEventTarget, defineSyncSchema, deserializeHLC, dummyKysely, formatSchemaVerificationIssues, generateId, introspectDb, isNoOpCrdtEventPayload, jsonSafeParse, makeCrdtTable, parametersAreEqual, quoteId, serializeHLC, startPerformanceLogger, t, tryCatch, tryCatchAsync, validateNewCrdtEvent, verifySyncSchemaWithDriver, xxhash };