UNPKG

@cedx/webstorage

Version:

Service for interacting with the Web Storage.

181 lines (180 loc) 5.72 kB
import { StorageEvent } from "./StorageEvent.js"; /** * Provides access to the [Web Storage](https://developer.mozilla.org/docs/Web/API/Web_Storage_API). */ export class Storage extends EventTarget { /** * The underlying data store. */ #backend; /** * A string prefixed to every key so that it is unique globally in the whole storage. */ #keyPrefix; /** * Creates a new storage service. * @param backend The underlying data store. * @param options An object providing values to initialize this instance. */ constructor(backend, options = {}) { super(); this.#backend = backend; this.#keyPrefix = options.keyPrefix ?? ""; if (options.listenToGlobalEvents) addEventListener("storage", this); } /** * The keys of this storage. */ get keys() { const keys = Array.from(Array(this.#backend.length), (_, index) => this.#backend.key(index)); return new Set(this.#keyPrefix ? keys.filter(key => key.startsWith(this.#keyPrefix)).map(key => key.slice(this.#keyPrefix.length)) : keys); } /** * The number of entries in this storage. */ get length() { return this.#keyPrefix ? this.keys.size : this.#backend.length; } /** * Creates a new local storage service. * @param options An object providing values to initialize the service. * @returns The newly created service. */ static local(options = {}) { return new this(localStorage, options); } /** * Creates a new session storage service. * @param options An object providing values to initialize the service. * @returns The newly created service. */ static session(options = {}) { return new this(sessionStorage, options); } /** * Releases any resources associated with this object. */ [Symbol.dispose]() { return this.destroy(); } /** * Returns a new iterator that allows iterating the entries of this storage. * @returns An iterator for the entries of this storage. */ *[Symbol.iterator]() { for (const key of this.keys) yield [key, this.get(key)]; } /** * Removes all entries from this storage. */ clear() { if (this.#keyPrefix) for (const key of this.keys) this.delete(key); else { this.#backend.clear(); this.dispatchEvent(new StorageEvent(null)); } } /** * Removes the value associated with the specified key. * @param key The storage key. * @returns The value associated with the key before it was removed. */ delete(key) { const oldValue = this.get(key); this.#backend.removeItem(this.#buildKey(key)); this.dispatchEvent(new StorageEvent(key, oldValue)); return oldValue; } /** * Cancels the subscription to the global storage events. */ destroy() { removeEventListener("storage", this); } /** * Gets the value associated to the specified key. * @param key The storage key. * @returns The storage value, or `null` if the key does not exist. */ get(key) { return this.#backend.getItem(this.#buildKey(key)); } /** * Gets the deserialized value associated with the specified key. * @param key The storage key. * @returns The storage value, or `null` if the key does not exist or the value cannot be deserialized. */ getObject(key) { try { return JSON.parse(this.get(key) ?? ""); } catch { return null; } } /** * Handles the events. * @param event The dispatched event. */ handleEvent(event) { if (event.storageArea == this.#backend && (!event.key || event.key.startsWith(this.#keyPrefix))) this.dispatchEvent(new StorageEvent(event.key?.slice(this.#keyPrefix.length) ?? null, event.oldValue, event.newValue)); } /** * Gets a value indicating whether this storage contains the specified key. * @param key The storage key. * @returns `true` if this storage contains the specified key, otherwise `false`. */ has(key) { return this.get(key) != null; } /** * Registers a function that will be invoked whenever the `change` event is triggered. * @param listener The event handler to register. * @returns This instance. */ onChange(listener) { this.addEventListener(StorageEvent.type, listener); return this; } /** * Associates a given value with the specified key. * @param key The storage key. * @param value The storage value. * @returns This instance. */ set(key, value) { const oldValue = this.get(key); this.#backend.setItem(this.#buildKey(key), value); this.dispatchEvent(new StorageEvent(key, oldValue, value)); return this; } /** * Serializes and associates a given `value` with the specified `key`. * @param key The storage key. * @param value The storage value. * @returns This instance. */ setObject(key, value) { return this.set(key, JSON.stringify(value)); } /** * Returns a JSON representation of this object. * @returns The JSON representation of this object. */ toJSON() { return Array.from(this); } /** * Builds a normalized storage key from the given key. * @param key The original key. * @returns The normalized storage key. */ #buildKey(key) { return `${this.#keyPrefix}${key}`; } }