@xsai/shared
Version:
extra-small AI SDK.
63 lines (53 loc) • 1.92 kB
JavaScript
class XSAIError extends Error {
response;
constructor(message, response, cause) {
super(message, { cause });
this.name = "XSAIError";
this.response = response;
}
}
const strCamelToSnake = (str) => str.replace(/[A-Z]/g, (s) => `_${s.toLowerCase()}`);
const objCamelToSnake = (obj) => Object.fromEntries(Object.entries(obj).map(([k, v]) => [strCamelToSnake(k), v]));
const clean = (obj) => Object.fromEntries(
Object.entries(obj).filter(([, v]) => v !== void 0)
);
const requestBody = (body) => JSON.stringify(objCamelToSnake(clean({
...body,
abortSignal: void 0,
apiKey: void 0,
baseURL: void 0,
fetch: void 0,
headers: void 0
})));
const requestHeaders = (headers, apiKey) => clean({
Authorization: apiKey !== void 0 ? `Bearer ${apiKey}` : void 0,
...headers
});
const requestURL = (path, baseURL) => {
const base = baseURL.toString();
return new URL(path, base.endsWith("/") ? base : `${base}/`);
};
const responseCatch = async (res) => {
if (!res.ok)
throw new XSAIError(`Remote sent ${res.status} response: ${await res.text()}`, res);
if (!res.body)
throw new XSAIError("Response body is empty from remote server", res);
if (!(res.body instanceof ReadableStream))
throw new XSAIError(`Expected Response body to be a ReadableStream, but got ${String(res.body)}; Content Type is ${res.headers.get("Content-Type")}`, res);
return res;
};
const responseJSON = async (res) => {
const text = await res.text();
try {
return JSON.parse(text);
} catch (cause) {
throw new XSAIError(`Failed to parse response, response body: ${text}`, res, cause);
}
};
const trampoline = async (fn) => {
let result = await fn();
while (result instanceof Function)
result = await result();
return result;
};
export { XSAIError, clean, objCamelToSnake, requestBody, requestHeaders, requestURL, responseCatch, responseJSON, strCamelToSnake, trampoline };