UNPKG

@chatbotkit/fetch

Version:

Isomorphic implenetation for fetch specifically designed for @chatbotkit/sdk.

287 lines (286 loc) 14.1 kB
"use strict"; 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;