@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
JavaScript
;
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