feat(editor): report uncaught errors to Better Stack
The editor reported nothing when a session died. Evidence lived only in-tab —
an 800-line React array behind a "Show console" button — so diagnosis meant
asking a user to paste a screenshot.
Better Stack's Error Tracking ingests the Sentry wire protocol, so this runs
the stock @sentry/browser against a Better Stack DSN. Sentry.init installs its
own window error/unhandledrejection handlers, so uncaught main-thread errors
and the wasm traps that escape emscripten's DOM event handlers are captured
with no instrumentation at the throw sites. Not their JS tag: it has no
beforeSend or fingerprint hooks, its runtime spawns workers from cross-origin
CDN hosts (this page is COEP: require-corp), and it ships session replay on by
default — which on a CAD canvas records customers' board geometry.
@sentry/browser is imported in exactly one file so the vendor stays swappable,
mirroring how lib/analytics.ts isolates Plausible.
Also replaces the terminal-signature regex with a shared, unit-tested predicate
(wasm/terminal-error.ts) used by BOTH the fatal overlay and the reporter, so
they cannot disagree. The regex was a type check written as a string match and
had three live holes: `RuntimeError` was listed but never appears IN
`.message`; Chrome's bare "unreachable" and "null function" matched nothing
(the v0.1.20 prod log is exactly those); and narrowing "table index is out of
bounds" to `\bindex out of bounds` for Firefox in 197f317 silently stopped
matching Chrome's spelling. Checking the TYPE — every trap in this family is a
WebAssembly.RuntimeError — covers all engines and ends the spelling chase; the
message patterns remain as a fallback for paths that lose the Error object,
such as a worker ErrorEvent crossing the realm boundary with error: null.
197f317's pthread-worker tap, promote() and Firefox findings are kept as-is.
Notes:
- Off unless VITE_ERRORS_DSN is set AND VITE_ALLOW_USER_OVERRIDE !== "1" (dev
servers and every Playwright harness set the latter, and production builds
never do), so a production DSN in a local .env still cannot report. With no
DSN the whole SDK is const-folded out: 1,193,080 vs 1,282,463 bytes of JS.
- browserApiErrors integration removed. It wraps setTimeout/rAF/addEventListener
in try/catch, which is exactly how KiCad-on-Emscripten drives its main loop.
- Console breadcrumbs off (collab/debug.ts's clog fires per Yjs update and would
evict the ring before any crash); dom/fetch/navigation breadcrumbs kept.
- beforeSend redacts token/apiKey/Bearer — collab/provider.ts puts the collab
token in the y-partyserver URL, so a connection-failure string carries a live
credential — and guards the cascade: one wedge produced 8 errors in prod, and
after the first terminal event the rest are dropped into cascade_count.
Verified end to end against the real EU host from a cross-origin-isolated page:
POST /api/<id>/envelope/ -> 200, and 4 terminal throws produce 1 event
(control: 1 throw, same count).
Privacy policy 9, cookie policy 6 and the licenses page are updated: Better
Stack is disclosed as an EU processor, and the licenses page now describes the
browser app's own JS dependencies, which it never did.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
20e5eb941c
commit
1b08a5eb06
20 changed files with 535 additions and 18 deletions
5
.github/workflows/deploy-demo.yml
vendored
5
.github/workflows/deploy-demo.yml
vendored
|
|
@ -37,6 +37,10 @@ env:
|
|||
# `wrangler pages deploy` a PREVIEW deploy and demo.pcbjam.com won't update.
|
||||
# Direct-Upload projects default to "production".
|
||||
PAGES_PROD_BRANCH: production
|
||||
# Better Stack error-tracking DSN. Unset ⇒ this build reports nothing.
|
||||
# Keep in sync with release.yml — the demo is built from BOTH workflows, and
|
||||
# setting it in only one silently ships a demo with no error reporting.
|
||||
ERRORS_DSN: ${{ secrets.ERRORS_DSN }}
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
# The publish scripts shell wrangler; no repo dep — fetch it on demand.
|
||||
|
|
@ -100,6 +104,7 @@ jobs:
|
|||
--cdn "$CDN" --lib-tag "$LIB_TAG"
|
||||
${MODELS_TAG:+--models-tag "$MODELS_TAG"}
|
||||
--plausible "https://plausible.io/js/pa-KjNS9YmidydULZTstsjRg.js"
|
||||
${ERRORS_DSN:+--errors-dsn "$ERRORS_DSN" --errors-env demo}
|
||||
|
||||
# 4) Ensure the Pages project exists (first deploy creates it; no-op after).
|
||||
# Its production branch must equal PAGES_PROD_BRANCH or deploys land as
|
||||
|
|
|
|||
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
|
|
@ -48,6 +48,12 @@ env:
|
|||
# Mgmt app origin: non-editor routes on the editor host redirect here
|
||||
# (standalone-hardening 0006). The demo build never sets this.
|
||||
EDITOR_APP_BASE: https://app.pcbjam.com
|
||||
# Better Stack error-tracking DSN (Sentry wire format). Unset ⇒ builds report
|
||||
# nothing, so this is safe to leave empty. Held as a secret rather than a
|
||||
# literal: this repo is public, and although the token becomes visible in the
|
||||
# shipped bundle anyway, keeping it out of git makes it rotatable without a
|
||||
# commit. Keep in sync with deploy-demo.yml.
|
||||
ERRORS_DSN: ${{ secrets.ERRORS_DSN }}
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
WRANGLER_CMD: npx --yes wrangler@4
|
||||
|
|
@ -136,6 +142,7 @@ jobs:
|
|||
--cdn "$CDN" --lib-tag "$LIB_TAG"
|
||||
${MODELS_TAG:+--models-tag "$MODELS_TAG"}
|
||||
--plausible "https://plausible.io/js/pa-KjNS9YmidydULZTstsjRg.js"
|
||||
${ERRORS_DSN:+--errors-dsn "$ERRORS_DSN" --errors-env demo}
|
||||
|
||||
- name: Ensure Pages project exists
|
||||
run: >
|
||||
|
|
@ -183,6 +190,7 @@ jobs:
|
|||
node scripts/deploy/build-editor.mjs --tag "$RELEASE_TAG"
|
||||
--cdn "$CDN" --api-base "$EDITOR_API_BASE" --app-base "$EDITOR_APP_BASE"
|
||||
--plausible "https://plausible.io/js/pa-KjNS9YmidydULZTstsjRg.js"
|
||||
${ERRORS_DSN:+--errors-dsn "$ERRORS_DSN" --errors-env production}
|
||||
${MODELS_TAG:+--models-tag "$MODELS_TAG"}
|
||||
|
||||
- name: Ensure Pages project exists
|
||||
|
|
|
|||
Loading…
Reference in a new issue