Surge_by_SukkaW/Dist/Build/lib/fetch-retry.cjs
SukkaW d354c5e988
Some checks are pending
Build / Build (push) Waiting to run
Build / Diff output (push) Blocked by required conditions
Build / Deploy to Cloudflare Pages (push) Blocked by required conditions
Build / Deploy to GitHub and GitLab (push) Blocked by required conditions
Chore: maintainance
2025-02-07 17:52:36 +08:00

235 lines
9.3 KiB
JavaScript

'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const fetchRetry=require('../../_virtual/fetch-retry.cjs'),require$$0$1=require('picocolors'),require$$1=require('undici'),require$$2=require('undici-cache-store-better-sqlite3'),require$$1$2=require('node:util'),require$$0=require('node:path'),require$$1$1=require('node:fs'),dir=require('../constants/dir.cjs');var hasRequiredFetchRetry;
function requireFetchRetry () {
if (hasRequiredFetchRetry) return fetchRetry.__exports;
hasRequiredFetchRetry = 1;
(function (exports) {
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
$$fetch: function() {
return $$fetch;
},
ResponseError: function() {
return ResponseError;
},
defaultRequestInit: function() {
return defaultRequestInit;
},
requestWithLog: function() {
return requestWithLog;
}
});
const _picocolors = /*#__PURE__*/ _interop_require_default(require$$0$1);
const _undici = /*#__PURE__*/ _interop_require_wildcard(require$$1);
const _undicicachestorebettersqlite3 = require$$2;
const _nodeutil = require$$1$2;
const _nodepath = /*#__PURE__*/ _interop_require_default(require$$0);
const _nodefs = /*#__PURE__*/ _interop_require_default(require$$1$1);
const _dir = /*@__PURE__*/ dir.__require();
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
if (!_nodefs.default.existsSync(_dir.CACHE_DIR)) {
_nodefs.default.mkdirSync(_dir.CACHE_DIR, {
recursive: true
});
}
const agent = new _undici.Agent({
allowH2: true
});
(0, _undici.setGlobalDispatcher)(agent.compose(_undici.interceptors.dns({
// disable IPv6
dualStack: false,
affinity: 4
}), _undici.interceptors.retry({
maxRetries: 5,
minTimeout: 500,
maxTimeout: 10 * 1000,
// TODO: this part of code is only for allow more errors to be retried by default
// This should be removed once https://github.com/nodejs/undici/issues/3728 is implemented
retry (err, { state, opts }, cb) {
const errorCode = 'code' in err ? err.code : undefined;
// Any code that is not a Undici's originated and allowed to retry
if (errorCode === 'ERR_UNESCAPED_CHARACTERS' || err.message === 'Request path contains unescaped characters' || err.name === 'AbortError') {
return cb(err);
}
const statusCode = 'statusCode' in err && typeof err.statusCode === 'number' ? err.statusCode : null;
// bail out if the status code matches one of the following
if (statusCode != null && (statusCode === 401 // Unauthorized, should check credentials instead of retrying
|| statusCode === 403 // Forbidden, should check permissions instead of retrying
|| statusCode === 404 // Not Found, should check URL instead of retrying
|| statusCode === 405 // Method Not Allowed, should check method instead of retrying
)) {
return cb(err);
}
// if (errorCode === 'UND_ERR_REQ_RETRY') {
// return cb(err);
// }
const { maxRetries = 5, minTimeout = 500, maxTimeout = 10 * 1000, timeoutFactor = 2, methods = [
'GET',
'HEAD',
'OPTIONS',
'PUT',
'DELETE',
'TRACE'
] } = opts.retryOptions || {};
// If we reached the max number of retries
if (state.counter > maxRetries) {
return cb(err);
}
// If a set of method are provided and the current method is not in the list
if (Array.isArray(methods) && !methods.includes(opts.method)) {
return cb(err);
}
const headers = 'headers' in err && typeof err.headers === 'object' ? err.headers : undefined;
const retryAfterHeader = headers?.['retry-after'];
let retryAfter = -1;
if (retryAfterHeader) {
retryAfter = Number(retryAfterHeader);
retryAfter = Number.isNaN(retryAfter) ? calculateRetryAfterHeader(retryAfterHeader) : retryAfter * 1e3; // Retry-After is in seconds
}
const retryTimeout = retryAfter > 0 ? Math.min(retryAfter, maxTimeout) : Math.min(minTimeout * timeoutFactor ** (state.counter - 1), maxTimeout);
console.log('[fetch retry]', 'schedule retry', {
statusCode,
retryTimeout,
errorCode,
url: opts.origin
});
// eslint-disable-next-line sukka/prefer-timer-id -- won't leak
setTimeout(()=>cb(null), retryTimeout);
}
}), _undici.interceptors.redirect({
maxRedirections: 5
}), _undici.interceptors.cache({
store: new _undicicachestorebettersqlite3.BetterSqlite3CacheStore({
location: _nodepath.default.join(_dir.CACHE_DIR, 'undici-better-sqlite3-cache-store.db'),
maxEntrySize: 1024 * 1024 * 100 // 100 MiB
})
})));
function calculateRetryAfterHeader(retryAfter) {
const current = Date.now();
return new Date(retryAfter).getTime() - current;
}
class ResponseError extends Error {
res;
url;
code;
statusCode;
constructor(res, url, ...args){
const statusCode = 'statusCode' in res ? res.statusCode : res.status;
super('HTTP ' + statusCode + ' ' + args.map((_)=>(0, _nodeutil.inspect)(_)).join(' ')), this.res = res, this.url = url;
if ('captureStackTrace' in Error) {
Error.captureStackTrace(this, ResponseError);
}
// eslint-disable-next-line sukka/unicorn/custom-error-definition -- deliberatly use previous name
this.name = this.constructor.name;
this.res = res;
this.code = statusCode;
this.statusCode = statusCode;
}
}
const defaultRequestInit = {
headers: {
'User-Agent': 'curl/8.9.1 (https://github.com/SukkaW/Surge)'
}
};
async function $$fetch(url, init) {
try {
const res = await _undici.default.fetch(url, init);
if (res.status >= 400) {
throw new ResponseError(res, url);
}
if (!(res.status >= 200 && res.status <= 299) && res.status !== 304) {
throw new ResponseError(res, url);
}
return res;
} catch (err) {
if (typeof err === 'object' && err !== null && 'name' in err) {
if (err.name === 'AbortError' || 'digest' in err && err.digest === 'AbortError') {
console.log(_picocolors.default.gray('[fetch abort]'), url);
}
} else {
console.log(_picocolors.default.gray('[fetch fail]'), url, {
name: err.name
}, err);
}
throw err;
}
}
async function requestWithLog(url, opt) {
try {
const res = await _undici.default.request(url, opt);
if (res.statusCode >= 400) {
throw new ResponseError(res, url);
}
if (!(res.statusCode >= 200 && res.statusCode <= 299) && res.statusCode !== 304) {
throw new ResponseError(res, url);
}
return res;
} catch (err) {
if (typeof err === 'object' && err !== null && 'name' in err) {
if (err.name === 'AbortError' || 'digest' in err && err.digest === 'AbortError') {
console.log(_picocolors.default.gray('[fetch abort]'), url);
}
} else {
console.log(_picocolors.default.gray('[fetch fail]'), url, {
name: err.name
}, err);
}
throw err;
}
}
} (fetchRetry.__exports));
return fetchRetry.__exports;
}exports.__require=requireFetchRetry;