@sqlite-sync/core 0.13.3 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{crdt-sync-producer-t2jHxO38.js → crdt-sync-producer-BQkuzCBM.js} +2 -2
- package/dist/{crdt-sync-producer-t2jHxO38.js.map → crdt-sync-producer-BQkuzCBM.js.map} +1 -1
- package/dist/{index-B3s_6aG6.d.ts → index-BgkTUdlX.d.ts} +10 -4
- package/dist/{index.common-Dp8CNMk4.js → index.common-DIN0mZxR.js} +4 -4
- package/dist/{index.common-Dp8CNMk4.js.map → index.common-DIN0mZxR.js.map} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -6
- package/dist/index.native.d.ts +1 -1
- package/dist/index.native.js +5 -5
- package/dist/internal.d.ts +1 -1
- package/dist/internal.js +2 -2
- package/dist/local.d.ts +2 -2
- package/dist/local.js +4 -4
- package/dist/{make-crdt-table-DYCXOYB7.js → make-crdt-table-Cu8WhRBk.js} +3 -3
- package/dist/{make-crdt-table-DYCXOYB7.js.map → make-crdt-table-Cu8WhRBk.js.map} +1 -1
- package/dist/{reset-state-Bz1sfbf3.js → reset-state-DAPyJglN.js} +2 -2
- package/dist/{reset-state-Bz1sfbf3.js.map → reset-state-DAPyJglN.js.map} +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/{sqlite-reactive-db-BwY3FoIy.js → sqlite-reactive-db-DLTvpGzO.js} +92 -18
- package/dist/sqlite-reactive-db-DLTvpGzO.js.map +1 -0
- package/dist/{system-schema-uHQdQTCk.js → system-schema-B8hbFl7o.js} +6 -4
- package/dist/system-schema-B8hbFl7o.js.map +1 -0
- package/dist/worker.d.ts +2 -2
- package/dist/worker.js +3 -3
- package/dist/{ws-remote-source-Dgd9dmMl.d.ts → ws-remote-source-BJFkwEyQ.d.ts} +2 -2
- package/package.json +1 -1
- package/dist/sqlite-reactive-db-BwY3FoIy.js.map +0 -1
- package/dist/system-schema-uHQdQTCk.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.common-Dp8CNMk4.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-DIN0mZxR.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-
|
|
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-BgkTUdlX.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
|
-
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-
|
|
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-B8hbFl7o.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-
|
|
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-BQkuzCBM.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-
|
|
5
|
+
import { n as parametersAreEqual, t as SQLiteReactiveDb } from "./sqlite-reactive-db-DLTvpGzO.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-
|
|
8
|
-
import { a as makeCrdtTable, o as registerCrdtIntentDrainer } from "./make-crdt-table-
|
|
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-
|
|
7
|
+
import { a as defineSyncSchema, i as t, n as ColumnBuilder, r as TableBuilder, t as createCrdtStorageMutator } from "./index.common-DIN0mZxR.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-DAPyJglN.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) {
|
package/dist/index.native.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, 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-
|
|
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-BgkTUdlX.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 };
|
package/dist/index.native.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
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-
|
|
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-B8hbFl7o.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-
|
|
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-BQkuzCBM.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-
|
|
5
|
+
import { n as parametersAreEqual, t as SQLiteReactiveDb } from "./sqlite-reactive-db-DLTvpGzO.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-
|
|
8
|
-
import { a as makeCrdtTable } from "./make-crdt-table-
|
|
7
|
+
import { a as defineSyncSchema, i as t, n as ColumnBuilder, r as TableBuilder, t as createCrdtStorageMutator } from "./index.common-DIN0mZxR.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 };
|
package/dist/internal.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Bt as KyselyStatementFactory, Gt as compileKyselyStatement, Nt as STATE_HASH_KV_KEY, Rt as InternalSQLiteWrapper, _ as crdtViewColumnsFromTable, _t as baseSystemMigrations, g as CRDT_CHANGE_INTENTS_TABLE, ot as CrdtChangeIntent, v as createCrdtViewStatements, vt as createSystemDbConfig, y as drainCrdtChangeIntents, yt as runSystemMigrations } from "./index-
|
|
1
|
+
import { Bt as KyselyStatementFactory, Gt as compileKyselyStatement, Nt as STATE_HASH_KV_KEY, Rt as InternalSQLiteWrapper, _ as crdtViewColumnsFromTable, _t as baseSystemMigrations, g as CRDT_CHANGE_INTENTS_TABLE, ot as CrdtChangeIntent, v as createCrdtViewStatements, vt as createSystemDbConfig, y as drainCrdtChangeIntents, yt as runSystemMigrations } from "./index-BgkTUdlX.js";
|
|
2
2
|
export { CRDT_CHANGE_INTENTS_TABLE, type CrdtChangeIntent, type InternalSQLiteWrapper, type KyselyStatementFactory, STATE_HASH_KV_KEY, baseSystemMigrations, compileKyselyStatement, crdtViewColumnsFromTable, createCrdtViewStatements, createSystemDbConfig, drainCrdtChangeIntents, runSystemMigrations };
|
package/dist/internal.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { _ as compileKyselyStatement, a as baseSystemMigrations, d as STATE_HASH_KV_KEY, l as runSystemMigrations, o as createSystemDbConfig } from "./system-schema-
|
|
2
|
-
import { i as drainCrdtChangeIntents, n as crdtViewColumnsFromTable, r as createCrdtViewStatements, t as CRDT_CHANGE_INTENTS_TABLE } from "./make-crdt-table-
|
|
1
|
+
import { _ as compileKyselyStatement, a as baseSystemMigrations, d as STATE_HASH_KV_KEY, l as runSystemMigrations, o as createSystemDbConfig } from "./system-schema-B8hbFl7o.js";
|
|
2
|
+
import { i as drainCrdtChangeIntents, n as crdtViewColumnsFromTable, r as createCrdtViewStatements, t as CRDT_CHANGE_INTENTS_TABLE } from "./make-crdt-table-Cu8WhRBk.js";
|
|
3
3
|
export { CRDT_CHANGE_INTENTS_TABLE, STATE_HASH_KV_KEY, baseSystemMigrations, compileKyselyStatement, crdtViewColumnsFromTable, createCrdtViewStatements, createSystemDbConfig, drainCrdtChangeIntents, runSystemMigrations };
|
package/dist/local.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as EventsPullRequest, Jt as SqliteDriverRows, Kt as SqliteDriver, Qt as Logger, S as CreateRemoteSourceFactory, T as EventsPushResponse, Xt as SqliteDriverValue, Yt as SqliteDriverStatement, dn as SyncDbSchema, l as SyncedDb, qt as SqliteDriverHooks, w as EventsPushRequest } from "./index-
|
|
2
|
-
import { t as createWsRemoteSource } from "./ws-remote-source-
|
|
1
|
+
import { C as EventsPullRequest, Jt as SqliteDriverRows, Kt as SqliteDriver, Qt as Logger, S as CreateRemoteSourceFactory, T as EventsPushResponse, Xt as SqliteDriverValue, Yt as SqliteDriverStatement, dn as SyncDbSchema, l as SyncedDb, qt as SqliteDriverHooks, w as EventsPushRequest } from "./index-BgkTUdlX.js";
|
|
2
|
+
import { t as createWsRemoteSource } from "./ws-remote-source-BJFkwEyQ.js";
|
|
3
3
|
//#region src/local/local-synced-db.d.ts
|
|
4
4
|
type LocalSyncedDbOptions<Database> = {
|
|
5
5
|
dbId: string;
|
package/dist/local.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { f as createKvStateHashStore, m as createSQLiteKvStore, n as applyLocalDbSchema, p as createKvStoreTableQuery, s as localDbConfig, t as LOCAL_KV_TABLE_NAME } from "./system-schema-
|
|
1
|
+
import { f as createKvStateHashStore, m as createSQLiteKvStore, n as applyLocalDbSchema, p as createKvStoreTableQuery, s as localDbConfig, t as LOCAL_KV_TABLE_NAME } from "./system-schema-B8hbFl7o.js";
|
|
2
2
|
import { l as generateId, s as createTypedEventTarget } from "./crdt-table-schema-D6Yf61Ex.js";
|
|
3
|
-
import { a as formatSchemaVerificationIssues, c as createMigrator, l as createExportData, n as createCrdtStorage, o as verifySyncSchemaWithDriver, t as createCrdtSyncProducer, u as createImportData } from "./crdt-sync-producer-
|
|
3
|
+
import { a as formatSchemaVerificationIssues, c as createMigrator, l as createExportData, n as createCrdtStorage, o as verifySyncSchemaWithDriver, t as createCrdtSyncProducer, u as createImportData } from "./crdt-sync-producer-BQkuzCBM.js";
|
|
4
4
|
import { o as HLCCounter, t as createCrdtSyncRemoteSource, u as xxhash } from "./crdt-sync-remote-source-yeTEkOjH.js";
|
|
5
|
-
import { t as SQLiteReactiveDb } from "./sqlite-reactive-db-
|
|
6
|
-
import { a as makeCrdtTable, o as registerCrdtIntentDrainer } from "./make-crdt-table-
|
|
5
|
+
import { t as SQLiteReactiveDb } from "./sqlite-reactive-db-DLTvpGzO.js";
|
|
6
|
+
import { a as makeCrdtTable, o as registerCrdtIntentDrainer } from "./make-crdt-table-Cu8WhRBk.js";
|
|
7
7
|
import { n as getOrCreateSQLiteSyncDevtoolsRegistry, r as validateDbId, t as createSyncedDbDatabase } from "./synced-db-database-B5M7MrBD.js";
|
|
8
8
|
import { i as runWorkerEventLogGc, r as formatStorageVersion, t as createWsRemoteSource } from "./ws-remote-source-BbPWrHB6.js";
|
|
9
9
|
//#region src/local/local-synced-db.ts
|
|
@@ -121,12 +121,12 @@ function registerCrdtIntentDrainer({ reactiveDb, storage }) {
|
|
|
121
121
|
processedIntentMutationVersion = reactiveDb.getTableMutationVersion(CRDT_CHANGE_INTENTS_TABLE);
|
|
122
122
|
}
|
|
123
123
|
});
|
|
124
|
-
reactiveDb.
|
|
124
|
+
reactiveDb.afterCommit = () => {
|
|
125
125
|
if (eventApplied) {
|
|
126
126
|
eventApplied = false;
|
|
127
127
|
storage.internal.processEnqueuedEvents();
|
|
128
128
|
}
|
|
129
|
-
}
|
|
129
|
+
};
|
|
130
130
|
}
|
|
131
131
|
function drainCrdtChangeIntents({ tx, storage }) {
|
|
132
132
|
const intents = tx.executePreparedRaw({
|
|
@@ -141,4 +141,4 @@ function drainCrdtChangeIntents({ tx, storage }) {
|
|
|
141
141
|
//#endregion
|
|
142
142
|
export { makeCrdtTable as a, drainCrdtChangeIntents as i, crdtViewColumnsFromTable as n, registerCrdtIntentDrainer as o, createCrdtViewStatements as r, CRDT_CHANGE_INTENTS_TABLE as t };
|
|
143
143
|
|
|
144
|
-
//# sourceMappingURL=make-crdt-table-
|
|
144
|
+
//# sourceMappingURL=make-crdt-table-Cu8WhRBk.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"make-crdt-table-DYCXOYB7.js","names":[],"sources":["../src/sqlite-crdt/make-crdt-table.ts"],"sourcesContent":["import type { SQLiteReactiveDb } from \"../memory-db/sqlite-reactive-db\";\nimport type { AnyTableBuilder } from \"../schema/table-builder\";\nimport type { InternalSQLiteTransactionWrapper, SQLiteDbWrapper } from \"../sqlite-db-wrapper\";\nimport { quoteId } from \"../utils\";\nimport type { CrdtChangeIntent, InternalCrdtStorage } from \"./crdt-storage\";\n\nexport const CRDT_CHANGE_INTENTS_TABLE = \"crdt_change_intents\";\n\nexport function makeCrdtTable({\n db,\n baseTableName,\n crdtTableName,\n temp,\n}: {\n db: SQLiteDbWrapper<any>;\n baseTableName: string;\n crdtTableName: string;\n temp?: boolean;\n}) {\n const tableSchema = db.dbSchema[baseTableName];\n\n if (!tableSchema) {\n throw new Error(`Table ${baseTableName} not found`);\n }\n\n const columns = new Map(tableSchema.columns.map((column) => [column.name, column]));\n\n const idColumn = columns.get(\"id\");\n if (!idColumn) {\n throw new Error(\n `Table \"${baseTableName}\" is missing a required \"id\" column. CRDT tables must have an \"id\" column to identify items.`,\n );\n }\n if (idColumn.dataType.toUpperCase() !== \"TEXT\") {\n throw new Error(\n `Table \"${baseTableName}\": \"id\" column must be of type TEXT, got \"${idColumn.dataType}\". CRDT item IDs are stored as strings.`,\n );\n }\n\n const tombstoneColumn = columns.get(\"tombstone\");\n if (!tombstoneColumn) {\n throw new Error(\n `Table \"${baseTableName}\" is missing a required \"tombstone\" column. CRDT tables must have a \"tombstone\" INTEGER column for soft deletes.`,\n );\n }\n const tombstoneType = tombstoneColumn.dataType.toUpperCase();\n if (tombstoneType !== \"INTEGER\" && tombstoneType !== \"BOOLEAN\") {\n throw new Error(\n `Table \"${baseTableName}\": \"tombstone\" column must be of type INTEGER or BOOLEAN, got \"${tombstoneColumn.dataType}\". It is compared as 0/1 for soft deletes.`,\n );\n }\n\n for (const sql of createCrdtViewStatements({\n baseTableName,\n crdtTableName,\n columns: tableSchema.columns.map((column) => ({ name: column.name, nullable: column.isNullable })),\n temp,\n })) {\n db.execute(sql, { loggerLevel: \"system\" });\n }\n}\n\n// Workerd caps expr depth at 100; a left-deep `||` chain fails around 34 columns.\nfunction concatSql(parts: readonly string[]): string {\n if (parts.length === 0) {\n return \"''\";\n }\n if (parts.length === 1) {\n return parts[0];\n }\n const mid = parts.length >> 1;\n return `(${concatSql(parts.slice(0, mid))})||(${concatSql(parts.slice(mid))})`;\n}\n\nfunction sqlStringLiteral(value: string) {\n return `'${value.replaceAll(\"'\", \"''\")}'`;\n}\n\nexport type CrdtViewColumn = {\n name: string;\n nullable: boolean;\n};\n\nexport function crdtViewColumnsFromTable(table: AnyTableBuilder): CrdtViewColumn[] {\n return Object.entries(table.columns).map(([name, meta]) => ({ name, nullable: meta.nullable }));\n}\n\n// Columns omitted from an insert are NULL in an INSTEAD OF trigger. NULLs of NOT NULL columns are\n// left out of the payload so applying it falls back to the table DEFAULT on every replica.\n// The tombstone is left out: applying a create always sets it to 0.\nfunction createdPayloadSql(columns: CrdtViewColumn[]) {\n const fields = columns\n .filter((column) => column.name !== \"tombstone\")\n .map((column) => {\n const quoted = quoteId(column.name);\n const field = `${sqlStringLiteral(`${JSON.stringify(column.name)}:`)}||json_quote(new.${quoted})||','`;\n return column.nullable ? field : `case when new.${quoted} is null then '' else ${field} end`;\n });\n return concatSql([\"'{'\", `rtrim(${concatSql(fields)}, ',')`, \"'}'\"]);\n}\n\nfunction sparseUpdatePayloadSql(columnNames: string[]) {\n const changedFields = columnNames\n .filter((columnName) => columnName !== \"id\")\n .map((columnName) => {\n const quoted = quoteId(columnName);\n const key = sqlStringLiteral(`${JSON.stringify(columnName)}:`);\n return `case when old.${quoted} collate binary is not new.${quoted} then ${key}||json_quote(new.${quoted})||',' else '' end`;\n });\n return concatSql([\"'{'\", `rtrim(${concatSql(changedFields)}, ',')`, \"'}'\"]);\n}\n\nexport function createCrdtViewStatements({\n baseTableName,\n crdtTableName,\n columns,\n temp = false,\n}: {\n baseTableName: string;\n crdtTableName: string;\n columns: CrdtViewColumn[];\n /**\n * Create the view, its triggers and the intents table in the connection's temp schema,\n * so a persisted database never stores them and they always match the current schema.\n */\n temp?: boolean;\n}) {\n const createdPayload = createdPayloadSql(columns);\n const updatePayload = sparseUpdatePayloadSql(columns.map((column) => column.name));\n const tempKeyword = temp ? \"temp \" : \"\";\n\n return [\n `create ${tempKeyword}table if not exists ${quoteId(CRDT_CHANGE_INTENTS_TABLE)} (\n \"seq\" integer primary key,\n \"dataset\" text not null,\n \"type\" text not null,\n \"item_id\" text not null,\n \"new_item_id\" text,\n \"payload_json\" text not null\n)`,\n `create ${tempKeyword}view ${quoteId(crdtTableName)} as\nselect * from ${quoteId(baseTableName)}\nwhere tombstone = 0`,\n `create ${tempKeyword}trigger ${quoteId(`${crdtTableName}_created`)}\ninstead of insert on ${quoteId(crdtTableName)}\nfor each row\nbegin\n insert into ${quoteId(CRDT_CHANGE_INTENTS_TABLE)} (\n \"dataset\", \"type\", \"item_id\", \"new_item_id\", \"payload_json\"\n ) values (\n ${sqlStringLiteral(baseTableName)}, 'item-created', new.\"id\", null, ${createdPayload}\n );\nend`,\n `create ${tempKeyword}trigger ${quoteId(`${crdtTableName}_updated`)}\ninstead of update on ${quoteId(crdtTableName)}\nfor each row\nbegin\n insert into ${quoteId(CRDT_CHANGE_INTENTS_TABLE)} (\n \"dataset\", \"type\", \"item_id\", \"new_item_id\", \"payload_json\"\n ) values (\n ${sqlStringLiteral(baseTableName)}, 'item-updated', old.\"id\", new.\"id\", ${updatePayload}\n );\nend`,\n `create ${tempKeyword}trigger ${quoteId(`${crdtTableName}_deleted`)}\ninstead of delete on ${quoteId(crdtTableName)}\nfor each row\nwhen old.\"tombstone\" = 0\nbegin\n insert into ${quoteId(CRDT_CHANGE_INTENTS_TABLE)} (\n \"dataset\", \"type\", \"item_id\", \"new_item_id\", \"payload_json\"\n ) values (\n ${sqlStringLiteral(baseTableName)}, 'item-deleted', old.\"id\", null, '{}'\n );\nend`,\n ];\n}\n\nexport function registerCrdtIntentDrainer({\n reactiveDb,\n storage,\n}: {\n reactiveDb: SQLiteReactiveDb<any>;\n storage: InternalCrdtStorage;\n}) {\n let eventApplied = false;\n let processedIntentMutationVersion = reactiveDb.getTableMutationVersion(CRDT_CHANGE_INTENTS_TABLE);\n\n reactiveDb.db.setAfterMutatingStatement((tx) => {\n if (\n reactiveDb.hasSynchronousHooks &&\n reactiveDb.getTableMutationVersion(CRDT_CHANGE_INTENTS_TABLE) === processedIntentMutationVersion\n ) {\n return;\n }\n\n try {\n if (drainCrdtChangeIntents({ tx, storage })) {\n eventApplied = true;\n }\n } finally {\n processedIntentMutationVersion = reactiveDb.getTableMutationVersion(CRDT_CHANGE_INTENTS_TABLE);\n }\n });\n\n // A rolled-back drain leaves `eventApplied` set on purpose: with asynchronous hooks the\n // rollback can be delivered after a later transaction drained again, and clearing the flag\n // then would strand that transaction's events. Processing with nothing pending is a no-op.\n reactiveDb.addEventListener(\"transaction-committed\", () => {\n if (eventApplied) {\n eventApplied = false;\n void storage.internal.processEnqueuedEvents();\n }\n });\n}\n\nexport function drainCrdtChangeIntents({\n tx,\n storage,\n}: {\n tx: InternalSQLiteTransactionWrapper<any>;\n storage: InternalCrdtStorage;\n}) {\n const intents = tx.executePreparedRaw<[], CrdtChangeIntent>({\n key: \"drain-crdt-change-intents\",\n sql: `delete from ${quoteId(CRDT_CHANGE_INTENTS_TABLE)} returning *`,\n meta: { loggerLevel: \"system\" },\n });\n intents.sort((a, b) => a.seq - b.seq);\n\n const { appliedEvents } = storage.internal.applyOwnIntentsFromTransaction(tx, intents);\n return appliedEvents > 0;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"make-crdt-table-Cu8WhRBk.js","names":[],"sources":["../src/sqlite-crdt/make-crdt-table.ts"],"sourcesContent":["import type { SQLiteReactiveDb } from \"../memory-db/sqlite-reactive-db\";\nimport type { AnyTableBuilder } from \"../schema/table-builder\";\nimport type { InternalSQLiteTransactionWrapper, SQLiteDbWrapper } from \"../sqlite-db-wrapper\";\nimport { quoteId } from \"../utils\";\nimport type { CrdtChangeIntent, InternalCrdtStorage } from \"./crdt-storage\";\n\nexport const CRDT_CHANGE_INTENTS_TABLE = \"crdt_change_intents\";\n\nexport function makeCrdtTable({\n db,\n baseTableName,\n crdtTableName,\n temp,\n}: {\n db: SQLiteDbWrapper<any>;\n baseTableName: string;\n crdtTableName: string;\n temp?: boolean;\n}) {\n const tableSchema = db.dbSchema[baseTableName];\n\n if (!tableSchema) {\n throw new Error(`Table ${baseTableName} not found`);\n }\n\n const columns = new Map(tableSchema.columns.map((column) => [column.name, column]));\n\n const idColumn = columns.get(\"id\");\n if (!idColumn) {\n throw new Error(\n `Table \"${baseTableName}\" is missing a required \"id\" column. CRDT tables must have an \"id\" column to identify items.`,\n );\n }\n if (idColumn.dataType.toUpperCase() !== \"TEXT\") {\n throw new Error(\n `Table \"${baseTableName}\": \"id\" column must be of type TEXT, got \"${idColumn.dataType}\". CRDT item IDs are stored as strings.`,\n );\n }\n\n const tombstoneColumn = columns.get(\"tombstone\");\n if (!tombstoneColumn) {\n throw new Error(\n `Table \"${baseTableName}\" is missing a required \"tombstone\" column. CRDT tables must have a \"tombstone\" INTEGER column for soft deletes.`,\n );\n }\n const tombstoneType = tombstoneColumn.dataType.toUpperCase();\n if (tombstoneType !== \"INTEGER\" && tombstoneType !== \"BOOLEAN\") {\n throw new Error(\n `Table \"${baseTableName}\": \"tombstone\" column must be of type INTEGER or BOOLEAN, got \"${tombstoneColumn.dataType}\". It is compared as 0/1 for soft deletes.`,\n );\n }\n\n for (const sql of createCrdtViewStatements({\n baseTableName,\n crdtTableName,\n columns: tableSchema.columns.map((column) => ({ name: column.name, nullable: column.isNullable })),\n temp,\n })) {\n db.execute(sql, { loggerLevel: \"system\" });\n }\n}\n\n// Workerd caps expr depth at 100; a left-deep `||` chain fails around 34 columns.\nfunction concatSql(parts: readonly string[]): string {\n if (parts.length === 0) {\n return \"''\";\n }\n if (parts.length === 1) {\n return parts[0];\n }\n const mid = parts.length >> 1;\n return `(${concatSql(parts.slice(0, mid))})||(${concatSql(parts.slice(mid))})`;\n}\n\nfunction sqlStringLiteral(value: string) {\n return `'${value.replaceAll(\"'\", \"''\")}'`;\n}\n\nexport type CrdtViewColumn = {\n name: string;\n nullable: boolean;\n};\n\nexport function crdtViewColumnsFromTable(table: AnyTableBuilder): CrdtViewColumn[] {\n return Object.entries(table.columns).map(([name, meta]) => ({ name, nullable: meta.nullable }));\n}\n\n// Columns omitted from an insert are NULL in an INSTEAD OF trigger. NULLs of NOT NULL columns are\n// left out of the payload so applying it falls back to the table DEFAULT on every replica.\n// The tombstone is left out: applying a create always sets it to 0.\nfunction createdPayloadSql(columns: CrdtViewColumn[]) {\n const fields = columns\n .filter((column) => column.name !== \"tombstone\")\n .map((column) => {\n const quoted = quoteId(column.name);\n const field = `${sqlStringLiteral(`${JSON.stringify(column.name)}:`)}||json_quote(new.${quoted})||','`;\n return column.nullable ? field : `case when new.${quoted} is null then '' else ${field} end`;\n });\n return concatSql([\"'{'\", `rtrim(${concatSql(fields)}, ',')`, \"'}'\"]);\n}\n\nfunction sparseUpdatePayloadSql(columnNames: string[]) {\n const changedFields = columnNames\n .filter((columnName) => columnName !== \"id\")\n .map((columnName) => {\n const quoted = quoteId(columnName);\n const key = sqlStringLiteral(`${JSON.stringify(columnName)}:`);\n return `case when old.${quoted} collate binary is not new.${quoted} then ${key}||json_quote(new.${quoted})||',' else '' end`;\n });\n return concatSql([\"'{'\", `rtrim(${concatSql(changedFields)}, ',')`, \"'}'\"]);\n}\n\nexport function createCrdtViewStatements({\n baseTableName,\n crdtTableName,\n columns,\n temp = false,\n}: {\n baseTableName: string;\n crdtTableName: string;\n columns: CrdtViewColumn[];\n /**\n * Create the view, its triggers and the intents table in the connection's temp schema,\n * so a persisted database never stores them and they always match the current schema.\n */\n temp?: boolean;\n}) {\n const createdPayload = createdPayloadSql(columns);\n const updatePayload = sparseUpdatePayloadSql(columns.map((column) => column.name));\n const tempKeyword = temp ? \"temp \" : \"\";\n\n return [\n `create ${tempKeyword}table if not exists ${quoteId(CRDT_CHANGE_INTENTS_TABLE)} (\n \"seq\" integer primary key,\n \"dataset\" text not null,\n \"type\" text not null,\n \"item_id\" text not null,\n \"new_item_id\" text,\n \"payload_json\" text not null\n)`,\n `create ${tempKeyword}view ${quoteId(crdtTableName)} as\nselect * from ${quoteId(baseTableName)}\nwhere tombstone = 0`,\n `create ${tempKeyword}trigger ${quoteId(`${crdtTableName}_created`)}\ninstead of insert on ${quoteId(crdtTableName)}\nfor each row\nbegin\n insert into ${quoteId(CRDT_CHANGE_INTENTS_TABLE)} (\n \"dataset\", \"type\", \"item_id\", \"new_item_id\", \"payload_json\"\n ) values (\n ${sqlStringLiteral(baseTableName)}, 'item-created', new.\"id\", null, ${createdPayload}\n );\nend`,\n `create ${tempKeyword}trigger ${quoteId(`${crdtTableName}_updated`)}\ninstead of update on ${quoteId(crdtTableName)}\nfor each row\nbegin\n insert into ${quoteId(CRDT_CHANGE_INTENTS_TABLE)} (\n \"dataset\", \"type\", \"item_id\", \"new_item_id\", \"payload_json\"\n ) values (\n ${sqlStringLiteral(baseTableName)}, 'item-updated', old.\"id\", new.\"id\", ${updatePayload}\n );\nend`,\n `create ${tempKeyword}trigger ${quoteId(`${crdtTableName}_deleted`)}\ninstead of delete on ${quoteId(crdtTableName)}\nfor each row\nwhen old.\"tombstone\" = 0\nbegin\n insert into ${quoteId(CRDT_CHANGE_INTENTS_TABLE)} (\n \"dataset\", \"type\", \"item_id\", \"new_item_id\", \"payload_json\"\n ) values (\n ${sqlStringLiteral(baseTableName)}, 'item-deleted', old.\"id\", null, '{}'\n );\nend`,\n ];\n}\n\nexport function registerCrdtIntentDrainer({\n reactiveDb,\n storage,\n}: {\n reactiveDb: SQLiteReactiveDb<any>;\n storage: InternalCrdtStorage;\n}) {\n let eventApplied = false;\n let processedIntentMutationVersion = reactiveDb.getTableMutationVersion(CRDT_CHANGE_INTENTS_TABLE);\n\n reactiveDb.db.setAfterMutatingStatement((tx) => {\n if (\n reactiveDb.hasSynchronousHooks &&\n reactiveDb.getTableMutationVersion(CRDT_CHANGE_INTENTS_TABLE) === processedIntentMutationVersion\n ) {\n return;\n }\n\n try {\n if (drainCrdtChangeIntents({ tx, storage })) {\n eventApplied = true;\n }\n } finally {\n processedIntentMutationVersion = reactiveDb.getTableMutationVersion(CRDT_CHANGE_INTENTS_TABLE);\n }\n });\n\n // A rolled-back drain leaves `eventApplied` set on purpose: with asynchronous hooks the\n // rollback can be delivered after a later transaction drained again, and clearing the flag\n // then would strand that transaction's events. Processing with nothing pending is a no-op.\n reactiveDb.afterCommit = () => {\n if (eventApplied) {\n eventApplied = false;\n void storage.internal.processEnqueuedEvents();\n }\n };\n}\n\nexport function drainCrdtChangeIntents({\n tx,\n storage,\n}: {\n tx: InternalSQLiteTransactionWrapper<any>;\n storage: InternalCrdtStorage;\n}) {\n const intents = tx.executePreparedRaw<[], CrdtChangeIntent>({\n key: \"drain-crdt-change-intents\",\n sql: `delete from ${quoteId(CRDT_CHANGE_INTENTS_TABLE)} returning *`,\n meta: { loggerLevel: \"system\" },\n });\n intents.sort((a, b) => a.seq - b.seq);\n\n const { appliedEvents } = storage.internal.applyOwnIntentsFromTransaction(tx, intents);\n return appliedEvents > 0;\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as acquireLock, l as generateId, r as TypedBroadcastChannel } from "./crdt-table-schema-D6Yf61Ex.js";
|
|
2
|
-
import { o as verifySyncSchemaWithDriver } from "./crdt-sync-producer-
|
|
2
|
+
import { o as verifySyncSchemaWithDriver } from "./crdt-sync-producer-BQkuzCBM.js";
|
|
3
3
|
import sqlite3InitModule from "@sqlite.org/sqlite-wasm";
|
|
4
4
|
import { createStore, del, get, set } from "idb-keyval";
|
|
5
5
|
//#region src/wasm-driver.ts
|
|
@@ -217,4 +217,4 @@ function createReloadRequestHandler({ resetState, broadcast, generateEpoch = gen
|
|
|
217
217
|
//#endregion
|
|
218
218
|
export { createWasmSqliteDriver as _, acquireReplicaLock as a, isWorkerErrorResponseMessage as c, isWorkerRequestMessage as d, isWorkerResponseMessage as f, createWasmMemoryDriver as g, verifySyncSchema as h, createResetStateStore as i, isWorkerInitMessage as l, syncDbWorkerLockName as m, createIdbResetStore as n, runWithNoActiveReplicas as o, syncDbClientLockName as p, createReloadRequestHandler as r, createBroadcastChannels as s, RESET_REQUEST_TTL_MS as t, isWorkerNotificationMessage as u, loadSqliteWasm as v };
|
|
219
219
|
|
|
220
|
-
//# sourceMappingURL=reset-state-
|
|
220
|
+
//# sourceMappingURL=reset-state-DAPyJglN.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reset-state-Bz1sfbf3.js","names":[],"sources":["../src/wasm-driver.ts","../src/schema/verify-sync-schema-wasm.ts","../src/worker-db/worker-common.ts","../src/worker-db/replica-lock.ts","../src/worker-db/reset-state.ts"],"sourcesContent":["import sqlite3InitModule, {\n type BindableValue,\n type Database,\n type Sqlite3Static,\n type SqlValue,\n} from \"@sqlite.org/sqlite-wasm\";\nimport type { SqliteDriver, SqliteDriverStatement, SqliteDriverValue } from \"./sqlite-driver\";\n\nlet sqliteModulePromise: Promise<Sqlite3Static> | null = null;\n\nexport function loadSqliteWasm() {\n sqliteModulePromise ??= sqlite3InitModule();\n return sqliteModulePromise;\n}\n\nexport async function createWasmMemoryDriver() {\n const sqlite3 = await loadSqliteWasm();\n return createWasmSqliteDriver(sqlite3, new sqlite3.oo1.DB({ filename: \":memory:\" }));\n}\n\nexport function createWasmSqliteDriver(sqlite3: Sqlite3Static, db: Database): SqliteDriver {\n const { capi } = sqlite3;\n\n const prepare = (sql: string): SqliteDriverStatement => {\n const statement = db.prepare(sql);\n const pointer = statement.pointer;\n if (!pointer) {\n throw new Error(\"Prepared statement is already finalized\");\n }\n\n return {\n readonly: capi.sqlite3_stmt_readonly(pointer) !== 0,\n run: (parameters) => {\n try {\n if (parameters.length > 0) {\n statement.bind(parameters as BindableValue[]);\n }\n\n const rows: SqliteDriverValue[][] = [];\n let columns: string[] | undefined;\n while (statement.step()) {\n columns ??= statement.getColumnNames([]);\n rows.push(statement.get([]) as SqliteDriverValue[]);\n }\n return { columns: columns ?? [], rows };\n } finally {\n statement.reset(true);\n }\n },\n finalize: () => {\n statement.finalize();\n },\n };\n };\n\n return {\n prepare,\n synchronousHooks: true,\n totalChanges: () => capi.sqlite3_total_changes(db),\n setHooks: (hooks) => {\n if (!hooks) {\n capi.sqlite3_update_hook(db, 0 as never, 0);\n capi.sqlite3_rollback_hook(db, 0, 0);\n capi.sqlite3_commit_hook(db, 0, 0);\n return;\n }\n\n capi.sqlite3_update_hook(db, (_ctx, _opId, _db, table) => hooks.onUpdate(table), 0);\n capi.sqlite3_rollback_hook(\n db,\n () => {\n hooks.onRollback();\n return 0;\n },\n 0,\n );\n capi.sqlite3_commit_hook(\n db,\n () => {\n hooks.onCommit();\n return 0;\n },\n 0,\n );\n },\n serialize: () => capi.sqlite3_js_db_export(db),\n deserialize: (snapshot) => {\n const dataPointer = sqlite3.wasm.allocFromTypedArray(snapshot);\n const resultCode = capi.sqlite3_deserialize(\n db,\n \"main\",\n dataPointer,\n snapshot.byteLength,\n snapshot.byteLength,\n capi.SQLITE_DESERIALIZE_FREEONCLOSE | capi.SQLITE_DESERIALIZE_RESIZEABLE,\n );\n db.checkRc(resultCode);\n },\n createScalarFunction: ({ name, callback, arity, deterministic, directOnly, innocuous }) => {\n db.createFunction({\n name,\n xFunc: (_, ...args) => callback(...(args as SqliteDriverValue[])) as SqlValue,\n arity,\n deterministic,\n directOnly,\n innocuous,\n });\n },\n close: () => {\n db.close();\n },\n };\n}\n","import type { SyncDbSchema } from \"../sqlite-crdt/crdt-schema\";\nimport { createWasmMemoryDriver } from \"../wasm-driver\";\nimport { type SchemaVerificationIssue, verifySyncSchemaWithDriver } from \"./verify-sync-schema\";\n\n/** {@link verifySyncSchemaWithDriver} on a throwaway in-memory sqlite-wasm database. */\nexport async function verifySyncSchema(schema: SyncDbSchema): Promise<SchemaVerificationIssue[]> {\n return verifySyncSchemaWithDriver(schema, await createWasmMemoryDriver());\n}\n","import type { ImportDataOptions, ImportDataResult, SyncedDbExport } from \"../export-import\";\nimport type {\n DeSyncDetectedReason,\n EventsPullRequest,\n EventsPushRequest,\n EventsPushResponse,\n} from \"../sqlite-crdt/crdt-sync-remote-source\";\nimport type { CrdtEventType } from \"../sqlite-crdt/crdt-table-schema\";\nimport type { ExecuteParams, ExecuteResult } from \"../sqlite-db-wrapper\";\nimport { TypedBroadcastChannel } from \"../utils\";\n\nexport const syncDbWorkerLockName = \"sync-db-worker-lock\";\nexport const syncDbClientLockName = \"sync-db-client-lock\";\n\nexport type WorkerNotificationMessage =\n | {\n notificationType: \"new-event-chunk-applied\";\n newSyncId: number;\n /** Worker's state hash after applying up to `newSyncId`. */\n stateHash: string | null;\n }\n | {\n notificationType: \"state-changed\";\n state: WorkerState;\n /** Id of the worker's persisted database. A wiped database gets a new one. */\n storageGeneration: string;\n }\n | {\n notificationType: \"reload-requested\";\n reloadEpoch: string;\n clean: boolean;\n }\n | {\n notificationType: \"de-sync-detected\";\n reason: DeSyncDetectedReason;\n }\n | {\n notificationType: \"remote-schema-version-mismatch\";\n remoteSchemaVersion: number;\n localSchemaVersion: number;\n };\n\nexport type WorkerNotificationEvents = {\n [K in WorkerNotificationMessage[\"notificationType\"]]: Extract<WorkerNotificationMessage, { notificationType: K }>;\n};\n\nexport type WorkerState = {\n remoteState: \"online\" | \"offline\" | \"connecting\";\n deSynced: boolean;\n schemaVersionMismatched: boolean;\n};\n\nexport type GetSnapshotResponse = {\n file: Uint8Array<ArrayBufferLike>;\n syncId: number;\n schemaVersion: number;\n storageGeneration: string;\n};\n\nexport type EventsPullResponse = {\n events: {\n schema_version: number;\n type: CrdtEventType;\n timestamp: string;\n dataset: string;\n item_id: string;\n payload: string;\n }[];\n hasMore: boolean;\n nextSyncId: number;\n};\n\nexport interface WorkerRpc {\n getSnapshot: () => GetSnapshotResponse;\n importData: (data: SyncedDbExport, opts?: ImportDataOptions) => ImportDataResult | Promise<ImportDataResult>;\n pushTabEvents: (request: EventsPushRequest) => EventsPushResponse;\n execute: (query: ExecuteParams) => ExecuteResult<unknown>;\n pullEvents: (params: EventsPullRequest) => EventsPullResponse;\n postState: () => void;\n goOnline: () => Promise<void>;\n goOffline: () => void;\n dropConnection: () => void;\n sync: () => void;\n requestReload: (options: { clean: boolean }) => Promise<void>;\n}\n\nexport type WorkerRequestMethod = keyof WorkerRpc;\n\nexport type WorkerRequestMessage<TMethod extends WorkerRequestMethod = WorkerRequestMethod> = {\n type: \"request\";\n requestId: string;\n method: TMethod;\n args: Parameters<WorkerRpc[TMethod]>;\n};\n\nexport type WorkerResponseMessage<TMethod extends WorkerRequestMethod = WorkerRequestMethod> = {\n type: \"response\";\n requestId: string;\n data: ReturnType<WorkerRpc[TMethod]>;\n};\n\nexport type WorkerErrorResponseMessage = {\n type: \"error-response\";\n requestId: string;\n error: string;\n};\n\nexport type AsyncRpc<T> = {\n [K in keyof T]: T[K] extends (...args: infer U) => infer V ? (...args: U) => Promise<Awaited<V>> : never;\n};\n\nexport const broadcastChannelNames = {\n requests: \"sync-db-worker-requests\",\n responses: \"sync-db-worker-responses\",\n} as const;\n\nexport type WorkerBroadcastChannels = {\n requests: TypedBroadcastChannel<WorkerRequestMessage>;\n responses: TypedBroadcastChannel<WorkerResponseMessage | WorkerErrorResponseMessage | WorkerNotificationMessage>;\n};\n\nexport const createBroadcastChannels = (prefix: string): WorkerBroadcastChannels => {\n return {\n requests: new TypedBroadcastChannel(`${prefix}-${broadcastChannelNames.requests}`),\n responses: new TypedBroadcastChannel(`${prefix}-${broadcastChannelNames.responses}`),\n };\n};\n\nexport type WorkerConfig<Props = any> = {\n dbId: string;\n clientId: string;\n props: Props;\n};\n\nexport type WorkerInitMessage = {\n type: \"init\";\n config: WorkerConfig;\n};\n\nexport function isWorkerInitMessage(message: unknown): message is WorkerInitMessage {\n return typeof message === \"object\" && message !== null && \"type\" in message && message.type === \"init\";\n}\n\nexport function isWorkerRequestMessage(message: unknown): message is WorkerRequestMessage {\n return typeof message === \"object\" && message !== null && \"type\" in message && message.type === \"request\";\n}\n\nexport function isWorkerResponseMessage(message: unknown): message is WorkerResponseMessage {\n return (\n typeof message === \"object\" && message !== null && \"type\" in message && \"requestId\" in message && \"data\" in message\n );\n}\n\nexport function isWorkerErrorResponseMessage(message: unknown): message is WorkerErrorResponseMessage {\n return typeof message === \"object\" && message !== null && \"type\" in message && message.type === \"error-response\";\n}\n\nexport function isWorkerNotificationMessage(message: unknown): message is WorkerNotificationMessage {\n return typeof message === \"object\" && message !== null && \"notificationType\" in message && !!message.notificationType;\n}\n","import { acquireLock } from \"../utils\";\n\nconst replicaLockName = (dbId: string) => `sync-db-replica-lock-${dbId}`;\n\nexport function acquireReplicaLock({ dbId }: { dbId: string }) {\n return acquireLock(replicaLockName(dbId), { mode: \"shared\" });\n}\n\nexport function runWithNoActiveReplicas({ dbId, run }: { dbId: string; run: () => void | Promise<void> }) {\n return navigator.locks.request(replicaLockName(dbId), { mode: \"exclusive\", ifAvailable: true }, async (lock) => {\n if (!lock) {\n return false;\n }\n await run();\n return true;\n });\n}\n","import { createStore, del, get, set } from \"idb-keyval\";\nimport { generateId } from \"../utils\";\nimport type { WorkerNotificationMessage } from \"./worker-common\";\n\nexport type ResetRequest = {\n epoch: string;\n requestedAt: number;\n};\n\n/** Durable async key-value storage for reset state. Injectable for tests. */\nexport type ResetStore = {\n get: <T>(key: string) => Promise<T | undefined>;\n set: (key: string, value: unknown) => Promise<void>;\n delete: (key: string) => Promise<void>;\n};\n\n/** Default IndexedDB-backed reset store (idb-keyval over a dedicated database). */\nexport function createIdbResetStore(): ResetStore {\n const store = createStore(\"sqlite-sync\", \"kv\");\n return {\n get: (key) => get(key, store),\n set: (key, value) => set(key, value, store),\n delete: (key) => del(key, store),\n };\n}\n\n/**\n * A clean reset is a recovery action for a de-sync detected now. If the reload\n * never happens (broadcast lost, tab crashed mid-reload, browser killed the page),\n * the request must not fire on an arbitrary later cold start and silently wipe\n * local-only writes accumulated since.\n */\nexport const RESET_REQUEST_TTL_MS = 10 * 60 * 1000; // 10 minutes\n\nconst resetRequestKey = (dbId: string) => `sqlite-sync-reset-request-${dbId}`;\nconst resetAppliedKey = (dbId: string) => `sqlite-sync-reset-applied-${dbId}`;\n\ntype ResetStateStoreOptions = {\n store: ResetStore;\n dbId: string;\n now?: () => number;\n};\n\nexport type ResetStateStore = ReturnType<typeof createResetStateStore>;\n\n/**\n * Worker-owned durable reset state. The reset decision must be owned by the\n * elected worker, not by tabs during `createSyncedDb` — otherwise a later\n * worker election could repeat an already-applied wipe.\n */\nexport function createResetStateStore({ store, dbId, now = () => Date.now() }: ResetStateStoreOptions) {\n const requestKey = resetRequestKey(dbId);\n const appliedKey = resetAppliedKey(dbId);\n\n return {\n async writeResetRequest(epoch: string): Promise<ResetRequest> {\n const request: ResetRequest = { epoch, requestedAt: now() };\n await store.set(requestKey, request);\n return request;\n },\n /**\n * Read the pending reset request after winning the worker election.\n * Returns the request only when it has not been applied yet and is within\n * the TTL. Stale requests are deleted so they cannot fire on a later cold start.\n */\n async resolvePendingReset(): Promise<ResetRequest | undefined> {\n const request = await store.get<ResetRequest>(requestKey);\n if (!request) {\n return undefined;\n }\n\n if (now() - request.requestedAt > RESET_REQUEST_TTL_MS) {\n await store.delete(requestKey);\n return undefined;\n }\n\n const appliedEpoch = await store.get<string>(appliedKey);\n if (request.epoch === appliedEpoch) {\n return undefined;\n }\n\n return request;\n },\n /**\n * Record the epoch as applied. Must be called only after the worker has\n * successfully initialized with `clearOnInit: true`, so a failed init can\n * be retried by a later elected worker.\n */\n async markResetApplied(epoch: string): Promise<void> {\n await store.set(appliedKey, epoch);\n },\n };\n}\n\ntype ReloadRequestHandlerOptions = {\n resetState: ResetStateStore;\n broadcast: (message: WorkerNotificationMessage) => void;\n generateEpoch?: () => string;\n};\n\n/**\n * Worker-side `requestReload` RPC implementation. For `clean: true` the reset\n * request is durably stored before broadcasting and before the RPC resolves,\n * so the epoch survives no matter which path triggers the reload.\n */\nexport function createReloadRequestHandler({\n resetState,\n broadcast,\n generateEpoch = generateId,\n}: ReloadRequestHandlerOptions) {\n return async (options: { clean: boolean }): Promise<void> => {\n const reloadEpoch = generateEpoch();\n\n if (options.clean) {\n await resetState.writeResetRequest(reloadEpoch);\n }\n\n broadcast({\n notificationType: \"reload-requested\",\n reloadEpoch,\n clean: options.clean,\n });\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"reset-state-DAPyJglN.js","names":[],"sources":["../src/wasm-driver.ts","../src/schema/verify-sync-schema-wasm.ts","../src/worker-db/worker-common.ts","../src/worker-db/replica-lock.ts","../src/worker-db/reset-state.ts"],"sourcesContent":["import sqlite3InitModule, {\n type BindableValue,\n type Database,\n type Sqlite3Static,\n type SqlValue,\n} from \"@sqlite.org/sqlite-wasm\";\nimport type { SqliteDriver, SqliteDriverStatement, SqliteDriverValue } from \"./sqlite-driver\";\n\nlet sqliteModulePromise: Promise<Sqlite3Static> | null = null;\n\nexport function loadSqliteWasm() {\n sqliteModulePromise ??= sqlite3InitModule();\n return sqliteModulePromise;\n}\n\nexport async function createWasmMemoryDriver() {\n const sqlite3 = await loadSqliteWasm();\n return createWasmSqliteDriver(sqlite3, new sqlite3.oo1.DB({ filename: \":memory:\" }));\n}\n\nexport function createWasmSqliteDriver(sqlite3: Sqlite3Static, db: Database): SqliteDriver {\n const { capi } = sqlite3;\n\n const prepare = (sql: string): SqliteDriverStatement => {\n const statement = db.prepare(sql);\n const pointer = statement.pointer;\n if (!pointer) {\n throw new Error(\"Prepared statement is already finalized\");\n }\n\n return {\n readonly: capi.sqlite3_stmt_readonly(pointer) !== 0,\n run: (parameters) => {\n try {\n if (parameters.length > 0) {\n statement.bind(parameters as BindableValue[]);\n }\n\n const rows: SqliteDriverValue[][] = [];\n let columns: string[] | undefined;\n while (statement.step()) {\n columns ??= statement.getColumnNames([]);\n rows.push(statement.get([]) as SqliteDriverValue[]);\n }\n return { columns: columns ?? [], rows };\n } finally {\n statement.reset(true);\n }\n },\n finalize: () => {\n statement.finalize();\n },\n };\n };\n\n return {\n prepare,\n synchronousHooks: true,\n totalChanges: () => capi.sqlite3_total_changes(db),\n setHooks: (hooks) => {\n if (!hooks) {\n capi.sqlite3_update_hook(db, 0 as never, 0);\n capi.sqlite3_rollback_hook(db, 0, 0);\n capi.sqlite3_commit_hook(db, 0, 0);\n return;\n }\n\n capi.sqlite3_update_hook(db, (_ctx, _opId, _db, table) => hooks.onUpdate(table), 0);\n capi.sqlite3_rollback_hook(\n db,\n () => {\n hooks.onRollback();\n return 0;\n },\n 0,\n );\n capi.sqlite3_commit_hook(\n db,\n () => {\n hooks.onCommit();\n return 0;\n },\n 0,\n );\n },\n serialize: () => capi.sqlite3_js_db_export(db),\n deserialize: (snapshot) => {\n const dataPointer = sqlite3.wasm.allocFromTypedArray(snapshot);\n const resultCode = capi.sqlite3_deserialize(\n db,\n \"main\",\n dataPointer,\n snapshot.byteLength,\n snapshot.byteLength,\n capi.SQLITE_DESERIALIZE_FREEONCLOSE | capi.SQLITE_DESERIALIZE_RESIZEABLE,\n );\n db.checkRc(resultCode);\n },\n createScalarFunction: ({ name, callback, arity, deterministic, directOnly, innocuous }) => {\n db.createFunction({\n name,\n xFunc: (_, ...args) => callback(...(args as SqliteDriverValue[])) as SqlValue,\n arity,\n deterministic,\n directOnly,\n innocuous,\n });\n },\n close: () => {\n db.close();\n },\n };\n}\n","import type { SyncDbSchema } from \"../sqlite-crdt/crdt-schema\";\nimport { createWasmMemoryDriver } from \"../wasm-driver\";\nimport { type SchemaVerificationIssue, verifySyncSchemaWithDriver } from \"./verify-sync-schema\";\n\n/** {@link verifySyncSchemaWithDriver} on a throwaway in-memory sqlite-wasm database. */\nexport async function verifySyncSchema(schema: SyncDbSchema): Promise<SchemaVerificationIssue[]> {\n return verifySyncSchemaWithDriver(schema, await createWasmMemoryDriver());\n}\n","import type { ImportDataOptions, ImportDataResult, SyncedDbExport } from \"../export-import\";\nimport type {\n DeSyncDetectedReason,\n EventsPullRequest,\n EventsPushRequest,\n EventsPushResponse,\n} from \"../sqlite-crdt/crdt-sync-remote-source\";\nimport type { CrdtEventType } from \"../sqlite-crdt/crdt-table-schema\";\nimport type { ExecuteParams, ExecuteResult } from \"../sqlite-db-wrapper\";\nimport { TypedBroadcastChannel } from \"../utils\";\n\nexport const syncDbWorkerLockName = \"sync-db-worker-lock\";\nexport const syncDbClientLockName = \"sync-db-client-lock\";\n\nexport type WorkerNotificationMessage =\n | {\n notificationType: \"new-event-chunk-applied\";\n newSyncId: number;\n /** Worker's state hash after applying up to `newSyncId`. */\n stateHash: string | null;\n }\n | {\n notificationType: \"state-changed\";\n state: WorkerState;\n /** Id of the worker's persisted database. A wiped database gets a new one. */\n storageGeneration: string;\n }\n | {\n notificationType: \"reload-requested\";\n reloadEpoch: string;\n clean: boolean;\n }\n | {\n notificationType: \"de-sync-detected\";\n reason: DeSyncDetectedReason;\n }\n | {\n notificationType: \"remote-schema-version-mismatch\";\n remoteSchemaVersion: number;\n localSchemaVersion: number;\n };\n\nexport type WorkerNotificationEvents = {\n [K in WorkerNotificationMessage[\"notificationType\"]]: Extract<WorkerNotificationMessage, { notificationType: K }>;\n};\n\nexport type WorkerState = {\n remoteState: \"online\" | \"offline\" | \"connecting\";\n deSynced: boolean;\n schemaVersionMismatched: boolean;\n};\n\nexport type GetSnapshotResponse = {\n file: Uint8Array<ArrayBufferLike>;\n syncId: number;\n schemaVersion: number;\n storageGeneration: string;\n};\n\nexport type EventsPullResponse = {\n events: {\n schema_version: number;\n type: CrdtEventType;\n timestamp: string;\n dataset: string;\n item_id: string;\n payload: string;\n }[];\n hasMore: boolean;\n nextSyncId: number;\n};\n\nexport interface WorkerRpc {\n getSnapshot: () => GetSnapshotResponse;\n importData: (data: SyncedDbExport, opts?: ImportDataOptions) => ImportDataResult | Promise<ImportDataResult>;\n pushTabEvents: (request: EventsPushRequest) => EventsPushResponse;\n execute: (query: ExecuteParams) => ExecuteResult<unknown>;\n pullEvents: (params: EventsPullRequest) => EventsPullResponse;\n postState: () => void;\n goOnline: () => Promise<void>;\n goOffline: () => void;\n dropConnection: () => void;\n sync: () => void;\n requestReload: (options: { clean: boolean }) => Promise<void>;\n}\n\nexport type WorkerRequestMethod = keyof WorkerRpc;\n\nexport type WorkerRequestMessage<TMethod extends WorkerRequestMethod = WorkerRequestMethod> = {\n type: \"request\";\n requestId: string;\n method: TMethod;\n args: Parameters<WorkerRpc[TMethod]>;\n};\n\nexport type WorkerResponseMessage<TMethod extends WorkerRequestMethod = WorkerRequestMethod> = {\n type: \"response\";\n requestId: string;\n data: ReturnType<WorkerRpc[TMethod]>;\n};\n\nexport type WorkerErrorResponseMessage = {\n type: \"error-response\";\n requestId: string;\n error: string;\n};\n\nexport type AsyncRpc<T> = {\n [K in keyof T]: T[K] extends (...args: infer U) => infer V ? (...args: U) => Promise<Awaited<V>> : never;\n};\n\nexport const broadcastChannelNames = {\n requests: \"sync-db-worker-requests\",\n responses: \"sync-db-worker-responses\",\n} as const;\n\nexport type WorkerBroadcastChannels = {\n requests: TypedBroadcastChannel<WorkerRequestMessage>;\n responses: TypedBroadcastChannel<WorkerResponseMessage | WorkerErrorResponseMessage | WorkerNotificationMessage>;\n};\n\nexport const createBroadcastChannels = (prefix: string): WorkerBroadcastChannels => {\n return {\n requests: new TypedBroadcastChannel(`${prefix}-${broadcastChannelNames.requests}`),\n responses: new TypedBroadcastChannel(`${prefix}-${broadcastChannelNames.responses}`),\n };\n};\n\nexport type WorkerConfig<Props = any> = {\n dbId: string;\n clientId: string;\n props: Props;\n};\n\nexport type WorkerInitMessage = {\n type: \"init\";\n config: WorkerConfig;\n};\n\nexport function isWorkerInitMessage(message: unknown): message is WorkerInitMessage {\n return typeof message === \"object\" && message !== null && \"type\" in message && message.type === \"init\";\n}\n\nexport function isWorkerRequestMessage(message: unknown): message is WorkerRequestMessage {\n return typeof message === \"object\" && message !== null && \"type\" in message && message.type === \"request\";\n}\n\nexport function isWorkerResponseMessage(message: unknown): message is WorkerResponseMessage {\n return (\n typeof message === \"object\" && message !== null && \"type\" in message && \"requestId\" in message && \"data\" in message\n );\n}\n\nexport function isWorkerErrorResponseMessage(message: unknown): message is WorkerErrorResponseMessage {\n return typeof message === \"object\" && message !== null && \"type\" in message && message.type === \"error-response\";\n}\n\nexport function isWorkerNotificationMessage(message: unknown): message is WorkerNotificationMessage {\n return typeof message === \"object\" && message !== null && \"notificationType\" in message && !!message.notificationType;\n}\n","import { acquireLock } from \"../utils\";\n\nconst replicaLockName = (dbId: string) => `sync-db-replica-lock-${dbId}`;\n\nexport function acquireReplicaLock({ dbId }: { dbId: string }) {\n return acquireLock(replicaLockName(dbId), { mode: \"shared\" });\n}\n\nexport function runWithNoActiveReplicas({ dbId, run }: { dbId: string; run: () => void | Promise<void> }) {\n return navigator.locks.request(replicaLockName(dbId), { mode: \"exclusive\", ifAvailable: true }, async (lock) => {\n if (!lock) {\n return false;\n }\n await run();\n return true;\n });\n}\n","import { createStore, del, get, set } from \"idb-keyval\";\nimport { generateId } from \"../utils\";\nimport type { WorkerNotificationMessage } from \"./worker-common\";\n\nexport type ResetRequest = {\n epoch: string;\n requestedAt: number;\n};\n\n/** Durable async key-value storage for reset state. Injectable for tests. */\nexport type ResetStore = {\n get: <T>(key: string) => Promise<T | undefined>;\n set: (key: string, value: unknown) => Promise<void>;\n delete: (key: string) => Promise<void>;\n};\n\n/** Default IndexedDB-backed reset store (idb-keyval over a dedicated database). */\nexport function createIdbResetStore(): ResetStore {\n const store = createStore(\"sqlite-sync\", \"kv\");\n return {\n get: (key) => get(key, store),\n set: (key, value) => set(key, value, store),\n delete: (key) => del(key, store),\n };\n}\n\n/**\n * A clean reset is a recovery action for a de-sync detected now. If the reload\n * never happens (broadcast lost, tab crashed mid-reload, browser killed the page),\n * the request must not fire on an arbitrary later cold start and silently wipe\n * local-only writes accumulated since.\n */\nexport const RESET_REQUEST_TTL_MS = 10 * 60 * 1000; // 10 minutes\n\nconst resetRequestKey = (dbId: string) => `sqlite-sync-reset-request-${dbId}`;\nconst resetAppliedKey = (dbId: string) => `sqlite-sync-reset-applied-${dbId}`;\n\ntype ResetStateStoreOptions = {\n store: ResetStore;\n dbId: string;\n now?: () => number;\n};\n\nexport type ResetStateStore = ReturnType<typeof createResetStateStore>;\n\n/**\n * Worker-owned durable reset state. The reset decision must be owned by the\n * elected worker, not by tabs during `createSyncedDb` — otherwise a later\n * worker election could repeat an already-applied wipe.\n */\nexport function createResetStateStore({ store, dbId, now = () => Date.now() }: ResetStateStoreOptions) {\n const requestKey = resetRequestKey(dbId);\n const appliedKey = resetAppliedKey(dbId);\n\n return {\n async writeResetRequest(epoch: string): Promise<ResetRequest> {\n const request: ResetRequest = { epoch, requestedAt: now() };\n await store.set(requestKey, request);\n return request;\n },\n /**\n * Read the pending reset request after winning the worker election.\n * Returns the request only when it has not been applied yet and is within\n * the TTL. Stale requests are deleted so they cannot fire on a later cold start.\n */\n async resolvePendingReset(): Promise<ResetRequest | undefined> {\n const request = await store.get<ResetRequest>(requestKey);\n if (!request) {\n return undefined;\n }\n\n if (now() - request.requestedAt > RESET_REQUEST_TTL_MS) {\n await store.delete(requestKey);\n return undefined;\n }\n\n const appliedEpoch = await store.get<string>(appliedKey);\n if (request.epoch === appliedEpoch) {\n return undefined;\n }\n\n return request;\n },\n /**\n * Record the epoch as applied. Must be called only after the worker has\n * successfully initialized with `clearOnInit: true`, so a failed init can\n * be retried by a later elected worker.\n */\n async markResetApplied(epoch: string): Promise<void> {\n await store.set(appliedKey, epoch);\n },\n };\n}\n\ntype ReloadRequestHandlerOptions = {\n resetState: ResetStateStore;\n broadcast: (message: WorkerNotificationMessage) => void;\n generateEpoch?: () => string;\n};\n\n/**\n * Worker-side `requestReload` RPC implementation. For `clean: true` the reset\n * request is durably stored before broadcasting and before the RPC resolves,\n * so the epoch survives no matter which path triggers the reload.\n */\nexport function createReloadRequestHandler({\n resetState,\n broadcast,\n generateEpoch = generateId,\n}: ReloadRequestHandlerOptions) {\n return async (options: { clean: boolean }): Promise<void> => {\n const reloadEpoch = generateEpoch();\n\n if (options.clean) {\n await resetState.writeResetRequest(reloadEpoch);\n }\n\n broadcast({\n notificationType: \"reload-requested\",\n reloadEpoch,\n clean: options.clean,\n });\n };\n}\n"],"mappings":";;;;;AAQA,IAAI,sBAAqD;AAEzD,SAAgB,iBAAiB;CAC/B,wBAAwB,kBAAkB;CAC1C,OAAO;AACT;AAEA,eAAsB,yBAAyB;CAC7C,MAAM,UAAU,MAAM,eAAe;CACrC,OAAO,uBAAuB,SAAS,IAAI,QAAQ,IAAI,GAAG,EAAE,UAAU,WAAW,CAAC,CAAC;AACrF;AAEA,SAAgB,uBAAuB,SAAwB,IAA4B;CACzF,MAAM,EAAE,SAAS;CAEjB,MAAM,WAAW,QAAuC;EACtD,MAAM,YAAY,GAAG,QAAQ,GAAG;EAChC,MAAM,UAAU,UAAU;EAC1B,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,yCAAyC;EAG3D,OAAO;GACL,UAAU,KAAK,sBAAsB,OAAO,MAAM;GAClD,MAAM,eAAe;IACnB,IAAI;KACF,IAAI,WAAW,SAAS,GACtB,UAAU,KAAK,UAA6B;KAG9C,MAAM,OAA8B,CAAC;KACrC,IAAI;KACJ,OAAO,UAAU,KAAK,GAAG;MACvB,YAAY,UAAU,eAAe,CAAC,CAAC;MACvC,KAAK,KAAK,UAAU,IAAI,CAAC,CAAC,CAAwB;KACpD;KACA,OAAO;MAAE,SAAS,WAAW,CAAC;MAAG;KAAK;IACxC,UAAU;KACR,UAAU,MAAM,IAAI;IACtB;GACF;GACA,gBAAgB;IACd,UAAU,SAAS;GACrB;EACF;CACF;CAEA,OAAO;EACL;EACA,kBAAkB;EAClB,oBAAoB,KAAK,sBAAsB,EAAE;EACjD,WAAW,UAAU;GACnB,IAAI,CAAC,OAAO;IACV,KAAK,oBAAoB,IAAI,GAAY,CAAC;IAC1C,KAAK,sBAAsB,IAAI,GAAG,CAAC;IACnC,KAAK,oBAAoB,IAAI,GAAG,CAAC;IACjC;GACF;GAEA,KAAK,oBAAoB,KAAK,MAAM,OAAO,KAAK,UAAU,MAAM,SAAS,KAAK,GAAG,CAAC;GAClF,KAAK,sBACH,UACM;IACJ,MAAM,WAAW;IACjB,OAAO;GACT,GACA,CACF;GACA,KAAK,oBACH,UACM;IACJ,MAAM,SAAS;IACf,OAAO;GACT,GACA,CACF;EACF;EACA,iBAAiB,KAAK,qBAAqB,EAAE;EAC7C,cAAc,aAAa;GACzB,MAAM,cAAc,QAAQ,KAAK,oBAAoB,QAAQ;GAC7D,MAAM,aAAa,KAAK,oBACtB,IACA,QACA,aACA,SAAS,YACT,SAAS,YACT,KAAK,iCAAiC,KAAK,6BAC7C;GACA,GAAG,QAAQ,UAAU;EACvB;EACA,uBAAuB,EAAE,MAAM,UAAU,OAAO,eAAe,YAAY,gBAAgB;GACzF,GAAG,eAAe;IAChB;IACA,QAAQ,GAAG,GAAG,SAAS,SAAS,GAAI,IAA4B;IAChE;IACA;IACA;IACA;GACF,CAAC;EACH;EACA,aAAa;GACX,GAAG,MAAM;EACX;CACF;AACF;;;;AC3GA,eAAsB,iBAAiB,QAA0D;CAC/F,OAAO,2BAA2B,QAAQ,MAAM,uBAAuB,CAAC;AAC1E;;;ACIA,MAAa,uBAAuB;AACpC,MAAa,uBAAuB;AAmGpC,MAAa,wBAAwB;CACnC,UAAU;CACV,WAAW;AACb;AAOA,MAAa,2BAA2B,WAA4C;CAClF,OAAO;EACL,UAAU,IAAI,sBAAsB,GAAG,OAAO,GAAG,sBAAsB,UAAU;EACjF,WAAW,IAAI,sBAAsB,GAAG,OAAO,GAAG,sBAAsB,WAAW;CACrF;AACF;AAaA,SAAgB,oBAAoB,SAAgD;CAClF,OAAO,OAAO,YAAY,YAAY,YAAY,QAAQ,UAAU,WAAW,QAAQ,SAAS;AAClG;AAEA,SAAgB,uBAAuB,SAAmD;CACxF,OAAO,OAAO,YAAY,YAAY,YAAY,QAAQ,UAAU,WAAW,QAAQ,SAAS;AAClG;AAEA,SAAgB,wBAAwB,SAAoD;CAC1F,OACE,OAAO,YAAY,YAAY,YAAY,QAAQ,UAAU,WAAW,eAAe,WAAW,UAAU;AAEhH;AAEA,SAAgB,6BAA6B,SAAyD;CACpG,OAAO,OAAO,YAAY,YAAY,YAAY,QAAQ,UAAU,WAAW,QAAQ,SAAS;AAClG;AAEA,SAAgB,4BAA4B,SAAwD;CAClG,OAAO,OAAO,YAAY,YAAY,YAAY,QAAQ,sBAAsB,WAAW,CAAC,CAAC,QAAQ;AACvG;;;AC7JA,MAAM,mBAAmB,SAAiB,wBAAwB;AAElE,SAAgB,mBAAmB,EAAE,QAA0B;CAC7D,OAAO,YAAY,gBAAgB,IAAI,GAAG,EAAE,MAAM,SAAS,CAAC;AAC9D;AAEA,SAAgB,wBAAwB,EAAE,MAAM,OAA0D;CACxG,OAAO,UAAU,MAAM,QAAQ,gBAAgB,IAAI,GAAG;EAAE,MAAM;EAAa,aAAa;CAAK,GAAG,OAAO,SAAS;EAC9G,IAAI,CAAC,MACH,OAAO;EAET,MAAM,IAAI;EACV,OAAO;CACT,CAAC;AACH;;;;ACCA,SAAgB,sBAAkC;CAChD,MAAM,QAAQ,YAAY,eAAe,IAAI;CAC7C,OAAO;EACL,MAAM,QAAQ,IAAI,KAAK,KAAK;EAC5B,MAAM,KAAK,UAAU,IAAI,KAAK,OAAO,KAAK;EAC1C,SAAS,QAAQ,IAAI,KAAK,KAAK;CACjC;AACF;;;;;;;AAQA,MAAa,uBAAuB;AAEpC,MAAM,mBAAmB,SAAiB,6BAA6B;AACvE,MAAM,mBAAmB,SAAiB,6BAA6B;;;;;;AAevE,SAAgB,sBAAsB,EAAE,OAAO,MAAM,YAAY,KAAK,IAAI,KAA6B;CACrG,MAAM,aAAa,gBAAgB,IAAI;CACvC,MAAM,aAAa,gBAAgB,IAAI;CAEvC,OAAO;EACL,MAAM,kBAAkB,OAAsC;GAC5D,MAAM,UAAwB;IAAE;IAAO,aAAa,IAAI;GAAE;GAC1D,MAAM,MAAM,IAAI,YAAY,OAAO;GACnC,OAAO;EACT;;;;;;EAMA,MAAM,sBAAyD;GAC7D,MAAM,UAAU,MAAM,MAAM,IAAkB,UAAU;GACxD,IAAI,CAAC,SACH;GAGF,IAAI,IAAI,IAAI,QAAQ,cAAA,KAAoC;IACtD,MAAM,MAAM,OAAO,UAAU;IAC7B;GACF;GAEA,MAAM,eAAe,MAAM,MAAM,IAAY,UAAU;GACvD,IAAI,QAAQ,UAAU,cACpB;GAGF,OAAO;EACT;;;;;;EAMA,MAAM,iBAAiB,OAA8B;GACnD,MAAM,MAAM,IAAI,YAAY,KAAK;EACnC;CACF;AACF;;;;;;AAaA,SAAgB,2BAA2B,EACzC,YACA,WACA,gBAAgB,cACc;CAC9B,OAAO,OAAO,YAA+C;EAC3D,MAAM,cAAc,cAAc;EAElC,IAAI,QAAQ,OACV,MAAM,WAAW,kBAAkB,WAAW;EAGhD,UAAU;GACR,kBAAkB;GAClB;GACA,OAAO,QAAQ;EACjB,CAAC;CACH;AACF"}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as EventsPullResponse, J as ClientDatasetRejectionReason, On as MigratableEvent, Ot as jsonSafeParse, T as EventsPushResponse, dn as SyncDbSchema, jn as SyncDbMigrator } from "./index-
|
|
1
|
+
import { D as EventsPullResponse, J as ClientDatasetRejectionReason, On as MigratableEvent, Ot as jsonSafeParse, T as EventsPushResponse, dn as SyncDbSchema, jn as SyncDbMigrator } from "./index-BgkTUdlX.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
//#region src/server/admit-client-push.d.ts
|
|
4
4
|
type PushedCrdtEvent = MigratableEvent & {
|