@workglow/indexeddb 0.4.8 → 0.4.9

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.
@@ -5,12 +5,12 @@
5
5
  "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * Opens an IDB connection and wires `onversionchange` so a future schema\n * bump in another tab can close this connection rather than blocking the\n * upgrade indefinitely.\n *\n * Pass `version` + `onUpgradeNeeded` only when the call site is itself\n * running a schema upgrade. Most callers want the no-arg form: open at\n * the database's current version and use it for reads/writes.\n */\nexport function openIdb(\n dbName: string,\n options: {\n readonly version?: number;\n readonly onUpgradeNeeded?: (event: IDBVersionChangeEvent) => void;\n } = {}\n): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const req = indexedDB.open(dbName, options.version);\n req.onsuccess = () => {\n const db = req.result;\n db.onversionchange = () => db.close();\n resolve(db);\n };\n req.onupgradeneeded = (ev) => options.onUpgradeNeeded?.(ev);\n req.onerror = () => {\n const err = req.error;\n if (err && err.name === \"VersionError\") {\n reject(\n new Error(\n `IndexedDB ${dbName} exists at a higher version than ${options.version ?? \"current\"}`\n )\n );\n return;\n }\n reject(err);\n };\n req.onblocked = () =>\n reject(new Error(`IndexedDB ${dbName} is blocked — close other tabs using this database.`));\n });\n}\n",
6
6
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { deepEqual } from \"@workglow/util\";\nimport { openIdb } from \"./openIdb\";\n\nexport interface ExpectedIndexDefinition {\n name: string;\n keyPath: string | string[];\n options?: IDBIndexParameters;\n}\n\nexport interface MigrationContext {\n db: IDBDatabase;\n transaction: IDBTransaction;\n oldVersion: number;\n newVersion: number;\n tableName: string;\n}\n\nexport interface DataTransformer {\n (oldData: any): any | Promise<any>;\n}\n\nexport interface MigrationOptions {\n /** Custom data transformer to apply during migration */\n dataTransformer?: DataTransformer;\n /** Whether to allow destructive operations (delete and recreate). Default: false */\n allowDestructiveMigration?: boolean;\n /** Callback for migration progress/logging */\n onMigrationProgress?: (message: string, progress?: number) => void;\n /** Callback for migration errors (non-fatal warnings) */\n onMigrationWarning?: (message: string, error?: Error) => void;\n}\n\ninterface SchemaSnapshot {\n version: number;\n primaryKey: string | string[];\n indexes: ExpectedIndexDefinition[];\n recordCount?: number;\n timestamp: number;\n}\n\nconst METADATA_STORE_NAME = \"__schema_metadata__\";\n\nasync function saveSchemaMetadata(\n db: IDBDatabase,\n tableName: string,\n snapshot: SchemaSnapshot\n): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n const transaction = db.transaction(METADATA_STORE_NAME, \"readwrite\");\n const store = transaction.objectStore(METADATA_STORE_NAME);\n const request = store.put({ ...snapshot, tableName }, tableName);\n\n request.onsuccess = () => resolve();\n request.onerror = () => reject(request.error);\n transaction.onerror = () => reject(transaction.error);\n } catch (err) {\n // Metadata store might not exist in old databases\n resolve();\n }\n });\n}\n\nfunction openIndexedDbTable(\n tableName: string,\n version?: number,\n upgradeNeededCallback?: (event: IDBVersionChangeEvent) => void\n): Promise<IDBDatabase> {\n return openIdb(tableName, { version, onUpgradeNeeded: upgradeNeededCallback });\n}\n\nasync function deleteIndexedDbTable(tableName: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const deleteRequest = indexedDB.deleteDatabase(tableName);\n\n deleteRequest.onsuccess = () => resolve();\n deleteRequest.onerror = () => reject(deleteRequest.error);\n deleteRequest.onblocked = () => {\n reject(\n new Error(`Cannot delete database ${tableName}. Close all other tabs using this database.`)\n );\n };\n });\n}\n\ninterface SchemaDiff {\n indexesToAdd: ExpectedIndexDefinition[];\n indexesToRemove: string[];\n indexesToModify: ExpectedIndexDefinition[];\n primaryKeyChanged: boolean;\n needsObjectStoreRecreation: boolean;\n}\n\nfunction compareSchemas(\n store: IDBObjectStore,\n expectedPrimaryKey: string | string[],\n expectedIndexes: ExpectedIndexDefinition[]\n): SchemaDiff {\n const diff: SchemaDiff = {\n indexesToAdd: [],\n indexesToRemove: [],\n indexesToModify: [],\n primaryKeyChanged: false,\n needsObjectStoreRecreation: false,\n };\n\n const actualKeyPath = store.keyPath;\n const normalizedExpected = Array.isArray(expectedPrimaryKey)\n ? expectedPrimaryKey\n : expectedPrimaryKey;\n const normalizedActual = Array.isArray(actualKeyPath) ? actualKeyPath : actualKeyPath;\n\n if (!deepEqual(normalizedExpected, normalizedActual)) {\n diff.primaryKeyChanged = true;\n diff.needsObjectStoreRecreation = true;\n return diff;\n }\n\n const existingIndexes = new Map<string, IDBIndex>();\n for (let i = 0; i < store.indexNames.length; i++) {\n const indexName = store.indexNames[i];\n existingIndexes.set(indexName, store.index(indexName));\n }\n\n for (const expectedIdx of expectedIndexes) {\n const existingIdx = existingIndexes.get(expectedIdx.name);\n\n if (!existingIdx) {\n diff.indexesToAdd.push(expectedIdx);\n } else {\n const expectedKeyPath = Array.isArray(expectedIdx.keyPath)\n ? expectedIdx.keyPath\n : [expectedIdx.keyPath];\n const actualKeyPath = Array.isArray(existingIdx.keyPath)\n ? existingIdx.keyPath\n : [existingIdx.keyPath];\n\n const keyPathChanged = !deepEqual(expectedKeyPath, actualKeyPath);\n const uniqueChanged = existingIdx.unique !== (expectedIdx.options?.unique ?? false);\n const multiEntryChanged =\n existingIdx.multiEntry !== (expectedIdx.options?.multiEntry ?? false);\n\n if (keyPathChanged || uniqueChanged || multiEntryChanged) {\n diff.indexesToModify.push(expectedIdx);\n }\n\n existingIndexes.delete(expectedIdx.name);\n }\n }\n\n diff.indexesToRemove = Array.from(existingIndexes.keys());\n\n return diff;\n}\n\nasync function readAllData(store: IDBObjectStore): Promise<any[]> {\n return new Promise((resolve, reject) => {\n const request = store.getAll();\n request.onsuccess = () => resolve(request.result || []);\n request.onerror = () => reject(request.error);\n });\n}\n\nasync function performIncrementalMigration(\n db: IDBDatabase,\n tableName: string,\n diff: SchemaDiff,\n options: MigrationOptions = {}\n): Promise<IDBDatabase> {\n const currentVersion = db.version;\n const newVersion = currentVersion + 1;\n\n db.close();\n\n options.onMigrationProgress?.(\n `Migrating ${tableName} from version ${currentVersion} to ${newVersion}...`,\n 0\n );\n\n return openIndexedDbTable(tableName, newVersion, (event: IDBVersionChangeEvent) => {\n const transaction = (event.target as IDBOpenDBRequest).transaction!;\n const store = transaction.objectStore(tableName);\n\n for (const indexName of diff.indexesToRemove) {\n options.onMigrationProgress?.(`Removing index: ${indexName}`, 0.2);\n store.deleteIndex(indexName);\n }\n\n for (const indexDef of diff.indexesToModify) {\n options.onMigrationProgress?.(`Updating index: ${indexDef.name}`, 0.4);\n if (store.indexNames.contains(indexDef.name)) {\n store.deleteIndex(indexDef.name);\n }\n store.createIndex(indexDef.name, indexDef.keyPath, indexDef.options);\n }\n\n for (const indexDef of diff.indexesToAdd) {\n options.onMigrationProgress?.(`Adding index: ${indexDef.name}`, 0.6);\n store.createIndex(indexDef.name, indexDef.keyPath, indexDef.options);\n }\n\n options.onMigrationProgress?.(`Migration complete`, 1.0);\n });\n}\n\n/** Destructive migration by recreating the object store; needed when the primary key changes. */\nasync function performDestructiveMigration(\n db: IDBDatabase,\n tableName: string,\n primaryKey: string | string[],\n expectedIndexes: ExpectedIndexDefinition[],\n options: MigrationOptions = {},\n autoIncrement: boolean = false\n): Promise<IDBDatabase> {\n if (!options.allowDestructiveMigration) {\n throw new Error(\n `Destructive migration required for ${tableName} but not allowed. ` +\n `Primary key has changed. Set allowDestructiveMigration=true to proceed with data loss, ` +\n `or provide a dataTransformer to migrate data.`\n );\n }\n\n const currentVersion = db.version;\n const newVersion = currentVersion + 1;\n\n options.onMigrationProgress?.(\n `Performing destructive migration of ${tableName}. Reading existing data...`,\n 0\n );\n\n let existingData: any[] = [];\n try {\n const transaction = db.transaction(tableName, \"readonly\");\n const store = transaction.objectStore(tableName);\n existingData = await readAllData(store);\n options.onMigrationProgress?.(`Read ${existingData.length} records`, 0.3);\n } catch (err) {\n options.onMigrationWarning?.(\n `Failed to read existing data during migration: ${err}`,\n err as Error\n );\n }\n\n db.close();\n\n if (options.dataTransformer && existingData.length > 0) {\n options.onMigrationProgress?.(`Transforming ${existingData.length} records...`, 0.4);\n try {\n const transformed = [];\n for (let i = 0; i < existingData.length; i++) {\n const record = existingData[i];\n const transformedRecord = await options.dataTransformer(record);\n if (transformedRecord !== undefined && transformedRecord !== null) {\n transformed.push(transformedRecord);\n }\n if (i % 100 === 0) {\n options.onMigrationProgress?.(\n `Transformed ${i}/${existingData.length} records`,\n 0.4 + (i / existingData.length) * 0.3\n );\n }\n }\n existingData = transformed;\n options.onMigrationProgress?.(`Transformation complete: ${existingData.length} records`, 0.7);\n } catch (err) {\n options.onMigrationWarning?.(\n `Data transformation failed: ${err}. Some data may be lost.`,\n err as Error\n );\n existingData = [];\n }\n }\n\n options.onMigrationProgress?.(`Recreating object store...`, 0.75);\n\n const newDb = await openIndexedDbTable(tableName, newVersion, (event: IDBVersionChangeEvent) => {\n const db = (event.target as IDBOpenDBRequest).result;\n\n if (db.objectStoreNames.contains(tableName)) {\n db.deleteObjectStore(tableName);\n }\n\n const store = db.createObjectStore(tableName, { keyPath: primaryKey, autoIncrement });\n\n for (const idx of expectedIndexes) {\n store.createIndex(idx.name, idx.keyPath, idx.options);\n }\n\n if (existingData.length > 0) {\n options.onMigrationProgress?.(`Restoring ${existingData.length} records...`, 0.8);\n\n for (const record of existingData) {\n try {\n store.put(record);\n } catch (err) {\n options.onMigrationWarning?.(`Failed to restore record: ${err}`, err as Error);\n }\n }\n }\n });\n\n options.onMigrationProgress?.(`Destructive migration complete`, 1.0);\n\n return newDb;\n}\n\nasync function createNewDatabase(\n tableName: string,\n primaryKey: string | string[],\n expectedIndexes: ExpectedIndexDefinition[],\n options: MigrationOptions = {},\n autoIncrement: boolean = false\n): Promise<IDBDatabase> {\n options.onMigrationProgress?.(`Creating new database: ${tableName}`, 0);\n\n // Delete existing database if it exists to avoid version conflicts\n try {\n await deleteIndexedDbTable(tableName);\n await new Promise((resolve) => setTimeout(resolve, 50));\n } catch (err) {\n // ignore — database might not exist\n }\n\n const version = 1;\n\n const db = await openIndexedDbTable(tableName, version, (event: IDBVersionChangeEvent) => {\n const db = (event.target as IDBOpenDBRequest).result;\n\n if (!db.objectStoreNames.contains(METADATA_STORE_NAME)) {\n db.createObjectStore(METADATA_STORE_NAME, { keyPath: \"tableName\" });\n }\n\n const store = db.createObjectStore(tableName, { keyPath: primaryKey, autoIncrement });\n\n for (const idx of expectedIndexes) {\n store.createIndex(idx.name, idx.keyPath, idx.options);\n }\n });\n\n const snapshot: SchemaSnapshot = {\n version: db.version,\n primaryKey,\n indexes: expectedIndexes,\n recordCount: 0,\n timestamp: Date.now(),\n };\n\n await saveSchemaMetadata(db, tableName, snapshot);\n\n options.onMigrationProgress?.(`Database created successfully`, 1.0);\n\n return db;\n}\n\n/**\n * Ensures that an IndexedDB table exists with the specified schema.\n * Performs migrations as needed without data loss when possible.\n */\nexport async function ensureIndexedDbTable(\n tableName: string,\n primaryKey: string | string[],\n expectedIndexes: ExpectedIndexDefinition[] = [],\n options: MigrationOptions = {},\n autoIncrement: boolean = false\n): Promise<IDBDatabase> {\n try {\n let db: IDBDatabase;\n let wasJustCreated = false;\n try {\n // Opens at current version if exists, else creates at version 1\n db = await openIndexedDbTable(tableName);\n\n // indexedDB.open creating a new DB without stores leaves it at version 1\n if (db.version === 1 && !db.objectStoreNames.contains(tableName)) {\n wasJustCreated = true;\n db.close();\n }\n } catch (err: any) {\n options.onMigrationProgress?.(\n `Database ${tableName} does not exist or has version conflict, creating...`,\n 0\n );\n return await createNewDatabase(\n tableName,\n primaryKey,\n expectedIndexes,\n options,\n autoIncrement\n );\n }\n\n // Delete the empty DB and recreate it at version 1 with stores\n if (wasJustCreated) {\n options.onMigrationProgress?.(`Creating new database: ${tableName}`, 0);\n try {\n await deleteIndexedDbTable(tableName);\n await new Promise((resolve) => setTimeout(resolve, 50));\n } catch (err) {\n // ignore\n }\n\n db = await openIndexedDbTable(tableName, 1, (event: IDBVersionChangeEvent) => {\n const db = (event.target as IDBOpenDBRequest).result;\n\n if (!db.objectStoreNames.contains(METADATA_STORE_NAME)) {\n db.createObjectStore(METADATA_STORE_NAME, { keyPath: \"tableName\" });\n }\n\n const store = db.createObjectStore(tableName, { keyPath: primaryKey, autoIncrement });\n\n for (const idx of expectedIndexes) {\n store.createIndex(idx.name, idx.keyPath, idx.options);\n }\n });\n\n const snapshot: SchemaSnapshot = {\n version: db.version,\n primaryKey,\n indexes: expectedIndexes,\n recordCount: 0,\n timestamp: Date.now(),\n };\n await saveSchemaMetadata(db, tableName, snapshot);\n\n options.onMigrationProgress?.(`Database created successfully`, 1.0);\n return db;\n }\n\n if (!db.objectStoreNames.contains(METADATA_STORE_NAME)) {\n const currentVersion = db.version;\n db.close();\n\n db = await openIndexedDbTable(\n tableName,\n currentVersion + 1,\n (event: IDBVersionChangeEvent) => {\n const db = (event.target as IDBOpenDBRequest).result;\n if (!db.objectStoreNames.contains(METADATA_STORE_NAME)) {\n db.createObjectStore(METADATA_STORE_NAME, { keyPath: \"tableName\" });\n }\n }\n );\n }\n\n if (!db.objectStoreNames.contains(tableName)) {\n options.onMigrationProgress?.(`Object store ${tableName} does not exist, creating...`, 0);\n db.close();\n return await createNewDatabase(\n tableName,\n primaryKey,\n expectedIndexes,\n options,\n autoIncrement\n );\n }\n\n const transaction = db.transaction(tableName, \"readonly\");\n const store = transaction.objectStore(tableName);\n const diff = compareSchemas(store, primaryKey, expectedIndexes);\n\n await new Promise<void>((resolve) => {\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => resolve();\n });\n\n const needsMigration =\n diff.indexesToAdd.length > 0 ||\n diff.indexesToRemove.length > 0 ||\n diff.indexesToModify.length > 0 ||\n diff.needsObjectStoreRecreation;\n\n if (!needsMigration) {\n options.onMigrationProgress?.(`Schema for ${tableName} is up to date`, 1.0);\n\n // Update metadata to keep timestamp current\n const snapshot: SchemaSnapshot = {\n version: db.version,\n primaryKey,\n indexes: expectedIndexes,\n timestamp: Date.now(),\n };\n await saveSchemaMetadata(db, tableName, snapshot);\n\n return db;\n }\n\n if (diff.needsObjectStoreRecreation) {\n options.onMigrationProgress?.(\n `Schema change requires object store recreation for ${tableName}`,\n 0\n );\n db = await performDestructiveMigration(\n db,\n tableName,\n primaryKey,\n expectedIndexes,\n options,\n autoIncrement\n );\n } else {\n options.onMigrationProgress?.(`Performing incremental migration for ${tableName}`, 0);\n db = await performIncrementalMigration(db, tableName, diff, options);\n }\n\n const snapshot: SchemaSnapshot = {\n version: db.version,\n primaryKey,\n indexes: expectedIndexes,\n timestamp: Date.now(),\n };\n await saveSchemaMetadata(db, tableName, snapshot);\n\n return db;\n } catch (err) {\n options.onMigrationWarning?.(`Migration failed for ${tableName}: ${err}`, err as Error);\n throw err;\n }\n}\n\nexport async function dropIndexedDbTable(tableName: string): Promise<void> {\n return deleteIndexedDbTable(tableName);\n}\n",
7
7
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { IKvStorage } from \"@workglow/storage\";\nimport { DefaultKeyValueKey, DefaultKeyValueSchema, KvViaTabularStorage } from \"@workglow/storage\";\nimport { createServiceToken } from \"@workglow/util\";\nimport type { JsonSchema } from \"@workglow/util/schema\";\nimport { IndexedDbTabularStorage } from \"./IndexedDbTabularStorage\";\n\nexport const IDB_KV_REPOSITORY = createServiceToken<IKvStorage<string, any, any>>(\n \"storage.kvRepository.indexedDb\"\n);\n\nexport class IndexedDbKvStorage extends KvViaTabularStorage {\n public tabularRepository: IndexedDbTabularStorage<\n typeof DefaultKeyValueSchema,\n typeof DefaultKeyValueKey\n >;\n\n constructor(\n public dbName: string,\n keySchema: JsonSchema = { type: \"string\" },\n valueSchema: JsonSchema = {}\n ) {\n super(keySchema, valueSchema);\n this.tabularRepository = new IndexedDbTabularStorage(\n dbName,\n DefaultKeyValueSchema,\n DefaultKeyValueKey\n );\n }\n}\n",
8
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {\n AnyTabularStorage,\n AutoGeneratedKeys,\n ClientProvidedKeysOption,\n CoveringIndexQueryOptions,\n DeleteSearchCriteria,\n InsertEntity,\n KeyGenerationStrategy,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n} from \"@workglow/storage\";\nimport {\n BaseTabularStorage,\n HybridSubscriptionManager,\n isSearchCondition,\n isSearchInCondition,\n matchesEqualityCriterion,\n matchesInequalityCriterion,\n normalizeCriterion,\n pickCoveringIndex,\n safeEmit,\n StorageUnsupportedError,\n type ITabularMigration,\n type ITabularMigrationApplier,\n} from \"@workglow/storage\";\nimport { createServiceToken, deepEqual, makeFingerprint, uuid4 } from \"@workglow/util\";\nimport type {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport type { ExpectedIndexDefinition, MigrationOptions } from \"./IndexedDbTable\";\nimport { ensureIndexedDbTable } from \"./IndexedDbTable\";\nimport {\n idbObjectStoreExists,\n IndexedDbTabularMigrationApplier,\n} from \"./IndexedDbTabularMigrationApplier\";\n\nexport const IDB_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.indexedDb\"\n);\n\n/**\n * Polling change-detection comparator for the hybrid subscription manager.\n *\n * Naively comparing entities via serialized equality is correct but\n * O(size-of-entity) per poll. That falls apart for tables\n * holding large blobs — e.g. an `activities` row whose `output_data` carries\n * a multi-megabyte `Uint8ClampedArray`: each poll cycle (default 1 s) would\n * stringify ~16 MB per row × N rows, locking the main thread.\n *\n * Fast path: if both rows expose a string `updated_at`, compare just those.\n * The repositories in this codebase bump `updated_at` on every write (see\n * `ActivityRepository.updateActivity`), so the timestamp is a sufficient\n * change witness. Fall back to the structural compare for tables that don't\n * follow that convention so correctness is preserved everywhere.\n */\nfunction compareEntitiesForChange<T>(a: T, b: T): boolean {\n const au = (a as { updated_at?: unknown })?.updated_at;\n const bu = (b as { updated_at?: unknown })?.updated_at;\n if (typeof au === \"string\" && typeof bu === \"string\") {\n return au === bu;\n }\n return deepEqual(a, b);\n}\n\n/**\n * A tabular repository implementation using IndexedDB for browser-based storage.\n *\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class IndexedDbTabularStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n // computed types\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n Value = Omit<Entity, PrimaryKeyNames[number] & keyof Entity>,\n InsertType extends InsertEntity<Entity, AutoGeneratedKeys<Schema>> = InsertEntity<\n Entity,\n AutoGeneratedKeys<Schema>\n >,\n> extends BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n private db: IDBDatabase | undefined;\n /**\n * True between `setupDatabase`'s call to `applyTabularMigrations` and its\n * completion. Backfill ops inside the orchestrator may close `this.db`\n * (via `onversionchange` from the next migration's upgrade) and trigger\n * a re-entrant `setupDatabase` call from `getDb()`. The re-entrant call\n * must only re-open the IDB connection — it MUST NOT recurse into the\n * orchestrator, or migrations will be replayed mid-flight.\n */\n private applyingMigrations = false;\n private setupPromise: Promise<IDBDatabase> | null = null;\n private migrationOptions: MigrationOptions;\n private hybridManager: HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n > | null = null;\n private readonly hybridOptions: {\n readonly useBroadcastChannel: boolean;\n readonly backupPollingIntervalMs: number;\n };\n /**\n * Indexes safe for cursor-based narrowing. An IDB index excludes records\n * whose keyPath has any undefined component, and equally any null one (null\n * is not a valid key), so iterating an index can miss records when an indexed\n * column is optional in the schema or its type admits null. Native\n * `count(range)` and cursor scans are only correct over indexes whose every\n * column is required and non-nullable. Computed lazily on first use.\n */\n private cursorSafeIndexes: Array<Array<keyof Entity>> | undefined;\n\n /**\n * Creates a new IndexedDB-based tabular repository.\n * @param table - Name of the IndexedDB store to use.\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable. Each string or single column creates a single-column index,\n * while each array creates a compound index with columns in the specified order.\n * @param migrationOptions - Options for handling database schema migrations\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n * @param tabularMigrations - Declarative migrations evolving the store schema\n * @param uniqueIndexes - Compound column tuples enforced as native IDB UNIQUE\n * indexes (`store.createIndex(..., { unique: true })`).\n * A `put` whose tuple collides with another record's\n * rejects with a `ConstraintError`.\n */\n constructor(\n public table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n migrationOptions: MigrationOptions & {\n readonly useBroadcastChannel?: boolean;\n readonly backupPollingIntervalMs?: number;\n } = {},\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\",\n tabularMigrations?: ReadonlyArray<ITabularMigration>,\n uniqueIndexes: readonly (readonly (keyof NoInfer<Entity>)[])[] = []\n ) {\n super(\n schema,\n primaryKeyNames,\n indexes,\n clientProvidedKeys,\n tabularMigrations,\n table,\n uniqueIndexes\n );\n this.migrationOptions = migrationOptions;\n this.hybridOptions = {\n useBroadcastChannel: migrationOptions.useBroadcastChannel ?? true,\n backupPollingIntervalMs: migrationOptions.backupPollingIntervalMs ?? 5000,\n };\n }\n\n private async getDb(): Promise<IDBDatabase> {\n if (this.db) return this.db;\n await this.setupDatabase();\n return this.db!;\n }\n\n /**\n * Sets up the IndexedDB database table with the required schema and indexes.\n * Must be called before using any other methods.\n */\n public override async setupDatabase(): Promise<void> {\n if (this.db) return;\n if (this.setupPromise) {\n await this.setupPromise;\n return;\n }\n\n // Re-entrant guard: when called from inside an in-flight migration\n // (typically because a backfill's `getPage` hit a closed connection\n // after the previous migration's upgrade-tx version bump), only\n // re-open the IDB connection. Re-running `applyTabularMigrations`\n // here would replay the orchestrator and double-apply migrations.\n if (this.applyingMigrations) {\n this.setupPromise = this.performSetup();\n try {\n this.db = await this.setupPromise;\n this.rewireOnVersionChange();\n } finally {\n this.setupPromise = null;\n }\n return;\n }\n\n // Probe whether the object store already exists BEFORE performSetup\n // creates it. The orchestrator needs this signal to take the\n // mark-all-applied fast path on a brand-new DB; otherwise it would\n // see the (just-created) store and try to apply ops against the\n // already-current target schema.\n const freshTable =\n this.tabularMigrations && this.tabularMigrations.length > 0\n ? !(await this.probeObjectStoreExists())\n : false;\n\n this.setupPromise = this.performSetup();\n try {\n this.db = await this.setupPromise;\n } finally {\n this.setupPromise = null;\n }\n\n if (this.tabularMigrations && this.tabularMigrations.length > 0) {\n this.rewireOnVersionChange();\n this.applyingMigrations = true;\n try {\n await this.applyTabularMigrations({ freshTable });\n } finally {\n this.applyingMigrations = false;\n }\n // After migrations, this.db may be undefined (closed by onversionchange).\n // Reopen so the storage is ready for use.\n if (!this.db) {\n this.db = await this.performSetup();\n }\n }\n }\n\n /**\n * Wires `onversionchange` so that when the migration runner bumps the IDB\n * version (currentVersion + 1 to trigger onupgradeneeded), the current\n * open connection is both closed AND cleared from `this.db`. Without the\n * clear, getDb() would return a stale closed connection and throw\n * InvalidStateError on the next transaction attempt (e.g. during backfill).\n */\n private rewireOnVersionChange(): void {\n if (!this.db) return;\n this.db.onversionchange = () => {\n this.db?.close();\n this.db = undefined;\n };\n }\n\n /**\n * Read-only probe: does the object store already exist in the IDB\n * database? Used by `setupDatabase` to decide between the orchestrator's\n * fresh-DB fast path (mark-all-applied) and the run-pending path.\n * Delegates to the shared `idbObjectStoreExists` helper.\n */\n private async probeObjectStoreExists(): Promise<boolean> {\n return idbObjectStoreExists(this.table, this.table);\n }\n\n private async performSetup(): Promise<IDBDatabase> {\n const pkColumns = super.primaryKeyColumns() as string[];\n\n const expectedIndexes: ExpectedIndexDefinition[] = [];\n\n for (const spec of this.indexes) {\n const columns = spec as Array<keyof Entity>;\n // Skip if this is just the primary key or a prefix of it\n if (columns.length <= pkColumns.length) {\n const isPkPrefix = columns.every((col, idx) => col === pkColumns[idx]);\n if (isPkPrefix) continue;\n }\n\n const columnNames = columns.map((col) => String(col));\n const indexName = columnNames.join(\"_\");\n expectedIndexes.push({\n name: indexName,\n keyPath: columnNames.length === 1 ? columnNames[0] : columnNames,\n options: { unique: false },\n });\n }\n\n // Declared unique tuples become native IDB UNIQUE indexes so a colliding\n // `put` is rejected with a `ConstraintError` — the browser-tier equivalent\n // of the `CREATE UNIQUE INDEX` the SQL backends emit. The base class has\n // already dropped any regular index whose tuple exactly matches a unique\n // tuple, so reusing the plain `cols.join(\"_\")` name cannot collide; it also\n // lets the query planner narrow on the unique index (see\n // {@link getCursorSafeIndexes}). IDB excludes records with an\n // undefined/invalid keyPath component from an index, so NULL/undefined tuple\n // values never trip the constraint — matching SQL's \"NULL is distinct\".\n for (const columns of this.uniqueIndexes) {\n const columnNames = (columns as Array<keyof Entity>).map((col) => String(col));\n const indexName = columnNames.join(\"_\");\n expectedIndexes.push({\n name: indexName,\n keyPath: columnNames.length === 1 ? columnNames[0] : columnNames,\n options: { unique: true },\n });\n }\n\n const primaryKey = pkColumns.length === 1 ? pkColumns[0] : pkColumns;\n\n // IndexedDB autoIncrement only works with single numeric keys\n const useAutoIncrement =\n this.hasAutoGeneratedKey() &&\n this.autoGeneratedKeyStrategy === \"autoincrement\" &&\n pkColumns.length === 1;\n\n return await ensureIndexedDbTable(\n this.table,\n primaryKey,\n expectedIndexes,\n this.migrationOptions,\n useAutoIncrement\n );\n }\n\n public override getMigrationApplier(): ITabularMigrationApplier | null {\n // The IDB tabular storage uses `this.table` as both the database name\n // and the object store name (see `ensureIndexedDbTable`'s call to\n // `openIdb(tableName, ...)`).\n return new IndexedDbTabularMigrationApplier(this.table, this.table, {\n getPage: (req) =>\n // The applier types `cursor` as `unknown` to avoid coupling to the\n // PageCursor branded type; cast at the boundary.\n this.getPage(req as Parameters<typeof this.getPage>[0]) as Promise<{\n items: Array<Record<string, unknown>>;\n nextCursor?: unknown;\n }>,\n put: (row) => this.put(row as Parameters<typeof this.put>[0]),\n delete: (row) => this.delete(row as Parameters<typeof this.delete>[0]),\n });\n }\n\n /**\n * Integer autoincrement keys are handled by IndexedDB's autoIncrement; this\n * only generates UUID keys client-side.\n */\n protected override generateKeyValue(\n columnName: string,\n strategy: KeyGenerationStrategy\n ): string | number {\n if (strategy === \"uuid\") {\n return uuid4();\n }\n throw new Error(\n `IndexedDB autoincrement keys are generated by the database, not client-side. Column: ${columnName}`\n );\n }\n\n /**\n * Resolve client-side key-generation policy for a single record and return\n * the entity the caller should hand to `store.put`. Shared by {@link put}\n * and {@link putBulkInTransaction} so the autoincrement / UUID /\n * clientProvidedKeys rules stay in one place.\n *\n * Throws synchronously on `clientProvidedKeys: \"always\"` without a key,\n * so the failure surfaces before any IDB transaction opens.\n */\n protected prepareRecordForPut(record: InsertType): Entity {\n let recordToStore = record as unknown as Entity;\n if (!this.hasAutoGeneratedKey() || !this.autoGeneratedKeyName) return recordToStore;\n\n const keyName = String(this.autoGeneratedKeyName);\n const clientProvidedValue = (record as Record<string, unknown>)[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n if (this.autoGeneratedKeyStrategy === \"uuid\") {\n let shouldGenerate = false;\n if (this.clientProvidedKeys === \"never\") {\n shouldGenerate = true;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldGenerate = false;\n } else {\n shouldGenerate = !hasClientValue;\n }\n\n if (shouldGenerate) {\n const generatedValue = this.generateKeyValue(keyName, \"uuid\");\n recordToStore = { ...record, [keyName]: generatedValue } as Entity;\n }\n } else if (this.autoGeneratedKeyStrategy === \"autoincrement\") {\n if (this.clientProvidedKeys === \"always\" && !hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n if (this.clientProvidedKeys === \"never\") {\n const { [keyName]: _, ...rest } = record as Record<string, unknown>;\n recordToStore = rest as Entity;\n }\n }\n return recordToStore;\n }\n\n /**\n * @emits put - Emitted when the value is successfully stored\n */\n async put(record: InsertType): Promise<Entity> {\n const db = await this.getDb();\n let recordToStore = this.prepareRecordForPut(record);\n\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.put(recordToStore);\n request.onerror = () => {\n reject(request.error);\n };\n request.onsuccess = () => {\n if (\n this.hasAutoGeneratedKey() &&\n this.autoGeneratedKeyName &&\n this.autoGeneratedKeyStrategy === \"autoincrement\"\n ) {\n const keyName = String(this.autoGeneratedKeyName);\n if (recordToStore[keyName as keyof Entity] === undefined) {\n recordToStore = { ...recordToStore, [keyName]: request.result } as Entity;\n }\n }\n safeEmit(this.events, \"put\", recordToStore);\n resolve(recordToStore);\n };\n transaction.oncomplete = () => {\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n /**\n * @emits put - Emitted for each record successfully stored\n */\n async putBulk(records: InsertType[]): Promise<Entity[]> {\n return await this.putBulkInTransaction(records);\n }\n\n /**\n * Atomic batch put: stages every record into a single `readwrite`\n * transaction and only emits per-row `put` events after `tx.oncomplete`,\n * so a failure on any record aborts the whole batch and no subscriber\n * observes uncommitted rows. Used by vector storages (which need an\n * all-or-nothing guarantee for chunk ingestion) — the inherited\n * Promise.all-based `putBulk` opens one transaction per row and can\n * leave the store half-written if the second or later request errors.\n *\n * Per-row `put` events fire from `tx.oncomplete`, which means subscribers\n * to {@link put} see batched commits as a burst after the transaction\n * succeeds rather than interleaved with the IDB requests.\n *\n * Wraps the transaction-open in a single retry to absorb the\n * `InvalidStateError` that fires when an `onversionchange` close races a\n * brand-new transaction.\n */\n protected async putBulkInTransaction(records: InsertType[]): Promise<Entity[]> {\n if (records.length === 0) return [];\n const prepared = records.map((r) => this.prepareRecordForPut(r));\n\n const run = async (): Promise<Entity[]> => {\n const db = await this.getDb();\n return new Promise<Entity[]>((resolve, reject) => {\n let tx: IDBTransaction;\n try {\n tx = db.transaction(this.table, \"readwrite\");\n } catch (err) {\n reject(err);\n return;\n }\n const store = tx.objectStore(this.table);\n const results: Entity[] = new Array(prepared.length);\n const useAutoincrement =\n this.hasAutoGeneratedKey() &&\n this.autoGeneratedKeyName !== undefined &&\n this.autoGeneratedKeyStrategy === \"autoincrement\";\n const keyName = useAutoincrement ? String(this.autoGeneratedKeyName) : undefined;\n\n // Wire the transaction-level settlers BEFORE issuing any request so a\n // request that errors mid-batch (which aborts the whole transaction)\n // is always observed, regardless of how far the loop got.\n tx.oncomplete = () => {\n for (const r of results) safeEmit(this.events, \"put\", r);\n this.hybridManager?.notifyLocalChange();\n resolve(results);\n };\n tx.onerror = () => reject(tx.error);\n tx.onabort = () => reject(tx.error ?? new Error(\"putBulk transaction aborted\"));\n\n try {\n for (let i = 0; i < prepared.length; i++) {\n const recordToStore = prepared[i];\n const request = store.put(recordToStore);\n // Capture the autoincrement key IDB assigned, so the\n // per-row result mirrors the single-`put` contract.\n request.onsuccess = () => {\n let finalRecord = recordToStore;\n if (useAutoincrement && keyName !== undefined) {\n if (finalRecord[keyName as keyof Entity] === undefined) {\n finalRecord = { ...finalRecord, [keyName]: request.result } as Entity;\n }\n }\n results[i] = finalRecord;\n };\n // No-op request error handler: we deliberately do NOT call\n // `event.preventDefault()`, so the error still propagates and\n // aborts the whole transaction (settled via `tx.onabort`). The\n // handler only stops the IDB engine from reporting it as an\n // uncaught request error.\n request.onerror = () => {};\n }\n } catch (err) {\n // `store.put()` can throw synchronously — `DataError` on a value that\n // fails structured clone in a real browser, or `InvalidStateError`\n // when the connection is closing. Requests already issued in this\n // loop are live on the transaction, so abort it to keep the batch\n // all-or-nothing before surfacing the error (the caller retries the\n // `InvalidStateError` case against a fresh connection).\n try {\n tx.abort();\n } catch {\n // transaction may already be inactive / aborting\n }\n reject(err);\n }\n });\n };\n\n try {\n return await run();\n } catch (err) {\n // `InvalidStateError` fires when the IDB connection was closed under\n // us by an `onversionchange` (e.g. a migration in another tab bumped\n // the version). Drop the stale handle so `getDb()` re-opens, then\n // retry exactly once.\n if (err instanceof DOMException && err.name === \"InvalidStateError\") {\n // The first attempt's transaction never reached `tx.oncomplete` (where\n // per-row `put` events fire), so no committed row was visible. Do NOT\n // emit a `rollback` here: the retry below may succeed and commit the\n // whole batch, in which case a rollback event would falsely signal that\n // nothing landed. Only emit rollback if the retry itself fails.\n try {\n this.db?.close();\n } catch {\n // best-effort: connection may already be closed.\n }\n this.db = undefined;\n try {\n return await run();\n } catch (retryErr) {\n safeEmit(this.events, \"rollback\", {\n op: \"putBulkInTransaction\",\n error: retryErr,\n ids: [],\n });\n throw retryErr;\n }\n }\n safeEmit(this.events, \"rollback\", { op: \"putBulkInTransaction\", error: err, ids: [] });\n throw err;\n }\n }\n\n protected override getPrimaryKeyAsOrderedArray(key: PrimaryKey) {\n return super\n .getPrimaryKeyAsOrderedArray(key)\n .map((value) => (typeof value === \"bigint\" ? value.toString() : value));\n }\n\n private getIndexedKey(key: PrimaryKey): any {\n const keys = super\n .getPrimaryKeyAsOrderedArray(key)\n .map((value) => (typeof value === \"bigint\" ? value.toString() : value));\n return keys.length === 1 ? keys[0] : keys;\n }\n\n /**\n * @emits get - Emitted when the value is successfully retrieved\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.get(this.getIndexedKey(key));\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n if (!request.result) {\n safeEmit(this.events, \"get\", key, undefined);\n resolve(undefined);\n return;\n }\n safeEmit(this.events, \"get\", key, request.result);\n resolve(request.result);\n };\n });\n }\n\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n const db = await this.getDb();\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.getAll();\n return new Promise((resolve, reject) => {\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n let values: Entity[] = request.result;\n if (values.length === 0) {\n resolve(undefined);\n return;\n }\n\n if (options?.orderBy && options.orderBy.length > 0) {\n values.sort((a, b) => {\n for (const { column, direction } of options.orderBy!) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n });\n }\n\n if (options?.offset !== undefined) {\n values = values.slice(options.offset);\n }\n\n if (options?.limit !== undefined) {\n values = values.slice(0, options.limit);\n }\n\n resolve(values.length > 0 ? values : undefined);\n };\n });\n }\n\n async delete(key: PrimaryKey): Promise<void> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.delete(this.getIndexedKey(key));\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n safeEmit(this.events, \"delete\", key as Partial<Entity>);\n resolve();\n };\n transaction.oncomplete = () => {\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n /**\n * @emits clearall - Emitted when all values are deleted\n */\n async deleteAll(): Promise<void> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.clear();\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n safeEmit(this.events, \"clearall\");\n resolve();\n };\n transaction.oncomplete = () => {\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n async size(): Promise<number> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.count();\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n });\n }\n\n /**\n * Returns the subset of configured indexes safe to use for cursor-based\n * narrowing — those whose every column is required by the schema AND cannot\n * hold null. IDB excludes a record from an index when the keyPath component\n * is undefined, and equally when it is null (null is not a valid key), so\n * iterating an index would silently miss records for either shape.\n *\n * A required-but-nullable column is the second case: legal here, impossible\n * in SQL (a required column is emitted `NOT NULL`), and invisible to the\n * caller because the scan returns fewer rows rather than failing.\n */\n private getCursorSafeIndexes(): Array<Array<keyof Entity>> {\n if (this.cursorSafeIndexes) return this.cursorSafeIndexes;\n const required = new Set(this.schema.required ?? []);\n const properties = this.schema.properties as Record<string, JsonSchema | undefined>;\n // Unique tuples are materialized as real IDB indexes (see `performSetup`)\n // under the same `cols.join(\"_\")` name the planner derives, so they can\n // narrow scans exactly like regular indexes. The base class guarantees no\n // tuple appears in both lists, so the union has no duplicate.\n this.cursorSafeIndexes = [...this.indexes, ...this.uniqueIndexes].filter((columns) =>\n columns.every(\n (column) => required.has(String(column)) && !schemaAdmitsNull(properties[String(column)])\n )\n );\n return this.cursorSafeIndexes;\n }\n\n /**\n * Picks the best index to narrow a criteria-based scan, preferring indexes\n * whose prefix covers every criteria column (so callers can use the native\n * `count()` API) and falling back to the longest equality-prefix match.\n *\n * Upper bound uses `[]` as a sentinel that compares greater than any\n * primitive value at the next index position (per IndexedDB key ordering:\n * array > binary > string > date > number). Assumes subsequent indexed\n * columns hold primitive values — array-valued columns would compare\n * greater than `[]` and slip outside the range.\n */\n private createIndexedRange(\n store: IDBObjectStore,\n criteria: SearchCriteria<Entity>\n ):\n | {\n source: IDBObjectStore | IDBIndex;\n range: IDBKeyRange | undefined;\n coversCriteria: boolean;\n }\n | undefined {\n const criteriaColumns = Object.keys(criteria) as Array<keyof Entity>;\n if (criteriaColumns.length === 0) return undefined;\n\n let best:\n | {\n indexName: string;\n prefixValues: unknown[];\n fullMatch: boolean;\n coversCriteria: boolean;\n }\n | undefined;\n\n for (const indexColumns of this.getCursorSafeIndexes()) {\n const prefixValues: unknown[] = [];\n for (const column of indexColumns) {\n const value = this.getEqualityCriterionValue(criteria, column);\n if (value === undefined) break;\n prefixValues.push(value);\n }\n\n if (prefixValues.length === 0) continue;\n\n const indexedPrefix = indexColumns.slice(0, prefixValues.length);\n const coversCriteria = criteriaColumns.every((column) => indexedPrefix.includes(column));\n\n const better =\n !best ||\n (coversCriteria && !best.coversCriteria) ||\n (coversCriteria === best.coversCriteria && prefixValues.length > best.prefixValues.length);\n\n if (better) {\n best = {\n indexName: indexColumns.map((column) => String(column)).join(\"_\"),\n prefixValues,\n fullMatch: prefixValues.length === indexColumns.length,\n coversCriteria,\n };\n }\n }\n\n if (!best) return undefined;\n\n const range = best.fullMatch\n ? IDBKeyRange.only(best.prefixValues.length === 1 ? best.prefixValues[0] : best.prefixValues)\n : IDBKeyRange.bound(best.prefixValues, [...best.prefixValues, []]);\n\n return {\n source: store.index(best.indexName),\n range,\n coversCriteria: best.coversCriteria,\n };\n }\n\n /**\n * Counts rows matching the specified search criteria.\n *\n * Uses the native `count()` API when an index prefix covers every criteria\n * column. Otherwise narrows via the longest matching index prefix and\n * filters the remaining columns during cursor iteration. Falls back to a\n * full store scan only when no index applies.\n */\n override async count(criteria?: SearchCriteria<Entity>): Promise<number> {\n if (!criteria || Object.keys(criteria).length === 0) {\n return await this.size();\n }\n\n this.validateQueryParams(criteria);\n const db = await this.getDb();\n\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const plan = this.createIndexedRange(store, criteria);\n\n if (plan?.coversCriteria) {\n const request = plan.source.count(plan.range);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n return;\n }\n\n const source = plan?.source ?? store;\n const range = plan?.range;\n let count = 0;\n const request = source.openCursor(range);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n const cursor = request.result;\n if (!cursor) {\n resolve(count);\n return;\n }\n if (this.matchesCriteria(cursor.value as Entity, criteria)) {\n count += 1;\n }\n cursor.continue();\n };\n });\n }\n\n async getOffsetPage(offset: number, limit: number): Promise<Entity[] | undefined> {\n if (offset < 0) {\n throw new RangeError(`offset must be non-negative, got ${offset}`);\n }\n if (limit <= 0) {\n return undefined;\n }\n\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.openCursor();\n const entities: Entity[] = [];\n let skipped = false;\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n const cursor = request.result;\n if (cursor) {\n if (!skipped && offset > 0) {\n skipped = true;\n cursor.advance(offset);\n return;\n }\n\n entities.push(cursor.value);\n if (entities.length === limit) {\n resolve(entities);\n return;\n }\n cursor.continue();\n } else {\n resolve(entities.length > 0 ? entities : undefined);\n }\n };\n });\n }\n\n private matchesCriteria(record: Entity, criteria: DeleteSearchCriteria<Entity>): boolean {\n for (const column of Object.keys(criteria) as Array<keyof Entity>) {\n const criterion = criteria[column];\n const recordValue = record[column];\n\n const normalized = normalizeCriterion<Entity[keyof Entity]>(criterion);\n if (normalized.kind === \"in\") {\n // Strict membership, matching the `=` arm: no coercion.\n if (!normalized.values.some((candidate) => recordValue === candidate)) return false;\n continue;\n }\n const { operator, value } = normalized;\n\n // `=` and `!=` carry their own null semantics (see the matches* helpers);\n // every ordering operator is UNKNOWN against null, so the row is excluded.\n if (\n operator !== \"=\" &&\n operator !== \"!=\" &&\n (recordValue === null || recordValue === undefined)\n ) {\n return false;\n }\n\n switch (operator) {\n case \"=\":\n // Shared rule: a null criterion matches null OR an absent column.\n if (!matchesEqualityCriterion(recordValue, value)) return false;\n break;\n case \"!=\":\n if (!matchesInequalityCriterion(recordValue, value)) return false;\n break;\n case \"<\":\n if (!(recordValue < value)) return false;\n break;\n case \"<=\":\n if (!(recordValue <= value)) return false;\n break;\n case \">\":\n if (!(recordValue > value)) return false;\n break;\n case \">=\":\n if (!(recordValue >= value)) return false;\n break;\n default:\n return false;\n }\n }\n return true;\n }\n\n async deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n const criteriaKeys = Object.keys(criteria) as Array<keyof Entity>;\n if (criteriaKeys.length === 0) {\n return;\n }\n\n const db = await this.getDb();\n\n return new Promise((resolve, reject) => {\n try {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n\n transaction.oncomplete = () => {\n safeEmit(this.events, \"delete\", this.deleteIdentity(criteria));\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n\n transaction.onerror = () => {\n reject(transaction.error);\n };\n\n const getAllRequest = store.getAll();\n\n getAllRequest.onsuccess = () => {\n const allRecords: Entity[] = getAllRequest.result;\n\n const recordsToDelete = allRecords.filter((record) =>\n this.matchesCriteria(record, criteria)\n );\n\n if (recordsToDelete.length === 0) {\n return;\n }\n\n for (const record of recordsToDelete) {\n const primaryKey = this.primaryKeyColumns().reduce((key, col) => {\n // @ts-expect-error - We know these properties exist on the record\n key[col] = record[col];\n return key;\n }, {} as PrimaryKey);\n\n const request = store.delete(this.getIndexedKey(primaryKey));\n\n request.onerror = () => {\n console.error(\"Error deleting record:\", request.error);\n };\n }\n };\n\n getAllRequest.onerror = () => {\n reject(getAllRequest.error);\n };\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * Compare-and-swap `updateWhere`: opens a single `readwrite` transaction\n * on the object store, walks the first cursor row satisfying `match`,\n * applies `patch` in place via `cursor.update()`, and resolves on\n * `tx.oncomplete`. Two concurrent callers with overlapping `match`\n * criteria therefore serialize on the underlying IDB transaction rather\n * than racing between a `query()` and a `put()`. Uniqueness is enforced\n * by IDB's native UNIQUE indexes — a patch that collides with another\n * row rejects the cursor request with `ConstraintError`, which aborts\n * the transaction (mirroring how {@link put} propagates the same error).\n *\n * The cursor source is picked with the same equality-prefix planner\n * {@link createIndexedRange} uses for {@link count}: an index scan when\n * an equality prefix narrows the criteria, otherwise a full store scan.\n */\n async updateWhere(\n match: SearchCriteria<Entity>,\n patch: Partial<Entity>\n ): Promise<Entity | undefined> {\n this.assertPatchKeepsPrimaryKey(patch);\n this.validateQueryParams(match);\n const db = await this.getDb();\n\n return new Promise<Entity | undefined>((resolve, reject) => {\n let tx: IDBTransaction;\n try {\n tx = db.transaction(this.table, \"readwrite\");\n } catch (err) {\n reject(err);\n return;\n }\n const store = tx.objectStore(this.table);\n const plan = this.createIndexedRange(store, match);\n const source = plan?.source ?? store;\n const range = plan?.range;\n\n let updated: Entity | undefined;\n\n tx.oncomplete = () => {\n if (updated !== undefined) {\n safeEmit(this.events, \"put\", updated);\n this.hybridManager?.notifyLocalChange();\n }\n resolve(updated);\n };\n tx.onerror = () => reject(tx.error);\n tx.onabort = () => reject(tx.error ?? new Error(\"updateWhere transaction aborted\"));\n\n const request = source.openCursor(range);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n const cursor = request.result;\n if (!cursor) return;\n\n const record = cursor.value as Entity;\n if (!this.matchesCriteria(record, match)) {\n cursor.continue();\n return;\n }\n\n const candidate = { ...record, ...patch } as Entity;\n const updateRequest = cursor.update(candidate);\n updateRequest.onsuccess = () => {\n updated = candidate;\n };\n updateRequest.onerror = () => {\n // Let the ConstraintError (unique-index collision) abort the\n // transaction; tx.onabort surfaces it to the caller.\n };\n };\n });\n }\n\n private getEqualityCriterionValue(\n criteria: SearchCriteria<Entity>,\n column: keyof Entity\n ): Entity[keyof Entity] | undefined {\n const criterion = criteria[column];\n if (criterion === undefined) return undefined;\n // An `in` list is not a single key, so it can't drive an IDB index lookup;\n // returning undefined sends it to the in-cursor filter instead.\n if (isSearchInCondition(criterion)) return undefined;\n if (isSearchCondition(criterion)) {\n if (criterion.operator !== \"=\") return undefined;\n // `null` is not a valid IDB key, so `IDBKeyRange.only`/`bound` would throw\n // a DataError on it. No range could serve the criterion anyway: IDB omits\n // a record from an index entirely when its indexed value is null, so the\n // rows being asked for are not in the index to be scanned. Report the\n // criterion as unusable for narrowing and let `matchesEqualityCriterion`\n // in the cursor filter decide it.\n if (criterion.value === null) return undefined;\n return criterion.value as Entity[keyof Entity];\n }\n if (criterion === null) return undefined;\n return criterion as Entity[keyof Entity];\n }\n\n private compareByOrder(a: Entity, b: Entity, options?: QueryOptions<Entity>): number {\n if (!options?.orderBy) return 0;\n for (const { column, direction } of options.orderBy) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n }\n\n private createIndexedQuery(\n store: IDBObjectStore,\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): {\n source: IDBObjectStore | IDBIndex;\n range: IDBKeyRange | undefined;\n direction: IDBCursorDirection;\n satisfiesOrder: boolean;\n appliedLimit: boolean;\n appliedOffset: boolean;\n skipRemaining: number;\n } {\n const orderBy = options?.orderBy ?? [];\n let best:\n | {\n indexName: string;\n prefixValues: unknown[];\n fullMatch: boolean;\n satisfiesOrder: boolean;\n direction: IDBCursorDirection;\n }\n | undefined;\n\n for (const indexColumns of this.getCursorSafeIndexes()) {\n const prefixValues: unknown[] = [];\n for (const column of indexColumns) {\n const value = this.getEqualityCriterionValue(criteria, column);\n if (value === undefined) break;\n prefixValues.push(value);\n }\n\n if (prefixValues.length === 0) continue;\n\n const remainingColumns = indexColumns.slice(prefixValues.length);\n let redundantOrderPrefixLength = 0;\n while (\n redundantOrderPrefixLength < orderBy.length &&\n redundantOrderPrefixLength < prefixValues.length &&\n orderBy[redundantOrderPrefixLength]?.column === indexColumns[redundantOrderPrefixLength]\n ) {\n redundantOrderPrefixLength++;\n }\n const normalizedOrderBy = orderBy.slice(redundantOrderPrefixLength);\n const satisfiesOrder =\n normalizedOrderBy.length === 0 ||\n (normalizedOrderBy.length <= remainingColumns.length &&\n normalizedOrderBy.every((order, index) => order.column === remainingColumns[index]) &&\n orderBy.every((order) => order.direction === orderBy[0]?.direction));\n\n if (!satisfiesOrder && best) continue;\n\n if (\n !best ||\n (satisfiesOrder && !best.satisfiesOrder) ||\n prefixValues.length > best.prefixValues.length\n ) {\n best = {\n indexName: indexColumns.map((column) => String(column)).join(\"_\"),\n prefixValues,\n fullMatch: prefixValues.length === indexColumns.length,\n satisfiesOrder,\n direction: orderBy[0]?.direction === \"DESC\" ? \"prev\" : \"next\",\n };\n }\n }\n\n const appliedLimit = Boolean(best?.satisfiesOrder && options?.limit !== undefined);\n const appliedOffset = Boolean(best?.satisfiesOrder && options?.offset !== undefined);\n\n if (!best) {\n return {\n source: store,\n range: undefined,\n direction: orderBy[0]?.direction === \"DESC\" ? \"prev\" : \"next\",\n satisfiesOrder: false,\n appliedLimit: false,\n appliedOffset: false,\n skipRemaining: 0,\n };\n }\n\n const source = store.index(best.indexName);\n // See createIndexedRange for the `[]` upper-bound sentinel rationale.\n const keyRange = best.fullMatch\n ? IDBKeyRange.only(best.prefixValues.length === 1 ? best.prefixValues[0] : best.prefixValues)\n : IDBKeyRange.bound(best.prefixValues, [...best.prefixValues, []]);\n\n return {\n source,\n range: keyRange,\n direction: best.direction,\n satisfiesOrder: best.satisfiesOrder,\n appliedLimit,\n appliedOffset,\n skipRemaining: appliedOffset ? (options?.offset ?? 0) : 0,\n };\n }\n\n async query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n this.validateQueryParams(criteria, options);\n const db = await this.getDb();\n\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const indexedQuery = this.createIndexedQuery(store, criteria, options);\n const results: Entity[] = [];\n const request = indexedQuery.source.openCursor(indexedQuery.range, indexedQuery.direction);\n\n request.onsuccess = () => {\n const cursor = request.result;\n if (!cursor) {\n let finalResults = results;\n\n if (!indexedQuery.satisfiesOrder && options?.orderBy && options.orderBy.length > 0) {\n finalResults = [...finalResults].sort((a, b) => this.compareByOrder(a, b, options));\n }\n\n if (!indexedQuery.appliedOffset && options?.offset !== undefined) {\n finalResults = finalResults.slice(options.offset);\n }\n\n if (!indexedQuery.appliedLimit && options?.limit !== undefined) {\n finalResults = finalResults.slice(0, options.limit);\n }\n\n const result = finalResults.length > 0 ? finalResults : undefined;\n safeEmit(this.events, \"query\", criteria as Partial<Entity>, result);\n resolve(result);\n return;\n }\n\n const record = cursor.value as Entity;\n if (this.matchesCriteria(record, criteria)) {\n if (indexedQuery.skipRemaining > 0) {\n indexedQuery.skipRemaining -= 1;\n } else {\n results.push(record);\n if (indexedQuery.appliedLimit && results.length === options?.limit) {\n const result = results.length > 0 ? results : undefined;\n safeEmit(this.events, \"query\", criteria as Partial<Entity>, result);\n resolve(result);\n return;\n }\n }\n }\n\n cursor.continue();\n };\n\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Strict, projected query served entirely by a covering compound index.\n * Uses `openKeyCursor` — never reads `cursor.value` — so only the index key\n * bytes are loaded into memory. Ideal for tables with large value blobs.\n *\n * Throws {@link CoveringIndexMissingError} when no registered index can serve\n * the request (i.e. the index does not cover all select + orderBy columns).\n *\n * A `null` equality criterion on a column of the chosen index is rejected with\n * {@link StorageUnsupportedError}. IndexedDB omits a record from an index when\n * its indexed value is null, so those rows exist in no index and a projection\n * reading values out of `cursor.key` can never produce them — the request\n * would return silently-empty results rather than the matching rows. Use\n * {@link query}, which reads whole records and filters them in the cursor.\n */\n override async queryIndex<K extends keyof Entity & string>(\n criteria: SearchCriteria<Entity>,\n options: CoveringIndexQueryOptions<Entity, K>\n ): Promise<Pick<Entity, K>[]> {\n this.validateSelect(options);\n this.validateQueryParams(criteria, options);\n\n const registered = this.indexes.map((cols) => {\n const cs = Array.isArray(cols) ? (cols as string[]) : [cols as string];\n return { name: cs.join(\"_\"), keyPath: cs };\n });\n\n const picked = pickCoveringIndex({\n table: this.table,\n indexes: registered,\n criteriaColumns: Object.keys(criteria),\n orderByColumns: (options.orderBy ?? []).map((o) => ({\n column: String(o.column),\n direction: o.direction,\n })),\n selectColumns: options.select.map(String),\n primaryKeyColumns: this.primaryKeyColumns().map(String),\n });\n\n for (const col of picked.keyPath) {\n const criterion = (criteria as Record<string, unknown>)[col];\n const isNullEquality = isSearchCondition(criterion)\n ? criterion.operator === \"=\" && criterion.value === null\n : criterion === null;\n if (isNullEquality) {\n throw new StorageUnsupportedError(\n `A null equality criterion on indexed column \"${col}\" (IndexedDB omits ` +\n `null-valued records from an index, so an index scan can never reach ` +\n `them — use query() instead)`,\n \"IndexedDbTabularStorage\"\n );\n }\n }\n\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.table, \"readonly\");\n const store = tx.objectStore(this.table);\n const idx = store.index(picked.name);\n\n // Only push columns whose criterion is a direct equality. A non-equality\n // operator breaks the prefix; the in-cursor compareWithOperator filter\n // below handles those columns.\n const prefix: unknown[] = [];\n for (const col of picked.keyPath) {\n const c = (criteria as Record<string, unknown>)[col];\n if (c === undefined && !(col in (criteria as Record<string, unknown>))) break;\n // An `in` list matches several keys, so it cannot extend a single\n // equality prefix — stop here and let the in-cursor filter handle it.\n if (isSearchInCondition(c)) break;\n if (isSearchCondition(c)) {\n if (c.operator !== \"=\") break;\n // Defense in depth: the guard above already rejected a null equality\n // on a key-path column, and `null` is not a valid IDB key.\n if (c.value === null) break;\n prefix.push(c.value);\n } else {\n if (c === null) break;\n prefix.push(c);\n }\n }\n // `[...prefix, []]` is greater than any key starting with prefix in IDB's\n // comparison ordering — used as the upper bound for prefix scans.\n const range =\n prefix.length === 0\n ? undefined\n : prefix.length === picked.keyPath.length\n ? IDBKeyRange.only(prefix.length === 1 ? prefix[0] : prefix)\n : IDBKeyRange.bound(prefix, [...prefix, []]);\n\n const direction: IDBCursorDirection = picked.reverseDirection ? \"prev\" : \"next\";\n // openKeyCursor — never reads cursor.value, only the index key and primaryKey\n const request = idx.openKeyCursor(range, direction);\n const out: Pick<Entity, K>[] = [];\n let toSkip = options.offset ?? 0;\n\n const keyPathPositions = new Map<string, number>();\n picked.keyPath.forEach((col, i) => keyPathPositions.set(col, i));\n\n const pkCols = this.primaryKeyColumns().map(String);\n const pkPositions = new Map<string, number>();\n pkCols.forEach((col, i) => pkPositions.set(col, i));\n\n request.onsuccess = () => {\n const cursor = request.result;\n if (!cursor) {\n resolve(out);\n return;\n }\n\n const key = cursor.key;\n\n const row = {} as Record<string, unknown>;\n for (const col of options.select) {\n const colStr = String(col);\n const pos = keyPathPositions.get(colStr);\n if (pos !== undefined) {\n row[colStr] = Array.isArray(key) ? key[pos] : key;\n } else {\n // Column must be a primary key column — use cursor.primaryKey\n if (pkCols.length === 1 && colStr === pkCols[0]) {\n row[colStr] = cursor.primaryKey;\n } else {\n const pkPos = pkPositions.get(colStr);\n if (pkPos !== undefined) {\n row[colStr] = Array.isArray(cursor.primaryKey)\n ? (cursor.primaryKey as unknown[])[pkPos]\n : cursor.primaryKey;\n }\n }\n }\n }\n\n // Apply criteria for index positions beyond the equality prefix.\n // Positions [0, prefix.length) are guaranteed-equal by the IDBKeyRange,\n // so they don't need re-checking. Positions >= prefix.length must be\n // filtered here — this includes plain-value equalities trailing a\n // non-equality break (criteria like `{a:1, b:>=5, c:3}` with prefix=[1]\n // need an in-cursor `c === 3` check) and any SearchCondition.\n let matches = true;\n for (const [col, crit] of Object.entries(criteria as Record<string, unknown>)) {\n const pos = keyPathPositions.get(col);\n if (pos === undefined) continue;\n if (pos < prefix.length) continue; // covered by IDBKeyRange\n const valFromKey = Array.isArray(key) ? (key as unknown[])[pos] : key;\n const normalized = normalizeCriterion<unknown>(crit);\n const ok =\n normalized.kind === \"in\"\n ? normalized.values.some((candidate) => valFromKey === candidate)\n : compareWithOperator(valFromKey, normalized.operator, normalized.value);\n if (!ok) {\n matches = false;\n break;\n }\n }\n\n if (matches) {\n if (toSkip > 0) {\n toSkip -= 1;\n } else {\n out.push(row as Pick<Entity, K>);\n if (options.limit !== undefined && out.length >= options.limit) {\n resolve(out);\n return;\n }\n }\n }\n\n cursor.continue();\n };\n\n request.onerror = () => reject(request.error);\n });\n }\n\n private getHybridManager(): HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n > {\n if (!this.hybridManager) {\n const channelName = `indexeddb-tabular-${this.table}`;\n\n this.hybridManager = new HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n >(\n channelName,\n async () => {\n const entities = (await this.getAll()) || [];\n const map = new Map<string, Entity>();\n for (const entity of entities) {\n const { key } = this.separateKeyValueFromCombined(entity);\n const fingerprint = await makeFingerprint(key);\n map.set(fingerprint, entity);\n }\n return map;\n },\n compareEntitiesForChange,\n {\n insert: (item) => ({ type: \"INSERT\" as const, new: item }),\n update: (oldItem, newItem) => ({ type: \"UPDATE\" as const, old: oldItem, new: newItem }),\n delete: (item) => ({ type: \"DELETE\" as const, old: item }),\n },\n {\n defaultIntervalMs: 1000,\n useBroadcastChannel: this.hybridOptions.useBroadcastChannel,\n backupPollingIntervalMs: this.hybridOptions.backupPollingIntervalMs,\n }\n );\n }\n return this.hybridManager;\n }\n\n /**\n * Uses polling since IndexedDB has no native cross-tab change notifications.\n */\n public override subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Kept synchronous; the hybrid manager's getAll() invokes setupDatabase()\n // when needed.\n const intervalMs = options?.pollingIntervalMs ?? 1000;\n const manager = this.getHybridManager();\n return manager.subscribe(callback, { intervalMs });\n }\n\n public override destroy(): void {\n if (this.hybridManager) {\n this.hybridManager.destroy();\n this.hybridManager = null;\n }\n this.db?.close();\n }\n}\n\n/**\n * Whether a column's schema admits `null`, in any of the spellings JSON Schema\n * offers for it. Mirrors the nullability test the SQL backends use to decide\n * between `NULL` and `NOT NULL`.\n */\nfunction schemaAdmitsNull(typeDef: JsonSchema | undefined): boolean {\n if (typeDef === undefined) return false;\n if (typeof typeDef === \"boolean\") return typeDef;\n if (typeDef.type === \"null\") return true;\n if (Array.isArray(typeDef.type)) return typeDef.type.includes(\"null\");\n const branches = typeDef.anyOf ?? typeDef.oneOf;\n if (Array.isArray(branches)) {\n return branches.some((branch) => typeof branch !== \"boolean\" && branch.type === \"null\");\n }\n return false;\n}\n\n/**\n * Compare two values using a SearchOperator. Used by queryIndex to evaluate\n * non-equality criteria that cannot be expressed as an IDBKeyRange prefix.\n */\nfunction compareWithOperator(a: unknown, op: SearchOperator, b: unknown): boolean {\n const av = a as string | number | null | undefined;\n const bv = b as string | number;\n switch (op) {\n case \"=\":\n // Same rule `matchesCriteria` applies, so the two agree on every input.\n return matchesEqualityCriterion(av, bv);\n case \"!=\":\n return matchesInequalityCriterion(av, bv);\n case \"<\":\n return av !== null && av !== undefined && av < bv;\n case \"<=\":\n return av !== null && av !== undefined && av <= bv;\n case \">\":\n return av !== null && av !== undefined && av > bv;\n case \">=\":\n return av !== null && av !== undefined && av >= bv;\n }\n}\n",
8
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {\n AnyTabularStorage,\n AutoGeneratedKeys,\n ClientProvidedKeysOption,\n CoveringIndexQueryOptions,\n DeleteSearchCriteria,\n InsertEntity,\n KeyGenerationStrategy,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n} from \"@workglow/storage\";\nimport {\n BaseTabularStorage,\n HybridSubscriptionManager,\n isSearchCondition,\n isSearchInCondition,\n isSearchNotInCondition,\n matchesEqualityCriterion,\n matchesInCriterion,\n matchesInequalityCriterion,\n matchesNotInCriterion,\n normalizeCriterion,\n pickCoveringIndex,\n safeEmit,\n StorageUnsupportedError,\n type ITabularMigration,\n type ITabularMigrationApplier,\n} from \"@workglow/storage\";\nimport { createServiceToken, deepEqual, makeFingerprint, uuid4 } from \"@workglow/util\";\nimport type {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport type { ExpectedIndexDefinition, MigrationOptions } from \"./IndexedDbTable\";\nimport { ensureIndexedDbTable } from \"./IndexedDbTable\";\nimport {\n idbObjectStoreExists,\n IndexedDbTabularMigrationApplier,\n} from \"./IndexedDbTabularMigrationApplier\";\n\nexport const IDB_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.indexedDb\"\n);\n\n/**\n * Polling change-detection comparator for the hybrid subscription manager.\n *\n * Naively comparing entities via serialized equality is correct but\n * O(size-of-entity) per poll. That falls apart for tables\n * holding large blobs — e.g. an `activities` row whose `output_data` carries\n * a multi-megabyte `Uint8ClampedArray`: each poll cycle (default 1 s) would\n * stringify ~16 MB per row × N rows, locking the main thread.\n *\n * Fast path: if both rows expose a string `updated_at`, compare just those.\n * The repositories in this codebase bump `updated_at` on every write (see\n * `ActivityRepository.updateActivity`), so the timestamp is a sufficient\n * change witness. Fall back to the structural compare for tables that don't\n * follow that convention so correctness is preserved everywhere.\n */\nfunction compareEntitiesForChange<T>(a: T, b: T): boolean {\n const au = (a as { updated_at?: unknown })?.updated_at;\n const bu = (b as { updated_at?: unknown })?.updated_at;\n if (typeof au === \"string\" && typeof bu === \"string\") {\n return au === bu;\n }\n return deepEqual(a, b);\n}\n\n/**\n * A tabular repository implementation using IndexedDB for browser-based storage.\n *\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class IndexedDbTabularStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n // computed types\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n Value = Omit<Entity, PrimaryKeyNames[number] & keyof Entity>,\n InsertType extends InsertEntity<Entity, AutoGeneratedKeys<Schema>> = InsertEntity<\n Entity,\n AutoGeneratedKeys<Schema>\n >,\n> extends BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n private db: IDBDatabase | undefined;\n /**\n * True between `setupDatabase`'s call to `applyTabularMigrations` and its\n * completion. Backfill ops inside the orchestrator may close `this.db`\n * (via `onversionchange` from the next migration's upgrade) and trigger\n * a re-entrant `setupDatabase` call from `getDb()`. The re-entrant call\n * must only re-open the IDB connection — it MUST NOT recurse into the\n * orchestrator, or migrations will be replayed mid-flight.\n */\n private applyingMigrations = false;\n private setupPromise: Promise<IDBDatabase> | null = null;\n private migrationOptions: MigrationOptions;\n private hybridManager: HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n > | null = null;\n private readonly hybridOptions: {\n readonly useBroadcastChannel: boolean;\n readonly backupPollingIntervalMs: number;\n };\n /**\n * Indexes safe for cursor-based narrowing. An IDB index excludes records\n * whose keyPath has any undefined component, and equally any null one (null\n * is not a valid key), so iterating an index can miss records when an indexed\n * column is optional in the schema or its type admits null. Native\n * `count(range)` and cursor scans are only correct over indexes whose every\n * column is required and non-nullable. Computed lazily on first use.\n */\n private cursorSafeIndexes: Array<Array<keyof Entity>> | undefined;\n\n /**\n * Creates a new IndexedDB-based tabular repository.\n * @param table - Name of the IndexedDB store to use.\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable. Each string or single column creates a single-column index,\n * while each array creates a compound index with columns in the specified order.\n * @param migrationOptions - Options for handling database schema migrations\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n * @param tabularMigrations - Declarative migrations evolving the store schema\n * @param uniqueIndexes - Compound column tuples enforced as native IDB UNIQUE\n * indexes (`store.createIndex(..., { unique: true })`).\n * A `put` whose tuple collides with another record's\n * rejects with a `ConstraintError`.\n */\n constructor(\n public table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n migrationOptions: MigrationOptions & {\n readonly useBroadcastChannel?: boolean;\n readonly backupPollingIntervalMs?: number;\n } = {},\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\",\n tabularMigrations?: ReadonlyArray<ITabularMigration>,\n uniqueIndexes: readonly (readonly (keyof NoInfer<Entity>)[])[] = []\n ) {\n super(\n schema,\n primaryKeyNames,\n indexes,\n clientProvidedKeys,\n tabularMigrations,\n table,\n uniqueIndexes\n );\n this.migrationOptions = migrationOptions;\n this.hybridOptions = {\n useBroadcastChannel: migrationOptions.useBroadcastChannel ?? true,\n backupPollingIntervalMs: migrationOptions.backupPollingIntervalMs ?? 5000,\n };\n }\n\n private async getDb(): Promise<IDBDatabase> {\n if (this.db) return this.db;\n await this.setupDatabase();\n return this.db!;\n }\n\n /**\n * Sets up the IndexedDB database table with the required schema and indexes.\n * Must be called before using any other methods.\n */\n public override async setupDatabase(): Promise<void> {\n if (this.db) return;\n if (this.setupPromise) {\n await this.setupPromise;\n return;\n }\n\n // Re-entrant guard: when called from inside an in-flight migration\n // (typically because a backfill's `getPage` hit a closed connection\n // after the previous migration's upgrade-tx version bump), only\n // re-open the IDB connection. Re-running `applyTabularMigrations`\n // here would replay the orchestrator and double-apply migrations.\n if (this.applyingMigrations) {\n this.setupPromise = this.performSetup();\n try {\n this.db = await this.setupPromise;\n this.rewireOnVersionChange();\n } finally {\n this.setupPromise = null;\n }\n return;\n }\n\n // Probe whether the object store already exists BEFORE performSetup\n // creates it. The orchestrator needs this signal to take the\n // mark-all-applied fast path on a brand-new DB; otherwise it would\n // see the (just-created) store and try to apply ops against the\n // already-current target schema.\n const freshTable =\n this.tabularMigrations && this.tabularMigrations.length > 0\n ? !(await this.probeObjectStoreExists())\n : false;\n\n this.setupPromise = this.performSetup();\n try {\n this.db = await this.setupPromise;\n } finally {\n this.setupPromise = null;\n }\n\n if (this.tabularMigrations && this.tabularMigrations.length > 0) {\n this.rewireOnVersionChange();\n this.applyingMigrations = true;\n try {\n await this.applyTabularMigrations({ freshTable });\n } finally {\n this.applyingMigrations = false;\n }\n // After migrations, this.db may be undefined (closed by onversionchange).\n // Reopen so the storage is ready for use.\n if (!this.db) {\n this.db = await this.performSetup();\n }\n }\n }\n\n /**\n * Wires `onversionchange` so that when the migration runner bumps the IDB\n * version (currentVersion + 1 to trigger onupgradeneeded), the current\n * open connection is both closed AND cleared from `this.db`. Without the\n * clear, getDb() would return a stale closed connection and throw\n * InvalidStateError on the next transaction attempt (e.g. during backfill).\n */\n private rewireOnVersionChange(): void {\n if (!this.db) return;\n this.db.onversionchange = () => {\n this.db?.close();\n this.db = undefined;\n };\n }\n\n /**\n * Read-only probe: does the object store already exist in the IDB\n * database? Used by `setupDatabase` to decide between the orchestrator's\n * fresh-DB fast path (mark-all-applied) and the run-pending path.\n * Delegates to the shared `idbObjectStoreExists` helper.\n */\n private async probeObjectStoreExists(): Promise<boolean> {\n return idbObjectStoreExists(this.table, this.table);\n }\n\n private async performSetup(): Promise<IDBDatabase> {\n const pkColumns = super.primaryKeyColumns() as string[];\n\n const expectedIndexes: ExpectedIndexDefinition[] = [];\n\n for (const spec of this.indexes) {\n const columns = spec as Array<keyof Entity>;\n // Skip if this is just the primary key or a prefix of it\n if (columns.length <= pkColumns.length) {\n const isPkPrefix = columns.every((col, idx) => col === pkColumns[idx]);\n if (isPkPrefix) continue;\n }\n\n const columnNames = columns.map((col) => String(col));\n const indexName = columnNames.join(\"_\");\n expectedIndexes.push({\n name: indexName,\n keyPath: columnNames.length === 1 ? columnNames[0] : columnNames,\n options: { unique: false },\n });\n }\n\n // Declared unique tuples become native IDB UNIQUE indexes so a colliding\n // `put` is rejected with a `ConstraintError` — the browser-tier equivalent\n // of the `CREATE UNIQUE INDEX` the SQL backends emit. The base class has\n // already dropped any regular index whose tuple exactly matches a unique\n // tuple, so reusing the plain `cols.join(\"_\")` name cannot collide; it also\n // lets the query planner narrow on the unique index (see\n // {@link getCursorSafeIndexes}). IDB excludes records with an\n // undefined/invalid keyPath component from an index, so NULL/undefined tuple\n // values never trip the constraint — matching SQL's \"NULL is distinct\".\n for (const columns of this.uniqueIndexes) {\n const columnNames = (columns as Array<keyof Entity>).map((col) => String(col));\n const indexName = columnNames.join(\"_\");\n expectedIndexes.push({\n name: indexName,\n keyPath: columnNames.length === 1 ? columnNames[0] : columnNames,\n options: { unique: true },\n });\n }\n\n const primaryKey = pkColumns.length === 1 ? pkColumns[0] : pkColumns;\n\n // IndexedDB autoIncrement only works with single numeric keys\n const useAutoIncrement =\n this.hasAutoGeneratedKey() &&\n this.autoGeneratedKeyStrategy === \"autoincrement\" &&\n pkColumns.length === 1;\n\n return await ensureIndexedDbTable(\n this.table,\n primaryKey,\n expectedIndexes,\n this.migrationOptions,\n useAutoIncrement\n );\n }\n\n public override getMigrationApplier(): ITabularMigrationApplier | null {\n // The IDB tabular storage uses `this.table` as both the database name\n // and the object store name (see `ensureIndexedDbTable`'s call to\n // `openIdb(tableName, ...)`).\n return new IndexedDbTabularMigrationApplier(this.table, this.table, {\n getPage: (req) =>\n // The applier types `cursor` as `unknown` to avoid coupling to the\n // PageCursor branded type; cast at the boundary.\n this.getPage(req as Parameters<typeof this.getPage>[0]) as Promise<{\n items: Array<Record<string, unknown>>;\n nextCursor?: unknown;\n }>,\n put: (row) => this.put(row as Parameters<typeof this.put>[0]),\n delete: (row) => this.delete(row as Parameters<typeof this.delete>[0]),\n });\n }\n\n /**\n * Integer autoincrement keys are handled by IndexedDB's autoIncrement; this\n * only generates UUID keys client-side.\n */\n protected override generateKeyValue(\n columnName: string,\n strategy: KeyGenerationStrategy\n ): string | number {\n if (strategy === \"uuid\") {\n return uuid4();\n }\n throw new Error(\n `IndexedDB autoincrement keys are generated by the database, not client-side. Column: ${columnName}`\n );\n }\n\n /**\n * Resolve client-side key-generation policy for a single record and return\n * the entity the caller should hand to `store.put`. Shared by {@link put}\n * and {@link putBulkInTransaction} so the autoincrement / UUID /\n * clientProvidedKeys rules stay in one place.\n *\n * Throws synchronously on `clientProvidedKeys: \"always\"` without a key,\n * so the failure surfaces before any IDB transaction opens.\n */\n protected prepareRecordForPut(record: InsertType): Entity {\n let recordToStore = record as unknown as Entity;\n if (!this.hasAutoGeneratedKey() || !this.autoGeneratedKeyName) return recordToStore;\n\n const keyName = String(this.autoGeneratedKeyName);\n const clientProvidedValue = (record as Record<string, unknown>)[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n if (this.autoGeneratedKeyStrategy === \"uuid\") {\n let shouldGenerate = false;\n if (this.clientProvidedKeys === \"never\") {\n shouldGenerate = true;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldGenerate = false;\n } else {\n shouldGenerate = !hasClientValue;\n }\n\n if (shouldGenerate) {\n const generatedValue = this.generateKeyValue(keyName, \"uuid\");\n recordToStore = { ...record, [keyName]: generatedValue } as Entity;\n }\n } else if (this.autoGeneratedKeyStrategy === \"autoincrement\") {\n if (this.clientProvidedKeys === \"always\" && !hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n if (this.clientProvidedKeys === \"never\") {\n const { [keyName]: _, ...rest } = record as Record<string, unknown>;\n recordToStore = rest as Entity;\n }\n }\n return recordToStore;\n }\n\n /**\n * @emits put - Emitted when the value is successfully stored\n */\n async put(record: InsertType): Promise<Entity> {\n const db = await this.getDb();\n let recordToStore = this.prepareRecordForPut(record);\n\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.put(recordToStore);\n request.onerror = () => {\n reject(request.error);\n };\n request.onsuccess = () => {\n if (\n this.hasAutoGeneratedKey() &&\n this.autoGeneratedKeyName &&\n this.autoGeneratedKeyStrategy === \"autoincrement\"\n ) {\n const keyName = String(this.autoGeneratedKeyName);\n if (recordToStore[keyName as keyof Entity] === undefined) {\n recordToStore = { ...recordToStore, [keyName]: request.result } as Entity;\n }\n }\n safeEmit(this.events, \"put\", recordToStore);\n resolve(recordToStore);\n };\n transaction.oncomplete = () => {\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n /**\n * @emits put - Emitted for each record successfully stored\n */\n async putBulk(records: InsertType[]): Promise<Entity[]> {\n return await this.putBulkInTransaction(records);\n }\n\n /**\n * Atomic batch put: stages every record into a single `readwrite`\n * transaction and only emits per-row `put` events after `tx.oncomplete`,\n * so a failure on any record aborts the whole batch and no subscriber\n * observes uncommitted rows. Used by vector storages (which need an\n * all-or-nothing guarantee for chunk ingestion) — the inherited\n * Promise.all-based `putBulk` opens one transaction per row and can\n * leave the store half-written if the second or later request errors.\n *\n * Per-row `put` events fire from `tx.oncomplete`, which means subscribers\n * to {@link put} see batched commits as a burst after the transaction\n * succeeds rather than interleaved with the IDB requests.\n *\n * Wraps the transaction-open in a single retry to absorb the\n * `InvalidStateError` that fires when an `onversionchange` close races a\n * brand-new transaction.\n */\n protected async putBulkInTransaction(records: InsertType[]): Promise<Entity[]> {\n if (records.length === 0) return [];\n const prepared = records.map((r) => this.prepareRecordForPut(r));\n\n const run = async (): Promise<Entity[]> => {\n const db = await this.getDb();\n return new Promise<Entity[]>((resolve, reject) => {\n let tx: IDBTransaction;\n try {\n tx = db.transaction(this.table, \"readwrite\");\n } catch (err) {\n reject(err);\n return;\n }\n const store = tx.objectStore(this.table);\n const results: Entity[] = new Array(prepared.length);\n const useAutoincrement =\n this.hasAutoGeneratedKey() &&\n this.autoGeneratedKeyName !== undefined &&\n this.autoGeneratedKeyStrategy === \"autoincrement\";\n const keyName = useAutoincrement ? String(this.autoGeneratedKeyName) : undefined;\n\n // Wire the transaction-level settlers BEFORE issuing any request so a\n // request that errors mid-batch (which aborts the whole transaction)\n // is always observed, regardless of how far the loop got.\n tx.oncomplete = () => {\n for (const r of results) safeEmit(this.events, \"put\", r);\n this.hybridManager?.notifyLocalChange();\n resolve(results);\n };\n tx.onerror = () => reject(tx.error);\n tx.onabort = () => reject(tx.error ?? new Error(\"putBulk transaction aborted\"));\n\n try {\n for (let i = 0; i < prepared.length; i++) {\n const recordToStore = prepared[i];\n const request = store.put(recordToStore);\n // Capture the autoincrement key IDB assigned, so the\n // per-row result mirrors the single-`put` contract.\n request.onsuccess = () => {\n let finalRecord = recordToStore;\n if (useAutoincrement && keyName !== undefined) {\n if (finalRecord[keyName as keyof Entity] === undefined) {\n finalRecord = { ...finalRecord, [keyName]: request.result } as Entity;\n }\n }\n results[i] = finalRecord;\n };\n // No-op request error handler: we deliberately do NOT call\n // `event.preventDefault()`, so the error still propagates and\n // aborts the whole transaction (settled via `tx.onabort`). The\n // handler only stops the IDB engine from reporting it as an\n // uncaught request error.\n request.onerror = () => {};\n }\n } catch (err) {\n // `store.put()` can throw synchronously — `DataError` on a value that\n // fails structured clone in a real browser, or `InvalidStateError`\n // when the connection is closing. Requests already issued in this\n // loop are live on the transaction, so abort it to keep the batch\n // all-or-nothing before surfacing the error (the caller retries the\n // `InvalidStateError` case against a fresh connection).\n try {\n tx.abort();\n } catch {\n // transaction may already be inactive / aborting\n }\n reject(err);\n }\n });\n };\n\n try {\n return await run();\n } catch (err) {\n // `InvalidStateError` fires when the IDB connection was closed under\n // us by an `onversionchange` (e.g. a migration in another tab bumped\n // the version). Drop the stale handle so `getDb()` re-opens, then\n // retry exactly once.\n if (err instanceof DOMException && err.name === \"InvalidStateError\") {\n // The first attempt's transaction never reached `tx.oncomplete` (where\n // per-row `put` events fire), so no committed row was visible. Do NOT\n // emit a `rollback` here: the retry below may succeed and commit the\n // whole batch, in which case a rollback event would falsely signal that\n // nothing landed. Only emit rollback if the retry itself fails.\n try {\n this.db?.close();\n } catch {\n // best-effort: connection may already be closed.\n }\n this.db = undefined;\n try {\n return await run();\n } catch (retryErr) {\n safeEmit(this.events, \"rollback\", {\n op: \"putBulkInTransaction\",\n error: retryErr,\n ids: [],\n });\n throw retryErr;\n }\n }\n safeEmit(this.events, \"rollback\", { op: \"putBulkInTransaction\", error: err, ids: [] });\n throw err;\n }\n }\n\n protected override getPrimaryKeyAsOrderedArray(key: PrimaryKey) {\n return super\n .getPrimaryKeyAsOrderedArray(key)\n .map((value) => (typeof value === \"bigint\" ? value.toString() : value));\n }\n\n private getIndexedKey(key: PrimaryKey): any {\n const keys = super\n .getPrimaryKeyAsOrderedArray(key)\n .map((value) => (typeof value === \"bigint\" ? value.toString() : value));\n return keys.length === 1 ? keys[0] : keys;\n }\n\n /**\n * @emits get - Emitted when the value is successfully retrieved\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.get(this.getIndexedKey(key));\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n if (!request.result) {\n safeEmit(this.events, \"get\", key, undefined);\n resolve(undefined);\n return;\n }\n safeEmit(this.events, \"get\", key, request.result);\n resolve(request.result);\n };\n });\n }\n\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n const db = await this.getDb();\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.getAll();\n return new Promise((resolve, reject) => {\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n let values: Entity[] = request.result;\n if (values.length === 0) {\n resolve(undefined);\n return;\n }\n\n if (options?.orderBy && options.orderBy.length > 0) {\n values.sort((a, b) => {\n for (const { column, direction } of options.orderBy!) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n });\n }\n\n if (options?.offset !== undefined) {\n values = values.slice(options.offset);\n }\n\n if (options?.limit !== undefined) {\n values = values.slice(0, options.limit);\n }\n\n resolve(values.length > 0 ? values : undefined);\n };\n });\n }\n\n async delete(key: PrimaryKey): Promise<void> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.delete(this.getIndexedKey(key));\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n safeEmit(this.events, \"delete\", key as Partial<Entity>);\n resolve();\n };\n transaction.oncomplete = () => {\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n /**\n * @emits clearall - Emitted when all values are deleted\n */\n async deleteAll(): Promise<void> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.clear();\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n safeEmit(this.events, \"clearall\");\n resolve();\n };\n transaction.oncomplete = () => {\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n async size(): Promise<number> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.count();\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n });\n }\n\n /**\n * Returns the subset of configured indexes safe to use for cursor-based\n * narrowing — those whose every column is required by the schema AND cannot\n * hold null. IDB excludes a record from an index when the keyPath component\n * is undefined, and equally when it is null (null is not a valid key), so\n * iterating an index would silently miss records for either shape.\n *\n * A required-but-nullable column is the second case: legal here, impossible\n * in SQL (a required column is emitted `NOT NULL`), and invisible to the\n * caller because the scan returns fewer rows rather than failing.\n */\n private getCursorSafeIndexes(): Array<Array<keyof Entity>> {\n if (this.cursorSafeIndexes) return this.cursorSafeIndexes;\n const required = new Set(this.schema.required ?? []);\n const properties = this.schema.properties as Record<string, JsonSchema | undefined>;\n // Unique tuples are materialized as real IDB indexes (see `performSetup`)\n // under the same `cols.join(\"_\")` name the planner derives, so they can\n // narrow scans exactly like regular indexes. The base class guarantees no\n // tuple appears in both lists, so the union has no duplicate.\n this.cursorSafeIndexes = [...this.indexes, ...this.uniqueIndexes].filter((columns) =>\n columns.every(\n (column) => required.has(String(column)) && !schemaAdmitsNull(properties[String(column)])\n )\n );\n return this.cursorSafeIndexes;\n }\n\n /**\n * Picks the best index to narrow a criteria-based scan, preferring indexes\n * whose prefix covers every criteria column (so callers can use the native\n * `count()` API) and falling back to the longest equality-prefix match.\n *\n * Upper bound uses `[]` as a sentinel that compares greater than any\n * primitive value at the next index position (per IndexedDB key ordering:\n * array > binary > string > date > number). Assumes subsequent indexed\n * columns hold primitive values — array-valued columns would compare\n * greater than `[]` and slip outside the range.\n */\n private createIndexedRange(\n store: IDBObjectStore,\n criteria: SearchCriteria<Entity>\n ):\n | {\n source: IDBObjectStore | IDBIndex;\n range: IDBKeyRange | undefined;\n coversCriteria: boolean;\n }\n | undefined {\n const criteriaColumns = Object.keys(criteria) as Array<keyof Entity>;\n if (criteriaColumns.length === 0) return undefined;\n\n let best:\n | {\n indexName: string;\n prefixValues: unknown[];\n fullMatch: boolean;\n coversCriteria: boolean;\n }\n | undefined;\n\n for (const indexColumns of this.getCursorSafeIndexes()) {\n const prefixValues: unknown[] = [];\n for (const column of indexColumns) {\n const value = this.getEqualityCriterionValue(criteria, column);\n if (value === undefined) break;\n prefixValues.push(value);\n }\n\n if (prefixValues.length === 0) continue;\n\n const indexedPrefix = indexColumns.slice(0, prefixValues.length);\n const coversCriteria = criteriaColumns.every((column) => indexedPrefix.includes(column));\n\n const better =\n !best ||\n (coversCriteria && !best.coversCriteria) ||\n (coversCriteria === best.coversCriteria && prefixValues.length > best.prefixValues.length);\n\n if (better) {\n best = {\n indexName: indexColumns.map((column) => String(column)).join(\"_\"),\n prefixValues,\n fullMatch: prefixValues.length === indexColumns.length,\n coversCriteria,\n };\n }\n }\n\n if (!best) return undefined;\n\n const range = best.fullMatch\n ? IDBKeyRange.only(best.prefixValues.length === 1 ? best.prefixValues[0] : best.prefixValues)\n : IDBKeyRange.bound(best.prefixValues, [...best.prefixValues, []]);\n\n return {\n source: store.index(best.indexName),\n range,\n coversCriteria: best.coversCriteria,\n };\n }\n\n /**\n * Counts rows matching the specified search criteria.\n *\n * Uses the native `count()` API when an index prefix covers every criteria\n * column. Otherwise narrows via the longest matching index prefix and\n * filters the remaining columns during cursor iteration. Falls back to a\n * full store scan only when no index applies.\n */\n override async count(criteria?: SearchCriteria<Entity>): Promise<number> {\n if (!criteria || Object.keys(criteria).length === 0) {\n return await this.size();\n }\n\n this.validateQueryParams(criteria);\n const db = await this.getDb();\n\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const plan = this.createIndexedRange(store, criteria);\n\n if (plan?.coversCriteria) {\n const request = plan.source.count(plan.range);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n return;\n }\n\n const source = plan?.source ?? store;\n const range = plan?.range;\n let count = 0;\n const request = source.openCursor(range);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n const cursor = request.result;\n if (!cursor) {\n resolve(count);\n return;\n }\n if (this.matchesCriteria(cursor.value as Entity, criteria)) {\n count += 1;\n }\n cursor.continue();\n };\n });\n }\n\n async getOffsetPage(offset: number, limit: number): Promise<Entity[] | undefined> {\n if (offset < 0) {\n throw new RangeError(`offset must be non-negative, got ${offset}`);\n }\n if (limit <= 0) {\n return undefined;\n }\n\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.openCursor();\n const entities: Entity[] = [];\n let skipped = false;\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n const cursor = request.result;\n if (cursor) {\n if (!skipped && offset > 0) {\n skipped = true;\n cursor.advance(offset);\n return;\n }\n\n entities.push(cursor.value);\n if (entities.length === limit) {\n resolve(entities);\n return;\n }\n cursor.continue();\n } else {\n resolve(entities.length > 0 ? entities : undefined);\n }\n };\n });\n }\n\n private matchesCriteria(record: Entity, criteria: DeleteSearchCriteria<Entity>): boolean {\n for (const column of Object.keys(criteria) as Array<keyof Entity>) {\n const criterion = criteria[column];\n const recordValue = record[column];\n\n const normalized = normalizeCriterion<Entity[keyof Entity]>(criterion);\n if (normalized.kind === \"in\") {\n // Strict membership, matching the `=` arm: no coercion.\n if (!matchesInCriterion(recordValue, normalized.values)) return false;\n continue;\n }\n if (normalized.kind === \"not-in\") {\n // Carries its own null rules (a null column is excluded, a null in the\n // list excludes everything), so it must precede the blanket null check\n // below rather than being folded into it.\n if (!matchesNotInCriterion(recordValue, normalized.values)) return false;\n continue;\n }\n const { operator, value } = normalized;\n\n // `=` and `!=` carry their own null semantics (see the matches* helpers);\n // every ordering operator is UNKNOWN against null, so the row is excluded.\n if (\n operator !== \"=\" &&\n operator !== \"!=\" &&\n (recordValue === null || recordValue === undefined)\n ) {\n return false;\n }\n\n switch (operator) {\n case \"=\":\n // Shared rule: a null criterion matches null OR an absent column.\n if (!matchesEqualityCriterion(recordValue, value)) return false;\n break;\n case \"!=\":\n if (!matchesInequalityCriterion(recordValue, value)) return false;\n break;\n case \"<\":\n if (!(recordValue < value)) return false;\n break;\n case \"<=\":\n if (!(recordValue <= value)) return false;\n break;\n case \">\":\n if (!(recordValue > value)) return false;\n break;\n case \">=\":\n if (!(recordValue >= value)) return false;\n break;\n default:\n return false;\n }\n }\n return true;\n }\n\n async deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n if (!this.shouldRunDeleteSearch(criteria)) return;\n\n const db = await this.getDb();\n\n return new Promise((resolve, reject) => {\n try {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n\n transaction.oncomplete = () => {\n safeEmit(this.events, \"delete\", this.deleteIdentity(criteria));\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n\n transaction.onerror = () => {\n reject(transaction.error);\n };\n\n const getAllRequest = store.getAll();\n\n getAllRequest.onsuccess = () => {\n const allRecords: Entity[] = getAllRequest.result;\n\n const recordsToDelete = allRecords.filter((record) =>\n this.matchesCriteria(record, criteria)\n );\n\n if (recordsToDelete.length === 0) {\n return;\n }\n\n for (const record of recordsToDelete) {\n const primaryKey = this.primaryKeyColumns().reduce((key, col) => {\n // @ts-expect-error - We know these properties exist on the record\n key[col] = record[col];\n return key;\n }, {} as PrimaryKey);\n\n const request = store.delete(this.getIndexedKey(primaryKey));\n\n request.onerror = () => {\n console.error(\"Error deleting record:\", request.error);\n };\n }\n };\n\n getAllRequest.onerror = () => {\n reject(getAllRequest.error);\n };\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * Compare-and-swap `updateWhere`: opens a single `readwrite` transaction\n * on the object store, walks the first cursor row satisfying `match`,\n * applies `patch` in place via `cursor.update()`, and resolves on\n * `tx.oncomplete`. Two concurrent callers with overlapping `match`\n * criteria therefore serialize on the underlying IDB transaction rather\n * than racing between a `query()` and a `put()`. Uniqueness is enforced\n * by IDB's native UNIQUE indexes — a patch that collides with another\n * row rejects the cursor request with `ConstraintError`, which aborts\n * the transaction (mirroring how {@link put} propagates the same error).\n *\n * The cursor source is picked with the same equality-prefix planner\n * {@link createIndexedRange} uses for {@link count}: an index scan when\n * an equality prefix narrows the criteria, otherwise a full store scan.\n */\n async updateWhere(\n match: SearchCriteria<Entity>,\n patch: Partial<Entity>\n ): Promise<Entity | undefined> {\n this.assertPatchKeepsPrimaryKey(patch);\n this.validateQueryParams(match);\n const db = await this.getDb();\n\n return new Promise<Entity | undefined>((resolve, reject) => {\n let tx: IDBTransaction;\n try {\n tx = db.transaction(this.table, \"readwrite\");\n } catch (err) {\n reject(err);\n return;\n }\n const store = tx.objectStore(this.table);\n const plan = this.createIndexedRange(store, match);\n const source = plan?.source ?? store;\n const range = plan?.range;\n\n let updated: Entity | undefined;\n\n tx.oncomplete = () => {\n if (updated !== undefined) {\n safeEmit(this.events, \"put\", updated);\n this.hybridManager?.notifyLocalChange();\n }\n resolve(updated);\n };\n tx.onerror = () => reject(tx.error);\n tx.onabort = () => reject(tx.error ?? new Error(\"updateWhere transaction aborted\"));\n\n const request = source.openCursor(range);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n const cursor = request.result;\n if (!cursor) return;\n\n const record = cursor.value as Entity;\n if (!this.matchesCriteria(record, match)) {\n cursor.continue();\n return;\n }\n\n const candidate = { ...record, ...patch } as Entity;\n const updateRequest = cursor.update(candidate);\n updateRequest.onsuccess = () => {\n updated = candidate;\n };\n updateRequest.onerror = () => {\n // Let the ConstraintError (unique-index collision) abort the\n // transaction; tx.onabort surfaces it to the caller.\n };\n };\n });\n }\n\n private getEqualityCriterionValue(\n criteria: SearchCriteria<Entity>,\n column: keyof Entity\n ): Entity[keyof Entity] | undefined {\n const criterion = criteria[column];\n if (criterion === undefined) return undefined;\n // A list criterion is not a single key, so it can't drive an IDB index\n // lookup; returning undefined sends it to the in-cursor filter instead.\n // Both list guards must be tested: neither passes `isSearchCondition`, so\n // an unguarded `not-in` would fall through to the literal-value return at\n // the bottom and be used as an equality key — silently matching nothing.\n if (isSearchInCondition(criterion) || isSearchNotInCondition(criterion)) return undefined;\n if (isSearchCondition(criterion)) {\n if (criterion.operator !== \"=\") return undefined;\n // `null` is not a valid IDB key, so `IDBKeyRange.only`/`bound` would throw\n // a DataError on it. No range could serve the criterion anyway: IDB omits\n // a record from an index entirely when its indexed value is null, so the\n // rows being asked for are not in the index to be scanned. Report the\n // criterion as unusable for narrowing and let `matchesEqualityCriterion`\n // in the cursor filter decide it.\n if (criterion.value === null) return undefined;\n return criterion.value as Entity[keyof Entity];\n }\n if (criterion === null) return undefined;\n return criterion as Entity[keyof Entity];\n }\n\n private compareByOrder(a: Entity, b: Entity, options?: QueryOptions<Entity>): number {\n if (!options?.orderBy) return 0;\n for (const { column, direction } of options.orderBy) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n }\n\n private createIndexedQuery(\n store: IDBObjectStore,\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): {\n source: IDBObjectStore | IDBIndex;\n range: IDBKeyRange | undefined;\n direction: IDBCursorDirection;\n satisfiesOrder: boolean;\n appliedLimit: boolean;\n appliedOffset: boolean;\n skipRemaining: number;\n } {\n const orderBy = options?.orderBy ?? [];\n let best:\n | {\n indexName: string;\n prefixValues: unknown[];\n fullMatch: boolean;\n satisfiesOrder: boolean;\n direction: IDBCursorDirection;\n }\n | undefined;\n\n for (const indexColumns of this.getCursorSafeIndexes()) {\n const prefixValues: unknown[] = [];\n for (const column of indexColumns) {\n const value = this.getEqualityCriterionValue(criteria, column);\n if (value === undefined) break;\n prefixValues.push(value);\n }\n\n if (prefixValues.length === 0) continue;\n\n const remainingColumns = indexColumns.slice(prefixValues.length);\n let redundantOrderPrefixLength = 0;\n while (\n redundantOrderPrefixLength < orderBy.length &&\n redundantOrderPrefixLength < prefixValues.length &&\n orderBy[redundantOrderPrefixLength]?.column === indexColumns[redundantOrderPrefixLength]\n ) {\n redundantOrderPrefixLength++;\n }\n const normalizedOrderBy = orderBy.slice(redundantOrderPrefixLength);\n const satisfiesOrder =\n normalizedOrderBy.length === 0 ||\n (normalizedOrderBy.length <= remainingColumns.length &&\n normalizedOrderBy.every((order, index) => order.column === remainingColumns[index]) &&\n orderBy.every((order) => order.direction === orderBy[0]?.direction));\n\n if (!satisfiesOrder && best) continue;\n\n if (\n !best ||\n (satisfiesOrder && !best.satisfiesOrder) ||\n prefixValues.length > best.prefixValues.length\n ) {\n best = {\n indexName: indexColumns.map((column) => String(column)).join(\"_\"),\n prefixValues,\n fullMatch: prefixValues.length === indexColumns.length,\n satisfiesOrder,\n direction: orderBy[0]?.direction === \"DESC\" ? \"prev\" : \"next\",\n };\n }\n }\n\n const appliedLimit = Boolean(best?.satisfiesOrder && options?.limit !== undefined);\n const appliedOffset = Boolean(best?.satisfiesOrder && options?.offset !== undefined);\n\n if (!best) {\n return {\n source: store,\n range: undefined,\n direction: orderBy[0]?.direction === \"DESC\" ? \"prev\" : \"next\",\n satisfiesOrder: false,\n appliedLimit: false,\n appliedOffset: false,\n skipRemaining: 0,\n };\n }\n\n const source = store.index(best.indexName);\n // See createIndexedRange for the `[]` upper-bound sentinel rationale.\n const keyRange = best.fullMatch\n ? IDBKeyRange.only(best.prefixValues.length === 1 ? best.prefixValues[0] : best.prefixValues)\n : IDBKeyRange.bound(best.prefixValues, [...best.prefixValues, []]);\n\n return {\n source,\n range: keyRange,\n direction: best.direction,\n satisfiesOrder: best.satisfiesOrder,\n appliedLimit,\n appliedOffset,\n skipRemaining: appliedOffset ? (options?.offset ?? 0) : 0,\n };\n }\n\n async query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n this.validateQueryParams(criteria, options);\n const db = await this.getDb();\n\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const indexedQuery = this.createIndexedQuery(store, criteria, options);\n const results: Entity[] = [];\n const request = indexedQuery.source.openCursor(indexedQuery.range, indexedQuery.direction);\n\n request.onsuccess = () => {\n const cursor = request.result;\n if (!cursor) {\n let finalResults = results;\n\n if (!indexedQuery.satisfiesOrder && options?.orderBy && options.orderBy.length > 0) {\n finalResults = [...finalResults].sort((a, b) => this.compareByOrder(a, b, options));\n }\n\n if (!indexedQuery.appliedOffset && options?.offset !== undefined) {\n finalResults = finalResults.slice(options.offset);\n }\n\n if (!indexedQuery.appliedLimit && options?.limit !== undefined) {\n finalResults = finalResults.slice(0, options.limit);\n }\n\n const result = finalResults.length > 0 ? finalResults : undefined;\n safeEmit(this.events, \"query\", criteria as Partial<Entity>, result);\n resolve(result);\n return;\n }\n\n const record = cursor.value as Entity;\n if (this.matchesCriteria(record, criteria)) {\n if (indexedQuery.skipRemaining > 0) {\n indexedQuery.skipRemaining -= 1;\n } else {\n results.push(record);\n if (indexedQuery.appliedLimit && results.length === options?.limit) {\n const result = results.length > 0 ? results : undefined;\n safeEmit(this.events, \"query\", criteria as Partial<Entity>, result);\n resolve(result);\n return;\n }\n }\n }\n\n cursor.continue();\n };\n\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Strict, projected query served entirely by a covering compound index.\n * Uses `openKeyCursor` — never reads `cursor.value` — so only the index key\n * bytes are loaded into memory. Ideal for tables with large value blobs.\n *\n * Throws {@link CoveringIndexMissingError} when no registered index can serve\n * the request (i.e. the index does not cover all select + orderBy columns).\n *\n * A criterion on a column of the chosen index that must match null-valued\n * rows is rejected with {@link StorageUnsupportedError} — a `null` equality,\n * or an empty `not-in` list, which excludes nothing and so matches every row.\n * IndexedDB omits a record from an index when its indexed value is null, so\n * those rows exist in no index and a projection reading values out of\n * `cursor.key` can never produce them — the request would return\n * silently-short results rather than the matching rows. Use {@link query},\n * which reads whole records and filters them in the cursor.\n */\n override async queryIndex<K extends keyof Entity & string>(\n criteria: SearchCriteria<Entity>,\n options: CoveringIndexQueryOptions<Entity, K>\n ): Promise<Pick<Entity, K>[]> {\n this.validateSelect(options);\n this.validateQueryParams(criteria, options);\n\n const registered = this.indexes.map((cols) => {\n const cs = Array.isArray(cols) ? (cols as string[]) : [cols as string];\n return { name: cs.join(\"_\"), keyPath: cs };\n });\n\n const picked = pickCoveringIndex({\n table: this.table,\n indexes: registered,\n criteriaColumns: Object.keys(criteria),\n orderByColumns: (options.orderBy ?? []).map((o) => ({\n column: String(o.column),\n direction: o.direction,\n })),\n selectColumns: options.select.map(String),\n primaryKeyColumns: this.primaryKeyColumns().map(String),\n });\n\n for (const col of picked.keyPath) {\n const criterion = (criteria as Record<string, unknown>)[col];\n // An empty exclusion list matches every row, nulls included — the only\n // criterion besides a null equality that a null-valued column can\n // satisfy. Rejected for the same reason: those records are in no index,\n // so an index scan returns a silently short result instead of them.\n if (isSearchNotInCondition(criterion) && criterion.value.length === 0) {\n throw new StorageUnsupportedError(\n `An empty \"not-in\" criterion on indexed column \"${col}\" (it matches every ` +\n `row including null-valued ones, but IndexedDB omits those from an index, ` +\n `so an index scan can never reach them — use query() instead)`,\n \"IndexedDbTabularStorage\"\n );\n }\n const isNullEquality = isSearchCondition(criterion)\n ? criterion.operator === \"=\" && criterion.value === null\n : criterion === null;\n if (isNullEquality) {\n throw new StorageUnsupportedError(\n `A null equality criterion on indexed column \"${col}\" (IndexedDB omits ` +\n `null-valued records from an index, so an index scan can never reach ` +\n `them — use query() instead)`,\n \"IndexedDbTabularStorage\"\n );\n }\n }\n\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.table, \"readonly\");\n const store = tx.objectStore(this.table);\n const idx = store.index(picked.name);\n\n // Only push columns whose criterion is a direct equality. A non-equality\n // operator breaks the prefix; the in-cursor compareWithOperator filter\n // below handles those columns.\n const prefix: unknown[] = [];\n for (const col of picked.keyPath) {\n const c = (criteria as Record<string, unknown>)[col];\n if (c === undefined && !(col in (criteria as Record<string, unknown>))) break;\n // A list criterion matches several keys (or excludes some), so it\n // cannot extend a single equality prefix — stop here and let the\n // in-cursor filter handle it. Same reason both guards are needed here\n // as in `getEqualityCriterionValue`: a `not-in` that reached the\n // `else` below would be pushed onto the prefix as a raw key.\n if (isSearchInCondition(c) || isSearchNotInCondition(c)) break;\n if (isSearchCondition(c)) {\n if (c.operator !== \"=\") break;\n // Defense in depth: the guard above already rejected a null equality\n // on a key-path column, and `null` is not a valid IDB key.\n if (c.value === null) break;\n prefix.push(c.value);\n } else {\n // `undefined` breaks alongside `null`: it matches no row at all, and\n // pushing it would hand `IDBKeyRange` a value that is not a valid\n // key. Stopping here lets the in-cursor filter return the empty\n // answer the SQL backends give.\n if (c === null || c === undefined) break;\n prefix.push(c);\n }\n }\n // `[...prefix, []]` is greater than any key starting with prefix in IDB's\n // comparison ordering — used as the upper bound for prefix scans.\n const range =\n prefix.length === 0\n ? undefined\n : prefix.length === picked.keyPath.length\n ? IDBKeyRange.only(prefix.length === 1 ? prefix[0] : prefix)\n : IDBKeyRange.bound(prefix, [...prefix, []]);\n\n const direction: IDBCursorDirection = picked.reverseDirection ? \"prev\" : \"next\";\n // openKeyCursor — never reads cursor.value, only the index key and primaryKey\n const request = idx.openKeyCursor(range, direction);\n const out: Pick<Entity, K>[] = [];\n let toSkip = options.offset ?? 0;\n\n const keyPathPositions = new Map<string, number>();\n picked.keyPath.forEach((col, i) => keyPathPositions.set(col, i));\n\n const pkCols = this.primaryKeyColumns().map(String);\n const pkPositions = new Map<string, number>();\n pkCols.forEach((col, i) => pkPositions.set(col, i));\n\n request.onsuccess = () => {\n const cursor = request.result;\n if (!cursor) {\n resolve(out);\n return;\n }\n\n const key = cursor.key;\n\n const row = {} as Record<string, unknown>;\n for (const col of options.select) {\n const colStr = String(col);\n const pos = keyPathPositions.get(colStr);\n if (pos !== undefined) {\n row[colStr] = Array.isArray(key) ? key[pos] : key;\n } else {\n // Column must be a primary key column — use cursor.primaryKey\n if (pkCols.length === 1 && colStr === pkCols[0]) {\n row[colStr] = cursor.primaryKey;\n } else {\n const pkPos = pkPositions.get(colStr);\n if (pkPos !== undefined) {\n row[colStr] = Array.isArray(cursor.primaryKey)\n ? (cursor.primaryKey as unknown[])[pkPos]\n : cursor.primaryKey;\n }\n }\n }\n }\n\n // Apply criteria for index positions beyond the equality prefix.\n // Positions [0, prefix.length) are guaranteed-equal by the IDBKeyRange,\n // so they don't need re-checking. Positions >= prefix.length must be\n // filtered here — this includes plain-value equalities trailing a\n // non-equality break (criteria like `{a:1, b:>=5, c:3}` with prefix=[1]\n // need an in-cursor `c === 3` check) and any SearchCondition.\n let matches = true;\n for (const [col, crit] of Object.entries(criteria as Record<string, unknown>)) {\n const pos = keyPathPositions.get(col);\n if (pos === undefined) continue;\n if (pos < prefix.length) continue; // covered by IDBKeyRange\n const valFromKey = Array.isArray(key) ? (key as unknown[])[pos] : key;\n const normalized = normalizeCriterion<unknown>(crit);\n const ok =\n normalized.kind === \"in\"\n ? matchesInCriterion(valFromKey, normalized.values)\n : normalized.kind === \"not-in\"\n ? matchesNotInCriterion(valFromKey, normalized.values)\n : compareWithOperator(valFromKey, normalized.operator, normalized.value);\n if (!ok) {\n matches = false;\n break;\n }\n }\n\n if (matches) {\n if (toSkip > 0) {\n toSkip -= 1;\n } else {\n out.push(row as Pick<Entity, K>);\n if (options.limit !== undefined && out.length >= options.limit) {\n resolve(out);\n return;\n }\n }\n }\n\n cursor.continue();\n };\n\n request.onerror = () => reject(request.error);\n });\n }\n\n private getHybridManager(): HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n > {\n if (!this.hybridManager) {\n const channelName = `indexeddb-tabular-${this.table}`;\n\n this.hybridManager = new HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n >(\n channelName,\n async () => {\n const entities = (await this.getAll()) || [];\n const map = new Map<string, Entity>();\n for (const entity of entities) {\n const { key } = this.separateKeyValueFromCombined(entity);\n const fingerprint = await makeFingerprint(key);\n map.set(fingerprint, entity);\n }\n return map;\n },\n compareEntitiesForChange,\n {\n insert: (item) => ({ type: \"INSERT\" as const, new: item }),\n update: (oldItem, newItem) => ({ type: \"UPDATE\" as const, old: oldItem, new: newItem }),\n delete: (item) => ({ type: \"DELETE\" as const, old: item }),\n },\n {\n defaultIntervalMs: 1000,\n useBroadcastChannel: this.hybridOptions.useBroadcastChannel,\n backupPollingIntervalMs: this.hybridOptions.backupPollingIntervalMs,\n }\n );\n }\n return this.hybridManager;\n }\n\n /**\n * Uses polling since IndexedDB has no native cross-tab change notifications.\n */\n public override subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Kept synchronous; the hybrid manager's getAll() invokes setupDatabase()\n // when needed.\n const intervalMs = options?.pollingIntervalMs ?? 1000;\n const manager = this.getHybridManager();\n return manager.subscribe(callback, { intervalMs });\n }\n\n public override destroy(): void {\n if (this.hybridManager) {\n this.hybridManager.destroy();\n this.hybridManager = null;\n }\n this.db?.close();\n }\n}\n\n/**\n * Whether a column's schema admits `null`, in any of the spellings JSON Schema\n * offers for it. Mirrors the nullability test the SQL backends use to decide\n * between `NULL` and `NOT NULL`.\n */\nfunction schemaAdmitsNull(typeDef: JsonSchema | undefined): boolean {\n if (typeDef === undefined) return false;\n if (typeof typeDef === \"boolean\") return typeDef;\n if (typeDef.type === \"null\") return true;\n if (Array.isArray(typeDef.type)) return typeDef.type.includes(\"null\");\n const branches = typeDef.anyOf ?? typeDef.oneOf;\n if (Array.isArray(branches)) {\n return branches.some((branch) => typeof branch !== \"boolean\" && branch.type === \"null\");\n }\n return false;\n}\n\n/**\n * Compare two values using a SearchOperator. Used by queryIndex to evaluate\n * non-equality criteria that cannot be expressed as an IDBKeyRange prefix.\n */\nfunction compareWithOperator(a: unknown, op: SearchOperator, b: unknown): boolean {\n const av = a as string | number | null | undefined;\n const bv = b as string | number;\n switch (op) {\n case \"=\":\n // Same rule `matchesCriteria` applies, so the two agree on every input.\n return matchesEqualityCriterion(av, bv);\n case \"!=\":\n return matchesInequalityCriterion(av, bv);\n case \"<\":\n return av !== null && av !== undefined && av < bv;\n case \"<=\":\n return av !== null && av !== undefined && av <= bv;\n case \">\":\n return av !== null && av !== undefined && av > bv;\n case \">=\":\n return av !== null && av !== undefined && av >= bv;\n }\n}\n",
9
9
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {\n type IMigration,\n type IMigrationRunner,\n type RunMigrationsOptions,\n MIGRATIONS_TABLE,\n sortMigrations,\n} from \"@workglow/storage\";\n\n/**\n * Context handed to an IndexedDB migration's `up()` body. IDB's spec only\n * permits schema changes (createObjectStore, createIndex, etc.) inside an\n * `onupgradeneeded` callback, so migrations receive both the {@link IDBDatabase}\n * and the version-change {@link IDBTransaction} active during that callback.\n *\n * `up()` MUST be synchronous — IDB upgrade transactions auto-commit as soon as\n * the callback returns control to the event loop, so any awaited Promise\n * between IDB requests would silently lose the rest of the migration.\n */\nexport interface IndexedDbUpgradeContext {\n readonly db: IDBDatabase;\n readonly tx: IDBTransaction;\n readonly oldVersion: number;\n readonly newVersion: number;\n}\n\n/** Convenience alias for IndexedDB-flavoured migrations. */\nexport type IndexedDbMigration = IMigration<IndexedDbUpgradeContext>;\n\nfunction getIndexedDb(): IDBFactory {\n // Node test environments (vitest + fake-indexeddb) install a global; browsers\n // expose it natively. We don't pick a fallback because callers in unsupported\n // runtimes (Bun without polyfill, Node without setup) need a clear failure.\n const idb = (globalThis as { indexedDB?: IDBFactory }).indexedDB;\n if (!idb) {\n throw new Error(\n \"indexedDB is not available in this environment. Provide one via the IndexedDbMigrationRunner constructor or polyfill globalThis.indexedDB.\"\n );\n }\n return idb;\n}\n\n/**\n * Thrown when an in-flight migration is interrupted by another tab opening\n * the same database at a higher version. Surfaces as the `run()` rejection\n * so callers can distinguish a tab-coordination failure from a programming\n * error in `up()`.\n */\nexport class MigrationAbortedByOtherTabError extends Error {\n constructor(dbName: string) {\n super(`IndexedDB ${dbName} migration aborted: another tab requested a higher version`);\n this.name = \"MigrationAbortedByOtherTabError\";\n }\n}\n\n/**\n * Per-DB serialization for `run()`. IDB's open-with-higher-version semantics\n * mean two concurrent migrations of the same database can deadlock each other\n * (each holds an open connection that blocks the other's upgrade). We\n * serialize at the JS layer per-dbName so back-to-back `runIndexedDbMigrationGroups`\n * calls (which construct fresh runner instances) cooperate.\n *\n * Module-scoped so it spans runner instances; safe because the only state is\n * a Promise chain keyed by `dbName`.\n */\nconst RUN_LOCKS = new Map<string, Promise<unknown>>();\n\n/**\n * Runs versioned migrations against a single IndexedDB database.\n *\n * Bookkeeping-driven dispatch (NOT IDB-version-ordinal driven). The runner:\n * 1. Probes the DB to read the `_storage_migrations` object store, building\n * a set of already-applied `(component, version)` pairs. The probe\n * registers an `onupgradeneeded` handler so that if the DB doesn't yet\n * exist, IDB's auto-creation path also creates the bookkeeping store\n * atomically (rather than leaving an empty v1 DB with no schema).\n * 2. Computes the pending migrations as `sorted \\ alreadyApplied` —\n * identifying each migration by `(component, version)`, NOT by its\n * position in the sorted array. This means inserting a new migration\n * that sorts BEFORE existing ones (e.g. a new component name that's\n * lexicographically earlier) is still correctly detected as pending.\n * 3. If pending is empty, returns without bumping the IDB version.\n * 4. Otherwise reopens at `currentVersion + 1` and runs every pending\n * migration inside the upgrade transaction, recording each in the\n * bookkeeping store as it goes.\n *\n * Concurrent `run()` calls against the same dbName (across instances) are\n * serialized via {@link RUN_LOCKS} so that two callers don't deadlock each\n * other on the open-at-higher-version handshake.\n *\n * The IDB database version is treated purely as a monotonic trigger for\n * `onupgradeneeded`; we never use it to decide which migrations to apply.\n *\n * Caveats:\n * - `up()` must be synchronous. IDB upgrade transactions auto-commit as\n * soon as control returns to the event loop, so awaited Promises between\n * IDB requests would silently lose the rest of the migration. The runner\n * throws if `up()` returns a Promise.\n */\nexport class IndexedDbMigrationRunner implements IMigrationRunner<IndexedDbUpgradeContext> {\n constructor(\n private readonly dbName: string,\n private readonly idb: IDBFactory = getIndexedDb()\n ) {}\n\n /**\n * Probe the DB without forcing a schema change. Reads the bookkeeping\n * store (creating it on first run via the auto-fired upgrade callback)\n * and returns the current IDB version + the set of applied migrations\n * keyed by `${component}@${version}`.\n */\n private async probe(): Promise<{ currentVersion: number; applied: Set<string> }> {\n return new Promise((resolve, reject) => {\n // Multiple IDB callbacks (onupgradeneeded, onsuccess + nested getAll\n // success/error, onerror, onblocked) can fire in surprising orders —\n // e.g. an orphaned `onerror` after we've already returned a result.\n // Gate every settlement through `finalize` so the Promise resolves or\n // rejects exactly once, and so the open connection is closed exactly\n // once on the way out.\n let settled = false;\n const finalize = (\n db: IDBDatabase | undefined,\n outcome:\n | { ok: true; value: { currentVersion: number; applied: Set<string> } }\n | { ok: false; error: unknown }\n ): void => {\n if (settled) return;\n settled = true;\n if (db) {\n try {\n db.close();\n } catch {\n // ignore — close is best-effort\n }\n }\n if (outcome.ok) resolve(outcome.value);\n else reject(outcome.error);\n };\n\n const req = this.idb.open(this.dbName);\n req.onupgradeneeded = () => {\n if (settled) return;\n // Fires only when the DB doesn't already exist (oldVersion = 0).\n // We seed the bookkeeping store atomically with DB creation so a\n // fresh DB never lacks it.\n const u = req.result;\n if (!u.objectStoreNames.contains(MIGRATIONS_TABLE)) {\n u.createObjectStore(MIGRATIONS_TABLE, { keyPath: [\"component\", \"version\"] });\n }\n };\n req.onsuccess = () => {\n if (settled) return;\n const db = req.result;\n const currentVersion = db.version;\n if (!db.objectStoreNames.contains(MIGRATIONS_TABLE)) {\n // Existed prior to this runner ever being used — no bookkeeping yet.\n finalize(db, { ok: true, value: { currentVersion, applied: new Set() } });\n return;\n }\n const tx = db.transaction(MIGRATIONS_TABLE, \"readonly\");\n const store = tx.objectStore(MIGRATIONS_TABLE);\n const getAll = store.getAll();\n getAll.onsuccess = () => {\n if (settled) return;\n const rows = getAll.result as Array<{ component: string; version: number }>;\n finalize(db, {\n ok: true,\n value: {\n currentVersion,\n applied: new Set(rows.map((r) => `${r.component}@${r.version}`)),\n },\n });\n };\n getAll.onerror = () => {\n if (settled) return;\n finalize(db, { ok: false, error: getAll.error });\n };\n };\n req.onerror = () => {\n if (settled) return;\n finalize(undefined, { ok: false, error: req.error });\n };\n req.onblocked = () => {\n if (settled) return;\n finalize(undefined, {\n ok: false,\n error: new Error(`IndexedDB ${this.dbName} blocked while probing for bookkeeping store`),\n });\n };\n });\n }\n\n /** Ensures the bookkeeping object store exists (created lazily by {@link probe}). */\n async ensureBookkeepingTable(): Promise<void> {\n await this.probe();\n }\n\n async appliedVersions(component: string): Promise<Set<number>> {\n const { applied } = await this.probe();\n const versions = new Set<number>();\n for (const key of applied) {\n const at = key.lastIndexOf(\"@\");\n if (at < 0) continue;\n const c = key.slice(0, at);\n const v = Number(key.slice(at + 1));\n if (c === component && Number.isFinite(v)) versions.add(v);\n }\n return versions;\n }\n\n async run(\n migrations: ReadonlyArray<IndexedDbMigration>,\n options: RunMigrationsOptions = {}\n ): Promise<ReadonlyArray<IndexedDbMigration>> {\n const prev = RUN_LOCKS.get(this.dbName) ?? Promise.resolve();\n const next = prev.catch(() => undefined).then(() => this.runLocked(migrations, options));\n RUN_LOCKS.set(this.dbName, next);\n try {\n return await next;\n } finally {\n if (RUN_LOCKS.get(this.dbName) === next) RUN_LOCKS.delete(this.dbName);\n }\n }\n\n /**\n * Body of `run()` that executes under the per-dbName lock. Probes the\n * bookkeeping store *after* acquiring the lock so each serialized caller\n * sees rows committed by the previous one — without re-probing, a queued\n * caller would re-run already-applied migrations from a stale snapshot.\n */\n private async runLocked(\n migrations: ReadonlyArray<IndexedDbMigration>,\n options: RunMigrationsOptions\n ): Promise<ReadonlyArray<IndexedDbMigration>> {\n const sorted = sortMigrations(migrations);\n if (sorted.length === 0) return [];\n\n const { currentVersion, applied: alreadyApplied } = await this.probe();\n const pending = sorted.filter((m) => !alreadyApplied.has(`${m.component}@${m.version}`));\n if (pending.length === 0) return [];\n\n // Bump the IDB version monotonically — its only role is to trigger\n // onupgradeneeded. The bookkeeping store decides what actually runs.\n const targetVersion = currentVersion + 1;\n const applied: IndexedDbMigration[] = [];\n // Buffer events emitted from inside `onupgradeneeded` and flush after the\n // open request settles. Calling user code (the listener) inside the IDB\n // upgrade transaction can let microtasks slip in and auto-commit the\n // transaction before our migrations are done.\n const onProgress = options.onProgress;\n const buffered: Parameters<NonNullable<typeof onProgress>>[0][] = [];\n const emitLater = onProgress\n ? (ev: Parameters<NonNullable<typeof onProgress>>[0]) => buffered.push(ev)\n : undefined;\n\n await new Promise<void>((resolve, reject) => {\n // Same orphan-callback hazard as `probe()`, plus an extra one: aborting\n // the upgrade transaction in our catch path queues an `onerror` that\n // would otherwise re-reject after we've already settled with the real\n // cause. Funnel everything through `finalize`.\n let settled = false;\n let upgradeDb: IDBDatabase | undefined;\n const finalize = (outcome: { ok: true } | { ok: false; error: unknown }): void => {\n if (settled) return;\n settled = true;\n if (upgradeDb) {\n try {\n upgradeDb.close();\n } catch {\n // ignore — close is best-effort\n }\n }\n if (outcome.ok) resolve();\n else reject(outcome.error);\n };\n\n const upreq = this.idb.open(this.dbName, targetVersion);\n upreq.onupgradeneeded = (ev) => {\n if (settled) return;\n try {\n const db = upreq.result;\n upgradeDb = db;\n const tx = upreq.transaction!;\n const oldVersion = ev.oldVersion;\n const newVersion = ev.newVersion ?? targetVersion;\n\n // Another tab opening at a still-higher version mid-upgrade: abort\n // our work and surface a typed error rather than blocking forever.\n db.onversionchange = () => {\n try {\n tx.abort();\n } catch {\n // ignore — tx may already be settling\n }\n finalize({ ok: false, error: new MigrationAbortedByOtherTabError(this.dbName) });\n };\n\n if (!db.objectStoreNames.contains(MIGRATIONS_TABLE)) {\n db.createObjectStore(MIGRATIONS_TABLE, { keyPath: [\"component\", \"version\"] });\n }\n const meta = tx.objectStore(MIGRATIONS_TABLE);\n\n for (const m of pending) {\n emitLater?.({\n component: m.component,\n version: m.version,\n phase: \"starting\",\n description: m.description,\n });\n const ctx: IndexedDbUpgradeContext = { db, tx, oldVersion, newVersion };\n const result = m.up(ctx, (fraction) => {\n emitLater?.({\n component: m.component,\n version: m.version,\n phase: \"running\",\n description: m.description,\n fraction,\n });\n });\n if (result instanceof Promise) {\n throw new Error(\n `IndexedDB migration \"${m.component}@${m.version}\" returned a Promise; ` +\n `IDB upgrade transactions cannot span async work.`\n );\n }\n meta.add({\n component: m.component,\n version: m.version,\n description: m.description ?? null,\n applied_at: new Date().toISOString(),\n });\n applied.push(m);\n emitLater?.({\n component: m.component,\n version: m.version,\n phase: \"completed\",\n description: m.description,\n fraction: 1,\n });\n }\n } catch (err) {\n // Force the open request to fail by aborting the upgrade transaction.\n // The orphan `onerror` it triggers will see `settled` and bail.\n try {\n upreq.transaction?.abort();\n } catch {\n // ignore\n }\n // Tag which migration failed (best-effort: the one whose `starting`\n // we last buffered without a matching `completed`).\n const lastStart = [...buffered].reverse().find((e) => e.phase === \"starting\");\n if (lastStart) {\n emitLater?.({\n component: lastStart.component,\n version: lastStart.version,\n phase: \"failed\",\n description: lastStart.description,\n error: err,\n });\n }\n finalize({ ok: false, error: err });\n }\n };\n upreq.onsuccess = () => {\n if (settled) return;\n upgradeDb = upreq.result;\n finalize({ ok: true });\n };\n upreq.onerror = () => {\n if (settled) return;\n finalize({ ok: false, error: upreq.error });\n };\n upreq.onblocked = () => {\n if (settled) return;\n finalize({\n ok: false,\n error: new Error(`IndexedDB ${this.dbName} upgrade blocked — close other tabs.`),\n });\n };\n }).finally(() => {\n // Flush buffered events after the upgrade settles, regardless of\n // success/failure. Listeners always see a consistent \"starting →\n // {completed | failed}\" sequence.\n if (onProgress) {\n for (const ev of buffered) onProgress(ev);\n }\n });\n\n return applied;\n }\n}\n\n/**\n * Convenience helper used by storage classes — runs the supplied migration\n * groups (one per IDB database) against fresh runners and returns an array\n * of the applied migrations across all groups.\n *\n * IndexedDB groups exist because some storages (e.g. the rate limiter) span\n * multiple databases and expose them as separate `(dbName, migrations)` pairs\n * via `getMigrations()`.\n */\nexport interface IndexedDbMigrationGroup {\n readonly dbName: string;\n readonly migrations: ReadonlyArray<IndexedDbMigration>;\n}\n\nexport async function runIndexedDbMigrationGroups(\n groups: ReadonlyArray<IndexedDbMigrationGroup>,\n options: RunMigrationsOptions & { idb?: IDBFactory } = {}\n): Promise<ReadonlyArray<IndexedDbMigration>> {\n const { idb, onProgress } = options;\n const all: IndexedDbMigration[] = [];\n for (const group of groups) {\n const runner = idb\n ? new IndexedDbMigrationRunner(group.dbName, idb)\n : new IndexedDbMigrationRunner(group.dbName);\n const applied = await runner.run(group.migrations, { onProgress });\n all.push(...applied);\n }\n return all;\n}\n",
10
10
  "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { type ITabularMigrationApplier, type TabularMigrationOp } from \"@workglow/storage\";\nimport {\n IndexedDbMigrationRunner,\n type IndexedDbUpgradeContext,\n} from \"../migrations/IndexedDbMigrationRunner\";\n\ninterface BackfillCapableStorage {\n getPage: (req?: { limit?: number; cursor?: unknown }) => Promise<{\n items: Array<Record<string, unknown>>;\n nextCursor?: unknown;\n }>;\n put: (row: Record<string, unknown>) => Promise<unknown>;\n delete: (row: Record<string, unknown>) => Promise<unknown>;\n}\n\n/**\n * Read-only existence probe shared by `IndexedDbTabularMigrationApplier.tableExists`\n * and `IndexedDbTabularStorage.probeObjectStoreExists`. Opens the IDB\n * database without a version (which is the only documented way to read the\n * existing version + object stores) and inspects `objectStoreNames`.\n *\n * **Side effect:** if the database does not yet exist, IDB's spec says\n * `open(name)` *creates* it at version 1 with no object stores. The caller\n * must be prepared to handle that — `ensureIndexedDbTable` already does, by\n * deleting and recreating the empty DB before bumping its version.\n */\nexport async function idbObjectStoreExists(dbName: string, storeName: string): Promise<boolean> {\n const idb = (globalThis as { indexedDB?: IDBFactory }).indexedDB;\n if (!idb) throw new Error(\"indexedDB is not available in this environment\");\n return new Promise<boolean>((resolve, reject) => {\n const req = idb.open(dbName);\n req.onsuccess = () => {\n const db = req.result;\n const exists = db.objectStoreNames.contains(storeName);\n db.close();\n resolve(exists);\n };\n req.onerror = () => reject(req.error);\n req.onblocked = () =>\n reject(new Error(`IndexedDB ${dbName} blocked while probing for object store`));\n });\n}\n\n/**\n * IndexedDB applier for tabular migrations.\n *\n * Op handling matches `InMemoryTabularMigrationApplier`'s schemaless model\n * (column ops are no-ops) and `SqlTabularMigrationApplier`'s SQL-backed\n * model (DDL is real) where each makes sense:\n *\n * - `addColumn` / `dropColumn` / `renameColumn` — **no-ops.** IDB stores\n * arbitrary JS objects, so there is no schema to evolve. Authors who\n * need to populate or rewrite a property on existing rows must pair\n * the column op with an explicit `backfill` op (which runs on every\n * backend, including SQL, where the backfill is in addition to the\n * real ALTER TABLE). This keeps a single migration spec portable\n * across backends.\n * - `addIndex` / `dropIndex` — **real DDL.** Run inside an upgrade\n * transaction issued by {@link IndexedDbMigrationRunner}, which writes\n * the `_storage_migrations` row in the same transaction so DDL +\n * bookkeeping commit atomically. `createIndex` / `deleteIndex` are\n * guarded by `objectStore.indexNames.contains` so a re-run does not\n * throw on already-existing / already-deleted indexes — mirroring\n * SQL's `IF NOT EXISTS` / `IF EXISTS` semantics.\n * - `backfill` — runs on a **separate** readwrite transaction *before*\n * the upgrade tx, because IDB upgrade transactions cannot span async\n * work. This means the backfill and the bookkeeping write are NOT\n * atomic on this backend: if the upgrade tx fails after a partial\n * backfill, the row mutations persist while no `(component, version)`\n * row is written, and the next run re-invokes `transform()` on the\n * already-mutated rows. **Backfill `transform`s on this applier MUST\n * therefore be idempotent.** SQL backends wrap everything in\n * `withTransaction` and do not have this requirement.\n *\n * Order of execution within a single migration: backfill first, then DDL.\n * This means a `[backfill, addIndex]` pair sees the new index applied to\n * the rewritten rows; the reverse order (`[addIndex, backfill]`) would\n * still execute backfill first because the runner buffers DDL until the\n * upgrade tx.\n */\nexport class IndexedDbTabularMigrationApplier implements ITabularMigrationApplier {\n private readonly runner: IndexedDbMigrationRunner;\n constructor(\n private readonly dbName: string,\n private readonly storeName: string,\n private readonly storage: BackfillCapableStorage,\n runner?: IndexedDbMigrationRunner\n ) {\n this.runner = runner ?? new IndexedDbMigrationRunner(dbName);\n }\n\n async ensureBookkeeping(): Promise<void> {\n await this.runner.ensureBookkeepingTable();\n }\n\n async appliedVersions(component: string): Promise<Set<number>> {\n return this.runner.appliedVersions(component);\n }\n\n async tableExists(): Promise<boolean> {\n return idbObjectStoreExists(this.dbName, this.storeName);\n }\n\n async markAllApplied(\n component: string,\n versions: ReadonlyArray<{ version: number; description: string | undefined }>\n ): Promise<void> {\n if (versions.length === 0) return;\n await this.runner.run(\n versions.map((v) => ({\n component,\n version: v.version,\n description: v.description,\n up: () => undefined,\n }))\n );\n }\n\n async applyMigration(\n component: string,\n version: number,\n description: string | undefined,\n ops: ReadonlyArray<TabularMigrationOp>,\n onProgress?: (fraction: number) => void\n ): Promise<void> {\n // Exhaustive partition. The `never` default makes adding a new op\n // kind to TabularMigrationOp a TS error here rather than a silent\n // drop into one of two filters, which is how the previous version\n // of this code lost addColumn / dropColumn / renameColumn ops.\n type AddIndexOp = Extract<TabularMigrationOp, { kind: \"addIndex\" }>;\n type DropIndexOp = Extract<TabularMigrationOp, { kind: \"dropIndex\" }>;\n type BackfillOp = Extract<TabularMigrationOp, { kind: \"backfill\" }>;\n const ddlOps: Array<AddIndexOp | DropIndexOp> = [];\n const backfills: BackfillOp[] = [];\n for (const op of ops) {\n switch (op.kind) {\n case \"addIndex\":\n case \"dropIndex\":\n ddlOps.push(op);\n break;\n case \"backfill\":\n backfills.push(op);\n break;\n case \"addColumn\":\n case \"dropColumn\":\n case \"renameColumn\":\n // Schemaless backend — no schema to evolve. Pair with `backfill`\n // when row data needs to change. See class JSDoc.\n break;\n default: {\n const _exhaustive: never = op;\n throw new Error(\n `IndexedDbTabularMigrationApplier: unhandled op kind ${(_exhaustive as { kind: string }).kind}`\n );\n }\n }\n }\n\n // Run backfills FIRST on a normal readwrite tx. If any throws, no\n // bookkeeping is written, so the migration is retried on the next run\n // — which is why backfill transforms must be idempotent on this\n // backend (see class JSDoc).\n let processed = 0;\n const total = Math.max(ops.length, 1);\n for (const op of backfills) {\n const batchSize = op.batchSize ?? 500;\n let cursor: unknown;\n while (true) {\n const page = await this.storage.getPage({ limit: batchSize, cursor });\n for (const row of page.items) {\n const out = await op.transform(row);\n if (out === row) continue;\n if (out === undefined) {\n await this.storage.delete(row);\n } else {\n await this.storage.put(out);\n }\n }\n if (!page.nextCursor) break;\n cursor = page.nextCursor;\n }\n processed++;\n onProgress?.(processed / total);\n }\n\n // Then run DDL + bookkeeping atomically inside an upgrade transaction.\n // The runner.run() writes the `_storage_migrations` row inside the same\n // upgrade tx as our `up` callback, so DDL failure = no bookkeeping.\n // We always invoke runner.run() (even when ddlOps is empty) so that\n // bookkeeping is recorded for backfill-only and column-op-only\n // migrations.\n const storeName = this.storeName;\n await this.runner.run([\n {\n component,\n version,\n description,\n up: (ctx: IndexedDbUpgradeContext) => {\n if (!ctx.db.objectStoreNames.contains(storeName)) return;\n const store = ctx.tx.objectStore(storeName);\n for (const op of ddlOps) {\n if (op.kind === \"addIndex\") {\n if (store.indexNames.contains(op.name)) continue;\n const keyPath = op.columns.length === 1 ? op.columns[0] : [...op.columns];\n store.createIndex(op.name, keyPath, { unique: op.unique ?? false });\n } else {\n if (!store.indexNames.contains(op.name)) continue;\n store.deleteIndex(op.name);\n }\n }\n },\n },\n ]);\n processed += ddlOps.length;\n onProgress?.(processed / total);\n }\n}\n",
11
11
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {\n AnyVectorStorage,\n AutoGeneratedKeys,\n ClientProvidedKeysOption,\n InsertEntity,\n IVectorStorage,\n VectorSearchOptions,\n} from \"@workglow/storage\";\nimport {\n assertVectorShape,\n emitSimilaritySearch,\n getMetadataProperty,\n getVectorProperty,\n matchesFilter,\n validateVectorEntities,\n} from \"@workglow/storage\";\nimport { createServiceToken } from \"@workglow/util\";\nimport type {\n DataPortSchemaObject,\n FromSchema,\n TypedArray,\n TypedArrayConstructor,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { cosineSimilarity } from \"@workglow/util/schema\";\nimport type { MigrationOptions } from \"./IndexedDbTable\";\nimport { IndexedDbTabularStorage } from \"./IndexedDbTabularStorage\";\n\nexport const IDB_VECTOR_REPOSITORY = createServiceToken<AnyVectorStorage>(\n \"storage.vectorRepository.indexedDb\"\n);\n\n/**\n * IndexedDB vector storage implementation.\n * Extends IndexedDbTabularStorage for storage.\n * Suitable for browser applications that need persistent vector storage.\n * No vector serialization needed since IndexedDB supports TypedArrays\n * natively via structured clone.\n *\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - The primary key names\n * @template Metadata - The metadata type for the vector\n * @template VectorCtor - Constructor for stored vectors (default {@link typeof Float32Array})\n * @template Entity - The entity type\n */\nexport class IndexedDbVectorStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n Metadata extends Record<string, unknown> = Record<string, unknown>,\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n InsertType extends InsertEntity<Entity, AutoGeneratedKeys<Schema>> = InsertEntity<\n Entity,\n AutoGeneratedKeys<Schema>\n >,\n>\n extends IndexedDbTabularStorage<Schema, PrimaryKeyNames, Entity>\n implements IVectorStorage<Metadata, Schema, Entity, PrimaryKeyNames>\n{\n private vectorDimensions: number;\n private vectorPropertyName: keyof Entity;\n private metadataPropertyName: keyof Entity | undefined;\n\n constructor(\n table: string = \"vectors\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n dimensions: number,\n _vectorCtor: TypedArrayConstructor = Float32Array,\n migrationOptions: MigrationOptions = {},\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(table, schema, primaryKeyNames, indexes, migrationOptions, clientProvidedKeys);\n\n this.vectorDimensions = dimensions;\n\n const vectorProp = getVectorProperty(schema);\n if (!vectorProp) {\n throw new Error(\"Schema must have a property with type array and format TypedArray\");\n }\n this.vectorPropertyName = vectorProp as keyof Entity;\n this.metadataPropertyName = getMetadataProperty(schema) as keyof Entity | undefined;\n }\n\n getVectorDimensions(): number {\n return this.vectorDimensions;\n }\n\n /**\n * Validate vector shape SYNCHRONOUSLY before any IDB transaction opens.\n * The throw propagates through the awaited Promise; no IDB request is ever\n * created, so a malformed put cannot leak a corrupt row into the object store.\n */\n override async put(record: InsertType): Promise<Entity> {\n assertVectorShape(\n (record as Record<string, unknown>)[this.vectorPropertyName as string],\n this.vectorDimensions,\n \"write\"\n );\n return super.put(record);\n }\n\n /**\n * Validate every entry up front so a single malformed vector aborts the\n * whole batch before any row is written, then route through a single IDB\n * `readwrite` transaction for atomicity. The inherited tabular `putBulk`\n * opens one transaction per row via `Promise.all`, so a duplicate-key or\n * quota error on the second or later record can leave earlier rows\n * committed — breaking the all-or-nothing guarantee vector ingestion (RAG\n * chunk upserts) depends on. The single-transaction path defers `put` event\n * emission to `tx.oncomplete`, which means subscribers see a successful\n * batch as a burst rather than interleaved with the per-record IDB requests.\n */\n override async putBulk(records: InsertType[]): Promise<Entity[]> {\n validateVectorEntities(\n records as ReadonlyArray<Record<string, unknown>>,\n this.vectorPropertyName as string,\n this.vectorDimensions\n );\n return this.putBulkInTransaction(records);\n }\n\n async similaritySearch(\n query: TypedArray,\n options: VectorSearchOptions<Record<string, unknown>> = {}\n ) {\n assertVectorShape(query, this.vectorDimensions, \"query\");\n // Default to 0 to match every SQL backend (Sqlite / Postgres / Supabase /\n // SqliteAi). Cosine similarity ranges over [-1, 1]; a negatively-correlated\n // hit is \"not a match\" for relevance retrieval. Callers that want every\n // result regardless of correlation pass `scoreThreshold: -Infinity`.\n const { topK = 10, filter, scoreThreshold = 0 } = options;\n const results: Array<Entity & { score: number }> = [];\n\n const allEntities = (await this.getAll()) || [];\n\n for (const entity of allEntities) {\n // IndexedDB stores TypedArrays natively via structured clone\n const vector = entity[this.vectorPropertyName] as TypedArray;\n // A present-but-null metadata column value coalesces to `{}` so a filtered\n // search treats the row as a non-match rather than dereferencing null.\n const rawMetadata = this.metadataPropertyName ? entity[this.metadataPropertyName] : undefined;\n const metadata = (rawMetadata ?? {}) as Metadata;\n\n if (filter && !matchesFilter(metadata, filter)) {\n continue;\n }\n\n const score = cosineSimilarity(query, vector);\n\n if (score < scoreThreshold) {\n continue;\n }\n\n results.push({\n ...entity,\n score,\n } as Entity & { score: number });\n }\n\n results.sort((a, b) => b.score - a.score);\n return emitSimilaritySearch(this.events, query, results.slice(0, topK));\n }\n}\n"
12
12
  ],
13
- "mappings": "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",
14
- "debugId": "0833B0AFB348CFFE64756E2164756E21",
13
+ "mappings": "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",
14
+ "debugId": "2B2714B1793C3B3064756E2164756E21",
15
15
  "names": []
16
16
  }