Files
RSSHub/lib/errors/index.tsx
T
dependabot[bot]andTony 873618e99d chore(deps-dev): bump eslint-plugin-unicorn from 65.0.1 to 66.0.0 (#22274)
* chore(deps-dev): bump eslint-plugin-unicorn from 65.0.1 to 66.0.0

Bumps [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) from 65.0.1 to 66.0.0.
- [Release notes](https://github.com/sindresorhus/eslint-plugin-unicorn/releases)
- [Commits](https://github.com/sindresorhus/eslint-plugin-unicorn/compare/v65.0.1...v66.0.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-unicorn
  dependency-version: 66.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* style: fix unicorn-js/prefer-url-href

* style: oxlint disable

* style: fix unicorn-js/no-useless-else

* style: no-unsafe-string-replacement

* style: fix no-duplicate-loops

* style: fix prefer-number-is-safe-integer

* style: fix prefer-single-array-predicate

* style: fix no-object-methods-with-collections

* style: fix no-useless-boolean-cast

* style: fix no-useless-template-literals

* style: fix no-negated-array-predicate

* style: fix prefer-direct-iteration

* style: fix consistent-optional-chaining

* style: fix prefer-simple-sort-comparator

* style: fix prefer-global-number-constants

* style: fix prefer-type-literal-last

* style: fix require-array-sort-compare.

* style: fix prefer-early-return

* style: fix prefer-short-arrow-method

* style: fix prefer-array-from-map

* style: fix prefer-scoped-selector

* style: fix no-global-object-property-assignment

* style: fix no-unnecessary-global-this

* style: fix no-unreadable-object-destructuring

* style: fix no-invalid-argument-count

* style: fix prefer-smaller-scope

* style: fix prefer-iterator-to-array.

* style: fix prefer-object-iterable-methods

* style: fix typo

* style: fix max-nested-calls

* style: fix no-incorrect-template-string-interpolation

* style: fix no-break-in-nested-loop

* style: fix prefer-await

* style: fix no-computed-property-existence-check

* style: fix prefer-number-coercion

* style: fix no-empty-file

* style: update eslint unicorn v66 recommended preset

* style: add unicorn/prefer-spread to oxlint-disable comments

* style: fix no-array-reduce

* style: delete github/no-then as it's covered by unicorn/prefer-await

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Tony <TonyRL@users.noreply.github.com>
2026-06-16 14:43:42 +08:00

93 lines
3.0 KiB
TypeScript

import Honeybadger from '@honeybadger-io/js';
import type { ErrorHandler, NotFoundHandler } from 'hono';
import { routePath } from 'hono/route';
import { config } from '@/config';
import { getDebugInfo, setDebugInfo } from '@/utils/debug-info';
import logger from '@/utils/logger';
import { requestMetric } from '@/utils/otel';
import Error from '@/views/error';
import NotFoundError from './types/not-found';
const Sentry = config.sentry.dsn ? await import('@sentry/node') : undefined;
export const errorHandler: ErrorHandler = (error, ctx) => {
const requestPath = ctx.req.path;
const matchedRoute = routePath(ctx);
const hasMatchedRoute = matchedRoute !== '/*';
const debug = getDebugInfo();
try {
if (ctx.res.headers.get('RSSHub-Cache-Status')) {
debug.hitCache++;
}
} catch {
// ignore
}
debug.error++;
const errorPathCount = debug.errorPaths[requestPath];
if (!errorPathCount) {
debug.errorPaths[requestPath] = 0;
}
debug.errorPaths[requestPath]++;
const errorRouteCount = debug.errorRoutes[matchedRoute];
if (!errorRouteCount && hasMatchedRoute) {
debug.errorRoutes[matchedRoute] = 0;
}
hasMatchedRoute && debug.errorRoutes[matchedRoute]++;
setDebugInfo(debug);
if (config.honeybadger.apiKey) {
Honeybadger.notify(error, {
context: { name: requestPath.split('/', 2)[1] },
});
}
if (Sentry) {
Sentry.withScope((scope) => {
scope.setTag('name', requestPath.split('/', 2)[1]);
Sentry.captureException(error);
});
}
let errorMessage = (process.env.NODE_ENV || process.env.VERCEL_ENV) === 'production' ? error.message : error.stack || error.message;
switch (error.constructor.name) {
case 'HTTPError':
case 'RequestError':
case 'FetchError':
ctx.status(503);
break;
case 'RequestInProgressError':
ctx.header('Cache-Control', `public, max-age=${config.requestTimeout / 1000}`);
ctx.status(503);
break;
case 'RejectError':
ctx.status(403);
break;
case 'NotFoundError':
ctx.status(404);
errorMessage += 'The route does not exist or has been deleted.';
break;
default:
ctx.status(503);
break;
}
const message = `${error.name}: ${errorMessage}`;
logger.error(`Error in ${requestPath}: ${message}`);
requestMetric.error({ path: matchedRoute, method: ctx.req.method, status: ctx.res.status });
return config.isPackage || ctx.req.query('format') === 'json'
? ctx.json({
error: {
message: error.message ?? error,
},
})
: ctx.html(<Error requestPath={requestPath} message={message} errorRoute={hasMatchedRoute ? matchedRoute : requestPath} nodeVersion={process.version} />);
};
export const notFoundHandler: NotFoundHandler = (ctx) => errorHandler(new NotFoundError(), ctx);