UNPKG

@embrace-io/web-sdk

Version:
1 lines 6.18 kB
{"version":3,"file":"NamespacedStorage.cjs","names":["diag"],"sources":["../../../src/utils/NamespacedStorage/NamespacedStorage.ts"],"sourcesContent":["import type { DiagLogger } from '@opentelemetry/api';\nimport { diag } from '@opentelemetry/api';\n\ninterface NamespacedStorageArgs {\n storage: Storage;\n namespace?: string;\n diag?: DiagLogger;\n}\n\n/**\n * `Storage`-shaped wrapper that isolates the SDK from storage errors and\n * optionally namespaces keys with a prefix. Mutation methods return `true`\n * on success and `false` when the call failed or writes have been disabled.\n *\n * Read failures (`getItem`, `key`, `length`) log at warn level and degrade\n * to `null`/empty results.\n *\n * The first `setItem` failure flips a sticky `_writeDisabled` flag and\n * emits one error; subsequent `setItem` calls silently return `false`\n * without attempting the underlying write, so a one-time quota error or\n * revoked permission does not keep throwing on every attempt. Reads,\n * removes, and clears continue to work.\n *\n * An empty namespace skips the key prefix; the wrapper then exposes the\n * underlying storage's full keyspace with only the safety layer applied.\n */\nexport class NamespacedStorage {\n private readonly _diag: DiagLogger;\n private readonly _keyPrefix: string;\n private readonly _storage: Storage;\n private _writeDisabled = false;\n\n public constructor({\n namespace,\n storage,\n diag: diagParam,\n }: NamespacedStorageArgs) {\n this._diag =\n diagParam ??\n diag.createComponentLogger({ namespace: 'NamespacedStorage' });\n this._keyPrefix = namespace ? `${namespace}__` : '';\n this._storage = storage;\n }\n\n /**\n * Logical keys when namespaced; raw underlying keys otherwise (may include\n * foreign keys sharing the origin's storage). Best-effort: indices that\n * throw are skipped, returns empty on bulk failure.\n */\n public keys(): string[] {\n let length: number;\n try {\n length = this._storage.length;\n } catch (e) {\n this._diag.warn('failed to read storage length', String(e));\n return [];\n }\n const result: string[] = [];\n for (let i = 0; i < length; i++) {\n try {\n const key = this._storage.key(i);\n if (key === null) {\n continue;\n }\n if (this._keyPrefix) {\n if (key.startsWith(this._keyPrefix)) {\n result.push(key.substring(this._keyPrefix.length));\n }\n } else {\n result.push(key);\n }\n } catch (e) {\n this._diag.warn(\n `failed to read storage key at index ${i.toString()}`,\n String(e),\n );\n }\n }\n return result;\n }\n\n public get length(): number {\n return this.keys().length;\n }\n\n public clear(): boolean {\n let allRemoved = true;\n for (const key of this.keys()) {\n if (!this._safeRemove(this._keyName(key))) {\n allRemoved = false;\n }\n }\n return allRemoved;\n }\n\n public getItem(key: string): string | null {\n try {\n return this._storage.getItem(this._keyName(key));\n } catch (e) {\n this._diag.warn(`failed to read ${key}`, String(e));\n return null;\n }\n }\n\n public key(index: number): string | null {\n return this.keys()[index] ?? null;\n }\n\n public removeItem(key: string): boolean {\n return this._safeRemove(this._keyName(key));\n }\n\n public setItem(key: string, value: string): boolean {\n if (this._writeDisabled) {\n return false;\n }\n try {\n this._storage.setItem(this._keyName(key), value);\n return true;\n } catch (e) {\n this._disableWrites(e);\n return false;\n }\n }\n\n private _keyName(key: string): string {\n return `${this._keyPrefix}${key}`;\n }\n\n private _safeRemove(keyName: string): boolean {\n try {\n this._storage.removeItem(keyName);\n return true;\n } catch (e) {\n this._diag.warn(`failed to remove ${keyName}`, String(e));\n return false;\n }\n }\n\n // Log only error.name: error.message can leak the stored value on some browsers.\n private _disableWrites(error: unknown): void {\n if (this._writeDisabled) {\n return;\n }\n this._writeDisabled = true;\n const errorName = error instanceof Error ? error.name : 'UnknownError';\n this._diag.error(\n 'writes disabled after failure; continuing in-memory only',\n errorName,\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA0BA,IAAa,oBAAb,MAA+B;CAC7B;CACA;CACA;CACA,iBAAyB;CAEzB,YAAmB,EACjB,WACA,SACA,MAAM,aACkB;EACxB,KAAK,QACH,aACAA,mBAAAA,KAAK,sBAAsB,EAAE,WAAW,oBAAoB,CAAC;EAC/D,KAAK,aAAa,YAAY,GAAG,UAAU,MAAM;EACjD,KAAK,WAAW;CAClB;;;;;;CAOA,OAAwB;EACtB,IAAI;EACJ,IAAI;GACF,SAAS,KAAK,SAAS;EACzB,SAAS,GAAG;GACV,KAAK,MAAM,KAAK,iCAAiC,OAAO,CAAC,CAAC;GAC1D,OAAO,CAAC;EACV;EACA,MAAM,SAAmB,CAAC;EAC1B,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAC1B,IAAI;GACF,MAAM,MAAM,KAAK,SAAS,IAAI,CAAC;GAC/B,IAAI,QAAQ,MACV;GAEF,IAAI,KAAK;QACH,IAAI,WAAW,KAAK,UAAU,GAChC,OAAO,KAAK,IAAI,UAAU,KAAK,WAAW,MAAM,CAAC;GAAA,OAGnD,OAAO,KAAK,GAAG;EAEnB,SAAS,GAAG;GACV,KAAK,MAAM,KACT,uCAAuC,EAAE,SAAS,KAClD,OAAO,CAAC,CACV;EACF;EAEF,OAAO;CACT;CAEA,IAAW,SAAiB;EAC1B,OAAO,KAAK,KAAK,CAAC,CAAC;CACrB;CAEA,QAAwB;EACtB,IAAI,aAAa;EACjB,KAAK,MAAM,OAAO,KAAK,KAAK,GAC1B,IAAI,CAAC,KAAK,YAAY,KAAK,SAAS,GAAG,CAAC,GACtC,aAAa;EAGjB,OAAO;CACT;CAEA,QAAe,KAA4B;EACzC,IAAI;GACF,OAAO,KAAK,SAAS,QAAQ,KAAK,SAAS,GAAG,CAAC;EACjD,SAAS,GAAG;GACV,KAAK,MAAM,KAAK,kBAAkB,OAAO,OAAO,CAAC,CAAC;GAClD,OAAO;EACT;CACF;CAEA,IAAW,OAA8B;EACvC,OAAO,KAAK,KAAK,CAAC,CAAC,UAAU;CAC/B;CAEA,WAAkB,KAAsB;EACtC,OAAO,KAAK,YAAY,KAAK,SAAS,GAAG,CAAC;CAC5C;CAEA,QAAe,KAAa,OAAwB;EAClD,IAAI,KAAK,gBACP,OAAO;EAET,IAAI;GACF,KAAK,SAAS,QAAQ,KAAK,SAAS,GAAG,GAAG,KAAK;GAC/C,OAAO;EACT,SAAS,GAAG;GACV,KAAK,eAAe,CAAC;GACrB,OAAO;EACT;CACF;CAEA,SAAiB,KAAqB;EACpC,OAAO,GAAG,KAAK,aAAa;CAC9B;CAEA,YAAoB,SAA0B;EAC5C,IAAI;GACF,KAAK,SAAS,WAAW,OAAO;GAChC,OAAO;EACT,SAAS,GAAG;GACV,KAAK,MAAM,KAAK,oBAAoB,WAAW,OAAO,CAAC,CAAC;GACxD,OAAO;EACT;CACF;CAGA,eAAuB,OAAsB;EAC3C,IAAI,KAAK,gBACP;EAEF,KAAK,iBAAiB;EACtB,MAAM,YAAY,iBAAiB,QAAQ,MAAM,OAAO;EACxD,KAAK,MAAM,MACT,4DACA,SACF;CACF;AACF"}