import "server-only"; import type { WorldLabsProviderConfig } from "./types"; type WorldLabsRequestOptions = { method?: "GET" | "POST"; path: string; json?: Record; headers?: Record; }; const DEFAULT_WORLDLABS_BASE_URL = "https://api.worldlabs.ai"; export class WorldLabsApiError extends Error { httpStatus: number; payload: unknown; constructor(params: { message: string; httpStatus: number; payload?: unknown; }) { super(params.message); this.name = "WorldLabsApiError"; this.httpStatus = params.httpStatus; this.payload = params.payload; } } function normalizeBaseUrl(baseUrl?: string) { const resolved = String(baseUrl || "").trim() || DEFAULT_WORLDLABS_BASE_URL; return resolved.replace(/\/+$/, ""); } function sanitizeApiKey(value: string): string { return String(value || "") .replace(/[\u2028\u2029]/g, "") .replace(/[\u0000-\u001F\u007F]/g, "") .trim(); } async function parseResponseBody(response: Response): Promise { const contentType = response.headers.get("content-type") || ""; if (contentType.includes("application/json")) { return response.json().catch(() => null); } const text = await response.text().catch(() => ""); return text || null; } function extractErrorMessage(payload: unknown, fallback: string) { if (!payload) return fallback; if (typeof payload === "string") return payload || fallback; if (typeof payload !== "object") return fallback; const record = payload as Record; if (typeof record.message === "string" && record.message.trim()) { return record.message.trim(); } if (typeof record.detail === "string" && record.detail.trim()) { return record.detail.trim(); } if (Array.isArray(record.detail) && record.detail.length > 0) { const firstDetail = record.detail[0]; if (firstDetail && typeof firstDetail === "object") { const msg = (firstDetail as Record).msg; if (typeof msg === "string" && msg.trim()) { return msg.trim(); } } } return fallback; } export async function worldLabsRequest( config: WorldLabsProviderConfig, options: WorldLabsRequestOptions ): Promise { const path = options.path.startsWith("/") ? options.path : `/${options.path}`; const url = `${normalizeBaseUrl(config.baseUrl)}${path}`; const headers = new Headers(options.headers || {}); const normalizedApiKey = sanitizeApiKey(String(config.apiKey || "")).replace(/\s+/g, ""); if (!normalizedApiKey) { throw new WorldLabsApiError({ message: "World Labs API Key 为空,请在本地AI设置中重新保存", httpStatus: 400, }); } headers.set("WLT-Api-Key", normalizedApiKey); headers.set("Accept", "application/json"); let body: BodyInit | undefined; if (options.json) { headers.set("Content-Type", "application/json"); body = JSON.stringify(options.json); } const response = await fetch(url, { method: options.method || "GET", headers, body, cache: "no-store", }); const parsed = await parseResponseBody(response); if (!response.ok) { throw new WorldLabsApiError({ message: extractErrorMessage(parsed, `World Labs 请求失败(HTTP ${response.status})`), httpStatus: response.status, payload: parsed, }); } return parsed as T; }