UNPKG

@idiosync/react-observable

Version:

State management control layer for React projects

94 lines (93 loc) 3.96 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.persistentObservables = void 0; exports.createPersistentObservable = createPersistentObservable; const observable_1 = require("./observable"); const general_1 = require("../utils/general"); const create_store_1 = require("../store/create-store"); exports.persistentObservables = []; const defaultMergeOnHydration = (initialValue, persisted) => { if (!(0, general_1.isPlainObject)(initialValue)) { return persisted; } return { ...initialValue, ...(persisted !== null && persisted !== void 0 ? persisted : {}) }; }; function createPersistentObservable({ name, initialValue, equalityFn, mergeOnHydration = defaultMergeOnHydration, }) { let _persistentStorage = create_store_1.persistentStorage$.get(); if (!_persistentStorage) { create_store_1.persistentStorage$.subscribeOnce((persistentStorage) => { _persistentStorage = persistentStorage; }); } const base = (0, observable_1.createObservable)({ initialValue, name }); const _setInternal = (isSilent) => (newValue, stack) => { const observableName = base.getName(); if (!observableName || observableName === base.getId()) { throw new Error('Persistent observable name is required for set.'); } const value = base.get(); const reducedValue = (0, general_1.isFunction)(newValue) ? newValue(value) : newValue; if ((equalityFn && !equalityFn(value, reducedValue)) || value === reducedValue) { return false; } // Set the value locally first const wasSet = isSilent ? base.setSilent(reducedValue) : base.set(reducedValue); if (_persistentStorage && wasSet) { // Handle async setItem without making the setter async _persistentStorage .setItem(observableName, JSON.stringify(reducedValue)) .catch((error) => { // Log the error but don't throw since setter is synchronous console.error(`Failed to persist value to storage for ${observableName}:`, error); }); } return wasSet; }; const setSilent = _setInternal(true); const set = _setInternal(false); const rehydrate = () => new Promise((resolve, reject) => { if (!_persistentStorage) { reject(new Error('Trying to rehydrate a persistent observable without a persistent storage.')); return; } const observableName = base.getName(); if (!observableName || observableName === base.getId()) { reject(new Error('Persistent observable name is required for rehydration.')); return; } _persistentStorage .getItem(observableName) .then((value) => { if (value) { try { const persisted = JSON.parse(value); const data = mergeOnHydration ? mergeOnHydration(base.getInitialValue(), persisted) : persisted; base.set(data); } catch (error) { // If JSON parsing fails, reject so library can handle reject(new Error(`Failed to parse stored value for ${observableName}: ${error}`)); return; } } resolve(); }) .catch((error) => reject(new Error(`Failed to get value from storage for ${observableName}: ${error instanceof Error ? error.message : error}`))); }); const reset = () => set(base.getInitialValue()); const observable = { ...base, set, setSilent, rehydrate, reset, }; exports.persistentObservables[exports.persistentObservables.length] = observable; return observable; }