Skip to content

Commit d92b14b

Browse files
fix: [ci-fix] add try/catch around navigator.clipboard.writeText calls
clipboard.writeText() can reject when the document isn't focused or permissions are denied. Wrap both call sites in try/catch to prevent unhandled promise rejections. Added files to the bare-catch allowlist since clipboard failures are intentionally silent. Co-authored-by: Ona <no-reply@ona.com>
1 parent 0cee40e commit d92b14b

3 files changed

Lines changed: 18 additions & 8 deletions

File tree

src/components/members/invite-form.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,14 @@ export function InviteForm({
4545

4646
const handleCopyLink = useCallback(async () => {
4747
if (!inviteLink) return;
48-
await navigator.clipboard.writeText(inviteLink);
49-
setLinkCopied(true);
50-
if (timerRef.current) clearTimeout(timerRef.current);
51-
timerRef.current = setTimeout(() => setLinkCopied(false), 2000);
48+
try {
49+
await navigator.clipboard.writeText(inviteLink);
50+
setLinkCopied(true);
51+
if (timerRef.current) clearTimeout(timerRef.current);
52+
timerRef.current = setTimeout(() => setLinkCopied(false), 2000);
53+
} catch {
54+
// Clipboard access denied — button stays in default state
55+
}
5256
}, [inviteLink]);
5357

5458
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {

src/components/members/pending-invite-list.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,14 @@ function CopyLinkButton({ token }: { token: string }) {
3030

3131
const handleCopy = useCallback(async () => {
3232
const url = `${window.location.origin}/invite/${token}`;
33-
await navigator.clipboard.writeText(url);
34-
setCopied(true);
35-
if (timerRef.current) clearTimeout(timerRef.current);
36-
timerRef.current = setTimeout(() => setCopied(false), 2000);
33+
try {
34+
await navigator.clipboard.writeText(url);
35+
setCopied(true);
36+
if (timerRef.current) clearTimeout(timerRef.current);
37+
timerRef.current = setTimeout(() => setCopied(false), 2000);
38+
} catch {
39+
// Clipboard access denied — no-op
40+
}
3741
}, [token]);
3842

3943
useEffect(() => {

src/lib/sentry.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ const BARE_CATCH_PERMANENT_ALLOWLIST = new Set([
1717
"src/lib/supabase/server.ts", // cookie setAll in Server Components
1818
"src/components/editor/editor.tsx", // URL validation (new URL() throws)
1919
"src/app/api/health/route.ts", // intentionally silent, monitored externally
20+
"src/components/members/invite-form.tsx", // clipboard writeText — intentionally silent on permission denied
21+
"src/components/members/pending-invite-list.tsx", // clipboard writeText — intentionally silent on permission denied
2022
]);
2123

2224
/**

0 commit comments

Comments
 (0)