@vielzeug/vault 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +74 -0
  2. package/dist/_dev.cjs +2 -0
  3. package/dist/_dev.cjs.map +1 -0
  4. package/dist/_dev.d.ts +2 -0
  5. package/dist/_dev.d.ts.map +1 -0
  6. package/dist/_dev.js +12 -0
  7. package/dist/_dev.js.map +1 -0
  8. package/dist/adapter-core.cjs +2 -0
  9. package/dist/adapter-core.cjs.map +1 -0
  10. package/dist/adapter-core.d.ts +8 -0
  11. package/dist/adapter-core.d.ts.map +1 -0
  12. package/dist/adapter-core.js +269 -0
  13. package/dist/adapter-core.js.map +1 -0
  14. package/dist/adapters/indexeddb.cjs +2 -0
  15. package/dist/adapters/indexeddb.cjs.map +1 -0
  16. package/dist/adapters/indexeddb.d.ts +13 -0
  17. package/dist/adapters/indexeddb.d.ts.map +1 -0
  18. package/dist/adapters/indexeddb.js +336 -0
  19. package/dist/adapters/indexeddb.js.map +1 -0
  20. package/dist/adapters/memory.cjs +2 -0
  21. package/dist/adapters/memory.cjs.map +1 -0
  22. package/dist/adapters/memory.d.ts +14 -0
  23. package/dist/adapters/memory.d.ts.map +1 -0
  24. package/dist/adapters/memory.js +200 -0
  25. package/dist/adapters/memory.js.map +1 -0
  26. package/dist/adapters/webstorage.cjs +2 -0
  27. package/dist/adapters/webstorage.cjs.map +1 -0
  28. package/dist/adapters/webstorage.d.ts +14 -0
  29. package/dist/adapters/webstorage.d.ts.map +1 -0
  30. package/dist/adapters/webstorage.js +182 -0
  31. package/dist/adapters/webstorage.js.map +1 -0
  32. package/dist/errors.cjs +2 -0
  33. package/dist/errors.cjs.map +1 -0
  34. package/dist/errors.d.ts +22 -0
  35. package/dist/errors.d.ts.map +1 -0
  36. package/dist/errors.js +17 -0
  37. package/dist/errors.js.map +1 -0
  38. package/dist/index.cjs +1 -0
  39. package/dist/index.d.ts +17 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +11 -0
  42. package/dist/internal.cjs +2 -0
  43. package/dist/internal.cjs.map +1 -0
  44. package/dist/internal.d.ts +50 -0
  45. package/dist/internal.d.ts.map +1 -0
  46. package/dist/internal.js +125 -0
  47. package/dist/internal.js.map +1 -0
  48. package/dist/migration.cjs +2 -0
  49. package/dist/migration.cjs.map +1 -0
  50. package/dist/migration.d.ts +37 -0
  51. package/dist/migration.d.ts.map +1 -0
  52. package/dist/migration.js +27 -0
  53. package/dist/migration.js.map +1 -0
  54. package/dist/prune.cjs +2 -0
  55. package/dist/prune.cjs.map +1 -0
  56. package/dist/prune.d.ts +32 -0
  57. package/dist/prune.d.ts.map +1 -0
  58. package/dist/prune.js +20 -0
  59. package/dist/prune.js.map +1 -0
  60. package/dist/query.cjs +2 -0
  61. package/dist/query.cjs.map +1 -0
  62. package/dist/query.d.ts +113 -0
  63. package/dist/query.d.ts.map +1 -0
  64. package/dist/query.js +126 -0
  65. package/dist/query.js.map +1 -0
  66. package/dist/streaming.cjs +2 -0
  67. package/dist/streaming.cjs.map +1 -0
  68. package/dist/streaming.d.ts +22 -0
  69. package/dist/streaming.d.ts.map +1 -0
  70. package/dist/streaming.js +21 -0
  71. package/dist/streaming.js.map +1 -0
  72. package/dist/ttl.cjs +2 -0
  73. package/dist/ttl.cjs.map +1 -0
  74. package/dist/ttl.d.ts +74 -0
  75. package/dist/ttl.d.ts.map +1 -0
  76. package/dist/ttl.js +32 -0
  77. package/dist/ttl.js.map +1 -0
  78. package/dist/types.cjs +2 -0
  79. package/dist/types.cjs.map +1 -0
  80. package/dist/types.d.ts +409 -0
  81. package/dist/types.d.ts.map +1 -0
  82. package/dist/types.js +27 -0
  83. package/dist/types.js.map +1 -0
  84. package/dist/vault.cjs +2 -0
  85. package/dist/vault.cjs.map +1 -0
  86. package/dist/vault.iife.js +2 -0
  87. package/dist/vault.iife.js.map +1 -0
  88. package/dist/vault.js +2 -0
  89. package/dist/vault.js.map +1 -0
  90. package/dist/versioned-codec.cjs +2 -0
  91. package/dist/versioned-codec.cjs.map +1 -0
  92. package/dist/versioned-codec.d.ts +44 -0
  93. package/dist/versioned-codec.d.ts.map +1 -0
  94. package/dist/versioned-codec.js +32 -0
  95. package/dist/versioned-codec.js.map +1 -0
  96. package/package.json +41 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexeddb.cjs","names":[],"sources":["../../src/adapters/indexeddb.ts"],"sourcesContent":["import type {\n Adapter,\n AnySchema,\n BaseAdapterOptions,\n KeyOf,\n MigrationFn,\n RecordOf,\n TransactionContext,\n TtlMs,\n} from '../types';\n\nimport { buildAdapterOps, buildTxContext, type StorageBackend } from '../adapter-core';\nimport { VaultDisposedError, VaultError, VaultMigrationError } from '../errors';\nimport { getRecordKey } from '../internal';\nimport { type NativeRange } from '../query';\nimport { defaultCodec, isExpired, type VaultCodec } from '../ttl';\n\nfunction idbReq<R>(request: IDBRequest<R>): Promise<R> {\n return new Promise<R>((resolve, reject) => {\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error ?? new VaultError('IndexedDB request failed'));\n });\n}\n\nfunction wrapTxError(scope: string, message: string, cause: unknown): VaultError {\n const causeMessage = cause instanceof Error && cause.message ? `: ${cause.message}` : '';\n\n return new VaultError(`${message} on \"${scope}\"${causeMessage}`, { cause });\n}\n\nfunction runIdbTx<T>(tx: IDBTransaction, scope: string, work: () => Promise<T>): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n let result: T | undefined;\n let callbackError: unknown;\n\n Promise.resolve()\n .then(work)\n .then((value) => {\n result = value;\n })\n .catch((error) => {\n callbackError = error;\n\n try {\n tx.abort();\n } catch {\n /* ignore */\n }\n });\n\n const rejectWithCallbackError = (fallbackCause: unknown, message = 'transaction failed'): void => {\n if (callbackError instanceof Error) {\n reject(callbackError);\n } else {\n reject(wrapTxError(scope, message, callbackError ?? fallbackCause));\n }\n };\n\n tx.oncomplete = () => {\n if (callbackError) {\n rejectWithCallbackError(undefined);\n\n return;\n }\n\n resolve(result as T);\n };\n tx.onerror = () => reject(wrapTxError(scope, 'transaction error', tx.error));\n tx.onabort = () => rejectWithCallbackError(tx.error, 'transaction aborted');\n });\n}\n\nasync function getAllFromStore<T extends Record<string, unknown>>(\n store: IDBObjectStore,\n decode: (raw: unknown) => T | undefined,\n): Promise<T[]> {\n const rawRecords = await idbReq<unknown[]>(store.getAll());\n const records: T[] = [];\n\n for (const raw of rawRecords) {\n const value = decode(raw);\n\n if (value !== undefined) records.push(value);\n }\n\n return records;\n}\n\nasync function getAllFromStoreByIndex<T extends Record<string, unknown>>(\n store: IDBObjectStore,\n indexName: string,\n range: NativeRange,\n decode: (raw: unknown) => T | undefined,\n): Promise<T[]> {\n const index = store.index(indexName);\n const idbRange =\n range.type === 'eq'\n ? IDBKeyRange.only(range.value as IDBValidKey)\n : range.type === 'between'\n ? IDBKeyRange.bound(range.lower as IDBValidKey, range.upper as IDBValidKey)\n : IDBKeyRange.bound(range.prefix, range.prefix + '\\uffff');\n const rawRecords = await idbReq<unknown[]>(index.getAll(idbRange));\n const records: T[] = [];\n\n for (const raw of rawRecords) {\n const value = decode(raw);\n\n if (value !== undefined) records.push(value);\n }\n\n return records;\n}\n\nasync function getAllFromStoreWithRange<T extends Record<string, unknown>>(\n store: IDBObjectStore,\n range: NativeRange,\n decode: (raw: unknown) => T | undefined,\n): Promise<T[]> {\n if (range.type === 'eq') {\n const record = await storeGet<T>(store, range.value as IDBValidKey, decode);\n\n return record !== undefined ? [record] : [];\n }\n\n const idbRange =\n range.type === 'between'\n ? IDBKeyRange.bound(range.lower as IDBValidKey, range.upper as IDBValidKey)\n : // 'starts': bound from prefix to prefix\\uffff (covers all BMP strings starting with prefix)\n IDBKeyRange.bound(range.prefix, range.prefix + '\\uffff');\n\n const rawRecords = await idbReq<unknown[]>(store.getAll(idbRange));\n const records: T[] = [];\n\n for (const raw of rawRecords) {\n const value = decode(raw);\n\n if (value !== undefined) records.push(value);\n }\n\n return records;\n}\n\nasync function storeGet<T extends Record<string, unknown>>(\n store: IDBObjectStore,\n key: IDBValidKey,\n decode: (raw: unknown) => T | undefined,\n): Promise<T | undefined> {\n const raw = await idbReq<unknown>(store.get(key));\n\n if (raw == null) return undefined;\n\n return decode(raw);\n}\n\nasync function storeHas<T extends Record<string, unknown>>(\n store: IDBObjectStore,\n key: IDBValidKey,\n decode: (raw: unknown) => T | undefined,\n): Promise<boolean> {\n return (await storeGet<T>(store, key, decode)) !== undefined;\n}\n\nasync function storeDelete<T extends Record<string, unknown>>(\n store: IDBObjectStore,\n key: IDBValidKey,\n decode: (raw: unknown) => T | undefined,\n): Promise<boolean> {\n const live = await storeHas<T>(store, key, decode);\n\n await idbReq(store.delete(key));\n\n return live;\n}\n\nasync function storeDeleteMany<T extends Record<string, unknown>>(\n store: IDBObjectStore,\n keys: IDBValidKey[],\n decode: (raw: unknown) => T | undefined,\n): Promise<number> {\n if (keys.length === 0) return 0;\n\n const results = await Promise.all(keys.map((k) => storeDelete<T>(store, k, decode)));\n\n return results.filter(Boolean).length;\n}\n\nasync function storePutAt<T>(\n store: IDBObjectStore,\n key: IDBValidKey,\n value: T,\n encode: (v: T, ttl?: TtlMs) => unknown,\n ttl?: TtlMs,\n): Promise<void> {\n await idbReq(store.put(encode(value, ttl), key));\n}\n\nfunction pruneExpiredInStore(store: IDBObjectStore, codec: VaultCodec): Promise<number> {\n return new Promise<number>((resolve, reject) => {\n let deleted = 0;\n const request = store.openCursor();\n\n request.onerror = () => reject(request.error ?? new VaultError('IndexedDB cursor failed during prune'));\n request.onsuccess = () => {\n const cursor = request.result;\n\n if (!cursor) {\n resolve(deleted);\n\n return;\n }\n\n const stored = codec.decode(cursor.value as unknown);\n\n if (!stored || isExpired(stored.expiresAt)) {\n cursor.delete();\n deleted += 1;\n }\n\n cursor.continue();\n };\n });\n}\n\n/**\n * Cursor state machine — a single discriminated union replaces five boolean/nullable variables.\n * Transitions: idle → waiting (next() before cursor fires) | buffered (cursor fires first) | done | error\n */\ntype CursorState<T> =\n | { type: 'idle' }\n | { reject: (e: unknown) => void; resolve: (r: IteratorResult<T>) => void; type: 'waiting' }\n | { result: IteratorResult<T>; type: 'buffered' }\n | { error: unknown; type: 'error' }\n | { type: 'done' };\n\n/**\n * F1: True cursor-based iteration for IndexedDB.\n * Yields live records one-by-one using an IDB cursor, avoiding materializing the full table.\n * This is memory-efficient for large tables — the cursor walks the store incrementally.\n *\n * Design: the cursor is opened *synchronously* in [Symbol.asyncIterator]() so that event\n * handlers are wired immediately (no queueMicrotask races). The cursor is advanced *eagerly*\n * before yielding — this keeps the IDB readonly transaction alive between consumer awaits,\n * because IDB auto-commits when there are no pending requests.\n */\nfunction iterateStoreWithCursor<T extends Record<string, unknown>>(\n store: IDBObjectStore,\n decode: (raw: unknown) => T | undefined,\n): AsyncIterable<T> {\n return {\n [Symbol.asyncIterator](): AsyncIterator<T> {\n const cursorRequest = store.openCursor();\n let state: CursorState<T> = { type: 'idle' };\n\n const deliver = (result: IteratorResult<T>): void => {\n if (state.type === 'waiting') {\n const { resolve } = state;\n\n state = result.done ? { type: 'done' } : { type: 'idle' };\n resolve(result);\n } else {\n state = { result, type: 'buffered' };\n }\n };\n\n cursorRequest.onerror = () => {\n const err = cursorRequest.error ?? new VaultError('IndexedDB cursor iteration failed');\n\n if (state.type === 'waiting') {\n const { reject } = state;\n\n state = { type: 'done' };\n reject(err);\n } else {\n state = { error: err, type: 'error' };\n }\n };\n\n cursorRequest.onsuccess = () => {\n const cursor = cursorRequest.result;\n\n if (!cursor) {\n deliver({ done: true, value: undefined });\n\n return;\n }\n\n const value = decode(cursor.value as unknown);\n\n // Advance eagerly BEFORE yielding to keep the IDB transaction alive.\n cursor.continue();\n\n if (value !== undefined) deliver({ done: false, value });\n };\n\n return {\n next(): Promise<IteratorResult<T>> {\n if (state.type === 'error') {\n const { error } = state;\n\n state = { type: 'done' };\n\n return Promise.reject(error);\n }\n\n if (state.type === 'buffered') {\n const { result } = state;\n\n state = result.done ? { type: 'done' } : { type: 'idle' };\n\n return Promise.resolve(result);\n }\n\n if (state.type === 'done') return Promise.resolve({ done: true, value: undefined });\n\n return new Promise<IteratorResult<T>>((resolve, reject) => {\n state = { reject, resolve, type: 'waiting' };\n });\n },\n\n return(value?: unknown): Promise<IteratorResult<T>> {\n if (state.type === 'waiting') state.resolve({ done: true, value: undefined });\n\n state = { type: 'done' };\n\n return Promise.resolve({ done: true, value });\n },\n\n throw(err?: unknown): Promise<IteratorResult<T>> {\n if (state.type === 'waiting') state.reject(err);\n\n state = { type: 'done' };\n\n return Promise.reject(err);\n },\n };\n },\n };\n}\n\n/**\n * R3: Extracted IDB batch core — builds a StorageBackend that operates within\n * an existing IDBTransaction, shared by all tables in the batch.\n * Eliminates the duplicated `txCore` block that was previously inlined in `idbBatch`.\n */\nfunction buildIdbBatchCore<S extends AnySchema, K extends keyof S & string>(\n schema: S,\n idbTx: IDBTransaction,\n decode: <T extends Record<string, unknown>>(raw: unknown) => T | undefined,\n encode: <T>(value: T, ttl?: TtlMs) => unknown,\n): StorageBackend<S, K> {\n const storeOf = (table: K): IDBObjectStore => idbTx.objectStore(table);\n\n return {\n clear: async (table) => {\n await idbReq(storeOf(table).clear());\n },\n count: async (table) => {\n // Must inspect each stored record to exclude TTL-expired entries.\n // Individual put() calls can attach a TTL even when the schema has no defaultTtl,\n // so schema[table].defaultTtl being absent does not guarantee a clean count.\n // This matches the top-level core.count() behaviour in the IDB adapter.\n const all = await idbReq<unknown[]>(storeOf(table).getAll());\n\n return all.filter((r) => decode(r) !== undefined).length;\n },\n delete: (table, key) => storeDelete<RecordOf<S, K>>(storeOf(table), key as IDBValidKey, decode),\n deleteMany: (table, keys) => storeDeleteMany<RecordOf<S, K>>(storeOf(table), keys as IDBValidKey[], decode),\n get: (table, key) => storeGet<RecordOf<S, typeof table>>(storeOf(table), key as IDBValidKey, decode),\n getAll: (table) => getAllFromStore<RecordOf<S, typeof table>>(storeOf(table), decode),\n getByIndexRange: (table, field, range) =>\n getAllFromStoreByIndex<RecordOf<S, typeof table>>(storeOf(table), field, range, decode),\n getByKeyRange: (table, range) => getAllFromStoreWithRange<RecordOf<S, typeof table>>(storeOf(table), range, decode),\n getMany: (table, keys) =>\n Promise.all(keys.map((k) => storeGet<RecordOf<S, typeof table>>(storeOf(table), k as IDBValidKey, decode))),\n has: (table, key) => storeHas<RecordOf<S, typeof table>>(storeOf(table), key as IDBValidKey, decode),\n pruneExpiredInTable: (table) => pruneExpiredInStore(storeOf(table), { decode, encode }),\n put(table, value, ttl) {\n return storePutAt(storeOf(table), getRecordKey(schema, table, value) as IDBValidKey, value, encode, ttl);\n },\n putAll(table, values, ttl) {\n return Promise.all(\n values.map((v) => storePutAt(storeOf(table), getRecordKey(schema, table, v) as IDBValidKey, v, encode, ttl)),\n ).then(() => undefined);\n },\n };\n}\n\ntype IndexedDbOptions<S extends AnySchema> = BaseAdapterOptions<S> & {\n migrate?: MigrationFn;\n name: string;\n /** Schema version. Must be a positive integer. Increment when adding tables or changing the schema, then provide `migrate`. Defaults to 1. */\n version?: number;\n};\n\nexport type IndexedDbAdapter<S extends AnySchema> = Adapter<S> & {\n iterate<K extends keyof S>(table: K): AsyncIterable<RecordOf<S, K>>;\n};\n\nexport function createIndexedDB<S extends AnySchema>(options: IndexedDbOptions<S>): IndexedDbAdapter<S> {\n const {\n codec: userCodec = defaultCodec,\n logger,\n migrate,\n name,\n onMetrics,\n schema,\n signals,\n validators,\n version = 1,\n } = options;\n\n if (!Number.isInteger(version) || version < 1) {\n throw new VaultError(`createIndexedDB: version must be a positive integer, got ${String(version)}`);\n }\n\n // F4: Codec-bound encode/decode used throughout the IDB adapter.\n const decode = <T extends Record<string, unknown>>(raw: unknown): T | undefined => {\n const stored = userCodec.decode<T>(raw);\n\n if (!stored) return undefined;\n\n if (isExpired(stored.expiresAt)) return undefined;\n\n return stored.value;\n };\n\n const encode = <T>(value: T, ttl?: TtlMs): unknown => {\n const expiresAt = ttl !== undefined ? Date.now() + ttl : undefined;\n\n return userCodec.encode(value, expiresAt);\n };\n\n const channel = typeof BroadcastChannel !== 'undefined' ? new BroadcastChannel(`vault:${name}`) : undefined;\n\n if (!channel && logger) {\n logger.error(`[vault] BroadcastChannel unavailable — cross-tab sync disabled for \"${name}\"`);\n }\n\n let db: IDBDatabase | null = null;\n let connectPromise: Promise<void> | null = null;\n let disposed = false;\n\n const createObjectStores = (target: IDBDatabase, tx: IDBTransaction): void => {\n for (const [tableName, entry] of Object.entries(schema)) {\n let store: IDBObjectStore;\n\n if (!target.objectStoreNames.contains(tableName)) {\n store = target.createObjectStore(tableName);\n } else {\n store = tx.objectStore(tableName);\n }\n\n // F5: Create secondary indexes for fields declared via .index() on the table() builder.\n // Stored format is { value: T, expiresAt?: number } so IDB keyPath is `value.<field>`.\n const indexes = (entry as { indexes?: readonly string[] }).indexes ?? [];\n\n for (const field of indexes) {\n if (!store.indexNames.contains(field)) {\n store.createIndex(field, `value.${field}`);\n }\n }\n }\n };\n\n const connect = async (): Promise<void> => {\n if (!connectPromise) {\n connectPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(name, version);\n\n request.onupgradeneeded = (event) => {\n const target = request.result;\n const tx = request.transaction!;\n\n if (migrate) {\n try {\n migrate({\n db: target,\n newVersion: (event as IDBVersionChangeEvent).newVersion ?? null,\n oldVersion: event.oldVersion,\n tx,\n });\n } catch (error) {\n try {\n tx.abort();\n } catch {\n /* ignore */\n }\n\n reject(new VaultMigrationError(`migration failed for \"${name}\"`, { cause: error }));\n\n return;\n }\n }\n\n createObjectStores(target, tx);\n };\n\n request.onsuccess = () => {\n if (disposed) {\n request.result.close();\n resolve();\n\n return;\n }\n\n const connection = request.result;\n\n connection.onversionchange = () => {\n connection.close();\n db = null;\n connectPromise = null;\n };\n\n db = connection;\n resolve();\n };\n request.onerror = () => {\n connectPromise = null;\n reject(new VaultError(`failed to open \"${name}\"`, { cause: request.error }));\n };\n });\n }\n\n return connectPromise;\n };\n\n const withStore = async <T>(\n table: keyof S,\n mode: 'readonly' | 'readwrite',\n fn: (store: IDBObjectStore) => Promise<T>,\n ): Promise<T> => {\n if (disposed) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n if (!db) await connect();\n\n if (!db) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n const tableName = String(table);\n const tx = db.transaction(tableName, mode);\n\n return runIdbTx(tx, `${name}/${tableName}`, () => fn(tx.objectStore(tableName)));\n };\n\n const requireDb = async (): Promise<IDBDatabase> => {\n if (disposed) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n if (!db) await connect();\n\n if (!db) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n return db;\n };\n\n const publish = <K extends keyof S>(table: K): void => {\n channel?.postMessage({ table: String(table) });\n };\n\n const core: StorageBackend<S> = {\n clear: (table) => withStore(table, 'readwrite', (s) => idbReq(s.clear()).then(() => undefined)),\n\n count: (table) =>\n withStore(table, 'readonly', async (s) => {\n // Must inspect each stored record to exclude TTL-expired entries.\n // Individual put() calls can attach a TTL even when the schema has no defaultTtl,\n // so schema[table].defaultTtl being absent does not guarantee a clean count.\n const all = await idbReq<unknown[]>(s.getAll());\n\n return all.filter((r) => decode(r) !== undefined).length;\n }),\n\n delete: (table, key) =>\n withStore(table, 'readwrite', (s) => storeDelete<RecordOf<S, typeof table>>(s, key as IDBValidKey, decode)),\n\n deleteMany: (table, keys) =>\n keys.length === 0\n ? Promise.resolve(0)\n : withStore(table, 'readwrite', (s) =>\n storeDeleteMany<RecordOf<S, typeof table>>(s, keys as IDBValidKey[], decode),\n ),\n\n async dispose(): Promise<void> {\n disposed = true;\n channel?.close();\n\n // F7: Wait for any in-progress connect before closing the DB to avoid\n // \"database connection is closing\" errors on in-flight requests.\n if (connectPromise) await connectPromise.catch(() => {});\n\n db?.close();\n db = null;\n connectPromise = null;\n },\n\n get: (table, key) =>\n withStore(table, 'readonly', (s) => storeGet<RecordOf<S, typeof table>>(s, key as IDBValidKey, decode)),\n\n getAll: (table) => withStore(table, 'readonly', (s) => getAllFromStore<RecordOf<S, typeof table>>(s, decode)),\n\n // Ad-hoc per-put TTLs can be attached regardless of schema-level defaultTtl (same caveat as\n // count()), so we cannot take the O(1) store.getAllKeys() shortcut unconditionally — every\n // record must be decoded to exclude TTL-expired entries correctly.\n getAllKeys: (table) =>\n withStore(table, 'readonly', async (s) => {\n const records = await getAllFromStore<RecordOf<S, typeof table>>(s, decode);\n const keyField = schema[table].key;\n\n return records.map((r) => (r as Record<string, unknown>)[keyField] as KeyOf<S, typeof table>);\n }),\n\n getByIndexRange: (table, field, range) =>\n withStore(table, 'readonly', (s) => getAllFromStoreByIndex<RecordOf<S, typeof table>>(s, field, range, decode)),\n\n getByKeyRange: (table, range) =>\n withStore(table, 'readonly', (s) => getAllFromStoreWithRange<RecordOf<S, typeof table>>(s, range, decode)),\n\n getMany: (table, keys) =>\n keys.length === 0\n ? Promise.resolve([])\n : withStore(table, 'readonly', (s) =>\n Promise.all(keys.map((k) => storeGet<RecordOf<S, typeof table>>(s, k as IDBValidKey, decode))),\n ),\n\n getRawCount: (table) => withStore(table, 'readonly', (s) => idbReq(s.count())),\n\n has: (table, key) =>\n withStore(table, 'readonly', (s) => storeHas<RecordOf<S, typeof table>>(s, key as IDBValidKey, decode)),\n\n async pruneAllExpired() {\n const idb = await requireDb();\n const tableNames = Object.keys(schema);\n const tx = idb.transaction(tableNames, 'readwrite');\n const results = await runIdbTx(tx, `${name}/pruneAll`, () =>\n Promise.all(tableNames.map(async (t) => [t, await pruneExpiredInStore(tx.objectStore(t), userCodec)] as const)),\n );\n\n return Object.fromEntries(results);\n },\n\n pruneExpiredInTable: (table) => withStore(table, 'readwrite', (s) => pruneExpiredInStore(s, userCodec)),\n\n put(table, value, ttl) {\n const key = getRecordKey(schema, table, value) as IDBValidKey;\n\n return withStore(table, 'readwrite', (s) => storePutAt(s, key, value, encode, ttl));\n },\n\n putAll(table, values, ttl) {\n return withStore(table, 'readwrite', (s) =>\n Promise.all(\n values.map((v) => storePutAt(s, getRecordKey(schema, table, v) as IDBValidKey, v, encode, ttl)),\n ).then(() => undefined),\n );\n },\n };\n\n const idbBatch = async <K extends keyof S & string, R>(\n tables: readonly K[],\n fn: (tx: TransactionContext<S, K>) => Promise<R>,\n notifyMutation: (table: K) => void,\n validateFn: <T extends K>(table: T, value: RecordOf<S, T>) => RecordOf<S, T>,\n ): Promise<R> => {\n const idb = await requireDb();\n const idbTx = idb.transaction([...tables] as string[], 'readwrite');\n const dirtyTables = new Set<K>();\n\n const txCore = buildIdbBatchCore<S, K>(schema, idbTx, decode, encode);\n const scope = new Set<string>(tables);\n const tx = buildTxContext<S, K>(schema, txCore, (t) => dirtyTables.add(t), validateFn, scope);\n const result = await runIdbTx(idbTx, name, () => fn(tx));\n\n for (const table of dirtyTables) {\n notifyMutation(table);\n }\n\n return result;\n };\n\n const adapter = buildAdapterOps(schema, core, {\n buildBatch:\n ({ notifyMutation, validate: validateFn }) =>\n (tables, fn) =>\n idbBatch(tables, fn, notifyMutation, validateFn),\n logger,\n onCrossTabMessage(notify) {\n if (!channel) {\n return undefined;\n }\n\n channel.onmessage = (event: MessageEvent<{ table?: string }>) => {\n const tableName = event.data?.table;\n\n if (!tableName || !Object.hasOwn(schema, tableName)) return;\n\n notify(tableName as keyof S & string);\n };\n\n return () => {\n channel.onmessage = null;\n };\n },\n onMetrics,\n onMutation: publish,\n schema,\n signals,\n validators,\n });\n\n /**\n * F1: Attach cursor-based `iterate()` on top of the adapter.\n * Opens a dedicated readonly transaction per call and streams records via IDB cursor —\n * genuinely memory-efficient for large tables unlike the getAll()-then-yield pattern.\n */\n return {\n ...adapter,\n iterate<K extends keyof S>(table: K): AsyncIterable<RecordOf<S, K>> {\n if (disposed) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n // Each call opens a fresh transaction so iteration doesn't hold locks across awaits.\n // We need to ensure the DB is connected before opening the transaction.\n const getIterable = async (): Promise<AsyncIterable<RecordOf<S, K>>> => {\n if (!db) await connect();\n\n if (!db || disposed) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n const idb = db;\n const tx = idb.transaction(String(table), 'readonly');\n const store = tx.objectStore(String(table));\n\n return iterateStoreWithCursor<RecordOf<S, K>>(store, decode as (raw: unknown) => RecordOf<S, K> | undefined);\n };\n\n let inner: AsyncIterator<RecordOf<S, K>> | undefined;\n\n const initInner = (): Promise<AsyncIterator<RecordOf<S, K>>> =>\n getIterable().then((iterable) => {\n inner = iterable[Symbol.asyncIterator]();\n\n return inner;\n });\n\n return {\n [Symbol.asyncIterator](): AsyncIterator<RecordOf<S, K>> {\n return {\n next(): Promise<IteratorResult<RecordOf<S, K>>> {\n // Sync check avoids an extra Promise allocation on every iteration after the first.\n if (inner) return inner.next();\n\n return initInner().then((it) => it.next());\n },\n return(value?: unknown): Promise<IteratorResult<RecordOf<S, K>>> {\n if (inner) return inner.return?.(value) ?? Promise.resolve({ done: true, value });\n\n return Promise.resolve({ done: true, value });\n },\n throw(err?: unknown): Promise<IteratorResult<RecordOf<S, K>>> {\n if (inner) return inner.throw?.(err) ?? Promise.reject(err);\n\n return Promise.reject(err);\n },\n };\n },\n };\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Adapter, AnySchema, BaseAdapterOptions, MigrationFn, RecordOf } from '../types';
2
+ type IndexedDbOptions<S extends AnySchema> = BaseAdapterOptions<S> & {
3
+ migrate?: MigrationFn;
4
+ name: string;
5
+ /** Schema version. Must be a positive integer. Increment when adding tables or changing the schema, then provide `migrate`. Defaults to 1. */
6
+ version?: number;
7
+ };
8
+ export type IndexedDbAdapter<S extends AnySchema> = Adapter<S> & {
9
+ iterate<K extends keyof S>(table: K): AsyncIterable<RecordOf<S, K>>;
10
+ };
11
+ export declare function createIndexedDB<S extends AnySchema>(options: IndexedDbOptions<S>): IndexedDbAdapter<S>;
12
+ export {};
13
+ //# sourceMappingURL=indexeddb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexeddb.d.ts","sourceRoot":"","sources":["../../src/adapters/indexeddb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EACT,kBAAkB,EAElB,WAAW,EACX,QAAQ,EAGT,MAAM,UAAU,CAAC;AA0XlB,KAAK,gBAAgB,CAAC,CAAC,SAAS,SAAS,IAAI,kBAAkB,CAAC,CAAC,CAAC,GAAG;IACnE,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,8IAA8I;IAC9I,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,SAAS,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG;IAC/D,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;CACrE,CAAC;AAEF,wBAAgB,eAAe,CAAC,CAAC,SAAS,SAAS,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CA8WtG"}
@@ -0,0 +1,336 @@
1
+ import { VaultDisposedError as e, VaultError as t, VaultMigrationError as n } from "../errors.js";
2
+ import { getRecordKey as r } from "../internal.js";
3
+ import { defaultCodec as i, isExpired as a } from "../ttl.js";
4
+ import { buildAdapterOps as o, buildTxContext as s } from "../adapter-core.js";
5
+ //#region src/adapters/indexeddb.ts
6
+ function c(e) {
7
+ return new Promise((n, r) => {
8
+ e.onsuccess = () => n(e.result), e.onerror = () => r(e.error ?? new t("IndexedDB request failed"));
9
+ });
10
+ }
11
+ function l(e, n, r) {
12
+ return new t(`${n} on "${e}"${r instanceof Error && r.message ? `: ${r.message}` : ""}`, { cause: r });
13
+ }
14
+ function u(e, t, n) {
15
+ return new Promise((r, i) => {
16
+ let a, o;
17
+ Promise.resolve().then(n).then((e) => {
18
+ a = e;
19
+ }).catch((t) => {
20
+ o = t;
21
+ try {
22
+ e.abort();
23
+ } catch {}
24
+ });
25
+ let s = (e, n = "transaction failed") => {
26
+ o instanceof Error ? i(o) : i(l(t, n, o ?? e));
27
+ };
28
+ e.oncomplete = () => {
29
+ if (o) {
30
+ s(void 0);
31
+ return;
32
+ }
33
+ r(a);
34
+ }, e.onerror = () => i(l(t, "transaction error", e.error)), e.onabort = () => s(e.error, "transaction aborted");
35
+ });
36
+ }
37
+ async function d(e, t) {
38
+ let n = await c(e.getAll()), r = [];
39
+ for (let e of n) {
40
+ let n = t(e);
41
+ n !== void 0 && r.push(n);
42
+ }
43
+ return r;
44
+ }
45
+ async function f(e, t, n, r) {
46
+ let i = e.index(t), a = n.type === "eq" ? IDBKeyRange.only(n.value) : n.type === "between" ? IDBKeyRange.bound(n.lower, n.upper) : IDBKeyRange.bound(n.prefix, n.prefix + "￿"), o = await c(i.getAll(a)), s = [];
47
+ for (let e of o) {
48
+ let t = r(e);
49
+ t !== void 0 && s.push(t);
50
+ }
51
+ return s;
52
+ }
53
+ async function p(e, t, n) {
54
+ if (t.type === "eq") {
55
+ let r = await m(e, t.value, n);
56
+ return r === void 0 ? [] : [r];
57
+ }
58
+ let r = t.type === "between" ? IDBKeyRange.bound(t.lower, t.upper) : IDBKeyRange.bound(t.prefix, t.prefix + "￿"), i = await c(e.getAll(r)), a = [];
59
+ for (let e of i) {
60
+ let t = n(e);
61
+ t !== void 0 && a.push(t);
62
+ }
63
+ return a;
64
+ }
65
+ async function m(e, t, n) {
66
+ let r = await c(e.get(t));
67
+ if (r != null) return n(r);
68
+ }
69
+ async function h(e, t, n) {
70
+ return await m(e, t, n) !== void 0;
71
+ }
72
+ async function g(e, t, n) {
73
+ let r = await h(e, t, n);
74
+ return await c(e.delete(t)), r;
75
+ }
76
+ async function _(e, t, n) {
77
+ return t.length === 0 ? 0 : (await Promise.all(t.map((t) => g(e, t, n)))).filter(Boolean).length;
78
+ }
79
+ async function v(e, t, n, r, i) {
80
+ await c(e.put(r(n, i), t));
81
+ }
82
+ function y(e, n) {
83
+ return new Promise((r, i) => {
84
+ let o = 0, s = e.openCursor();
85
+ s.onerror = () => i(s.error ?? new t("IndexedDB cursor failed during prune")), s.onsuccess = () => {
86
+ let e = s.result;
87
+ if (!e) {
88
+ r(o);
89
+ return;
90
+ }
91
+ let t = n.decode(e.value);
92
+ (!t || a(t.expiresAt)) && (e.delete(), o += 1), e.continue();
93
+ };
94
+ });
95
+ }
96
+ function b(e, n) {
97
+ return { [Symbol.asyncIterator]() {
98
+ let r = e.openCursor(), i = { type: "idle" }, a = (e) => {
99
+ if (i.type === "waiting") {
100
+ let { resolve: t } = i;
101
+ i = e.done ? { type: "done" } : { type: "idle" }, t(e);
102
+ } else i = {
103
+ result: e,
104
+ type: "buffered"
105
+ };
106
+ };
107
+ return r.onerror = () => {
108
+ let e = r.error ?? new t("IndexedDB cursor iteration failed");
109
+ if (i.type === "waiting") {
110
+ let { reject: t } = i;
111
+ i = { type: "done" }, t(e);
112
+ } else i = {
113
+ error: e,
114
+ type: "error"
115
+ };
116
+ }, r.onsuccess = () => {
117
+ let e = r.result;
118
+ if (!e) {
119
+ a({
120
+ done: !0,
121
+ value: void 0
122
+ });
123
+ return;
124
+ }
125
+ let t = n(e.value);
126
+ e.continue(), t !== void 0 && a({
127
+ done: !1,
128
+ value: t
129
+ });
130
+ }, {
131
+ next() {
132
+ if (i.type === "error") {
133
+ let { error: e } = i;
134
+ return i = { type: "done" }, Promise.reject(e);
135
+ }
136
+ if (i.type === "buffered") {
137
+ let { result: e } = i;
138
+ return i = e.done ? { type: "done" } : { type: "idle" }, Promise.resolve(e);
139
+ }
140
+ return i.type === "done" ? Promise.resolve({
141
+ done: !0,
142
+ value: void 0
143
+ }) : new Promise((e, t) => {
144
+ i = {
145
+ reject: t,
146
+ resolve: e,
147
+ type: "waiting"
148
+ };
149
+ });
150
+ },
151
+ return(e) {
152
+ return i.type === "waiting" && i.resolve({
153
+ done: !0,
154
+ value: void 0
155
+ }), i = { type: "done" }, Promise.resolve({
156
+ done: !0,
157
+ value: e
158
+ });
159
+ },
160
+ throw(e) {
161
+ return i.type === "waiting" && i.reject(e), i = { type: "done" }, Promise.reject(e);
162
+ }
163
+ };
164
+ } };
165
+ }
166
+ function x(e, t, n, i) {
167
+ let a = (e) => t.objectStore(e);
168
+ return {
169
+ clear: async (e) => {
170
+ await c(a(e).clear());
171
+ },
172
+ count: async (e) => (await c(a(e).getAll())).filter((e) => n(e) !== void 0).length,
173
+ delete: (e, t) => g(a(e), t, n),
174
+ deleteMany: (e, t) => _(a(e), t, n),
175
+ get: (e, t) => m(a(e), t, n),
176
+ getAll: (e) => d(a(e), n),
177
+ getByIndexRange: (e, t, r) => f(a(e), t, r, n),
178
+ getByKeyRange: (e, t) => p(a(e), t, n),
179
+ getMany: (e, t) => Promise.all(t.map((t) => m(a(e), t, n))),
180
+ has: (e, t) => h(a(e), t, n),
181
+ pruneExpiredInTable: (e) => y(a(e), {
182
+ decode: n,
183
+ encode: i
184
+ }),
185
+ put(t, n, o) {
186
+ return v(a(t), r(e, t, n), n, i, o);
187
+ },
188
+ putAll(t, n, o) {
189
+ return Promise.all(n.map((n) => v(a(t), r(e, t, n), n, i, o))).then(() => void 0);
190
+ }
191
+ };
192
+ }
193
+ function S(l) {
194
+ let { codec: S = i, logger: C, migrate: w, name: T, onMetrics: E, schema: D, signals: O, validators: k, version: A = 1 } = l;
195
+ if (!Number.isInteger(A) || A < 1) throw new t(`createIndexedDB: version must be a positive integer, got ${String(A)}`);
196
+ let j = (e) => {
197
+ let t = S.decode(e);
198
+ if (t && !a(t.expiresAt)) return t.value;
199
+ }, M = (e, t) => {
200
+ let n = t === void 0 ? void 0 : Date.now() + t;
201
+ return S.encode(e, n);
202
+ }, N = typeof BroadcastChannel < "u" ? new BroadcastChannel(`vault:${T}`) : void 0;
203
+ !N && C && C.error(`[vault] BroadcastChannel unavailable — cross-tab sync disabled for "${T}"`);
204
+ let P = null, F = null, I = !1, L = (e, t) => {
205
+ for (let [n, r] of Object.entries(D)) {
206
+ let i;
207
+ i = e.objectStoreNames.contains(n) ? t.objectStore(n) : e.createObjectStore(n);
208
+ let a = r.indexes ?? [];
209
+ for (let e of a) i.indexNames.contains(e) || i.createIndex(e, `value.${e}`);
210
+ }
211
+ }, R = async () => (F ||= new Promise((e, r) => {
212
+ let i = indexedDB.open(T, A);
213
+ i.onupgradeneeded = (e) => {
214
+ let t = i.result, a = i.transaction;
215
+ if (w) try {
216
+ w({
217
+ db: t,
218
+ newVersion: e.newVersion ?? null,
219
+ oldVersion: e.oldVersion,
220
+ tx: a
221
+ });
222
+ } catch (e) {
223
+ try {
224
+ a.abort();
225
+ } catch {}
226
+ r(new n(`migration failed for "${T}"`, { cause: e }));
227
+ return;
228
+ }
229
+ L(t, a);
230
+ }, i.onsuccess = () => {
231
+ if (I) {
232
+ i.result.close(), e();
233
+ return;
234
+ }
235
+ let t = i.result;
236
+ t.onversionchange = () => {
237
+ t.close(), P = null, F = null;
238
+ }, P = t, e();
239
+ }, i.onerror = () => {
240
+ F = null, r(new t(`failed to open "${T}"`, { cause: i.error }));
241
+ };
242
+ }), F), z = async (t, n, r) => {
243
+ if (I || (P || await R(), !P)) throw new e(`"${T}" is disposed`);
244
+ let i = String(t), a = P.transaction(i, n);
245
+ return u(a, `${T}/${i}`, () => r(a.objectStore(i)));
246
+ }, B = async () => {
247
+ if (I || (P || await R(), !P)) throw new e(`"${T}" is disposed`);
248
+ return P;
249
+ }, V = (e) => {
250
+ N?.postMessage({ table: String(e) });
251
+ }, H = {
252
+ clear: (e) => z(e, "readwrite", (e) => c(e.clear()).then(() => void 0)),
253
+ count: (e) => z(e, "readonly", async (e) => (await c(e.getAll())).filter((e) => j(e) !== void 0).length),
254
+ delete: (e, t) => z(e, "readwrite", (e) => g(e, t, j)),
255
+ deleteMany: (e, t) => t.length === 0 ? Promise.resolve(0) : z(e, "readwrite", (e) => _(e, t, j)),
256
+ async dispose() {
257
+ I = !0, N?.close(), F && await F.catch(() => {}), P?.close(), P = null, F = null;
258
+ },
259
+ get: (e, t) => z(e, "readonly", (e) => m(e, t, j)),
260
+ getAll: (e) => z(e, "readonly", (e) => d(e, j)),
261
+ getAllKeys: (e) => z(e, "readonly", async (t) => {
262
+ let n = await d(t, j), r = D[e].key;
263
+ return n.map((e) => e[r]);
264
+ }),
265
+ getByIndexRange: (e, t, n) => z(e, "readonly", (e) => f(e, t, n, j)),
266
+ getByKeyRange: (e, t) => z(e, "readonly", (e) => p(e, t, j)),
267
+ getMany: (e, t) => t.length === 0 ? Promise.resolve([]) : z(e, "readonly", (e) => Promise.all(t.map((t) => m(e, t, j)))),
268
+ getRawCount: (e) => z(e, "readonly", (e) => c(e.count())),
269
+ has: (e, t) => z(e, "readonly", (e) => h(e, t, j)),
270
+ async pruneAllExpired() {
271
+ let e = await B(), t = Object.keys(D), n = e.transaction(t, "readwrite"), r = await u(n, `${T}/pruneAll`, () => Promise.all(t.map(async (e) => [e, await y(n.objectStore(e), S)])));
272
+ return Object.fromEntries(r);
273
+ },
274
+ pruneExpiredInTable: (e) => z(e, "readwrite", (e) => y(e, S)),
275
+ put(e, t, n) {
276
+ let i = r(D, e, t);
277
+ return z(e, "readwrite", (e) => v(e, i, t, M, n));
278
+ },
279
+ putAll(e, t, n) {
280
+ return z(e, "readwrite", (i) => Promise.all(t.map((t) => v(i, r(D, e, t), t, M, n))).then(() => void 0));
281
+ }
282
+ }, U = async (e, t, n, r) => {
283
+ let i = (await B()).transaction([...e], "readwrite"), a = /* @__PURE__ */ new Set(), o = x(D, i, j, M), c = new Set(e), l = s(D, o, (e) => a.add(e), r, c), d = await u(i, T, () => t(l));
284
+ for (let e of a) n(e);
285
+ return d;
286
+ };
287
+ return {
288
+ ...o(D, H, {
289
+ buildBatch: ({ notifyMutation: e, validate: t }) => (n, r) => U(n, r, e, t),
290
+ logger: C,
291
+ onCrossTabMessage(e) {
292
+ if (N) return N.onmessage = (t) => {
293
+ let n = t.data?.table;
294
+ !n || !Object.hasOwn(D, n) || e(n);
295
+ }, () => {
296
+ N.onmessage = null;
297
+ };
298
+ },
299
+ onMetrics: E,
300
+ onMutation: V,
301
+ schema: D,
302
+ signals: O,
303
+ validators: k
304
+ }),
305
+ iterate(t) {
306
+ if (I) throw new e(`"${T}" is disposed`);
307
+ let n = async () => {
308
+ if (P || await R(), !P || I) throw new e(`"${T}" is disposed`);
309
+ return b(P.transaction(String(t), "readonly").objectStore(String(t)), j);
310
+ }, r, i = () => n().then((e) => (r = e[Symbol.asyncIterator](), r));
311
+ return { [Symbol.asyncIterator]() {
312
+ return {
313
+ next() {
314
+ return r ? r.next() : i().then((e) => e.next());
315
+ },
316
+ return(e) {
317
+ return r ? r.return?.(e) ?? Promise.resolve({
318
+ done: !0,
319
+ value: e
320
+ }) : Promise.resolve({
321
+ done: !0,
322
+ value: e
323
+ });
324
+ },
325
+ throw(e) {
326
+ return r ? r.throw?.(e) ?? Promise.reject(e) : Promise.reject(e);
327
+ }
328
+ };
329
+ } };
330
+ }
331
+ };
332
+ }
333
+ //#endregion
334
+ export { S as createIndexedDB };
335
+
336
+ //# sourceMappingURL=indexeddb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexeddb.js","names":[],"sources":["../../src/adapters/indexeddb.ts"],"sourcesContent":["import type {\n Adapter,\n AnySchema,\n BaseAdapterOptions,\n KeyOf,\n MigrationFn,\n RecordOf,\n TransactionContext,\n TtlMs,\n} from '../types';\n\nimport { buildAdapterOps, buildTxContext, type StorageBackend } from '../adapter-core';\nimport { VaultDisposedError, VaultError, VaultMigrationError } from '../errors';\nimport { getRecordKey } from '../internal';\nimport { type NativeRange } from '../query';\nimport { defaultCodec, isExpired, type VaultCodec } from '../ttl';\n\nfunction idbReq<R>(request: IDBRequest<R>): Promise<R> {\n return new Promise<R>((resolve, reject) => {\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error ?? new VaultError('IndexedDB request failed'));\n });\n}\n\nfunction wrapTxError(scope: string, message: string, cause: unknown): VaultError {\n const causeMessage = cause instanceof Error && cause.message ? `: ${cause.message}` : '';\n\n return new VaultError(`${message} on \"${scope}\"${causeMessage}`, { cause });\n}\n\nfunction runIdbTx<T>(tx: IDBTransaction, scope: string, work: () => Promise<T>): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n let result: T | undefined;\n let callbackError: unknown;\n\n Promise.resolve()\n .then(work)\n .then((value) => {\n result = value;\n })\n .catch((error) => {\n callbackError = error;\n\n try {\n tx.abort();\n } catch {\n /* ignore */\n }\n });\n\n const rejectWithCallbackError = (fallbackCause: unknown, message = 'transaction failed'): void => {\n if (callbackError instanceof Error) {\n reject(callbackError);\n } else {\n reject(wrapTxError(scope, message, callbackError ?? fallbackCause));\n }\n };\n\n tx.oncomplete = () => {\n if (callbackError) {\n rejectWithCallbackError(undefined);\n\n return;\n }\n\n resolve(result as T);\n };\n tx.onerror = () => reject(wrapTxError(scope, 'transaction error', tx.error));\n tx.onabort = () => rejectWithCallbackError(tx.error, 'transaction aborted');\n });\n}\n\nasync function getAllFromStore<T extends Record<string, unknown>>(\n store: IDBObjectStore,\n decode: (raw: unknown) => T | undefined,\n): Promise<T[]> {\n const rawRecords = await idbReq<unknown[]>(store.getAll());\n const records: T[] = [];\n\n for (const raw of rawRecords) {\n const value = decode(raw);\n\n if (value !== undefined) records.push(value);\n }\n\n return records;\n}\n\nasync function getAllFromStoreByIndex<T extends Record<string, unknown>>(\n store: IDBObjectStore,\n indexName: string,\n range: NativeRange,\n decode: (raw: unknown) => T | undefined,\n): Promise<T[]> {\n const index = store.index(indexName);\n const idbRange =\n range.type === 'eq'\n ? IDBKeyRange.only(range.value as IDBValidKey)\n : range.type === 'between'\n ? IDBKeyRange.bound(range.lower as IDBValidKey, range.upper as IDBValidKey)\n : IDBKeyRange.bound(range.prefix, range.prefix + '\\uffff');\n const rawRecords = await idbReq<unknown[]>(index.getAll(idbRange));\n const records: T[] = [];\n\n for (const raw of rawRecords) {\n const value = decode(raw);\n\n if (value !== undefined) records.push(value);\n }\n\n return records;\n}\n\nasync function getAllFromStoreWithRange<T extends Record<string, unknown>>(\n store: IDBObjectStore,\n range: NativeRange,\n decode: (raw: unknown) => T | undefined,\n): Promise<T[]> {\n if (range.type === 'eq') {\n const record = await storeGet<T>(store, range.value as IDBValidKey, decode);\n\n return record !== undefined ? [record] : [];\n }\n\n const idbRange =\n range.type === 'between'\n ? IDBKeyRange.bound(range.lower as IDBValidKey, range.upper as IDBValidKey)\n : // 'starts': bound from prefix to prefix\\uffff (covers all BMP strings starting with prefix)\n IDBKeyRange.bound(range.prefix, range.prefix + '\\uffff');\n\n const rawRecords = await idbReq<unknown[]>(store.getAll(idbRange));\n const records: T[] = [];\n\n for (const raw of rawRecords) {\n const value = decode(raw);\n\n if (value !== undefined) records.push(value);\n }\n\n return records;\n}\n\nasync function storeGet<T extends Record<string, unknown>>(\n store: IDBObjectStore,\n key: IDBValidKey,\n decode: (raw: unknown) => T | undefined,\n): Promise<T | undefined> {\n const raw = await idbReq<unknown>(store.get(key));\n\n if (raw == null) return undefined;\n\n return decode(raw);\n}\n\nasync function storeHas<T extends Record<string, unknown>>(\n store: IDBObjectStore,\n key: IDBValidKey,\n decode: (raw: unknown) => T | undefined,\n): Promise<boolean> {\n return (await storeGet<T>(store, key, decode)) !== undefined;\n}\n\nasync function storeDelete<T extends Record<string, unknown>>(\n store: IDBObjectStore,\n key: IDBValidKey,\n decode: (raw: unknown) => T | undefined,\n): Promise<boolean> {\n const live = await storeHas<T>(store, key, decode);\n\n await idbReq(store.delete(key));\n\n return live;\n}\n\nasync function storeDeleteMany<T extends Record<string, unknown>>(\n store: IDBObjectStore,\n keys: IDBValidKey[],\n decode: (raw: unknown) => T | undefined,\n): Promise<number> {\n if (keys.length === 0) return 0;\n\n const results = await Promise.all(keys.map((k) => storeDelete<T>(store, k, decode)));\n\n return results.filter(Boolean).length;\n}\n\nasync function storePutAt<T>(\n store: IDBObjectStore,\n key: IDBValidKey,\n value: T,\n encode: (v: T, ttl?: TtlMs) => unknown,\n ttl?: TtlMs,\n): Promise<void> {\n await idbReq(store.put(encode(value, ttl), key));\n}\n\nfunction pruneExpiredInStore(store: IDBObjectStore, codec: VaultCodec): Promise<number> {\n return new Promise<number>((resolve, reject) => {\n let deleted = 0;\n const request = store.openCursor();\n\n request.onerror = () => reject(request.error ?? new VaultError('IndexedDB cursor failed during prune'));\n request.onsuccess = () => {\n const cursor = request.result;\n\n if (!cursor) {\n resolve(deleted);\n\n return;\n }\n\n const stored = codec.decode(cursor.value as unknown);\n\n if (!stored || isExpired(stored.expiresAt)) {\n cursor.delete();\n deleted += 1;\n }\n\n cursor.continue();\n };\n });\n}\n\n/**\n * Cursor state machine — a single discriminated union replaces five boolean/nullable variables.\n * Transitions: idle → waiting (next() before cursor fires) | buffered (cursor fires first) | done | error\n */\ntype CursorState<T> =\n | { type: 'idle' }\n | { reject: (e: unknown) => void; resolve: (r: IteratorResult<T>) => void; type: 'waiting' }\n | { result: IteratorResult<T>; type: 'buffered' }\n | { error: unknown; type: 'error' }\n | { type: 'done' };\n\n/**\n * F1: True cursor-based iteration for IndexedDB.\n * Yields live records one-by-one using an IDB cursor, avoiding materializing the full table.\n * This is memory-efficient for large tables — the cursor walks the store incrementally.\n *\n * Design: the cursor is opened *synchronously* in [Symbol.asyncIterator]() so that event\n * handlers are wired immediately (no queueMicrotask races). The cursor is advanced *eagerly*\n * before yielding — this keeps the IDB readonly transaction alive between consumer awaits,\n * because IDB auto-commits when there are no pending requests.\n */\nfunction iterateStoreWithCursor<T extends Record<string, unknown>>(\n store: IDBObjectStore,\n decode: (raw: unknown) => T | undefined,\n): AsyncIterable<T> {\n return {\n [Symbol.asyncIterator](): AsyncIterator<T> {\n const cursorRequest = store.openCursor();\n let state: CursorState<T> = { type: 'idle' };\n\n const deliver = (result: IteratorResult<T>): void => {\n if (state.type === 'waiting') {\n const { resolve } = state;\n\n state = result.done ? { type: 'done' } : { type: 'idle' };\n resolve(result);\n } else {\n state = { result, type: 'buffered' };\n }\n };\n\n cursorRequest.onerror = () => {\n const err = cursorRequest.error ?? new VaultError('IndexedDB cursor iteration failed');\n\n if (state.type === 'waiting') {\n const { reject } = state;\n\n state = { type: 'done' };\n reject(err);\n } else {\n state = { error: err, type: 'error' };\n }\n };\n\n cursorRequest.onsuccess = () => {\n const cursor = cursorRequest.result;\n\n if (!cursor) {\n deliver({ done: true, value: undefined });\n\n return;\n }\n\n const value = decode(cursor.value as unknown);\n\n // Advance eagerly BEFORE yielding to keep the IDB transaction alive.\n cursor.continue();\n\n if (value !== undefined) deliver({ done: false, value });\n };\n\n return {\n next(): Promise<IteratorResult<T>> {\n if (state.type === 'error') {\n const { error } = state;\n\n state = { type: 'done' };\n\n return Promise.reject(error);\n }\n\n if (state.type === 'buffered') {\n const { result } = state;\n\n state = result.done ? { type: 'done' } : { type: 'idle' };\n\n return Promise.resolve(result);\n }\n\n if (state.type === 'done') return Promise.resolve({ done: true, value: undefined });\n\n return new Promise<IteratorResult<T>>((resolve, reject) => {\n state = { reject, resolve, type: 'waiting' };\n });\n },\n\n return(value?: unknown): Promise<IteratorResult<T>> {\n if (state.type === 'waiting') state.resolve({ done: true, value: undefined });\n\n state = { type: 'done' };\n\n return Promise.resolve({ done: true, value });\n },\n\n throw(err?: unknown): Promise<IteratorResult<T>> {\n if (state.type === 'waiting') state.reject(err);\n\n state = { type: 'done' };\n\n return Promise.reject(err);\n },\n };\n },\n };\n}\n\n/**\n * R3: Extracted IDB batch core — builds a StorageBackend that operates within\n * an existing IDBTransaction, shared by all tables in the batch.\n * Eliminates the duplicated `txCore` block that was previously inlined in `idbBatch`.\n */\nfunction buildIdbBatchCore<S extends AnySchema, K extends keyof S & string>(\n schema: S,\n idbTx: IDBTransaction,\n decode: <T extends Record<string, unknown>>(raw: unknown) => T | undefined,\n encode: <T>(value: T, ttl?: TtlMs) => unknown,\n): StorageBackend<S, K> {\n const storeOf = (table: K): IDBObjectStore => idbTx.objectStore(table);\n\n return {\n clear: async (table) => {\n await idbReq(storeOf(table).clear());\n },\n count: async (table) => {\n // Must inspect each stored record to exclude TTL-expired entries.\n // Individual put() calls can attach a TTL even when the schema has no defaultTtl,\n // so schema[table].defaultTtl being absent does not guarantee a clean count.\n // This matches the top-level core.count() behaviour in the IDB adapter.\n const all = await idbReq<unknown[]>(storeOf(table).getAll());\n\n return all.filter((r) => decode(r) !== undefined).length;\n },\n delete: (table, key) => storeDelete<RecordOf<S, K>>(storeOf(table), key as IDBValidKey, decode),\n deleteMany: (table, keys) => storeDeleteMany<RecordOf<S, K>>(storeOf(table), keys as IDBValidKey[], decode),\n get: (table, key) => storeGet<RecordOf<S, typeof table>>(storeOf(table), key as IDBValidKey, decode),\n getAll: (table) => getAllFromStore<RecordOf<S, typeof table>>(storeOf(table), decode),\n getByIndexRange: (table, field, range) =>\n getAllFromStoreByIndex<RecordOf<S, typeof table>>(storeOf(table), field, range, decode),\n getByKeyRange: (table, range) => getAllFromStoreWithRange<RecordOf<S, typeof table>>(storeOf(table), range, decode),\n getMany: (table, keys) =>\n Promise.all(keys.map((k) => storeGet<RecordOf<S, typeof table>>(storeOf(table), k as IDBValidKey, decode))),\n has: (table, key) => storeHas<RecordOf<S, typeof table>>(storeOf(table), key as IDBValidKey, decode),\n pruneExpiredInTable: (table) => pruneExpiredInStore(storeOf(table), { decode, encode }),\n put(table, value, ttl) {\n return storePutAt(storeOf(table), getRecordKey(schema, table, value) as IDBValidKey, value, encode, ttl);\n },\n putAll(table, values, ttl) {\n return Promise.all(\n values.map((v) => storePutAt(storeOf(table), getRecordKey(schema, table, v) as IDBValidKey, v, encode, ttl)),\n ).then(() => undefined);\n },\n };\n}\n\ntype IndexedDbOptions<S extends AnySchema> = BaseAdapterOptions<S> & {\n migrate?: MigrationFn;\n name: string;\n /** Schema version. Must be a positive integer. Increment when adding tables or changing the schema, then provide `migrate`. Defaults to 1. */\n version?: number;\n};\n\nexport type IndexedDbAdapter<S extends AnySchema> = Adapter<S> & {\n iterate<K extends keyof S>(table: K): AsyncIterable<RecordOf<S, K>>;\n};\n\nexport function createIndexedDB<S extends AnySchema>(options: IndexedDbOptions<S>): IndexedDbAdapter<S> {\n const {\n codec: userCodec = defaultCodec,\n logger,\n migrate,\n name,\n onMetrics,\n schema,\n signals,\n validators,\n version = 1,\n } = options;\n\n if (!Number.isInteger(version) || version < 1) {\n throw new VaultError(`createIndexedDB: version must be a positive integer, got ${String(version)}`);\n }\n\n // F4: Codec-bound encode/decode used throughout the IDB adapter.\n const decode = <T extends Record<string, unknown>>(raw: unknown): T | undefined => {\n const stored = userCodec.decode<T>(raw);\n\n if (!stored) return undefined;\n\n if (isExpired(stored.expiresAt)) return undefined;\n\n return stored.value;\n };\n\n const encode = <T>(value: T, ttl?: TtlMs): unknown => {\n const expiresAt = ttl !== undefined ? Date.now() + ttl : undefined;\n\n return userCodec.encode(value, expiresAt);\n };\n\n const channel = typeof BroadcastChannel !== 'undefined' ? new BroadcastChannel(`vault:${name}`) : undefined;\n\n if (!channel && logger) {\n logger.error(`[vault] BroadcastChannel unavailable — cross-tab sync disabled for \"${name}\"`);\n }\n\n let db: IDBDatabase | null = null;\n let connectPromise: Promise<void> | null = null;\n let disposed = false;\n\n const createObjectStores = (target: IDBDatabase, tx: IDBTransaction): void => {\n for (const [tableName, entry] of Object.entries(schema)) {\n let store: IDBObjectStore;\n\n if (!target.objectStoreNames.contains(tableName)) {\n store = target.createObjectStore(tableName);\n } else {\n store = tx.objectStore(tableName);\n }\n\n // F5: Create secondary indexes for fields declared via .index() on the table() builder.\n // Stored format is { value: T, expiresAt?: number } so IDB keyPath is `value.<field>`.\n const indexes = (entry as { indexes?: readonly string[] }).indexes ?? [];\n\n for (const field of indexes) {\n if (!store.indexNames.contains(field)) {\n store.createIndex(field, `value.${field}`);\n }\n }\n }\n };\n\n const connect = async (): Promise<void> => {\n if (!connectPromise) {\n connectPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(name, version);\n\n request.onupgradeneeded = (event) => {\n const target = request.result;\n const tx = request.transaction!;\n\n if (migrate) {\n try {\n migrate({\n db: target,\n newVersion: (event as IDBVersionChangeEvent).newVersion ?? null,\n oldVersion: event.oldVersion,\n tx,\n });\n } catch (error) {\n try {\n tx.abort();\n } catch {\n /* ignore */\n }\n\n reject(new VaultMigrationError(`migration failed for \"${name}\"`, { cause: error }));\n\n return;\n }\n }\n\n createObjectStores(target, tx);\n };\n\n request.onsuccess = () => {\n if (disposed) {\n request.result.close();\n resolve();\n\n return;\n }\n\n const connection = request.result;\n\n connection.onversionchange = () => {\n connection.close();\n db = null;\n connectPromise = null;\n };\n\n db = connection;\n resolve();\n };\n request.onerror = () => {\n connectPromise = null;\n reject(new VaultError(`failed to open \"${name}\"`, { cause: request.error }));\n };\n });\n }\n\n return connectPromise;\n };\n\n const withStore = async <T>(\n table: keyof S,\n mode: 'readonly' | 'readwrite',\n fn: (store: IDBObjectStore) => Promise<T>,\n ): Promise<T> => {\n if (disposed) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n if (!db) await connect();\n\n if (!db) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n const tableName = String(table);\n const tx = db.transaction(tableName, mode);\n\n return runIdbTx(tx, `${name}/${tableName}`, () => fn(tx.objectStore(tableName)));\n };\n\n const requireDb = async (): Promise<IDBDatabase> => {\n if (disposed) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n if (!db) await connect();\n\n if (!db) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n return db;\n };\n\n const publish = <K extends keyof S>(table: K): void => {\n channel?.postMessage({ table: String(table) });\n };\n\n const core: StorageBackend<S> = {\n clear: (table) => withStore(table, 'readwrite', (s) => idbReq(s.clear()).then(() => undefined)),\n\n count: (table) =>\n withStore(table, 'readonly', async (s) => {\n // Must inspect each stored record to exclude TTL-expired entries.\n // Individual put() calls can attach a TTL even when the schema has no defaultTtl,\n // so schema[table].defaultTtl being absent does not guarantee a clean count.\n const all = await idbReq<unknown[]>(s.getAll());\n\n return all.filter((r) => decode(r) !== undefined).length;\n }),\n\n delete: (table, key) =>\n withStore(table, 'readwrite', (s) => storeDelete<RecordOf<S, typeof table>>(s, key as IDBValidKey, decode)),\n\n deleteMany: (table, keys) =>\n keys.length === 0\n ? Promise.resolve(0)\n : withStore(table, 'readwrite', (s) =>\n storeDeleteMany<RecordOf<S, typeof table>>(s, keys as IDBValidKey[], decode),\n ),\n\n async dispose(): Promise<void> {\n disposed = true;\n channel?.close();\n\n // F7: Wait for any in-progress connect before closing the DB to avoid\n // \"database connection is closing\" errors on in-flight requests.\n if (connectPromise) await connectPromise.catch(() => {});\n\n db?.close();\n db = null;\n connectPromise = null;\n },\n\n get: (table, key) =>\n withStore(table, 'readonly', (s) => storeGet<RecordOf<S, typeof table>>(s, key as IDBValidKey, decode)),\n\n getAll: (table) => withStore(table, 'readonly', (s) => getAllFromStore<RecordOf<S, typeof table>>(s, decode)),\n\n // Ad-hoc per-put TTLs can be attached regardless of schema-level defaultTtl (same caveat as\n // count()), so we cannot take the O(1) store.getAllKeys() shortcut unconditionally — every\n // record must be decoded to exclude TTL-expired entries correctly.\n getAllKeys: (table) =>\n withStore(table, 'readonly', async (s) => {\n const records = await getAllFromStore<RecordOf<S, typeof table>>(s, decode);\n const keyField = schema[table].key;\n\n return records.map((r) => (r as Record<string, unknown>)[keyField] as KeyOf<S, typeof table>);\n }),\n\n getByIndexRange: (table, field, range) =>\n withStore(table, 'readonly', (s) => getAllFromStoreByIndex<RecordOf<S, typeof table>>(s, field, range, decode)),\n\n getByKeyRange: (table, range) =>\n withStore(table, 'readonly', (s) => getAllFromStoreWithRange<RecordOf<S, typeof table>>(s, range, decode)),\n\n getMany: (table, keys) =>\n keys.length === 0\n ? Promise.resolve([])\n : withStore(table, 'readonly', (s) =>\n Promise.all(keys.map((k) => storeGet<RecordOf<S, typeof table>>(s, k as IDBValidKey, decode))),\n ),\n\n getRawCount: (table) => withStore(table, 'readonly', (s) => idbReq(s.count())),\n\n has: (table, key) =>\n withStore(table, 'readonly', (s) => storeHas<RecordOf<S, typeof table>>(s, key as IDBValidKey, decode)),\n\n async pruneAllExpired() {\n const idb = await requireDb();\n const tableNames = Object.keys(schema);\n const tx = idb.transaction(tableNames, 'readwrite');\n const results = await runIdbTx(tx, `${name}/pruneAll`, () =>\n Promise.all(tableNames.map(async (t) => [t, await pruneExpiredInStore(tx.objectStore(t), userCodec)] as const)),\n );\n\n return Object.fromEntries(results);\n },\n\n pruneExpiredInTable: (table) => withStore(table, 'readwrite', (s) => pruneExpiredInStore(s, userCodec)),\n\n put(table, value, ttl) {\n const key = getRecordKey(schema, table, value) as IDBValidKey;\n\n return withStore(table, 'readwrite', (s) => storePutAt(s, key, value, encode, ttl));\n },\n\n putAll(table, values, ttl) {\n return withStore(table, 'readwrite', (s) =>\n Promise.all(\n values.map((v) => storePutAt(s, getRecordKey(schema, table, v) as IDBValidKey, v, encode, ttl)),\n ).then(() => undefined),\n );\n },\n };\n\n const idbBatch = async <K extends keyof S & string, R>(\n tables: readonly K[],\n fn: (tx: TransactionContext<S, K>) => Promise<R>,\n notifyMutation: (table: K) => void,\n validateFn: <T extends K>(table: T, value: RecordOf<S, T>) => RecordOf<S, T>,\n ): Promise<R> => {\n const idb = await requireDb();\n const idbTx = idb.transaction([...tables] as string[], 'readwrite');\n const dirtyTables = new Set<K>();\n\n const txCore = buildIdbBatchCore<S, K>(schema, idbTx, decode, encode);\n const scope = new Set<string>(tables);\n const tx = buildTxContext<S, K>(schema, txCore, (t) => dirtyTables.add(t), validateFn, scope);\n const result = await runIdbTx(idbTx, name, () => fn(tx));\n\n for (const table of dirtyTables) {\n notifyMutation(table);\n }\n\n return result;\n };\n\n const adapter = buildAdapterOps(schema, core, {\n buildBatch:\n ({ notifyMutation, validate: validateFn }) =>\n (tables, fn) =>\n idbBatch(tables, fn, notifyMutation, validateFn),\n logger,\n onCrossTabMessage(notify) {\n if (!channel) {\n return undefined;\n }\n\n channel.onmessage = (event: MessageEvent<{ table?: string }>) => {\n const tableName = event.data?.table;\n\n if (!tableName || !Object.hasOwn(schema, tableName)) return;\n\n notify(tableName as keyof S & string);\n };\n\n return () => {\n channel.onmessage = null;\n };\n },\n onMetrics,\n onMutation: publish,\n schema,\n signals,\n validators,\n });\n\n /**\n * F1: Attach cursor-based `iterate()` on top of the adapter.\n * Opens a dedicated readonly transaction per call and streams records via IDB cursor —\n * genuinely memory-efficient for large tables unlike the getAll()-then-yield pattern.\n */\n return {\n ...adapter,\n iterate<K extends keyof S>(table: K): AsyncIterable<RecordOf<S, K>> {\n if (disposed) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n // Each call opens a fresh transaction so iteration doesn't hold locks across awaits.\n // We need to ensure the DB is connected before opening the transaction.\n const getIterable = async (): Promise<AsyncIterable<RecordOf<S, K>>> => {\n if (!db) await connect();\n\n if (!db || disposed) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n const idb = db;\n const tx = idb.transaction(String(table), 'readonly');\n const store = tx.objectStore(String(table));\n\n return iterateStoreWithCursor<RecordOf<S, K>>(store, decode as (raw: unknown) => RecordOf<S, K> | undefined);\n };\n\n let inner: AsyncIterator<RecordOf<S, K>> | undefined;\n\n const initInner = (): Promise<AsyncIterator<RecordOf<S, K>>> =>\n getIterable().then((iterable) => {\n inner = iterable[Symbol.asyncIterator]();\n\n return inner;\n });\n\n return {\n [Symbol.asyncIterator](): AsyncIterator<RecordOf<S, K>> {\n return {\n next(): Promise<IteratorResult<RecordOf<S, K>>> {\n // Sync check avoids an extra Promise allocation on every iteration after the first.\n if (inner) return inner.next();\n\n return initInner().then((it) => it.next());\n },\n return(value?: unknown): Promise<IteratorResult<RecordOf<S, K>>> {\n if (inner) return inner.return?.(value) ?? Promise.resolve({ done: true, value });\n\n return Promise.resolve({ done: true, value });\n },\n throw(err?: unknown): Promise<IteratorResult<RecordOf<S, K>>> {\n if (inner) return inner.throw?.(err) ?? Promise.reject(err);\n\n return Promise.reject(err);\n },\n };\n },\n };\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require("../errors.cjs"),t=require("../internal.cjs"),n=require("../ttl.cjs"),r=require("../adapter-core.cjs");function i(e){return function(t){if(typeof t!=`object`||!t)return!1;let n=t;if(typeof n.table!=`string`||typeof n.type!=`string`||n.table===`__proto__`||n.table===`constructor`||n.table===`prototype`)return!1;switch(n.type){case`clear`:return!0;case`delete`:return typeof n.key==`string`;case`deleteMany`:return Array.isArray(n.keys)&&n.keys.every(e=>typeof e==`string`);case`put`:return typeof n.key==`string`&&e.decode(n.stored)!==void 0;case`putAll`:return Array.isArray(n.entries)&&n.entries.every(t=>typeof t==`object`&&!!t&&typeof t.key==`string`&&e.decode(t.stored)!==void 0);default:return!1}}}function a(a){let{codec:o=n.defaultCodec,logger:s,name:c,onMetrics:l,schema:u,signals:d,validators:f}=a,p=new Map(Object.keys(u).map(e=>[e,new Map])),m=e=>p.get(e),h=i(o),g=c!==void 0&&typeof BroadcastChannel<`u`?new BroadcastChannel(`vault-memory:${c}`):void 0,_=r.buildAdapterOps(u,{async clear(e){m(e).clear(),g?.postMessage({table:e,type:`clear`})},async count(e){let t=m(e),r=0,i=[];for(let[e,a]of t){let t=o.decode(a);!t||n.isExpired(t.expiresAt)?i.push(e):r+=1}for(let e of i)t.delete(e);return r},async delete(e,t){let r=m(e),i=r.get(String(t));if(!i)return!1;let a=o.decode(i),s=a!==void 0&&!n.isExpired(a.expiresAt);return r.delete(String(t)),s&&g?.postMessage({key:String(t),table:e,type:`delete`}),s},async deleteMany(e,t){let r=m(e),i=[];for(let e of t){let t=String(e),a=r.get(t);if(a){let e=o.decode(a);e!==void 0&&!n.isExpired(e.expiresAt)&&i.push(t),r.delete(t)}}return i.length>0&&g?.postMessage({keys:i,table:e,type:`deleteMany`}),i.length},dispose:g?async()=>g.close():void 0,async get(e,t){let r=m(e),i=r.get(String(t));if(!i)return;let a=o.decode(i);if(!a||n.isExpired(a.expiresAt)){r.delete(String(t));return}return a.value},async getAll(e){let t=m(e),r=[],i=[];for(let[e,a]of t){let t=o.decode(a);!t||n.isExpired(t.expiresAt)?i.push(e):r.push(t.value)}for(let e of i)t.delete(e);return r},async getRawCount(e){return m(e).size},async has(e,t){let r=m(e),i=r.get(String(t));if(!i)return!1;let a=o.decode(i),s=a!==void 0&&!n.isExpired(a.expiresAt);return s||r.delete(String(t)),s},async pruneExpiredInTable(e){let t=m(e),r=0;for(let[e,i]of t){let a=o.decode(i);(!a||n.isExpired(a.expiresAt))&&(t.delete(e),r+=1)}return r},async put(e,n,r){let i=String(t.getRecordKey(u,e,n)),a=r===void 0?void 0:Date.now()+r,s=o.encode(n,a);m(e).set(i,s),g?.postMessage({key:i,stored:s,table:e,type:`put`})},async putAll(e,n,r){let i=m(e),a=[],s=r===void 0?void 0:Date.now()+r;for(let r of n){let n=String(t.getRecordKey(u,e,r)),c=o.encode(r,s);i.set(n,c),a.push({key:n,stored:c})}a.length>0&&g?.postMessage({entries:a,table:e,type:`putAll`})}},{logger:s,onCrossTabMessage:g?e=>(g.onmessage=t=>{let n;try{if(!h(t.data))return;n=t.data}catch{return}let r=p.get(n.table);if(!r)return;let i=f?.[n.table],a=u[n.table]?.key,s=(e,t)=>{try{let n=o.decode(t);if(!n)return!1;let s=i?i.parse(n.value):n.value;if(a&&String(s[a])!==e)return!1;let c=n.expiresAt===void 0?{value:s}:{expiresAt:n.expiresAt,value:s};return r.set(e,c),!0}catch{return!1}};switch(n.type){case`clear`:r.clear(),e(n.table);return;case`delete`:r.delete(n.key),e(n.table);return;case`deleteMany`:for(let e of n.keys)r.delete(e);e(n.table);return;case`put`:s(n.key,n.stored)&&e(n.table);return;case`putAll`:{let t=!1;for(let{key:e,stored:r}of n.entries)s(e,r)&&(t=!0);t&&e(n.table)}return}},()=>{g.onmessage=null}):void 0,onMetrics:l,schema:u,signals:d,validators:f});return{..._,iterate(t){let r=m(String(t));return{async*[Symbol.asyncIterator](){if(_.disposed)throw new e.VaultDisposedError;let t=[];for(let[e,i]of r){let r=o.decode(i);!r||n.isExpired(r.expiresAt)?t.push(e):yield r.value}for(let e of t)r.delete(e)}}}}}exports.createMemory=a;
2
+ //# sourceMappingURL=memory.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.cjs","names":[],"sources":["../../src/adapters/memory.ts"],"sourcesContent":["import type { Adapter, AnySchema, BaseAdapterOptions, KeyOf, RecordOf, TtlMs } from '../types';\n\nimport { buildAdapterOps, type StorageBackend } from '../adapter-core';\nimport { VaultDisposedError } from '../errors';\nimport { getRecordKey } from '../internal';\nimport { defaultCodec, isExpired, type StoredRecord } from '../ttl';\n\ntype MemoryBroadcastMsg =\n | { table: string; type: 'clear' }\n | { key: string; table: string; type: 'delete' }\n | { keys: string[]; table: string; type: 'deleteMany' }\n | { key: string; stored: StoredRecord<unknown>; table: string; type: 'put' }\n | { entries: Array<{ key: string; stored: StoredRecord<unknown> }>; table: string; type: 'putAll' };\n\n/** Runtime type guard — rejects malformed or unknown BroadcastChannel messages. */\nfunction makeBroadcastMsgGuard(codec: { decode<T>(raw: unknown): (StoredRecord<T> & { value: T }) | undefined }) {\n return function isBroadcastMsg(data: unknown): data is MemoryBroadcastMsg {\n if (typeof data !== 'object' || data === null) return false;\n\n const d = data as Record<string, unknown>;\n\n if (typeof d['table'] !== 'string' || typeof d['type'] !== 'string') return false;\n\n // Guard against prototype-polluting table names from crafted cross-tab messages.\n if (d['table'] === '__proto__' || d['table'] === 'constructor' || d['table'] === 'prototype') return false;\n\n switch (d['type']) {\n case 'clear':\n return true;\n case 'delete':\n return typeof d['key'] === 'string';\n case 'deleteMany':\n return Array.isArray(d['keys']) && (d['keys'] as unknown[]).every((k) => typeof k === 'string');\n case 'put':\n return typeof d['key'] === 'string' && codec.decode(d['stored']) !== undefined;\n case 'putAll':\n return (\n Array.isArray(d['entries']) &&\n (d['entries'] as unknown[]).every(\n (e) =>\n typeof e === 'object' &&\n e !== null &&\n typeof (e as Record<string, unknown>)['key'] === 'string' &&\n codec.decode((e as Record<string, unknown>)['stored']) !== undefined,\n )\n );\n default:\n return false;\n }\n };\n}\n\ntype MemoryOptions<S extends AnySchema> = BaseAdapterOptions<S> & {\n /**\n * When provided and BroadcastChannel is available, enables cross-tab state sync.\n * All `createMemory` instances with the same `name` will replicate mutations to each other.\n */\n name?: string;\n};\n\nexport type MemoryAdapter<S extends AnySchema> = Adapter<S> & {\n iterate<K extends keyof S>(table: K): AsyncIterable<RecordOf<S, K>>;\n};\n\nexport function createMemory<S extends AnySchema>(options: MemoryOptions<S>): MemoryAdapter<S> {\n const { codec = defaultCodec, logger, name, onMetrics, schema, signals, validators } = options;\n const tables = new Map(Object.keys(schema).map((k) => [k, new Map<string, StoredRecord<unknown>>()]));\n const getTableStore = (table: string) => tables.get(table)!;\n const isBroadcastMsg = makeBroadcastMsgGuard(codec);\n\n const channel =\n name !== undefined && typeof BroadcastChannel !== 'undefined'\n ? new BroadcastChannel(`vault-memory:${name}`)\n : undefined;\n\n const core: StorageBackend<S> = {\n async clear<K extends keyof S & string>(table: K): Promise<void> {\n getTableStore(table).clear();\n channel?.postMessage({ table, type: 'clear' });\n },\n\n async count<K extends keyof S & string>(table: K): Promise<number> {\n const store = getTableStore(table);\n let liveCount = 0;\n const expiredKeys: string[] = [];\n\n for (const [key, raw] of store) {\n const decoded = codec.decode<RecordOf<S, K>>(raw);\n\n if (!decoded || isExpired(decoded.expiresAt)) {\n expiredKeys.push(key);\n } else {\n liveCount += 1;\n }\n }\n\n for (const key of expiredKeys) store.delete(key);\n\n return liveCount;\n },\n\n async delete<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<boolean> {\n const store = getTableStore(table);\n const raw = store.get(String(key));\n\n if (!raw) return false;\n\n const decoded = codec.decode<RecordOf<S, K>>(raw);\n const isLive = decoded !== undefined && !isExpired(decoded.expiresAt);\n\n store.delete(String(key));\n\n if (isLive) channel?.postMessage({ key: String(key), table, type: 'delete' });\n\n return isLive;\n },\n\n async deleteMany<K extends keyof S & string>(table: K, keys: KeyOf<S, K>[]): Promise<number> {\n const store = getTableStore(table);\n const deletedKeys: string[] = [];\n\n for (const key of keys) {\n const strKey = String(key);\n const raw = store.get(strKey);\n\n if (raw) {\n const decoded = codec.decode<RecordOf<S, K>>(raw);\n\n if (decoded !== undefined && !isExpired(decoded.expiresAt)) deletedKeys.push(strKey);\n\n store.delete(strKey);\n }\n }\n\n if (deletedKeys.length > 0) channel?.postMessage({ keys: deletedKeys, table, type: 'deleteMany' });\n\n return deletedKeys.length;\n },\n\n dispose: channel ? async () => channel.close() : undefined,\n\n async get<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<RecordOf<S, K> | undefined> {\n const store = getTableStore(table);\n const raw = store.get(String(key));\n\n if (!raw) return undefined;\n\n const decoded = codec.decode<RecordOf<S, K>>(raw);\n\n if (!decoded || isExpired(decoded.expiresAt)) {\n store.delete(String(key));\n\n return undefined;\n }\n\n return decoded.value;\n },\n\n async getAll<K extends keyof S & string>(table: K): Promise<RecordOf<S, K>[]> {\n const store = getTableStore(table);\n const records: RecordOf<S, K>[] = [];\n const expiredKeys: string[] = [];\n\n for (const [key, raw] of store) {\n const decoded = codec.decode<RecordOf<S, K>>(raw);\n\n if (!decoded || isExpired(decoded.expiresAt)) {\n expiredKeys.push(key);\n } else {\n records.push(decoded.value);\n }\n }\n\n for (const key of expiredKeys) store.delete(key);\n\n return records;\n },\n\n async getRawCount<K extends keyof S & string>(table: K): Promise<number> {\n return getTableStore(table).size;\n },\n\n async has<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<boolean> {\n const store = getTableStore(table);\n const raw = store.get(String(key));\n\n if (!raw) return false;\n\n const decoded = codec.decode<RecordOf<S, K>>(raw);\n const live = decoded !== undefined && !isExpired(decoded.expiresAt);\n\n if (!live) store.delete(String(key));\n\n return live;\n },\n\n async pruneExpiredInTable<K extends keyof S & string>(table: K): Promise<number> {\n const store = getTableStore(table);\n let pruned = 0;\n\n for (const [key, raw] of store) {\n const decoded = codec.decode<RecordOf<S, K>>(raw);\n\n if (!decoded || isExpired(decoded.expiresAt)) {\n store.delete(key);\n pruned += 1;\n }\n }\n\n return pruned;\n },\n\n async put<K extends keyof S & string>(table: K, value: RecordOf<S, K>, ttl?: TtlMs): Promise<void> {\n const key = String(getRecordKey(schema, table, value));\n const expiresAt = ttl !== undefined ? Date.now() + ttl : undefined;\n const stored = codec.encode(value, expiresAt) as StoredRecord<unknown>;\n\n getTableStore(table).set(key, stored);\n channel?.postMessage({ key, stored, table, type: 'put' });\n },\n\n async putAll<K extends keyof S & string>(table: K, values: RecordOf<S, K>[], ttl?: TtlMs): Promise<void> {\n const store = getTableStore(table);\n const entries: Array<{ key: string; stored: StoredRecord<unknown> }> = [];\n const expiresAt = ttl !== undefined ? Date.now() + ttl : undefined;\n\n for (const value of values) {\n const key = String(getRecordKey(schema, table, value));\n const stored = codec.encode(value, expiresAt) as StoredRecord<unknown>;\n\n store.set(key, stored);\n entries.push({ key, stored });\n }\n\n if (entries.length > 0) channel?.postMessage({ entries, table, type: 'putAll' });\n },\n };\n\n const adapter = buildAdapterOps(schema, core, {\n logger,\n onCrossTabMessage: channel\n ? (notify) => {\n channel.onmessage = (event: MessageEvent<unknown>) => {\n let msg: MemoryBroadcastMsg;\n\n try {\n if (!isBroadcastMsg(event.data)) return;\n\n msg = event.data;\n } catch {\n return;\n }\n\n const store = tables.get(msg.table);\n\n if (!store) return;\n\n const validator = validators?.[msg.table as keyof S];\n\n const keyField = schema[msg.table as keyof S & string]?.key;\n\n const applyStoredWithValidation = (key: string, stored: StoredRecord<unknown>): boolean => {\n try {\n const parsed = codec.decode(stored as unknown);\n\n if (!parsed) return false;\n\n const rawValue = validator ? validator.parse(parsed.value) : parsed.value;\n\n // Security: verify the record's own primary key matches the broadcast envelope key.\n // Prevents a rogue same-origin sender from inserting records with mismatched keys.\n if (keyField && String((rawValue as Record<string, unknown>)[keyField]) !== key) return false;\n\n const validated: StoredRecord<unknown> =\n parsed.expiresAt !== undefined\n ? { expiresAt: parsed.expiresAt, value: rawValue }\n : { value: rawValue };\n\n store.set(key, validated);\n\n return true;\n } catch {\n return false;\n }\n };\n\n switch (msg.type) {\n case 'clear':\n store.clear();\n notify(msg.table as keyof S & string);\n\n return;\n case 'delete':\n store.delete(msg.key);\n notify(msg.table as keyof S & string);\n\n return;\n case 'deleteMany':\n for (const key of msg.keys) store.delete(key);\n notify(msg.table as keyof S & string);\n\n return;\n case 'put':\n if (applyStoredWithValidation(msg.key, msg.stored)) {\n notify(msg.table as keyof S & string);\n }\n\n return;\n case 'putAll':\n {\n let anyApplied = false;\n\n for (const { key, stored } of msg.entries) {\n if (applyStoredWithValidation(key, stored)) anyApplied = true;\n }\n\n if (anyApplied) notify(msg.table as keyof S & string);\n }\n\n return;\n }\n };\n\n return () => {\n channel.onmessage = null;\n };\n }\n : undefined,\n onMetrics,\n schema,\n signals,\n validators,\n });\n\n return {\n ...adapter,\n iterate<K extends keyof S>(table: K): AsyncIterable<RecordOf<S, K>> {\n const store = getTableStore(String(table));\n\n return {\n async *[Symbol.asyncIterator]() {\n if (adapter.disposed) throw new VaultDisposedError();\n\n const expiredKeys: string[] = [];\n\n for (const [key, raw] of store) {\n const decoded = codec.decode<RecordOf<S, K>>(raw);\n\n if (!decoded || isExpired(decoded.expiresAt)) {\n expiredKeys.push(key);\n } else {\n yield decoded.value;\n }\n }\n\n for (const key of expiredKeys) store.delete(key);\n },\n };\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { Adapter, AnySchema, BaseAdapterOptions, RecordOf } from '../types';
2
+ type MemoryOptions<S extends AnySchema> = BaseAdapterOptions<S> & {
3
+ /**
4
+ * When provided and BroadcastChannel is available, enables cross-tab state sync.
5
+ * All `createMemory` instances with the same `name` will replicate mutations to each other.
6
+ */
7
+ name?: string;
8
+ };
9
+ export type MemoryAdapter<S extends AnySchema> = Adapter<S> & {
10
+ iterate<K extends keyof S>(table: K): AsyncIterable<RecordOf<S, K>>;
11
+ };
12
+ export declare function createMemory<S extends AnySchema>(options: MemoryOptions<S>): MemoryAdapter<S>;
13
+ export {};
14
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/adapters/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAS,QAAQ,EAAS,MAAM,UAAU,CAAC;AAoD/F,KAAK,aAAa,CAAC,CAAC,SAAS,SAAS,IAAI,kBAAkB,CAAC,CAAC,CAAC,GAAG;IAChE;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,SAAS,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG;IAC5D,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;CACrE,CAAC;AAEF,wBAAgB,YAAY,CAAC,CAAC,SAAS,SAAS,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAwS7F"}