@fragno-dev/lofi 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/adapters/in-memory/adapter.d.ts.map +1 -1
  2. package/dist/adapters/in-memory/adapter.js.map +1 -1
  3. package/dist/adapters/in-memory/query.js +1 -2
  4. package/dist/adapters/in-memory/query.js.map +1 -1
  5. package/dist/adapters/in-memory/store.d.ts.map +1 -1
  6. package/dist/adapters/in-memory/store.js +1 -1
  7. package/dist/adapters/in-memory/store.js.map +1 -1
  8. package/dist/adapters/stacked/adapter.d.ts.map +1 -1
  9. package/dist/adapters/stacked/adapter.js.map +1 -1
  10. package/dist/adapters/stacked/merge.js.map +1 -1
  11. package/dist/cli/client.js +1 -1
  12. package/dist/cli/client.js.map +1 -1
  13. package/dist/cli/index.d.ts.map +1 -1
  14. package/dist/cli/index.js +2 -2
  15. package/dist/cli/index.js.map +1 -1
  16. package/dist/cli/scenario.js +1 -1
  17. package/dist/cli/scenario.js.map +1 -1
  18. package/dist/cli/server.js +1 -1
  19. package/dist/cli/server.js.map +1 -1
  20. package/dist/client/client.d.ts.map +1 -1
  21. package/dist/client/client.js.map +1 -1
  22. package/dist/indexeddb/adapter.d.ts.map +1 -1
  23. package/dist/indexeddb/adapter.js +1 -1
  24. package/dist/indexeddb/adapter.js.map +1 -1
  25. package/dist/optimistic/overlay-manager.d.ts.map +1 -1
  26. package/dist/optimistic/overlay-manager.js +0 -1
  27. package/dist/optimistic/overlay-manager.js.map +1 -1
  28. package/dist/outbox/decode.d.ts.map +1 -1
  29. package/dist/outbox/decode.js.map +1 -1
  30. package/dist/outbox/uow.d.ts.map +1 -1
  31. package/dist/outbox/uow.js.map +1 -1
  32. package/dist/query/conditions.d.ts +2 -1
  33. package/dist/query/conditions.d.ts.map +1 -1
  34. package/dist/query/conditions.js +2 -1
  35. package/dist/query/conditions.js.map +1 -1
  36. package/dist/query/engine.d.ts.map +1 -1
  37. package/dist/query/engine.js +1 -1
  38. package/dist/query/engine.js.map +1 -1
  39. package/dist/scenario.d.ts.map +1 -1
  40. package/dist/scenario.js.map +1 -1
  41. package/dist/submit/client.d.ts.map +1 -1
  42. package/dist/submit/client.js.map +1 -1
  43. package/dist/submit/local-handler-tx.d.ts.map +1 -1
  44. package/dist/submit/local-handler-tx.js.map +1 -1
  45. package/dist/submit/queue.js.map +1 -1
  46. package/dist/submit/rebase.d.ts.map +1 -1
  47. package/dist/submit/rebase.js.map +1 -1
  48. package/dist/types.d.ts.map +1 -1
  49. package/package.json +23 -26
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","names":["knownMutations: Array<{ mutation: LofiMutation; schema: AnySchema; table: AnyTable }>","inboxRow: InboxRow","definitions: IndexDefinition[]","key: LofiRow[\"key\"]","row: LofiRow","row","norm: Record<string, unknown>","rawValue"],"sources":["../../src/indexeddb/adapter.ts"],"sourcesContent":["import type { AnyColumn, AnySchema, AnyTable } from \"@fragno-dev/db/schema\";\nimport { FragnoId, FragnoReference } from \"@fragno-dev/db/schema\";\nimport { generateMigrationFromSchema } from \"@fragno-dev/db/client\";\nimport { openDB, type IDBPDatabase, type IDBPObjectStore, type IDBPTransaction } from \"idb\";\nimport type {\n IndexedDbAdapterOptions,\n LofiAdapter,\n LofiMutation,\n LofiQueryEngineOptions,\n LofiQueryInterface,\n LofiQueryableAdapter,\n} from \"../types\";\nimport type { ReferenceTarget } from \"./types\";\nimport { normalizeValue } from \"../query/normalize\";\nimport { createIndexedDbQueryEngine, type IndexedDbQueryContext } from \"../query/engine\";\n\ntype LofiRow = {\n key: [string, string, string, string];\n endpoint: string;\n schema: string;\n table: string;\n id: string;\n data: Record<string, unknown>;\n _lofi: {\n versionstamp: string;\n norm: Record<string, unknown>;\n internalId: number;\n version: number;\n };\n};\n\ntype InboxRow = {\n key: [string, string, string];\n sourceKey: string;\n uowId: string;\n versionstamp: string;\n receivedAt: number;\n};\n\ntype MetaRow = { key: string; value: string };\n\ntype LofiDb = IDBPDatabase<unknown>;\ntype WriteStore<TxStores extends ArrayLike<string>, StoreName extends string> = IDBPObjectStore<\n unknown,\n TxStores,\n StoreName,\n \"readwrite\"\n>;\ntype UpgradeStore<TxStores extends ArrayLike<string>, StoreName extends string> = IDBPObjectStore<\n unknown,\n TxStores,\n StoreName,\n \"versionchange\"\n>;\ntype UpgradeTx<TxStores extends ArrayLike<string>> = IDBPTransaction<\n unknown,\n TxStores,\n \"versionchange\"\n>;\n\ntype IndexDefinition = {\n name: string;\n table: string;\n schema: string;\n columns: string[];\n unique: boolean;\n};\n\nconst META_STORE = \"lofi_meta\";\nconst ROWS_STORE = \"lofi_rows\";\nconst INBOX_STORE = \"lofi_inbox\";\n\nconst INDEX_SCHEMA_TABLE = \"idx_schema_table\";\nconst INDEX_INBOX_SOURCE_UOW = \"idx_inbox_source_uow\";\nconst LEGACY_INBOX_INDEX = \"idx_inbox_source_version\";\n\nexport class IndexedDbAdapter implements LofiAdapter, LofiQueryableAdapter {\n private readonly dbName: string;\n private readonly endpointName: string;\n private readonly schemas: AnySchema[];\n private readonly schemaMap: Map<string, AnySchema>;\n private readonly tableMap: Map<string, Map<string, AnyTable>>;\n private readonly referenceTargets: Map<string, ReferenceTarget>;\n private readonly schemaFingerprint: string;\n private readonly indexDefinitions: IndexDefinition[];\n private readonly ignoreUnknownSchemas: boolean;\n\n private dbPromise?: Promise<LofiDb>;\n\n constructor(options: IndexedDbAdapterOptions) {\n if (!options.endpointName || options.endpointName.trim().length === 0) {\n throw new Error(\"IndexedDbAdapter requires a non-empty endpointName.\");\n }\n\n const schemaMap = new Map<string, AnySchema>();\n const tableMap = new Map<string, Map<string, AnyTable>>();\n const referenceTargets = new Map<string, ReferenceTarget>();\n\n for (const registration of options.schemas) {\n const schema = registration.schema;\n if (!schema.name || schema.name.trim().length === 0) {\n throw new Error(\"IndexedDbAdapter schemas must have a non-empty name.\");\n }\n if (schemaMap.has(schema.name)) {\n throw new Error(`IndexedDbAdapter schema name must be unique: ${schema.name}`);\n }\n\n schemaMap.set(schema.name, schema);\n const tables = new Map<string, AnyTable>();\n for (const [tableName, table] of Object.entries(schema.tables)) {\n tables.set(tableName, table);\n for (const relation of Object.values(table.relations)) {\n for (const [fromColumn] of relation.on) {\n referenceTargets.set(`${schema.name}::${table.name}::${fromColumn}`, {\n schema: schema.name,\n table: relation.table.name,\n });\n }\n }\n }\n tableMap.set(schema.name, tables);\n }\n\n this.dbName = options.dbName ?? `fragno_lofi_${options.endpointName}`;\n this.endpointName = options.endpointName;\n this.schemas = [...schemaMap.values()];\n this.schemaMap = schemaMap;\n this.tableMap = tableMap;\n this.referenceTargets = referenceTargets;\n this.indexDefinitions = buildIndexDefinitions(this.schemas);\n this.schemaFingerprint = buildSchemaFingerprint(this.schemas, this.indexDefinitions);\n this.ignoreUnknownSchemas = options.ignoreUnknownSchemas ?? false;\n }\n\n async applyOutboxEntry(options: {\n sourceKey: string;\n versionstamp: string;\n uowId: string;\n mutations: LofiMutation[];\n }): Promise<{ applied: boolean }> {\n const db = await this.openDatabase();\n\n const knownMutations: Array<{ mutation: LofiMutation; schema: AnySchema; table: AnyTable }> =\n [];\n for (const mutation of options.mutations) {\n const schema = this.schemaMap.get(mutation.schema);\n if (!schema) {\n if (this.ignoreUnknownSchemas) {\n continue;\n }\n throw new Error(`Unknown outbox schema: ${mutation.schema}`);\n }\n const table = this.tableMap.get(mutation.schema)?.get(mutation.table);\n if (!table) {\n if (this.ignoreUnknownSchemas) {\n continue;\n }\n throw new Error(`Unknown outbox table: ${mutation.schema}.${mutation.table}`);\n }\n knownMutations.push({ mutation, schema, table });\n }\n\n const tx = db.transaction([ROWS_STORE, INBOX_STORE, META_STORE], \"readwrite\");\n const rowsStore = tx.objectStore(ROWS_STORE);\n const inboxStore = tx.objectStore(INBOX_STORE);\n const metaStore = tx.objectStore(META_STORE);\n\n const existingInbox = (await inboxStore.get([\n options.sourceKey,\n options.uowId,\n options.versionstamp,\n ])) as InboxRow | undefined;\n if (existingInbox) {\n await tx.done;\n return { applied: false };\n }\n\n try {\n for (const { mutation, schema, table } of knownMutations) {\n await applyMutation({\n mutation,\n schema,\n table,\n endpointName: this.endpointName,\n rowsStore,\n metaStore,\n referenceTargets: this.referenceTargets,\n });\n }\n\n const inboxRow: InboxRow = {\n key: [options.sourceKey, options.uowId, options.versionstamp],\n sourceKey: options.sourceKey,\n uowId: options.uowId,\n versionstamp: options.versionstamp,\n receivedAt: Date.now(),\n };\n await inboxStore.put(inboxRow);\n\n await tx.done;\n return { applied: true };\n } catch (error) {\n try {\n tx.abort();\n } catch {\n // Ignore abort errors; transaction will already be closing.\n }\n try {\n await tx.done;\n } catch {\n // Ignore abort completion errors; original error is more useful.\n }\n throw error;\n }\n }\n\n async applyMutations(mutations: LofiMutation[]): Promise<void> {\n if (mutations.length === 0) {\n return;\n }\n\n const db = await this.openDatabase();\n\n const knownMutations: Array<{ mutation: LofiMutation; schema: AnySchema; table: AnyTable }> =\n [];\n for (const mutation of mutations) {\n const schema = this.schemaMap.get(mutation.schema);\n if (!schema) {\n if (this.ignoreUnknownSchemas) {\n continue;\n }\n throw new Error(`Unknown mutation schema: ${mutation.schema}`);\n }\n const table = this.tableMap.get(mutation.schema)?.get(mutation.table);\n if (!table) {\n if (this.ignoreUnknownSchemas) {\n continue;\n }\n throw new Error(`Unknown mutation table: ${mutation.schema}.${mutation.table}`);\n }\n knownMutations.push({ mutation, schema, table });\n }\n\n const tx = db.transaction([ROWS_STORE, META_STORE], \"readwrite\");\n const rowsStore = tx.objectStore(ROWS_STORE);\n const metaStore = tx.objectStore(META_STORE);\n\n try {\n for (const { mutation, schema, table } of knownMutations) {\n await applyMutation({\n mutation,\n schema,\n table,\n endpointName: this.endpointName,\n rowsStore,\n metaStore,\n referenceTargets: this.referenceTargets,\n });\n }\n\n await tx.done;\n } catch (error) {\n try {\n tx.abort();\n } catch {\n // Ignore abort errors; transaction will already be closing.\n }\n try {\n await tx.done;\n } catch {\n // Ignore abort completion errors; original error is more useful.\n }\n throw error;\n }\n }\n\n async getMeta(key: string): Promise<string | undefined> {\n const db = await this.openDatabase();\n const tx = db.transaction(META_STORE, \"readonly\");\n const store = tx.objectStore(META_STORE);\n const row = (await store.get(key)) as MetaRow | undefined;\n await tx.done;\n return row?.value;\n }\n\n async setMeta(key: string, value: string): Promise<void> {\n const db = await this.openDatabase();\n const tx = db.transaction(META_STORE, \"readwrite\");\n const store = tx.objectStore(META_STORE);\n await store.put({ key, value });\n await tx.done;\n }\n\n createQueryEngine<const T extends AnySchema>(\n schema: T,\n options?: LofiQueryEngineOptions,\n ): LofiQueryInterface<T> {\n return createIndexedDbQueryEngine({\n schema,\n endpointName: this.endpointName,\n getDb: () => this.openDatabase(),\n referenceTargets: this.referenceTargets,\n schemaName: options?.schemaName,\n });\n }\n\n createQueryContext(schemaName: string): IndexedDbQueryContext {\n return {\n endpointName: this.endpointName,\n schemaName,\n getDb: () => this.openDatabase(),\n referenceTargets: this.referenceTargets,\n };\n }\n\n private openDatabase(): Promise<LofiDb> {\n if (!this.dbPromise) {\n this.dbPromise = this.openDatabaseInternal();\n }\n return this.dbPromise;\n }\n\n private async openDatabaseInternal(): Promise<LofiDb> {\n const initialDb = await openDatabaseWithUpgrade(this.dbName, undefined, async (db, tx) => {\n ensureStores(db, tx);\n ensureIndexes(tx, this.indexDefinitions);\n await setMetaInTransaction(\n tx,\n schemaFingerprintKey(this.endpointName),\n this.schemaFingerprint,\n );\n });\n\n const existingFingerprint = await readMetaValue(\n initialDb,\n schemaFingerprintKey(this.endpointName),\n );\n\n if (existingFingerprint === this.schemaFingerprint) {\n return initialDb;\n }\n\n const currentVersion = initialDb.version;\n initialDb.close();\n\n const upgraded = await openDatabaseWithUpgrade(\n this.dbName,\n currentVersion + 1,\n async (db, tx) => {\n ensureStores(db, tx);\n ensureIndexes(tx, this.indexDefinitions);\n await clearEndpointData(tx, this.endpointName);\n await setMetaInTransaction(\n tx,\n schemaFingerprintKey(this.endpointName),\n this.schemaFingerprint,\n );\n },\n );\n\n return upgraded;\n }\n}\nconst schemaFingerprintKey = (endpointName: string) => `${endpointName}::schema_fingerprint`;\nconst cursorKeyDefault = (endpointName: string) => `${endpointName}::outbox`;\nconst seqKey = (endpointName: string, schema: string, table: string) =>\n `${endpointName}::seq::${schema}::${table}`;\n\nconst buildIndexDefinitions = (schemas: AnySchema[]): IndexDefinition[] => {\n const definitions: IndexDefinition[] = [];\n\n for (const schema of schemas) {\n const operations = generateMigrationFromSchema(schema, 0, schema.version);\n for (const op of operations) {\n if (op.type !== \"add-index\") {\n continue;\n }\n definitions.push({\n name: op.name,\n schema: schema.name,\n table: op.table,\n columns: op.columns,\n unique: op.unique,\n });\n }\n }\n\n return definitions;\n};\n\nconst buildSchemaFingerprint = (schemas: AnySchema[], indexes: IndexDefinition[]): string => {\n const payload = {\n inboxKey: \"uowId+versionstamp\",\n schemas: [...schemas]\n .map((schema) => ({\n name: schema.name,\n version: schema.version,\n tables: Object.keys(schema.tables).sort(),\n }))\n .sort((a, b) => a.name.localeCompare(b.name)),\n indexes: [...indexes]\n .map((index) => ({\n schema: index.schema,\n table: index.table,\n name: index.name,\n columns: [...index.columns],\n unique: index.unique,\n }))\n .sort((a, b) =>\n `${a.schema}.${a.table}.${a.name}`.localeCompare(`${b.schema}.${b.table}.${b.name}`),\n ),\n };\n\n return JSON.stringify(payload);\n};\n\nconst ensureStores = <TxStores extends ArrayLike<string>>(\n db: LofiDb,\n tx: UpgradeTx<TxStores>,\n): void => {\n if (!db.objectStoreNames.contains(META_STORE)) {\n db.createObjectStore(META_STORE, { keyPath: \"key\" });\n }\n\n if (!db.objectStoreNames.contains(ROWS_STORE)) {\n const store = db.createObjectStore(ROWS_STORE, { keyPath: \"key\" });\n store.createIndex(INDEX_SCHEMA_TABLE, [\"endpoint\", \"schema\", \"table\"], { unique: false });\n } else {\n const store = tx.objectStore(ROWS_STORE);\n if (!store.indexNames.contains(INDEX_SCHEMA_TABLE)) {\n store.createIndex(INDEX_SCHEMA_TABLE, [\"endpoint\", \"schema\", \"table\"], { unique: false });\n }\n }\n\n if (!db.objectStoreNames.contains(INBOX_STORE)) {\n const store = db.createObjectStore(INBOX_STORE, { keyPath: \"key\" });\n store.createIndex(INDEX_INBOX_SOURCE_UOW, [\"sourceKey\", \"uowId\", \"versionstamp\"], {\n unique: true,\n });\n } else {\n const store = tx.objectStore(INBOX_STORE);\n if (store.indexNames.contains(LEGACY_INBOX_INDEX)) {\n store.deleteIndex(LEGACY_INBOX_INDEX);\n }\n if (store.indexNames.contains(INDEX_INBOX_SOURCE_UOW)) {\n store.deleteIndex(INDEX_INBOX_SOURCE_UOW);\n }\n store.createIndex(INDEX_INBOX_SOURCE_UOW, [\"sourceKey\", \"uowId\", \"versionstamp\"], {\n unique: true,\n });\n }\n};\n\nconst ensureIndexes = <TxStores extends ArrayLike<string>>(\n tx: UpgradeTx<TxStores>,\n indexes: IndexDefinition[],\n): void => {\n const store = tx.objectStore(ROWS_STORE);\n\n for (const index of indexes) {\n const name = `idx__${index.schema}__${index.table}__${index.name}`;\n if (store.indexNames.contains(name)) {\n continue;\n }\n\n const keyPath = [\n \"endpoint\",\n \"schema\",\n \"table\",\n ...index.columns.map((column) => `_lofi.norm.${column}`),\n \"id\",\n ];\n\n store.createIndex(name, keyPath, { unique: index.unique });\n }\n};\n\nconst clearEndpointData = async <TxStores extends ArrayLike<string>>(\n tx: UpgradeTx<TxStores>,\n endpointName: string,\n): Promise<void> => {\n const rowsStore = tx.objectStore(ROWS_STORE);\n const inboxStore = tx.objectStore(INBOX_STORE);\n const metaStore = tx.objectStore(META_STORE);\n\n await deleteRowsForEndpoint(rowsStore, endpointName);\n await deleteWhere(\n inboxStore,\n (row) => isInboxRow(row) && row.sourceKey.startsWith(`${endpointName}::`),\n );\n await deleteWhere(\n metaStore,\n (row) => isMetaRow(row) && row.key === cursorKeyDefault(endpointName),\n );\n};\n\nconst deleteRowsForEndpoint = async <TxStores extends ArrayLike<string>, StoreName extends string>(\n store: UpgradeStore<TxStores, StoreName>,\n endpointName: string,\n): Promise<void> => {\n const index = store.index(INDEX_SCHEMA_TABLE);\n const range = IDBKeyRange.bound([endpointName], [endpointName, \"\\uffff\", \"\\uffff\"]);\n let cursor = await index.openCursor(range);\n while (cursor) {\n await cursor.delete();\n cursor = await cursor.continue();\n }\n};\n\nconst deleteWhere = async <TxStores extends ArrayLike<string>, StoreName extends string>(\n store: UpgradeStore<TxStores, StoreName>,\n predicate: (value: unknown) => boolean,\n): Promise<void> => {\n let cursor = await store.openCursor();\n while (cursor) {\n if (predicate(cursor.value)) {\n await cursor.delete();\n }\n cursor = await cursor.continue();\n }\n};\n\nconst isInboxRow = (value: unknown): value is InboxRow =>\n typeof value === \"object\" &&\n value !== null &&\n \"sourceKey\" in value &&\n typeof (value as { sourceKey?: unknown }).sourceKey === \"string\";\n\nconst isMetaRow = (value: unknown): value is MetaRow =>\n typeof value === \"object\" &&\n value !== null &&\n \"key\" in value &&\n typeof (value as { key?: unknown }).key === \"string\";\n\nconst openDatabaseWithUpgrade = (\n dbName: string,\n version: number | undefined,\n onUpgrade: (db: LofiDb, tx: UpgradeTx<ArrayLike<string>>) => void | Promise<void>,\n): Promise<LofiDb> =>\n openDB(dbName, version, {\n upgrade: async (db, _oldVersion, _newVersion, tx) => {\n await onUpgrade(db, tx as UpgradeTx<ArrayLike<string>>);\n },\n }).then((db) => {\n db.onversionchange = () => db.close();\n return db;\n });\n\nconst readMetaValue = async (db: LofiDb, key: string): Promise<string | undefined> => {\n if (!db.objectStoreNames.contains(META_STORE)) {\n return undefined;\n }\n const tx = db.transaction(META_STORE, \"readonly\");\n const store = tx.objectStore(META_STORE);\n const row = (await store.get(key)) as MetaRow | undefined;\n await tx.done;\n return row?.value;\n};\n\nconst setMetaInTransaction = async <TxStores extends ArrayLike<string>>(\n tx: UpgradeTx<TxStores>,\n key: string,\n value: string,\n): Promise<void> => {\n const store = tx.objectStore(META_STORE);\n await store.put({ key, value });\n};\n\nconst applyMutation = async <\n TxStores extends ArrayLike<string>,\n RowsStoreName extends string,\n MetaStoreName extends string,\n>(options: {\n mutation: LofiMutation;\n schema: AnySchema;\n table: AnyTable;\n endpointName: string;\n rowsStore: WriteStore<TxStores, RowsStoreName>;\n metaStore: WriteStore<TxStores, MetaStoreName>;\n referenceTargets: Map<string, ReferenceTarget>;\n}): Promise<void> => {\n const { mutation, schema, table, endpointName, rowsStore, metaStore, referenceTargets } = options;\n\n const key: LofiRow[\"key\"] = [endpointName, schema.name, table.name, mutation.externalId];\n const existing = (await rowsStore.get(key)) as LofiRow | undefined;\n\n if (mutation.op === \"delete\") {\n if (existing) {\n await rowsStore.delete(key);\n }\n return;\n }\n\n const values = mutation.op === \"create\" ? mutation.values : mutation.set;\n if (existing && existing._lofi.versionstamp.startsWith(\"local-\")) {\n const isMatch = Object.entries(values).every(([column, value]) =>\n Object.is(existing.data[column], value),\n );\n if (isMatch) {\n const row: LofiRow = {\n ...existing,\n data: { ...existing.data, ...values },\n _lofi: {\n ...existing._lofi,\n versionstamp: mutation.versionstamp,\n },\n };\n await rowsStore.put(row);\n return;\n }\n }\n if (!existing && mutation.op === \"update\") {\n return;\n }\n\n const data = existing ? { ...existing.data, ...values } : { ...values };\n\n const internalId = existing\n ? existing._lofi.internalId\n : await allocateInternalId(metaStore, endpointName, schema.name, table.name);\n\n const version = existing ? existing._lofi.version + (mutation.op === \"update\" ? 1 : 0) : 1;\n const norm = await buildNormalizedValues({\n schema,\n table,\n data,\n rowId: mutation.externalId,\n internalId,\n version,\n endpointName,\n rowsStore,\n referenceTargets,\n });\n\n const row: LofiRow = {\n key,\n endpoint: endpointName,\n schema: schema.name,\n table: table.name,\n id: mutation.externalId,\n data,\n _lofi: {\n versionstamp: mutation.versionstamp,\n norm,\n internalId,\n version,\n },\n };\n\n await rowsStore.put(row);\n};\n\nconst allocateInternalId = async <TxStores extends ArrayLike<string>, StoreName extends string>(\n metaStore: WriteStore<TxStores, StoreName>,\n endpointName: string,\n schemaName: string,\n tableName: string,\n): Promise<number> => {\n const key = seqKey(endpointName, schemaName, tableName);\n const existing = (await metaStore.get(key)) as MetaRow | undefined;\n const next = existing ? Number(existing.value) + 1 : 1;\n if (Number.isNaN(next) || next > Number.MAX_SAFE_INTEGER) {\n throw new Error(\n `IndexedDbAdapter internalId overflow for ${schemaName}.${tableName}: ${existing?.value}`,\n );\n }\n await metaStore.put({ key, value: String(next) });\n return next;\n};\n\nconst buildNormalizedValues = async <\n TxStores extends ArrayLike<string>,\n StoreName extends string,\n>(options: {\n schema: AnySchema;\n table: AnyTable;\n data: Record<string, unknown>;\n rowId: string;\n internalId: number;\n version: number;\n endpointName: string;\n rowsStore: WriteStore<TxStores, StoreName>;\n referenceTargets: Map<string, ReferenceTarget>;\n}): Promise<Record<string, unknown>> => {\n const {\n schema,\n table,\n data,\n rowId,\n internalId,\n version,\n endpointName,\n rowsStore,\n referenceTargets,\n } = options;\n\n const norm: Record<string, unknown> = {};\n\n for (const [columnName, column] of Object.entries(table.columns)) {\n norm[columnName] = await resolveColumnValue({\n schema,\n table,\n columnName,\n column,\n data,\n rowId,\n internalId,\n version,\n endpointName,\n rowsStore,\n referenceTargets,\n });\n }\n\n return norm;\n};\n\nconst resolveColumnValue = async <\n TxStores extends ArrayLike<string>,\n StoreName extends string,\n>(options: {\n schema: AnySchema;\n table: AnyTable;\n columnName: string;\n column: AnyColumn;\n data: Record<string, unknown>;\n rowId: string;\n internalId: number;\n version: number;\n endpointName: string;\n rowsStore: WriteStore<TxStores, StoreName>;\n referenceTargets: Map<string, ReferenceTarget>;\n}): Promise<unknown> => {\n const {\n schema,\n table,\n columnName,\n column,\n data,\n rowId,\n internalId,\n version,\n endpointName,\n rowsStore,\n referenceTargets,\n } = options;\n\n if (column.role === \"external-id\") {\n return rowId;\n }\n\n if (column.role === \"internal-id\") {\n return internalId;\n }\n\n if (column.role === \"version\") {\n return version;\n }\n\n if (column.role === \"reference\") {\n const rawValue = data[columnName];\n if (rawValue == null) {\n return rawValue;\n }\n\n if (rawValue instanceof FragnoReference) {\n return coerceInternalIdValue(rawValue.internalId, schema, table, columnName);\n }\n\n if (rawValue instanceof FragnoId) {\n if (rawValue.internalId !== undefined) {\n return coerceInternalIdValue(rawValue.internalId, schema, table, columnName);\n }\n return resolveReferenceExternalId({\n schema,\n table,\n columnName,\n externalId: rawValue.externalId,\n endpointName,\n rowsStore,\n referenceTargets,\n });\n }\n\n if (typeof rawValue === \"number\") {\n throw new Error(\n `Expected reference value to be external ID string for ${schema.name}.${table.name}.${columnName}.`,\n );\n }\n\n if (typeof rawValue === \"bigint\") {\n return coerceInternalIdValue(rawValue, schema, table, columnName);\n }\n\n if (typeof rawValue !== \"string\") {\n throw new Error(\n `Expected reference value to be external ID string for ${schema.name}.${table.name}.${columnName}.`,\n );\n }\n\n return resolveReferenceExternalId({\n schema,\n table,\n columnName,\n externalId: rawValue,\n endpointName,\n rowsStore,\n referenceTargets,\n });\n }\n\n const rawValue = data[columnName];\n if (rawValue === undefined) {\n return undefined;\n }\n if (rawValue === null) {\n return null;\n }\n\n return normalizeValue(rawValue, column);\n};\n\nconst resolveReferenceExternalId = async <\n TxStores extends ArrayLike<string>,\n StoreName extends string,\n>(options: {\n schema: AnySchema;\n table: AnyTable;\n columnName: string;\n externalId: string;\n endpointName: string;\n rowsStore: WriteStore<TxStores, StoreName>;\n referenceTargets: Map<string, ReferenceTarget>;\n}): Promise<number | undefined> => {\n const { schema, table, columnName, externalId, endpointName, rowsStore, referenceTargets } =\n options;\n const target = referenceTargets.get(`${schema.name}::${table.name}::${columnName}`);\n if (!target) {\n return undefined;\n }\n const key: LofiRow[\"key\"] = [endpointName, target.schema, target.table, externalId];\n const referenced = (await rowsStore.get(key)) as LofiRow | undefined;\n if (!referenced) {\n return undefined;\n }\n return referenced._lofi.internalId;\n};\n\nconst coerceInternalIdValue = (\n value: bigint | number,\n schema: AnySchema,\n table: AnyTable,\n columnName: string,\n): number => {\n const asNumber = typeof value === \"bigint\" ? Number(value) : value;\n if (!Number.isSafeInteger(asNumber)) {\n throw new Error(\n `Reference internalId is not a safe integer for ${schema.name}.${table.name}.${columnName}: ${value.toString()}`,\n );\n }\n return asNumber;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"adapter.js","names":["knownMutations: Array<{ mutation: LofiMutation; schema: AnySchema; table: AnyTable }>","inboxRow: InboxRow","definitions: IndexDefinition[]","key: LofiRow[\"key\"]","row: LofiRow","row","norm: Record<string, unknown>","rawValue"],"sources":["../../src/indexeddb/adapter.ts"],"sourcesContent":["import { generateMigrationFromSchema } from \"@fragno-dev/db/client\";\nimport type { AnyColumn, AnySchema, AnyTable } from \"@fragno-dev/db/schema\";\nimport { FragnoId, FragnoReference } from \"@fragno-dev/db/schema\";\nimport { openDB, type IDBPDatabase, type IDBPObjectStore, type IDBPTransaction } from \"idb\";\n\nimport { createIndexedDbQueryEngine, type IndexedDbQueryContext } from \"../query/engine\";\nimport { normalizeValue } from \"../query/normalize\";\nimport type {\n IndexedDbAdapterOptions,\n LofiAdapter,\n LofiMutation,\n LofiQueryEngineOptions,\n LofiQueryInterface,\n LofiQueryableAdapter,\n} from \"../types\";\nimport type { ReferenceTarget } from \"./types\";\n\ntype LofiRow = {\n key: [string, string, string, string];\n endpoint: string;\n schema: string;\n table: string;\n id: string;\n data: Record<string, unknown>;\n _lofi: {\n versionstamp: string;\n norm: Record<string, unknown>;\n internalId: number;\n version: number;\n };\n};\n\ntype InboxRow = {\n key: [string, string, string];\n sourceKey: string;\n uowId: string;\n versionstamp: string;\n receivedAt: number;\n};\n\ntype MetaRow = { key: string; value: string };\n\ntype LofiDb = IDBPDatabase<unknown>;\ntype WriteStore<TxStores extends ArrayLike<string>, StoreName extends string> = IDBPObjectStore<\n unknown,\n TxStores,\n StoreName,\n \"readwrite\"\n>;\ntype UpgradeStore<TxStores extends ArrayLike<string>, StoreName extends string> = IDBPObjectStore<\n unknown,\n TxStores,\n StoreName,\n \"versionchange\"\n>;\ntype UpgradeTx<TxStores extends ArrayLike<string>> = IDBPTransaction<\n unknown,\n TxStores,\n \"versionchange\"\n>;\n\ntype IndexDefinition = {\n name: string;\n table: string;\n schema: string;\n columns: string[];\n unique: boolean;\n};\n\nconst META_STORE = \"lofi_meta\";\nconst ROWS_STORE = \"lofi_rows\";\nconst INBOX_STORE = \"lofi_inbox\";\n\nconst INDEX_SCHEMA_TABLE = \"idx_schema_table\";\nconst INDEX_INBOX_SOURCE_UOW = \"idx_inbox_source_uow\";\nconst LEGACY_INBOX_INDEX = \"idx_inbox_source_version\";\n\nexport class IndexedDbAdapter implements LofiAdapter, LofiQueryableAdapter {\n private readonly dbName: string;\n private readonly endpointName: string;\n private readonly schemas: AnySchema[];\n private readonly schemaMap: Map<string, AnySchema>;\n private readonly tableMap: Map<string, Map<string, AnyTable>>;\n private readonly referenceTargets: Map<string, ReferenceTarget>;\n private readonly schemaFingerprint: string;\n private readonly indexDefinitions: IndexDefinition[];\n private readonly ignoreUnknownSchemas: boolean;\n\n private dbPromise?: Promise<LofiDb>;\n\n constructor(options: IndexedDbAdapterOptions) {\n if (!options.endpointName || options.endpointName.trim().length === 0) {\n throw new Error(\"IndexedDbAdapter requires a non-empty endpointName.\");\n }\n\n const schemaMap = new Map<string, AnySchema>();\n const tableMap = new Map<string, Map<string, AnyTable>>();\n const referenceTargets = new Map<string, ReferenceTarget>();\n\n for (const registration of options.schemas) {\n const schema = registration.schema;\n if (!schema.name || schema.name.trim().length === 0) {\n throw new Error(\"IndexedDbAdapter schemas must have a non-empty name.\");\n }\n if (schemaMap.has(schema.name)) {\n throw new Error(`IndexedDbAdapter schema name must be unique: ${schema.name}`);\n }\n\n schemaMap.set(schema.name, schema);\n const tables = new Map<string, AnyTable>();\n for (const [tableName, table] of Object.entries(schema.tables)) {\n tables.set(tableName, table);\n for (const relation of Object.values(table.relations)) {\n for (const [fromColumn] of relation.on) {\n referenceTargets.set(`${schema.name}::${table.name}::${fromColumn}`, {\n schema: schema.name,\n table: relation.table.name,\n });\n }\n }\n }\n tableMap.set(schema.name, tables);\n }\n\n this.dbName = options.dbName ?? `fragno_lofi_${options.endpointName}`;\n this.endpointName = options.endpointName;\n this.schemas = [...schemaMap.values()];\n this.schemaMap = schemaMap;\n this.tableMap = tableMap;\n this.referenceTargets = referenceTargets;\n this.indexDefinitions = buildIndexDefinitions(this.schemas);\n this.schemaFingerprint = buildSchemaFingerprint(this.schemas, this.indexDefinitions);\n this.ignoreUnknownSchemas = options.ignoreUnknownSchemas ?? false;\n }\n\n async applyOutboxEntry(options: {\n sourceKey: string;\n versionstamp: string;\n uowId: string;\n mutations: LofiMutation[];\n }): Promise<{ applied: boolean }> {\n const db = await this.openDatabase();\n\n const knownMutations: Array<{ mutation: LofiMutation; schema: AnySchema; table: AnyTable }> =\n [];\n for (const mutation of options.mutations) {\n const schema = this.schemaMap.get(mutation.schema);\n if (!schema) {\n if (this.ignoreUnknownSchemas) {\n continue;\n }\n throw new Error(`Unknown outbox schema: ${mutation.schema}`);\n }\n const table = this.tableMap.get(mutation.schema)?.get(mutation.table);\n if (!table) {\n if (this.ignoreUnknownSchemas) {\n continue;\n }\n throw new Error(`Unknown outbox table: ${mutation.schema}.${mutation.table}`);\n }\n knownMutations.push({ mutation, schema, table });\n }\n\n const tx = db.transaction([ROWS_STORE, INBOX_STORE, META_STORE], \"readwrite\");\n const rowsStore = tx.objectStore(ROWS_STORE);\n const inboxStore = tx.objectStore(INBOX_STORE);\n const metaStore = tx.objectStore(META_STORE);\n\n const existingInbox = (await inboxStore.get([\n options.sourceKey,\n options.uowId,\n options.versionstamp,\n ])) as InboxRow | undefined;\n if (existingInbox) {\n await tx.done;\n return { applied: false };\n }\n\n try {\n for (const { mutation, schema, table } of knownMutations) {\n await applyMutation({\n mutation,\n schema,\n table,\n endpointName: this.endpointName,\n rowsStore,\n metaStore,\n referenceTargets: this.referenceTargets,\n });\n }\n\n const inboxRow: InboxRow = {\n key: [options.sourceKey, options.uowId, options.versionstamp],\n sourceKey: options.sourceKey,\n uowId: options.uowId,\n versionstamp: options.versionstamp,\n receivedAt: Date.now(),\n };\n await inboxStore.put(inboxRow);\n\n await tx.done;\n return { applied: true };\n } catch (error) {\n try {\n tx.abort();\n } catch {\n // Ignore abort errors; transaction will already be closing.\n }\n try {\n await tx.done;\n } catch {\n // Ignore abort completion errors; original error is more useful.\n }\n throw error;\n }\n }\n\n async applyMutations(mutations: LofiMutation[]): Promise<void> {\n if (mutations.length === 0) {\n return;\n }\n\n const db = await this.openDatabase();\n\n const knownMutations: Array<{ mutation: LofiMutation; schema: AnySchema; table: AnyTable }> =\n [];\n for (const mutation of mutations) {\n const schema = this.schemaMap.get(mutation.schema);\n if (!schema) {\n if (this.ignoreUnknownSchemas) {\n continue;\n }\n throw new Error(`Unknown mutation schema: ${mutation.schema}`);\n }\n const table = this.tableMap.get(mutation.schema)?.get(mutation.table);\n if (!table) {\n if (this.ignoreUnknownSchemas) {\n continue;\n }\n throw new Error(`Unknown mutation table: ${mutation.schema}.${mutation.table}`);\n }\n knownMutations.push({ mutation, schema, table });\n }\n\n const tx = db.transaction([ROWS_STORE, META_STORE], \"readwrite\");\n const rowsStore = tx.objectStore(ROWS_STORE);\n const metaStore = tx.objectStore(META_STORE);\n\n try {\n for (const { mutation, schema, table } of knownMutations) {\n await applyMutation({\n mutation,\n schema,\n table,\n endpointName: this.endpointName,\n rowsStore,\n metaStore,\n referenceTargets: this.referenceTargets,\n });\n }\n\n await tx.done;\n } catch (error) {\n try {\n tx.abort();\n } catch {\n // Ignore abort errors; transaction will already be closing.\n }\n try {\n await tx.done;\n } catch {\n // Ignore abort completion errors; original error is more useful.\n }\n throw error;\n }\n }\n\n async getMeta(key: string): Promise<string | undefined> {\n const db = await this.openDatabase();\n const tx = db.transaction(META_STORE, \"readonly\");\n const store = tx.objectStore(META_STORE);\n const row = (await store.get(key)) as MetaRow | undefined;\n await tx.done;\n return row?.value;\n }\n\n async setMeta(key: string, value: string): Promise<void> {\n const db = await this.openDatabase();\n const tx = db.transaction(META_STORE, \"readwrite\");\n const store = tx.objectStore(META_STORE);\n await store.put({ key, value });\n await tx.done;\n }\n\n createQueryEngine<const T extends AnySchema>(\n schema: T,\n options?: LofiQueryEngineOptions,\n ): LofiQueryInterface<T> {\n return createIndexedDbQueryEngine({\n schema,\n endpointName: this.endpointName,\n getDb: () => this.openDatabase(),\n referenceTargets: this.referenceTargets,\n schemaName: options?.schemaName,\n });\n }\n\n createQueryContext(schemaName: string): IndexedDbQueryContext {\n return {\n endpointName: this.endpointName,\n schemaName,\n getDb: () => this.openDatabase(),\n referenceTargets: this.referenceTargets,\n };\n }\n\n private openDatabase(): Promise<LofiDb> {\n if (!this.dbPromise) {\n this.dbPromise = this.openDatabaseInternal();\n }\n return this.dbPromise;\n }\n\n private async openDatabaseInternal(): Promise<LofiDb> {\n const initialDb = await openDatabaseWithUpgrade(this.dbName, undefined, async (db, tx) => {\n ensureStores(db, tx);\n ensureIndexes(tx, this.indexDefinitions);\n await setMetaInTransaction(\n tx,\n schemaFingerprintKey(this.endpointName),\n this.schemaFingerprint,\n );\n });\n\n const existingFingerprint = await readMetaValue(\n initialDb,\n schemaFingerprintKey(this.endpointName),\n );\n\n if (existingFingerprint === this.schemaFingerprint) {\n return initialDb;\n }\n\n const currentVersion = initialDb.version;\n initialDb.close();\n\n const upgraded = await openDatabaseWithUpgrade(\n this.dbName,\n currentVersion + 1,\n async (db, tx) => {\n ensureStores(db, tx);\n ensureIndexes(tx, this.indexDefinitions);\n await clearEndpointData(tx, this.endpointName);\n await setMetaInTransaction(\n tx,\n schemaFingerprintKey(this.endpointName),\n this.schemaFingerprint,\n );\n },\n );\n\n return upgraded;\n }\n}\nconst schemaFingerprintKey = (endpointName: string) => `${endpointName}::schema_fingerprint`;\nconst cursorKeyDefault = (endpointName: string) => `${endpointName}::outbox`;\nconst seqKey = (endpointName: string, schema: string, table: string) =>\n `${endpointName}::seq::${schema}::${table}`;\n\nconst buildIndexDefinitions = (schemas: AnySchema[]): IndexDefinition[] => {\n const definitions: IndexDefinition[] = [];\n\n for (const schema of schemas) {\n const operations = generateMigrationFromSchema(schema, 0, schema.version);\n for (const op of operations) {\n if (op.type !== \"add-index\") {\n continue;\n }\n definitions.push({\n name: op.name,\n schema: schema.name,\n table: op.table,\n columns: op.columns,\n unique: op.unique,\n });\n }\n }\n\n return definitions;\n};\n\nconst buildSchemaFingerprint = (schemas: AnySchema[], indexes: IndexDefinition[]): string => {\n const payload = {\n inboxKey: \"uowId+versionstamp\",\n schemas: [...schemas]\n .map((schema) => ({\n name: schema.name,\n version: schema.version,\n tables: Object.keys(schema.tables).sort(),\n }))\n .sort((a, b) => a.name.localeCompare(b.name)),\n indexes: [...indexes]\n .map((index) => ({\n schema: index.schema,\n table: index.table,\n name: index.name,\n columns: [...index.columns],\n unique: index.unique,\n }))\n .sort((a, b) =>\n `${a.schema}.${a.table}.${a.name}`.localeCompare(`${b.schema}.${b.table}.${b.name}`),\n ),\n };\n\n return JSON.stringify(payload);\n};\n\nconst ensureStores = <TxStores extends ArrayLike<string>>(\n db: LofiDb,\n tx: UpgradeTx<TxStores>,\n): void => {\n if (!db.objectStoreNames.contains(META_STORE)) {\n db.createObjectStore(META_STORE, { keyPath: \"key\" });\n }\n\n if (!db.objectStoreNames.contains(ROWS_STORE)) {\n const store = db.createObjectStore(ROWS_STORE, { keyPath: \"key\" });\n store.createIndex(INDEX_SCHEMA_TABLE, [\"endpoint\", \"schema\", \"table\"], { unique: false });\n } else {\n const store = tx.objectStore(ROWS_STORE);\n if (!store.indexNames.contains(INDEX_SCHEMA_TABLE)) {\n store.createIndex(INDEX_SCHEMA_TABLE, [\"endpoint\", \"schema\", \"table\"], { unique: false });\n }\n }\n\n if (!db.objectStoreNames.contains(INBOX_STORE)) {\n const store = db.createObjectStore(INBOX_STORE, { keyPath: \"key\" });\n store.createIndex(INDEX_INBOX_SOURCE_UOW, [\"sourceKey\", \"uowId\", \"versionstamp\"], {\n unique: true,\n });\n } else {\n const store = tx.objectStore(INBOX_STORE);\n if (store.indexNames.contains(LEGACY_INBOX_INDEX)) {\n store.deleteIndex(LEGACY_INBOX_INDEX);\n }\n if (store.indexNames.contains(INDEX_INBOX_SOURCE_UOW)) {\n store.deleteIndex(INDEX_INBOX_SOURCE_UOW);\n }\n store.createIndex(INDEX_INBOX_SOURCE_UOW, [\"sourceKey\", \"uowId\", \"versionstamp\"], {\n unique: true,\n });\n }\n};\n\nconst ensureIndexes = <TxStores extends ArrayLike<string>>(\n tx: UpgradeTx<TxStores>,\n indexes: IndexDefinition[],\n): void => {\n const store = tx.objectStore(ROWS_STORE);\n\n for (const index of indexes) {\n const name = `idx__${index.schema}__${index.table}__${index.name}`;\n if (store.indexNames.contains(name)) {\n continue;\n }\n\n const keyPath = [\n \"endpoint\",\n \"schema\",\n \"table\",\n ...index.columns.map((column) => `_lofi.norm.${column}`),\n \"id\",\n ];\n\n store.createIndex(name, keyPath, { unique: index.unique });\n }\n};\n\nconst clearEndpointData = async <TxStores extends ArrayLike<string>>(\n tx: UpgradeTx<TxStores>,\n endpointName: string,\n): Promise<void> => {\n const rowsStore = tx.objectStore(ROWS_STORE);\n const inboxStore = tx.objectStore(INBOX_STORE);\n const metaStore = tx.objectStore(META_STORE);\n\n await deleteRowsForEndpoint(rowsStore, endpointName);\n await deleteWhere(\n inboxStore,\n (row) => isInboxRow(row) && row.sourceKey.startsWith(`${endpointName}::`),\n );\n await deleteWhere(\n metaStore,\n (row) => isMetaRow(row) && row.key === cursorKeyDefault(endpointName),\n );\n};\n\nconst deleteRowsForEndpoint = async <TxStores extends ArrayLike<string>, StoreName extends string>(\n store: UpgradeStore<TxStores, StoreName>,\n endpointName: string,\n): Promise<void> => {\n const index = store.index(INDEX_SCHEMA_TABLE);\n const range = IDBKeyRange.bound([endpointName], [endpointName, \"\\uffff\", \"\\uffff\"]);\n let cursor = await index.openCursor(range);\n while (cursor) {\n await cursor.delete();\n cursor = await cursor.continue();\n }\n};\n\nconst deleteWhere = async <TxStores extends ArrayLike<string>, StoreName extends string>(\n store: UpgradeStore<TxStores, StoreName>,\n predicate: (value: unknown) => boolean,\n): Promise<void> => {\n let cursor = await store.openCursor();\n while (cursor) {\n if (predicate(cursor.value)) {\n await cursor.delete();\n }\n cursor = await cursor.continue();\n }\n};\n\nconst isInboxRow = (value: unknown): value is InboxRow =>\n typeof value === \"object\" &&\n value !== null &&\n \"sourceKey\" in value &&\n typeof (value as { sourceKey?: unknown }).sourceKey === \"string\";\n\nconst isMetaRow = (value: unknown): value is MetaRow =>\n typeof value === \"object\" &&\n value !== null &&\n \"key\" in value &&\n typeof (value as { key?: unknown }).key === \"string\";\n\nconst openDatabaseWithUpgrade = (\n dbName: string,\n version: number | undefined,\n onUpgrade: (db: LofiDb, tx: UpgradeTx<ArrayLike<string>>) => void | Promise<void>,\n): Promise<LofiDb> =>\n openDB(dbName, version, {\n upgrade: async (db, _oldVersion, _newVersion, tx) => {\n await onUpgrade(db, tx as UpgradeTx<ArrayLike<string>>);\n },\n }).then((db) => {\n db.onversionchange = () => db.close();\n return db;\n });\n\nconst readMetaValue = async (db: LofiDb, key: string): Promise<string | undefined> => {\n if (!db.objectStoreNames.contains(META_STORE)) {\n return undefined;\n }\n const tx = db.transaction(META_STORE, \"readonly\");\n const store = tx.objectStore(META_STORE);\n const row = (await store.get(key)) as MetaRow | undefined;\n await tx.done;\n return row?.value;\n};\n\nconst setMetaInTransaction = async <TxStores extends ArrayLike<string>>(\n tx: UpgradeTx<TxStores>,\n key: string,\n value: string,\n): Promise<void> => {\n const store = tx.objectStore(META_STORE);\n await store.put({ key, value });\n};\n\nconst applyMutation = async <\n TxStores extends ArrayLike<string>,\n RowsStoreName extends string,\n MetaStoreName extends string,\n>(options: {\n mutation: LofiMutation;\n schema: AnySchema;\n table: AnyTable;\n endpointName: string;\n rowsStore: WriteStore<TxStores, RowsStoreName>;\n metaStore: WriteStore<TxStores, MetaStoreName>;\n referenceTargets: Map<string, ReferenceTarget>;\n}): Promise<void> => {\n const { mutation, schema, table, endpointName, rowsStore, metaStore, referenceTargets } = options;\n\n const key: LofiRow[\"key\"] = [endpointName, schema.name, table.name, mutation.externalId];\n const existing = (await rowsStore.get(key)) as LofiRow | undefined;\n\n if (mutation.op === \"delete\") {\n if (existing) {\n await rowsStore.delete(key);\n }\n return;\n }\n\n const values = mutation.op === \"create\" ? mutation.values : mutation.set;\n if (existing && existing._lofi.versionstamp.startsWith(\"local-\")) {\n const isMatch = Object.entries(values).every(([column, value]) =>\n Object.is(existing.data[column], value),\n );\n if (isMatch) {\n const row: LofiRow = {\n ...existing,\n data: { ...existing.data, ...values },\n _lofi: {\n ...existing._lofi,\n versionstamp: mutation.versionstamp,\n },\n };\n await rowsStore.put(row);\n return;\n }\n }\n if (!existing && mutation.op === \"update\") {\n return;\n }\n\n const data = existing ? { ...existing.data, ...values } : { ...values };\n\n const internalId = existing\n ? existing._lofi.internalId\n : await allocateInternalId(metaStore, endpointName, schema.name, table.name);\n\n const version = existing ? existing._lofi.version + (mutation.op === \"update\" ? 1 : 0) : 1;\n const norm = await buildNormalizedValues({\n schema,\n table,\n data,\n rowId: mutation.externalId,\n internalId,\n version,\n endpointName,\n rowsStore,\n referenceTargets,\n });\n\n const row: LofiRow = {\n key,\n endpoint: endpointName,\n schema: schema.name,\n table: table.name,\n id: mutation.externalId,\n data,\n _lofi: {\n versionstamp: mutation.versionstamp,\n norm,\n internalId,\n version,\n },\n };\n\n await rowsStore.put(row);\n};\n\nconst allocateInternalId = async <TxStores extends ArrayLike<string>, StoreName extends string>(\n metaStore: WriteStore<TxStores, StoreName>,\n endpointName: string,\n schemaName: string,\n tableName: string,\n): Promise<number> => {\n const key = seqKey(endpointName, schemaName, tableName);\n const existing = (await metaStore.get(key)) as MetaRow | undefined;\n const next = existing ? Number(existing.value) + 1 : 1;\n if (Number.isNaN(next) || next > Number.MAX_SAFE_INTEGER) {\n throw new Error(\n `IndexedDbAdapter internalId overflow for ${schemaName}.${tableName}: ${existing?.value}`,\n );\n }\n await metaStore.put({ key, value: String(next) });\n return next;\n};\n\nconst buildNormalizedValues = async <\n TxStores extends ArrayLike<string>,\n StoreName extends string,\n>(options: {\n schema: AnySchema;\n table: AnyTable;\n data: Record<string, unknown>;\n rowId: string;\n internalId: number;\n version: number;\n endpointName: string;\n rowsStore: WriteStore<TxStores, StoreName>;\n referenceTargets: Map<string, ReferenceTarget>;\n}): Promise<Record<string, unknown>> => {\n const {\n schema,\n table,\n data,\n rowId,\n internalId,\n version,\n endpointName,\n rowsStore,\n referenceTargets,\n } = options;\n\n const norm: Record<string, unknown> = {};\n\n for (const [columnName, column] of Object.entries(table.columns)) {\n norm[columnName] = await resolveColumnValue({\n schema,\n table,\n columnName,\n column,\n data,\n rowId,\n internalId,\n version,\n endpointName,\n rowsStore,\n referenceTargets,\n });\n }\n\n return norm;\n};\n\nconst resolveColumnValue = async <\n TxStores extends ArrayLike<string>,\n StoreName extends string,\n>(options: {\n schema: AnySchema;\n table: AnyTable;\n columnName: string;\n column: AnyColumn;\n data: Record<string, unknown>;\n rowId: string;\n internalId: number;\n version: number;\n endpointName: string;\n rowsStore: WriteStore<TxStores, StoreName>;\n referenceTargets: Map<string, ReferenceTarget>;\n}): Promise<unknown> => {\n const {\n schema,\n table,\n columnName,\n column,\n data,\n rowId,\n internalId,\n version,\n endpointName,\n rowsStore,\n referenceTargets,\n } = options;\n\n if (column.role === \"external-id\") {\n return rowId;\n }\n\n if (column.role === \"internal-id\") {\n return internalId;\n }\n\n if (column.role === \"version\") {\n return version;\n }\n\n if (column.role === \"reference\") {\n const rawValue = data[columnName];\n if (rawValue == null) {\n return rawValue;\n }\n\n if (rawValue instanceof FragnoReference) {\n return coerceInternalIdValue(rawValue.internalId, schema, table, columnName);\n }\n\n if (rawValue instanceof FragnoId) {\n if (rawValue.internalId !== undefined) {\n return coerceInternalIdValue(rawValue.internalId, schema, table, columnName);\n }\n return resolveReferenceExternalId({\n schema,\n table,\n columnName,\n externalId: rawValue.externalId,\n endpointName,\n rowsStore,\n referenceTargets,\n });\n }\n\n if (typeof rawValue === \"number\") {\n throw new Error(\n `Expected reference value to be external ID string for ${schema.name}.${table.name}.${columnName}.`,\n );\n }\n\n if (typeof rawValue === \"bigint\") {\n return coerceInternalIdValue(rawValue, schema, table, columnName);\n }\n\n if (typeof rawValue !== \"string\") {\n throw new Error(\n `Expected reference value to be external ID string for ${schema.name}.${table.name}.${columnName}.`,\n );\n }\n\n return resolveReferenceExternalId({\n schema,\n table,\n columnName,\n externalId: rawValue,\n endpointName,\n rowsStore,\n referenceTargets,\n });\n }\n\n const rawValue = data[columnName];\n if (rawValue === undefined) {\n return undefined;\n }\n if (rawValue === null) {\n return null;\n }\n\n return normalizeValue(rawValue, column);\n};\n\nconst resolveReferenceExternalId = async <\n TxStores extends ArrayLike<string>,\n StoreName extends string,\n>(options: {\n schema: AnySchema;\n table: AnyTable;\n columnName: string;\n externalId: string;\n endpointName: string;\n rowsStore: WriteStore<TxStores, StoreName>;\n referenceTargets: Map<string, ReferenceTarget>;\n}): Promise<number | undefined> => {\n const { schema, table, columnName, externalId, endpointName, rowsStore, referenceTargets } =\n options;\n const target = referenceTargets.get(`${schema.name}::${table.name}::${columnName}`);\n if (!target) {\n return undefined;\n }\n const key: LofiRow[\"key\"] = [endpointName, target.schema, target.table, externalId];\n const referenced = (await rowsStore.get(key)) as LofiRow | undefined;\n if (!referenced) {\n return undefined;\n }\n return referenced._lofi.internalId;\n};\n\nconst coerceInternalIdValue = (\n value: bigint | number,\n schema: AnySchema,\n table: AnyTable,\n columnName: string,\n): number => {\n const asNumber = typeof value === \"bigint\" ? Number(value) : value;\n if (!Number.isSafeInteger(asNumber)) {\n throw new Error(\n `Reference internalId is not a safe integer for ${schema.name}.${table.name}.${columnName}: ${value.toString()}`,\n );\n }\n return asNumber;\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"overlay-manager.d.ts","names":[],"sources":["../../src/optimistic/overlay-manager.ts"],"sourcesContent":[],"mappings":";;;;;;;KAeK,qBAAA,GAAwB,cAAc;KAE/B;EAFP,YAAA,EAAA,MAAA;EAEO,OAAA,EAED,qBAFsB;EAEtB,OAAA,EACA,SADA,EAAA;EACA,QAAA,EACC,KADD,CACO,2BADP,CAAA,OAAA,EAC4C,QAD5C,CAAA,CAAA;EAC4C,oBAAA,CAAA,EAAA,CAAA,OAAA,EACpB,2BADoB,CAAA,OAAA,EACiB,QADjB,CAAA,EAAA,GAC+B,QAD/B;EAArC,KAAA,CAAA,EAER,iBAFQ;EAAN,QAAA,CAAA,EAAA,MAAA;EAC4D,WAAA,CAAA,EAAA,MAAA,EAAA;CAArC;AAAmD,cAMzE,kBANyE,CAAA,WAAA,OAAA,CAAA,CAAA;EAC5E,SAAA,KAAA,EAMQ,iBANR;EAAiB,SAAA,cAAA,EAOA,mBAPA;EAKd,SAAA,cAAkB,EAGJ,kBAHI;EACb,iBAAA,OAAA;EACS,iBAAA,OAAA;EACA,iBAAA,QAAA;EAUkB,iBAAA,QAAA;EAAtB,iBAAA,oBAAA;EAwBa,iBAAA,OAAA;EACxB,WAAA,CAAA,OAAA,EAzBW,qBAyBX,CAzBiC,QAyBjC,CAAA;EACE,iBAAA,CAAA,gBAFsB,SAEtB,CAAA,CAAA,MAAA,EADF,CACE,EAAA,OAAA,CAAA,EAAA,sBAAA,CAAA,EACT,kBADS,CACU,CADV,CAAA;EACU,OAAA,CAAA,OAI4D,CAJ5D,EAAA;IAAnB,KAAA,CAAA,EAI+B,iBAJ/B,EAAA;IAI+B,WAAA,CAAA,EAAA,MAAA,EAAA;EAAgD,CAAA,CAAA,EAAA,OAAA,CAAA,IAAA,CAAA;EAQnE,KAAA,CAAA,CAAA,EAAA,OAAA,CAAA,IAAA,CAAA;EAIa,YAAA,CAAA,OAAA,EAAA,iBAAA,CAAA,EAAoB,OAApB,CAAA,IAAA,CAAA;EAAoB,QAAA,UAAA"}
1
+ {"version":3,"file":"overlay-manager.d.ts","names":[],"sources":["../../src/optimistic/overlay-manager.ts"],"sourcesContent":[],"mappings":";;;;;;;KAgBK,qBAAA,GAAwB,cAAc;KAE/B;EAFP,YAAA,EAAA,MAAA;EAEO,OAAA,EAED,qBAFsB;EAEtB,OAAA,EACA,SADA,EAAA;EACA,QAAA,EACC,KADD,CACO,2BADP,CAAA,OAAA,EAC4C,QAD5C,CAAA,CAAA;EAC4C,oBAAA,CAAA,EAAA,CAAA,OAAA,EACpB,2BADoB,CAAA,OAAA,EACiB,QADjB,CAAA,EAAA,GAC+B,QAD/B;EAArC,KAAA,CAAA,EAER,iBAFQ;EAAN,QAAA,CAAA,EAAA,MAAA;EAC4D,WAAA,CAAA,EAAA,MAAA,EAAA;CAArC;AAAmD,cAMzE,kBANyE,CAAA,WAAA,OAAA,CAAA,CAAA;EAC5E,SAAA,KAAA,EAMQ,iBANR;EAAiB,SAAA,cAAA,EAOA,mBAPA;EAKd,SAAA,cAAkB,EAGJ,kBAHI;EACb,iBAAA,OAAA;EACS,iBAAA,OAAA;EACA,iBAAA,QAAA;EAUkB,iBAAA,QAAA;EAAtB,iBAAA,oBAAA;EAwBa,iBAAA,OAAA;EACxB,WAAA,CAAA,OAAA,EAzBW,qBAyBX,CAzBiC,QAyBjC,CAAA;EACE,iBAAA,CAAA,gBAFsB,SAEtB,CAAA,CAAA,MAAA,EADF,CACE,EAAA,OAAA,CAAA,EAAA,sBAAA,CAAA,EACT,kBADS,CACU,CADV,CAAA;EACU,OAAA,CAAA,OAI4D,CAJ5D,EAAA;IAAnB,KAAA,CAAA,EAI+B,iBAJ/B,EAAA;IAI+B,WAAA,CAAA,EAAA,MAAA,EAAA;EAAgD,CAAA,CAAA,EAAA,OAAA,CAAA,IAAA,CAAA;EAQnE,KAAA,CAAA,CAAA,EAAA,OAAA,CAAA,IAAA,CAAA;EAIa,YAAA,CAAA,OAAA,EAAA,iBAAA,CAAA,EAAoB,OAApB,CAAA,IAAA,CAAA;EAAoB,QAAA,UAAA"}
@@ -1,4 +1,3 @@
1
- import "../adapters/in-memory/store.js";
2
1
  import { InMemoryLofiAdapter } from "../adapters/in-memory/adapter.js";
3
2
  import { StackedLofiAdapter } from "../adapters/stacked/adapter.js";
4
3
  import { createLocalHandlerTx } from "../submit/local-handler-tx.js";
@@ -1 +1 @@
1
- {"version":3,"file":"overlay-manager.js","names":[],"sources":["../../src/optimistic/overlay-manager.ts"],"sourcesContent":["import type { AnySchema } from \"@fragno-dev/db/schema\";\nimport type {\n LofiAdapter,\n LofiQueryEngineOptions,\n LofiQueryInterface,\n LofiSubmitCommand,\n LofiSubmitCommandDefinition,\n LofiQueryableAdapter,\n} from \"../types\";\nimport { createLocalHandlerTx } from \"../submit/local-handler-tx\";\nimport { buildCommandKey, defaultQueueKey, loadSubmitQueue } from \"../submit/queue\";\nimport { InMemoryLofiAdapter } from \"../adapters/in-memory/adapter\";\nimport { InMemoryLofiStore } from \"../adapters/in-memory/store\";\nimport { StackedLofiAdapter } from \"../adapters/stacked/adapter\";\n\ntype OverlayManagerAdapter = LofiAdapter & LofiQueryableAdapter;\n\nexport type OverlayManagerOptions<TContext> = {\n endpointName: string;\n adapter: OverlayManagerAdapter;\n schemas: AnySchema[];\n commands: Array<LofiSubmitCommandDefinition<unknown, TContext>>;\n createCommandContext?: (command: LofiSubmitCommandDefinition<unknown, TContext>) => TContext;\n store?: InMemoryLofiStore;\n queueKey?: string;\n schemaNames?: string[];\n};\n\nexport class LofiOverlayManager<TContext = unknown> {\n readonly store: InMemoryLofiStore;\n readonly overlayAdapter: InMemoryLofiAdapter;\n readonly stackedAdapter: StackedLofiAdapter;\n private readonly adapter: OverlayManagerAdapter;\n private readonly schemas: AnySchema[];\n private readonly commands: Map<string, LofiSubmitCommandDefinition<unknown, TContext>>;\n private readonly queueKey: string;\n private readonly createCommandContext?: (\n command: LofiSubmitCommandDefinition<unknown, TContext>,\n ) => TContext;\n private readonly localTx: ReturnType<typeof createLocalHandlerTx>;\n\n constructor(options: OverlayManagerOptions<TContext>) {\n this.adapter = options.adapter;\n this.schemas = options.schemas;\n this.overlayAdapter = new InMemoryLofiAdapter({\n endpointName: options.endpointName,\n schemas: options.schemas,\n ...(options.store ? { store: options.store } : {}),\n });\n this.store = this.overlayAdapter.store;\n this.stackedAdapter = new StackedLofiAdapter({\n base: this.adapter,\n overlay: this.overlayAdapter,\n schemas: options.schemas,\n });\n this.queueKey = options.queueKey ?? defaultQueueKey(options.endpointName);\n this.commands = new Map(options.commands.map((command) => [buildCommandKey(command), command]));\n this.createCommandContext = options.createCommandContext;\n\n this.localTx = createLocalHandlerTx({\n adapter: this.stackedAdapter,\n schemas: options.schemas,\n });\n }\n\n createQueryEngine<const T extends AnySchema>(\n schema: T,\n options?: LofiQueryEngineOptions,\n ): LofiQueryInterface<T> {\n return this.overlayAdapter.createQueryEngine(schema, options);\n }\n\n async rebuild(options?: { queue?: LofiSubmitCommand[]; schemaNames?: string[] }): Promise<void> {\n this.overlayAdapter.reset();\n const queue = options?.queue ?? (await loadSubmitQueue(this.adapter, this.queueKey));\n for (const command of queue) {\n await this.runCommand(command);\n }\n }\n\n async reset(): Promise<void> {\n this.overlayAdapter.reset();\n }\n\n async applyCommand(command: LofiSubmitCommand): Promise<void> {\n await this.runCommand(command);\n }\n\n private async runCommand(command: LofiSubmitCommand): Promise<void> {\n const key = buildCommandKey(command);\n const definition = this.commands.get(key);\n if (!definition) {\n throw new Error(`Unknown sync command: ${key}`);\n }\n const ctx = this.createCommandContext\n ? this.createCommandContext(definition)\n : ({} as TContext);\n\n await definition.handler({\n input: command.input,\n ctx,\n tx: this.localTx,\n });\n }\n}\n"],"mappings":";;;;;;;AA4BA,IAAa,qBAAb,MAAoD;CAClD,AAAS;CACT,AAAS;CACT,AAAS;CACT,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAGjB,AAAiB;CAEjB,YAAY,SAA0C;AACpD,OAAK,UAAU,QAAQ;AACvB,OAAK,UAAU,QAAQ;AACvB,OAAK,iBAAiB,IAAI,oBAAoB;GAC5C,cAAc,QAAQ;GACtB,SAAS,QAAQ;GACjB,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,OAAO,GAAG,EAAE;GAClD,CAAC;AACF,OAAK,QAAQ,KAAK,eAAe;AACjC,OAAK,iBAAiB,IAAI,mBAAmB;GAC3C,MAAM,KAAK;GACX,SAAS,KAAK;GACd,SAAS,QAAQ;GAClB,CAAC;AACF,OAAK,WAAW,QAAQ,YAAY,gBAAgB,QAAQ,aAAa;AACzE,OAAK,WAAW,IAAI,IAAI,QAAQ,SAAS,KAAK,YAAY,CAAC,gBAAgB,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC/F,OAAK,uBAAuB,QAAQ;AAEpC,OAAK,UAAU,qBAAqB;GAClC,SAAS,KAAK;GACd,SAAS,QAAQ;GAClB,CAAC;;CAGJ,kBACE,QACA,SACuB;AACvB,SAAO,KAAK,eAAe,kBAAkB,QAAQ,QAAQ;;CAG/D,MAAM,QAAQ,SAAkF;AAC9F,OAAK,eAAe,OAAO;EAC3B,MAAM,QAAQ,SAAS,SAAU,MAAM,gBAAgB,KAAK,SAAS,KAAK,SAAS;AACnF,OAAK,MAAM,WAAW,MACpB,OAAM,KAAK,WAAW,QAAQ;;CAIlC,MAAM,QAAuB;AAC3B,OAAK,eAAe,OAAO;;CAG7B,MAAM,aAAa,SAA2C;AAC5D,QAAM,KAAK,WAAW,QAAQ;;CAGhC,MAAc,WAAW,SAA2C;EAClE,MAAM,MAAM,gBAAgB,QAAQ;EACpC,MAAM,aAAa,KAAK,SAAS,IAAI,IAAI;AACzC,MAAI,CAAC,WACH,OAAM,IAAI,MAAM,yBAAyB,MAAM;EAEjD,MAAM,MAAM,KAAK,uBACb,KAAK,qBAAqB,WAAW,GACpC,EAAE;AAEP,QAAM,WAAW,QAAQ;GACvB,OAAO,QAAQ;GACf;GACA,IAAI,KAAK;GACV,CAAC"}
1
+ {"version":3,"file":"overlay-manager.js","names":[],"sources":["../../src/optimistic/overlay-manager.ts"],"sourcesContent":["import type { AnySchema } from \"@fragno-dev/db/schema\";\n\nimport { InMemoryLofiAdapter } from \"../adapters/in-memory/adapter\";\nimport { InMemoryLofiStore } from \"../adapters/in-memory/store\";\nimport { StackedLofiAdapter } from \"../adapters/stacked/adapter\";\nimport { createLocalHandlerTx } from \"../submit/local-handler-tx\";\nimport { buildCommandKey, defaultQueueKey, loadSubmitQueue } from \"../submit/queue\";\nimport type {\n LofiAdapter,\n LofiQueryEngineOptions,\n LofiQueryInterface,\n LofiSubmitCommand,\n LofiSubmitCommandDefinition,\n LofiQueryableAdapter,\n} from \"../types\";\n\ntype OverlayManagerAdapter = LofiAdapter & LofiQueryableAdapter;\n\nexport type OverlayManagerOptions<TContext> = {\n endpointName: string;\n adapter: OverlayManagerAdapter;\n schemas: AnySchema[];\n commands: Array<LofiSubmitCommandDefinition<unknown, TContext>>;\n createCommandContext?: (command: LofiSubmitCommandDefinition<unknown, TContext>) => TContext;\n store?: InMemoryLofiStore;\n queueKey?: string;\n schemaNames?: string[];\n};\n\nexport class LofiOverlayManager<TContext = unknown> {\n readonly store: InMemoryLofiStore;\n readonly overlayAdapter: InMemoryLofiAdapter;\n readonly stackedAdapter: StackedLofiAdapter;\n private readonly adapter: OverlayManagerAdapter;\n private readonly schemas: AnySchema[];\n private readonly commands: Map<string, LofiSubmitCommandDefinition<unknown, TContext>>;\n private readonly queueKey: string;\n private readonly createCommandContext?: (\n command: LofiSubmitCommandDefinition<unknown, TContext>,\n ) => TContext;\n private readonly localTx: ReturnType<typeof createLocalHandlerTx>;\n\n constructor(options: OverlayManagerOptions<TContext>) {\n this.adapter = options.adapter;\n this.schemas = options.schemas;\n this.overlayAdapter = new InMemoryLofiAdapter({\n endpointName: options.endpointName,\n schemas: options.schemas,\n ...(options.store ? { store: options.store } : {}),\n });\n this.store = this.overlayAdapter.store;\n this.stackedAdapter = new StackedLofiAdapter({\n base: this.adapter,\n overlay: this.overlayAdapter,\n schemas: options.schemas,\n });\n this.queueKey = options.queueKey ?? defaultQueueKey(options.endpointName);\n this.commands = new Map(options.commands.map((command) => [buildCommandKey(command), command]));\n this.createCommandContext = options.createCommandContext;\n\n this.localTx = createLocalHandlerTx({\n adapter: this.stackedAdapter,\n schemas: options.schemas,\n });\n }\n\n createQueryEngine<const T extends AnySchema>(\n schema: T,\n options?: LofiQueryEngineOptions,\n ): LofiQueryInterface<T> {\n return this.overlayAdapter.createQueryEngine(schema, options);\n }\n\n async rebuild(options?: { queue?: LofiSubmitCommand[]; schemaNames?: string[] }): Promise<void> {\n this.overlayAdapter.reset();\n const queue = options?.queue ?? (await loadSubmitQueue(this.adapter, this.queueKey));\n for (const command of queue) {\n await this.runCommand(command);\n }\n }\n\n async reset(): Promise<void> {\n this.overlayAdapter.reset();\n }\n\n async applyCommand(command: LofiSubmitCommand): Promise<void> {\n await this.runCommand(command);\n }\n\n private async runCommand(command: LofiSubmitCommand): Promise<void> {\n const key = buildCommandKey(command);\n const definition = this.commands.get(key);\n if (!definition) {\n throw new Error(`Unknown sync command: ${key}`);\n }\n const ctx = this.createCommandContext\n ? this.createCommandContext(definition)\n : ({} as TContext);\n\n await definition.handler({\n input: command.input,\n ctx,\n tx: this.localTx,\n });\n }\n}\n"],"mappings":";;;;;;AA6BA,IAAa,qBAAb,MAAoD;CAClD,AAAS;CACT,AAAS;CACT,AAAS;CACT,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAGjB,AAAiB;CAEjB,YAAY,SAA0C;AACpD,OAAK,UAAU,QAAQ;AACvB,OAAK,UAAU,QAAQ;AACvB,OAAK,iBAAiB,IAAI,oBAAoB;GAC5C,cAAc,QAAQ;GACtB,SAAS,QAAQ;GACjB,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,OAAO,GAAG,EAAE;GAClD,CAAC;AACF,OAAK,QAAQ,KAAK,eAAe;AACjC,OAAK,iBAAiB,IAAI,mBAAmB;GAC3C,MAAM,KAAK;GACX,SAAS,KAAK;GACd,SAAS,QAAQ;GAClB,CAAC;AACF,OAAK,WAAW,QAAQ,YAAY,gBAAgB,QAAQ,aAAa;AACzE,OAAK,WAAW,IAAI,IAAI,QAAQ,SAAS,KAAK,YAAY,CAAC,gBAAgB,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC/F,OAAK,uBAAuB,QAAQ;AAEpC,OAAK,UAAU,qBAAqB;GAClC,SAAS,KAAK;GACd,SAAS,QAAQ;GAClB,CAAC;;CAGJ,kBACE,QACA,SACuB;AACvB,SAAO,KAAK,eAAe,kBAAkB,QAAQ,QAAQ;;CAG/D,MAAM,QAAQ,SAAkF;AAC9F,OAAK,eAAe,OAAO;EAC3B,MAAM,QAAQ,SAAS,SAAU,MAAM,gBAAgB,KAAK,SAAS,KAAK,SAAS;AACnF,OAAK,MAAM,WAAW,MACpB,OAAM,KAAK,WAAW,QAAQ;;CAIlC,MAAM,QAAuB;AAC3B,OAAK,eAAe,OAAO;;CAG7B,MAAM,aAAa,SAA2C;AAC5D,QAAM,KAAK,WAAW,QAAQ;;CAGhC,MAAc,WAAW,SAA2C;EAClE,MAAM,MAAM,gBAAgB,QAAQ;EACpC,MAAM,aAAa,KAAK,SAAS,IAAI,IAAI;AACzC,MAAI,CAAC,WACH,OAAM,IAAI,MAAM,yBAAyB,MAAM;EAEjD,MAAM,MAAM,KAAK,uBACb,KAAK,qBAAqB,WAAW,GACpC,EAAE;AAEP,QAAM,WAAW,QAAQ;GACvB,OAAO,QAAQ;GACf;GACA,IAAI,KAAK;GACV,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"decode.d.ts","names":[],"sources":["../../src/outbox/decode.ts"],"sourcesContent":[],"mappings":";;;iBAGgB,mBAAA,oBAAuC"}
1
+ {"version":3,"file":"decode.d.ts","names":[],"sources":["../../src/outbox/decode.ts"],"sourcesContent":[],"mappings":";;;iBAIgB,mBAAA,oBAAuC"}
@@ -1 +1 @@
1
- {"version":3,"file":"decode.js","names":[],"sources":["../../src/outbox/decode.ts"],"sourcesContent":["import type { OutboxPayload } from \"@fragno-dev/db\";\nimport superjson, { type SuperJSONResult } from \"superjson\";\n\nexport function decodeOutboxPayload(payload: unknown): OutboxPayload {\n const decoded = superjson.deserialize(payload as SuperJSONResult);\n if (!isOutboxPayload(decoded)) {\n throw new Error(\"Invalid outbox payload\");\n }\n\n for (const mutation of decoded.mutations) {\n const schema = mutation?.schema;\n if (typeof schema !== \"string\" || schema.trim().length === 0) {\n throw new Error(\"Outbox mutation schema is required\");\n }\n }\n\n return decoded;\n}\n\nfunction isOutboxPayload(value: unknown): value is OutboxPayload {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const payload = value as OutboxPayload;\n return payload.version === 1 && Array.isArray(payload.mutations);\n}\n"],"mappings":";;;AAGA,SAAgB,oBAAoB,SAAiC;CACnE,MAAM,UAAU,UAAU,YAAY,QAA2B;AACjE,KAAI,CAAC,gBAAgB,QAAQ,CAC3B,OAAM,IAAI,MAAM,yBAAyB;AAG3C,MAAK,MAAM,YAAY,QAAQ,WAAW;EACxC,MAAM,SAAS,UAAU;AACzB,MAAI,OAAO,WAAW,YAAY,OAAO,MAAM,CAAC,WAAW,EACzD,OAAM,IAAI,MAAM,qCAAqC;;AAIzD,QAAO;;AAGT,SAAS,gBAAgB,OAAwC;AAC/D,KAAI,CAAC,SAAS,OAAO,UAAU,SAC7B,QAAO;CAGT,MAAM,UAAU;AAChB,QAAO,QAAQ,YAAY,KAAK,MAAM,QAAQ,QAAQ,UAAU"}
1
+ {"version":3,"file":"decode.js","names":[],"sources":["../../src/outbox/decode.ts"],"sourcesContent":["import superjson, { type SuperJSONResult } from \"superjson\";\n\nimport type { OutboxPayload } from \"@fragno-dev/db\";\n\nexport function decodeOutboxPayload(payload: unknown): OutboxPayload {\n const decoded = superjson.deserialize(payload as SuperJSONResult);\n if (!isOutboxPayload(decoded)) {\n throw new Error(\"Invalid outbox payload\");\n }\n\n for (const mutation of decoded.mutations) {\n const schema = mutation?.schema;\n if (typeof schema !== \"string\" || schema.trim().length === 0) {\n throw new Error(\"Outbox mutation schema is required\");\n }\n }\n\n return decoded;\n}\n\nfunction isOutboxPayload(value: unknown): value is OutboxPayload {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const payload = value as OutboxPayload;\n return payload.version === 1 && Array.isArray(payload.mutations);\n}\n"],"mappings":";;;AAIA,SAAgB,oBAAoB,SAAiC;CACnE,MAAM,UAAU,UAAU,YAAY,QAA2B;AACjE,KAAI,CAAC,gBAAgB,QAAQ,CAC3B,OAAM,IAAI,MAAM,yBAAyB;AAG3C,MAAK,MAAM,YAAY,QAAQ,WAAW;EACxC,MAAM,SAAS,UAAU;AACzB,MAAI,OAAO,WAAW,YAAY,OAAO,MAAM,CAAC,WAAW,EACzD,OAAM,IAAI,MAAM,qCAAqC;;AAIzD,QAAO;;AAGT,SAAS,gBAAgB,OAAwC;AAC/D,KAAI,CAAC,SAAS,OAAO,UAAU,SAC7B,QAAO;CAGT,MAAM,UAAU;AAChB,QAAO,QAAQ,YAAY,KAAK,MAAM,QAAQ,QAAQ,UAAU"}
@@ -1 +1 @@
1
- {"version":3,"file":"uow.d.ts","names":[],"sources":["../../src/outbox/uow.ts"],"sourcesContent":[],"mappings":";;;;;iBAIgB,8BAAA,YACH,2BACA,eAAe,aACzB,kBAAkB"}
1
+ {"version":3,"file":"uow.d.ts","names":[],"sources":["../../src/outbox/uow.ts"],"sourcesContent":[],"mappings":";;;;;iBAKgB,8BAAA,YACH,2BACA,eAAe,aACzB,kBAAkB"}
@@ -1 +1 @@
1
- {"version":3,"file":"uow.js","names":[],"sources":["../../src/outbox/uow.ts"],"sourcesContent":["import type { AnySchema } from \"@fragno-dev/db/schema\";\nimport type { MutationOperation } from \"@fragno-dev/db/unit-of-work\";\nimport type { LofiMutation } from \"../types\";\n\nexport function outboxMutationsToUowOperations(\n mutations: LofiMutation[],\n schemaMap: Record<string, AnySchema>,\n): MutationOperation<AnySchema>[] {\n return mutations.map((mutation) => {\n const schema = schemaMap[mutation.schema];\n if (!schema) {\n throw new Error(`Unknown outbox schema: ${mutation.schema}`);\n }\n\n if (mutation.op === \"create\") {\n return {\n type: \"create\",\n schema,\n table: mutation.table,\n values: mutation.values,\n generatedExternalId: mutation.externalId,\n };\n }\n\n if (mutation.op === \"update\") {\n return {\n type: \"update\",\n schema,\n table: mutation.table,\n id: mutation.externalId,\n checkVersion: false,\n set: mutation.set,\n };\n }\n\n return {\n type: \"delete\",\n schema,\n table: mutation.table,\n id: mutation.externalId,\n checkVersion: false,\n };\n });\n}\n"],"mappings":";AAIA,SAAgB,+BACd,WACA,WACgC;AAChC,QAAO,UAAU,KAAK,aAAa;EACjC,MAAM,SAAS,UAAU,SAAS;AAClC,MAAI,CAAC,OACH,OAAM,IAAI,MAAM,0BAA0B,SAAS,SAAS;AAG9D,MAAI,SAAS,OAAO,SAClB,QAAO;GACL,MAAM;GACN;GACA,OAAO,SAAS;GAChB,QAAQ,SAAS;GACjB,qBAAqB,SAAS;GAC/B;AAGH,MAAI,SAAS,OAAO,SAClB,QAAO;GACL,MAAM;GACN;GACA,OAAO,SAAS;GAChB,IAAI,SAAS;GACb,cAAc;GACd,KAAK,SAAS;GACf;AAGH,SAAO;GACL,MAAM;GACN;GACA,OAAO,SAAS;GAChB,IAAI,SAAS;GACb,cAAc;GACf;GACD"}
1
+ {"version":3,"file":"uow.js","names":[],"sources":["../../src/outbox/uow.ts"],"sourcesContent":["import type { AnySchema } from \"@fragno-dev/db/schema\";\nimport type { MutationOperation } from \"@fragno-dev/db/unit-of-work\";\n\nimport type { LofiMutation } from \"../types\";\n\nexport function outboxMutationsToUowOperations(\n mutations: LofiMutation[],\n schemaMap: Record<string, AnySchema>,\n): MutationOperation<AnySchema>[] {\n return mutations.map((mutation) => {\n const schema = schemaMap[mutation.schema];\n if (!schema) {\n throw new Error(`Unknown outbox schema: ${mutation.schema}`);\n }\n\n if (mutation.op === \"create\") {\n return {\n type: \"create\",\n schema,\n table: mutation.table,\n values: mutation.values,\n generatedExternalId: mutation.externalId,\n };\n }\n\n if (mutation.op === \"update\") {\n return {\n type: \"update\",\n schema,\n table: mutation.table,\n id: mutation.externalId,\n checkVersion: false,\n set: mutation.set,\n };\n }\n\n return {\n type: \"delete\",\n schema,\n table: mutation.table,\n id: mutation.externalId,\n checkVersion: false,\n };\n });\n}\n"],"mappings":";AAKA,SAAgB,+BACd,WACA,WACgC;AAChC,QAAO,UAAU,KAAK,aAAa;EACjC,MAAM,SAAS,UAAU,SAAS;AAClC,MAAI,CAAC,OACH,OAAM,IAAI,MAAM,0BAA0B,SAAS,SAAS;AAG9D,MAAI,SAAS,OAAO,SAClB,QAAO;GACL,MAAM;GACN;GACA,OAAO,SAAS;GAChB,QAAQ,SAAS;GACjB,qBAAqB,SAAS;GAC/B;AAGH,MAAI,SAAS,OAAO,SAClB,QAAO;GACL,MAAM;GACN;GACA,OAAO,SAAS;GAChB,IAAI,SAAS;GACb,cAAc;GACd,KAAK,SAAS;GACf;AAGH,SAAO;GACL,MAAM;GACN;GACA,OAAO,SAAS;GAChB,IAAI,SAAS;GACb,cAAc;GACf;GACD"}
@@ -1,5 +1,5 @@
1
1
  import { AnyColumn } from "@fragno-dev/db/schema";
2
- import { DbNow } from "@fragno-dev/db";
2
+ import { DbInterval, DbIntervalInput, DbNow } from "@fragno-dev/db";
3
3
 
4
4
  //#region src/query/conditions.d.ts
5
5
  type Condition = {
@@ -24,6 +24,7 @@ type ConditionBuilder<Columns extends Record<string, AnyColumn>> = {
24
24
  isNull: (a: keyof Columns) => Condition;
25
25
  isNotNull: (a: keyof Columns) => Condition;
26
26
  now: () => DbNow;
27
+ interval: (input: DbIntervalInput) => DbInterval;
27
28
  };
28
29
  declare const stringOperators: readonly ["contains", "starts with", "ends with", "not contains", "not starts with", "not ends with"];
29
30
  declare const arrayOperators: readonly ["in", "not in"];
@@ -1 +1 @@
1
- {"version":3,"file":"conditions.d.ts","names":[],"sources":["../../src/query/conditions.ts"],"sourcesContent":[],"mappings":";;;;KAKY,SAAA;EAAA,IAAA,EAAA,SAAS;EAGZ,CAAA,EAAA,SAAA;EACO,QAAA,EAAA,QAAA;EACP,CAAA,EAAA,SAAA,GAAA,OAAA,GAAA,IAAA;CAII,GAAA;EAID,IAAA,EAAA,IAAA,GAAA,KAAA;EAAS,KAAA,EAJR,SAIQ,EAAA;AAGrB,CAAA,GAAY;EAAgD,IAAA,EAAA,KAAA;EAAf,IAAA,EAHjC,SAGiC;CACpB;AAClB,KAFK,gBAEL,CAAA,gBAFsC,MAEtC,CAAA,MAAA,EAFqD,SAErD,CAAA,CAAA,GAAA;EACe,CAAA,gBAAA,MAFG,OAEH,CAAA,CAAA,CAAA,EADf,OACe,EAAA,QAAA,EAAA,CAAA,OAAA,cAAA,CAAA,CAAA,MAAA,CAAA,GAAA,CAAA,OAAkC,eAAlC,CAAA,CAAA,MAAA,CAAA,EAAA,CAAA,EACf,OADe,CACP,OADO,CAAA,CAAA,KAAA,CAAA,GAAA,IAAA,CAAA,EAEjB,SAFiB;EAAkC,CAAA,gBAAA,MAI/B,OAJ+B,CAAA,CAAA,CAAA,EAKjD,OALiD,EAAA,QAAA,EAAA,CAAA,OAMlC,cANkC,CAAA,CAAA,MAAA,CAAA,EAAA,CAAA,EAOjD,OAPiD,CAOzC,OAPyC,CAAA,CAAA,KAAA,CAAA,EAAA,CAAA,EAQnD,SARmD;EACjD,CAAA,gBAAA,MASkB,OATlB,CAAA,CAAA,CAAA,EAS8B,OAT9B,CAAA,EASwC,SATxC;EAAQ,GAAA,EAAA,CAAA,GAAA,CAAA,EAAA,CAWA,SAXA,GAAA,OAAA,CAAA,EAAA,EAAA,GAW2B,SAX3B,GAAA,OAAA;EACV,EAAA,EAAA,CAAA,GAAA,CAAA,EAAA,CAWS,SAXT,GAAA,OAAA,CAAA,EAAA,EAAA,GAWoC,SAXpC,GAAA,OAAA;EAEoB,GAAA,EAAA,CAAA,CAAA,EAUd,SAVc,GAAA,OAAA,EAAA,GAUU,SAVV,GAAA,OAAA;EAClB,MAAA,EAAA,CAAA,CAAA,EAAA,MAWa,OAXb,EAAA,GAWyB,SAXzB;EACe,SAAA,EAAA,CAAA,CAAA,EAAA,MAWC,OAXD,EAAA,GAWa,SAXb;EACf,GAAA,EAAA,GAAA,GAWM,KAXN;CAAQ;cAcT,eAbD,EAAA,SAAA,CAAA,UAAA,EAAA,aAAA,EAAA,WAAA,EAAA,cAAA,EAAA,iBAAA,EAAA,eAAA,CAAA;cAuBC,cArBmB,EAAA,SAAA,CAAA,IAAA,EAAA,QAAA,CAAA;cAuBnB,cAvB+B,EAAA,SAAA,CAAA,GAAA,EAAA,IAAA,EAAA,GAAA,EAAA,IAAA,EAAA,GAAA,EAAA,IAAA,EAAA,IAAA,EAAA,QAAA,CAAA;AAAU,cAyBlC,SAzBkC,EAAA,SAAA,CAAA,GAAA,EAAA,IAAA,EAAA,GAAA,EAAA,IAAA,EAAA,GAAA,EAAA,IAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,QAAA,EAAA,UAAA,EAAA,aAAA,EAAA,WAAA,EAAA,cAAA,EAAA,iBAAA,EAAA,eAAA,CAAA;AAEhC,KAyBH,QAAA,GAzBG,CAAA,OAyBgB,SAzBhB,CAAA,CAAA,MAAA,CAAA"}
1
+ {"version":3,"file":"conditions.d.ts","names":[],"sources":["../../src/query/conditions.ts"],"sourcesContent":[],"mappings":";;;;KAYY,SAAA;EAAA,IAAA,EAAA,SAAS;EAGZ,CAAA,EAAA,SAAA;EACO,QAAA,EAAA,QAAA;EACP,CAAA,EAAA,SAAA,GAAA,OAAA,GAAA,IAAA;CAII,GAAA;EAID,IAAA,EAAA,IAAA,GAAA,KAAA;EAAS,KAAA,EAJR,SAIQ,EAAA;AAGrB,CAAA,GAAY;EAAgD,IAAA,EAAA,KAAA;EAAf,IAAA,EAHjC,SAGiC;CACpB;AAClB,KAFK,gBAEL,CAAA,gBAFsC,MAEtC,CAAA,MAAA,EAFqD,SAErD,CAAA,CAAA,GAAA;EACe,CAAA,gBAAA,MAFG,OAEH,CAAA,CAAA,CAAA,EADf,OACe,EAAA,QAAA,EAAA,CAAA,OAAA,cAAA,CAAA,CAAA,MAAA,CAAA,GAAA,CAAA,OAAkC,eAAlC,CAAA,CAAA,MAAA,CAAA,EAAA,CAAA,EACf,OADe,CACP,OADO,CAAA,CAAA,KAAA,CAAA,GAAA,IAAA,CAAA,EAEjB,SAFiB;EAAkC,CAAA,gBAAA,MAI/B,OAJ+B,CAAA,CAAA,CAAA,EAKjD,OALiD,EAAA,QAAA,EAAA,CAAA,OAMlC,cANkC,CAAA,CAAA,MAAA,CAAA,EAAA,CAAA,EAOjD,OAPiD,CAOzC,OAPyC,CAAA,CAAA,KAAA,CAAA,EAAA,CAAA,EAQnD,SARmD;EACjD,CAAA,gBAAA,MASkB,OATlB,CAAA,CAAA,CAAA,EAS8B,OAT9B,CAAA,EASwC,SATxC;EAAQ,GAAA,EAAA,CAAA,GAAA,CAAA,EAAA,CAWA,SAXA,GAAA,OAAA,CAAA,EAAA,EAAA,GAW2B,SAX3B,GAAA,OAAA;EACV,EAAA,EAAA,CAAA,GAAA,CAAA,EAAA,CAWS,SAXT,GAAA,OAAA,CAAA,EAAA,EAAA,GAWoC,SAXpC,GAAA,OAAA;EAEoB,GAAA,EAAA,CAAA,CAAA,EAUd,SAVc,GAAA,OAAA,EAAA,GAUU,SAVV,GAAA,OAAA;EAClB,MAAA,EAAA,CAAA,CAAA,EAAA,MAWa,OAXb,EAAA,GAWyB,SAXzB;EACe,SAAA,EAAA,CAAA,CAAA,EAAA,MAWC,OAXD,EAAA,GAWa,SAXb;EACf,GAAA,EAAA,GAAA,GAWM,KAXN;EAAQ,QAAA,EAAA,CAAA,KAAA,EAYK,eAZL,EAAA,GAYyB,UAZzB;CACV;cAcC,eAZmB,EAAA,SAAA,CAAA,UAAA,EAAA,aAAA,EAAA,WAAA,EAAA,cAAA,EAAA,iBAAA,EAAA,eAAA,CAAA;cAsBnB,cAtB+B,EAAA,SAAA,CAAA,IAAA,EAAA,QAAA,CAAA;cAwB/B,cAxByC,EAAA,SAAA,CAAA,GAAA,EAAA,IAAA,EAAA,GAAA,EAAA,IAAA,EAAA,GAAA,EAAA,IAAA,EAAA,IAAA,EAAA,QAAA,CAAA;AAEhC,cAwBF,SAxBE,EAAA,SAAA,CAAA,GAAA,EAAA,IAAA,EAAA,GAAA,EAAA,IAAA,EAAA,GAAA,EAAA,IAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,QAAA,EAAA,UAAA,EAAA,aAAA,EAAA,WAAA,EAAA,cAAA,EAAA,iBAAA,EAAA,eAAA,CAAA;AAA2B,KA0B9B,QAAA,GA1B8B,CAAA,OA0BX,SA1BW,CAAA,CAAA,MAAA,CAAA"}
@@ -1,4 +1,4 @@
1
- import { dbNow } from "@fragno-dev/db";
1
+ import { dbInterval, dbNow } from "@fragno-dev/db";
2
2
 
3
3
  //#region src/query/conditions.ts
4
4
  const stringOperators = [
@@ -52,6 +52,7 @@ function createBuilder(columns) {
52
52
  builder.isNull = (a) => builder(a, "is", null);
53
53
  builder.isNotNull = (a) => builder(a, "is not", null);
54
54
  builder.now = () => dbNow();
55
+ builder.interval = (input) => dbInterval(input);
55
56
  builder.not = (condition) => {
56
57
  if (typeof condition === "boolean") return !condition;
57
58
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"conditions.js","names":["builder: ConditionBuilder<Columns>"],"sources":["../../src/query/conditions.ts"],"sourcesContent":["import { dbNow, type DbNow } from \"@fragno-dev/db\";\nimport type { AnyColumn } from \"@fragno-dev/db/schema\";\n\nexport type ConditionType = \"compare\" | \"and\" | \"or\" | \"not\";\n\nexport type Condition =\n | {\n type: \"compare\";\n a: AnyColumn;\n operator: Operator;\n b: AnyColumn | unknown | null;\n }\n | {\n type: \"or\" | \"and\";\n items: Condition[];\n }\n | {\n type: \"not\";\n item: Condition;\n };\n\nexport type ConditionBuilder<Columns extends Record<string, AnyColumn>> = {\n <ColName extends keyof Columns>(\n a: ColName,\n operator: (typeof valueOperators)[number] | (typeof stringOperators)[number],\n b: Columns[ColName][\"$in\"] | null,\n ): Condition;\n\n <ColName extends keyof Columns>(\n a: ColName,\n operator: (typeof arrayOperators)[number],\n b: Columns[ColName][\"$in\"][],\n ): Condition;\n\n <ColName extends keyof Columns>(a: ColName): Condition;\n\n and: (...v: (Condition | boolean)[]) => Condition | boolean;\n or: (...v: (Condition | boolean)[]) => Condition | boolean;\n not: (v: Condition | boolean) => Condition | boolean;\n\n isNull: (a: keyof Columns) => Condition;\n isNotNull: (a: keyof Columns) => Condition;\n now: () => DbNow;\n};\n\nconst stringOperators = [\n \"contains\",\n \"starts with\",\n \"ends with\",\n\n \"not contains\",\n \"not starts with\",\n \"not ends with\",\n] as const;\n\nconst arrayOperators = [\"in\", \"not in\"] as const;\n\nconst valueOperators = [\"=\", \"!=\", \">\", \">=\", \"<\", \"<=\", \"is\", \"is not\"] as const;\n\nexport const operators = [...valueOperators, ...arrayOperators, ...stringOperators] as const;\n\nexport type Operator = (typeof operators)[number];\n\nexport function createBuilder<Columns extends Record<string, AnyColumn>>(\n columns: Columns,\n): ConditionBuilder<Columns> {\n function col(name: keyof Columns) {\n const out = columns[name];\n if (!out) {\n throw new Error(`Invalid column name ${String(name)}`);\n }\n\n return out;\n }\n\n const builder: ConditionBuilder<Columns> = (...args: [string, Operator, unknown] | [string]) => {\n if (args.length === 3) {\n const [a, operator, b] = args;\n\n if (!operators.includes(operator)) {\n throw new Error(`Unsupported operator: ${operator}`);\n }\n\n return {\n type: \"compare\",\n a: col(a),\n b,\n operator,\n };\n }\n\n return {\n type: \"compare\",\n a: col(args[0]),\n operator: \"=\",\n b: true,\n };\n };\n\n builder.isNull = (a) => builder(a, \"is\", null);\n builder.isNotNull = (a) => builder(a, \"is not\", null);\n builder.now = () => dbNow();\n builder.not = (condition) => {\n if (typeof condition === \"boolean\") {\n return !condition;\n }\n\n return {\n type: \"not\",\n item: condition,\n };\n };\n\n builder.or = (...conditions) => {\n const out = {\n type: \"or\",\n items: [] as Condition[],\n } as const;\n\n for (const item of conditions) {\n if (item === true) {\n return true;\n }\n if (item === false) {\n continue;\n }\n\n out.items.push(item);\n }\n\n if (out.items.length === 0) {\n return false;\n }\n return out;\n };\n\n builder.and = (...conditions) => {\n const out = {\n type: \"and\",\n items: [] as Condition[],\n } as const;\n\n for (const item of conditions) {\n if (item === true) {\n continue;\n }\n if (item === false) {\n return false;\n }\n\n out.items.push(item);\n }\n\n if (out.items.length === 0) {\n return true;\n }\n return out;\n };\n\n return builder;\n}\n\nexport function buildCondition<T, Columns extends Record<string, AnyColumn>>(\n columns: Columns,\n input: (builder: ConditionBuilder<Columns>) => T,\n): T {\n return input(createBuilder(columns));\n}\n"],"mappings":";;;AA6CA,MAAM,kBAAkB;CACtB;CACA;CACA;CAEA;CACA;CACA;CACD;AAED,MAAM,iBAAiB,CAAC,MAAM,SAAS;AAEvC,MAAM,iBAAiB;CAAC;CAAK;CAAM;CAAK;CAAM;CAAK;CAAM;CAAM;CAAS;AAExE,MAAa,YAAY;CAAC,GAAG;CAAgB,GAAG;CAAgB,GAAG;CAAgB;AAInF,SAAgB,cACd,SAC2B;CAC3B,SAAS,IAAI,MAAqB;EAChC,MAAM,MAAM,QAAQ;AACpB,MAAI,CAAC,IACH,OAAM,IAAI,MAAM,uBAAuB,OAAO,KAAK,GAAG;AAGxD,SAAO;;CAGT,MAAMA,WAAsC,GAAG,SAAiD;AAC9F,MAAI,KAAK,WAAW,GAAG;GACrB,MAAM,CAAC,GAAG,UAAU,KAAK;AAEzB,OAAI,CAAC,UAAU,SAAS,SAAS,CAC/B,OAAM,IAAI,MAAM,yBAAyB,WAAW;AAGtD,UAAO;IACL,MAAM;IACN,GAAG,IAAI,EAAE;IACT;IACA;IACD;;AAGH,SAAO;GACL,MAAM;GACN,GAAG,IAAI,KAAK,GAAG;GACf,UAAU;GACV,GAAG;GACJ;;AAGH,SAAQ,UAAU,MAAM,QAAQ,GAAG,MAAM,KAAK;AAC9C,SAAQ,aAAa,MAAM,QAAQ,GAAG,UAAU,KAAK;AACrD,SAAQ,YAAY,OAAO;AAC3B,SAAQ,OAAO,cAAc;AAC3B,MAAI,OAAO,cAAc,UACvB,QAAO,CAAC;AAGV,SAAO;GACL,MAAM;GACN,MAAM;GACP;;AAGH,SAAQ,MAAM,GAAG,eAAe;EAC9B,MAAM,MAAM;GACV,MAAM;GACN,OAAO,EAAE;GACV;AAED,OAAK,MAAM,QAAQ,YAAY;AAC7B,OAAI,SAAS,KACX,QAAO;AAET,OAAI,SAAS,MACX;AAGF,OAAI,MAAM,KAAK,KAAK;;AAGtB,MAAI,IAAI,MAAM,WAAW,EACvB,QAAO;AAET,SAAO;;AAGT,SAAQ,OAAO,GAAG,eAAe;EAC/B,MAAM,MAAM;GACV,MAAM;GACN,OAAO,EAAE;GACV;AAED,OAAK,MAAM,QAAQ,YAAY;AAC7B,OAAI,SAAS,KACX;AAEF,OAAI,SAAS,MACX,QAAO;AAGT,OAAI,MAAM,KAAK,KAAK;;AAGtB,MAAI,IAAI,MAAM,WAAW,EACvB,QAAO;AAET,SAAO;;AAGT,QAAO;;AAGT,SAAgB,eACd,SACA,OACG;AACH,QAAO,MAAM,cAAc,QAAQ,CAAC"}
1
+ {"version":3,"file":"conditions.js","names":["builder: ConditionBuilder<Columns>"],"sources":["../../src/query/conditions.ts"],"sourcesContent":["import type { AnyColumn } from \"@fragno-dev/db/schema\";\n\nimport {\n dbInterval,\n dbNow,\n type DbInterval,\n type DbIntervalInput,\n type DbNow,\n} from \"@fragno-dev/db\";\n\nexport type ConditionType = \"compare\" | \"and\" | \"or\" | \"not\";\n\nexport type Condition =\n | {\n type: \"compare\";\n a: AnyColumn;\n operator: Operator;\n b: AnyColumn | unknown | null;\n }\n | {\n type: \"or\" | \"and\";\n items: Condition[];\n }\n | {\n type: \"not\";\n item: Condition;\n };\n\nexport type ConditionBuilder<Columns extends Record<string, AnyColumn>> = {\n <ColName extends keyof Columns>(\n a: ColName,\n operator: (typeof valueOperators)[number] | (typeof stringOperators)[number],\n b: Columns[ColName][\"$in\"] | null,\n ): Condition;\n\n <ColName extends keyof Columns>(\n a: ColName,\n operator: (typeof arrayOperators)[number],\n b: Columns[ColName][\"$in\"][],\n ): Condition;\n\n <ColName extends keyof Columns>(a: ColName): Condition;\n\n and: (...v: (Condition | boolean)[]) => Condition | boolean;\n or: (...v: (Condition | boolean)[]) => Condition | boolean;\n not: (v: Condition | boolean) => Condition | boolean;\n\n isNull: (a: keyof Columns) => Condition;\n isNotNull: (a: keyof Columns) => Condition;\n now: () => DbNow;\n interval: (input: DbIntervalInput) => DbInterval;\n};\n\nconst stringOperators = [\n \"contains\",\n \"starts with\",\n \"ends with\",\n\n \"not contains\",\n \"not starts with\",\n \"not ends with\",\n] as const;\n\nconst arrayOperators = [\"in\", \"not in\"] as const;\n\nconst valueOperators = [\"=\", \"!=\", \">\", \">=\", \"<\", \"<=\", \"is\", \"is not\"] as const;\n\nexport const operators = [...valueOperators, ...arrayOperators, ...stringOperators] as const;\n\nexport type Operator = (typeof operators)[number];\n\nexport function createBuilder<Columns extends Record<string, AnyColumn>>(\n columns: Columns,\n): ConditionBuilder<Columns> {\n function col(name: keyof Columns) {\n const out = columns[name];\n if (!out) {\n throw new Error(`Invalid column name ${String(name)}`);\n }\n\n return out;\n }\n\n const builder: ConditionBuilder<Columns> = (...args: [string, Operator, unknown] | [string]) => {\n if (args.length === 3) {\n const [a, operator, b] = args;\n\n if (!operators.includes(operator)) {\n throw new Error(`Unsupported operator: ${operator}`);\n }\n\n return {\n type: \"compare\",\n a: col(a),\n b,\n operator,\n };\n }\n\n return {\n type: \"compare\",\n a: col(args[0]),\n operator: \"=\",\n b: true,\n };\n };\n\n builder.isNull = (a) => builder(a, \"is\", null);\n builder.isNotNull = (a) => builder(a, \"is not\", null);\n builder.now = () => dbNow();\n builder.interval = (input) => dbInterval(input);\n builder.not = (condition) => {\n if (typeof condition === \"boolean\") {\n return !condition;\n }\n\n return {\n type: \"not\",\n item: condition,\n };\n };\n\n builder.or = (...conditions) => {\n const out = {\n type: \"or\",\n items: [] as Condition[],\n } as const;\n\n for (const item of conditions) {\n if (item === true) {\n return true;\n }\n if (item === false) {\n continue;\n }\n\n out.items.push(item);\n }\n\n if (out.items.length === 0) {\n return false;\n }\n return out;\n };\n\n builder.and = (...conditions) => {\n const out = {\n type: \"and\",\n items: [] as Condition[],\n } as const;\n\n for (const item of conditions) {\n if (item === true) {\n continue;\n }\n if (item === false) {\n return false;\n }\n\n out.items.push(item);\n }\n\n if (out.items.length === 0) {\n return true;\n }\n return out;\n };\n\n return builder;\n}\n\nexport function buildCondition<T, Columns extends Record<string, AnyColumn>>(\n columns: Columns,\n input: (builder: ConditionBuilder<Columns>) => T,\n): T {\n return input(createBuilder(columns));\n}\n"],"mappings":";;;AAqDA,MAAM,kBAAkB;CACtB;CACA;CACA;CAEA;CACA;CACA;CACD;AAED,MAAM,iBAAiB,CAAC,MAAM,SAAS;AAEvC,MAAM,iBAAiB;CAAC;CAAK;CAAM;CAAK;CAAM;CAAK;CAAM;CAAM;CAAS;AAExE,MAAa,YAAY;CAAC,GAAG;CAAgB,GAAG;CAAgB,GAAG;CAAgB;AAInF,SAAgB,cACd,SAC2B;CAC3B,SAAS,IAAI,MAAqB;EAChC,MAAM,MAAM,QAAQ;AACpB,MAAI,CAAC,IACH,OAAM,IAAI,MAAM,uBAAuB,OAAO,KAAK,GAAG;AAGxD,SAAO;;CAGT,MAAMA,WAAsC,GAAG,SAAiD;AAC9F,MAAI,KAAK,WAAW,GAAG;GACrB,MAAM,CAAC,GAAG,UAAU,KAAK;AAEzB,OAAI,CAAC,UAAU,SAAS,SAAS,CAC/B,OAAM,IAAI,MAAM,yBAAyB,WAAW;AAGtD,UAAO;IACL,MAAM;IACN,GAAG,IAAI,EAAE;IACT;IACA;IACD;;AAGH,SAAO;GACL,MAAM;GACN,GAAG,IAAI,KAAK,GAAG;GACf,UAAU;GACV,GAAG;GACJ;;AAGH,SAAQ,UAAU,MAAM,QAAQ,GAAG,MAAM,KAAK;AAC9C,SAAQ,aAAa,MAAM,QAAQ,GAAG,UAAU,KAAK;AACrD,SAAQ,YAAY,OAAO;AAC3B,SAAQ,YAAY,UAAU,WAAW,MAAM;AAC/C,SAAQ,OAAO,cAAc;AAC3B,MAAI,OAAO,cAAc,UACvB,QAAO,CAAC;AAGV,SAAO;GACL,MAAM;GACN,MAAM;GACP;;AAGH,SAAQ,MAAM,GAAG,eAAe;EAC9B,MAAM,MAAM;GACV,MAAM;GACN,OAAO,EAAE;GACV;AAED,OAAK,MAAM,QAAQ,YAAY;AAC7B,OAAI,SAAS,KACX,QAAO;AAET,OAAI,SAAS,MACX;AAGF,OAAI,MAAM,KAAK,KAAK;;AAGtB,MAAI,IAAI,MAAM,WAAW,EACvB,QAAO;AAET,SAAO;;AAGT,SAAQ,OAAO,GAAG,eAAe;EAC/B,MAAM,MAAM;GACV,MAAM;GACN,OAAO,EAAE;GACV;AAED,OAAK,MAAM,QAAQ,YAAY;AAC7B,OAAI,SAAS,KACX;AAEF,OAAI,SAAS,MACX,QAAO;AAGT,OAAI,MAAM,KAAK,KAAK;;AAGtB,MAAI,IAAI,MAAM,WAAW,EACvB,QAAO;AAET,SAAO;;AAGT,QAAO;;AAGT,SAAgB,eACd,SACA,OACG;AACH,QAAO,MAAM,cAAc,QAAQ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","names":[],"sources":["../../src/query/engine.ts"],"sourcesContent":[],"mappings":";;;;;;;;KA6BK,MAAA,GAAS;AAAT,KAeO,qBAAA,GAfE;EAeF,YAAA,EAAA,MAAA;EAGW,UAAA,EAAA,MAAA;EAAR,KAAA,EAAA,GAAA,GAAA,OAAA,CAAQ,MAAR,CAAA;EACiB,gBAAA,EAAZ,GAAY,CAAA,MAAA,EAAA,eAAA,CAAA;CAAZ"}
1
+ {"version":3,"file":"engine.d.ts","names":[],"sources":["../../src/query/engine.ts"],"sourcesContent":[],"mappings":";;;;;;;;KA8BK,MAAA,GAAS;AAAT,KAeO,qBAAA,GAfE;EAeF,YAAA,EAAA,MAAA;EAGW,UAAA,EAAA,MAAA;EAAR,KAAA,EAAA,GAAA,GAAA,OAAA,CAAQ,MAAR,CAAA;EACiB,gBAAA,EAAZ,GAAY,CAAA,MAAA,EAAA,eAAA,CAAA;CAAZ"}
@@ -1,5 +1,5 @@
1
- import { normalizeValue } from "./normalize.js";
2
1
  import { buildCondition } from "./conditions.js";
2
+ import { normalizeValue } from "./normalize.js";
3
3
  import { Column, FragnoId, FragnoReference } from "@fragno-dev/db/schema";
4
4
  import { Cursor, createCursorFromRecord, decodeCursor } from "@fragno-dev/db/cursor";
5
5
  import { FindBuilder } from "@fragno-dev/db/unit-of-work";