{"version":3,"file":"IndexedDBDriver.mjs","names":[],"sources":["../../../../../../../cache/src/drivers/IndexedDBDriver.ts"],"sourcesContent":["import { getCacheConfig } from \"../config\";\r\nimport {\r\n  CacheQuotaExceededError,\r\n  IndexedDBBlockedError,\r\n  IndexedDBUnavailableError,\r\n} from \"../errors\";\r\nimport {\r\n  CacheDriverInterface,\r\n  IndexedDBCacheRecord,\r\n  IndexedDBDriverOptions,\r\n} from \"../types\";\r\nimport isForbiddenKey from \"./isForbiddenKey\";\r\n\r\n/**\r\n * Defaults for the IndexedDB driver.\r\n *\r\n * Exported so a consumer can reuse the same database from their own\r\n * tooling (a \"clear all caches\" button, a devtools panel) without\r\n * hard-coding the strings.\r\n */\r\nexport const DEFAULT_INDEXED_DB_NAME = \"mongez-cache\";\r\nexport const DEFAULT_INDEXED_DB_STORE = \"cache\";\r\nexport const DEFAULT_INDEXED_DB_VERSION = 1;\r\n\r\n/**\r\n * IndexedDB cache driver — opt-in.\r\n *\r\n * Unlike the Web Storage drivers this one is never wired up for you:\r\n * opening a database is a side effect, and a package import should not\r\n * create one. Pass an instance explicitly:\r\n *\r\n * ```ts\r\n * setCacheConfigurations({ driver: new IndexedDBDriver() });\r\n * ```\r\n *\r\n * Storage layout: a single object store with out-of-line keys, where the\r\n * key is the (prefixed) cache key and the record is\r\n * `{ value, expiresAt }`. Values go through the structured clone\r\n * algorithm, so `Date`, `Map`, `Set`, `ArrayBuffer` and friends survive\r\n * a round-trip untouched — no JSON pass by default. Values that are not\r\n * cloneable (functions, class instances with methods, DOM nodes) are\r\n * rejected by the browser; give the driver a `setValueConverter` /\r\n * `setValueParser` pair if you need to serialize those yourself.\r\n *\r\n * Why IndexedDB is not the default: it is asynchronous, per-origin\r\n * quota'd, and unavailable during server-side rendering, while\r\n * localStorage is present in every browser context the other drivers\r\n * already support. Consumers who need more than the ~5MB Web Storage\r\n * budget, or structured values, opt in.\r\n */\r\nexport default class IndexedDBDriver implements CacheDriverInterface {\r\n  /**\r\n   * Prefix key\r\n   */\r\n  public prefixKey: string = \"\";\r\n\r\n  /**\r\n   * Database name\r\n   */\r\n  public readonly databaseName: string;\r\n\r\n  /**\r\n   * Object store name\r\n   */\r\n  public readonly storeName: string;\r\n\r\n  /**\r\n   * Database version\r\n   */\r\n  public readonly version: number;\r\n\r\n  /**\r\n   * Migration hook\r\n   */\r\n  protected readonly onUpgrade?: IndexedDBDriverOptions[\"onUpgrade\"];\r\n\r\n  /**\r\n   * The memoized open-database promise\r\n   *\r\n   * Every operation awaits this one promise, so N concurrent calls made\r\n   * before the database is open share a single `open()` request instead\r\n   * of racing each other into N connections.\r\n   */\r\n  protected connection?: Promise<IDBDatabase>;\r\n\r\n  /**\r\n   * Value parser\r\n   */\r\n  protected _valueParser = this.parseValue.bind(this);\r\n\r\n  /**\r\n   * Value converter\r\n   */\r\n  protected _valueConverter = this.convertValue.bind(this);\r\n\r\n  public constructor(options: IndexedDBDriverOptions = {}) {\r\n    this.databaseName = options.databaseName ?? DEFAULT_INDEXED_DB_NAME;\r\n    this.storeName = options.storeName ?? DEFAULT_INDEXED_DB_STORE;\r\n    this.version = options.version ?? DEFAULT_INDEXED_DB_VERSION;\r\n    this.onUpgrade = options.onUpgrade;\r\n  }\r\n\r\n  /**\r\n   * Determine whether the current runtime can use this driver\r\n   *\r\n   * Use it to pick a driver at bootstrap instead of catching the\r\n   * `IndexedDBUnavailableError` thrown by the first read.\r\n   */\r\n  public static isSupported(): boolean {\r\n    return (\r\n      typeof globalThis !== \"undefined\" &&\r\n      Boolean((globalThis as any).indexedDB)\r\n    );\r\n  }\r\n\r\n  /**\r\n   * Resolve the `indexedDB` factory or fail loudly\r\n   *\r\n   * Looked up lazily — at call time, never at import or construction\r\n   * time — so that a module that merely *mentions* this driver can be\r\n   * bundled into a server-rendered app without exploding on import.\r\n   */\r\n  protected factory(): IDBFactory {\r\n    const factory =\r\n      typeof globalThis !== \"undefined\"\r\n        ? ((globalThis as any).indexedDB as IDBFactory | undefined)\r\n        : undefined;\r\n\r\n    if (!factory) {\r\n      throw new IndexedDBUnavailableError();\r\n    }\r\n\r\n    return factory;\r\n  }\r\n\r\n  /**\r\n   * Open (once) and return the database connection\r\n   */\r\n  protected database(): Promise<IDBDatabase> {\r\n    if (this.connection) return this.connection;\r\n\r\n    const factory = this.factory();\r\n\r\n    const connection = new Promise<IDBDatabase>((resolve, reject) => {\r\n      const request = factory.open(this.databaseName, this.version);\r\n\r\n      request.onupgradeneeded = (event: IDBVersionChangeEvent) => {\r\n        const database = request.result;\r\n        const transaction = request.transaction as IDBTransaction;\r\n\r\n        // Created on first open, reused on every later version bump so\r\n        // that a migration keeps the existing entries.\r\n        const store = database.objectStoreNames.contains(this.storeName)\r\n          ? transaction.objectStore(this.storeName)\r\n          : database.createObjectStore(this.storeName);\r\n\r\n        this.onUpgrade?.({\r\n          database,\r\n          store,\r\n          transaction,\r\n          oldVersion: event.oldVersion,\r\n          newVersion: event.newVersion ?? this.version,\r\n        });\r\n      };\r\n\r\n      // Another tab still holds an older version open, so this upgrade\r\n      // can never run. Reject instead of hanging forever.\r\n      request.onblocked = () => {\r\n        reject(new IndexedDBBlockedError(this.databaseName));\r\n      };\r\n\r\n      request.onsuccess = () => {\r\n        const database = request.result;\r\n\r\n        // When another tab upgrades the schema, drop this connection so\r\n        // it does not block that upgrade; the next operation reopens.\r\n        database.onversionchange = () => {\r\n          database.close();\r\n          this.connection = undefined;\r\n        };\r\n\r\n        resolve(database);\r\n      };\r\n\r\n      request.onerror = () => reject(request.error);\r\n    });\r\n\r\n    // A failed open must not be memoized forever — a transient failure\r\n    // (a blocked upgrade that later clears) would otherwise poison the\r\n    // driver for the lifetime of the page.\r\n    this.connection = connection;\r\n    connection.catch(() => {\r\n      if (this.connection === connection) this.connection = undefined;\r\n    });\r\n\r\n    return connection;\r\n  }\r\n\r\n  /**\r\n   * Close the database connection\r\n   *\r\n   * The next operation reopens it. Mostly useful in tests and in code\r\n   * that deletes the database.\r\n   */\r\n  public async close(): Promise<this> {\r\n    const connection = this.connection;\r\n\r\n    this.connection = undefined;\r\n\r\n    if (!connection) return this;\r\n\r\n    try {\r\n      (await connection).close();\r\n    } catch (error) {\r\n      // Nothing to close — the open failed in the first place.\r\n    }\r\n\r\n    return this;\r\n  }\r\n\r\n  /**\r\n   * Run a single request against the object store\r\n   */\r\n  protected async request<T>(\r\n    mode: IDBTransactionMode,\r\n    run: (store: IDBObjectStore) => IDBRequest\r\n  ): Promise<T> {\r\n    const database = await this.database();\r\n\r\n    return new Promise<T>((resolve, reject) => {\r\n      let request: IDBRequest;\r\n\r\n      try {\r\n        const transaction = database.transaction(this.storeName, mode);\r\n        request = run(transaction.objectStore(this.storeName));\r\n      } catch (error) {\r\n        // Structured-clone failures and closed-database errors are\r\n        // thrown synchronously, not delivered as an error event.\r\n        return reject(error);\r\n      }\r\n\r\n      request.onsuccess = () => resolve(request.result as T);\r\n      request.onerror = () => reject(request.error);\r\n    });\r\n  }\r\n\r\n  /**\r\n   * Determine whether an error is the browser's out-of-quota signal\r\n   */\r\n  protected isQuotaError(error: any): boolean {\r\n    if (!error) return false;\r\n\r\n    return (\r\n      error.name === \"QuotaExceededError\" ||\r\n      // Firefox's historical name for the same condition.\r\n      error.name === \"NS_ERROR_DOM_QUOTA_REACHED\" ||\r\n      error.code === 22\r\n    );\r\n  }\r\n\r\n  /**\r\n   * Parse a stored value\r\n   *\r\n   * Identity by default: IndexedDB stores structured clones, so there\r\n   * is nothing to decode.\r\n   */\r\n  protected parseValue(value: any) {\r\n    return value;\r\n  }\r\n\r\n  /**\r\n   * Convert a value before storing it\r\n   */\r\n  protected convertValue(value: any) {\r\n    return value;\r\n  }\r\n\r\n  /**\r\n   * Set value parser\r\n   */\r\n  public setValueParser(parser: any) {\r\n    this._valueParser = parser;\r\n    return this;\r\n  }\r\n\r\n  /**\r\n   * Set value converter\r\n   */\r\n  public setValueConverter(converter: any) {\r\n    this._valueConverter = converter;\r\n    return this;\r\n  }\r\n\r\n  /**\r\n   * Get a proper key\r\n   */\r\n  public getKey(key: string): string {\r\n    return (this.getPrefixKey() || \"\") + key;\r\n  }\r\n\r\n  /**\r\n   * Get prefix key\r\n   */\r\n  public getPrefixKey(): string {\r\n    return this.prefixKey;\r\n  }\r\n\r\n  /**\r\n   * Set prefix key\r\n   */\r\n  public setPrefixKey(key: string) {\r\n    this.prefixKey = key;\r\n    return this;\r\n  }\r\n\r\n  /**\r\n   * Compute the absolute expiry timestamp for a write\r\n   */\r\n  protected expiryOf(expiresAfter?: number): number | undefined {\r\n    const expireTime: number | false =\r\n      expiresAfter !== undefined\r\n        ? expiresAfter\r\n        : ((getCacheConfig(\"expiresAfter\") || 0) as number);\r\n\r\n    return expireTime ? new Date().getTime() + expireTime * 1000 : undefined;\r\n  }\r\n\r\n  /**\r\n   * Read the raw record stored under a cache key\r\n   */\r\n  protected async record(\r\n    key: string\r\n  ): Promise<IndexedDBCacheRecord | undefined> {\r\n    return this.request<IndexedDBCacheRecord | undefined>(\r\n      \"readonly\",\r\n      store => store.get(this.getKey(key))\r\n    );\r\n  }\r\n\r\n  /**\r\n   * Determine whether a record is past its expiry\r\n   */\r\n  protected isExpired(record: IndexedDBCacheRecord): boolean {\r\n    return Boolean(record.expiresAt && record.expiresAt < new Date().getTime());\r\n  }\r\n\r\n  /**\r\n   * Get value from cache engine, if key does not exist return default value\r\n   */\r\n  public async get(key: string, defaultValue: any = null) {\r\n    const record = await this.record(key);\r\n\r\n    if (record === undefined || record === null) return defaultValue;\r\n\r\n    // Same TTL model as the other drivers: expiry is enforced on read,\r\n    // and the dead entry is dropped rather than left to rot.\r\n    if (this.isExpired(record)) {\r\n      await this.remove(key);\r\n      return defaultValue;\r\n    }\r\n\r\n    return this._valueParser(record.value);\r\n  }\r\n\r\n  /**\r\n   * Set cache into storage\r\n   */\r\n  public async set(key: string, value: any, expiresAfter?: number) {\r\n    const record: IndexedDBCacheRecord = {\r\n      value: this._valueConverter(value),\r\n      expiresAt: this.expiryOf(expiresAfter),\r\n    };\r\n\r\n    try {\r\n      await this.request(\"readwrite\", store =>\r\n        store.put(record, this.getKey(key))\r\n      );\r\n    } catch (error) {\r\n      if (this.isQuotaError(error)) {\r\n        throw new CacheQuotaExceededError(key, error);\r\n      }\r\n\r\n      throw error;\r\n    }\r\n\r\n    return this;\r\n  }\r\n\r\n  /**\r\n   * Determine whether the cache engine has a live entry for the key\r\n   */\r\n  public async has(key: string): Promise<boolean> {\r\n    const record = await this.record(key);\r\n\r\n    if (record === undefined || record === null) return false;\r\n\r\n    if (this.isExpired(record)) {\r\n      await this.remove(key);\r\n      return false;\r\n    }\r\n\r\n    return true;\r\n  }\r\n\r\n  /**\r\n   * Remove the given key from the cache storage\r\n   */\r\n  public async remove(key: string) {\r\n    await this.request(\"readwrite\", store => store.delete(this.getKey(key)));\r\n\r\n    return this;\r\n  }\r\n\r\n  /**\r\n   * List every key held in the object store\r\n   */\r\n  protected async storageKeys(): Promise<string[]> {\r\n    const keys = await this.request<IDBValidKey[]>(\"readonly\", store =>\r\n      store.getAllKeys()\r\n    );\r\n\r\n    return keys.map(key => String(key));\r\n  }\r\n\r\n  /**\r\n   * List the caller-facing keys owned by this engine\r\n   */\r\n  public async keys(): Promise<string[]> {\r\n    const prefix = this.getPrefixKey();\r\n    const keys = await this.storageKeys();\r\n\r\n    if (!prefix) return keys;\r\n\r\n    return keys\r\n      .filter(key => key.startsWith(prefix))\r\n      .map(key => key.slice(prefix.length));\r\n  }\r\n\r\n  /**\r\n   * Read every live entry owned by this engine in one transaction\r\n   *\r\n   * The returned object has a null prototype and every key is defined\r\n   * as an own property, so a cache key of `__proto__`, `constructor` or\r\n   * `prototype` — which any script sharing the origin can write into\r\n   * the database — lands as plain data instead of reaching a prototype\r\n   * setter and polluting every object in the runtime.\r\n   */\r\n  public async getAll(): Promise<Record<string, any>> {\r\n    const prefix = this.getPrefixKey();\r\n    const entries: Record<string, any> = Object.create(null);\r\n\r\n    await this.eachRecord((key, record) => {\r\n      if (prefix && !key.startsWith(prefix)) return;\r\n      if (this.isExpired(record)) return;\r\n\r\n      const cacheKey = prefix ? key.slice(prefix.length) : key;\r\n      const value = this._valueParser(record.value);\r\n\r\n      if (isForbiddenKey(cacheKey)) {\r\n        // Belt and braces: a plain assignment is already safe on a\r\n        // null-prototype object, but `defineProperty` cannot ever hit\r\n        // an inherited setter even if this object gains a prototype.\r\n        Object.defineProperty(entries, cacheKey, {\r\n          value,\r\n          writable: true,\r\n          enumerable: true,\r\n          configurable: true,\r\n        });\r\n\r\n        return;\r\n      }\r\n\r\n      entries[cacheKey] = value;\r\n    });\r\n\r\n    return entries;\r\n  }\r\n\r\n  /**\r\n   * Walk every record in the store inside a single transaction\r\n   */\r\n  protected async eachRecord(\r\n    handle: (key: string, record: IndexedDBCacheRecord) => void\r\n  ): Promise<void> {\r\n    const database = await this.database();\r\n\r\n    return new Promise<void>((resolve, reject) => {\r\n      let transaction: IDBTransaction;\r\n\r\n      try {\r\n        transaction = database.transaction(this.storeName, \"readonly\");\r\n      } catch (error) {\r\n        return reject(error);\r\n      }\r\n\r\n      const request = transaction.objectStore(this.storeName).openCursor();\r\n\r\n      request.onsuccess = () => {\r\n        const cursor = request.result;\r\n\r\n        if (!cursor) return;\r\n\r\n        handle(String(cursor.key), cursor.value as IndexedDBCacheRecord);\r\n        cursor.continue();\r\n      };\r\n\r\n      request.onerror = () => reject(request.error);\r\n      transaction.oncomplete = () => resolve();\r\n      transaction.onabort = () => reject(transaction.error);\r\n      transaction.onerror = () => reject(transaction.error);\r\n    });\r\n  }\r\n\r\n  /**\r\n   * Clear the cache storage\r\n   *\r\n   * Prefix-scoped exactly like the Web Storage engines: the cache\r\n   * database is shared by every driver instance pointed at it, so an\r\n   * app that namespaced its keys must not wipe its neighbour's. With no\r\n   * prefix the engine owns the whole store and clears it.\r\n   */\r\n  public async clear() {\r\n    const prefix = this.getPrefixKey();\r\n\r\n    if (!prefix) {\r\n      await this.request(\"readwrite\", store => store.clear());\r\n\r\n      return this;\r\n    }\r\n\r\n    const database = await this.database();\r\n\r\n    await new Promise<void>((resolve, reject) => {\r\n      let transaction: IDBTransaction;\r\n\r\n      try {\r\n        transaction = database.transaction(this.storeName, \"readwrite\");\r\n      } catch (error) {\r\n        return reject(error);\r\n      }\r\n\r\n      // A cursor keeps the deletions inside one transaction: issuing\r\n      // them one promise at a time would let the transaction commit\r\n      // between deletes and leave a half-cleared namespace behind.\r\n      const request = transaction.objectStore(this.storeName).openCursor();\r\n\r\n      request.onsuccess = () => {\r\n        const cursor = request.result;\r\n\r\n        if (!cursor) return;\r\n\r\n        if (String(cursor.key).startsWith(prefix)) {\r\n          cursor.delete();\r\n        }\r\n\r\n        cursor.continue();\r\n      };\r\n\r\n      request.onerror = () => reject(request.error);\r\n      transaction.oncomplete = () => resolve();\r\n      transaction.onabort = () => reject(transaction.error);\r\n      transaction.onerror = () => reject(transaction.error);\r\n    });\r\n\r\n    return this;\r\n  }\r\n}\r\n"],"mappings":"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"}