{"version":3,"file":"larscom-ngrx-signals-storage.mjs","sources":["../../../projects/ngrx-signals-storage/src/lib/ssr.ts","../../../projects/ngrx-signals-storage/src/lib/config.ts","../../../projects/ngrx-signals-storage/src/lib/with-storage.ts","../../../projects/ngrx-signals-storage/src/larscom-ngrx-signals-storage.ts"],"sourcesContent":["export class NoopStorage implements Storage {\n  length = -1\n  clear = () => {}\n  getItem = (_key: string) => null\n  key = (_index: number) => null\n  removeItem = (_key: string) => {}\n  setItem = (_key: string, _value: string) => {}\n}\n\nfunction isBrowser() {\n  return typeof window !== 'undefined'\n}\n\n/**\n * Helper function for SSR (Server Side Rendered) apps to get a storage location.\n *\n * @example\n *  export const CounterStore = signalStore(\n *     withState({\n *       count: 0\n *     }),\n *     withStorage('myKey', getStorage('sessionStorage'))\n *   )\n *\n * Check out github for more information.\n * @see https://github.com/larscom/ngrx-signals-storage\n */\nexport function getStorage(storageType: 'localStorage' | 'sessionStorage'): Storage {\n  switch (storageType) {\n    case 'localStorage': {\n      return isBrowser() ? window.localStorage : new NoopStorage()\n    }\n    case 'sessionStorage': {\n      return isBrowser() ? window.sessionStorage : new NoopStorage()\n    }\n    default: {\n      return new NoopStorage()\n    }\n  }\n}\n","export interface Config<T> {\n  /**\n   * These keys will not get saved to storage\n   */\n  excludeKeys: Array<keyof T>\n\n  /**\n   * Serializer for the state, by default it uses `JSON.stringify()`\n   * @param state the last state known before it gets saved to storage\n   */\n  serialize: (state: T) => string\n\n  /**\n   * Deserializer for the state, by default it uses `JSON.parse()`\n   * @param state the last state known from the storage location\n   */\n  deserialize: (state: string) => T\n\n  /**\n   * Save to storage will only occur when this function returns true\n   * @param state the last state known before it gets saved to storage\n   */\n  saveIf: (state: T) => boolean\n\n  /**\n   * Function that gets executed on a storage error (get/set)\n   * @param error the error that occurred\n   */\n  error: (error: any) => void\n}\n\nexport const defaultConfig: Config<any> = {\n  excludeKeys: [],\n\n  serialize: (state: any) => JSON.stringify(state),\n\n  deserialize: (state: string) => JSON.parse(state),\n\n  saveIf: (state: any) => true,\n\n  error: (error: any) => console.error(error)\n}\n","import { effect } from '@angular/core'\nimport { EmptyFeatureResult, SignalStoreFeature, SignalStoreFeatureResult, getState, patchState } from '@ngrx/signals'\nimport { Config, defaultConfig } from './config'\n\n/**\n * The `withStorage` function that lets you save the state to localstorage/sessionstorage\n * and rehydrate the state upon page load.\n *\n * @param key the key under which the state should be saved into `Storage`\n * @param storage an implementation of the `Storage` interface, like: `sessionStorage` or `localStorage`\n *\n * @example\n *  // for apps *without* SSR (Server Side Rendering)\n *  export const CounterStore = signalStore(\n *     withState({\n *       count: 0\n *     }),\n *     withStorage('myKey', sessionStorage)\n *   )\n *\n * @example\n *  // for apps *with* SSR (Server Side Rendering)\n *  export const CounterStore = signalStore(\n *     withState({\n *       count: 0\n *     }),\n *     withStorage('myKey', getStorage('sessionStorage'))\n *   )\n *\n * Check out github for more information.\n * @see https://github.com/larscom/ngrx-signals-storage\n */\nexport function withStorage<State extends SignalStoreFeatureResult>(\n  key: string,\n  storage: Storage,\n  config?: Partial<Config<State['state']>>\n): SignalStoreFeature<State, EmptyFeatureResult> {\n  const cfg = { ...defaultConfig, ...config }\n\n  const item = getFromStorage(key, storage, cfg)\n  const storageState: State['state'] | null = item ? cfg.deserialize(item) : null\n\n  let hydrated = false\n\n  return (store) => {\n    if (storageState != null && !hydrated) {\n      const stateSignals = store['stateSignals']\n      const stateSignalKeys = Object.keys(stateSignals)\n      const state = stateSignalKeys.reduce((state, key) => {\n        const value = storageState[key as keyof State['state']]\n        return value\n          ? {\n              ...state,\n              [key]: value\n            }\n          : state\n      }, getState(store))\n\n      patchState(store, state)\n      hydrated = true\n    }\n\n    effect(() => {\n      const state = structuredClone(getState(store))\n      try {\n        if (cfg.saveIf(state)) {\n          cfg.excludeKeys.forEach((key) => {\n            delete state[key as keyof State['state']]\n          })\n          storage.setItem(key, cfg.serialize(state))\n        }\n      } catch (e) {\n        cfg.error(e)\n      }\n    })\n\n    return store\n  }\n}\n\nfunction getFromStorage<State extends SignalStoreFeatureResult>(\n  key: string,\n  storage: Storage,\n  cfg: Config<State>\n): string | null {\n  try {\n    return storage.getItem(key)\n  } catch (e) {\n    cfg.error(e)\n    return null\n  }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}