Prevent false Stuffbox failure when the successful popup closes first

Hop-State: A_06FP8DE7KCCAG4HXZNBATBG
Hop-Proposal: R_06FP8DDKY394CXK69M1Q78R
Hop-Task: T_06FP8D3ECRPSTFC8CT8DZB0
Hop-Attempt: AT_06FP8D3ECRDMQ2HEYDAE7W0
This commit is contained in:
2026-07-14 22:17:53 -07:00
committed by Hop
parent e8a2dd2979
commit e50316bbad
3 changed files with 24 additions and 3 deletions
+22 -1
View File
@@ -2,6 +2,7 @@
import { useEffect, useState } from 'react';
import { Box, ChevronDown, ExternalLink } from 'lucide-react';
import { getStorageProvider } from '@/lib/stuffbox/browser-upload';
interface StorageConfigurationPromptProps {
open: boolean;
@@ -61,14 +62,34 @@ export function StorageConfigurationPrompt({ open, onConfigured, onCancel, varia
if (!response.ok || !data.authorizationUrl) throw new Error(data.error || 'Unable to connect Stuffbox');
const result = new Promise<void>((resolve, reject) => {
let settled = false;
let verifyingClosedPopup = false;
let channel: BroadcastChannel | null = null;
const timeout = window.setTimeout(() => {
finish({ type: 'synapsis:stuffbox', success: false, message: 'Stuffbox connection timed out.' });
}, 10 * 60_000);
const popupClosed = window.setInterval(() => {
if (popup.closed) finish({ type: 'synapsis:stuffbox', success: false, message: 'The Stuffbox window was closed before connecting.' });
if (popup.closed) void verifyConnectionAfterPopupClosed();
}, 500);
async function verifyConnectionAfterPopupClosed() {
if (settled || verifyingClosedPopup) return;
verifyingClosedPopup = true;
window.clearInterval(popupClosed);
for (let attempt = 0; attempt < 4 && !settled; attempt += 1) {
await new Promise(resolveDelay => window.setTimeout(resolveDelay, 250));
if (settled) return;
try {
if (await getStorageProvider() === 'stuffbox') {
finish({ type: 'synapsis:stuffbox', success: true, message: 'Stuffbox connected.' });
return;
}
} catch { /* Retry while the callback finishes saving the connection. */ }
}
finish({ type: 'synapsis:stuffbox', success: false, message: 'The Stuffbox window was closed before connecting.' });
}
function cleanup() {
window.clearTimeout(timeout);
window.clearInterval(popupClosed);
+1 -1
View File
@@ -7,7 +7,7 @@ describe('renderStuffboxPopupResponse', () => {
expect(html).toContain("new BroadcastChannel('synapsis:stuffbox')");
expect(html).toContain("localStorage.setItem('synapsis:stuffbox:result'");
expect(html).toContain('window.close()');
expect(html).toContain('window.setTimeout(() => window.close(), 250)');
expect(html).not.toContain('window.location.replace');
});
});
+1 -1
View File
@@ -18,7 +18,7 @@ export function renderStuffboxPopupResponse(origin: string, success: boolean, me
try {
localStorage.setItem('synapsis:stuffbox:result', JSON.stringify({ ...payload, sentAt: Date.now() }));
} catch {}
window.setTimeout(() => window.close(), 75);
window.setTimeout(() => window.close(), 250);
</script>
</body></html>`;
}