fix(ui): surface real error instead of generic toast + catch async errors
The global Vue errorHandler swallowed every crash into "Something went wrong. Please refresh the page." — which hides exactly what we need to diagnose the companion-app (Android WebView) post-login crash. Now: - the toast shows the real (truncated) error message; - a 25-entry ring buffer is kept on window.__archyErrors for retrieval where there's no console (companion WebView via chrome://inspect, or a debug view); - window 'error' and 'unhandledrejection' listeners catch async/non-Vue errors that Vue's errorHandler misses (e.g. a JS API absent in an older WebView). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f92e442bfc
commit
b3633ec525
@ -37,10 +37,35 @@ app.use(i18n)
|
||||
// templates instead of hard-coding a `v` prefix.
|
||||
app.config.globalProperties.$ver = displayVersion
|
||||
|
||||
app.config.errorHandler = (err, _instance, info) => {
|
||||
console.error('[Vue Error]', err, info)
|
||||
const { error } = useToast()
|
||||
error('Something went wrong. Please refresh the page.')
|
||||
// Keep a small ring buffer of the most recent errors on `window.__archyErrors`
|
||||
// so a crash that only reproduces inside a specific runtime (e.g. the Android
|
||||
// companion WebView, where there's no easy console) can be retrieved after the
|
||||
// fact — read it from chrome://inspect, or we can surface it in a debug view.
|
||||
interface ArchyErrorEntry { when: string; source: string; message: string; info?: string; stack?: string }
|
||||
const errorLog: ArchyErrorEntry[] = []
|
||||
;(window as unknown as { __archyErrors?: ArchyErrorEntry[] }).__archyErrors = errorLog
|
||||
|
||||
function recordError(source: string, err: unknown, info?: string) {
|
||||
const e = err as { message?: string; stack?: string } | undefined
|
||||
const message = (e?.message ?? String(err)) || 'unknown error'
|
||||
const entry: ArchyErrorEntry = { when: new Date().toISOString(), source, message, info, stack: e?.stack }
|
||||
errorLog.push(entry)
|
||||
if (errorLog.length > 25) errorLog.shift()
|
||||
console.error(`[${source}]`, err, info ?? '')
|
||||
// Surface the real message (truncated) instead of a generic toast — this is a
|
||||
// test/bug-bash build, and "Something went wrong" hides exactly what we need.
|
||||
const short = message.length > 140 ? `${message.slice(0, 140)}…` : message
|
||||
try {
|
||||
useToast().error(`Something went wrong: ${short}`)
|
||||
} catch { /* toast itself failed — the console + ring buffer still have it */ }
|
||||
}
|
||||
|
||||
app.config.errorHandler = (err, _instance, info) => recordError('Vue Error', err, info)
|
||||
|
||||
// Vue's errorHandler only catches errors raised synchronously inside Vue's
|
||||
// lifecycle/reactivity. Async rejections and plain runtime errors (e.g. a JS
|
||||
// API missing in an older WebView) slip past it, so catch those too.
|
||||
window.addEventListener('error', (ev) => recordError('window.error', ev.error ?? ev.message))
|
||||
window.addEventListener('unhandledrejection', (ev) => recordError('unhandledrejection', ev.reason))
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user