/** * Iframe Dialog Test Logic * Tests WebSerial + WebUSB dialog behavior in iframe vs standalone environments */ import { findPort } from "@lerobot/web"; let isRunning = false; function log(message: string) { const logElement = document.getElementById("log"); if (logElement) { const timestamp = new Date().toLocaleTimeString(); logElement.textContent += `[${timestamp}] ${message}\n`; logElement.scrollTop = logElement.scrollHeight; } } function setButtonState(buttonId: string, running: boolean) { const button = document.getElementById(buttonId) as HTMLButtonElement; if (button) { button.disabled = running; if (running) { button.textContent = "โณ Testing..."; } else { // Restore original text if (buttonId === "testStandalone") { button.textContent = "๐Ÿ–ฅ๏ธ Test Standalone (Current Window)"; } } } } // Mock implementation to test dialog behavior without actual findPort async function testDialogBehavior(environment: "standalone" | "iframe") { log(`๐ŸŽฏ Testing dialog behavior in ${environment} environment...`); try { // Method 1: Sequential (current approach) log("๐Ÿ“ก Method 1: Sequential WebSerial โ†’ WebUSB"); log("๐Ÿ”ธ Requesting WebSerial port..."); const serialPort = await navigator.serial.requestPort(); log("โœ… WebSerial port selected"); log("๐Ÿ”ธ Requesting WebUSB device..."); const usbDevice = await navigator.usb.requestDevice({ filters: [] }); log("โœ… WebUSB device selected"); log("๐ŸŽ‰ Sequential method succeeded!"); return { serialPort, usbDevice, method: "sequential" }; } catch (error: any) { log(`โŒ Sequential method failed: ${error.message}`); // Method 2: Simultaneous (new approach) try { log("๐Ÿ“ก Method 2: Simultaneous WebSerial + WebUSB"); log("๐Ÿš€ Starting both dialogs simultaneously..."); const [serialPortPromise, usbDevicePromise] = [ navigator.serial.requestPort(), navigator.usb.requestDevice({ filters: [] }), ]; log("โณ Waiting for both dialogs..."); const [serialPort, usbDevice] = await Promise.all([ serialPortPromise, usbDevicePromise, ]); log("โœ… Both dialogs completed!"); log("๐ŸŽ‰ Simultaneous method succeeded!"); return { serialPort, usbDevice, method: "simultaneous" }; } catch (simultaneousError: any) { log(`โŒ Simultaneous method also failed: ${simultaneousError.message}`); throw simultaneousError; } } } // Test using actual findPort function async function testActualFindPort() { log("๐Ÿ” Testing actual findPort function..."); try { const findProcess = await findPort(); const robots = await findProcess.result; log(`โœ… findPort succeeded! Found ${robots.length} robots`); robots.forEach((robot, index) => { log(` Robot ${index + 1}: ${robot.name} (${robot.robotType})`); }); return robots; } catch (error: any) { log(`โŒ findPort failed: ${error.message}`); throw error; } } declare global { interface Window { clearLog: () => void; testStandalone: () => Promise; loadIframe: (mode: string) => void; } } window.clearLog = function () { const logElement = document.getElementById("log"); if (logElement) { logElement.textContent = "Log cleared.\n"; } }; window.loadIframe = function (mode: string) { const iframe = document.getElementById("testFrame") as HTMLIFrameElement; const infoElement = document.getElementById("iframeInfo"); if (!iframe) return; // Clear existing attributes iframe.removeAttribute("sandbox"); iframe.removeAttribute("allow"); let iframeContent = ""; let description = ""; switch (mode) { case "permissive": // Most permissive - similar to our original test iframe.setAttribute("allow", "serial; usb"); description = "Permissive: Full access to WebSerial and WebUSB"; iframeContent = generateIframeContent(); break; case "restricted": // Restricted with sandbox - might block certain permissions iframe.setAttribute( "sandbox", "allow-scripts allow-same-origin allow-popups allow-forms" ); iframe.setAttribute("allow", "serial; usb"); description = "Restricted: Sandboxed with limited permissions"; iframeContent = generateIframeContent(); break; case "crossorigin": // Cross-origin simulation (limited local test) iframe.setAttribute("sandbox", "allow-scripts allow-popups allow-forms"); iframe.setAttribute("allow", "serial; usb"); description = "Cross-Origin: Different origin with sandbox restrictions"; iframeContent = generateIframeContent(); break; } if (infoElement) { infoElement.textContent = `Current iframe mode: ${description}`; } iframe.src = "data:text/html;charset=utf-8," + encodeURIComponent(iframeContent); log(`๐Ÿ“ Loaded iframe in ${mode} mode: ${description}`); }; window.testStandalone = async function () { if (isRunning) return; isRunning = true; setButtonState("testStandalone", true); log("๐Ÿงช Testing with actual findPort function..."); try { // Test the actual findPort function with our new fallback logic await testActualFindPort(); log("\nโœ… findPort test completed!"); } catch (error: any) { log(`โŒ findPort test failed: ${error.message}`); // Analyze the error if (error.message.includes("user gesture")) { log("๐Ÿ” User gesture consumption detected!"); log("๐Ÿ’ก This confirms the issue - WebSerial consumes the gesture"); } else if (error.message.includes("cancelled")) { log("๐Ÿ” User cancelled dialog - this is expected for testing"); } else if (error.message.includes("No port selected")) { log("๐Ÿ” Dialog conflict detected - this should trigger fallback mode"); } } finally { isRunning = false; setButtonState("testStandalone", false); } }; // Generate iframe content dynamically function generateIframeContent(): string { return ` Iframe Test Content

๐Ÿ–ผ๏ธ Inside Iframe

This simulates HuggingFace Spaces environment

Ready to test...
`; } // Initialize on DOM load document.addEventListener("DOMContentLoaded", () => { // Check browser support if (!("serial" in navigator)) { log("โŒ WebSerial API not supported in this browser"); log("๐Ÿ’ก Try Chrome/Edge with --enable-web-serial flag"); const button = document.getElementById( "testStandalone" ) as HTMLButtonElement; if (button) button.disabled = true; } else { log("โœ… WebSerial API supported"); } if (!("usb" in navigator)) { log("โŒ WebUSB API not supported in this browser"); log("๐Ÿ’ก Try Chrome/Edge with --enable-web-usb flag"); } else { log("โœ… WebUSB API supported"); } log("๐ŸŽฏ Environment: " + (window === window.top ? "Standalone" : "Iframe")); log("Ready to test dialog behavior..."); // Set up iframe content - start with permissive mode window.loadIframe("permissive"); // Listen for messages from iframe window.addEventListener("message", (event) => { if (event.data.type === "iframe-log") { log(`[IFRAME] ${event.data.message}`); } }); });