mirror of
https://github.com/SukkaW/Surge.git
synced 2025-12-21 13:50:29 +08:00
307 lines
12 KiB
JavaScript
307 lines
12 KiB
JavaScript
'use strict';const require$$0$1=require('picocolors'),require$$1$1=require('undici'),require$$2=require('undici-cache-store-better-sqlite3'),require$$1$3=require('node:util'),require$$0=require('node:path'),require$$1$2=require('node:fs'),require$$1=require('node:process');function getDefaultExportFromCjs (x) {
|
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
}var fetchRetry = {};var dir = {};var hasRequiredDir;
|
|
|
|
function requireDir () {
|
|
if (hasRequiredDir) return dir;
|
|
hasRequiredDir = 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, {
|
|
CACHE_DIR: function() {
|
|
return CACHE_DIR;
|
|
},
|
|
OUTPUT_CLASH_DIR: function() {
|
|
return OUTPUT_CLASH_DIR;
|
|
},
|
|
OUTPUT_INTERNAL_DIR: function() {
|
|
return OUTPUT_INTERNAL_DIR;
|
|
},
|
|
OUTPUT_MOCK_DIR: function() {
|
|
return OUTPUT_MOCK_DIR;
|
|
},
|
|
OUTPUT_MODULES_DIR: function() {
|
|
return OUTPUT_MODULES_DIR;
|
|
},
|
|
OUTPUT_MODULES_RULES_DIR: function() {
|
|
return OUTPUT_MODULES_RULES_DIR;
|
|
},
|
|
OUTPUT_SINGBOX_DIR: function() {
|
|
return OUTPUT_SINGBOX_DIR;
|
|
},
|
|
OUTPUT_SURGE_DIR: function() {
|
|
return OUTPUT_SURGE_DIR;
|
|
},
|
|
PUBLIC_DIR: function() {
|
|
return PUBLIC_DIR;
|
|
},
|
|
ROOT_DIR: function() {
|
|
return ROOT_DIR;
|
|
},
|
|
SOURCE_DIR: function() {
|
|
return SOURCE_DIR;
|
|
}
|
|
});
|
|
const _nodepath = /*#__PURE__*/ _interop_require_default(require$$0);
|
|
const _nodeprocess = /*#__PURE__*/ _interop_require_default(require$$1);
|
|
function _interop_require_default(obj) {
|
|
return obj && obj.__esModule ? obj : {
|
|
default: obj
|
|
};
|
|
}
|
|
const ROOT_DIR = _nodepath.default.resolve(__dirname, '../..');
|
|
const CACHE_DIR = _nodepath.default.resolve(ROOT_DIR, '.cache');
|
|
const SOURCE_DIR = _nodepath.default.join(ROOT_DIR, 'Source');
|
|
const PUBLIC_DIR = _nodeprocess.default.env.PUBLIC_DIR || _nodepath.default.resolve(ROOT_DIR, 'public');
|
|
const OUTPUT_SURGE_DIR = _nodepath.default.join(PUBLIC_DIR, 'List');
|
|
const OUTPUT_CLASH_DIR = _nodepath.default.resolve(PUBLIC_DIR, 'Clash');
|
|
const OUTPUT_SINGBOX_DIR = _nodepath.default.resolve(PUBLIC_DIR, 'sing-box');
|
|
const OUTPUT_MODULES_DIR = _nodepath.default.resolve(PUBLIC_DIR, 'Modules');
|
|
const OUTPUT_MODULES_RULES_DIR = _nodepath.default.resolve(OUTPUT_MODULES_DIR, 'Rules');
|
|
const OUTPUT_INTERNAL_DIR = _nodepath.default.resolve(PUBLIC_DIR, 'Internal');
|
|
const OUTPUT_MOCK_DIR = _nodepath.default.resolve(PUBLIC_DIR, 'Mock');
|
|
} (dir));
|
|
return dir;
|
|
}var hasRequiredFetchRetry;
|
|
|
|
function requireFetchRetry () {
|
|
if (hasRequiredFetchRetry) return fetchRetry;
|
|
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$1);
|
|
const _undicicachestorebettersqlite3 = require$$2;
|
|
const _nodeutil = require$$1$3;
|
|
const _nodepath = /*#__PURE__*/ _interop_require_default(require$$0);
|
|
const _nodefs = /*#__PURE__*/ _interop_require_default(require$$1$2);
|
|
const _dir = /*@__PURE__*/ requireDir();
|
|
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));
|
|
return fetchRetry;
|
|
}exports.a=requireDir;exports.g=getDefaultExportFromCjs;exports.r=requireFetchRetry; |