diff --git a/.eslintrc.json b/.eslintrc.json index f6e2bc341..f86ea69c2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,24 +1,21 @@ { - "extends": ["eslint:recommended", "plugin:n/recommended", "plugin:prettier/recommended", "plugin:yml/recommended"], - "plugins": ["prettier", "@stylistic/js"], + "extends": ["eslint:recommended", "plugin:n/recommended", "plugin:unicorn/recommended", "plugin:prettier/recommended", "plugin:yml/recommended"], + "plugins": ["prettier", "@stylistic/js", "unicorn"], "parserOptions": { "ecmaVersion": "latest", "sourceType": "module" }, "env": { "node": true, - "es6": true, + "es2024": true, "browser": true }, "rules": { // possible problems - "array-callback-return": 2, + "array-callback-return": ["error", { "allowImplicit": true }], "no-await-in-loop": 2, "no-control-regex": 0, "no-duplicate-imports": 2, - "no-prototype-builtins": 0, - "no-unsafe-negation": 2, - "require-atomic-updates": 0, // suggestions "arrow-body-style": 2, "block-scoped-var": 2, @@ -29,16 +26,7 @@ "no-eval": 2, "no-extend-native": 2, "no-extra-label": 2, - "no-global-assign": 2, - "no-implicit-coercion": [ - "error", - { - "boolean": false, - "number": false, - "string": false, - "disallowTemplateShorthand": true - } - ], + "no-implicit-coercion": ["error", { "boolean": false, "number": false, "string": false, "disallowTemplateShorthand": true }], "no-implicit-globals": 2, "no-labels": 2, "no-multi-str": 2, @@ -52,9 +40,49 @@ "object-shorthand": 2, "prefer-arrow-callback": 2, "prefer-const": 2, - "prefer-regex-literals": 1, + "prefer-object-has-own": 2, + "prefer-regex-literals": ["error", { "disallowRedundantWrapping": true }], "require-await": 2, // plugin specific + "unicorn/consistent-destructuring": 1, + "unicorn/consistent-function-scoping": 1, + "unicorn/explicit-length-check": 0, + "unicorn/filename-case": ["error", { "case": "kebabCase", "ignore": [".*\\.(yaml|yml)$", "RequestInProgress\\.js$"] }], + "unicorn/new-for-builtins": 0, + "unicorn/no-array-callback-reference": 0, + "unicorn/no-array-reduce": 1, + "unicorn/no-await-expression-member": 1, + "unicorn/no-empty-file": 1, + "unicorn/no-hex-escape": 1, + "unicorn/no-null": 0, + "unicorn/no-object-as-default-parameter": 1, + "unicorn/no-process-exit": 0, + "unicorn/no-useless-switch-case": 0, + "unicorn/no-useless-undefined": ["error", { "checkArguments": false }], + "unicorn/numeric-separators-style": [ + "warn", + { + "onlyIfContainsSeparator": false, + "number": { "minimumDigits": 7, "groupLength": 3 }, + "binary": { "minimumDigits": 9, "groupLength": 4 }, + "octal": { "minimumDigits": 9, "groupLength": 4 }, + "hexadecimal": { "minimumDigits": 5, "groupLength": 2 } + } + ], + "unicorn/prefer-code-point": 1, + "unicorn/prefer-logical-operator-over-ternary": 1, + "unicorn/prefer-module": 0, + "unicorn/prefer-node-protocol": 0, + "unicorn/prefer-number-properties": ["warn", { "checkInfinity": false }], + "unicorn/prefer-object-from-entries": 1, + "unicorn/prefer-regexp-test": 1, + "unicorn/prefer-string-replace-all": 1, + "unicorn/prefer-string-slice": 0, + "unicorn/prefer-switch": ["error", { "emptyDefaultCase": "do-nothing-comment" }], + "unicorn/prefer-top-level-await": 0, + "unicorn/prevent-abbreviations": 0, + "unicorn/switch-case-braces": ["error", "avoid"], + "unicorn/text-encoding-identifier-case": 0, // previous eslint formatting rules "@stylistic/js/arrow-parens": 2, "@stylistic/js/arrow-spacing": 2, @@ -74,40 +102,20 @@ "@stylistic/js/space-unary-ops": 2, "@stylistic/js/spaced-comment": 2, // https://github.com/eslint-community/eslint-plugin-n - "n/no-extraneous-require": [ - "error", - { - "allowModules": ["puppeteer-extra-plugin-user-preferences", "puppeteer-extra-plugin-user-data-dir"] - } - ], + "n/no-extraneous-require": ["error", { "allowModules": ["puppeteer-extra-plugin-user-preferences", "puppeteer-extra-plugin-user-data-dir"] }], "n/no-deprecated-api": 1, "n/no-missing-require": 0, "n/no-process-exit": 0, - "n/no-unpublished-require": [ - "error", - { - "allowModules": ["tosource"] - } - ], + "n/no-unpublished-require": ["error", { "allowModules": ["tosource"] }], "prettier/prettier": 0, - "yml/quotes": [ - "error", - { - "prefer": "single" - } - ] + "yml/quotes": ["error", { "prefer": "single" }] }, "overrides": [ { "files": ["*.yaml", "*.yml"], "parser": "yaml-eslint-parser", "rules": { - "lines-around-comment": [ - "error", - { - "beforeBlockComment": false - } - ] + "lines-around-comment": ["error", { "beforeBlockComment": false }] } } ] diff --git a/assets/radar-rules.js b/assets/radar-rules.js index 43bcbba21..1b1724529 100644 --- a/assets/radar-rules.js +++ b/assets/radar-rules.js @@ -167,7 +167,7 @@ docs: 'https://docs.rsshub.app/routes/multimedia#onejav', source: '/', target: (params, url, document) => { - const today = document.querySelector('div.card.mb-1.card-overview').getAttribute('data-date').replace(/-/g, ''); + const today = document.querySelector('div.card.mb-1.card-overview').dataset.date.replaceAll('-', ''); return `/onejav/day/${today}`; }, }, @@ -215,7 +215,7 @@ } else { return false; } - return `/sexinsex/${pid}/${typeid ? typeid : ''}`; + return `/sexinsex/${pid}/${typeid ?? ''}`; }, }, ], @@ -230,7 +230,7 @@ target: (params, url) => { const id = new URL(url).searchParams.get('fid'); const type = new URL(url).searchParams.get('type'); - return `/t66y/${id}/${type ? type : ''}`; + return `/t66y/${id}/${type ?? ''}`; }, }, ], diff --git a/lib/api_router.js b/lib/api-router.js similarity index 88% rename from lib/api_router.js rename to lib/api-router.js index b452d6066..bed73e393 100644 --- a/lib/api_router.js +++ b/lib/api-router.js @@ -6,8 +6,7 @@ router.get('/routes/:name?', (ctx) => { let counter = 0; const maintainer = require('./maintainer'); - Object.keys(maintainer).forEach((i) => { - const path = i; + for (const path of Object.keys(maintainer)) { const top = path.split('/')[1]; if (!ctx.params.name || top === ctx.params.name) { @@ -18,7 +17,7 @@ router.get('/routes/:name?', (ctx) => { } counter++; } - }); + } ctx.body = { counter, result }; }); diff --git a/lib/app.js b/lib/app.js index 39b91f574..720da7f71 100644 --- a/lib/app.js +++ b/lib/app.js @@ -20,13 +20,13 @@ const antiHotlink = require('./middleware/anti-hotlink'); const loadOnDemand = require('./middleware/load-on-demand'); const router = require('./router'); -const core_router = require('./core_router'); -const protected_router = require('./protected_router'); +const core_router = require('./core-router'); +const protected_router = require('./protected-router'); const mount = require('koa-mount'); // API related const apiTemplate = require('./middleware/api-template'); -const api_router = require('./api_router'); +const api_router = require('./api-router'); const apiResponseHandler = require('./middleware/api-response-handler'); process.on('uncaughtException', (e) => { @@ -37,8 +37,8 @@ const app = new Koa(); app.proxy = true; // favicon -app.use(favicon(__dirname + '/favicon.png', { maxAge: 31536000000 })); -app.use(serve(__dirname + '/static', { maxage: 31536000000 })); +app.use(favicon(__dirname + '/favicon.png', { maxAge: 31_536_000_000 })); +app.use(serve(__dirname + '/static', { maxage: 31_536_000_000 })); // global error handing app.use(onerror); diff --git a/lib/config.js b/lib/config.js index 81f9b2c6c..13f781236 100644 --- a/lib/config.js +++ b/lib/config.js @@ -45,21 +45,21 @@ const calculateValue = () => { socket: envs.SOCKET || null, // 监听 Unix Socket, null 为禁用 }, listenInaddrAny: envs.LISTEN_INADDR_ANY || 1, // 是否允许公网连接,取值 0 1 - requestRetry: parseInt(envs.REQUEST_RETRY) || 2, // 请求失败重试次数 - requestTimeout: parseInt(envs.REQUEST_TIMEOUT) || 30000, // Milliseconds to wait for the server to end the response before aborting the request - ua: envs.UA ? envs.UA : envs.NO_RANDOM_UA === 'true' || envs.NO_RANDOM_UA === '1' ? TRUE_UA : randUserAgent({ browser: 'chrome', os: 'mac os', device: 'desktop' }), + requestRetry: Number.parseInt(envs.REQUEST_RETRY) || 2, // 请求失败重试次数 + requestTimeout: Number.parseInt(envs.REQUEST_TIMEOUT) || 30000, // Milliseconds to wait for the server to end the response before aborting the request + ua: envs.UA ?? (envs.NO_RANDOM_UA === 'true' || envs.NO_RANDOM_UA === '1' ? TRUE_UA : randUserAgent({ browser: 'chrome', os: 'mac os', device: 'desktop' })), trueUA: TRUE_UA, // cors request allowOrigin: envs.ALLOW_ORIGIN, // cache cache: { - type: typeof envs.CACHE_TYPE === 'undefined' ? 'memory' : envs.CACHE_TYPE, // 缓存类型,支持 'memory' 和 'redis',设为空可以禁止缓存 - requestTimeout: parseInt(envs.CACHE_REQUEST_TIMEOUT) || 60, - routeExpire: parseInt(envs.CACHE_EXPIRE) || 5 * 60, // 路由缓存时间,单位为秒 - contentExpire: parseInt(envs.CACHE_CONTENT_EXPIRE) || 1 * 60 * 60, // 不变内容缓存时间,单位为秒 + type: envs.CACHE_TYPE === undefined ? 'memory' : envs.CACHE_TYPE, // 缓存类型,支持 'memory' 和 'redis',设为空可以禁止缓存 + requestTimeout: Number.parseInt(envs.CACHE_REQUEST_TIMEOUT) || 60, + routeExpire: Number.parseInt(envs.CACHE_EXPIRE) || 5 * 60, // 路由缓存时间,单位为秒 + contentExpire: Number.parseInt(envs.CACHE_CONTENT_EXPIRE) || 1 * 60 * 60, // 不变内容缓存时间,单位为秒 }, memory: { - max: parseInt(envs.MEMORY_MAX) || Math.pow(2, 8), // The maximum number of items that remain in the cache. This must be a positive finite intger. + max: Number.parseInt(envs.MEMORY_MAX) || Math.pow(2, 8), // The maximum number of items that remain in the cache. This must be a positive finite intger. // https://github.com/isaacs/node-lru-cache#options }, redis: { @@ -96,7 +96,7 @@ const calculateValue = () => { showLoggerTimestamp: envs.SHOW_LOGGER_TIMESTAMP, sentry: { dsn: envs.SENTRY, - routeTimeout: parseInt(envs.SENTRY_ROUTE_TIMEOUT) || 30000, + routeTimeout: Number.parseInt(envs.SENTRY_ROUTE_TIMEOUT) || 30000, }, // feed config hotlink: { @@ -110,7 +110,7 @@ const calculateValue = () => { allow_user_supply_unsafe_domain: envs.ALLOW_USER_SUPPLY_UNSAFE_DOMAIN === 'true', }, suffix: envs.SUFFIX, - titleLengthLimit: parseInt(envs.TITLE_LENGTH_LIMIT) || 150, + titleLengthLimit: Number.parseInt(envs.TITLE_LENGTH_LIMIT) || 150, openai: { apiKey: envs.OPENAI_API_KEY, model: envs.OPENAI_MODEL || 'gpt-3.5-turbo-16k', diff --git a/lib/core_router.js b/lib/core-router.js similarity index 100% rename from lib/core_router.js rename to lib/core-router.js diff --git a/lib/index.js b/lib/index.js index cf7e0f63f..730a73c09 100644 --- a/lib/index.js +++ b/lib/index.js @@ -16,7 +16,7 @@ if (config.enableCluster && cluster.isMaster && process.env.NODE_ENV !== 'test' if (fs.existsSync(config.connect.socket)) { fs.unlinkSync(config.connect.socket); } - server = app.listen(config.connect.socket, parseInt(config.listenInaddrAny) ? null : '127.0.0.1'); + server = app.listen(config.connect.socket, Number.parseInt(config.listenInaddrAny) ? null : '127.0.0.1'); logger.info('Listening Unix Socket ' + config.connect.socket); process.on('SIGINT', () => { fs.unlinkSync(config.connect.socket); @@ -24,7 +24,7 @@ if (config.enableCluster && cluster.isMaster && process.env.NODE_ENV !== 'test' }); } if (config.connect.port) { - server = app.listen(config.connect.port, parseInt(config.listenInaddrAny) ? null : '127.0.0.1'); + server = app.listen(config.connect.port, Number.parseInt(config.listenInaddrAny) ? null : '127.0.0.1'); logger.info('Listening Port ' + config.connect.port); } diff --git a/lib/maintainer.js b/lib/maintainer.js index 41592e812..5417992ef 100644 --- a/lib/maintainer.js +++ b/lib/maintainer.js @@ -1,12 +1,12 @@ const dirname = __dirname + '/v2'; const fs = require('fs'); -const { join } = require('path'); +const path = require('path'); // Presence Check for (const dir of fs.readdirSync(dirname)) { - const dirPath = join(dirname, dir); - if (fs.existsSync(join(dirPath, 'router.js')) && !fs.existsSync(join(dirPath, 'maintainer.js'))) { - throw Error(`No maintainer.js in "${dirPath}".`); + const dirPath = path.join(dirname, dir); + if (fs.existsSync(path.join(dirPath, 'router.js')) && !fs.existsSync(path.join(dirPath, 'maintainer.js'))) { + throw new Error(`No maintainer.js in "${dirPath}".`); } } @@ -24,15 +24,15 @@ for (const dir in maintainerPath) { // typo check e.g., ✘ module.export, ✔ module.exports if (!Object.keys(routes).length) { - throw Error(`No maintainer in "${dir}".`); + throw new Error(`No maintainer in "${dir}".`); } for (const author of Object.values(routes)) { if (!Array.isArray(author)) { - throw Error(`Maintainers' name should be an array in "${dir}".`); + throw new TypeError(`Maintainers' name should be an array in "${dir}".`); } // check for [], [''] or ['Someone', ''] if (author.length < 1 || author.includes('')) { - throw Error(`Empty maintainer in "${dir}".`); + throw new Error(`Empty maintainer in "${dir}".`); } } @@ -43,11 +43,11 @@ for (const dir in maintainerPath) { // 兼容旧版路由 const router = require('./router'); -router.stack.forEach((e) => { +for (const e of router.stack) { if (!maintainers[e.path]) { maintainers[e.path] = []; } -}); +} module.exports = Object.keys(maintainers) .sort() diff --git a/lib/middleware/access-control.js b/lib/middleware/access-control.js index 277362689..a7b4ab2ba 100644 --- a/lib/middleware/access-control.js +++ b/lib/middleware/access-control.js @@ -5,11 +5,11 @@ const isLocalhost = require('is-localhost-ip'); const reject = (ctx) => { ctx.response.status = 403; - throw Error('Authentication failed. Access denied.'); + throw new Error('Authentication failed. Access denied.'); }; const ipv4Pattern = /^(\d{1,3}\.){3}\d{1,3}$/; -const cidrPattern = /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/(\d{1,2})/; +const cidrPattern = /((?:\d{1,3}\.){3}\d{1,3})\/(\d{1,2})/; const ipInCidr = (cidr, ip) => { const cidrMatch = cidr.match(cidrPattern); @@ -17,7 +17,7 @@ const ipInCidr = (cidr, ip) => { if (!cidrMatch || !ipMatch) { return false; } - const subnetMask = parseInt(cidrMatch[2]); + const subnetMask = Number.parseInt(cidrMatch[2]); const cidrIpBits = ipv4ToBitsring(cidrMatch[1]).substring(0, subnetMask); const ipBits = ipv4ToBitsring(ip).substring(0, subnetMask); return cidrIpBits === ipBits; @@ -26,7 +26,7 @@ const ipInCidr = (cidr, ip) => { const ipv4ToBitsring = (ip) => ip .split('.') - .map((part) => ('00000000' + parseInt(part).toString(2)).slice(-8)) + .map((part) => ('00000000' + Number.parseInt(part).toString(2)).slice(-8)) .join(''); module.exports = async (ctx, next) => { @@ -53,22 +53,16 @@ module.exports = async (ctx, next) => { return grant(); } - if (config.accessKey) { - if (config.accessKey === accessKey || accessCode === md5(requestPath + config.accessKey)) { - return grant(); - } + if (config.accessKey && (config.accessKey === accessKey || accessCode === md5(requestPath + config.accessKey))) { + return grant(); } - if (config.allowlist) { - if (config.allowlist.find((item) => ip.includes(item) || ipInCidr(item, ip) || requestPath.includes(item) || requestUA.includes(item))) { - return grant(); - } + if (config.allowlist && config.allowlist.some((item) => ip.includes(item) || ipInCidr(item, ip) || requestPath.includes(item) || requestUA.includes(item))) { + return grant(); } - if (config.denylist) { - if (!config.denylist.find((item) => ip.includes(item) || ipInCidr(item, ip) || requestPath.includes(item) || requestUA.includes(item))) { - return grant(); - } + if (config.denylist && !config.denylist.some((item) => ip.includes(item) || ipInCidr(item, ip) || requestPath.includes(item) || requestUA.includes(item))) { + return grant(); } reject(ctx); diff --git a/lib/middleware/anti-hotlink.js b/lib/middleware/anti-hotlink.js index 049487010..9a216126a 100644 --- a/lib/middleware/anti-hotlink.js +++ b/lib/middleware/anti-hotlink.js @@ -4,8 +4,8 @@ const logger = require('@/utils/logger'); const path = require('path'); const { art } = require('@/utils/render'); -const templateRegex = /\$\{([^{}]+)}/g; -const allowedUrlProperties = ['hash', 'host', 'hostname', 'href', 'origin', 'password', 'pathname', 'port', 'protocol', 'search', 'searchParams', 'username']; +const templateRegex = /\${([^{}]+)}/g; +const allowedUrlProperties = new Set(['hash', 'host', 'hostname', 'href', 'origin', 'password', 'pathname', 'port', 'protocol', 'search', 'searchParams', 'username']); const IframeWrapperTemplate = path.join(__dirname, 'templates/iframe.art'); // match path or sub-path @@ -26,7 +26,7 @@ const filterPath = (path) => { }; const interpolate = (str, obj) => - str.replace(templateRegex, (_, prop) => { + str.replaceAll(templateRegex, (_, prop) => { let needEncode = false; if (prop.endsWith('_ue')) { // url encode @@ -39,7 +39,7 @@ const parseUrl = (str) => { let url; try { url = new URL(str); - } catch (e) { + } catch { logger.error(`Failed to parse ${str}`); } @@ -87,12 +87,12 @@ const validateTemplate = (template) => { if (!template) { return; } - [...template.matchAll(templateRegex)].forEach((match) => { + for (const match of template.matchAll(templateRegex)) { const prop = match[1].endsWith('_ue') ? match[1].slice(0, -3) : match[1]; - if (!allowedUrlProperties.includes(prop)) { + if (!allowedUrlProperties.has(prop)) { throw new Error(`Invalid URL property: ${prop}`); } - }); + } }; module.exports = async (ctx, next) => { @@ -115,11 +115,7 @@ module.exports = async (ctx, next) => { // Force config hotlink template on conflict if (config.hotlink.template) { - if (!filterPath(ctx.request.path)) { - image_hotlink_template = undefined; - } else { - image_hotlink_template = config.hotlink.template; - } + image_hotlink_template = filterPath(ctx.request.path) ? config.hotlink.template : undefined; } if (!image_hotlink_template && !multimedia_hotlink_template && !shouldWrapInIframe) { @@ -138,11 +134,12 @@ module.exports = async (ctx, next) => { ctx.state.data.description = process(ctx.state.data.description, image_hotlink_template, multimedia_hotlink_template, shouldWrapInIframe); } - ctx.state.data.item && - ctx.state.data.item.forEach((item) => { + if (ctx.state.data.item) { + for (const item of ctx.state.data.item) { if (item.description) { item.description = process(item.description, image_hotlink_template, multimedia_hotlink_template, shouldWrapInIframe); } - }); + } + } } }; diff --git a/lib/middleware/cache/index.js b/lib/middleware/cache/index.js index 4c715b85a..bde7cdc0a 100644 --- a/lib/middleware/cache/index.js +++ b/lib/middleware/cache/index.js @@ -57,22 +57,22 @@ module.exports = function (app) { ...cacheModule, tryGet: async (key, getValueFunc, maxAge = config.cache.contentExpire, refresh = true) => { if (typeof key !== 'string') { - throw Error('Cache key must be a string'); + throw new TypeError('Cache key must be a string'); } let v = await get(key, refresh); - if (!v) { - v = await getValueFunc(); - set(key, v, maxAge); - } else { + if (v) { let parsed; try { parsed = JSON.parse(v); - } catch (e) { + } catch { parsed = null; } if (parsed) { v = parsed; } + } else { + v = await getValueFunc(); + set(key, v, maxAge); } return v; @@ -112,7 +112,7 @@ module.exports = function (app) { ctx.state.data = JSON.parse(value); return; } - } catch (e) { + } catch { // } @@ -121,9 +121,9 @@ module.exports = function (app) { try { await next(); - } catch (e) { + } catch (error) { await globalCache.set(controlKey, '0', config.cache.requestTimeout); - throw e; + throw error; } if (ctx.response.get('Cache-Control') !== 'no-cache' && ctx.state && ctx.state.data) { diff --git a/lib/middleware/cache/redis.js b/lib/middleware/cache/redis.js index 2234dd866..b7d57b974 100644 --- a/lib/middleware/cache/redis.js +++ b/lib/middleware/cache/redis.js @@ -20,7 +20,7 @@ redisClient.on('connect', () => { const getCacheTtlKey = (key) => { if (key.startsWith('rsshub:cacheTtl:')) { - throw Error('"rsshub:cacheTtl:" prefix is reserved for the internal usage, please change your cache key'); // blocking any attempt to get/set the cacheTtl + throw new Error('"rsshub:cacheTtl:" prefix is reserved for the internal usage, please change your cache key'); // blocking any attempt to get/set the cacheTtl } return `rsshub:cacheTtl:${key}`; }; @@ -31,13 +31,13 @@ module.exports = { const cacheTtlKey = getCacheTtlKey(key); let [value, cacheTtl] = await redisClient.mget(key, cacheTtlKey); if (value && refresh) { - if (!cacheTtl) { + if (cacheTtl) { + redisClient.expire(cacheTtlKey, cacheTtl); + } else { // if cacheTtl is not set, that means the cache expire time is contentExpire cacheTtl = config.cache.contentExpire; // dont save cacheTtl to Redis, as it is the default value // redisClient.set(cacheTtlKey, cacheTtl, 'EX', cacheTtl); - } else { - redisClient.expire(cacheTtlKey, cacheTtl); } redisClient.expire(key, cacheTtl); value = value + ''; diff --git a/lib/middleware/header.js b/lib/middleware/header.js index 2292ddbed..762363f9d 100644 --- a/lib/middleware/header.js +++ b/lib/middleware/header.js @@ -24,7 +24,7 @@ module.exports = async (ctx, next) => { return; } - const status = (ctx.status / 100) | 0; + const status = Math.trunc(ctx.status / 100); if (2 !== status) { return; } diff --git a/lib/middleware/load-on-demand.js b/lib/middleware/load-on-demand.js index 0c15bb423..837a17cc7 100644 --- a/lib/middleware/load-on-demand.js +++ b/lib/middleware/load-on-demand.js @@ -11,7 +11,9 @@ module.exports = function (app) { if (p.length > 0) { modName = p[0]; - if (!loadedRoutes.has(modName)) { + if (loadedRoutes.has(modName)) { + mounted = true; + } else { const mod = routes[modName]; // Mount module if (mod) { @@ -21,8 +23,6 @@ module.exports = function (app) { mod(router); app.use(mount(`/${modName}`, router.routes())).use(router.allowedMethods()); } - } else { - mounted = true; } } diff --git a/lib/middleware/onerror.js b/lib/middleware/onerror.js index 3f2c3a04b..a4272b0aa 100644 --- a/lib/middleware/onerror.js +++ b/lib/middleware/onerror.js @@ -20,15 +20,15 @@ if (config.sentry.dsn) { try { gitHash = require('git-rev-sync').short(); -} catch (e) { +} catch { gitHash = (process.env.HEROKU_SLUG_COMMIT && process.env.HEROKU_SLUG_COMMIT.slice(0, 7)) || (process.env.VERCEL_GIT_COMMIT_SHA && process.env.VERCEL_GIT_COMMIT_SHA.slice(0, 7)) || 'unknown'; } module.exports = async (ctx, next) => { try { - const time = +new Date(); + const time = Date.now(); await next(); - if (config.sentry.dsn && +new Date() - time >= config.sentry.routeTimeout) { + if (config.sentry.dsn && Date.now() - time >= config.sentry.routeTimeout) { Sentry.withScope((scope) => { scope.setTag('route', ctx._matchedRoute); scope.setTag('name', ctx.request.path.split('/')[1]); @@ -36,8 +36,8 @@ module.exports = async (ctx, next) => { Sentry.captureException(new Error('Route Timeout')); }); } - } catch (err) { - if (err instanceof Error && !err.stack.split('\n')[1].includes('lib/middleware/parameter.js')) { + } catch (error) { + if (error instanceof Error && !error.stack.split('\n')[1].includes('lib/middleware/parameter.js')) { // Append v2 route path if a route throws an error // since koa-mount will remove the mount path from ctx.request.path // https://github.com/koajs/mount/issues/62 @@ -45,11 +45,11 @@ module.exports = async (ctx, next) => { ctx._matchedRoute = ctx._matchedRoute ? (ctx.mountPath ?? '') + ctx._matchedRoute : ctx._matchedRoute; } - let message = err; - if (err.name && (err.name === 'HTTPError' || err.name === 'RequestError')) { - message = `${err.message}: target website might be blocking our access, you can host your own RSSHub instance for a better usability.`; - } else if (err instanceof Error) { - message = process.env.NODE_ENV === 'production' ? err.message : err.stack; + let message = error; + if (error.name && (error.name === 'HTTPError' || error.name === 'RequestError')) { + message = `${error.message}: target website might be blocking our access, you can host your own RSSHub instance for a better usability.`; + } else if (error instanceof Error) { + message = process.env.NODE_ENV === 'production' ? error.message : error.stack; } logger.error(`Error in ${ctx.request.path}: ${message}`); @@ -57,7 +57,7 @@ module.exports = async (ctx, next) => { if (config.isPackage) { ctx.body = { error: { - message: err.message ? err.message : err, + message: error.message ?? error, }, }; } else { @@ -65,12 +65,12 @@ module.exports = async (ctx, next) => { 'Content-Type': 'text/html; charset=UTF-8', }); - if (err instanceof RequestInProgressError) { + if (error instanceof RequestInProgressError) { ctx.status = 503; - message = err.message; + message = error.message; ctx.set('Cache-Control', `public, max-age=${config.cache.requestTimeout}`); } else if (ctx.status === 403) { - message = err.message; + message = error.message; } else { ctx.status = 404; } @@ -112,7 +112,7 @@ module.exports = async (ctx, next) => { scope.setTag('route', ctx._matchedRoute); scope.setTag('name', ctx.request.path.split('/')[1]); scope.addEventProcessor((event) => Sentry.Handlers.parseRequest(event, ctx.request)); - Sentry.captureException(err); + Sentry.captureException(error); }); } } diff --git a/lib/middleware/parameter.js b/lib/middleware/parameter.js index bd37d3510..86f5fa85e 100644 --- a/lib/middleware/parameter.js +++ b/lib/middleware/parameter.js @@ -21,7 +21,7 @@ const resolveRelativeLink = ($, elem, attr, baseUrl) => { // e.g. should leave