Skip to content

fix: extension sign-out on expired tokens, record modal load errors, Monaco workers - #2162

Open
paustint wants to merge 3 commits into
mainfrom
fix/web-extension-auth-and-record-modal
Open

paustint wants to merge 3 commits into
mainfrom
fix/web-extension-auth-and-record-modal

Conversation

@paustint

Copy link
Copy Markdown
Contributor

Three fixes, one commit each. Two came out of triaging the production extension's chrome://extensions errors page; the record modal one is from a user report.

1. The extension never signs out when Jetstream rejects its token

handleVerifyAuth only treated a 401 as final when the body was { data: { success: false } }, which only the verify controller produces. A token the auth middleware rejects (expired, revoked, entitlement removed) never reaches the controller: the API error handler answers { error: true, success: false, message }, so the service worker filed it as transient, kept the dead session, and retried on every check. The user never saw the sign-in screen, and record sync kept failing with 401s ([DB] Error initializing db Error: Unauthorized). Regression from 5a3c66e, shipped in 3.10.0.

Prod API logs, 10-10 → 10-17: ~1,000 "Access token is invalid for device" rejections across 30 devices, 602 /web-extension/data-sync/push 401s (470 from one device over 8 days), and 399 verify 401s against 96 200s. One device was rejected for "Browser extension is not enabled" and kept working, so this also closes an entitlement gap.

  • The verify response parser accepts both body shapes; an HTML/unparseable 401 from a proxy is still transient.
  • A 401 no longer clears a token that Chrome Sync replaced while the request was in flight, so a token rotation on another install doesn't sign every install out now that 401s are honored.
  • The spec's jsonResponse helper always wrapped bodies in data, which is why tests never caught this; new tests use the error handler's real body.

2. View/Edit Record modal: "There was a problem loading the record information"

getPicklistValuesForRecordAndRecordType rethrew any UI API failure except "not supported in UI API", which replaced the whole modal with a generic "make sure the record id is valid" error (missing records are handled separately, so that hint was misleading). It now falls back to the describe's picklist values on any failure, and the modal shows the real error message. Also applies to Create Records and the web app.

3. Monaco workers missing from the extension

Monaco 0.55+ keeps its workers in min/vs/assets/, which the extension's copy step skipped, so importScripts 404'd and every editor ran language services on the main thread ("Could not create web worker(s)"). The error tracker ignores /js/monaco/vs/, so it never surfaced. The copy now includes assets/ minus the 6.7MB TypeScript worker (no extension editor uses JS/TS); +2.6MB. Separate from #2153's Canvas CSP fix.

Testing

  • jetstream-web-extension, shared-ui-record-form, ui-core tests + typecheck pass; oxlint clean.
  • pnpm build:web-extension packages vs/assets/{editor,json,css,html}.worker-*.js matching the hashes editor.main.js references.
  • Not manually tested in a browser.

Expected after release

The ~30 devices currently stuck on a dead session will see the extension's sign-in screen once.

Not in this PR

  • The handoff's "version-safe UI API URL" fix: the web app uses the same defaultApiVersion by design (chore: read the Salesforce API version from one shared constant #2151), and the picklist fallback keeps the modal working on an older org anyway.
  • Token lifetime: login issues a 7-day token and verify only rotates it with ≤2 days left, so a user who doesn't touch the extension during days 5–7 has to sign in again. Widening TOKEN_AUTO_REFRESH_DAYS would fix that; left as a product decision.

…oken

Since 3.10.0 the service worker only treated a 401 as final when the body
was wrapped in `data`, which only the verify controller does. A token the
auth middleware rejects (expired, revoked, entitlement removed) comes back
from the error handler unwrapped, so the extension kept the dead session,
never asked the user to sign in again, and record sync failed with 401s.

A 401 no longer clears a token that Chrome Sync replaced while the request
was in flight, so a rotation on another install does not sign everyone out.
Any UI API picklist-values failure other than "not supported in UI API"
threw and replaced the whole view/edit modal with a generic "make sure the
record id is valid" error. The record form now falls back to the describe's
picklist values, and the modal shows the real error when loading fails.
Monaco 0.55+ keeps its workers in vs/assets, which the extension copy step
skipped, so every editor fell back to running language services on the main
thread. The TypeScript worker is left out because no extension editor uses
JavaScript or TypeScript and it is 6.7MB.
Copilot AI balanced review requested due to automatic review settings October 17, 2026 15:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Cross-install token synchronization and packaged Monaco worker startup still need browser-level validation.

No open issues 🎉

What changed in this PR

Fixes extension authentication recovery, record-form loading resilience, and Monaco worker packaging.

Changes:

  • Recognizes middleware token rejections while preserving tokens replaced during verification.
  • Falls back to describe picklist values and displays actual record-loading errors.
  • Packages Monaco workers, excluding the unused TypeScript worker.
File Description
scripts/​copy-monaco-assets.mjs Copies required Monaco worker assets.
libs/​shared/​ui-record-form/​src/​lib/​ui-record-form-utils.ts Falls back on UI API failures.
libs/​shared/​ui-record-form/​src/​lib/​__tests__/​ui-record-form-utils.spec.ts Tests picklist fallback behavior.
libs/​shared/​ui-core/​src/​record/​ViewEditCloneRecord.tsx Displays underlying loading errors.
apps/​jetstream-web-extension/​src/​extension-scripts/​service-worker.ts Handles token rejection and concurrent replacement.
apps/​jetstream-web-extension/​src/​extension-scripts/​__tests__/​service-worker.spec.ts Covers middleware errors and token replacement.

Review effort: Balanced

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants