copy.ts
1/**2 * Popup-side copy helper.3 *4 * MV3 service workers can't reliably write the clipboard from a non-focused5 * tab — the SW path's `chrome.scripting.executeScript` into the active tab6 * loses the popup's user gesture and the page document is not focused, so7 * `navigator.clipboard.writeText` rejects with NotAllowed. The popup itself8 * is a focused document with a fresh user gesture and `clipboardWrite`9 * permission, so it can call the API directly. We then notify the SW with10 * `alreadyWritten: true` so it skips its own write and only schedules the11 * auto-clear timer.12 */1314import { sendMessage } from "./App";1516export async function popupCopy(text: string, label: string): Promise<boolean> {17 let alreadyWritten = false;18 try {19 await navigator.clipboard.writeText(text);20 alreadyWritten = true;21 } catch {22 // Some popup contexts (jsdom in tests, or rare permission-denied edge23 // cases) reject the direct write. Fall through to the SW path.24 }2526 const response = await sendMessage({27 type: "COPY",28 payload: { text, label, alreadyWritten },29 });30 return alreadyWritten || Boolean((response as { ok?: boolean })?.ok);31}