UNPKG

@f5i23q999d/cow-sdk

Version:

<p align="center"> <img width="400" src="https://github.com/cowprotocol/cow-sdk/raw/main/docs/images/CoW.png" /> </p>

124 lines 4.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.request = exports.DEFAULT_LIMITER_OPTIONS = exports.DEFAULT_BACKOFF_OPTIONS = exports.OrderBookApiError = void 0; const exponential_backoff_1 = require("exponential-backoff"); /** * Error thrown when the CoW Protocol OrderBook API returns an error. */ class OrderBookApiError extends Error { response; body; /** * Error thrown when the CoW Protocol OrderBook API returns an error. * @param response The response from the CoW Protocol OrderBook API. * @param body The body of the response. * @constructor */ constructor(response, body) { super(typeof body === 'string' ? body : response.statusText); this.response = response; this.body = body; } } exports.OrderBookApiError = OrderBookApiError; const REQUEST_TIMEOUT = 408; const TOO_EARLY = 425; const TOO_MANY_REQUESTS = 429; const INTERNAL_SERVER_ERROR = 500; const BAD_GATEWAY = 502; const SERVICE_UNAVAILABLE = 503; const GATEWAY_TIMEOUT = 504; const STATUS_CODES_TO_RETRY = [ REQUEST_TIMEOUT, TOO_EARLY, TOO_MANY_REQUESTS, INTERNAL_SERVER_ERROR, BAD_GATEWAY, SERVICE_UNAVAILABLE, GATEWAY_TIMEOUT, ]; /** * The default backoff options for CoW Protocol's API * @see {@link Backoff configuration: https://www.npmjs.com/package/@insertish/exponential-backoff} */ exports.DEFAULT_BACKOFF_OPTIONS = { numOfAttempts: 10, maxDelay: Infinity, jitter: 'none', retry: (error) => { if (error instanceof OrderBookApiError) { return STATUS_CODES_TO_RETRY.includes(error.response.status); } return true; }, }; /** * The default rate limiter options for CoW Protocol's API. * * **CAUTION**: The CoW Protocol OrderBook API is limited to 5 requests per second per IP. */ exports.DEFAULT_LIMITER_OPTIONS = { tokensPerInterval: 5, interval: 'second', }; const getResponseBody = async (response) => { if (response.status !== 204) { try { const contentType = response.headers.get('Content-Type'); if (contentType) { if (contentType.toLowerCase().startsWith('application/json')) { return await response.json(); } else { return await response.text(); } } } catch (error) { console.error(error); } } return undefined; }; /** * Helper function to make a rate-limited request to an API. * @param baseUrl The base URL of the API. * @param path The path of the request. * @param query The query parameters of the request. * @param method The HTTP method of the request. * @param body The body of the request. * @param rateLimiter The rate limiter to use. * @param backoffOpts The backoff options to use. * @returns The response of the request. * @throws If the API returns an error or if the request fails. */ async function request(baseUrl, { path, query, method, body }, rateLimiter, backoffOpts) { const queryString = query ? '?' + query : ''; const headers = { Accept: 'application/json', 'Content-Type': 'application/json', }; const url = `${baseUrl}${path}${queryString}`; const bodyContent = (() => { if (!body) return undefined; return typeof body === 'string' ? body : JSON.stringify(body); })(); const init = { method, body: bodyContent, headers, }; return (0, exponential_backoff_1.backOff)(async () => { await rateLimiter.removeTokens(1); const response = await fetch(url, init); const responseBody = (await getResponseBody(response)); // Successful response if (response.status >= 200 && response.status < 300) { return responseBody; } return Promise.reject(new OrderBookApiError(response, responseBody)); }, backoffOpts); } exports.request = request; //# sourceMappingURL=request.js.map