Skip to content

Commit a2283a0

Browse files
GiteaBotsilverwindclaude
authored
Clean up and improve non-gitea js error filter (#37148) (#37155)
Backport #37148 by @silverwind 1. Filter out errors that contain `chrome-extension://` etc protocols 2. Extract filtering into its own function and test it 3. Fix the `window.config.assetUrlPrefix` mock, guaranteed to end with `/assets` 4. Remove useless `??` and `?.` for properties that always exist --- This PR was written with the help of Claude Opus 4.6 Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
1 parent 3e6b9e5 commit a2283a0

3 files changed

Lines changed: 31 additions & 9 deletions

File tree

web_src/js/modules/errors.test.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,19 @@
1-
import {showGlobalErrorMessage} from './errors.ts';
1+
import {isGiteaError, showGlobalErrorMessage} from './errors.ts';
2+
3+
test('isGiteaError', () => {
4+
expect(isGiteaError('', '')).toBe(true);
5+
expect(isGiteaError('moz-extension://abc/content.js', '')).toBe(false);
6+
expect(isGiteaError('safari-extension://abc/content.js', '')).toBe(false);
7+
expect(isGiteaError('safari-web-extension://abc/content.js', '')).toBe(false);
8+
expect(isGiteaError('chrome-extension://abc/content.js', '')).toBe(false);
9+
expect(isGiteaError('https://other-site.com/script.js', '')).toBe(false);
10+
expect(isGiteaError('http://localhost:3000/some/page', '')).toBe(true);
11+
expect(isGiteaError('http://localhost:3000/assets/js/index.abc123.js', '')).toBe(true);
12+
expect(isGiteaError('', `Error\n at chrome-extension://abc/content.js:1:1`)).toBe(false);
13+
expect(isGiteaError('', `Error\n at https://other-site.com/script.js:1:1`)).toBe(false);
14+
expect(isGiteaError('', `Error\n at http://localhost:3000/assets/js/index.abc123.js:1:1`)).toBe(true);
15+
expect(isGiteaError('http://localhost:3000/assets/js/index.js', `Error\n at chrome-extension://abc/content.js:1:1`)).toBe(false);
16+
});
217

318
test('showGlobalErrorMessage', () => {
419
document.body.innerHTML = '<div class="page-content"></div>';

web_src/js/modules/errors.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,31 @@ export function showGlobalErrorMessage(msg: string, msgType: Intent = 'error') {
2323
msgContainer.prepend(msgDiv);
2424
}
2525

26+
// Detect whether an error originated from Gitea's own scripts, not from
27+
// browser extensions or other external scripts.
28+
const extensionRe = /(chrome|moz|safari(-web)?)-extension:\/\//;
29+
export function isGiteaError(filename: string, stack: string): boolean {
30+
if (extensionRe.test(filename) || extensionRe.test(stack)) return false;
31+
const assetBaseUrl = new URL(`${window.config.assetUrlPrefix}/`, window.location.origin).href;
32+
if (filename && !filename.startsWith(assetBaseUrl) && !filename.startsWith(window.location.origin)) return false;
33+
if (stack && !stack.includes(assetBaseUrl)) return false;
34+
return true;
35+
}
36+
2637
export function processWindowErrorEvent({error, reason, message, type, filename, lineno, colno}: ErrorEvent & PromiseRejectionEvent) {
2738
const err = error ?? reason;
28-
const assetBaseUrl = String(new URL(`${window.config?.assetUrlPrefix ?? '/assets'}/`, window.location.origin));
29-
const {runModeIsProd} = window.config ?? {};
30-
3139
// `error` and `reason` are not guaranteed to be errors. If the value is falsy, it is likely a
3240
// non-critical event from the browser. We log them but don't show them to users. Examples:
3341
// - https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors
3442
// - https://github.com/mozilla-mobile/firefox-ios/issues/10817
3543
// - https://github.com/go-gitea/gitea/issues/20240
3644
if (!err) {
3745
if (message) console.error(new Error(message));
38-
if (runModeIsProd) return;
46+
if (window.config.runModeIsProd) return;
3947
}
4048

41-
// If the error stack trace does not include the base URL of our script assets, it likely came
42-
// from a browser extension or inline script. Do not show such errors in production.
43-
if (err instanceof Error && !err.stack?.includes(assetBaseUrl) && runModeIsProd) return;
49+
// Filter out errors from browser extensions or other non-Gitea scripts.
50+
if (!isGiteaError(filename ?? '', err?.stack ?? '')) return;
4451

4552
let msg = err?.message ?? message;
4653
if (lineno) msg += ` (${filename} @ ${lineno}:${colno})`;

web_src/js/vitest.setup.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ await import('./globals.ts');
1313
window.config = {
1414
appUrl: 'http://localhost:3000/',
1515
appSubUrl: '',
16-
assetUrlPrefix: '',
16+
assetUrlPrefix: '/assets',
1717
sharedWorkerUri: '',
1818
runModeIsProd: true,
1919
customEmojis: {},

0 commit comments

Comments
 (0)