Files
Moltbot/src/infra/provider-usage.fetch.shared.ts

61 lines
1.7 KiB
TypeScript

import { PROVIDER_LABELS } from "./provider-usage.shared.js";
import type { ProviderUsageSnapshot, UsageProviderId } from "./provider-usage.types.js";
export async function fetchJson(
url: string,
init: RequestInit,
timeoutMs: number,
fetchFn: typeof fetch,
): Promise<Response> {
const controller = new AbortController();
const timer = setTimeout(controller.abort.bind(controller), timeoutMs);
try {
return await fetchFn(url, { ...init, signal: controller.signal });
} finally {
clearTimeout(timer);
}
}
export function parseFiniteNumber(value: unknown): number | undefined {
if (typeof value === "number" && Number.isFinite(value)) {
return value;
}
if (typeof value === "string") {
const parsed = Number.parseFloat(value);
if (Number.isFinite(parsed)) {
return parsed;
}
}
return undefined;
}
type BuildUsageHttpErrorSnapshotOptions = {
provider: UsageProviderId;
status: number;
message?: string;
tokenExpiredStatuses?: readonly number[];
};
export function buildUsageErrorSnapshot(
provider: UsageProviderId,
error: string,
): ProviderUsageSnapshot {
return {
provider,
displayName: PROVIDER_LABELS[provider],
windows: [],
error,
};
}
export function buildUsageHttpErrorSnapshot(
options: BuildUsageHttpErrorSnapshotOptions,
): ProviderUsageSnapshot {
const tokenExpiredStatuses = options.tokenExpiredStatuses ?? [];
if (tokenExpiredStatuses.includes(options.status)) {
return buildUsageErrorSnapshot(options.provider, "Token expired");
}
const suffix = options.message?.trim() ? `: ${options.message.trim()}` : "";
return buildUsageErrorSnapshot(options.provider, `HTTP ${options.status}${suffix}`);
}