From d6f01862fe67afdb93d97031a1a78232349637d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Thu, 13 Aug 2026 12:33:23 +0000 Subject: [PATCH] fix a stack overflow in the wallet copy button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mine, from the clipboard sweep. format.ts exported copyToClipboard wrapping navigator.clipboard; the sweep replaced the body call with copyToClipboard(value), so the function called itself. CopyField.tsx is the caller, so every copy button in the Wallet was an infinite recursion. Removed the wrapper rather than repointing it — helpers/clipboard already does more (execCommand fallback on an insecure origin) and CopyField imports it directly now. Found by finally running tsgo, in the officerdev-test tree, which has node_modules. Co-Authored-By: Claude Opus 5 --- .../officerdev/src/apps/Wallet/CopyField.tsx | 2 +- .../officerdev/src/apps/Wallet/format.ts | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/workspaces/officerdev/src/apps/Wallet/CopyField.tsx b/src/workspaces/officerdev/src/apps/Wallet/CopyField.tsx index 41ed52e0..fbe0d841 100644 --- a/src/workspaces/officerdev/src/apps/Wallet/CopyField.tsx +++ b/src/workspaces/officerdev/src/apps/Wallet/CopyField.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; import { Check, Copy } from 'lucide-react'; -import { copyToClipboard } from './format'; +import { copyToClipboard } from 'helpers/clipboard'; // A read-only value with a copy button — addresses, invoices, txids, xpubs. // diff --git a/src/workspaces/officerdev/src/apps/Wallet/format.ts b/src/workspaces/officerdev/src/apps/Wallet/format.ts index 57dd75b6..5c22a000 100644 --- a/src/workspaces/officerdev/src/apps/Wallet/format.ts +++ b/src/workspaces/officerdev/src/apps/Wallet/format.ts @@ -1,5 +1,5 @@ import type { InvoiceState, PaymentStatus } from './shared'; -import { copyToClipboard } from 'helpers/clipboard'; + // Display formatting for the Wallet panels. // @@ -142,12 +142,10 @@ export const PAYMENT_TONES: Record = { failed: 'bg-destructive/10 text-destructive', }; -/** Clipboard with a graceful failure — an insecure origin has no navigator.clipboard at all. */ -export async function copyToClipboard(value: string): Promise { - try { - await copyToClipboard(value); - return true; - } catch { - return false; - } -} +// `copyToClipboard` used to be re-exported from here, wrapping navigator.clipboard with a try/catch. The +// helper in `helpers/clipboard` now does that and more — it falls back to execCommand on an insecure +// origin, where navigator.clipboard does not exist at all — so callers import it from there directly. +// +// Removed rather than left as a pass-through: the wrapper had become `copyToClipboard` calling +// `copyToClipboard`, which is a stack overflow on any Wallet copy button. Every re-export is a chance for +// exactly that, and this file is about formatting.