@ngx-pwa/local-storage
Version:
Efficient local storage module for Angular: simple API based on native localStorage API, but internally stored via the asynchronous IndexedDB API for performance, and wrapped in RxJS observables to be homogeneous with other Angular modules.
1 lines • 88.5 kB
Source Map (JSON)
{"version":3,"file":"ngx-pwa-local-storage.mjs","sources":["../../../lib/src/lib/databases/exceptions.ts","../../../lib/src/lib/tokens.ts","../../../lib/src/lib/providers.ts","../../../lib/src/lib/storage.module.ts","../../../lib/src/lib/storages/exceptions.ts","../../../lib/src/lib/databases/localstorage-database.ts","../../../lib/src/lib/databases/memory-database.ts","../../../lib/src/lib/databases/local-database.ts","../../../lib/src/lib/databases/indexeddb-database.ts","../../../lib/src/lib/validation/json-validator.ts","../../../lib/src/lib/storages/storage-map.ts","../../../lib/src/public-api.ts","../../../lib/src/ngx-pwa-local-storage.ts"],"sourcesContent":["/**\n * Exception message when `indexedDB` is not working\n */\nexport const IDB_BROKEN_ERROR = \"indexedDB is not working\";\n\n/**\n * Exception raised when `indexedDB` is not working\n */\nexport class IDBBrokenError extends Error {\n override message: string = IDB_BROKEN_ERROR;\n}\n\n/**\n * Exception message when a value cannot be serialized for `localStorage`\n */\nexport const SERIALIZATION_ERROR = `The storage is currently localStorage,\nwhere data must be serialized, and the provided data can't be serialized.`;\n\n/**\n * Exception throwned when a value cannot be serialized for `localStorage`\n */\nexport class SerializationError extends Error {\n override message: string = SERIALIZATION_ERROR;\n}\n","import { InjectionToken } from \"@angular/core\";\n\n/**\n * Token to provide a prefix to `localStorage` keys.\n */\nexport const LS_PREFIX: InjectionToken<string> = new InjectionToken<string>(\"localStoragePrefix\", {\n providedIn: \"root\",\n factory: (): string => \"\"\n});\n\n/**\n * Default name used for `indexedDB` database.\n */\nexport const DEFAULT_IDB_DB_NAME = \"ngStorage\";\n\n/**\n * Token to provide `indexedDB` database name.\n */\nexport const IDB_DB_NAME: InjectionToken<string> = new InjectionToken<string>(\"localStorageIDBDBName\", {\n providedIn: \"root\",\n factory: (): string => DEFAULT_IDB_DB_NAME\n});\n\n/**\n * Default version used for `indexedDB` database.\n */\nexport const DEFAULT_IDB_DB_VERSION = 1;\n\n/**\n * Token to provide `indexedDB` database version.\n * Must be an unsigned **integer**.\n */\nexport const IDB_DB_VERSION: InjectionToken<number> = new InjectionToken<number>(\"localStorageIDBDBVersion\", {\n providedIn: \"root\",\n factory: (): number => DEFAULT_IDB_DB_VERSION\n});\n\n/**\n * Default name used for `indexedDB` object store.\n */\nexport const DEFAULT_IDB_STORE_NAME = \"localStorage\";\n\n/**\n * Token to provide `indexedDB` store name.\n * For backward compatibility, the default can't be set now, `IndexedDBDatabase` will do it at runtime.\n */\nexport const IDB_STORE_NAME: InjectionToken<string> = new InjectionToken<string>(\"localStorageIDBStoreName\", {\n providedIn: \"root\",\n factory: (): string => DEFAULT_IDB_STORE_NAME\n});\n\n/**\n * Default value for interoperability with native `indexedDB` and other storage libs,\n * by changing how values are stored in `indexedDB` database.\n */\nexport const DEFAULT_IDB_NO_WRAP = true;\n\n/**\n * Token to allow interoperability with native `indexedDB` and other storage libs,\n * by changing how values are stored in `indexedDB` database.\n * Defaults to `true`. Change to `false` for backward compatiblity in existing applications.\n * **DO NOT CHANGE THIS BEHAVIOR ONCE IN PRODUCTION**, as it would break with existing data.\n */\nexport const IDB_NO_WRAP: InjectionToken<boolean> = new InjectionToken<boolean>(\"localStorageIDBWrap\", {\n providedIn: \"root\",\n factory: (): boolean => DEFAULT_IDB_NO_WRAP\n});\n\n/**\n * This interface is only here for backward compatibility, **do not add it by yourself**\n * \n * @ignore\n */\nexport interface StorageConfig {\n\n /**\n * @deprecated Use `provideLocalStoragePrefix()` method instead\n */\n LSPrefix?: string;\n\n /**\n * @deprecated Use `provideIndexedDBDataBaseName()` method instead\n */\n IDBDBName?: string;\n\n /**\n * @deprecated Use `provideIndexedDBStoreName()` method instead\n */\n IDBStoreName?: string;\n\n /**\n * @deprecated Use `provideIndexedDBDataBaseVersion()` method instead\n */\n IDBDBVersion?: number;\n\n /**\n * Allows interoperability with native `indexedDB` and other storage libs,\n * by changing how values are stored in `indexedDB` database.\n * \n * Defaults to `true`. Change to `false` for backward compatiblity in existing applications.\n * \n * **DO NOT CHANGE THIS BEHAVIOR ONCE IN PRODUCTION**, as it would break with existing data.\n */\n IDBNoWrap?: boolean;\n\n}\n","import { makeEnvironmentProviders, type EnvironmentProviders } from \"@angular/core\";\nimport { IDB_DB_NAME, IDB_DB_VERSION, IDB_STORE_NAME, LS_PREFIX } from \"./tokens\";\n\n/**\n * Allows to add a prefix before `localStorage` keys.\n * \n * *Use only* for interoperability with other APIs or to avoid collision for multiple applications on the same subdomain.\n * \n * **WARNING: do not change this option in an application already deployed in production, as previously stored data would be lost.**\n *\n * @example\n * export const appConfig: ApplicationConfig = {\n * providers: [provideLocalStoragePrefix('custom_')]\n * };\n */\nexport function provideLocalStoragePrefix(prefix: string): EnvironmentProviders {\n\n return makeEnvironmentProviders([{ provide: LS_PREFIX, useValue: prefix }]);\n\n}\n\n/**\n * Allows to change the name used for `indexedDB` database.\n * \n * *Use only* for interoperability with other APIs or to avoid collision for multiple applications on the same subdomain.\n * \n * **WARNING: do not change this option in an application already deployed in production, as previously stored data would be lost.**\n *\n * @example\n * export const appConfig: ApplicationConfig = {\n * providers: [provideIndexedDBDataBaseName('custom')]\n * };\n */\nexport function provideIndexedDBDataBaseName(name: string): EnvironmentProviders {\n\n return makeEnvironmentProviders([{ provide: IDB_DB_NAME, useValue: name }]);\n\n}\n\n/**\n * Allows to change the database version used for `indexedDB` database.\n * Must be an unsigned **integer**.\n * \n * **Use with caution as the creation of the store depends on the version.**\n * \n * *Use only* for interoperability with other APIs or to avoid collision for multiple applications on the same subdomain.\n * \n * **WARNING: do not change this option in an applicattion already deployed in production, as previously stored data would be lost.**\n *\n * @example\n * export const appConfig: ApplicationConfig = {\n * providers: [provideIndexedDBDataBaseVersion(2)]\n * };\n */\nexport function provideIndexedDBDataBaseVersion(version: number): EnvironmentProviders {\n\n return makeEnvironmentProviders([{ provide: IDB_DB_VERSION, useValue: version }]);\n\n}\n\n/**\n * Allows to change the name used for `indexedDB` object store.\n * \n * *Use only* for interoperability with other APIs.\n * \n * **WARNING: do not change this option in an application already deployed in production, as previously stored data would be lost.**\n *\n * @example\n * export const appConfig: ApplicationConfig = {\n * providers: [provideIndexedDBStoreName('custom')]\n * };\n */\nexport function provideIndexedDBStoreName(name: string): EnvironmentProviders {\n\n return makeEnvironmentProviders([{ provide: IDB_STORE_NAME, useValue: name }]);\n\n}\n","import { NgModule, type ModuleWithProviders } from \"@angular/core\";\nimport { IDB_DB_NAME, IDB_DB_VERSION, IDB_NO_WRAP, IDB_STORE_NAME, LS_PREFIX, type StorageConfig } from \"./tokens\";\n\n/**\n * This module is only here for backward compatibility, **do not add it by yourself**\n * \n * @ignore\n */\n@NgModule()\nexport class StorageModule {\n\n /**\n * Only useful to provide options, otherwise it does nothing.\n * \n * **Must be used at initialization, ie. in `AppModule`, and must not be loaded again in another module.**\n */\n static forRoot(config: StorageConfig): ModuleWithProviders<StorageModule> {\n return {\n ngModule: StorageModule,\n providers: [\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n config.LSPrefix !== undefined ? { provide: LS_PREFIX, useValue: config.LSPrefix } : [],\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n config.IDBDBName !== undefined ? { provide: IDB_DB_NAME, useValue: config.IDBDBName } : [],\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n config.IDBStoreName !== undefined ? { provide: IDB_STORE_NAME, useValue: config.IDBStoreName } : [],\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n config.IDBDBVersion !== undefined ? { provide: IDB_DB_VERSION, useValue: config.IDBDBVersion } : [],\n (config.IDBNoWrap === false) ? { provide: IDB_NO_WRAP, useValue: config.IDBNoWrap } : [],\n ],\n };\n }\n\n}\n","/**\n * Exception message when a value is not valid against the JSON schema\n */\nexport const VALIDATION_ERROR = `Data stored is not valid against the provided JSON schema.\nCheck your JSON schema, otherwise it means data has been corrupted.`;\n\n/**\n * Exception throwned when a value is not valid against the JSON schema\n */\nexport class ValidationError extends Error {\n override message: string = VALIDATION_ERROR;\n}\n","import { Injectable, inject } from \"@angular/core\";\nimport { Observable, asyncScheduler, of, throwError } from \"rxjs\";\nimport { observeOn } from \"rxjs/operators\";\nimport { LS_PREFIX } from \"../tokens\";\nimport { SerializationError } from \"./exceptions\";\nimport { LocalDatabase } from \"./local-database\";\n\n@Injectable({\n providedIn: \"root\"\n})\nexport class LocalStorageDatabase implements LocalDatabase {\n\n /**\n * Optional user prefix to avoid collision for multiple apps on the same subdomain\n */\n readonly prefix: string;\n\n constructor() {\n\n /* Prefix if asked, or no prefix otherwise */\n this.prefix = inject(LS_PREFIX);\n\n }\n\n /**\n * Number of items in `localStorage`\n */\n get size(): Observable<number> {\n\n /* Wrap in a RxJS `Observable` to be consistent with other storages */\n return of(localStorage.length);\n\n }\n\n /**\n * Gets an item value in `localStorage`\n * @param key The item's key\n * @returns The item's value if the key exists, `undefined` otherwise, wrapped in a RxJS `Observable`\n */\n get(key: string): Observable<unknown> {\n\n /* Get raw data */\n const unparsedData = localStorage.getItem(this.prefixKey(key));\n\n /* No need to parse if data is `null` or `undefined` */\n if (unparsedData !== null) {\n\n /* Try to parse */\n try {\n\n const parsedData: unknown = JSON.parse(unparsedData);\n\n /* Wrap in a RxJS `Observable` to be consistent with other storages */\n return of(parsedData);\n\n } catch (error) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n return throwError(() => error as SyntaxError);\n }\n\n }\n\n return of(undefined);\n\n }\n\n /**\n * Store an item in `localStorage`\n * @param key The item's key\n * @param data The item's value\n * @returns A RxJS `Observable` to wait the end of the operation\n */\n set(key: string, data: object): Observable<undefined> {\n\n let serializedData: StringifyResult<object> | null = null;\n\n /* Check if data can be serialized */\n const dataPrototype = Object.getPrototypeOf(data);\n if ((typeof data === \"object\") && !Array.isArray(data) &&\n !((dataPrototype === Object.prototype) || (dataPrototype === null))) {\n return throwError(() => new SerializationError());\n }\n\n /* Try to stringify (can fail on circular references) */\n try {\n serializedData = JSON.stringify(data);\n if (serializedData === undefined) {\n throw new Error();\n }\n } catch (error) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n return throwError(() => error as TypeError);\n }\n\n /* Can fail if storage quota is exceeded */\n try {\n localStorage.setItem(this.prefixKey(key), serializedData);\n } catch (error) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n return throwError(() => error as DOMException);\n }\n\n /* Wrap in a RxJS `Observable` to be consistent with other storages */\n return of(undefined);\n\n }\n\n /**\n * Deletes an item in `localStorage`\n * @param key The item's key\n * @returns A RxJS `Observable` to wait the end of the operation\n */\n delete(key: string): Observable<undefined> {\n\n localStorage.removeItem(this.prefixKey(key));\n\n /* Wrap in a RxJS `Observable` to be consistent with other storages */\n return of(undefined);\n\n }\n\n /**\n * Deletes all items in `localStorage`\n * @returns A RxJS `Observable` to wait the end of the operation\n */\n clear(): Observable<undefined> {\n\n localStorage.clear();\n\n /* Wrap in a RxJS `Observable` to be consistent with other storages */\n return of(undefined);\n\n }\n\n /**\n * Get all keys in `localStorage`\n * Note the order of the keys may be inconsistent in Firefox\n * @returns A RxJS `Observable` iterating on keys\n */\n keys(): Observable<string> {\n\n /* Create an `Observable` from keys */\n return new Observable<string>((subscriber) => {\n\n /* Iteretate over all the indexes */\n for (let index = 0; index < localStorage.length; index += 1) {\n\n /* Cast as we are sure in this case the key is not `null` */\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Ensured by the logic\n subscriber.next(this.getUnprefixedKey(index)!);\n\n }\n\n subscriber.complete();\n\n }).pipe(\n /* Required to work like other databases which are asynchronous */\n observeOn(asyncScheduler),\n );\n\n }\n\n /**\n * Check if a key exists in `localStorage`\n * @param key The item's key\n * @returns A RxJS `Observable` telling if the key exists or not\n */\n has(key: string): Observable<boolean> {\n\n /* Itérate over all indexes in storage */\n for (let index = 0; index < localStorage.length; index += 1) {\n\n if (key === this.getUnprefixedKey(index)) {\n\n /* Wrap in a RxJS `Observable` to be consistent with other storages */\n return of(true);\n\n }\n\n }\n\n /* Wrap in a RxJS `Observable` to be consistent with other storages */\n return of(false);\n\n }\n\n /**\n * Get an unprefixed key\n * @param index Index of the key\n * @returns The unprefixed key name if exists, `null` otherwise\n */\n private getUnprefixedKey(index: number): string | null {\n\n /* Get the key in storage: may have a prefix */\n const prefixedKey = localStorage.key(index);\n\n if (prefixedKey !== null) {\n\n /* If no prefix, the key is already good, otherwrite strip the prefix */\n return this.prefix === \"\" ? prefixedKey : prefixedKey.substring(this.prefix.length);\n\n }\n\n return null;\n\n }\n\n /**\n * Add the prefix to a key\n * @param key The key name\n * @returns The prefixed key name\n */\n private prefixKey(key: string): string {\n\n return `${this.prefix}${key}`;\n\n }\n\n}\n","import { Injectable } from \"@angular/core\";\nimport { Observable, from, of } from \"rxjs\";\nimport { LocalDatabase } from \"./local-database\";\n\n@Injectable({\n providedIn: \"root\"\n})\nexport class MemoryDatabase implements LocalDatabase {\n\n /**\n * Memory storage\n */\n private readonly memoryStorage = new Map<string, unknown>();\n\n /**\n * Number of items in memory\n */\n get size(): Observable<number> {\n\n /* Wrap in a RxJS `Observable` to be consistent with other storages */\n return of(this.memoryStorage.size);\n\n }\n\n /**\n * Gets an item value in memory\n * @param key The item's key\n * @returns The item's value if the key exists, `undefined` otherwise, wrapped in a RxJS `Observable`\n */\n get(key: string): Observable<unknown> {\n\n /* Wrap in a RxJS `Observable` to be consistent with other storages */\n return of(this.memoryStorage.get(key));\n\n }\n\n /**\n * Sets an item in memory\n * @param key The item's key\n * @param data The item's value\n * @returns A RxJS `Observable` to wait the end of the operation\n */\n set(key: string, data: unknown): Observable<undefined> {\n\n this.memoryStorage.set(key, data);\n\n /* Wrap in a RxJS `Observable` to be consistent with other storages */\n return of(undefined);\n\n }\n\n /**\n * Deletes an item in memory\n * @param key The item's key\n * @returns A RxJS `Observable` to wait the end of the operation\n */\n delete(key: string): Observable<undefined> {\n\n this.memoryStorage.delete(key);\n\n /* Wrap in a RxJS `Observable` to be consistent with other storages */\n return of(undefined);\n\n }\n\n /**\n * Deletes all items in memory\n * @returns A RxJS `Observable` to wait the end of the operation\n */\n clear(): Observable<undefined> {\n\n this.memoryStorage.clear();\n\n /* Wrap in a RxJS `Observable` to be consistent with other storages */\n return of(undefined);\n\n }\n\n /**\n * Get all keys in memory\n * @returns A RxJS `Observable` iterating on keys\n */\n keys(): Observable<string> {\n\n /* Create an `Observable` from keys */\n return from(this.memoryStorage.keys());\n\n }\n\n /**\n * Check if a key exists in memory\n * @param key Key name\n * @returns a RxJS `Observable` telling if the key exists or not\n */\n has(key: string): Observable<boolean> {\n\n /* Wrap in a RxJS `Observable` to be consistent with other storages */\n return of(this.memoryStorage.has(key));\n\n }\n\n}\n","import { isPlatformBrowser } from \"@angular/common\";\nimport { inject, Injectable, PLATFORM_ID } from \"@angular/core\";\nimport { Observable } from \"rxjs\";\nimport { IndexedDBDatabase } from \"./indexeddb-database\";\nimport { LocalStorageDatabase } from \"./localstorage-database\";\nimport { MemoryDatabase } from \"./memory-database\";\n\n/**\n * Factory to create a storage according to browser support\n * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/BROWSERS_SUPPORT.md}\n */\nexport function localDatabaseFactory(): LocalDatabase {\n\n const platformId = inject(PLATFORM_ID);\n\n /* When storage is fully disabled in browser (via the \"Block all cookies\" option),\n * just trying to check `indexedDB` or `localStorage` variables causes a security exception.\n * Prevents https://github.com/cyrilletuzi/angular-async-local-storage/issues/118\n */\n try {\n\n // Do not explicit `window` here, as the global object is not the same in web workers\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- They can be undefined in some browsers scenarios\n if (isPlatformBrowser(platformId) && (indexedDB !== undefined) && (indexedDB !== null) && (\"open\" in indexedDB)) {\n\n /* Check:\n * - if we are in a browser context (issue: server-side rendering)\n * - it could exist but be `undefined` or `null`\n * - it could exists but not having a working API\n * Will be the case for:\n * - All other browsers in normal mode\n * - Chromium / Safari / Firefox private mode, but in this case, data will be swiped when the user leaves the app */\n return new IndexedDBDatabase();\n\n } else if (isPlatformBrowser(platformId)\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- They can be undefined in some browsers scenarios\n && (localStorage !== undefined) && (localStorage !== null) && (\"getItem\" in localStorage)) {\n\n /* Check:\n * - if we are in a browser context (issue: server-side rendering)\n * - if `localStorage` exists (to be sure)\n * - it could exists but not having a working API\n * Will be the case for:\n * - Safari cross-origin iframes, detected later in `IndexedDBDatabase.connect()`\n * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/issues/42}\n */\n return new LocalStorageDatabase();\n\n }\n\n } catch {\n // Nothing to do\n }\n\n /* Will be the case for:\n * - In browsers if storage has been fully disabled (via the \"Block all cookies\" option)\n * - Server-side rendering\n * - All other non-browser context\n */\n return new MemoryDatabase();\n\n}\n\n@Injectable({\n providedIn: \"root\",\n useFactory: localDatabaseFactory,\n})\nexport abstract class LocalDatabase {\n\n abstract readonly size: Observable<number>;\n\n abstract get(key: string): Observable<unknown>;\n abstract set(key: string, data: unknown): Observable<undefined>;\n abstract delete(key: string): Observable<undefined>;\n abstract clear(): Observable<undefined>;\n abstract keys(): Observable<string>;\n abstract has(key: string): Observable<boolean>;\n\n}\n","import { Injectable, inject } from \"@angular/core\";\nimport { Observable, ReplaySubject, fromEvent, of, race, throwError } from \"rxjs\";\nimport { first, map, mergeMap, takeWhile, tap } from \"rxjs/operators\";\nimport { IDB_DB_NAME, IDB_DB_VERSION, IDB_NO_WRAP, IDB_STORE_NAME } from \"../tokens\";\nimport { IDBBrokenError } from \"./exceptions\";\nimport { LocalDatabase } from \"./local-database\";\n\n@Injectable({\n providedIn: \"root\"\n})\nexport class IndexedDBDatabase implements LocalDatabase {\n\n /**\n * `indexedDB` database name\n */\n private readonly dbName: string;\n\n /**\n * `indexedDB` object store name\n */\n private readonly storeName: string;\n\n /**\n * `indexedDB` database version. Must be an unsigned **integer**\n */\n private readonly dbVersion: number;\n\n /**\n * `indexedDB` database connection, wrapped in a RxJS `ReplaySubject` to be able to access the connection\n * even after the connection success event happened\n */\n private readonly database = new ReplaySubject<IDBDatabase>(1);\n\n /**\n * Flag to not wrap `indexedDB` values for interoperability or to wrap for backward compatibility.\n */\n private readonly noWrap: boolean;\n\n /**\n * Index used when wrapping value. *For backward compatibility only.*\n */\n private readonly wrapIndex = \"value\";\n\n constructor() {\n\n this.dbName = inject(IDB_DB_NAME);\n this.storeName = inject(IDB_STORE_NAME);\n this.dbVersion = inject(IDB_DB_VERSION);\n this.noWrap = inject(IDB_NO_WRAP);\n\n /* Connect to `indexedDB`, with prefix if provided by the user */\n this.connect();\n\n }\n\n /**\n * Information about `indexedDB` connection. *Only useful for interoperability.*\n * @returns `indexedDB` database name, store name and database version\n */\n get backingStore(): { database: string, store: string, version: number; } {\n\n return {\n database: this.dbName,\n store: this.storeName,\n version: this.dbVersion,\n };\n\n }\n\n /**\n * Number of items in our `indexedDB` database and object store\n */\n get size(): Observable<number> {\n\n /* Open a transaction in read-only mode */\n return this.transaction(\"readonly\").pipe(\n mergeMap((transactionData) => {\n\n const { store, events } = transactionData;\n\n /* Request to know the number of items */\n const request = store.count();\n\n /* Return the result */\n return events.pipe(map(() => request.result));\n\n }),\n /* The observable will complete after the first value */\n first(),\n );\n\n }\n\n /**\n * Gets an item value in our `indexedDB` store\n * @param key The item's key\n * @returns The item's value if the key exists, `undefined` otherwise, wrapped in an RxJS `Observable`\n */\n get(key: string): Observable<unknown> {\n\n /* Open a transaction in read-only mode */\n return this.transaction(\"readonly\").pipe(\n mergeMap((transactionData) => {\n\n const { store, events } = transactionData;\n\n /* Request the value with the key provided by the user */\n const request = store.get(key);\n\n /* Listen events and return the result */\n return events.pipe(map((): unknown => {\n\n if ((request.result !== undefined) && (request.result !== null)) {\n\n /* Prior to v8, the value was wrapped in an `{ value: ...}` object */\n if (!this.noWrap && (typeof request.result === \"object\") && (this.wrapIndex in request.result) &&\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- Required by indexedDb behavior\n (request.result[this.wrapIndex] !== undefined) && (request.result[this.wrapIndex] !== null)) {\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- Required by indexedDb behavior\n return request.result[this.wrapIndex];\n\n } else {\n\n /* Cast to the wanted type */\n return request.result;\n\n }\n\n }\n\n /* Return `undefined` if the value is empty */\n return undefined;\n\n }));\n\n }),\n /* The observable will complete after the first value */\n first(),\n );\n\n }\n\n /**\n * Sets an item in our `indexedDB` store\n * @param key The item's key\n * @param data The item's value\n * @returns An RxJS `Observable` to wait the end of the operation\n */\n set(key: string, data: unknown): Observable<undefined> {\n\n /* Storing `undefined` in `indexedDb` can cause issues in some browsers so removing item instead */\n if (data === undefined) {\n return this.delete(key);\n }\n\n /* Open a transaction in write mode */\n return this.transaction(\"readwrite\").pipe(\n mergeMap((transactionData) => {\n\n const { store, events } = transactionData;\n\n /* Prior to v8, data was wrapped in a `{ value: ... }` object */\n const dataToStore = this.noWrap ? data : { [this.wrapIndex]: data };\n\n /* Add if the item is not existing yet, or update otherwise */\n store.put(dataToStore, key);\n\n /* Listen to events and return `undefined` as no value is expected */\n return events.pipe(map(() => undefined));\n\n }),\n /* The observable will complete after the first value */\n first(),\n );\n\n }\n\n /**\n * Deletes an item in our `indexedDB` store\n * @param key The item's key\n * @returns An RxJS `Observable` to wait the end of the operation\n */\n delete(key: string): Observable<undefined> {\n\n /* Open a transaction in write mode */\n return this.transaction(\"readwrite\").pipe(\n mergeMap((transactionData) => {\n\n const { store, events } = transactionData;\n\n /* Delete the item in store */\n store.delete(key);\n\n /* Listen to events and return `undefined` as no data is expected here */\n return events.pipe(map(() => undefined));\n\n }),\n /* The observable will complete after the first value */\n first(),\n );\n\n }\n\n /**\n * Deletes all items from our `indexedDB` objet store\n * @returns An RxJS `Observable` to wait the end of the operation\n */\n clear(): Observable<undefined> {\n\n /* Open a transaction in write mode */\n return this.transaction(\"readwrite\").pipe(\n mergeMap((transactionData) => {\n\n const { store, events } = transactionData;\n\n /* Delete all items in object store */\n store.clear();\n\n /* Listen to events and return `undefined` as no data is expected here */\n return events.pipe(map(() => undefined));\n\n }),\n /* The observable will complete */\n first(),\n );\n\n }\n\n /**\n * Get all the keys in our `indexedDB` store\n * @returns An RxJS `Observable` iterating on each key\n */\n keys(): Observable<string> {\n\n /* Open a transaction in read-only mode */\n return this.transaction(\"readonly\").pipe(\n /* `first()` is used as the final operator in other methods to complete the `Observable`\n * (as it all starts from a `ReplaySubject` which never ends),\n * but as this method is iterating over multiple values, `first()` **must** be used here */\n first(),\n mergeMap((transactionData) => {\n\n const { store } = transactionData;\n\n /* Open a cursor on the store\n * Avoid issues like https://github.com/cyrilletuzi/angular-async-local-storage/issues/69 */\n const request = store.openKeyCursor();\n\n /* Listen to success event */\n const success$ = fromEvent(request, \"success\").pipe(\n /* Stop the `Observable` when the cursor is `null` */\n // // eslint-disable-next-line rxjs/no-ignored-takewhile-value -- Required by indexedDb behavior, getting the result from the event does not always work\n takeWhile(() => (request.result !== null)),\n /* This lib only allows string keys, but user could have added other types of keys from outside\n * It's OK to cast as the cursor as been tested in the previous operator */\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-base-to-string -- Required by indexedDb behavior, and strings are enforced by the lib\n map(() => request.result!.key.toString()),\n /* Iterate on the cursor */\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Required by indexedDb behavior\n tap(() => { request.result!.continue(); }),\n );\n\n /* Listen to error event and if so, throw an error */\n const error$ = this.listenError(request);\n\n /* Choose the first event to occur */\n return race([success$, error$]);\n\n }),\n );\n\n }\n\n /**\n * Check if a key exists in our `indexedDB` store\n * @returns An RxJS `Observable` telling if the key exists or not\n */\n has(key: string): Observable<boolean> {\n\n /* Open a transaction in read-only mode */\n return this.transaction(\"readonly\").pipe(\n mergeMap((transactionData) => {\n\n const { store, events } = transactionData;\n\n /* Check if the key exists in the store\n * Fixes https://github.com/cyrilletuzi/angular-async-local-storage/issues/69\n */\n const request = store.getKey(key);\n\n /* Listen to events and return `true` or `false` */\n return events.pipe(map(() => (request.result !== undefined) ? true : false));\n\n }),\n /* The observable will complete */\n first(),\n );\n\n }\n\n /**\n * Connects to `indexedDB` and creates the object store on first time\n */\n private connect(): void {\n\n let request: IDBOpenDBRequest;\n\n /* Connect to `indexedDB`\n * Will fail in Safari cross-origin iframes\n * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/issues/42} */\n try {\n\n /* Do NOT explicit `window` here, as `indexedDB` could be used from a web worker too */\n request = indexedDB.open(this.dbName, this.dbVersion);\n\n } catch {\n\n this.database.error(new IDBBrokenError());\n\n return;\n\n }\n\n /* Create store on first connection */\n this.createStore(request);\n\n /* Listen to success and error events */\n const success$ = fromEvent(request, \"success\");\n const error$ = this.listenError(request);\n\n /* Choose the first to occur */\n race([success$, error$])\n /* The observable will complete */\n .pipe(first())\n .subscribe({\n next: () => {\n /* Register the database connection in the `ReplaySubject` for further access */\n this.database.next(request.result);\n },\n error: () => {\n /* Keeping this error management for safety, but it should not happen anymore.\n * It was for Firefox private mode issue in Firefox versions < 115\n * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/issues/26} */\n this.database.error(new IDBBrokenError());\n },\n });\n\n }\n\n /**\n * Create store on first use of `indexedDB`\n * @param request `indexedDB` database opening request\n */\n private createStore(request: IDBOpenDBRequest): void {\n\n /* Listen to the event fired on first connection */\n fromEvent(request, \"upgradeneeded\")\n /* The observable will complete */\n .pipe(first())\n .subscribe({\n next: () => {\n\n /* Check if the store already exists, to avoid error */\n if (!request.result.objectStoreNames.contains(this.storeName)) {\n\n /* Create the object store */\n request.result.createObjectStore(this.storeName);\n\n }\n\n }\n });\n\n }\n\n /**\n * Open an `indexedDB` transaction and get our store\n * @param mode `readonly` or `readwrite`\n * @returns An `indexedDB` transaction store and events, wrapped in an RxJS `Observable`\n */\n private transaction(mode: IDBTransactionMode): Observable<{\n store: IDBObjectStore;\n events: Observable<Event>;\n }> {\n\n /* From the `indexedDB` connection, open a transaction and get the store */\n return this.database\n .pipe(mergeMap((database) => {\n\n let transaction: IDBTransaction;\n\n try {\n\n transaction = database.transaction([this.storeName], mode);\n\n } catch (error) {\n\n /* The store could have been deleted from outside */\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n return throwError(() => error as DOMException);\n\n }\n\n /* Get the store from the transaction */\n const store = transaction.objectStore(this.storeName);\n\n /* Listen transaction `complete` and `error` events */\n const events = this.listenTransactionEvents(transaction);\n\n return of({ store, events });\n\n }));\n\n }\n\n /**\n * Listen errors on a transaction or request, and throw if trigerred\n * @param transactionOrRequest `indexedDb` transaction or request to listen\n * @returns An `Observable` listening to errors\n */\n private listenError(transactionOrRequest: IDBTransaction | IDBRequest): Observable<never> {\n\n return fromEvent(transactionOrRequest, \"error\").pipe(\n /* Throw on error to be able to catch errors in RxJS way.\n * Here `event.target` must be used, as `transactionOrRequest.error` will be `null`\n * if we are on the request and the error is only triggered later by the transaction */\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n mergeMap((event) => throwError(() => (event.target as IDBTransaction | IDBRequest | null)?.error)),\n );\n\n }\n\n /**\n * Listen transaction `complete` and `error` events\n * @param transaction Transaction to listen\n * @returns An `Observable` listening to transaction `complete` and `error` events\n */\n private listenTransactionEvents(transaction: IDBTransaction): Observable<Event> {\n\n /* Listen to the `complete` event */\n const complete$ = fromEvent(transaction, \"complete\");\n\n /* Listen to the `error` event */\n const error$ = this.listenError(transaction);\n\n /* Choose the first event to occur */\n return race([complete$, error$]);\n\n }\n\n}\n","import { Injectable } from \"@angular/core\";\nimport type {\n JSONSchema,\n JSONSchemaArray,\n JSONSchemaBoolean,\n JSONSchemaInteger, JSONSchemaNumber,\n JSONSchemaObject,\n JSONSchemaString,\n JSONSchemaTuple\n} from \"./json-schema\";\n\n@Injectable({\n providedIn: \"root\"\n})\nexport class JSONValidator {\n\n /**\n * Validate a JSON data against a Jsubset of the JSON Schema standard.\n * Types are enforced to validate everything: each schema must\n * @param data JSON data to validate\n * @param schema Subset of JSON Schema. Must have a `type`.\n * @returns If data is valid: `true`, if it is invalid: `false`\n * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/VALIDATION.md}\n */\n validate(data: unknown, schema: JSONSchema): boolean {\n\n switch (schema.type) {\n\n case \"string\":\n return this.validateString(data, schema);\n case \"number\":\n case \"integer\":\n return this.validateNumber(data, schema);\n case \"boolean\":\n return this.validateBoolean(data, schema);\n case \"array\":\n return this.validateArray(data, schema);\n case \"object\":\n return this.validateObject(data, schema);\n\n }\n\n }\n\n /**\n * Validate a string\n * @param data Data to validate\n * @param schema Schema describing the string\n * @returns If data is valid: `true`, if it is invalid: `false`\n */\n private validateString(data: unknown, schema: JSONSchemaString): boolean {\n\n if (typeof data !== \"string\") {\n return false;\n }\n\n if (!this.validateConst(data, schema)) {\n return false;\n }\n\n if (!this.validateEnum(data, schema)) {\n return false;\n }\n\n if ((schema.maxLength !== undefined) && (data.length > schema.maxLength)) {\n return false;\n }\n\n if ((schema.minLength !== undefined) && (data.length < schema.minLength)) {\n return false;\n }\n\n if (schema.pattern !== undefined) {\n\n try {\n const regularExpression = new RegExp(schema.pattern);\n\n if (!regularExpression.test(data)) {\n return false;\n }\n } catch {\n // Nothing to do\n }\n\n }\n\n return true;\n\n }\n\n /**\n * Validate a number or an integer\n * @param data Data to validate\n * @param schema Schema describing the number or integer\n * @returns If data is valid: `true`, if it is invalid: `false`\n */\n private validateNumber(data: unknown, schema: JSONSchemaNumber | JSONSchemaInteger): boolean {\n\n if (typeof data !== \"number\") {\n return false;\n }\n\n if ((schema.type === \"integer\") && !Number.isInteger(data)) {\n return false;\n }\n\n if (!this.validateConst(data, schema)) {\n return false;\n }\n\n if (!this.validateEnum(data, schema)) {\n return false;\n }\n\n /* Test is done this way to not divide by 0 */\n if (schema.multipleOf !== undefined && schema.multipleOf !== 0 && Number.isFinite(schema.multipleOf) && !Number.isInteger(data / schema.multipleOf)) {\n return false;\n }\n\n if ((schema.maximum !== undefined) && (data > schema.maximum)) {\n return false;\n }\n\n if ((schema.exclusiveMaximum !== undefined) && (data >= schema.exclusiveMaximum)) {\n return false;\n\n }\n\n if ((schema.minimum !== undefined) && (data < schema.minimum)) {\n return false;\n\n }\n\n if ((schema.exclusiveMinimum !== undefined) && (data <= schema.exclusiveMinimum)) {\n return false;\n }\n\n return true;\n\n }\n\n /**\n * Validate a boolean\n * @param data Data to validate\n * @param schema Schema describing the boolean\n * @returns If data is valid: `true`, if it is invalid: `false`\n */\n private validateBoolean(data: unknown, schema: JSONSchemaBoolean): boolean {\n\n if (typeof data !== \"boolean\") {\n return false;\n }\n\n if (!this.validateConst(data, schema)) {\n return false;\n }\n\n return true;\n\n }\n\n /**\n * Validate an array\n * @param data Data to validate\n * @param schema Schema describing the array\n * @returns If data is valid: `true`, if it is invalid: `false`\n */\n private validateArray(data: unknown, schema: JSONSchemaArray | JSONSchemaTuple): boolean {\n\n if (!Array.isArray(data)) {\n return false;\n }\n\n if ((schema.maxItems !== undefined) && (data.length > schema.maxItems)) {\n return false;\n }\n\n if ((schema.minItems !== undefined) && (data.length < schema.minItems)) {\n return false;\n }\n\n if (schema.uniqueItems === true) {\n\n /* Create a set to eliminate values with multiple occurences */\n const dataSet = new Set(data);\n\n if (data.length !== dataSet.size) {\n return false;\n }\n\n }\n\n /* Specific test for tuples */\n if (Array.isArray(schema.items) || schema.items === undefined) {\n\n // TODO: cast should not be needed here\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n return this.validateTuple(data, schema.items as JSONSchema[] | undefined);\n\n }\n\n /* Validate all the values in array */\n for (const value of data) {\n\n // TODO: remove when TypeScript 4.1 is available\n // (currently the narrowed type from `Array.isArray()` is lost on readonly arrays)\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n if (!this.validate(value, schema.items as JSONSchema)) {\n return false;\n }\n\n }\n\n return true;\n\n }\n\n /**\n * Validate a tuple (array with fixed length and multiple types)\n * @param data Data to validate\n * @param schemas Schemas describing the tuple\n * @returns If data is valid: `true`, if it is invalid: `false`\n */\n private validateTuple(data: unknown[], schemas: JSONSchema[] | undefined): boolean {\n\n const lengthToCheck = schemas ? schemas.length : 0;\n\n /* Tuples have a fixed length */\n if (data.length !== lengthToCheck) {\n\n return false;\n\n }\n\n if (schemas) {\n\n for (const [index, schema] of schemas.entries()) {\n\n if (!this.validate(data[index], schema)) {\n return false;\n }\n\n }\n\n }\n\n return true;\n\n }\n\n /**\n * Validate an object\n * @param data Data to validate\n * @param schema JSON schema describing the object\n * @returns If data is valid: `true`, if it is invalid: `false`\n */\n private validateObject(data: unknown, schema: JSONSchemaObject): boolean {\n\n /* Check the type and if not `null` as `null` also have the type `object` in old browsers */\n if ((typeof data !== \"object\") || (data === null)) {\n return false;\n }\n\n /* Check if the object doesn't have more properties than expected\n * Equivalent of `additionalProperties: false`\n */\n if (Object.keys(schema.properties).length < Object.keys(data).length) {\n return false;\n }\n\n /* Validate required properties */\n if (schema.required) {\n\n for (const requiredProp of schema.required) {\n\n if (!Object.hasOwn(data, requiredProp)) {\n return false;\n }\n\n }\n\n }\n\n /* Recursively validate all properties */\n for (const property in schema.properties) {\n\n /* Filter to keep only real properties (no internal JS stuff) and check if the data has the property too */\n if (Object.hasOwn(schema.properties, property) && Object.hasOwn(data, property)) {\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unsafe-type-assertion -- Ensured by the logic\n if (!this.validate((data as Record<string, unknown>)[property], schema.properties[property]!)) {\n return false;\n }\n\n }\n\n }\n\n return true;\n\n }\n\n /**\n * Validate a constant\n * @param data Data ta validate\n * @param schema JSON schema describing the constant\n * @returns If data is valid: `true`, if it is invalid: `false`\n */\n private validateConst(data: unknown, schema: JSONSchemaBoolean | JSONSchemaInteger | JSONSchemaNumber | JSONSchemaString): boolean {\n\n if (schema.const === undefined) {\n return true;\n }\n\n return (data === schema.const);\n\n }\n\n /**\n * Validate an enum\n * @param data Data ta validate\n * @param schema JSON schema describing the enum\n * @returns If data is valid: `true`, if it is invalid: `false`\n */\n private validateEnum(data: unknown, schema: JSONSchemaInteger | JSONSchemaNumber | JSONSchemaString): boolean {\n\n if (!schema.enum) {\n return true;\n }\n\n /* Cast as the data can be of multiple types, and so TypeScript is lost */\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n return ((schema.enum as unknown[]).includes(data));\n\n }\n\n}\n","import { Injectable } from \"@angular/core\";\nimport { Observable, ReplaySubject, of, throwError, type OperatorFunction } from \"rxjs\";\nimport { catchError, mergeMap, tap } from \"rxjs/operators\";\nimport { IDB_BROKEN_ERROR } from \"../databases/exceptions\";\nimport { IndexedDBDatabase } from \"../databases/indexeddb-database\";\nimport { LocalDatabase } from \"../databases/local-database\";\nimport { LocalStorageDatabase } from \"../databases/localstorage-database\";\nimport { MemoryDatabase } from \"../databases/memory-database\";\nimport type {\n JSONSchema,\n JSONSchemaArrayOf,\n JSONSchemaBoolean, JSONSchemaInteger,\n JSONSchemaNumber, JSONSchemaString\n} from \"../validation/json-schema\";\nimport { JSONValidator } from \"../validation/json-validator\";\nimport { ValidationError } from \"./exceptions\";\n\n@Injectable({\n providedIn: \"root\"\n})\nexport class StorageMap {\n\n #database: LocalDatabase;\n readonly #jsonValidator: JSONValidator;\n readonly #notifiers = new Map<string, ReplaySubject<unknown>>();\n\n /**\n * Constructor params are provided by Angular (but can also be passed manually in tests)\n * @param database Storage to use\n */\n constructor(\n // eslint-disable-next-line @angular-eslint/prefer-inject -- Used in tests\n database: LocalDatabase,\n ) {\n this.#database = database;\n this.#jsonValidator = new JSONValidator();\n }\n\n /**\n * **Number of items** in storage, wrapped in an Observable.\n * \n * Note you do *not* need to unsubscribe (it is a self-completing Observable).\n *\n * @example\n * this.storageMap.size.subscribe((size) => {\n * console.log(size);\n * });\n */\n get size(): Observable<number> {\n\n return this.#database.size\n /* Catch if `indexedDb` is broken */\n .pipe(this.#catchIDBBroken(() => this.#database.size));\n\n }\n\n /**\n * Tells you which storage engine is used.\n * \n * *Only useful for interoperability.*\n * \n * Note that due to some browsers issues in some special contexts\n * (like Safari cross-origin iframes),\n * **this information may be wrong at initialization,**\n * as the storage could fallback from `indexedDB` to `localStorage`\n * only after a first read or write operation.\n * @returns Storage engine used\n *\n * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/INTEROPERABILITY.md}\n *\n * @example\n * if (this.storageMap.backingEngine === 'indexedDB') {}\n */\n get backingEngine(): \"indexedDB\" | \"localStorage\" | \"memory\" | \"unknown\" {\n\n if (this.#database instanceof IndexedDBDatabase) {\n\n return \"indexedDB\";\n\n } else if (this.#database instanceof LocalStorageDatabase) {\n\n return \"localStorage\";\n\n } else if (this.#database instanceof MemoryDatabase) {\n\n return \"memory\";\n\n } else {\n\n return \"unknown\";\n\n }\n\n }\n\n /**\n * Information about `indexedDB` database.\n * \n * *Only useful for interoperability.*\n * \n * @returns `indexedDB` database name, store name and database version.\n * **Values will be empty if the storage is not `indexedDB`, so it should be used after an engine check**.\n *\n * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/INTEROPERABILITY.md}\n *\n * @example\n * if (this.storageMap.backingEngine === 'indexedDB') {\n * const { database, store, version } = this.storageMap.backingStore;\n * }\n */\n get backingStore(): { database: string, store: string, version: number; } {\n\n return (this.#database instanceof IndexedDBDatabase) ?\n this.#database.backingStore :\n { database: \"\", store: \"\", version: 0 };\n\n }\n\n /**\n * Information about `localStorage` fallback storage.\n * \n * *Only useful for interoperability.*\n * \n * @returns `localStorage` prefix.\n * **Values will be empty if the storage is not `localStorage`, so it should be used after an engine check**.\n *\n * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/INTEROPERABILITY.md}\n *\n * @example\n * if (this.storageMap.backingEngine === 'localStorage') {\n * const { prefix } = this.storageMap.fallbackBackingStore;\n * }\n */\n get fallbackBackingStore(): { prefix: string; } {\n\n return (this.#database instanceof LocalStorageDatabase) ?\n { prefix: this.#database.prefix } :\n { prefix: \"\" };\n\n }\n\n /**\n * Get an item value in storage.\n * \n * Note that:\n * * not finding an item is not an error, it succeeds but returns `undefined`,\n * * you do *not* need to unsubscribe (it is a self-completing Observable),\n * * you will only get *one* value: the Observable is here for asynchrony but is *not* meant to emit again when the stored data is changed. If you need to watch the value, see the `watch` method.\n * \n * Do not forget it is client-side storage: **always check the data**, as it could have been forged.\n * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/VALIDATION.md}\n * \n * @param key The item's key\n * @param schema Optional but recommended JSON schema to validate the data\n * @returns The item's value if the key exists, `undefined` otherwise, wrapped in a RxJS Observable\n *\n * @example\n * this.storageMap.get('key', { type: 'string' }).subscribe((result) => {\n * result; // string or undefined\n * });\n *\n * @example\n * interface User {\n * firstName: string;\n * lastName?: string;\n * }\n *\n * const schema = {\n * type: 'object',\n * properties: {\n * firstName: { type: 'string' },\n * lastName: { type: 'string' },\n * },\n * required: ['firstName'],\n * } satisfies JSONSchema;\n *\n * this.storageMap.get<User>('user', schema).subscribe((user) => {\n * if (user) {\n * user.firstName;\n * }\n * });\n */\n get(key: string): Observable<unknown>;\n get<T extends string = string>(key: string, schema: JSONSchemaString): Observable<T | undefined>;\n get<T extends number = number>(key: string, schema: JSONSchemaInteger | JSONSchemaNumber): Observable<T | undefined>;\n get<T extends boolean = boolean>(key: string, schema: JSONSchemaBoolean): Observable<T | undefined>;\n get<T extends readonly string[] = string[]>(key: string, schema: JSONSchemaArrayOf<JSONSchemaString>): Observable<T | undefined>;\n // eslint-disable-next-line @typescript-eslint/unified-signatures -- Better for documentation\n get<T extends readonly number[] = number[]>(key: string, schema: JSONSchemaArrayOf<JSONSchemaInteger | JSONSchemaNumber>): Observable<T | undefined>;\n // eslint-disable-next-line @typescript-eslint/unified-signatures -- Better for documentation\n get<T extends readonly boolean[] = boolean[]>(key: string, schema: JSONSchemaArrayOf<JSONSchemaBoolean>): Observable<T | undefined>;\n get<T>(key: string, schema: JSONSchema): Observable<T | undefined>;\n get<T = unknown>(key: string, schema?: JSONSchema): Observable<unknown> {\n\n /* Get the data in storage */\n return this.#database.get(key).pipe(\n /* Check if `indexedDb` is broken */\n this.#catchIDBBroken(() => this.#database.get(key)),\n mergeMap((data) => {\n\n /* No need to validate if the data is empty */\n if ((data === undefined) || (data === null)) {\n\n return of(undefined);\n\n } else if (schema) {\n\n /* Validate data against a JSON schema if provided */\n if (!this.#jsonValidator.validate(data, schema)) {\n return throwError(() => new ValidationError());\n }\n\n /* Data have been checked, so it's OK to cast */\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n return of(data as T | undefined);\n\n }\n\n /* Cast to unknown as the data wasn't checked */\n return of(data);\n\n }),\n );\n\n }\n\n /**\n * Store an item in storage.\n * \n * Note that:\n * * you *do* need to subscribe, even if you do not have something specific to do after writing in storage, otherwise nothing happens (because it is how RxJS Observables work),\n * * but you do *not* need to unsubscribe (it is a self-completing Observable),\n * * setting `null` or `undefined` will remove the item to avoid some browsers issues,\n * * you should stick to serializable JSON data, meaning primitive types, arrays and literal objects. Date, Map, Set, Blob and other special structures can cause issues in some scenarios.\n * @see {@link https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/SERIALIZATION.md}\n * \n * @param key The item's key\n * @param data The item's value\n * @param schema Optional JSON schema to validate the data\n * @returns A RxJS Observable to wait the end of the operation\n *\n * @example\n * this.storageMap.set('key', 'value').subscribe(() => {});\n */\n set(key: string, data: unknown, schema?: JSONSchema): Observable<undefined> {\n\n /* Storing `undefined` or `null` is useless and can cause issues in `indexedDb` in some browsers,\n * so removing item instead for all storages to have a consistent API */\n if ((data === undefined) || (data === null)) {\n return this.delete(key);\n }\n\n /* Validate data against a JSON schema if provided */\n if (schema && !this.#jsonValidator.validate(data, schema)) {\n return throwError(() => new ValidationError());\n }\n\n return this.#database.set(key, data).pipe(\n /* Catch if `indexedDb` is broken */\n this.#catchIDBBroken(() => this.#database.set(key, data)),\n /* Notify watchers (must be last because it should only happen if the operation succeeds) */\n tap(() => { this.#notify(key, data); }),\n );\n }\n\n /**\n * Delete an item in storage.\n * \n * Note that:\n * * you *do* need to subscribe, even if you do not have something specific to do after deleting, otherwise nothing happens (because it is how RxJS Observables work),\n * * but you do *not* need to unsubscribe (it is a self-completing Observable).\n * \n * @param key The item's key\n * @returns A RxJS Observable to wait the end of the operation\n *\n * @example\n * this.storageMap.delete('key').subscribe(() => {});\n */\n delete(key: string): Observable<undefined> {\n\n return this.#database.delete(key).pipe(\n /* Catch if `indexedDb` is broken */\n this.#catchIDBBroken(() => this.#database.delete(key)),\n /* Notify watchers (must be last because it should only happen if the operation succeeds) */\n tap(() => { this.#notify(key, undefined); }),\n );\n\n }\n\n /**\n * Delete all items in storage.\n * \n * Note that:\n * * you *do* need to subscribe, even if you do not have something specific to do after clearing, otherwise nothing happens (because it is how RxJS Observables work),\n * * but you do *not* need to unsubscribe (it is a self-completing Observable).\n * \n * @returns A RxJS Observable to wait the end of the operation\n *\n * @example\n * this.storageMap.clear().subscribe(() => {});\n */\n clear(): Observable<undefined> {\n\n return this.#database.clear().pipe(\n /* Catch if `indexedDb` is broken */\n this.#catchIDBBroken(() => this.#database.clear()),\n /* Notify watchers (must be last because it should only happen if the operation succeeds) */\n tap(() => {\n for (const key of this.#notifiers.keys()) {\n this.#notify(key, undefined);\n }\n }),\n );\n\n }\n\n /**\n * Get all keys stored in storage.\n * \n * Note **this is an *iterating* Observable**:\n * * if there is no key, the `next` callback will not be invoked,\n * * if you need to wait the whole operation to end, be sure to act in the `complete` callback,\n * as this Observable can emit several values and so will invoke the `next` callback several times,\n * * you do *not* need to unsubscribe (it is a self-completing Observable).\n * \n * @returns A list of the keys wrapped in a RxJS Observable\n *\n * @example\n * this.storageMap.keys().subscribe({\n * next: (key) => { console.log(key); },\n * complete: () => { console.log('Done'); },\n * });\n */\n keys(): Observable<string> {\n\n return this.#database.keys()\n /* Catch if `indexedDb` is broken */\n .pipe(this.#catchIDBBroken(() => this.#database.keys()));\n\n }\n\n /**\n * Tells if a key exists in storage.\n * \n * Note you do *not* need to unsubscribe (it is a self-completing Observable).\n * \n * @returns A RxJS Observable telling if the key exists\n *\n * @example\n * this.storageMap.has('key').subscribe((hasKey) => {\n * if (hasKey) {}\n * });\n */\n has(key: string): Observable<boolean> {\n\n return this.#database.has(key)\n /* Catch if `indexedDb` is broken */\n .pipe(this.#catchIDBBroken(() => this.#database.has(key)));\n\n }\n\n /**\n * Watch an item value in storage.\n * \n * Note that:\n * * it is an infinite Observable, do not forget to unsubscribe,\n * * only changes done via this library will be watched, external changes in storage cannot be detected.\n * \n * The signature has many overloads due to validation, **please refer to the documentation.**\n * @see https://github.com/cyrilletuzi/angular-async-local-storage/blob/main/docs/VALIDATION.md\n * \n * @param key The item's key to watch\n * @param schema Optional JSON schema to validate the initial value\n * @returns An infinite Observable giving the current value\n * \n * @example\n * Component()\n * export class MyComponent implements OnInit, OnDestroy {\n * \n * private storageSubscription?: Subscription;\n * \n * ngOnInit(): void {\n * this.storageSubscription = this.storageMap.watch('key', { type: 'string' }).subscribe((result) => {\n * result; // string or undefined\n * });\n * }\n * \n * ngOnDestroy(): void {\n * this.storageSubscription?.unsubscribe();\n * }\n * \n * }\n */\n watch(key: string): Observable<unknown>;\n watch<T extends string = string>(key: string, schema: JSONSchemaString): Observable<T | undefined>;\n watch<T extends number = number>(key: string, schema: JSONSchemaInteger | JSONSchemaNumber): Observable<T | undefined>;\n watch<T extends boolean = boolean>(key: string, schema: JSONSchemaBoolean): Observable<T | undefined>;\n watch<T extends readonly string[] = string[]>(key: string, schema: JSONSchemaArrayOf<JSONSchemaString>): Observable<T | undefined>;\n // eslint-disable-next-line @typescript-eslint/unified-signatures -- Better for documentation\n watch<T extends readonly number[] = number[]>(key: string, schema: JSONSchemaArrayOf<JSONSchemaInteger | JSONSchemaNumber>): Observable<T | undefined>;\n // eslint-disable-next-line @typescript-eslint/unified-signatures -- Better for documentation\n watch<T extends readonly boolean[] = boolean[]>(key: string, schema: JSONSchemaArrayOf<JSONSchemaBoolean>): Observable<T | undefined>;\n watch<T>(key: string, schema: JSONSchema): Observable<T | undefined>;\n watch<T = unknown>(key: string, schema?: JSONSchema): Observable<unknown> {\n\n /* Check if there is already a notifier */\n if (!this.#notifiers.has(key)) {\n this.#notifiers.set(key, new ReplaySubject(1));\n }\n\n /* Non-null assertion is required because TypeScript doesn't narrow `.has()` yet */\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Ensured by the logic\n const notifier = this.#notifiers.get(key)!;\n\n /* Get the current item value */\n (schema ? this.get<T>(key, schema) : this.get(key)).subscribe({\n next: (result) => {\n notifier.next(result);\n },\n error: (error) => {\n notifier.error(error);\n },\n });\n\n /* Only the public API of the Observable should be returned */\n return (schema ?\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n notifier.asObservable() as Observable<T | undefined> :\n notifier.asObservable()\n );\n\n }\n\n /**\n * Notify when a value changes\n * @param key The item's key\n * @param data The new value\n */\n #notify(key: string, value: unknown): void {\n\n const notifier = this.#notifiers.get(key);\n\n if (notifier) {\n notifier.next(value);\n }\n\n }\n\n /**\n * RxJS operator to catch if `indexedDB` is broken\n * @param operationCallback Callback with the operation to redo\n */\n #catchIDBBroken<T>(operationCallback: () => Observable<T>): OperatorFunction<T, T> {\n\n return catchError((error) => {\n\n /* Check if `indexedDB` is broken based on error message (the specific error class seems to be lost in the process) */\n if ((error !== undefined) && (error !== null)\n && (typeof error === \"object\") && (\"message\" in error)\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- Required because TypeScript narrowing is not working here\n && (error.message === IDB_BROKEN_ERROR)) {\n\n /* When storage is fully disabled in browser (via the \"Block all cookies\" option),\n * just trying to check `localStorage` variable causes a security exception.\n * Prevents https://github.com/cyrilletuzi/angular-async-local-storage/issues/118\n */\n try {\n\n if (\"getItem\" in localStorage) {\n\n /* Fallback to `localStorage` if available */\n this.#database = new LocalStorageDatabase();\n\n } else {\n\n /* Fallback to memory storage otherwise */\n this.#database = new MemoryDatabase();\n\n }\n\n } catch {\n\n /* Fallback to memory storage otherwise */\n this.#database = new MemoryDatabase();\n\n }\n\n /* Redo the operation */\n return operationCallback();\n\n } else {\n\n /* Otherwise, rethrow the error */\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return throwError(() => error);\n\n }\n\n });\n\n }\n\n /**\n * THIS METHOD IS FOR INTERNAL PURPOSE ONLY AND MUST NOT BE USED,\n * IT CAN BE REMOVED AT ANY TIME AND MESSING WITH IT CAN CAUSE ISSUES\n * @private\n * @ignore\n */\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- Silence the not used error, it is used in tests\n // @ts-ignore\n private ɵinternalGetDatabase(): LocalDatabase {\n\n return this.#database;\n\n }\n\n}\n","/*\n * Public API Surface of local-storage\n */\n\nexport { SERIALIZATION_ERROR, SerializationError } from \"./lib/databases/exceptions\";\nexport {\n provideIndexedDBDataBaseName, provideIndexedDBDataBaseVersion,\n provideIndexedDBStoreName, provideLocalStoragePrefix\n} from \"./lib/providers\";\nexport { StorageModule } from \"./lib/storage.module\";\nexport { VALIDATION_ERROR, ValidationError } from \"./lib/storages/exceptions\";\nexport { StorageMap } from \"./lib/storages/storage-map\";\nexport type { StorageConfig } from \"./lib/tokens\";\nexport type { JSONSchema } from \"./lib/validation/json-schema\";\n\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.LocalDatabase"],"mappings":"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"}