{"version":3,"file":"pinia-cache.mjs","sources":["../src/pinia-cache.ts"],"sourcesContent":["import { markRaw } from 'vue-demi'\nimport {\n  _GettersTree,\n  PiniaPluginContext,\n  StateTree,\n  Store,\n  StoreDefinition,\n} from 'pinia'\nimport 'pinia'\n\ntype CacheOptions = {\n  timeout?: number\n}\n\ntype Payload = unknown | Record<string, unknown>\n\ndeclare module 'pinia' {\n  export interface PiniaCustomProperties {\n    cache: Cache\n  }\n\n  export interface DefineStoreOptionsBase<S, Store> {\n    cache?: CacheOptions\n  }\n}\n\nfunction isObject(value: unknown): boolean {\n  return !!value && typeof value === 'object'\n}\n\nfunction isPromise(value: unknown): boolean {\n  return !!value && value instanceof Promise\n}\n\nfunction toString(value: unknown): string {\n  return isObject(value) ? JSON.stringify(value) : String(value)\n}\n\n/**\n * Generate key from Dispatch parameters.\n */\nfunction generateKey(action: string, payload?: Payload): string | null {\n  try {\n    return `${action}:${toString(payload)}`\n  } catch (_) {\n    return null\n  }\n}\n\n/**\n * Check if value has timeout property.\n */\nconst hasTimeout = (value: unknown): boolean => {\n  return isObject(value) && typeof (value as CacheOptions).timeout === 'number'\n}\n\n/**\n * Check if value (time) is expired.\n */\nconst isExpired = (expiresIn: number): boolean => {\n  return expiresIn && Date.now() > expiresIn\n}\n\ntype CacheRecord = {\n  expiresIn: number\n  value: Promise<unknown>\n}\n\nclass Cache {\n  private _state: Map<string, CacheRecord> = new Map()\n\n  private readonly _store: Store\n  private readonly _options: CacheOptions\n\n  constructor(store: Store, options: CacheOptions) {\n    this._store = store\n    this._options = options\n  }\n\n  /**\n   * Resolve timeout from parameters and plugin options.\n   */\n  private resolveTimeout(dispatchOptions: CacheOptions = {}): number {\n    if (hasTimeout(dispatchOptions)) {\n      return dispatchOptions.timeout\n    } else if (hasTimeout(this._options)) {\n      return this._options.timeout\n    }\n    return 0\n  }\n\n  /**\n   * Dispatch an action and set it on cache.\n   * @param {String} action\n   * @param {?any} payload\n   * @param {?any} options\n   * @returns {Promise<any>}\n   */\n  dispatch(action: string, payload?: Payload, options?: CacheOptions) {\n    const entry = this._store[action]\n    if (!entry) {\n      throw new Error(`[pinia-cache] unknown action: ${action}`)\n    }\n\n    const key = generateKey(action, payload)\n    if (key === null) {\n      // Fallback on generateKey errors.\n      return entry.call(this._store, payload)\n    }\n\n    const { value: cachedValue, expiresIn } = this._state.get(key) || {}\n    if (!!cachedValue && !isExpired(expiresIn)) {\n      return cachedValue\n    }\n\n    let result = entry.call(this._store, payload)\n    if (!isPromise(result)) {\n      result = Promise.resolve(result)\n    }\n\n    const timeout = this.resolveTimeout(options)\n\n    const record = {\n      expiresIn: timeout ? Date.now() + timeout : undefined,\n      value: new Promise((resolve, reject) => {\n        result.then(\n          (res) => resolve(res),\n          (error) => {\n            this._state.delete(key)\n            reject(error)\n          },\n        )\n      }),\n    }\n\n    this._state.set(key, record)\n\n    return record.value\n  }\n\n  /**\n   * Check if an action dispatch is on cache.\n   * @param {String} action\n   * @param {?any} payload\n   * * @returns {boolean}\n   */\n  has(action: string, payload?: Payload): boolean {\n    const key = generateKey(action, payload)\n\n    if (key === null) {\n      // Fallback on generateKey errors.\n      return false\n    }\n\n    const record = this._state.get(key)\n    return isObject(record) && !isExpired(record.expiresIn)\n  }\n\n  /**\n   * Clear cache. Returns `true` if cache was cleared and `false` otherwise.\n   * If using the type parameter, only actions with the specified type are\n   * deleted from cache and the number of deleted keys is returned.\n   */\n  clear(action?: string): boolean {\n    if (action) {\n      return Array.from(this._state.keys())\n        .filter((key) => key.split(':')[0] === action)\n        .reduce((done, key) => this._state.delete(key) || done, false)\n    }\n\n    this._state.clear()\n    return true\n  }\n\n  /**\n   * Delete an action dispatch from cache. Returns `true` if it was deleted\n   * and `false` otherwise.\n   */\n  delete(action: string, payload?: Payload): boolean {\n    const key = generateKey(action, payload)\n\n    if (key === null) {\n      // Fallback on generateKey errors.\n      return false\n    }\n\n    return this._state.delete(key)\n  }\n\n  state() {\n    return this._state\n  }\n}\n\nexport type MapCacheActionsReturn<A> = {\n  [key in keyof A]: A[key]\n}\n\nexport type MapCacheActionsObjectReturn<\n  A,\n  T extends Record<string, keyof A>,\n> = {\n  [key in keyof T]: A[T[key]]\n}\n\nexport function mapCacheActions<\n  Id extends string,\n  S extends StateTree,\n  G extends _GettersTree<S>,\n  A,\n  KeyMapper extends Record<string, keyof A>,\n>(\n  useStore: StoreDefinition<Id, S, G, A>,\n  keysOrMapper: KeyMapper,\n): MapCacheActionsObjectReturn<A, KeyMapper>\n\nexport function mapCacheActions<\n  Id extends string,\n  S extends StateTree,\n  G extends _GettersTree<S>,\n  A,\n>(\n  useStore: StoreDefinition<Id, S, G, A>,\n  keys: Array<keyof A>,\n): MapCacheActionsReturn<A>\n\nexport function mapCacheActions<\n  Id extends string,\n  S extends StateTree,\n  G extends _GettersTree<S>,\n  A,\n  KeyMapper extends Record<string, keyof A>,\n>(\n  useStore: StoreDefinition<Id, S, G, A>,\n  keysOrMapper: KeyMapper,\n): MapCacheActionsReturn<A> | MapCacheActionsObjectReturn<A, KeyMapper> {\n  return Array.isArray(keysOrMapper)\n    ? keysOrMapper.reduce((reduced, key) => {\n        reduced[key] = function (...args) {\n          return useStore(this.$pinia).cache.dispatch(key, ...args)\n        }\n        return reduced\n      }, {})\n    : Object.keys(keysOrMapper).reduce((reduced, key) => {\n        reduced[key] = function (...args) {\n          const action = keysOrMapper[key] as string\n          const cache = useStore(this.$pinia).cache\n\n          return cache.dispatch(action, ...args)\n        }\n        return reduced\n      }, {})\n}\n\nexport function piniaCachePlugin(context: PiniaPluginContext) {\n  const cacheOptions = context.options.cache ?? {}\n  context.store.cache = markRaw(new Cache(context.store, cacheOptions))\n}\n"],"names":[],"mappings":"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"}