{"version":3,"file":"async_caller.cjs","names":["PQueueMod","_getFetchImplementation"],"sources":["../../src/utils/async_caller.ts"],"sourcesContent":["import pRetry from \"p-retry\";\nimport PQueueMod from \"p-queue\";\nimport { _getFetchImplementation } from \"../singletons/fetch.js\";\n\nconst STATUS_NO_RETRY = [\n  400, // Bad Request\n  401, // Unauthorized\n  402, // Payment required\n  403, // Forbidden\n  404, // Not Found\n  405, // Method Not Allowed\n  406, // Not Acceptable\n  407, // Proxy Authentication Required\n  408, // Request Timeout\n  409, // Conflict\n  422, // Unprocessable Entity\n];\n\ntype ResponseCallback = (response?: Response) => Promise<boolean>;\n\nexport interface AsyncCallerParams {\n  /**\n   * The maximum number of concurrent calls that can be made.\n   * Defaults to `Infinity`, which means no limit.\n   */\n  maxConcurrency?: number;\n  /**\n   * The maximum number of retries that can be made for a single call,\n   * with an exponential backoff between each attempt. Defaults to 6.\n   */\n  maxRetries?: number;\n\n  onFailedResponseHook?: ResponseCallback;\n\n  /**\n   * Specify a custom fetch implementation.\n   *\n   * By default we expect the `fetch` is available in the global scope.\n   */\n  fetch?: typeof fetch | ((...args: any[]) => any); // eslint-disable-line @typescript-eslint/no-explicit-any\n}\n\nexport interface AsyncCallerCallOptions {\n  signal?: AbortSignal;\n}\n\n/**\n * Do not rely on globalThis.Response, rather just\n * do duck typing\n */\nfunction isResponse(x: unknown): x is Response {\n  if (x == null || typeof x !== \"object\") return false;\n  return \"status\" in x && \"statusText\" in x && \"text\" in x;\n}\n\n/**\n * Utility error to properly handle failed requests\n */\nclass HTTPError extends Error {\n  status: number;\n\n  text: string;\n\n  response?: Response;\n\n  constructor(status: number, message: string, response?: Response) {\n    super(`HTTP ${status}: ${message}`);\n    this.status = status;\n    this.text = message;\n    this.response = response;\n  }\n\n  static async fromResponse(\n    response: Response,\n    options?: { includeResponse?: boolean }\n  ): Promise<HTTPError> {\n    try {\n      return new HTTPError(\n        response.status,\n        await response.text(),\n        options?.includeResponse ? response : undefined\n      );\n    } catch {\n      return new HTTPError(\n        response.status,\n        response.statusText,\n        options?.includeResponse ? response : undefined\n      );\n    }\n  }\n}\n\n/**\n * A class that can be used to make async calls with concurrency and retry logic.\n *\n * This is useful for making calls to any kind of \"expensive\" external resource,\n * be it because it's rate-limited, subject to network issues, etc.\n *\n * Concurrent calls are limited by the `maxConcurrency` parameter, which defaults\n * to `Infinity`. This means that by default, all calls will be made in parallel.\n *\n * Retries are limited by the `maxRetries` parameter, which defaults to 5. This\n * means that by default, each call will be retried up to 5 times, with an\n * exponential backoff between each attempt.\n */\nexport class AsyncCaller {\n  protected maxConcurrency: AsyncCallerParams[\"maxConcurrency\"];\n\n  protected maxRetries: AsyncCallerParams[\"maxRetries\"];\n\n  private queue: (typeof import(\"p-queue\"))[\"default\"][\"prototype\"];\n\n  private onFailedResponseHook?: ResponseCallback;\n\n  private customFetch?: typeof fetch;\n\n  constructor(params: AsyncCallerParams) {\n    this.maxConcurrency = params.maxConcurrency ?? Infinity;\n    this.maxRetries = params.maxRetries ?? 4;\n\n    if (\"default\" in PQueueMod) {\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      this.queue = new (PQueueMod.default as any)({\n        concurrency: this.maxConcurrency,\n      });\n    } else {\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      this.queue = new (PQueueMod as any)({ concurrency: this.maxConcurrency });\n    }\n    this.onFailedResponseHook = params?.onFailedResponseHook;\n    this.customFetch = params.fetch;\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  call<A extends any[], T extends (...args: A) => Promise<any>>(\n    callable: T,\n    ...args: Parameters<T>\n  ): Promise<Awaited<ReturnType<T>>> {\n    const { onFailedResponseHook } = this;\n    return this.queue.add(\n      () =>\n        pRetry(\n          () =>\n            callable(...(args as Parameters<T>)).catch(async (error) => {\n              // eslint-disable-next-line no-instanceof/no-instanceof\n              if (error instanceof Error) {\n                throw error;\n              } else if (isResponse(error)) {\n                throw await HTTPError.fromResponse(error, {\n                  includeResponse: !!onFailedResponseHook,\n                });\n              } else {\n                throw new Error(error);\n              }\n            }),\n          {\n            async onFailedAttempt({ error, retriesLeft }) {\n              const errorMessage = error.message ?? \"\";\n              if (\n                errorMessage.startsWith(\"Cancel\") ||\n                errorMessage.startsWith(\"TimeoutError\") ||\n                errorMessage.startsWith(\"AbortError\")\n              ) {\n                throw error;\n              }\n              // eslint-disable-next-line @typescript-eslint/no-explicit-any\n              if ((error as any)?.code === \"ECONNABORTED\") {\n                throw error;\n              }\n\n              // Check for connection refused errors (server not running)\n              if (\n                errorMessage.includes(\"ECONNREFUSED\") ||\n                errorMessage.includes(\"fetch failed\") ||\n                errorMessage.includes(\"Failed to fetch\") ||\n                errorMessage.includes(\"NetworkError\")\n              ) {\n                if (retriesLeft > 0) return;\n                const connectionError = new Error(\n                  `Unable to connect to LangGraph server. Please ensure the server is running and accessible. Original error: ${errorMessage}`\n                );\n                connectionError.name = \"ConnectionError\";\n                throw connectionError;\n              }\n\n              // eslint-disable-next-line no-instanceof/no-instanceof\n              if (error instanceof HTTPError) {\n                if (STATUS_NO_RETRY.includes(error.status)) {\n                  throw error;\n                }\n                if (onFailedResponseHook && error.response) {\n                  await onFailedResponseHook(error.response);\n                }\n              }\n            },\n            // If needed we can change some of the defaults here,\n            // but they're quite sensible.\n            retries: this.maxRetries,\n            randomize: true,\n          }\n        ),\n      { throwOnTimeout: true }\n    );\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  callWithOptions<A extends any[], T extends (...args: A) => Promise<any>>(\n    options: AsyncCallerCallOptions,\n    callable: T,\n    ...args: Parameters<T>\n  ): Promise<Awaited<ReturnType<T>>> {\n    // Note this doesn't cancel the underlying request,\n    // when available prefer to use the signal option of the underlying call\n    if (options.signal) {\n      return Promise.race([\n        this.call<A, T>(callable, ...args),\n        new Promise<never>((_, reject) => {\n          options.signal?.addEventListener(\"abort\", () => {\n            reject(new Error(\"AbortError\"));\n          });\n        }),\n      ]);\n    }\n    return this.call<A, T>(callable, ...args);\n  }\n\n  fetch(...args: Parameters<typeof fetch>): ReturnType<typeof fetch> {\n    const fetchFn =\n      this.customFetch ?? (_getFetchImplementation() as typeof fetch);\n    return this.call(() =>\n      fetchFn(...args).then((res) => (res.ok ? res : Promise.reject(res)))\n    );\n  }\n}\n"],"mappings":"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"}