UNPKG

@aws-amplify/core

Version:

Core category of aws-amplify

116 lines (113 loc) • 4.7 kB
import { ConsoleLogger } from '../Logger/ConsoleLogger.mjs'; import { PlatformNotSupportedError } from '../errors/PlatformNotSupportedError.mjs'; import '../errors/errorHelpers.mjs'; import '../utils/getClientInfo/getClientInfo.mjs'; import { isBrowser } from '../utils/isBrowser.mjs'; import '../utils/retry/retry.mjs'; // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 const logger = new ConsoleLogger('KeyValueStorage'); /** * @internal */ class KeyValueStorage { constructor(storage) { this.storage = storage; } /** * This is used to set a specific item in storage * @param {string} key - the key for the item * @param {object} value - the value * @returns {string} value that was set */ async setItem(key, value) { if (!this.storage) throw new PlatformNotSupportedError(); this.storage.setItem(key, value); } /** * This is used to get a specific key from storage * @param {string} key - the key for the item * This is used to clear the storage * @returns {string} the data item */ async getItem(key) { if (!this.storage) throw new PlatformNotSupportedError(); return this.storage.getItem(key); } /** * This is used to remove an item from storage * @param {string} key - the key being set * @returns {string} value - value that was deleted */ async removeItem(key) { if (!this.storage) throw new PlatformNotSupportedError(); this.storage.removeItem(key); } /** * This is used to clear the storage * @returns {string} nothing */ async clear() { if (!this.storage) throw new PlatformNotSupportedError(); this.storage.clear(); } /** * This is used to allow listening for changes * @param {function} listener - the function called on storage change * @returns {function} an unsubscribe function that removes the listener. The * underlying `window` 'storage' event listener is attached lazily on the * first subscription and detached once the last listener unsubscribes. In * non-browser (SSR/native) environments nothing is attached and the returned * unsubscribe function is a safe no-op. */ addListener(listener) { const listeners = (this.listeners ?? (this.listeners = new Set())); listeners.add(listener); // Lazily attach the cross-tab 'storage' listener on the first subscription. if (isBrowser() && listeners.size === 1) { // Create the handler lazily (and only in a browser) so instances that // never subscribe keep no function-valued own property. The same // reference is reused for detach on last-unsubscribe. const storageListener = (e) => { // Only react to events for this instance's backing store. Without // this guard a localStorage-backed instance and a // sessionStorage-backed instance would react to each other's // 'storage' events, since both share the single window listener. if (e.storageArea !== this.storage) { return; } this.listeners?.forEach(l => { // A listener may be async and reject; isolate each call so one // rejecting listener neither aborts the others nor surfaces as an // unhandled promise rejection. Promise.resolve(l({ key: e.key, oldValue: e.oldValue, newValue: e.newValue, })).catch(error => { logger.error('Error in storage event listener', error); }); }); }; this.storageListener = storageListener; window.addEventListener('storage', storageListener, false); } return () => { listeners.delete(listener); const { storageListener } = this; // Detach once the last subscriber unsubscribes — real teardown, not // just pruning the set. Guarding on the stored handler keeps repeated // unsubscribe calls idempotent. if (isBrowser() && listeners.size === 0 && storageListener) { window.removeEventListener('storage', storageListener, false); this.storageListener = undefined; } }; } } export { KeyValueStorage }; //# sourceMappingURL=KeyValueStorage.mjs.map