Skip to content

Move to Electron 41, replace Electron clipboard API with navigator.clipboard#2643

Open
bengotow wants to merge 3 commits intomasterfrom
claude/upgrade-electron-ISUsb
Open

Move to Electron 41, replace Electron clipboard API with navigator.clipboard#2643
bengotow wants to merge 3 commits intomasterfrom
claude/upgrade-electron-ISUsb

Conversation

@bengotow
Copy link
Collaborator

Summary

Migrated all clipboard operations from the deprecated Electron clipboard module to the standard Web API navigator.clipboard. This modernizes the codebase and aligns with current best practices for clipboard access in Electron applications.

Key Changes

  • Removed clipboard imports from all Electron module requires across 8 files
  • Replaced all clipboard.writeText() calls with navigator.clipboard.writeText() in:
    • evented-iframe.tsx (3 occurrences)
    • oauth-signin-page.tsx
    • participants-text-field.tsx
    • share-button.tsx
    • event-attendees-input.tsx
    • message-controls.tsx
    • copy-button.tsx
    • thread-list-context-menu.ts
    • thread-sharing-button.tsx

Implementation Details

  • The navigator.clipboard API is the modern standard for clipboard access in web contexts and is available in Electron's renderer process
  • All clipboard write operations are now using the same API, providing consistency across the codebase
  • No functional changes to clipboard behavior; this is purely an API migration
  • Electron version updated from 39.2.7 to 41.0.2 to ensure compatibility with the standard clipboard API

https://claude.ai/code/session_01WBGx8XkrU7X1FhuXGdMygt

- 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
@indent-staging
Copy link
Contributor

indent-staging bot commented Mar 14, 2026

Issues

No issues found.

Resolved (2 issues)
  • navigator.clipboard.writeText() returns a Promise, but all 9 call sites use it fire-and-forget without await or .catch(). If the write fails (e.g., due to document focus loss in context menu callbacks), the user gets no feedback and an unhandled promise rejection is logged. In copy-button.tsx, the UI shows "Copied" immediately regardless of whether the write succeeded. (fixed by commit cfe0c47)
  • The test harness in app/spec/spec-runner/master-before-each.ts (lines 130-136) still spies on electron.clipboard.writeText and readText, but production code no longer uses the Electron clipboard for writes. These spies are now dead code. (fixed by commit cfe0c47)

Summary

This PR upgrades Electron from 39.2.7 to 41.0.2 and migrates all renderer-process clipboard.writeText() calls from Electron's clipboard API to the standard Web navigator.clipboard.writeText() API, addressing a deprecation introduced in Electron 40. Platform-specific clipboard reads in composer-editor.tsx and main-process clipboard usage in application.ts are correctly preserved.

  • Bump electron from 39.2.7 to 41.0.2 in package.json and regenerate package-lock.json
  • Replace clipboard.writeText() (from electron) with navigator.clipboard.writeText() across 9 renderer-side files
  • Add .catch() error handling on all async clipboard writes; copy-button.tsx awaits success before showing "Copied" label
  • Update test spies in master-before-each.ts to mock navigator.clipboard instead of electron.clipboard
  • Retain Electron clipboard API for platform-specific format reads (composer-editor.tsx) and main-process usage (application.ts)

CI Checks

better-sqlite3 fails to compile against Electron 41's Node/V8 headers during npm ci. The native module uses V8 APIs (PropertyCallbackInfo::This(), External::Value()) that have been changed/deprecated in the V8 version bundled with Electron 41 (Node ABI v145). The better-sqlite3 dependency needs to be upgraded to a version compatible with Electron 41's V8, or Electron should be pinned to a version that better-sqlite3 supports.

Failingtest Autofix

better-sqlite3 native module fails to compile against Electron 41's V8 headers. The V8 API has breaking changes (PropertyCallbackInfo::This() removed, External::Value()/External::New() deprecated) that the current version of better-sqlite3 doesn't handle. Need to upgrade better-sqlite3 to a version compatible with Electron 41, or use electron-rebuild with the correct Electron version.

Rule Checks 3 rules evaluated, 3 passed, 0 failed

Passing rules

Passing This is a longer title to see what happens when they are too long to fit
Passing B
Passing Ben Rule

Autofix All

@bengotow bengotow changed the title Replace Electron clipboard API with navigator.clipboard Move to Electron 41, replace Electron clipboard API with navigator.clipboard Mar 14, 2026
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
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
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