@chatbotkit/fetch
Version:
Isomorphic implenetation for fetch specifically designed for @chatbotkit/sdk.
287 lines (286 loc) • 14.1 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.TOO_MANY_REQUESTS_CODE = exports.UNPROCESSABLE_ENTITY_CODE = exports.CONFLICT_CODE = exports.TIMEOUT_CODE = exports.METHOD_NOT_ALLOWED_CODE = exports.NOT_FOUND_CODE = exports.NO_SUBSCRIPTION_CODE = exports.NOT_AUTHORIZED_CODE = exports.NOT_AUTHENTICATED_CODE = exports.BAD_REQUEST_CODE = exports.NOT_MODIFIED_CODE = exports.OK_CODE = exports.GATEWAY_TIMEOUT_MESSAGE = exports.SERVICE_UNAVAILABLE_MESSAGE = exports.BAD_GATEWAY_MESSAGE = exports.NOT_IMPLEMENTED_MESSAGE = exports.INTERNAL_SERVER_ERROR_MESSAGE = exports.LIMITS_REACHED_MESSAGE = exports.TOO_MANY_REQUESTS_MESSAGE = exports.UNPROCESSABLE_ENTITY_STATUS_MESSAGE = exports.CONFLICT_MESSAGE = exports.TIMEOUT_MESSAGE = exports.METHOD_NOT_ALLOWED_MESSAGE = exports.NOT_FOUND_MESSAGE = exports.NO_SUBSCRIPTION_MESSAGE = exports.NOT_AUTHORIZED_MESSAGE = exports.NOT_AUTHENTICATED_MESSAGE = exports.BAD_REQUEST_MESSAGE = exports.NOT_MODIFIED_MESSAGE = exports.OK_MESSAGE = exports.GATEWAY_TIMEOUT_STATUS = exports.SERVICE_UNAVAILABLE_STATUS = exports.BAD_GATEWAY_STATUS = exports.NOT_IMPLEMENTED_STATUS = exports.INTERNAL_SERVER_ERROR_STATUS = exports.LIMITS_REACHED_STATUS = exports.TOO_MANY_REQUESTS_STATUS = exports.UNPROCESSABLE_ENTITY_STATUS = exports.CONFLICT_STATUS = exports.TIMEOUT_STATUS = exports.METHOD_NOT_ALLOWED_STATUS = exports.NOT_FOUND_STATUS = exports.NOT_AUTHORIZED_STATUS = exports.NO_SUBSCRIPTION_STATUS = exports.NOT_AUTHENTICATED_STATUS = exports.BAD_REQUEST_STATUS = exports.NOT_MODIFIED_STATUS = exports.OK_STATUS = exports.FormData = exports.Blob = void 0;
exports.jsonl = exports.withRetry = exports.withTimeout = exports.anySignal = exports.fetch = exports.TimeoutError = exports.AbortError = exports.DEFAULT_RETRY_STATUSES = exports.DEFAULT_RETRY_TIMEOUT = exports.DEFAULT_RETRY_DELAY = exports.DEFAULT_RETRIES = exports.DEFAULT_TIMEOUT = exports.TIMEOUT_ERROR_NAME = exports.ABORT_ERROR_NAME = exports.getFetchError = exports.FetchError = exports.statusToCodeMap = exports.GATEWAY_TIMEOUT_CODE = exports.SERVICE_UNAVAILABLE_CODE = exports.BAD_GATEWAY_CODE = exports.NOT_IMPLEMENTED_CODE = exports.INTERNAL_SERVER_ERROR_CODE = exports.LIMITS_REACHED_CODE = void 0;
const node_fetch_native_1 = require("node-fetch-native");
Object.defineProperty(exports, "Blob", { enumerable: true, get: function () { return node_fetch_native_1.Blob; } });
Object.defineProperty(exports, "FormData", { enumerable: true, get: function () { return node_fetch_native_1.FormData; } });
{
if (typeof globalThis.ReadableStream === 'function' &&
typeof globalThis.ReadableStream.prototype[Symbol.asyncIterator] !==
'function') {
globalThis.ReadableStream.prototype[Symbol.asyncIterator] = function () {
const reader = this.getReader();
return {
next: () => reader.read(),
return: () => {
reader.releaseLock();
return Promise.resolve({ done: true });
},
};
};
}
}
exports.OK_STATUS = 200;
exports.NOT_MODIFIED_STATUS = 304;
exports.BAD_REQUEST_STATUS = 400;
exports.NOT_AUTHENTICATED_STATUS = 401;
exports.NO_SUBSCRIPTION_STATUS = 402;
exports.NOT_AUTHORIZED_STATUS = 403;
exports.NOT_FOUND_STATUS = 404;
exports.METHOD_NOT_ALLOWED_STATUS = 405;
exports.TIMEOUT_STATUS = 408;
exports.CONFLICT_STATUS = 409;
exports.UNPROCESSABLE_ENTITY_STATUS = 422;
exports.TOO_MANY_REQUESTS_STATUS = 429;
exports.LIMITS_REACHED_STATUS = 429;
exports.INTERNAL_SERVER_ERROR_STATUS = 500;
exports.NOT_IMPLEMENTED_STATUS = 501;
exports.BAD_GATEWAY_STATUS = 502;
exports.SERVICE_UNAVAILABLE_STATUS = 503;
exports.GATEWAY_TIMEOUT_STATUS = 504;
exports.OK_MESSAGE = 'OK';
exports.NOT_MODIFIED_MESSAGE = 'Not modified';
exports.BAD_REQUEST_MESSAGE = 'Bad request';
exports.NOT_AUTHENTICATED_MESSAGE = 'Not authenticated';
exports.NOT_AUTHORIZED_MESSAGE = 'Not authorized';
exports.NO_SUBSCRIPTION_MESSAGE = 'No subscription';
exports.NOT_FOUND_MESSAGE = 'Not found';
exports.METHOD_NOT_ALLOWED_MESSAGE = 'Method not allowed';
exports.TIMEOUT_MESSAGE = 'Timeout';
exports.CONFLICT_MESSAGE = 'Conflict';
exports.UNPROCESSABLE_ENTITY_STATUS_MESSAGE = 'Unprocessable entity';
exports.TOO_MANY_REQUESTS_MESSAGE = 'Too many requests';
exports.LIMITS_REACHED_MESSAGE = 'Limits reached';
exports.INTERNAL_SERVER_ERROR_MESSAGE = 'Internal server error';
exports.NOT_IMPLEMENTED_MESSAGE = 'Not implemented';
exports.BAD_GATEWAY_MESSAGE = 'Bad gateway';
exports.SERVICE_UNAVAILABLE_MESSAGE = 'Service unavailable';
exports.GATEWAY_TIMEOUT_MESSAGE = 'Gateway timeout';
exports.OK_CODE = 'OK';
exports.NOT_MODIFIED_CODE = 'NOT_MODIFIED';
exports.BAD_REQUEST_CODE = 'BAD_REQUEST';
exports.NOT_AUTHENTICATED_CODE = 'NOT_AUTHENTICATED';
exports.NOT_AUTHORIZED_CODE = 'NOT_AUTHORIZED';
exports.NO_SUBSCRIPTION_CODE = 'NO_SUBSCRIPTION';
exports.NOT_FOUND_CODE = 'NOT_FOUND';
exports.METHOD_NOT_ALLOWED_CODE = 'METHOD_NOT_ALLOWED';
exports.TIMEOUT_CODE = 'TIMEOUT';
exports.CONFLICT_CODE = 'CONFLICT';
exports.UNPROCESSABLE_ENTITY_CODE = 'UNPROCESSABLE_ENTITY';
exports.TOO_MANY_REQUESTS_CODE = 'TOO_MANY_REQUESTS';
exports.LIMITS_REACHED_CODE = 'LIMITS_REACHED';
exports.INTERNAL_SERVER_ERROR_CODE = 'INTERNAL_SERVER_ERROR';
exports.NOT_IMPLEMENTED_CODE = 'NOT_IMPLEMENTED';
exports.BAD_GATEWAY_CODE = 'BAD_GATEWAY';
exports.SERVICE_UNAVAILABLE_CODE = 'SERVICE_UNAVAILABLE';
exports.GATEWAY_TIMEOUT_CODE = 'GATEWAY_TIMEOUT';
exports.statusToCodeMap = {
[exports.OK_STATUS]: exports.OK_CODE,
[exports.NOT_MODIFIED_STATUS]: exports.NOT_MODIFIED_CODE,
[exports.BAD_REQUEST_STATUS]: exports.BAD_REQUEST_CODE,
[exports.NOT_AUTHENTICATED_STATUS]: exports.NOT_AUTHENTICATED_CODE,
[exports.NOT_AUTHORIZED_STATUS]: exports.NOT_AUTHORIZED_CODE,
[exports.NO_SUBSCRIPTION_STATUS]: exports.NO_SUBSCRIPTION_CODE,
[exports.NOT_FOUND_STATUS]: exports.NOT_FOUND_CODE,
[exports.METHOD_NOT_ALLOWED_STATUS]: exports.METHOD_NOT_ALLOWED_CODE,
[exports.TIMEOUT_STATUS]: exports.TIMEOUT_CODE,
[exports.CONFLICT_STATUS]: exports.CONFLICT_CODE,
[exports.UNPROCESSABLE_ENTITY_STATUS]: exports.UNPROCESSABLE_ENTITY_CODE,
[exports.TOO_MANY_REQUESTS_STATUS]: exports.TOO_MANY_REQUESTS_CODE,
[exports.INTERNAL_SERVER_ERROR_STATUS]: exports.INTERNAL_SERVER_ERROR_CODE,
[exports.NOT_IMPLEMENTED_STATUS]: exports.NOT_IMPLEMENTED_CODE,
[exports.BAD_GATEWAY_STATUS]: exports.BAD_GATEWAY_CODE,
[exports.SERVICE_UNAVAILABLE_STATUS]: exports.SERVICE_UNAVAILABLE_CODE,
[exports.GATEWAY_TIMEOUT_STATUS]: exports.GATEWAY_TIMEOUT_CODE,
};
class FetchError extends Error {
constructor(message, code, meta) {
super(message);
this.name = meta
? 'FetchError'
: `FetchError(${JSON.stringify(meta || {})})`;
this.code = code || 'FetchError';
}
}
exports.FetchError = FetchError;
async function getFetchError(response, meta) {
if (response.ok) {
throw new Error(`Response ok: ${response.status} ${response.statusText}`);
}
const status = response.status;
const text = await response.text();
let json;
try {
json = JSON.parse(text);
}
catch (e) {
json = { message: text, code: exports.statusToCodeMap[status] };
}
return new FetchError(json.message || text, json.code || exports.statusToCodeMap[status] || exports.statusToCodeMap[500], meta);
}
exports.getFetchError = getFetchError;
exports.ABORT_ERROR_NAME = 'AbortError';
exports.TIMEOUT_ERROR_NAME = 'TimeoutError';
exports.DEFAULT_TIMEOUT = process.env.FETCH_DEFAULT_TIMEOUT
? parseInt(process.env.FETCH_DEFAULT_TIMEOUT, 10)
: 30000;
exports.DEFAULT_RETRIES = 5;
exports.DEFAULT_RETRY_DELAY = 250;
exports.DEFAULT_RETRY_TIMEOUT = false;
exports.DEFAULT_RETRY_STATUSES = [429, 500, 502, 503, 504];
class AbortError extends Error {
constructor(message) {
super(message || exports.ABORT_ERROR_NAME);
this.name = exports.ABORT_ERROR_NAME;
this.code = exports.ABORT_ERROR_NAME;
}
}
exports.AbortError = AbortError;
class TimeoutError extends Error {
constructor(message) {
super(message || exports.TIMEOUT_ERROR_NAME);
this.name = exports.TIMEOUT_ERROR_NAME;
this.code = exports.TIMEOUT_ERROR_NAME;
}
}
exports.TimeoutError = TimeoutError;
function fetch(url, init) {
return (0, node_fetch_native_1.fetch)(url, init);
}
exports.fetch = fetch;
function anySignal(signals) {
const controller = new AbortController();
for (const signal of signals) {
if (!signal) {
continue;
}
if (signal.aborted) {
controller.abort(signal.reason);
return signal;
}
signal.addEventListener('abort', () => controller.abort(signal.reason), {
signal: controller.signal,
});
}
return controller.signal;
}
exports.anySignal = anySignal;
function withTimeout(fetch, defaultOptions) {
return async function fetchWithTimeout(url, options) {
var _a, _b;
const timeout = (_b = (_a = options === null || options === void 0 ? void 0 : options.timeout) !== null && _a !== void 0 ? _a : defaultOptions === null || defaultOptions === void 0 ? void 0 : defaultOptions.timeout) !== null && _b !== void 0 ? _b : exports.DEFAULT_TIMEOUT;
let signal;
let handler;
let isTimeOutAbort = false;
if (timeout > 0 && timeout !== Infinity) {
const abortController = new AbortController();
handler = setTimeout(() => {
isTimeOutAbort = true;
abortController.abort(new TimeoutError());
}, timeout);
signal = (options === null || options === void 0 ? void 0 : options.signal)
? anySignal([abortController.signal, options.signal])
: abortController.signal;
}
else {
signal = options === null || options === void 0 ? void 0 : options.signal;
}
let response;
try {
response = await fetch(url, {
...options,
signal,
});
}
catch (error) {
if ([error.name, error.message].includes(exports.ABORT_ERROR_NAME)) {
if (isTimeOutAbort) {
throw new TimeoutError();
}
}
throw error;
}
finally {
clearTimeout(handler);
}
return response;
};
}
exports.withTimeout = withTimeout;
function withRetry(fetch, defaultOptions) {
return async function fetchWithRetry(url, options) {
var _a, _b, _c, _d, _e, _f, _g, _h;
const retries = (_b = (_a = options === null || options === void 0 ? void 0 : options.retries) !== null && _a !== void 0 ? _a : defaultOptions === null || defaultOptions === void 0 ? void 0 : defaultOptions.retries) !== null && _b !== void 0 ? _b : exports.DEFAULT_RETRIES;
const retryDelay = (_d = (_c = options === null || options === void 0 ? void 0 : options.retryDelay) !== null && _c !== void 0 ? _c : defaultOptions === null || defaultOptions === void 0 ? void 0 : defaultOptions.retryDelay) !== null && _d !== void 0 ? _d : exports.DEFAULT_RETRY_DELAY;
const retryTimeout = (_f = (_e = options === null || options === void 0 ? void 0 : options.retryTimeout) !== null && _e !== void 0 ? _e : defaultOptions === null || defaultOptions === void 0 ? void 0 : defaultOptions.retryTimeout) !== null && _f !== void 0 ? _f : exports.DEFAULT_RETRY_TIMEOUT;
const retryStatuses = (_h = (_g = options === null || options === void 0 ? void 0 : options.retryStatuses) !== null && _g !== void 0 ? _g : defaultOptions === null || defaultOptions === void 0 ? void 0 : defaultOptions.retryStatuses) !== null && _h !== void 0 ? _h : exports.DEFAULT_RETRY_STATUSES;
let response;
try {
response = await fetch(url, { ...options });
if (!response.ok) {
if (retryStatuses.includes(response.status)) {
throw new FetchError(`Fetch failed with status ${response.status} (${response.statusText})`, exports.statusToCodeMap[response.status] || exports.statusToCodeMap[500], {
url: new URL(url).href,
options: options,
});
}
else {
return response;
}
}
return response;
}
catch (error) {
switch (true) {
case [error.name, error.message].includes(exports.TIMEOUT_ERROR_NAME) &&
!retryTimeout:
{
throw error;
}
case retries === 0: {
if (response) {
return response;
}
else {
throw error;
}
}
}
await new Promise((resolve) => setTimeout(resolve, retryDelay));
return await fetchWithRetry(url, {
...options,
retries: retries - 1,
retryDelay: retryDelay * 2,
});
}
};
}
exports.withRetry = withRetry;
async function* jsonl(body) {
try {
const decoder = new TextDecoder();
let previous = '';
for await (const chunk of body) {
previous += decoder.decode(chunk);
let eolIndex;
while ((eolIndex = previous.indexOf('\n')) >= 0) {
const line = previous.slice(0, eolIndex + 1);
if (line) {
yield JSON.parse(line);
}
previous = previous.slice(eolIndex + 1);
}
}
if (previous.trim().length > 0) {
yield JSON.parse(previous);
}
}
catch (e) {
if (e.name !== exports.ABORT_ERROR_NAME) {
throw e;
}
}
}
exports.jsonl = jsonl;
exports.default = fetch;
;