ngx-webstorage-service
Version:
Angular service wrappers for the webstorage API
443 lines (433 loc) • 19.6 kB
JavaScript
import * as i0 from '@angular/core';
import { InjectionToken, NgModule } from '@angular/core';
/**
* A storage service implementation that is used as a proxy for another storage service. This is used to create storage services with a
* different default transcoder.
*/
class ProxyStorageService {
/**
* Creates a new `ProxyStorageService` instance that uses the specified transcoder by default for read and write operations. Actual
* read and writes are delegated to given storage service.
*
* @param defaultTranscoder Transcoder which is to be used by default for storage read and write operations.
* @param subject Storage service which should handle to actual storage of data.
*/
constructor(defaultTranscoder, subject) {
this.defaultTranscoder = defaultTranscoder;
this.subject = subject;
}
/**
* Checks whether an entry with the specified key exists in the storage.
*
* @param key Identifier of the entry for which its presence in the storage is to be checked.
* @returns `true` if an entry with the specified key exists in the storage, `false` if not.
*/
has(key) {
return this.subject.has(key);
}
/*
* Retrieves the value stored for the entry that is associated with the specified key. The given decoder is used to convert the stored
* value to the desired type. If no entry for the specified key exists or if the decoder is unable to decode the stored value, then
* `undefined` will be returned.
*
* @param key Identifier of the entry whose value is to be retrieved.
* @param decoder Decoder to use for converting the stored value to the desired return type.
* @returns Value of the entry that is identified by the specified key. In case the entry does not exist or if it cannot be
* loaded (due to a decoding issue), then `undefined` will be returned by this function.
*/
get(key, decoder) {
return this.subject.get(key, decoder !== null && decoder !== void 0 ? decoder : this.defaultTranscoder);
}
/**
* Creates or updates the entry identified by the specified key with the given value. The specified encoder is used to convert the given
* value into a format that can be stored by the storage service's underlying storage.
*
* Storing a value into the storage service will ensure that an equivalent of the value can be read back, i.e. the data and structure of
* the value will be the same. It, however, does not necessarily return the same reference.
*
* @param key Identifier of the entry which is to be created or updated.
* @param value Value which is to be stored.
* @param encoder Encoder used to convert the given value into a format that can be used for storage.
*/
set(key, value, encoder) {
this.subject.set(key, value, encoder !== null && encoder !== void 0 ? encoder : this.defaultTranscoder);
}
/**
* Removes the entry that is identified by the specified key. Attempting to remove an entry for an unknown key will have no effect.
* Attempting to retrieve an entry via the `get` method after it has been removed will result in `undefined`.
*
* @param key Identifier of the entry which is to be removed.
*/
remove(key) {
this.subject.remove(key);
}
/**
* Clears the storage by removing all entries. Subsequent `get(x)` calls for a key *x* will return `undefined`, until a new value is set
* for key *x*.
*/
clear() {
this.subject.clear();
}
/**
* Creates a new storage service that uses the specified transcoder by default for read and write operations. The new storage service
* uses the storage service on which this function is invoked as underlying storage. Both storage services will thus be able to access
* the same data.
*
* The default transcoder will not be changed for the storage service on which this function is invoked.
*
* @param transcoder Transcoder that should be used by default for read and write operations by the new storage service.
* @returns A new storage service that uses the specified transcoder by default.
*/
withDefaultTranscoder(transcoder) {
return new ProxyStorageService(transcoder, this.subject);
}
}
/**
* Base implementation for storage services.
*/
class BaseStorageService {
/**
* Creates a new `BaseStorageService` that uses the specified transcoder by default for read and write operations.
*
* @param defaultTranscoder Transcoder which is to be used by default for storage read and write operations.
*/
constructor(defaultTranscoder) {
this.defaultTranscoder = defaultTranscoder;
}
/**
* Retrieves the value stored for the entry that is associated with the specified key. The given decoder is used to convert the stored
* value to the desired type. If no entry for the specified key exists or if the decoder is unable to decode the stored value, then
* `undefined` will be returned.
*
* @param key Identifier of the entry whose value is to be retrieved.
* @param decoder Decoder to use for converting the stored value to the desired return type.
* @returns Value of the entry that is identified by the specified key. In case the entry does not exist or if it cannot be
* loaded (due to a decoding issue), then `undefined` will be returned by this function.
*/
get(key, decoder) {
const value = this.getItem(key);
return value !== undefined ? (decoder !== null && decoder !== void 0 ? decoder : this.defaultTranscoder).decode(value) : undefined;
}
/**
* Creates or updates the entry identified by the specified key with the given value. The specified encoder is used to convert the given
* value into a format that can be stored by the storage service's underlying storage.
*
* Storing a value into the storage service will ensure that an equivalent of the value can be read back, i.e. the data and structure of
* the value will be the same. It, however, does not necessarily return the same reference.
*
* @param key Identifier of the entry which is to be created or updated.
* @param value Value which is to be stored.
* @param encoder Encoder used to convert the given value into a format that can be used for storage.
*/
set(key, value, encoder) {
this.setItem(key, (encoder !== null && encoder !== void 0 ? encoder : this.defaultTranscoder).encode(value));
}
/**
* Creates a new storage service that uses the specified transcoder by default for read and write operations. The new storage service
* uses the storage service on which this function is invoked as underlying storage. Both storage services will thus be able to access
* the same data.
*
* The default transcoder will not be changed for the storage service on which this function is invoked.
*
* @param transcoder Transcoder that should be used by default for read and write operations by the new storage service.
* @returns A new storage service that uses the specified transcoder by default.
*/
withDefaultTranscoder(transcoder) {
return new ProxyStorageService(transcoder, this);
}
}
/** Transcoder that encodes values as JSON strings. */
class JsonStorageTranscoder {
encode(value) {
return JSON.stringify(value);
}
decode(value) {
try {
return JSON.parse(value);
}
catch (error) {
return undefined;
}
}
}
/** Transcoder that encodes/decodes strings **as is**, i.e. values are not modified in any way. */
class StringStorageTranscoder {
encode(value) {
return value;
}
decode(value) {
return value;
}
}
/** Transcoder that encodes/decodes `boolean` values. */
class BooleanStorageTranscoder {
encode(value) {
return value.toString();
}
decode(value) {
if (value === 'true') {
return true;
}
if (value === 'false') {
return false;
}
return undefined;
}
}
/** Transcoder that encodes/decodes `number` values. */
class NumberStorageTranscoder {
encode(value) {
return value.toString();
}
decode(value) {
const parsedNumber = Number(value);
return Number.isFinite(parsedNumber) ? parsedNumber : undefined;
}
}
/** Transcoder that encodes/decodes `Date` values to ISO strings. */
class DateIsoStorageTranscoder {
encode(value) {
return value.toISOString();
}
decode(value) {
const timestamp = Date.parse(value);
return isNaN(timestamp) ? undefined : new Date(timestamp);
}
}
/** Transcoder that encodes/decodes `Date` values to epoch timestamps. */
class DateEpochStorageTranscoder {
encode(value) {
return value.valueOf().toString();
}
decode(value) {
const timestamp = parseInt(value, 10);
return isNaN(timestamp) ? undefined : new Date(timestamp);
}
}
/** A set of storage transcoders. */
const StorageTranscoders = {
/** Transcoder that encodes values as JSON strings. */
JSON: new JsonStorageTranscoder(),
/** Transcoder that encodes/decodes strings **as is**, i.e. values are not modified in any way. */
STRING: new StringStorageTranscoder(),
/** Transcoder that encodes/decodes `boolean` values. */
BOOLEAN: new BooleanStorageTranscoder(),
/** Transcoder that encodes/decodes `number` values. */
NUMBER: new NumberStorageTranscoder(),
/** Transcoder that encodes/decodes `Date` values into ISO strings. */
DATE_ISO_STRING: new DateIsoStorageTranscoder(),
/** Transcoder that encodes/decodes `Date` values into epoch timestamps. */
DATE_EPOCH_TIME: new DateEpochStorageTranscoder(),
};
/**
* A volatile `StorageService` implementation. This service guarantees that data stored will remain available as long as the application
* instance is active. After the application is terminated all data will be lost.
*/
class InMemoryStorageService extends BaseStorageService {
/**
* Creates a new `InMemoryStorageService` instance.
*/
constructor() {
super(StorageTranscoders.JSON);
/** A map that serves as the underlying backing storage for this service. */
this.storage = new Map();
}
/**
* Checks whether an entry with the specified key exists in the storage.
*
* @param key Identifier of the entry for which its presence in the storage is to be checked.
* @returns `true` if an entry with the specified key exists in the storage, `false` if not.
*/
has(key) {
return this.storage.has(key);
}
/**
* Removes the entry that is identified by the specified key. Attempting to remove an entry for an unknown key will have no effect.
* Attempting to retrieve an entry via the `get` method after it has been removed will result in `undefined`.
*
* @param key Identifier of the entry which is to be removed.
*/
remove(key) {
this.storage.delete(key);
}
/**
* Clears the storage by removing all entries. Subsequent `get(x)` calls for a key *x* will return `undefined`, until a new value is set
* for key *x*.
*/
clear() {
this.storage.clear();
}
/**
* Performs the actual retrieval of a value from storage.
*
* @param key Identifier of the entry whose value is to be retrieved.
* @returns The value that is stored for the specified entry or `undefined` if no entry exists for the specified key.
*/
getItem(key) {
if (!this.storage.has(key)) {
return undefined;
}
return this.storage.get(key);
}
/**
* Stores the provided value using specified key in the storage.
*
* @param key Identifier of the entry for which the value is to be stored.
* @param value The value that is to be stored.
*/
setItem(key, value) {
this.storage.set(key, value);
}
}
/**
* An implementation of `StorageService` interface that uses an underlying (web) `Storage` object, such as `localStorage` and
* `sessionStorage`, as backing data store. This class basically wraps the `Storage` object so it can be accessed through the
* `StorageService` interface.
*/
class WebStorageService extends BaseStorageService {
/**
* Creates a new `WebStorageService` instance that uses the specified (web) storage object as underlying backing storage.
*
* @param storage Storage object which is to be wrapped in a class that implements the `StorageService` interface.
*/
constructor(storage) {
super(StorageTranscoders.JSON);
this.storage = storage;
}
/**
* Checks whether an entry with the specified key exists in the storage.
*
* @param key Identifier of the entry for which its presence in the storage is to be checked.
* @returns `true` if an entry with the specified key exists in the storage, `false` if not.
*/
has(key) {
return this.storage.getItem(key) !== null;
}
/**
* Removes the entry that is identified by the specified key. Attempting to remove an entry for an unknown key will have no effect.
* Attempting to retrieve an entry via the `get` method after it has been removed will result in `undefined`.
*
* @param key Identifier of the entry which is to be removed.
*/
remove(key) {
this.storage.removeItem(key);
}
/**
* Clears the storage by removing all entries. Subsequent `get(x)` calls for a key *x* will return `undefined`, until a new value is set
* for key *x*.
*/
clear() {
this.storage.clear();
}
/**
* Performs the actual retrieval of a value from storage.
*
* @param key Identifier of the entry whose value is to be retrieved.
* @returns The value that is stored for the specified entry or `undefined` if no entry exists for the specified key.
*/
getItem(key) {
const value = this.storage.getItem(key);
return value !== null ? value : undefined;
}
/**
* Stores the provided value using specified key in the storage.
*
* @param key Identifier of the entry for which the value is to be stored.
* @param value The value that is to be stored.
*/
setItem(key, value) {
return this.storage.setItem(key, value);
}
}
/**
* Checks whether the specified (web) storage is available and functional. This might not be the case for older browsers. However even
* certain browsers that do support the web storage API can, under some circumstances, have non functional storage objects. For example,
* Safari is known to have `localStorage` and `sessionStorage` throw exceptions in private mode.
*
* @param storage Storage object which is to be tested for availability.
* @returns `true` if the specified storage can be used, `false` if not.
*/
function isStorageAvailable(storage) {
// Check if storage is available.
if (!storage) {
return false;
}
// Check if the storage can actually be accessed.
try {
const now = Date.now();
const testItemKey = `storage-test-entry-${now}`;
const testItemValue = `storage-test-value-${now}`;
storage.setItem(testItemKey, testItemValue);
const retrievedItemValue = storage.getItem(testItemKey);
storage.removeItem(testItemKey);
return retrievedItemValue === testItemValue;
}
catch (error) {
return false;
}
}
/**
* Checks whether session storage is available and functional. This might not be the case for older browsers. However even certain browsers
* that do support the web storage API can, under some circumstances, have non functional storage objects. For example, Safari is known to
* have `sessionStorage` throw exceptions in private mode.
*
* @returns `true` if session storage can be used, `false` if not.
*/
function isSessionStorageAvailable() {
try {
if (typeof sessionStorage !== 'undefined') {
return isStorageAvailable(sessionStorage);
}
}
catch (_a) { }
return false;
}
/**
* Checks whether local storage is available and functional. This might not be the case for older browsers. However even certain browsers
* that do support the web storage API can, under some circumstances, have non functional storage objects. For example, Safari is known to
* have `localStorage` throw exceptions in private mode.
*
* @returns `true` if local storage can be used, `false` if not.
*/
function isLocalStorageAvailable() {
try {
if (typeof localStorage !== 'undefined') {
return isStorageAvailable(localStorage);
}
}
catch (_a) { }
return false;
}
function sessionStorageFactory() {
if (isSessionStorageAvailable()) {
return new WebStorageService(sessionStorage);
}
return new InMemoryStorageService();
}
/** Injection token for the session storage service. */
const SESSION_STORAGE = new InjectionToken('SESSION_STORAGE', { providedIn: 'root', factory: sessionStorageFactory });
function localStorageFactory() {
if (isLocalStorageAvailable()) {
return new WebStorageService(localStorage);
}
return new InMemoryStorageService();
}
/** Injection token for the local storage service. */
const LOCAL_STORAGE = new InjectionToken('LOCAL_STORAGE', { providedIn: 'root', factory: localStorageFactory });
/**
* @deprecated You no longer need to import the `StorageServiceModule`, since the `SESSION_STORAGE` and `LOCAL_STORAGE` injection tokens are
* now 'self providing' in the root injector.
*/
class StorageServiceModule {
}
StorageServiceModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: StorageServiceModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
StorageServiceModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: StorageServiceModule });
StorageServiceModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: StorageServiceModule });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: StorageServiceModule, decorators: [{
type: NgModule
}] });
/**
* Generated bundle index. Do not edit.
*/
export { BaseStorageService, BooleanStorageTranscoder, DateEpochStorageTranscoder, DateIsoStorageTranscoder, InMemoryStorageService, JsonStorageTranscoder, LOCAL_STORAGE, NumberStorageTranscoder, ProxyStorageService, SESSION_STORAGE, StorageServiceModule, StorageTranscoders, StringStorageTranscoder, WebStorageService, isLocalStorageAvailable, isSessionStorageAvailable, isStorageAvailable, localStorageFactory, sessionStorageFactory };
//# sourceMappingURL=ngx-webstorage-service.mjs.map