import pRetry$1 from "../node_modules/.pnpm/p-retry@7.1.1/node_modules/p-retry/index.js";
import PQueue from "../node_modules/.pnpm/p-queue@9.1.0/node_modules/p-queue/dist/index.js";
import { _getFetchImplementation } from "../singletons/fetch.js";
//#region src/utils/async_caller.ts
/**
* `p-retry` is a pure-ESM module that we bundle into the build output (so the
* CJS artifact doesn't `require()` an ESM module). Depending on how a
* downstream transpiler/bundler (e.g. `tsx`/esbuild) resolves the default
* export of the bundled chunk, the import can come through either as the
* function itself or as a namespace-like `{ default: fn }`. Normalize to the
* callable, mirroring the `"default" in` interop guard used for `p-queue`.
*/
const pRetry = typeof pRetry$1 === "function" ? pRetry$1 : pRetry$1.default;
const STATUS_NO_RETRY = [
	400,
	401,
	402,
	403,
	404,
	405,
	406,
	407,
	408,
	409,
	422
];
/**
* Do not rely on globalThis.Response, rather just
* do duck typing
*/
function isResponse(x) {
	if (x == null || typeof x !== "object") return false;
	return "status" in x && "statusText" in x && "text" in x;
}
/**
* Utility error to properly handle failed requests
*/
var HTTPError = class HTTPError extends Error {
	status;
	text;
	response;
	constructor(status, message, response) {
		super(`HTTP ${status}: ${message}`);
		this.status = status;
		this.text = message;
		this.response = response;
	}
	static async fromResponse(response, options) {
		try {
			return new HTTPError(response.status, await response.text(), options?.includeResponse ? response : void 0);
		} catch {
			return new HTTPError(response.status, response.statusText, options?.includeResponse ? response : void 0);
		}
	}
};
/**
* A class that can be used to make async calls with concurrency and retry logic.
*
* This is useful for making calls to any kind of "expensive" external resource,
* be it because it's rate-limited, subject to network issues, etc.
*
* Concurrent calls are limited by the `maxConcurrency` parameter, which defaults
* to `Infinity`. This means that by default, all calls will be made in parallel.
*
* Retries are limited by the `maxRetries` parameter, which defaults to 5. This
* means that by default, each call will be retried up to 5 times, with an
* exponential backoff between each attempt.
*/
var AsyncCaller = class {
	maxConcurrency;
	maxRetries;
	queue;
	onFailedResponseHook;
	customFetch;
	constructor(params) {
		this.maxConcurrency = params.maxConcurrency ?? Infinity;
		this.maxRetries = params.maxRetries ?? 4;
		if ("default" in PQueue) this.queue = new PQueue.default({ concurrency: this.maxConcurrency });
		else this.queue = new PQueue({ concurrency: this.maxConcurrency });
		this.onFailedResponseHook = params?.onFailedResponseHook;
		this.customFetch = params.fetch;
	}
	call(callable, ...args) {
		const { onFailedResponseHook } = this;
		return this.queue.add(() => pRetry(() => callable(...args).catch(async (error) => {
			if (error instanceof Error) throw error;
			else if (isResponse(error)) throw await HTTPError.fromResponse(error, { includeResponse: !!onFailedResponseHook });
			else throw new Error(error);
		}), {
			async onFailedAttempt({ error, retriesLeft }) {
				const errorMessage = error.message ?? "";
				if (errorMessage.startsWith("Cancel") || errorMessage.startsWith("TimeoutError") || errorMessage.startsWith("AbortError")) throw error;
				if (error?.code === "ECONNABORTED") throw error;
				if (errorMessage.includes("ECONNREFUSED") || errorMessage.includes("fetch failed") || errorMessage.includes("Failed to fetch") || errorMessage.includes("NetworkError")) {
					if (retriesLeft > 0) return;
					const connectionError = /* @__PURE__ */ new Error(`Unable to connect to LangGraph server. Please ensure the server is running and accessible. Original error: ${errorMessage}`);
					connectionError.name = "ConnectionError";
					throw connectionError;
				}
				if (error instanceof HTTPError) {
					if (STATUS_NO_RETRY.includes(error.status)) throw error;
					if (onFailedResponseHook && error.response) await onFailedResponseHook(error.response);
				}
			},
			retries: this.maxRetries,
			randomize: true
		}), { throwOnTimeout: true });
	}
	callWithOptions(options, callable, ...args) {
		if (options.signal) return Promise.race([this.call(callable, ...args), new Promise((_, reject) => {
			options.signal?.addEventListener("abort", () => {
				reject(/* @__PURE__ */ new Error("AbortError"));
			});
		})]);
		return this.call(callable, ...args);
	}
	fetch(...args) {
		const fetchFn = this.customFetch ?? _getFetchImplementation();
		return this.call(() => fetchFn(...args).then((res) => res.ok ? res : Promise.reject(res)));
	}
};
//#endregion
export { AsyncCaller };

//# sourceMappingURL=async_caller.js.map