@langchain/langgraph-sdk
Version:
Client library for interacting with the LangGraph API
69 lines (68 loc) • 2.97 kB
JavaScript
//#region src/client/stream/transport/utils.ts
const isRecord = (value) => typeof value === "object" && value !== null;
/**
* True for a 4xx HTTP error other than 408 (Request Timeout) and 429
* (Too Many Requests): retrying the same request cannot succeed. Errors
* with no `status` (network errors, idle timeouts, server closes) stay
* retryable.
*/
function isNonRetryableHttpError(error) {
if (!isRecord(error) || typeof error.status !== "number") return false;
const { status } = error;
return status >= 400 && status < 500 && status !== 408 && status !== 429;
}
/**
* Resolve a {@link ProtocolPath} against the transport's currently-bound
* thread.
*
* - a fixed `string` is trusted and used verbatim, with no encoding
* (back-compat: a baked path is independent of the bound thread);
* - a function path and the default fallback are evaluated against
* `threadId`, so late-bound / re-bound adapters target the right thread.
*
* Throws when neither a fixed path nor a bound thread is available — i.e.
* a request was attempted before `client.threads.stream(threadId, …)` /
* {@link TransportAdapter.setThreadId} bound a thread.
*/
function resolveProtocolPath(path, threadId, fallback) {
if (typeof path === "string") return path;
if (!threadId) throw new Error("Protocol transport has no bound threadId. Bind one — the framework calls client.threads.stream(threadId, { transport }) / transport.setThreadId(threadId) — before issuing requests.");
return path ? path(threadId) : fallback(threadId);
}
/** Match {@link BaseClient.prepareFetchOptions}: preserve any apiUrl path prefix. */
const toAbsoluteUrl = (apiUrl, path) => new URL(`${apiUrl.replace(/\/$/, "")}${path}`);
const toError = (error) => error instanceof Error ? error : new Error(String(error));
const toWebSocketUrl = (apiUrl) => {
const url = new URL(apiUrl);
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
url.search = "";
url.hash = "";
return url.toString();
};
const hasHeaders = (headers) => Object.values(headers ?? {}).some((value) => value != null);
function mergeHeaders(...headerGroups) {
const merged = new Headers();
for (const group of headerGroups) {
if (!group) continue;
if (group instanceof Headers) {
group.forEach((value, key) => {
merged.set(key, value);
});
continue;
}
if (Array.isArray(group)) {
for (const [key, value] of group) if (value == null) merged.delete(key);
else merged.set(key, value);
continue;
}
for (const [key, value] of Object.entries(group)) if (value == null) merged.delete(key);
else merged.set(key, value);
}
return merged;
}
function isProtocolResponse(value) {
return isRecord(value) && typeof value.type === "string" && (value.type === "success" || value.type === "error");
}
//#endregion
export { hasHeaders, isNonRetryableHttpError, isProtocolResponse, isRecord, mergeHeaders, resolveProtocolPath, toAbsoluteUrl, toError, toWebSocketUrl };
//# sourceMappingURL=utils.js.map