Files
Ben Gotow 4f09302077 Move to Electron 41, replace Electron clipboard API with navigator.clipboard (#2643)
* Upgrade Electron from 39.2.7 to 41.0.2 and address deprecations

- Bump `electron` from 39.2.7 → 41.0.2 in package.json
- Electron 40 deprecated direct clipboard API access from renderer
  processes. Migrate all renderer-side `clipboard.writeText()` calls
  (imported from 'electron') to the standard Web API
  `navigator.clipboard.writeText()` across 9 files:
    app/src/components/evented-iframe.tsx
    app/src/components/participants-text-field.tsx
    app/internal_packages/activity/lib/dashboard/share-button.tsx
    app/internal_packages/main-calendar/lib/core/event-attendees-input.tsx
    app/internal_packages/message-list/lib/message-controls.tsx
    app/internal_packages/onboarding/lib/oauth-signin-page.tsx
    app/internal_packages/thread-list/lib/thread-list-context-menu.ts
    app/internal_packages/thread-sharing/lib/copy-button.tsx
    app/internal_packages/thread-sharing/lib/thread-sharing-button.tsx
- Keep Electron clipboard.read() in composer-editor.tsx for
  platform-specific format reads (public.file-url, FileNameW,
  text/uri-list) which have no navigator.clipboard equivalent
- Main-process clipboard usage in application.ts is unchanged (not
  subject to the renderer deprecation)
- No action needed for Electron 41 breaking changes: the PDF
  WebContents change does not affect this app (PDFs are rendered via
  pdf.js in a separate BrowserWindow, not via MimeHandlerViewGuest),
  and the cookie change-event cause update does not affect this app
  (no cookie change listeners present)

https://claude.ai/code/session_01WBGx8XkrU7X1FhuXGdMygt

* Update package-lock.json for Electron 41.0.2 upgrade

Regenerate lock file to satisfy npm ci after bumping electron from
39.2.7 to 41.0.2. Also updates transitive deps @types/node and
undici-types to versions compatible with Node 24 (bundled in Electron 41).

https://claude.ai/code/session_01WBGx8XkrU7X1FhuXGdMygt

* Fix unhandled Promise rejections and dead clipboard test spies

navigator.clipboard.writeText() is async; the previous change left all
call sites fire-and-forget. Two problems fixed:

1. All 8 non-CopyButton call sites now chain .catch() so failures are
   logged to the console instead of producing unhandled rejection
   warnings (e.g. when context menu callbacks fire after the window
   loses focus).

2. copy-button.tsx previously showed "Copied" immediately regardless of
   whether the write succeeded. The UI update and 2-second timer are now
   moved into .then() so the label only changes on success. A truthy
   sentinel (true) is assigned to _timeout before the async call to
   block re-entry while the write is in-flight; clearTimeout(true) is a
   safe no-op so componentWillUnmount is unaffected. On failure _timeout
   is reset to null so the user can retry.

3. master-before-each.ts: remove dead spyOn(electron.clipboard, ...)
   stubs (production code no longer calls electron.clipboard.writeText
   from renderer) and replace with spyOn(navigator.clipboard, ...)
   stubs that return resolved Promises, matching the async API contract.

https://claude.ai/code/session_01WBGx8XkrU7X1FhuXGdMygt

* Fix node-gyp config so better-sqlite3 finds its prebuilt for Electron 41

Two related problems:

1. app/package.json pinned electron to "39.2.7" in its resolutions field
   while the root package.json (and npm_config_target in postinstall) was
   already at "41.0.2". The stale pin would override the correct version in
   the app's dependency subtree. Updated to "41.0.2" to stay in sync.

2. The electron npm environment in postinstall.js did not set
   npm_config_node_gyp. Without it, npm falls back to its own bundled
   node-gyp, which is typically older and does not recognise Electron 41 /
   Node.js 22 headers. prebuild-install (used by better-sqlite3) calls
   node-gyp when resolving the prebuilt binary URL; if it gets the wrong
   version it fails to match the ABI and either falls back to a slow
   source compile or errors out. Pointing npm_config_node_gyp at the
   project's node-gyp v12 binary ensures the correct headers are fetched
   and the prebuilt .node file is used.

https://claude.ai/code/session_01WBGx8XkrU7X1FhuXGdMygt

* Fix

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-17 20:46:53 -05:00
..