@prismicio/client
Version:
The official JavaScript + TypeScript client library for Prismic
63 lines (62 loc) • 2.37 kB
JavaScript
const require_pLimit = require("./pLimit.cjs");
//#region src/lib/request.ts
/**
* The default number of milliseconds to wait before retrying a rate-limited `fetch()` request (429
* response code). The default value is only used if the response does not include a `retry-after`
* header.
*/
const DEFAULT_RETRY_AFTER = 1500;
/** A record of URLs mapped to throttled task runners. */
const THROTTLED_RUNNERS = {};
/** A record of URLs mapped to active deduplicated jobs. Jobs are keyed by their optional signal. */
const DEDUPLICATED_JOBS = {};
async function memoizeResponse(response) {
const buffer = await response.arrayBuffer();
const memoized = {
ok: response.ok,
status: response.status,
headers: response.headers,
url: response.url,
text: async () => new TextDecoder().decode(buffer),
json: async () => JSON.parse(new TextDecoder().decode(buffer)),
arrayBuffer: async () => buffer,
blob: async () => new Blob([buffer]),
clone: () => memoized
};
return memoized;
}
/**
* Makes an HTTP request with automatic retry for rate limits and request deduplication.
*
* @param url - The URL to request.
* @param init - Fetch options.
* @param fetchFn - The fetch function to use.
* @returns The response from the fetch request.
*/
async function request(url, init, fetchFn) {
const stringURL = url.toString();
let job;
if (init?.body) job = (THROTTLED_RUNNERS[url.hostname] ||= require_pLimit.pLimit({ interval: DEFAULT_RETRY_AFTER }))(() => fetchFn(stringURL, init));
else {
const existingJob = DEDUPLICATED_JOBS[stringURL]?.get(init?.signal);
if (existingJob) job = existingJob;
else {
job = fetchFn(stringURL, init).then(memoizeResponse).finally(() => {
DEDUPLICATED_JOBS[stringURL]?.delete(init?.signal);
if (DEDUPLICATED_JOBS[stringURL]?.size === 0) delete DEDUPLICATED_JOBS[stringURL];
});
(DEDUPLICATED_JOBS[stringURL] ||= /* @__PURE__ */ new Map()).set(init?.signal, job);
}
}
const response = await job;
if (response.status === 429) {
const retryAfter = Number(response.headers.get("retry-after"));
const resolvedRetryAfter = Number.isNaN(retryAfter) ? DEFAULT_RETRY_AFTER : retryAfter * 1e3;
await new Promise((resolve) => setTimeout(resolve, resolvedRetryAfter));
return request(url, init, fetchFn);
}
return response;
}
//#endregion
exports.request = request;
//# sourceMappingURL=request.cjs.map