fix: duck type error checking (#6924)
* fix: duck type error checking * fix: use duck-typing * simplify * fix typings * fix comments
This commit is contained in:
parent
252bf32d2f
commit
0ced5f2402
@ -79,7 +79,7 @@ describe('beforeSend', () => {
|
||||
describe('filters browser extension errors', () => {
|
||||
it('filters chrome-extension errors', () => {
|
||||
const originalException = new Error()
|
||||
originalException.stack = `
|
||||
originalException.stack = `
|
||||
TypeError: Cannot create proxy with a non-object as target or handler
|
||||
at pa(chrome-extension://kbjhmlgclljgdhmhffjofbobmficicjp/proxy-window-evm.a5430696.js:22:216604)
|
||||
at da(chrome-extension://kbjhmlgclljgdhmhffjofbobmficicjp/proxy-window-evm.a5430696.js:22:212968)
|
||||
@ -90,13 +90,25 @@ describe('beforeSend', () => {
|
||||
|
||||
it('filters moz-extension errors', () => {
|
||||
const originalException = new Error()
|
||||
originalException.stack = `
|
||||
originalException.stack = `
|
||||
Error: Permission denied to access property "apply"
|
||||
at WINDOW.onunhandledrejection(../node_modules/@sentry/src/instrument.ts:610:1)
|
||||
at y/h.onunhandledrejection(moz-extension://95cafb7b-6038-4bdd-b832-d3a58544601d/content_script/inpage_sol.js:143:16274)
|
||||
`
|
||||
expect(beforeSend(ERROR, { originalException })).toBeNull()
|
||||
})
|
||||
|
||||
it('filters non-Error objects thrown from an extension', () => {
|
||||
const originalException = {
|
||||
message: '',
|
||||
stack: `
|
||||
Error: Permission denied to access property "apply"
|
||||
at WINDOW.onunhandledrejection(../node_modules/@sentry/src/instrument.ts:610:1)
|
||||
at y/h.onunhandledrejection(moz-extension://95cafb7b-6038-4bdd-b832-d3a58544601d/content_script/inpage_sol.js:143:16274)
|
||||
`,
|
||||
}
|
||||
expect(beforeSend(ERROR, { originalException })).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('OneKey', () => {
|
||||
|
@ -23,9 +23,14 @@ export const beforeSend: Required<ClientOptions>['beforeSend'] = (event: ErrorEv
|
||||
return event
|
||||
}
|
||||
|
||||
type ErrorLike = Partial<Error> & Required<Pick<Error, 'message'>>
|
||||
function isErrorLike(error: unknown): error is ErrorLike {
|
||||
return error instanceof Object && 'message' in error && typeof (error as Partial<ErrorLike>)?.message === 'string'
|
||||
}
|
||||
|
||||
/** Identifies ethers request errors (as thrown by {@type import(@ethersproject/web).fetchJson}). */
|
||||
function isEthersRequestError(error: Error): error is Error & { requestBody: string } {
|
||||
return 'requestBody' in error && typeof (error as unknown as Record<'requestBody', unknown>).requestBody === 'string'
|
||||
function isEthersRequestErrorLike(error: ErrorLike): error is ErrorLike & { requestBody: string } {
|
||||
return 'requestBody' in error && typeof (error as Record<'requestBody', unknown>).requestBody === 'string'
|
||||
}
|
||||
|
||||
// Since the interface currently uses HashRouter, URLs will have a # before the path.
|
||||
@ -44,11 +49,12 @@ function updateRequestUrl(event: ErrorEvent) {
|
||||
|
||||
// TODO(WEB-2400): Refactor to use a config instead of returning true for each condition.
|
||||
function shouldRejectError(error: EventHint['originalException']) {
|
||||
if (error instanceof Error) {
|
||||
// ethers aggressively polls for block number, and it sometimes fails (whether spuriously or through rate-limiting).
|
||||
// If block number polling, it should not be considered an exception.
|
||||
if (isEthersRequestError(error)) {
|
||||
// Some libraries throw ErrorLike objects ({ code, message, stack }) instead of true Errors.
|
||||
if (isErrorLike(error)) {
|
||||
if (isEthersRequestErrorLike(error)) {
|
||||
const method = JSON.parse(error.requestBody).method
|
||||
// ethers aggressively polls for block number, and it sometimes fails (whether spuriously or through rate-limiting).
|
||||
// If block number polling, it should not be considered an exception.
|
||||
if (method === 'eth_blockNumber') return true
|
||||
}
|
||||
|
||||
@ -64,14 +70,6 @@ function shouldRejectError(error: EventHint['originalException']) {
|
||||
// Therefore, this can be ignored.
|
||||
if (error.message.match(/Unexpected token '<'/)) return true
|
||||
|
||||
// Errors coming from a browser extension can be ignored. These errors are usually caused by extensions injecting
|
||||
// scripts into the page, which we cannot control.
|
||||
if (error.stack?.match(/-extension:\/\//i)) return true
|
||||
|
||||
// Errors coming from OneKey (a desktop wallet) can be ignored for now.
|
||||
// These errors are either application-specific, or they will be thrown separately outside of OneKey.
|
||||
if (error.stack?.match(/OneKey/i)) return true
|
||||
|
||||
// Content security policy 'unsafe-eval' errors can be filtered out because there are expected failures.
|
||||
// For example, if a user runs an eval statement in console this error would still get thrown.
|
||||
// TODO(WEB-2348): We should extend this to filter out any type of CSP error.
|
||||
@ -92,8 +90,18 @@ function shouldRejectError(error: EventHint['originalException']) {
|
||||
return true
|
||||
}
|
||||
|
||||
if ('stack' in error && typeof error.stack === 'string') {
|
||||
// Errors coming from a browser extension can be ignored. These errors are usually caused by extensions injecting
|
||||
// scripts into the page, which we cannot control.
|
||||
if (error.stack.match(/-extension:\/\//i)) return true
|
||||
|
||||
// Errors coming from OneKey (a desktop wallet) can be ignored for now.
|
||||
// These errors are either application-specific, or they will be thrown separately outside of OneKey.
|
||||
if (error.stack.match(/OneKey/i)) return true
|
||||
}
|
||||
|
||||
// These are caused by user navigation away from the page before a request has finished.
|
||||
if (error instanceof DOMException && error.name === 'AbortError') return true
|
||||
if (error instanceof DOMException && error?.name === 'AbortError') return true
|
||||
}
|
||||
|
||||
return false
|
||||
|
Loading…
Reference in New Issue
Block a user