{"version":3,"file":"retryer.cjs","names":["onlineManager","noop","focusManager","isServerEnvironment"],"sources":["../../src/retryer.ts"],"sourcesContent":["import { focusManager } from './focusManager'\nimport { onlineManager } from './onlineManager'\nimport { isServer as isServerEnvironment } from './environmentManager'\nimport { noop, sleep } from './utils'\nimport type { CancelOptions, DefaultError, NetworkMode } from './types'\n\n// TYPES\n\ninterface RetryerConfig<TData = unknown, TError = DefaultError> {\n  fn: () => TData | Promise<TData>\n  initialPromise?: Promise<TData>\n  onCancel?: (error: TError) => void\n  onFail?: (failureCount: number, error: TError) => void\n  onPause?: () => void\n  onContinue?: () => void\n  retry?: RetryValue<TError>\n  retryDelay?: RetryDelayValue<TError>\n  networkMode: NetworkMode | undefined\n  canRun: () => boolean\n}\n\nexport interface Retryer<TData = unknown> {\n  promise: Promise<TData>\n  cancel: (cancelOptions?: CancelOptions) => void\n  continue: () => Promise<unknown>\n  cancelRetry: () => void\n  continueRetry: () => void\n  canStart: () => boolean\n  start: () => Promise<TData>\n  status: () => 'pending' | 'resolved' | 'rejected'\n}\n\ntype RetryerStatus = 'pending' | 'resolved' | 'rejected'\n\nexport type RetryValue<TError> = boolean | number | ShouldRetryFunction<TError>\n\ntype ShouldRetryFunction<TError = DefaultError> = (\n  failureCount: number,\n  error: TError,\n) => boolean\n\nexport type RetryDelayValue<TError> = number | RetryDelayFunction<TError>\n\ntype RetryDelayFunction<TError = DefaultError> = (\n  failureCount: number,\n  error: TError,\n) => number\n\nfunction defaultRetryDelay(failureCount: number) {\n  return Math.min(1000 * 2 ** failureCount, 30000)\n}\n\nexport function canFetch(networkMode: NetworkMode | undefined): boolean {\n  return (networkMode ?? 'online') === 'online'\n    ? onlineManager.isOnline()\n    : true\n}\n\nexport class CancelledError extends Error {\n  revert?: boolean\n  silent?: boolean\n  constructor(options?: CancelOptions) {\n    super('CancelledError')\n    this.revert = options?.revert\n    this.silent = options?.silent\n  }\n}\n\n/**\n * @deprecated Use instanceof `CancelledError` instead.\n */\nexport function isCancelledError(value: any): value is CancelledError {\n  return value instanceof CancelledError\n}\n\nexport function createRetryer<TData = unknown, TError = DefaultError>(\n  config: RetryerConfig<TData, TError>,\n): Retryer<TData> {\n  let isRetryCancelled = false\n  let failureCount = 0\n  let continueFn: ((value?: unknown) => void) | undefined\n  let status: RetryerStatus = 'pending'\n  let promiseResolve: (data: TData) => void\n  let promiseReject: (error: TError) => void\n\n  const promise = new Promise<TData>((resolve, reject) => {\n    promiseResolve = resolve\n    promiseReject = reject\n  })\n  promise.catch(noop)\n\n  const isResolved = () => status !== 'pending'\n\n  const cancel = (cancelOptions?: CancelOptions): void => {\n    if (!isResolved()) {\n      const error = new CancelledError(cancelOptions) as TError\n      reject(error)\n\n      config.onCancel?.(error)\n    }\n  }\n  const cancelRetry = () => {\n    isRetryCancelled = true\n  }\n\n  const continueRetry = () => {\n    isRetryCancelled = false\n  }\n\n  const canContinue = () =>\n    focusManager.isFocused() &&\n    (config.networkMode === 'always' || onlineManager.isOnline()) &&\n    config.canRun()\n\n  const canStart = () => canFetch(config.networkMode) && config.canRun()\n\n  const resolve = (value: any) => {\n    if (!isResolved()) {\n      continueFn?.()\n      status = 'resolved'\n      promiseResolve(value)\n    }\n  }\n\n  const reject = (value: any) => {\n    if (!isResolved()) {\n      continueFn?.()\n      status = 'rejected'\n      promiseReject(value)\n    }\n  }\n\n  const pause = () => {\n    return new Promise((continueResolve) => {\n      continueFn = (value) => {\n        if (isResolved() || canContinue()) {\n          continueResolve(value)\n        }\n      }\n      config.onPause?.()\n    }).then(() => {\n      continueFn = undefined\n      if (!isResolved()) {\n        config.onContinue?.()\n      }\n    })\n  }\n\n  // Create loop function\n  const run = () => {\n    // Do nothing if already resolved\n    if (isResolved()) {\n      return\n    }\n\n    let promiseOrValue: any\n\n    // we can re-use config.initialPromise on the first call of run()\n    const initialPromise =\n      failureCount === 0 ? config.initialPromise : undefined\n\n    // Execute query\n    try {\n      promiseOrValue = initialPromise ?? config.fn()\n    } catch (error) {\n      promiseOrValue = Promise.reject(error)\n    }\n\n    Promise.resolve(promiseOrValue)\n      .then(resolve)\n      .catch((error) => {\n        // Stop if the fetch is already resolved\n        if (isResolved()) {\n          return\n        }\n\n        // Do we need to retry the request?\n        const retry = config.retry ?? (isServerEnvironment() ? 0 : 3)\n        const retryDelay = config.retryDelay ?? defaultRetryDelay\n        const delay =\n          typeof retryDelay === 'function'\n            ? retryDelay(failureCount, error)\n            : retryDelay\n        const shouldRetry =\n          retry === true ||\n          (typeof retry === 'number' && failureCount < retry) ||\n          (typeof retry === 'function' && retry(failureCount, error))\n\n        if (isRetryCancelled || !shouldRetry) {\n          // We are done if the query does not need to be retried\n          reject(error)\n          return\n        }\n\n        failureCount++\n\n        // Notify on fail\n        config.onFail?.(failureCount, error)\n\n        // Delay\n        sleep(delay)\n          // Pause if the document is not visible or when the device is offline\n          .then(() => {\n            return canContinue() ? undefined : pause()\n          })\n          .then(() => {\n            if (isRetryCancelled) {\n              reject(error)\n            } else {\n              run()\n            }\n          })\n      })\n  }\n\n  return {\n    promise,\n    status: () => status,\n    cancel,\n    continue: () => {\n      continueFn?.()\n      return promise\n    },\n    cancelRetry,\n    continueRetry,\n    canStart,\n    start: () => {\n      // Start loop\n      if (canStart()) {\n        run()\n      } else {\n        pause().then(run)\n      }\n      return promise\n    },\n  }\n}\n"],"mappings":"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"}