deploy: 521cc9020218e7b930a9bb873cabced01b877579

This commit is contained in:
SukkaBot
2022-11-01 12:21:58 +00:00
parent e63db21af9
commit cc9054a9d0
17 changed files with 2 additions and 1750 deletions

View File

@@ -1,30 +0,0 @@
const { fetchWithRetry } = require('./lib/fetch-retry');
const fs = require('fs');
const path = require('path');
const { isIP } = require('net');
(async () => {
console.time('Total Time - build-anti-bogus-domain');
console.time('* Download bogus-nxdomain-list')
const res = (await (await fetchWithRetry('https://raw.githubusercontent.com/felixonmars/dnsmasq-china-list/master/bogus-nxdomain.china.conf')).text())
.split('\n')
.map(line => {
if (line.startsWith('bogus-nxdomain=')) {
return line.replace('bogus-nxdomain=', '');
}
return null
})
.filter(ip => typeof ip === 'string' && isIP(ip) !== 0);
console.timeEnd('* Download bogus-nxdomain-list')
const filePath = path.resolve(__dirname, '../List/ip/reject.conf');
const content = (await fs.promises.readFile(filePath, 'utf-8'))
.replace(
'# --- [Anti Bogus Domain Replace Me] ---',
res.map(ip => `IP-CIDR,${ip}/32,no-resolve`).join('\n')
);
await fs.promises.writeFile(filePath, content, 'utf-8');
console.timeEnd('Total Time - build-anti-bogus-domain');
})();

View File

@@ -1,35 +0,0 @@
const { fetchWithRetry } = require('./lib/fetch-retry');
const fs = require('fs');
const path = require('path');
const rDomain = /^(((?!\-))(xn\-\-)?[a-z0-9\-_]{0,61}[a-z0-9]{1,1}\.)*(xn\-\-)?([a-z0-9\-]{1,61}|[a-z0-9\-]{1,30})\.[a-z]{2,}$/m;
(async () => {
console.time('Total Time - build-apple-cdn-conf');
const res = (await (await fetchWithRetry('https://raw.githubusercontent.com/felixonmars/dnsmasq-china-list/master/apple.china.conf')).text())
.split('\n')
.map(line => {
if (line.startsWith('server=/') && line.endsWith('/114.114.114.114')) {
return line.replace('server=/', '').replace('/114.114.114.114', '');
}
return null
})
.filter(domain => typeof domain === 'string' && rDomain.test(domain));
await Promise.all([
fs.promises.writeFile(
path.resolve(__dirname, '../List/non_ip/apple_cdn.conf'),
res.map(domain => `DOMAIN-SUFFIX,${domain}`).join('\n') + '\n',
'utf-8'
),
fs.promises.writeFile(
path.resolve(__dirname, '../List/domainset/apple_cdn.conf'),
res.map(i => `.${i}`).join('\n') + '\n',
'utf-8'
)
])
console.timeEnd('Total Time - build-apple-cdn-conf');
})();

View File

@@ -1,36 +0,0 @@
const { fetchWithRetry } = require('./lib/fetch-retry');
const fs = require('fs');
const path = require('path');
(async () => {
console.time('Total Time - build-cdn-conf');
const domains = (await (await fetchWithRetry('https://publicsuffix.org/list/public_suffix_list.dat')).text()).split('\n');
const S3OSSDomains = domains.filter(line => {
if (line) {
return (
line.startsWith('s3-')
|| line.startsWith('s3.')
)
&& (
line.endsWith('.amazonaws.com')
|| line.endsWith('.scw.cloud')
)
&& !line.includes('cn-')
}
return false;
})
const filePath = path.resolve(__dirname, '../List/non_ip/cdn.conf');
const content = (await fs.promises.readFile(filePath, 'utf-8'))
.replace(
'# --- [AWS S3 Replace Me] ---',
S3OSSDomains.map(domain => `DOMAIN-SUFFIX,${domain}`).join('\n')
);
await fs.promises.writeFile(filePath, content, 'utf-8');
console.timeEnd('Total Time - build-cdn-conf');
})();

View File

@@ -1,32 +0,0 @@
const { fetchWithRetry } = require('./lib/fetch-retry');
const { promises: fsPromises } = require('fs');
const { resolve: pathResolve } = require('path');
(async () => {
console.time('Total Time - build-chnroutes-cidr');
const cidr = (await (await fetchWithRetry('https://raw.githubusercontent.com/misakaio/chnroutes2/master/chnroutes.txt')).text()).split('\n');
const filteredCidr = cidr.filter(line => {
if (line) {
return !line.startsWith('#')
}
return false;
})
await fsPromises.writeFile(pathResolve(__dirname, '../List/ip/china_ip.conf'), makeCidrList(filteredCidr), { encoding: 'utf-8' });
console.timeEnd('Total Time - build-chnroutes-cidr');
})();
function makeCidrList(cidr) {
const date = new Date();
return `############################
# Mainland China IPv4 CIDR
# Data from misaka.io (misakaio @ GitHub)
# Last Updated: ${date.toISOString()}
# Routes: ${cidr.length}
############################\n` + cidr.map(i => `IP-CIDR,${i}`).join('\n') + '\n########### END ############\n';
};

View File

@@ -1,59 +0,0 @@
const listDir = require('@sukka/listdir');
const path = require('path');
const fs = require('fs');
const rootPath = path.resolve(__dirname, '../');
(async () => {
const list = await listDir(rootPath, {
ignoreHidden: true,
ignorePattern: /node_modules|Build|.DS_Store|\.(json|html|md|js)|LICENSE/
});
const html = template(list);
await fs.promises.writeFile(path.join(rootPath, 'index.html'), html, 'utf-8');
})();
/**
* @param {string[]} urlList
* @returns {string}
*/
function template(urlList) {
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Surge Ruleset Server | Sukka (@SukkaW)</title>
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
<link href="https://cdn.skk.moe/favicon.ico" rel="icon" type="image/ico">
<link href="https://cdn.skk.moe/favicon/apple-touch-icon.png" rel="apple-touch-icon" sizes="180x180">
<link href="https://cdn.skk.moe/favicon/android-chrome-192x192.png" rel="icon" type="image/png" sizes="192x192">
<link href="https://cdn.skk.moe/favicon/favicon-32x32.png" rel="icon" type="image/png" sizes="32x32">
<link href="https://cdn.skk.moe/favicon/favicon-16x16.png" rel="icon" type="image/png" sizes="16x16">
<meta name="description" content="Sukka 自用的 Surge 规则组">
<meta property="og:title" content="Surge Ruleset | Sukka (@SukkaW)">
<meta property="og:type" content="Website">
<meta property="og:url" content="https://ruleset.skk.moe/">
<meta property="og:image" content="https://cdn.skk.moe/favicon/android-chrome-192x192.png">
<meta property="og:description" content="Sukka 自用的 Surge 规则组">
<meta name="twitter:card" content="summary">
<link rel="canonical" href="https://ruleset.skk.moe/">
<link rel="stylesheet" href="https://cdn.staticfile.org/picocss/1.5.0/pico.slim.min.css">
</head>
<body>
<main class="container">
<h1>Sukka Surge Ruleset Server</h1>
<p>Made by <a href="https://skk.moe">Sukka</a> | <a href="https://github.com/SukkaW/Surge/">Source @ GitHub</a> | Licensed under <a href="https://github.com/SukkaW/Surge/blob/master/LICENSE" target="_blank">AGPL-3.0</a></p>
<p>Last Updated: ${new Date().toISOString()}</p>
<hr>
<br>
<ul>
${urlList.sort().map(url => `<li><a href="${url}" target="_blank">${url}</a></li>`).join('')}
</ul>
</main>
</body>
</html>
`
}

View File

@@ -1,190 +0,0 @@
const fsPromises = require('fs').promises;
const pathFn = require('path');
const table = require('table');
const listDir = require('@sukka/listdir');
const { green, yellow } = require('picocolors');
const PRESET_MITM_HOSTNAMES = [
// '*baidu.com',
'*ydstatic.com',
// '*snssdk.com',
'*musical.com',
// '*musical.ly',
// '*snssdk.ly',
'api.chelaile.net.cn',
'atrace.chelaile.net.cn',
'*.meituan.net',
'ctrl.playcvn.com',
'ctrl.playcvn.net',
'ctrl.zmzapi.com',
'ctrl.zmzapi.net',
'api.zhuishushenqi.com',
'b.zhuishushenqi.com',
'*.music.126.net',
'*.prod.hosts.ooklaserver.net'
];
(async () => {
const folderListPath = pathFn.resolve(__dirname, '../List/');
const rulesets = await listDir(folderListPath);
let urlRegexPaths = [];
urlRegexPaths.push(
...(await fsPromises.readFile(pathFn.join(__dirname, '../Modules/sukka_url_rewrite.sgmodule'), { encoding: 'utf-8' }))
.split('\n')
.filter(
i => !i.startsWith('#')
&& !i.startsWith('[')
)
.map(i => i.split(' ')[0])
.map(i => ({
origin: i,
processed: i
.replaceAll('(www.)?', '{www or not}')
.replaceAll('^https?://', '')
.replaceAll('^https://', '')
.replaceAll('^http://', '')
.split('/')[0]
.replaceAll('\\.', '.')
.replaceAll('.+', '*')
.replaceAll('(.*)', '*')
}))
);
const bothWwwApexDomains = [];
urlRegexPaths = urlRegexPaths.map(i => {
if (!i.processed.includes('{www or not}')) return i;
const d = i.processed.replace('{www or not}', '');
bothWwwApexDomains.push({
origin: i.origin,
processed: `www.${d}`
});
return {
origin: i.origin,
processed: d
};
});
urlRegexPaths.push(...bothWwwApexDomains);
await Promise.all(rulesets.map(async file => {
const content = (await fsPromises.readFile(pathFn.join(folderListPath, file), { encoding: 'utf-8' })).split('\n');
urlRegexPaths.push(
...content
.filter(i => i.startsWith('URL-REGEX'))
.map(i => i.split(',')[1])
.map(i => ({
origin: i,
processed: i
.replaceAll('^https?://', '')
.replaceAll('^https://', '')
.replaceAll('^http://', '')
.replaceAll('\\.', '.')
.replaceAll('.+', '*')
.replaceAll('\\d', '*')
.replaceAll('([a-z])', '*')
.replaceAll('[a-z]', '*')
.replaceAll('([0-9])', '*')
.replaceAll('[0-9]', '*')
.replaceAll(/{.+?}/g, '')
.replaceAll(/\*+/g, '*')
}))
);
}));
let mitmDomains = new Set(PRESET_MITM_HOSTNAMES); // Special case for parsed failed
const parsedFailures = new Set();
const dedupedUrlRegexPaths = [...new Set(urlRegexPaths)];
dedupedUrlRegexPaths.forEach(i => {
const result = parseDomain(i.processed);
if (result.success) {
mitmDomains.add(result.hostname.trim());
} else {
parsedFailures.add(i.origin);
}
});
mitmDomains = [...mitmDomains].filter(i => {
return i.length > 3
&& !i.includes('.mp4') // Special Case
&& i !== '(www.)' // Special Case
&& !(i !== '*.meituan.net' && i.endsWith('.meituan.net'))
&& !i.startsWith('.')
&& !i.endsWith('.')
&& !i.endsWith('*')
});
const mitmDomainsRegExpArray = mitmDomains.map(i => {
return new RegExp(
escapeRegExp(i)
.replaceAll('{www or not}', '(www.)?')
.replaceAll('\\*', '(.*)')
)
});
const parsedDomainsData = [];
dedupedUrlRegexPaths.forEach(i => {
const result = parseDomain(i.processed);
if (result.success) {
if (matchWithRegExpArray(result.hostname.trim(), mitmDomainsRegExpArray)) {
parsedDomainsData.push([green(result.hostname), i.origin]);
} else {
parsedDomainsData.push([yellow(result.hostname), i.origin]);
}
}
});
console.log('Mitm Hostnames:');
console.log('hostname = %APPEND% ' + mitmDomains.join(', '));
console.log('--------------------');
console.log('Parsed Sucessed:');
console.log(table.table(parsedDomainsData, {
border: table.getBorderCharacters('void'),
columnDefault: {
paddingLeft: 0,
paddingRight: 3
},
drawHorizontalLine: () => false
}));
console.log('--------------------');
console.log('Parsed Failed');
console.log([...parsedFailures].join('\n'));
})();
/** Util function */
function parseDomain(input) {
try {
const url = new URL(`https://${input}`);
return {
success: true,
hostname: url.hostname
}
} catch {
return {
success: false
}
}
}
function matchWithRegExpArray(input, regexps = []) {
for (const r of regexps) {
if (r.test(input)) return true;
}
return false;
}
function escapeRegExp(string = '') {
const reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
const reHasRegExpChar = RegExp(reRegExpChar.source);
return string && reHasRegExpChar.test(string)
? string.replace(reRegExpChar, '\\$&')
: string;
}

View File

@@ -1,73 +0,0 @@
const psl = require('psl');
const { processFilterRules } = require('./lib/parse-filter.js');
const fs = require('fs');
const path = require('path');
const WHITELIST_DOMAIN = new Set([]);
const BLACK_TLD = [
'.xyz',
'.top',
'.win',
'.vip',
'.site',
'.space',
'.online',
'.icu',
'.fun',
'.shop',
'.cool',
'.cyou',
'.id',
'.pro'
];
(async () => {
const domainSet = Array.from(
(
await processFilterRules('https://curbengh.github.io/phishing-filter/phishing-filter-agh.txt')
).black
);
const domainCountMap = {};
for (let i = 0, len = domainSet.length; i < len; i++) {
const line = domainSet[i];
// starts with #
if (line.charCodeAt(0) === 35) {
continue;
}
if (line.trim().length === 0) {
continue;
}
const domain = line.charCodeAt(0) === 46 ? line.slice(1) : line;
if (line.length > 25) {
const parsed = psl.parse(domain);
if (parsed.input === parsed.tld) {
continue;
}
const apexDomain = parsed.domain
if (WHITELIST_DOMAIN.has(apexDomain)) {
continue;
}
domainCountMap[apexDomain] ||= 0;
domainCountMap[apexDomain] += 1;
}
}
const results = [];
Object.entries(domainCountMap).forEach(([domain, count]) => {
if (
count >= 8
&& BLACK_TLD.some(tld => domain.endsWith(tld))
) {
results.push('.' + domain);
}
});
const filePath = path.resolve(__dirname, '../List/domainset/reject_phishing.conf');
await fs.promises.writeFile(filePath, results.join('\n'), 'utf-8');
})();

View File

@@ -1,330 +0,0 @@
const { promises: fsPromises } = require('fs');
const { resolve: pathResolve } = require('path');
const Piscina = require('piscina');
const { processHosts, processFilterRules, preprocessFullDomainSetBeforeUsedAsWorkerData } = require('./lib/parse-filter');
const cpuCount = require('os').cpus().length;
const { isCI } = require('ci-info');
const threads = isCI ? cpuCount : cpuCount / 2;
(async () => {
console.time('Total Time - build-reject-domain-set');
/** @type Set<string> */
const domainSets = new Set();
console.log('Downloading hosts file...');
console.time('* Download and process Hosts');
// Parse from remote hosts & domain lists
(await Promise.all([
processHosts('https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=0&mimetype=plaintext', true),
processHosts('https://raw.githubusercontent.com/hoshsadiq/adblock-nocoin-list/master/hosts.txt'),
processHosts('https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy.txt')
])).forEach(hosts => {
hosts.forEach(host => {
if (host) {
domainSets.add(host);
}
});
});
console.timeEnd('* Download and process Hosts');
let previousSize = domainSets.size;
console.log(`Import ${previousSize} rules from hosts files!`);
await fsPromises.readFile(pathResolve(__dirname, '../List/domainset/reject_sukka.conf'), { encoding: 'utf-8' }).then(data => {
data.split('\n').forEach(line => {
const trimmed = line.trim();
if (
line.startsWith('#')
|| line.startsWith(' ')
|| line.startsWith('\r')
|| line.startsWith('\n')
|| trimmed === ''
) {
return;
}
/* if (domainSets.has(line) || domainSets.has(`.${line}`)) {
console.warn(`|${line}| is already in the list!`);
} */
domainSets.add(trimmed);
});
});
previousSize = domainSets.size - previousSize;
console.log(`Import ${previousSize} rules from reject_sukka.conf!`);
// Parse from AdGuard Filters
/** @type Set<string> */
const filterRuleWhitelistDomainSets = new Set([
'localhost',
'broadcasthost',
'ip6-loopback',
'ip6-localnet',
'ip6-mcastprefix',
'ip6-allnodes',
'ip6-allrouters',
'ip6-allhosts',
'mcastprefix',
'skk.moe',
'analytics.google.com',
'msa.cdn.mediaset.net', // Added manually using DOMAIN-KEYWORDS
'cloud.answerhub.com',
'ae01.alicdn.com',
'whoami.akamai.net',
'whoami.ds.akahelp.net',
'pxlk9.net.', // This one is malformed from EasyList, which I will manually add instead
'instant.page', // No, it doesn't violate anyone's privacy. I will whitelist it
'piwik.pro',
'mixpanel.com',
'cdn.mxpnl.com',
'heapanalytics.com',
'segment.com',
'segmentify.com',
't.co', // pgl yoyo add t.co to the blacklist
'survicate.com', // AdGuardDNSFilter
'perfops.io', // AdGuardDNSFilter
'd2axgrpnciinw7.cloudfront.net', // ADGuardDNSFilter
'tb-lb.sb-cd.com', // AdGuard
'storage.yandexcloud.net', // phishing list
'login.microsoftonline.com' // phishing list
]);
console.time('* Download and process AdBlock Filter Rules');
(await Promise.all([
// Easy List
[
'https://easylist.to/easylist/easylist.txt',
[
'https://easylist-downloads.adblockplus.org/easylist.txt',
'https://raw.githubusercontent.com/easylist/easylist/gh-pages/easylist.txt',
'https://secure.fanboy.co.nz/easylist.txt'
]
],
// AdGuard DNS Filter
'https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt',
// uBlock Origin Filter List
'https://ublockorigin.github.io/uAssetsCDN/filters/filters.txt',
'https://ublockorigin.github.io/uAssetsCDN/filters/filters-2020.txt',
'https://ublockorigin.github.io/uAssetsCDN/filters/filters-2021.txt',
'https://ublockorigin.github.io/uAssetsCDN/filters/filters-2022.txt',
// uBlock Origin Badware Risk List
'https://ublockorigin.github.io/uAssets/filters/badware.txt',
// uBlock Origin Privacy List
'https://ublockorigin.github.io/uAssets/filters/privacy.txt',
// uBlock Origin Resource Abuse
'https://ublockorigin.github.io/uAssets/filters/resource-abuse.txt',
// uBlock Origin Unbreak
'https://ublockorigin.github.io/uAssets/filters/unbreak.txt',
// AdGuard Base Filter
'https://filters.adtidy.org/extension/ublock/filters/2_without_easylist.txt',
// AdGuard Mobile AD
'https://filters.adtidy.org/extension/ublock/filters/11.txt',
// AdGuard Tracking Protection
'https://filters.adtidy.org/extension/ublock/filters/3.txt',
// AdGuard Japanese filter
'https://filters.adtidy.org/extension/ublock/filters/7.txt',
// AdGuard Chinese filter (EasyList China + AdGuard Chinese filter)
'https://filters.adtidy.org/extension/ublock/filters/224.txt',
// Easy Privacy
[
'https://easylist.to/easylist/easyprivacy.txt',
[
'https://secure.fanboy.co.nz/easyprivacy.txt',
'https://raw.githubusercontent.com/easylist/easylist/gh-pages/easyprivacy.txt',
'https://easylist-downloads.adblockplus.org/easyprivacy.txt'
]
],
// Curben's UrlHaus Malicious URL Blocklist
// Prefer mirror, since malware-filter.gitlab.io has not been updated for a while
'https://curbengh.github.io/urlhaus-filter/urlhaus-filter-agh-online.txt',
// [
// 'https://malware-filter.pages.dev/urlhaus-filter-agh-online.txt',
// [
// 'https://malware-filter.gitlab.io/urlhaus-filter/urlhaus-filter-agh-online.txt'
// ]
// ],
// Curben's Phishing URL Blocklist
// Prefer mirror, since malware-filter.gitlab.io has not been updated for a while
'https://curbengh.github.io/phishing-filter/phishing-filter-agh.txt',
// [
// 'https://phishing-filter.pages.dev/phishing-filter-agh.txt',
// [
// 'https://malware-filter.gitlab.io/malware-filter/phishing-filter-agh.txt'
// ]
// ],
// Curben's PUP Domains Blocklist
'https://curbengh.github.io/pup-filter/pup-filter-agh.txt',
// Prefer mirror, since malware-filter.gitlab.io has not been updated for a while
// [
// 'https://pup-filter.pages.dev/pup-filter-agh.txt',
// [
// 'https://malware-filter.gitlab.io/malware-filter/pup-filter-agh.txt'
// ]
// ],
// GameConsoleAdblockList
'https://raw.githubusercontent.com/DandelionSprout/adfilt/master/GameConsoleAdblockList.txt',
// PiHoleBlocklist
'https://raw.githubusercontent.com/Perflyst/PiHoleBlocklist/master/SmartTV-AGH.txt',
// Spam404
'https://raw.githubusercontent.com/Spam404/lists/master/adblock-list.txt'
].map(input => {
if (typeof input === 'string') {
return processFilterRules(input);
}
if (Array.isArray(input) && input.length === 2) {
return processFilterRules(input[0], input[1]);
}
}))).forEach(({ white, black }) => {
white.forEach(i => filterRuleWhitelistDomainSets.add(i));
black.forEach(i => domainSets.add(i));
});
console.timeEnd('* Download and process AdBlock Filter Rules');
previousSize = domainSets.size - previousSize;
console.log(`Import ${previousSize} rules from adguard filters!`);
// Read DOMAIN Keyword
const domainKeywordsSet = new Set();
const domainSuffixSet = new Set();
await fsPromises.readFile(pathResolve(__dirname, '../List/non_ip/reject.conf'), { encoding: 'utf-8' }).then(data => {
data.split('\n').forEach(line => {
if (line.startsWith('DOMAIN-KEYWORD')) {
const [, ...keywords] = line.split(',');
domainKeywordsSet.add(keywords.join(',').trim());
} else if (line.startsWith('DOMAIN-SUFFIX')) {
const [, ...keywords] = line.split(',');
domainSuffixSet.add(keywords.join(',').trim());
}
});
});
// Read Special Phishing Suffix list
await fsPromises.readFile(pathResolve(__dirname, '../List/domainset/reject_phishing.conf'), { encoding: 'utf-8' }).then(data => {
data.split('\n').forEach(line => {
const trimmed = line.trim();
if (
line.startsWith('#')
|| line.startsWith(' ')
|| line.startsWith('\r')
|| line.startsWith('\n')
|| trimmed === ''
) {
return;
}
/* if (domainSets.has(line) || domainSets.has(`.${line}`)) {
console.warn(`|${line}| is already in the list!`);
} */
domainSuffixSet.add(trimmed);
});
});
console.log(`Import ${domainKeywordsSet.size} black keywords and ${domainSuffixSet.size} black suffixes!`);
previousSize = domainSets.size;
// Dedupe domainSets
console.log(`Start deduping from black keywords/suffixes! (${previousSize})`);
console.time(`* Dedupe from black keywords/suffixes`);
for (const domain of domainSets) {
let isTobeRemoved = false;
for (const keyword of domainKeywordsSet) {
if (domain.includes(keyword)) {
isTobeRemoved = true;
break;
}
}
if (!isTobeRemoved) {
for (const suffix of domainSuffixSet) {
if (domain.endsWith(suffix)) {
isTobeRemoved = true;
break;
}
}
}
if (!isTobeRemoved) {
for (const white of filterRuleWhitelistDomainSets) {
if (domain.includes(white) || white.includes(domain)) {
isTobeRemoved = true;
break;
}
}
}
if (isTobeRemoved) {
domainSets.delete(domain);
}
}
console.timeEnd(`* Dedupe from black keywords/suffixes`);
console.log(`Deduped ${previousSize} - ${domainSets.size} = ${previousSize - domainSets.size} from black keywords and suffixes!`);
previousSize = domainSets.size;
// Dedupe domainSets
console.log(`Start deduping! (${previousSize})`);
const START_TIME = Date.now();
const piscina = new Piscina({
filename: pathResolve(__dirname, 'worker/build-reject-domainset-worker.js'),
workerData: preprocessFullDomainSetBeforeUsedAsWorkerData([...domainSets]),
idleTimeout: 50,
minThreads: threads,
maxThreads: threads
});
console.log(`Launching ${threads} threads...`)
const tasksArray = Array.from(domainSets)
.reduce((result, element, index) => {
const chunk = index % threads;
result[chunk] ??= [];
result[chunk].push(element);
return result;
}, []);
(
await Promise.all(
Array.from(domainSets)
.reduce((result, element, index) => {
const chunk = index % threads;
result[chunk] ??= [];
result[chunk].push(element);
return result;
}, [])
.map(chunk => piscina.run({ chunk }, { name: 'dedupe' }))
)
).forEach((result, taskIndex) => {
const chunk = tasksArray[taskIndex];
result.forEach((value, index) => {
if (value === 1) {
domainSets.delete(chunk[index])
}
})
});
console.log(`* Dedupe from covered subdomain - ${(Date.now() - START_TIME) / 1000}s`);
console.log(`Deduped ${previousSize - domainSets.size} rules!`);
await Promise.all([
fsPromises.writeFile(
pathResolve(__dirname, '../List/domainset/reject.conf'),
`${[...domainSets].join('\n')}\n`,
{ encoding: 'utf-8' }
),
piscina.destroy()
]);
console.timeEnd('Total Time - build-reject-domain-set');
if (piscina.queueSize === 0) {
process.exit(0);
}
})();

View File

@@ -1,34 +0,0 @@
const { fetchWithRetry } = require('./lib/fetch-retry');
const fs = require('fs');
const path = require('path');
const { isIPv4, isIPv6 } = require('net');
(async () => {
console.time('Total Time - build-telegram-cidr');
const resp = await fetchWithRetry('https://core.telegram.org/resources/cidr.txt');
const lastModified = new Date(resp.headers.get('last-modified'));
const res = (await resp.text())
.split('\n')
.filter(line => line.trim() !== '');
await fs.promises.writeFile(
path.resolve(__dirname, '../List/ip/telegram.conf'),
'# Telegram CIDR (https://core.telegram.org/resources/cidr.txt)' + '\n' +
'# Last Updated: ' + lastModified.toISOString() + '\n' +
res.map(ip => {
const [subnet] = ip.split('/');
if (isIPv4(subnet)) {
return `IP-CIDR,${ip},no-resolve`;
}
if (isIPv6(subnet)) {
return `IP-CIDR6,${ip},no-resolve`;
}
return '';
}).join('\n') + '\n',
'utf-8'
);
console.timeEnd('Total Time - build-telegram-cidr');
})();

View File

@@ -1,3 +0,0 @@
const { fetch } = require('undici');
const fetchWithRetry = require('@vercel/fetch-retry')(fetch);
module.exports.fetchWithRetry = fetchWithRetry;

View File

@@ -1,248 +0,0 @@
const { isIP } = require('net');
const { fetchWithRetry } = require('./fetch-retry');
const rDomain = /^(((?!\-))(xn\-\-)?[a-z0-9\-_]{0,61}[a-z0-9]{1,1}\.)*(xn\-\-)?([a-z0-9\-]{1,61}|[a-z0-9\-]{1,30})\.[a-z]{2,}$/m
const DEBUG_DOMAIN_TO_FIND = null; // example.com | null
const warnOnceUrl = new Set();
const warnOnce = (url, isWhite, ...message) => {
const key = `${url}${isWhite ? 'white' : 'black'}`;
if (warnOnceUrl.has(key)) {
return;
}
warnOnceUrl.add(key);
console.warn(url, isWhite ? '(white)' : '(black)', ...message);
}
/**
* @param {string | URL} domainListsUrl
*/
async function processDomainLists (domainListsUrl) {
if (typeof domainListsUrl === 'string') {
domainListsUrl = new URL(domainListsUrl);
}
/** @type Set<string> */
const domainSets = new Set();
/** @type string[] */
const domains = (await (await fetchWithRetry(domainListsUrl)).text()).split('\n');
domains.forEach(line => {
if (
line.startsWith('#')
|| line.startsWith('!')
|| line.startsWith(' ')
|| line === ''
|| line.startsWith('\r')
|| line.startsWith('\n')
) {
return;
}
const domainToAdd = line.trim();
if (DEBUG_DOMAIN_TO_FIND && domainToAdd.includes(DEBUG_DOMAIN_TO_FIND)) {
warnOnce(domainListsUrl.toString(), false, DEBUG_DOMAIN_TO_FIND);
}
domainSets.add(domainToAdd);
});
return [...domainSets];
}
/**
* @param {string | URL} hostsUrl
*/
async function processHosts (hostsUrl, includeAllSubDomain = false) {
console.time(` - processHosts: ${hostsUrl}`);
if (typeof hostsUrl === 'string') {
hostsUrl = new URL(hostsUrl);
}
/** @type Set<string> */
const domainSets = new Set();
/** @type string[] */
const hosts = (await (await fetchWithRetry(hostsUrl)).text()).split('\n');
hosts.forEach(line => {
if (line.includes('#')) {
return;
}
if (line.startsWith(' ') || line.startsWith('\r') || line.startsWith('\n') || line.trim() === '') {
return;
}
const [, ...domains] = line.split(' ');
const domain = domains.join(' ').trim();
if (DEBUG_DOMAIN_TO_FIND && domain.includes(DEBUG_DOMAIN_TO_FIND)) {
warnOnce(hostsUrl.toString(), false, DEBUG_DOMAIN_TO_FIND);
}
if (rDomain.test(domain)) {
if (includeAllSubDomain) {
domainSets.add(`.${domain}`);
} else {
domainSets.add(domain);
}
}
});
console.timeEnd(` - processHosts: ${hostsUrl}`);
return [...domainSets];
}
/**
* @param {string | URL} filterRulesUrl
* @param {(string | URL)[] | undefined} fallbackUrls
* @returns {Promise<{ white: Set<string>, black: Set<string> }>}
*/
async function processFilterRules (filterRulesUrl, fallbackUrls) {
console.time(` - processFilterRules: ${filterRulesUrl}`);
/** @type Set<string> */
const whitelistDomainSets = new Set();
/** @type Set<string> */
const blacklistDomainSets = new Set();
let filterRules;
try {
/** @type string[] */
filterRules = (
await Promise.any(
[filterRulesUrl, ...(fallbackUrls || [])].map(
async url => (await fetchWithRetry(url)).text()
)
)
).split('\n').map(line => line.trim());
} catch (e) {
console.log('Download Rule for [' + filterRulesUrl + '] failed');
throw e;
}
filterRules.forEach(line => {
const lineStartsWithDoubleVerticalBar = line.startsWith('||');
if (
line === ''
|| line.includes('#')
|| line.includes('!')
|| line.includes('*')
|| line.includes('/')
|| line.includes('[')
|| line.includes('$') && !lineStartsWithDoubleVerticalBar
|| line === ''
|| isIP(line) !== 0
) {
return;
}
const lineEndsWithCaret = line.endsWith('^');
const lineEndsWithCaretVerticalBar = line.endsWith('^|');
if (lineStartsWithDoubleVerticalBar && line.endsWith('^$badfilter')) {
const domain = line.replace('||', '').replace('^$badfilter', '').trim();
if (rDomain.test(domain)) {
if (DEBUG_DOMAIN_TO_FIND && domain.includes(DEBUG_DOMAIN_TO_FIND)) {
warnOnce(filterRulesUrl.toString(), true, DEBUG_DOMAIN_TO_FIND);
}
whitelistDomainSets.add(domain);
}
} else if (line.startsWith('@@||')
&& (
lineEndsWithCaret
|| lineEndsWithCaretVerticalBar
|| line.endsWith('^$badfilter')
|| line.endsWith('^$1p')
)
) {
const domain = line
.replaceAll('@@||', '')
.replaceAll('^$badfilter', '')
.replaceAll('^$1p', '')
.replaceAll('^|', '')
.replaceAll('^', '')
.trim();
if (rDomain.test(domain)) {
if (DEBUG_DOMAIN_TO_FIND && domain.includes(DEBUG_DOMAIN_TO_FIND)) {
warnOnce(filterRulesUrl.toString(), true, DEBUG_DOMAIN_TO_FIND);
}
whitelistDomainSets.add(domain);
}
} else if (
lineStartsWithDoubleVerticalBar
&& (
lineEndsWithCaret
|| lineEndsWithCaretVerticalBar
|| line.endsWith('^$all')
)
) {
const domain = line
.replaceAll('||', '')
.replaceAll('^|', '')
.replaceAll('^$all', '')
.replaceAll('^', '')
.trim();
if (rDomain.test(domain)) {
if (DEBUG_DOMAIN_TO_FIND && domain.includes(DEBUG_DOMAIN_TO_FIND)) {
warnOnce(filterRulesUrl.toString(), false, DEBUG_DOMAIN_TO_FIND);
}
blacklistDomainSets.add(`.${domain}`);
}
} else if (line.startsWith('://')
&& (
lineEndsWithCaret
|| lineEndsWithCaretVerticalBar
)
) {
const domain = `${line.replaceAll('://', '').replaceAll('^|', '').replaceAll('^', '')}`.trim();
if (rDomain.test(domain)) {
if (DEBUG_DOMAIN_TO_FIND && domain.includes(DEBUG_DOMAIN_TO_FIND)) {
warnOnce(filterRulesUrl.toString(), false, DEBUG_DOMAIN_TO_FIND);
}
blacklistDomainSets.add(domain);
}
}
});
console.timeEnd(` - processFilterRules: ${filterRulesUrl}`);
return {
white: whitelistDomainSets,
black: blacklistDomainSets
};
}
function preprocessFullDomainSetBeforeUsedAsWorkerData (data) {
return data.filter(domain => (
domain.charCodeAt(0) === 46
&& !canExcludeFromDedupe(domain)
));
}
// duckdns.org domain will not overlap and doesn't need dedupe
function canExcludeFromDedupe (domain) {
if (
// starts with a dot
domain.charCodeAt(0) === 46
&& domain.length === 23
&& domain.endsWith('.duckdns.org')
) {
return true;
}
return false;
}
module.exports.processDomainLists = processDomainLists;
module.exports.processHosts = processHosts;
module.exports.processFilterRules = processFilterRules;
module.exports.preprocessFullDomainSetBeforeUsedAsWorkerData = preprocessFullDomainSetBeforeUsedAsWorkerData;
module.exports.canExcludeFromDedupe = canExcludeFromDedupe;

View File

@@ -1,57 +0,0 @@
const psl = require('psl');
const picocolors = require('picocolors');
const fs = require('fs');
const path = require('path');
(async () => {
const domainSetContent = await fs.promises.readFile(
path.resolve(__dirname, '../List/domainset/cdn.conf'),
{ encoding: 'utf-8' }
);
const domainSetLines = domainSetContent.split('\n');
for (let i = 0, len = domainSetLines.length; i < len; i++) {
const line = domainSetLines[i];
// starts with #
if (line.charCodeAt(0) === 35) {
continue;
}
if (line.trim().length === 0) {
continue;
}
const domain = line.charCodeAt(0) === 46 ? line.slice(1) : line;
const parsed = psl.parse(domain);
if (parsed.listed && parsed.input === parsed.tld) {
console.error('Domain', picocolors.yellow(domain), picocolors.red('is in public suffix list!'));
}
}
const rulesetContent = await fs.promises.readFile(
path.resolve(__dirname, '../List/non_ip/cdn.conf'),
{ encoding: 'utf-8' }
);
const rulesetLines = rulesetContent.split('\n');
for (let i = 0, len = rulesetLines.length; i < len; i++) {
const line = rulesetLines[i];
// starts with #
if (line.charCodeAt(0) === 35) {
continue;
}
if (line.trim().length === 0) {
continue;
}
if (line.startsWith('DOMAIN-SUFFIX')) {
const domain = line.slice(14);
const parsed = psl.parse(domain);
if (parsed.input !== parsed.tld) {
console.error('Domain', picocolors.yellow(domain), picocolors.green('is not in public suffix list!'));
}
}
}
})();

View File

@@ -1,56 +0,0 @@
const Piscina = require('piscina');
const { canExcludeFromDedupe } = require('../lib/parse-filter')
const fullsetDomainStartsWithADot = Piscina.workerData
const totalLen = fullsetDomainStartsWithADot.length;
module.exports.dedupe = ({ chunk }) => {
const chunkLength = chunk.length;
const outputToBeRemoved = new Int8Array(chunkLength);
for (let i = 0; i < chunkLength; i++) {
const domainFromInput = chunk[i];
if (canExcludeFromDedupe(domainFromInput)) {
continue;
}
for (let j = 0; j < totalLen; j++) {
const domainFromFullSet = fullsetDomainStartsWithADot[j];
// domainFromFullSet is now startsWith a "."
if (domainFromFullSet === domainFromInput) continue;
const domainFromInputLen = domainFromInput.length;
const domainFromFullSetLen = domainFromFullSet.length;
// !domainFromInput.starsWith('.') && `.${domainFromInput}` === domainFromFullSet
if (domainFromInput.charCodeAt(0) !== 46) {
if (domainFromInputLen + 1 === domainFromFullSetLen) {
let shouldBeRemoved = true;
for (let k = 0; k < domainFromInputLen; k++) {
if (domainFromFullSet.charCodeAt(k + 1) !== domainFromInput.charCodeAt(k)) {
shouldBeRemoved = false;
break;
}
}
if (shouldBeRemoved) {
outputToBeRemoved[i] = 1;
break;
}
}
} else if (domainFromInputLen > domainFromFullSetLen) {
// domainFromInput is now startsWith a "."
if (domainFromInput.endsWith(domainFromFullSet)) {
outputToBeRemoved[i] = 1;
break;
}
}
}
}
return Piscina.move(outputToBeRemoved);
};

View File

@@ -1,7 +1,7 @@
############################
# Mainland China IPv4 CIDR
# Data from misaka.io (misakaio @ GitHub)
# Last Updated: 2022-11-01T12:14:31.663Z
# Last Updated: 2022-11-01T12:19:49.696Z
# Routes: 3183
############################
IP-CIDR,1.2.4.0/24

View File

@@ -24,7 +24,7 @@
<main class="container">
<h1>Sukka Surge Ruleset Server</h1>
<p>Made by <a href="https://skk.moe">Sukka</a> | <a href="https://github.com/SukkaW/Surge/">Source @ GitHub</a> | Licensed under <a href="https://github.com/SukkaW/Surge/blob/master/LICENSE" target="_blank">AGPL-3.0</a></p>
<p>Last Updated: 2022-11-01T12:16:42.581Z</p>
<p>Last Updated: 2022-11-01T12:21:57.063Z</p>
<hr>
<br>
<ul>

View File

@@ -1,88 +0,0 @@
{
"name": "ruleset.skk.moe",
"version": "0.0.0",
"private": true,
"description": "",
"scripts": {
"build": "wireit",
"build:anti-bogus-domain": "wireit",
"build:apple-cdn": "wireit",
"build:cdn-conf": "wireit",
"build:index-html": "wireit",
"build:reject-domainset": "wireit",
"build:phishing-domainset": "wireit",
"build:telegram-cidr": "wireit",
"build:chn-cidr": "wireit",
"validate:cdn-conf": "wireit"
},
"wireit": {
"build:anti-bogus-domain": {
"command": "node ./Build/build-anti-bogus-domain.js"
},
"build:apple-cdn": {
"command": "node ./Build/build-apple-cdn.js"
},
"build:cdn-conf": {
"command": "node ./Build/build-cdn-conf.js"
},
"build:phishing-domainset": {
"command": "node ./Build/build-phishing-domainset.js"
},
"build:reject-domainset": {
"command": "node ./Build/build-reject-domainset.js",
"dependencies": [
"build:phishing-domainset"
]
},
"build:telegram-cidr": {
"command": "node ./Build/build-telegram-cidr.js"
},
"build:chn-cidr": {
"command": "node ./Build/build-chn-cidr.js"
},
"build:index-html": {
"command": "node ./Build/build-index.html.js",
"dependencies": [
"build:anti-bogus-domain",
"build:apple-cdn",
"build:cdn-conf",
"build:reject-domainset",
"build:telegram-cidr"
]
},
"validate:cdn-conf": {
"command": "node ./Build/validate-cdn-conf.js"
},
"build": {
"dependencies": [
"build:anti-bogus-domain",
"build:apple-cdn",
"build:cdn-conf",
"build:reject-domainset",
"build:telegram-cidr",
"build:chn-cidr",
"build:index-html",
"validate:cdn-conf"
]
}
},
"repository": {
"type": "git",
"url": "git+https://github.com/SukkaW/Surge.git"
},
"author": "",
"license": "ISC",
"dependencies": {
"@sukka/listdir": "^0.2.0",
"@vercel/fetch-retry": "^5.1.3",
"ci-info": "^3.5.0",
"picocolors": "^1.0.0",
"piscina": "^3.2.0",
"psl": "^1.9.0",
"table": "^6.8.0",
"undici": "5.11.0"
},
"devDependencies": {
"wireit": "^0.7.2"
}
}

477
pnpm-lock.yaml generated
View File

@@ -1,477 +0,0 @@
lockfileVersion: 5.4
specifiers:
'@sukka/listdir': ^0.2.0
'@vercel/fetch-retry': ^5.1.3
ci-info: ^3.5.0
picocolors: ^1.0.0
piscina: ^3.2.0
psl: ^1.9.0
table: ^6.8.0
undici: 5.11.0
wireit: ^0.7.2
dependencies:
'@sukka/listdir': 0.2.0
'@vercel/fetch-retry': 5.1.3
ci-info: 3.5.0
picocolors: 1.0.0
piscina: 3.2.0
psl: 1.9.0
table: 6.8.0
undici: 5.11.0
devDependencies:
wireit: 0.7.2
packages:
/@assemblyscript/loader/0.10.1:
resolution: {integrity: sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==}
dev: false
/@nodelib/fs.scandir/2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
dependencies:
'@nodelib/fs.stat': 2.0.5
run-parallel: 1.2.0
dev: true
/@nodelib/fs.stat/2.0.5:
resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
engines: {node: '>= 8'}
dev: true
/@nodelib/fs.walk/1.2.8:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
dependencies:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.13.0
dev: true
/@sukka/listdir/0.2.0:
resolution: {integrity: sha512-UyVirNhAOXKwjiDehjUaGtpfk0QwNHyiXrlLb/FmWMtI+BGhaEvB9MypSfEAtiiMI3g6QTfG38ayNAorEuz5ow==}
dev: false
/@vercel/fetch-retry/5.1.3:
resolution: {integrity: sha512-UIbFc4VsEZHOr6dWuE+kxY4NxnOLXFMCWm0fSKRRHUEtrIzaJLzHpWk2QskCXTSzFgFvhkLAvSrBK2XZg7NSzg==}
peerDependencies:
node-fetch: ^2.6.7
dependencies:
async-retry: 1.3.3
debug: 4.3.4
transitivePeerDependencies:
- supports-color
dev: false
/ajv/8.8.2:
resolution: {integrity: sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==}
dependencies:
fast-deep-equal: 3.1.3
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
uri-js: 4.4.1
dev: false
/ansi-regex/5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
dev: false
/ansi-styles/4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
dependencies:
color-convert: 2.0.1
dev: false
/anymatch/3.1.2:
resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==}
engines: {node: '>= 8'}
dependencies:
normalize-path: 3.0.0
picomatch: 2.3.1
dev: true
/astral-regex/2.0.0:
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
engines: {node: '>=8'}
dev: false
/async-retry/1.3.3:
resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==}
dependencies:
retry: 0.13.1
dev: false
/base64-js/1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
dev: false
/binary-extensions/2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
dev: true
/braces/3.0.2:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
engines: {node: '>=8'}
dependencies:
fill-range: 7.0.1
dev: true
/busboy/1.6.0:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
engines: {node: '>=10.16.0'}
dependencies:
streamsearch: 1.1.0
dev: false
/chokidar/3.5.3:
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
engines: {node: '>= 8.10.0'}
dependencies:
anymatch: 3.1.2
braces: 3.0.2
glob-parent: 5.1.2
is-binary-path: 2.1.0
is-glob: 4.0.3
normalize-path: 3.0.0
readdirp: 3.6.0
optionalDependencies:
fsevents: 2.3.2
dev: true
/ci-info/3.5.0:
resolution: {integrity: sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==}
dev: false
/color-convert/2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
dependencies:
color-name: 1.1.4
dev: false
/color-name/1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: false
/debug/4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
dependencies:
ms: 2.1.2
dev: false
/emoji-regex/8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
dev: false
/eventemitter-asyncresource/1.0.0:
resolution: {integrity: sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==}
dev: false
/fast-deep-equal/3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: false
/fast-glob/3.2.11:
resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==}
engines: {node: '>=8.6.0'}
dependencies:
'@nodelib/fs.stat': 2.0.5
'@nodelib/fs.walk': 1.2.8
glob-parent: 5.1.2
merge2: 1.4.1
micromatch: 4.0.5
dev: true
/fastq/1.13.0:
resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==}
dependencies:
reusify: 1.0.4
dev: true
/fill-range/7.0.1:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'}
dependencies:
to-regex-range: 5.0.1
dev: true
/fsevents/2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
dev: true
optional: true
/glob-parent/5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
dependencies:
is-glob: 4.0.3
dev: true
/graceful-fs/4.2.10:
resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==}
dev: true
/hdr-histogram-js/2.0.1:
resolution: {integrity: sha512-uPZxl1dAFnjUFHWLZmt93vUUvtHeaBay9nVNHu38SdOjMSF/4KqJUqa1Seuj08ptU1rEb6AHvB41X8n/zFZ74Q==}
dependencies:
'@assemblyscript/loader': 0.10.1
base64-js: 1.5.1
pako: 1.0.11
dev: false
/hdr-histogram-percentiles-obj/3.0.0:
resolution: {integrity: sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==}
dev: false
/is-binary-path/2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
dependencies:
binary-extensions: 2.2.0
dev: true
/is-extglob/2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
dev: true
/is-fullwidth-code-point/3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
dev: false
/is-glob/4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
dependencies:
is-extglob: 2.1.1
dev: true
/is-number/7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
dev: true
/json-schema-traverse/1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
dev: false
/jsonc-parser/3.0.0:
resolution: {integrity: sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==}
dev: true
/lodash.truncate/4.4.2:
resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==}
dev: false
/merge2/1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
dev: true
/micromatch/4.0.5:
resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
engines: {node: '>=8.6'}
dependencies:
braces: 3.0.2
picomatch: 2.3.1
dev: true
/ms/2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: false
/nice-napi/1.0.2:
resolution: {integrity: sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==}
os: ['!win32']
requiresBuild: true
dependencies:
node-addon-api: 3.2.1
node-gyp-build: 4.3.0
dev: false
optional: true
/node-addon-api/3.2.1:
resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==}
dev: false
optional: true
/node-gyp-build/4.3.0:
resolution: {integrity: sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==}
hasBin: true
dev: false
optional: true
/normalize-path/3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
dev: true
/pako/1.0.11:
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
dev: false
/picocolors/1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
dev: false
/picomatch/2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
dev: true
/piscina/3.2.0:
resolution: {integrity: sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==}
dependencies:
eventemitter-asyncresource: 1.0.0
hdr-histogram-js: 2.0.1
hdr-histogram-percentiles-obj: 3.0.0
optionalDependencies:
nice-napi: 1.0.2
dev: false
/proper-lockfile/4.1.2:
resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==}
dependencies:
graceful-fs: 4.2.10
retry: 0.12.0
signal-exit: 3.0.7
dev: true
/psl/1.9.0:
resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
dev: false
/punycode/2.1.1:
resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
engines: {node: '>=6'}
dev: false
/queue-microtask/1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true
/readdirp/3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
dependencies:
picomatch: 2.3.1
dev: true
/require-from-string/2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
dev: false
/retry/0.12.0:
resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==}
engines: {node: '>= 4'}
dev: true
/retry/0.13.1:
resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
engines: {node: '>= 4'}
dev: false
/reusify/1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
dev: true
/run-parallel/1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
queue-microtask: 1.2.3
dev: true
/signal-exit/3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
dev: true
/slice-ansi/4.0.0:
resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
engines: {node: '>=10'}
dependencies:
ansi-styles: 4.3.0
astral-regex: 2.0.0
is-fullwidth-code-point: 3.0.0
dev: false
/streamsearch/1.1.0:
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
engines: {node: '>=10.0.0'}
dev: false
/string-width/4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
dependencies:
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
dev: false
/strip-ansi/6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
dependencies:
ansi-regex: 5.0.1
dev: false
/table/6.8.0:
resolution: {integrity: sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==}
engines: {node: '>=10.0.0'}
dependencies:
ajv: 8.8.2
lodash.truncate: 4.4.2
slice-ansi: 4.0.0
string-width: 4.2.3
strip-ansi: 6.0.1
dev: false
/to-regex-range/5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
dependencies:
is-number: 7.0.0
dev: true
/undici/5.11.0:
resolution: {integrity: sha512-oWjWJHzFet0Ow4YZBkyiJwiK5vWqEYoH7BINzJAJOLedZ++JpAlCbUktW2GQ2DS2FpKmxD/JMtWUUWl1BtghGw==}
engines: {node: '>=12.18'}
dependencies:
busboy: 1.6.0
dev: false
/uri-js/4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
dependencies:
punycode: 2.1.1
dev: false
/wireit/0.7.2:
resolution: {integrity: sha512-Zjq50QH5hguk64hXfJmJJpLGgi8TUy7780w0u2VXK325qWxJtw1fP6HhOYcdjTWeoYLWQDDkTytQ119y/UMseg==}
engines: {node: '>=14.14.0'}
hasBin: true
dependencies:
braces: 3.0.2
chokidar: 3.5.3
fast-glob: 3.2.11
jsonc-parser: 3.0.0
proper-lockfile: 4.1.2
dev: true