alwaysai
Version:
The alwaysAI command-line interface (CLI)
64 lines (57 loc) • 1.92 kB
text/typescript
import { CodedError } from '@carnesen/coded-error';
import type { ReadableStream as NodeWebReadableStream } from 'node:stream/web';
import { logger } from './logger';
import { Readable } from 'node:stream';
export async function throwIfNotOk(response: Response) {
if (!response.ok) {
logger.error(`Status: ${response.status}, ${response.statusText}`);
const message = `Server responded ${response.status} ("${response.statusText}")`;
const code = response.status;
throw new CodedError(message, code);
}
}
export async function fetchWithTimeout(
url: string,
options = {},
timeout = 6000
) {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
...options,
signal: controller.signal
});
clearTimeout(id);
await throwIfNotOk(response);
if (response.body === null) {
throw new Error(`Body empty for query ${url}`);
}
// Typescript matches the wrong type to body (DOM) so cast body to desired type
return response as Response & { body: NodeWebReadableStream };
} catch (error) {
clearTimeout(id);
if (error.name === 'AbortError') {
throw new Error('Request timed out');
} else {
throw error;
}
}
}
export async function downloadJson(url: string) {
const options = { method: 'Get' };
const response = await fetchWithTimeout(url, options);
await throwIfNotOk(response);
return response.json();
}
export async function fetchFilestream(url: string, options: any = {}) {
const response = await fetchWithTimeout(url, {
...options
});
await throwIfNotOk(response);
if (response.body === null) {
throw new Error(`Body empty for query ${url}`);
}
// Typescript matches the wrong type to body (DOM) so cast body to desired type
return Readable.fromWeb(response.body as NodeWebReadableStream);
}