livedesk 0.1.656 → 0.1.657
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/hub/src/remote-hub.js +47 -24
- package/hub/src/server.js +200 -13
- package/hub/src/shared-wall-profile-contract.mjs +40 -0
- package/hub/src/shared-wall-profile-contract.test.mjs +38 -0
- package/package.json +1 -1
- package/web/dist/app.html +3 -3
- package/web/dist/app.webmanifest +1 -1
- package/web/dist/assets/{AgentSettingsTab-D0271Ynp.js → AgentSettingsTab-CU3kHssT.js} +1 -1
- package/web/dist/assets/{AgentsPage-DEdUBoe0.js → AgentsPage-DcUy7xPU.js} +1 -1
- package/web/dist/assets/{App-DK9GZcvU.js → App-ARrqCA9B.js} +3 -3
- package/web/dist/assets/{CaptureGallery-C0xqFLap.js → CaptureGallery-BPKKxPej.js} +1 -1
- package/web/dist/assets/{DesktopUpdatePanel-uMaTnBsl.js → DesktopUpdatePanel-C5wDB5zf.js} +1 -1
- package/web/dist/assets/{SettingsPage-BoFLQBfH.js → SettingsPage-ChNfBaQo.js} +1 -1
- package/web/dist/assets/{SettingsTabs-D0zQN-Mo.js → SettingsTabs-B-uMhvwn.js} +1 -1
- package/web/dist/assets/{ShareFilesPage-BiCS0Nyd.js → ShareFilesPage-C9vhKzGp.js} +1 -1
- package/web/dist/assets/{SupportPage-D241Vkb1.js → SupportPage-C-uQ-RTX.js} +1 -1
- package/web/dist/assets/{VuvoDeskApp-36bRXXS2.js → VuvoDeskApp-BeeOb_MQ.js} +1 -1
- package/web/dist/assets/{app-hMd5uyvT.js → app-DhbXrOFp.js} +1 -1
- package/web/dist/assets/{main-DT492iHt.js → main-BTb7f--C.js} +2 -2
- package/web/dist/assets/styles-eZ2IzXEL.js +16 -0
- package/web/dist/index.html +2 -2
- package/web/dist/sw.js +2 -2
- package/web/dist/vuvodesk-build-evidence.json +51 -51
- package/web/dist/assets/styles-Ba1tPFHg.js +0 -16
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/AgentsPage-
|
|
2
|
-
import{D as Tn,k as Jv,l as gl,i as wi,h as Ue,o as Zv,e as ks,q as ey,u as As,v as Is,_ as mr,x as Yh,y as ty,z as ny,j as i,p as $e,A as Qh,B as ry,C as Zp,E as ay,G as _u,g as oy,T as ef,b as ju,a as ds,F as Bu,M as tf,f as Hu,H as iy,L as sy}from"./styles-Ba1tPFHg.js";import{a as s,am as cy,an as nf,p as ly,ao as uy,ap as dy,ae as kl,X as xa,U as Ts,aq as Xh,c as Aa,l as bl,ac as Ra,ar as my,as as py,at as fy,au as hy,k as wo,av as Jh,g as Ci,aw as gy,ax as by,b as Cn,y as vy,ay as Zh,f as Ms,a0 as eg,T as vl,aa as kd,ab as yy,ad as rf,a9 as wy,az as Sy,D as af,O as Cy,N as ky,A as My,E as xy,aA as of,W as tg,aB as Wu,Z as Ry,a2 as $u,x as Ay,aC as sf,aD as Iy,aE as ng,C as rg,n as ms,aF as Ty,aG as Py,t as Ey,aH as Ny,a4 as Fy,G as Dy,Q as Ly}from"./icons-CacEbnZu.js";import{c as Oy}from"./supabase-C7qjtLN3.js";import{c as _y,a as jy,f as Vu,b as By,r as zu,t as Uu,d as cf,e as Hy,i as lf,g as Wy,h as On,j as wa,s as dn,k as ho,l as qu,m as Gu,n as Ku,o as $y,p as el,q as uf,u as tl,v as df}from"./frame-lifecycle-esOdP-EY.js";const ag={hub:"Use this computer as Hub. Hub connects to and manages Client computers.","switch-to-hub":"Switch this computer from Client to Hub. It will manage Client computers instead of sharing its own screen.",client:"Keep this computer in Client mode so its screens, files, audio, and remote controls remain available to the active Hub.",wall:"Show live thumbnails from every connected Client. Choose a display, change tile size, or move into Control without opening another connection.",control:"Open the selected Client at full resolution and send mouse and keyboard input through the existing Hub session.","share-files":"Browse files on the Hub, send files to selected Clients, and manage shared folders and transfer progress.",agents:"Run approved commands on connected Clients through the Hub-hosted Codex Agent and VuvoDesk permission controls."},Md={en:ag,ko:{hub:"이 컴퓨터를 Hub로 사용합니다. Hub는 Client 컴퓨터를 연결하고 관리합니다.","switch-to-hub":"이 컴퓨터를 Client에서 Hub로 바꿉니다. 자신의 화면 공유를 멈추고 Client 컴퓨터를 관리합니다.",client:"이 컴퓨터를 Client 모드로 유지합니다. 화면, 파일, 오디오와 원격 제어 기능이 활성 Hub에서 계속 사용 가능하도록 연결합니다.",wall:"연결된 모든 Client의 실시간 화면을 한곳에 표시합니다. 모니터와 타일 크기를 선택하고 새 연결 없이 Control로 이동할 수 있습니다.",control:"선택한 Client 화면을 전체 해상도로 열고 기존 Hub 세션을 통해 마우스와 키보드 입력을 전송합니다.","share-files":"Hub의 파일을 탐색하고 선택한 Client로 전송하며 공유 폴더와 전송 진행 상태를 관리합니다.",agents:"Hub의 Codex가 연결된 Client에서 VuvoDesk 권한과 승인 범위 안의 명령을 실행합니다."},ja:{hub:"このコンピューターを VuvoDesk Hub として運用します。Hub は Client 接続、Wall、Control、ファイル共有、Agents を一か所で管理する統合コントロールセンターで、ネットワーク変更後に押すと安全な接続情報も更新します。","switch-to-hub":"このコンピューターを Client から Hub に切り替えます。新しい役割を保存して同じデスクトップランタイムを再起動し、Wall を開きます。Client としての共有は停止します。",client:"このコンピューターを Client モードで維持し、画面、ファイル、音声、リモート操作をアクティブ Hub から利用できるようにします。",wall:"接続中のすべての Client のライブ画面を一覧表示します。ディスプレイやタイルサイズを選び、新しい接続なしで Control に移動できます。",control:"選択した Client をフル解像度で開き、既存の Hub セッションからマウスとキーボード入力を送信します。","share-files":"Hub のファイルを参照し、選択した Client への送信、共有フォルダー、転送状況を管理します。",agents:"Hub の Codex Agent が、VuvoDesk の権限と承認の範囲内で接続中の Client にコマンドを実行します。"},zh:{hub:"将此电脑作为 VuvoDesk Hub 运行。Hub 是统一控制中心,可集中管理 Client 连接、Wall、Control、文件共享和 Agents;网络变化后按下此按钮还会刷新安全连接信息。","switch-to-hub":"将此电脑从 Client 切换为 Hub。VuvoDesk 保存新角色、重启同一桌面运行时并打开 Wall;此电脑将停止作为 Client 共享。",client:"让此电脑保持 Client 模式,使活动 Hub 可以继续使用它的屏幕、文件、音频和远程控制。",wall:"集中显示所有已连接 Client 的实时缩略图。可以选择显示器、调整磁贴大小,并在不新建连接的情况下进入 Control。",control:"以完整分辨率打开所选 Client,并通过现有 Hub 会话发送鼠标和键盘输入。","share-files":"浏览 Hub 文件、向所选 Client 发送文件,并管理共享文件夹和传输进度。",agents:"Hub 的 Codex Agent 会在 VuvoDesk 权限与批准范围内,对已连接的 Client 执行命令。"},"zh-TW":{hub:"將此電腦作為 VuvoDesk Hub 運作。Hub 是統一控制中心,可集中管理 Client 連線、Wall、Control、檔案分享與 Agents;網路變更後按下此按鈕也會更新安全連線資訊。","switch-to-hub":"將此電腦從 Client 切換為 Hub。VuvoDesk 會儲存新角色、重新啟動同一桌面執行階段並開啟 Wall;此電腦將停止以 Client 身分共享。",client:"讓此電腦維持 Client 模式,使作用中 Hub 可繼續使用它的畫面、檔案、音訊與遠端控制。",wall:"集中顯示所有已連線 Client 的即時縮圖。可選擇顯示器、調整圖塊大小,並在不建立新連線的情況下進入 Control。",control:"以完整解析度開啟所選 Client,並透過現有 Hub 工作階段傳送滑鼠與鍵盤輸入。","share-files":"瀏覽 Hub 檔案、傳送檔案到所選 Client,並管理共享資料夾與傳輸進度。",agents:"Hub 的 Codex Agent 會在 VuvoDesk 權限與核准範圍內,對已連線的 Client 執行命令。"},es:{hub:"Usa este equipo como VuvoDesk Hub. Hub es el centro de control unificado para conexiones Client, Wall, Control, archivos y Agents; púlsalo tras cambios de red para actualizar el acceso seguro.","switch-to-hub":"Cambia este equipo de Client a Hub. VuvoDesk guarda el nuevo rol, reinicia el mismo entorno de escritorio y abre Wall; el equipo deja de compartirse como Client.",client:"Mantiene este equipo en modo Client para que sus pantallas, archivos, audio y control remoto sigan disponibles desde el Hub activo.",wall:"Muestra miniaturas en vivo de todos los Clients conectados. Elige pantalla y tamaño, o entra en Control sin abrir otra conexión.",control:"Abre el Client seleccionado a resolución completa y envía ratón y teclado por la sesión Hub existente.","share-files":"Explora archivos del Hub, envíalos a los Clients seleccionados y administra carpetas compartidas y transferencias.",agents:"El Codex Agent del Hub ejecuta comandos en los Clients conectados dentro de los permisos y aprobaciones de VuvoDesk."},fr:{hub:"Utilise cet ordinateur comme VuvoDesk Hub. Hub est le centre de contrôle unifié des connexions Client, de Wall, Control, des fichiers et des Agents ; appuyez après un changement réseau pour actualiser l’accès sécurisé.","switch-to-hub":"Bascule cet ordinateur de Client vers Hub. VuvoDesk enregistre le nouveau rôle, redémarre le même environnement de bureau et ouvre Wall ; le partage Client s’arrête.",client:"Maintient cet ordinateur en mode Client afin que ses écrans, fichiers, sons et commandes à distance restent disponibles depuis le Hub actif.",wall:"Affiche les miniatures en direct de tous les Clients connectés. Choisissez l’écran et la taille, ou passez à Control sans nouvelle connexion.",control:"Ouvre le Client sélectionné en pleine résolution et transmet souris et clavier via la session Hub existante.","share-files":"Parcourez les fichiers du Hub, envoyez-les aux Clients sélectionnés et gérez dossiers partagés et transferts.",agents:"Le Codex Agent du Hub exécute des commandes sur les Clients connectés selon les permissions et approbations de VuvoDesk."},de:{hub:"Verwendet diesen Computer als VuvoDesk Hub. Hub ist die gemeinsame Steuerzentrale für Client-Verbindungen, Wall, Control, Dateien und Agents; nach Netzwerkänderungen aktualisiert ein Klick den sicheren Zugriff.","switch-to-hub":"Wechselt diesen Computer von Client zu Hub. VuvoDesk speichert die neue Rolle, startet dieselbe Desktop-Laufzeit neu und öffnet Wall; die Client-Freigabe endet.",client:"Hält diesen Computer im Client-Modus, damit Bildschirme, Dateien, Audio und Fernsteuerung am aktiven Hub verfügbar bleiben.",wall:"Zeigt Live-Vorschaubilder aller verbundenen Clients. Display und Kachelgröße wählen oder ohne neue Verbindung zu Control wechseln.",control:"Öffnet den gewählten Client in voller Auflösung und sendet Maus- und Tastatureingaben über die bestehende Hub-Sitzung.","share-files":"Dateien auf dem Hub durchsuchen, an gewählte Clients senden sowie Freigaben und Übertragungen verwalten.",agents:"Der Codex Agent des Hubs führt Befehle auf verbundenen Clients innerhalb der VuvoDesk-Berechtigungen und Freigaben aus."},"pt-BR":{hub:"Usa este computador como VuvoDesk Hub. Hub é o centro de controle unificado para conexões Client, Wall, Control, arquivos e Agents; após mudanças de rede, pressione para atualizar o acesso seguro.","switch-to-hub":"Muda este computador de Client para Hub. O VuvoDesk salva a nova função, reinicia o mesmo runtime de desktop e abre o Wall; o compartilhamento como Client é encerrado.",client:"Mantém este computador no modo Client para que telas, arquivos, áudio e controle remoto continuem disponíveis no Hub ativo.",wall:"Mostra miniaturas ao vivo de todos os Clients conectados. Escolha a tela e o tamanho ou entre em Control sem criar outra conexão.",control:"Abre o Client selecionado em resolução total e envia mouse e teclado pela sessão Hub existente.","share-files":"Navegue pelos arquivos do Hub, envie para Clients selecionados e gerencie pastas compartilhadas e transferências.",agents:"O Codex Agent do Hub executa comandos nos Clients conectados dentro das permissões e aprovações do VuvoDesk."},it:{hub:"Usa questo computer come VuvoDesk Hub. Hub è il centro di controllo unificato per connessioni Client, Wall, Control, file e Agents; dopo modifiche di rete, premilo per aggiornare l’accesso sicuro.","switch-to-hub":"Passa questo computer da Client a Hub. VuvoDesk salva il nuovo ruolo, riavvia lo stesso runtime desktop e apre Wall; la condivisione come Client termina.",client:"Mantiene questo computer in modalità Client, rendendo schermi, file, audio e controllo remoto disponibili all’Hub attivo.",wall:"Mostra le anteprime live di tutti i Client connessi. Scegli display e dimensione oppure passa a Control senza una nuova connessione.",control:"Apre il Client selezionato a piena risoluzione e invia mouse e tastiera tramite la sessione Hub esistente.","share-files":"Esplora i file dell’Hub, inviali ai Client selezionati e gestisci cartelle condivise e trasferimenti.",agents:"Il Codex Agent dell’Hub esegue comandi sui Client connessi entro i permessi e le approvazioni di VuvoDesk."},id:{hub:"Gunakan komputer ini sebagai VuvoDesk Hub. Hub adalah pusat kendali terpadu untuk koneksi Client, Wall, Control, file, dan Agents; tekan setelah perubahan jaringan untuk memperbarui akses aman.","switch-to-hub":"Alihkan komputer ini dari Client menjadi Hub. VuvoDesk menyimpan peran baru, memulai ulang runtime desktop yang sama, lalu membuka Wall; berbagi sebagai Client berhenti.",client:"Pertahankan komputer ini dalam mode Client agar layar, file, audio, dan kendali jarak jauh tetap tersedia bagi Hub aktif.",wall:"Tampilkan thumbnail live semua Client yang terhubung. Pilih layar dan ukuran tile atau masuk ke Control tanpa koneksi baru.",control:"Buka Client terpilih pada resolusi penuh dan kirim input mouse serta keyboard melalui sesi Hub yang ada.","share-files":"Jelajahi file Hub, kirim ke Client terpilih, serta kelola folder bersama dan progres transfer.",agents:"Codex Agent di Hub menjalankan perintah pada Client terhubung sesuai izin dan persetujuan VuvoDesk."},vi:{hub:"Dùng máy tính này làm VuvoDesk Hub. Hub là trung tâm điều khiển hợp nhất cho kết nối Client, Wall, Control, tệp và Agents; nhấn sau khi đổi mạng để làm mới quyền truy cập an toàn.","switch-to-hub":"Chuyển máy tính này từ Client sang Hub. VuvoDesk lưu vai trò mới, khởi động lại cùng môi trường desktop và mở Wall; việc chia sẻ dưới dạng Client sẽ dừng.",client:"Giữ máy tính này ở chế độ Client để màn hình, tệp, âm thanh và điều khiển từ xa luôn sẵn sàng cho Hub đang hoạt động.",wall:"Hiển thị ảnh thu nhỏ trực tiếp của mọi Client đã kết nối. Chọn màn hình, cỡ ô hoặc vào Control mà không tạo kết nối mới.",control:"Mở Client đã chọn ở độ phân giải đầy đủ và gửi chuột, bàn phím qua phiên Hub hiện có.","share-files":"Duyệt tệp trên Hub, gửi tới Client đã chọn và quản lý thư mục chia sẻ cùng tiến trình truyền.",agents:"Codex Agent trên Hub chạy lệnh trên các Client đã kết nối trong phạm vi quyền và phê duyệt của VuvoDesk."},th:{hub:"ใช้คอมพิวเตอร์เครื่องนี้เป็น VuvoDesk Hub โดย Hub คือศูนย์ควบคุมรวมสำหรับการเชื่อมต่อ Client, Wall, Control, ไฟล์ และ Agents และกดหลังเปลี่ยนเครือข่ายเพื่อรีเฟรชการเข้าถึงที่ปลอดภัย","switch-to-hub":"เปลี่ยนคอมพิวเตอร์นี้จาก Client เป็น Hub โดย VuvoDesk จะบันทึกบทบาทใหม่ รีสตาร์ต desktop runtime เดิม และเปิด Wall พร้อมหยุดแชร์ในฐานะ Client",client:"ให้คอมพิวเตอร์นี้อยู่ในโหมด Client เพื่อให้ Hub ที่ใช้งานเข้าถึงหน้าจอ ไฟล์ เสียง และการควบคุมระยะไกลได้ต่อเนื่อง",wall:"แสดงภาพสดแบบย่อของ Client ที่เชื่อมต่อทั้งหมด เลือกจอและขนาด tile หรือเข้า Control ได้โดยไม่เปิดการเชื่อมต่อใหม่",control:"เปิด Client ที่เลือกแบบความละเอียดเต็ม และส่งเมาส์กับคีย์บอร์ดผ่าน session ของ Hub ที่มีอยู่","share-files":"เรียกดูไฟล์บน Hub ส่งไปยัง Client ที่เลือก และจัดการโฟลเดอร์แชร์กับความคืบหน้าการโอน",agents:"Codex Agent บน Hub เรียกใช้คำสั่งบน Client ที่เชื่อมต่อภายใต้สิทธิ์และการอนุมัติของ VuvoDesk"},hi:{hub:"इस कंप्यूटर को VuvoDesk Hub के रूप में उपयोग करें। Hub, Client कनेक्शन, Wall, Control, फ़ाइल और Agents का एकीकृत नियंत्रण केंद्र है; नेटवर्क बदलने के बाद सुरक्षित पहुँच ताज़ा करने के लिए इसे दबाएँ।","switch-to-hub":"इस कंप्यूटर को Client से Hub में बदलता है। VuvoDesk नई भूमिका सहेजता है, उसी desktop runtime को restart करके Wall खोलता है और Client sharing रोक देता है।",client:"इस कंप्यूटर को Client मोड में रखता है ताकि इसकी स्क्रीन, फ़ाइलें, ऑडियो और remote control सक्रिय Hub पर उपलब्ध रहें।",wall:"सभी जुड़े Clients के live thumbnail दिखाता है। स्क्रीन और tile आकार चुनें या नया connection खोले बिना Control में जाएँ।",control:"चुने हुए Client को पूर्ण resolution में खोलता है और मौजूदा Hub session से mouse तथा keyboard input भेजता है।","share-files":"Hub की फ़ाइलें देखें, चुने हुए Clients को भेजें और shared folders तथा transfer progress प्रबंधित करें।",agents:"Hub का Codex Agent VuvoDesk permissions और approvals के भीतर जुड़े Clients पर commands चलाता है।"},ar:{hub:"استخدم هذا الكمبيوتر بوصفه VuvoDesk Hub. يمثّل Hub مركز التحكم الموحّد لاتصالات Client وWall وControl والملفات وAgents؛ اضغط عليه بعد تغييرات الشبكة لتحديث الوصول الآمن.","switch-to-hub":"يحوّل هذا الكمبيوتر من Client إلى Hub. يحفظ VuvoDesk الدور الجديد ويعيد تشغيل بيئة سطح المكتب نفسها ويفتح Wall، ويتوقف الجهاز عن المشاركة كـ Client.",client:"يبقي هذا الكمبيوتر في وضع Client لتظل شاشاته وملفاته وصوته والتحكم عن بعد متاحة من Hub النشط.",wall:"يعرض صورا حية مصغرة لكل Clients المتصلين. اختر الشاشة وحجم البلاطات أو انتقل إلى Control من دون اتصال جديد.",control:"يفتح Client المحدد بالدقة الكاملة ويرسل إدخال الماوس ولوحة المفاتيح عبر جلسة Hub الحالية.","share-files":"استعرض ملفات Hub وأرسلها إلى Clients المحددين وأدر المجلدات المشتركة وتقدم النقل.",agents:"يشغّل Codex Agent على Hub الأوامر في Clients المتصلين ضمن صلاحيات وموافقات VuvoDesk."},tr:{hub:"Bu bilgisayarı VuvoDesk Hub olarak kullanır. Hub; Client bağlantıları, Wall, Control, dosyalar ve Agents için birleşik kontrol merkezidir; ağ değişikliklerinden sonra güvenli erişimi yenilemek için basın.","switch-to-hub":"Bu bilgisayarı Client rolünden Hub rolüne geçirir. VuvoDesk yeni rolü kaydeder, aynı masaüstü runtime’ını yeniden başlatıp Wall’u açar; Client paylaşımı durur.",client:"Bu bilgisayarı Client modunda tutar; ekran, dosya, ses ve uzaktan kontrol özellikleri etkin Hub tarafından kullanılabilir kalır.",wall:"Bağlı tüm Client ekranlarının canlı küçük görüntülerini gösterir. Ekran ve kutu boyutunu seçin veya yeni bağlantı açmadan Control’e geçin.",control:"Seçili Client’ı tam çözünürlükte açar ve mevcut Hub oturumu üzerinden fare ile klavye girdisi gönderir.","share-files":"Hub dosyalarını gezin, seçili Client’lara gönderin ve paylaşılan klasörlerle aktarım ilerlemesini yönetin.",agents:"Hub Codex Agent, bağlı Client’larda VuvoDesk izinleri ve onayları kapsamında komut çalıştırır."}};function Vd(e){const t=e?[e]:typeof navigator>"u"?["en"]:navigator.languages?.length?navigator.languages:[navigator.language];for(const a of t){const r=String(a||"").trim(),c=r.toLowerCase();if(!c)continue;if(c.startsWith("zh-tw")||c.startsWith("zh-hk"))return"zh-TW";if(c.startsWith("zh"))return"zh";if(c.startsWith("pt"))return"pt-BR";const u=c.split("-")[0];if(Md[r])return r;if(Md[u])return u}return"en"}function og(e,t){const a=Vd(t);return Md[a]?.[e]||ag[e]}function Vy(e,t,a){return`${e}
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/AgentsPage-DcUy7xPU.js","assets/styles-eZ2IzXEL.js","assets/icons-CacEbnZu.js","assets/react-Cfedt3N5.js","assets/styles-DDKP4MTD.css","assets/AgentsPage-D29gvPcH.css","assets/ShareFilesPage-C9vhKzGp.js","assets/ShareFilesPage-BCCMoGKE.css","assets/SupportPage-C-uQ-RTX.js","assets/supabase-C7qjtLN3.js","assets/frame-lifecycle-esOdP-EY.js","assets/SupportPage-Cxx61WwR.css","assets/SettingsPage-ChNfBaQo.js","assets/SettingsTabs-B-uMhvwn.js","assets/AgentSettingsTab-CU3kHssT.js","assets/DesktopUpdatePanel-C5wDB5zf.js","assets/CaptureGallery-BPKKxPej.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{D as Tn,k as Jv,l as gl,i as wi,h as Ue,o as Zv,e as ks,q as ey,u as As,v as Is,_ as mr,x as Yh,y as ty,z as ny,j as i,p as $e,A as Qh,B as ry,C as Zp,E as ay,G as _u,g as oy,T as ef,b as ju,a as ds,F as Bu,M as tf,f as Hu,H as iy,L as sy}from"./styles-eZ2IzXEL.js";import{a as s,am as cy,an as nf,p as ly,ao as uy,ap as dy,ae as kl,X as xa,U as Ts,aq as Xh,c as Aa,l as bl,ac as Ra,ar as my,as as py,at as fy,au as hy,k as wo,av as Jh,g as Ci,aw as gy,ax as by,b as Cn,y as vy,ay as Zh,f as Ms,a0 as eg,T as vl,aa as kd,ab as yy,ad as rf,a9 as wy,az as Sy,D as af,O as Cy,N as ky,A as My,E as xy,aA as of,W as tg,aB as Wu,Z as Ry,a2 as $u,x as Ay,aC as sf,aD as Iy,aE as ng,C as rg,n as ms,aF as Ty,aG as Py,t as Ey,aH as Ny,a4 as Fy,G as Dy,Q as Ly}from"./icons-CacEbnZu.js";import{c as Oy}from"./supabase-C7qjtLN3.js";import{c as _y,a as jy,f as Vu,b as By,r as zu,t as Uu,d as cf,e as Hy,i as lf,g as Wy,h as On,j as wa,s as dn,k as ho,l as qu,m as Gu,n as Ku,o as $y,p as el,q as uf,u as tl,v as df}from"./frame-lifecycle-esOdP-EY.js";const ag={hub:"Use this computer as Hub. Hub connects to and manages Client computers.","switch-to-hub":"Switch this computer from Client to Hub. It will manage Client computers instead of sharing its own screen.",client:"Keep this computer in Client mode so its screens, files, audio, and remote controls remain available to the active Hub.",wall:"Show live thumbnails from every connected Client. Choose a display, change tile size, or move into Control without opening another connection.",control:"Open the selected Client at full resolution and send mouse and keyboard input through the existing Hub session.","share-files":"Browse files on the Hub, send files to selected Clients, and manage shared folders and transfer progress.",agents:"Run approved commands on connected Clients through the Hub-hosted Codex Agent and VuvoDesk permission controls."},Md={en:ag,ko:{hub:"이 컴퓨터를 Hub로 사용합니다. Hub는 Client 컴퓨터를 연결하고 관리합니다.","switch-to-hub":"이 컴퓨터를 Client에서 Hub로 바꿉니다. 자신의 화면 공유를 멈추고 Client 컴퓨터를 관리합니다.",client:"이 컴퓨터를 Client 모드로 유지합니다. 화면, 파일, 오디오와 원격 제어 기능이 활성 Hub에서 계속 사용 가능하도록 연결합니다.",wall:"연결된 모든 Client의 실시간 화면을 한곳에 표시합니다. 모니터와 타일 크기를 선택하고 새 연결 없이 Control로 이동할 수 있습니다.",control:"선택한 Client 화면을 전체 해상도로 열고 기존 Hub 세션을 통해 마우스와 키보드 입력을 전송합니다.","share-files":"Hub의 파일을 탐색하고 선택한 Client로 전송하며 공유 폴더와 전송 진행 상태를 관리합니다.",agents:"Hub의 Codex가 연결된 Client에서 VuvoDesk 권한과 승인 범위 안의 명령을 실행합니다."},ja:{hub:"このコンピューターを VuvoDesk Hub として運用します。Hub は Client 接続、Wall、Control、ファイル共有、Agents を一か所で管理する統合コントロールセンターで、ネットワーク変更後に押すと安全な接続情報も更新します。","switch-to-hub":"このコンピューターを Client から Hub に切り替えます。新しい役割を保存して同じデスクトップランタイムを再起動し、Wall を開きます。Client としての共有は停止します。",client:"このコンピューターを Client モードで維持し、画面、ファイル、音声、リモート操作をアクティブ Hub から利用できるようにします。",wall:"接続中のすべての Client のライブ画面を一覧表示します。ディスプレイやタイルサイズを選び、新しい接続なしで Control に移動できます。",control:"選択した Client をフル解像度で開き、既存の Hub セッションからマウスとキーボード入力を送信します。","share-files":"Hub のファイルを参照し、選択した Client への送信、共有フォルダー、転送状況を管理します。",agents:"Hub の Codex Agent が、VuvoDesk の権限と承認の範囲内で接続中の Client にコマンドを実行します。"},zh:{hub:"将此电脑作为 VuvoDesk Hub 运行。Hub 是统一控制中心,可集中管理 Client 连接、Wall、Control、文件共享和 Agents;网络变化后按下此按钮还会刷新安全连接信息。","switch-to-hub":"将此电脑从 Client 切换为 Hub。VuvoDesk 保存新角色、重启同一桌面运行时并打开 Wall;此电脑将停止作为 Client 共享。",client:"让此电脑保持 Client 模式,使活动 Hub 可以继续使用它的屏幕、文件、音频和远程控制。",wall:"集中显示所有已连接 Client 的实时缩略图。可以选择显示器、调整磁贴大小,并在不新建连接的情况下进入 Control。",control:"以完整分辨率打开所选 Client,并通过现有 Hub 会话发送鼠标和键盘输入。","share-files":"浏览 Hub 文件、向所选 Client 发送文件,并管理共享文件夹和传输进度。",agents:"Hub 的 Codex Agent 会在 VuvoDesk 权限与批准范围内,对已连接的 Client 执行命令。"},"zh-TW":{hub:"將此電腦作為 VuvoDesk Hub 運作。Hub 是統一控制中心,可集中管理 Client 連線、Wall、Control、檔案分享與 Agents;網路變更後按下此按鈕也會更新安全連線資訊。","switch-to-hub":"將此電腦從 Client 切換為 Hub。VuvoDesk 會儲存新角色、重新啟動同一桌面執行階段並開啟 Wall;此電腦將停止以 Client 身分共享。",client:"讓此電腦維持 Client 模式,使作用中 Hub 可繼續使用它的畫面、檔案、音訊與遠端控制。",wall:"集中顯示所有已連線 Client 的即時縮圖。可選擇顯示器、調整圖塊大小,並在不建立新連線的情況下進入 Control。",control:"以完整解析度開啟所選 Client,並透過現有 Hub 工作階段傳送滑鼠與鍵盤輸入。","share-files":"瀏覽 Hub 檔案、傳送檔案到所選 Client,並管理共享資料夾與傳輸進度。",agents:"Hub 的 Codex Agent 會在 VuvoDesk 權限與核准範圍內,對已連線的 Client 執行命令。"},es:{hub:"Usa este equipo como VuvoDesk Hub. Hub es el centro de control unificado para conexiones Client, Wall, Control, archivos y Agents; púlsalo tras cambios de red para actualizar el acceso seguro.","switch-to-hub":"Cambia este equipo de Client a Hub. VuvoDesk guarda el nuevo rol, reinicia el mismo entorno de escritorio y abre Wall; el equipo deja de compartirse como Client.",client:"Mantiene este equipo en modo Client para que sus pantallas, archivos, audio y control remoto sigan disponibles desde el Hub activo.",wall:"Muestra miniaturas en vivo de todos los Clients conectados. Elige pantalla y tamaño, o entra en Control sin abrir otra conexión.",control:"Abre el Client seleccionado a resolución completa y envía ratón y teclado por la sesión Hub existente.","share-files":"Explora archivos del Hub, envíalos a los Clients seleccionados y administra carpetas compartidas y transferencias.",agents:"El Codex Agent del Hub ejecuta comandos en los Clients conectados dentro de los permisos y aprobaciones de VuvoDesk."},fr:{hub:"Utilise cet ordinateur comme VuvoDesk Hub. Hub est le centre de contrôle unifié des connexions Client, de Wall, Control, des fichiers et des Agents ; appuyez après un changement réseau pour actualiser l’accès sécurisé.","switch-to-hub":"Bascule cet ordinateur de Client vers Hub. VuvoDesk enregistre le nouveau rôle, redémarre le même environnement de bureau et ouvre Wall ; le partage Client s’arrête.",client:"Maintient cet ordinateur en mode Client afin que ses écrans, fichiers, sons et commandes à distance restent disponibles depuis le Hub actif.",wall:"Affiche les miniatures en direct de tous les Clients connectés. Choisissez l’écran et la taille, ou passez à Control sans nouvelle connexion.",control:"Ouvre le Client sélectionné en pleine résolution et transmet souris et clavier via la session Hub existante.","share-files":"Parcourez les fichiers du Hub, envoyez-les aux Clients sélectionnés et gérez dossiers partagés et transferts.",agents:"Le Codex Agent du Hub exécute des commandes sur les Clients connectés selon les permissions et approbations de VuvoDesk."},de:{hub:"Verwendet diesen Computer als VuvoDesk Hub. Hub ist die gemeinsame Steuerzentrale für Client-Verbindungen, Wall, Control, Dateien und Agents; nach Netzwerkänderungen aktualisiert ein Klick den sicheren Zugriff.","switch-to-hub":"Wechselt diesen Computer von Client zu Hub. VuvoDesk speichert die neue Rolle, startet dieselbe Desktop-Laufzeit neu und öffnet Wall; die Client-Freigabe endet.",client:"Hält diesen Computer im Client-Modus, damit Bildschirme, Dateien, Audio und Fernsteuerung am aktiven Hub verfügbar bleiben.",wall:"Zeigt Live-Vorschaubilder aller verbundenen Clients. Display und Kachelgröße wählen oder ohne neue Verbindung zu Control wechseln.",control:"Öffnet den gewählten Client in voller Auflösung und sendet Maus- und Tastatureingaben über die bestehende Hub-Sitzung.","share-files":"Dateien auf dem Hub durchsuchen, an gewählte Clients senden sowie Freigaben und Übertragungen verwalten.",agents:"Der Codex Agent des Hubs führt Befehle auf verbundenen Clients innerhalb der VuvoDesk-Berechtigungen und Freigaben aus."},"pt-BR":{hub:"Usa este computador como VuvoDesk Hub. Hub é o centro de controle unificado para conexões Client, Wall, Control, arquivos e Agents; após mudanças de rede, pressione para atualizar o acesso seguro.","switch-to-hub":"Muda este computador de Client para Hub. O VuvoDesk salva a nova função, reinicia o mesmo runtime de desktop e abre o Wall; o compartilhamento como Client é encerrado.",client:"Mantém este computador no modo Client para que telas, arquivos, áudio e controle remoto continuem disponíveis no Hub ativo.",wall:"Mostra miniaturas ao vivo de todos os Clients conectados. Escolha a tela e o tamanho ou entre em Control sem criar outra conexão.",control:"Abre o Client selecionado em resolução total e envia mouse e teclado pela sessão Hub existente.","share-files":"Navegue pelos arquivos do Hub, envie para Clients selecionados e gerencie pastas compartilhadas e transferências.",agents:"O Codex Agent do Hub executa comandos nos Clients conectados dentro das permissões e aprovações do VuvoDesk."},it:{hub:"Usa questo computer come VuvoDesk Hub. Hub è il centro di controllo unificato per connessioni Client, Wall, Control, file e Agents; dopo modifiche di rete, premilo per aggiornare l’accesso sicuro.","switch-to-hub":"Passa questo computer da Client a Hub. VuvoDesk salva il nuovo ruolo, riavvia lo stesso runtime desktop e apre Wall; la condivisione come Client termina.",client:"Mantiene questo computer in modalità Client, rendendo schermi, file, audio e controllo remoto disponibili all’Hub attivo.",wall:"Mostra le anteprime live di tutti i Client connessi. Scegli display e dimensione oppure passa a Control senza una nuova connessione.",control:"Apre il Client selezionato a piena risoluzione e invia mouse e tastiera tramite la sessione Hub esistente.","share-files":"Esplora i file dell’Hub, inviali ai Client selezionati e gestisci cartelle condivise e trasferimenti.",agents:"Il Codex Agent dell’Hub esegue comandi sui Client connessi entro i permessi e le approvazioni di VuvoDesk."},id:{hub:"Gunakan komputer ini sebagai VuvoDesk Hub. Hub adalah pusat kendali terpadu untuk koneksi Client, Wall, Control, file, dan Agents; tekan setelah perubahan jaringan untuk memperbarui akses aman.","switch-to-hub":"Alihkan komputer ini dari Client menjadi Hub. VuvoDesk menyimpan peran baru, memulai ulang runtime desktop yang sama, lalu membuka Wall; berbagi sebagai Client berhenti.",client:"Pertahankan komputer ini dalam mode Client agar layar, file, audio, dan kendali jarak jauh tetap tersedia bagi Hub aktif.",wall:"Tampilkan thumbnail live semua Client yang terhubung. Pilih layar dan ukuran tile atau masuk ke Control tanpa koneksi baru.",control:"Buka Client terpilih pada resolusi penuh dan kirim input mouse serta keyboard melalui sesi Hub yang ada.","share-files":"Jelajahi file Hub, kirim ke Client terpilih, serta kelola folder bersama dan progres transfer.",agents:"Codex Agent di Hub menjalankan perintah pada Client terhubung sesuai izin dan persetujuan VuvoDesk."},vi:{hub:"Dùng máy tính này làm VuvoDesk Hub. Hub là trung tâm điều khiển hợp nhất cho kết nối Client, Wall, Control, tệp và Agents; nhấn sau khi đổi mạng để làm mới quyền truy cập an toàn.","switch-to-hub":"Chuyển máy tính này từ Client sang Hub. VuvoDesk lưu vai trò mới, khởi động lại cùng môi trường desktop và mở Wall; việc chia sẻ dưới dạng Client sẽ dừng.",client:"Giữ máy tính này ở chế độ Client để màn hình, tệp, âm thanh và điều khiển từ xa luôn sẵn sàng cho Hub đang hoạt động.",wall:"Hiển thị ảnh thu nhỏ trực tiếp của mọi Client đã kết nối. Chọn màn hình, cỡ ô hoặc vào Control mà không tạo kết nối mới.",control:"Mở Client đã chọn ở độ phân giải đầy đủ và gửi chuột, bàn phím qua phiên Hub hiện có.","share-files":"Duyệt tệp trên Hub, gửi tới Client đã chọn và quản lý thư mục chia sẻ cùng tiến trình truyền.",agents:"Codex Agent trên Hub chạy lệnh trên các Client đã kết nối trong phạm vi quyền và phê duyệt của VuvoDesk."},th:{hub:"ใช้คอมพิวเตอร์เครื่องนี้เป็น VuvoDesk Hub โดย Hub คือศูนย์ควบคุมรวมสำหรับการเชื่อมต่อ Client, Wall, Control, ไฟล์ และ Agents และกดหลังเปลี่ยนเครือข่ายเพื่อรีเฟรชการเข้าถึงที่ปลอดภัย","switch-to-hub":"เปลี่ยนคอมพิวเตอร์นี้จาก Client เป็น Hub โดย VuvoDesk จะบันทึกบทบาทใหม่ รีสตาร์ต desktop runtime เดิม และเปิด Wall พร้อมหยุดแชร์ในฐานะ Client",client:"ให้คอมพิวเตอร์นี้อยู่ในโหมด Client เพื่อให้ Hub ที่ใช้งานเข้าถึงหน้าจอ ไฟล์ เสียง และการควบคุมระยะไกลได้ต่อเนื่อง",wall:"แสดงภาพสดแบบย่อของ Client ที่เชื่อมต่อทั้งหมด เลือกจอและขนาด tile หรือเข้า Control ได้โดยไม่เปิดการเชื่อมต่อใหม่",control:"เปิด Client ที่เลือกแบบความละเอียดเต็ม และส่งเมาส์กับคีย์บอร์ดผ่าน session ของ Hub ที่มีอยู่","share-files":"เรียกดูไฟล์บน Hub ส่งไปยัง Client ที่เลือก และจัดการโฟลเดอร์แชร์กับความคืบหน้าการโอน",agents:"Codex Agent บน Hub เรียกใช้คำสั่งบน Client ที่เชื่อมต่อภายใต้สิทธิ์และการอนุมัติของ VuvoDesk"},hi:{hub:"इस कंप्यूटर को VuvoDesk Hub के रूप में उपयोग करें। Hub, Client कनेक्शन, Wall, Control, फ़ाइल और Agents का एकीकृत नियंत्रण केंद्र है; नेटवर्क बदलने के बाद सुरक्षित पहुँच ताज़ा करने के लिए इसे दबाएँ।","switch-to-hub":"इस कंप्यूटर को Client से Hub में बदलता है। VuvoDesk नई भूमिका सहेजता है, उसी desktop runtime को restart करके Wall खोलता है और Client sharing रोक देता है।",client:"इस कंप्यूटर को Client मोड में रखता है ताकि इसकी स्क्रीन, फ़ाइलें, ऑडियो और remote control सक्रिय Hub पर उपलब्ध रहें।",wall:"सभी जुड़े Clients के live thumbnail दिखाता है। स्क्रीन और tile आकार चुनें या नया connection खोले बिना Control में जाएँ।",control:"चुने हुए Client को पूर्ण resolution में खोलता है और मौजूदा Hub session से mouse तथा keyboard input भेजता है।","share-files":"Hub की फ़ाइलें देखें, चुने हुए Clients को भेजें और shared folders तथा transfer progress प्रबंधित करें।",agents:"Hub का Codex Agent VuvoDesk permissions और approvals के भीतर जुड़े Clients पर commands चलाता है।"},ar:{hub:"استخدم هذا الكمبيوتر بوصفه VuvoDesk Hub. يمثّل Hub مركز التحكم الموحّد لاتصالات Client وWall وControl والملفات وAgents؛ اضغط عليه بعد تغييرات الشبكة لتحديث الوصول الآمن.","switch-to-hub":"يحوّل هذا الكمبيوتر من Client إلى Hub. يحفظ VuvoDesk الدور الجديد ويعيد تشغيل بيئة سطح المكتب نفسها ويفتح Wall، ويتوقف الجهاز عن المشاركة كـ Client.",client:"يبقي هذا الكمبيوتر في وضع Client لتظل شاشاته وملفاته وصوته والتحكم عن بعد متاحة من Hub النشط.",wall:"يعرض صورا حية مصغرة لكل Clients المتصلين. اختر الشاشة وحجم البلاطات أو انتقل إلى Control من دون اتصال جديد.",control:"يفتح Client المحدد بالدقة الكاملة ويرسل إدخال الماوس ولوحة المفاتيح عبر جلسة Hub الحالية.","share-files":"استعرض ملفات Hub وأرسلها إلى Clients المحددين وأدر المجلدات المشتركة وتقدم النقل.",agents:"يشغّل Codex Agent على Hub الأوامر في Clients المتصلين ضمن صلاحيات وموافقات VuvoDesk."},tr:{hub:"Bu bilgisayarı VuvoDesk Hub olarak kullanır. Hub; Client bağlantıları, Wall, Control, dosyalar ve Agents için birleşik kontrol merkezidir; ağ değişikliklerinden sonra güvenli erişimi yenilemek için basın.","switch-to-hub":"Bu bilgisayarı Client rolünden Hub rolüne geçirir. VuvoDesk yeni rolü kaydeder, aynı masaüstü runtime’ını yeniden başlatıp Wall’u açar; Client paylaşımı durur.",client:"Bu bilgisayarı Client modunda tutar; ekran, dosya, ses ve uzaktan kontrol özellikleri etkin Hub tarafından kullanılabilir kalır.",wall:"Bağlı tüm Client ekranlarının canlı küçük görüntülerini gösterir. Ekran ve kutu boyutunu seçin veya yeni bağlantı açmadan Control’e geçin.",control:"Seçili Client’ı tam çözünürlükte açar ve mevcut Hub oturumu üzerinden fare ile klavye girdisi gönderir.","share-files":"Hub dosyalarını gezin, seçili Client’lara gönderin ve paylaşılan klasörlerle aktarım ilerlemesini yönetin.",agents:"Hub Codex Agent, bağlı Client’larda VuvoDesk izinleri ve onayları kapsamında komut çalıştırır."}};function Vd(e){const t=e?[e]:typeof navigator>"u"?["en"]:navigator.languages?.length?navigator.languages:[navigator.language];for(const a of t){const r=String(a||"").trim(),c=r.toLowerCase();if(!c)continue;if(c.startsWith("zh-tw")||c.startsWith("zh-hk"))return"zh-TW";if(c.startsWith("zh"))return"zh";if(c.startsWith("pt"))return"pt-BR";const u=c.split("-")[0];if(Md[r])return r;if(Md[u])return u}return"en"}function og(e,t){const a=Vd(t);return Md[a]?.[e]||ag[e]}function Vy(e,t,a){return`${e}
|
|
3
3
|
${og(t,a)}`}const ig={eyebrow:"Change computer role",title:"Switch this computer to Hub?",description:"VuvoDesk will stop sharing this computer as a Client, save the Hub role, restart the local runtime, and open Wall in this same window.",restartNotice:"Remote streams from this computer will end while VuvoDesk restarts.",cancel:"Cancel",confirm:"Switch to Hub",closeLabel:"Close Hub switch confirmation"},zy={en:ig,ko:{eyebrow:"컴퓨터 역할 변경",title:"이 컴퓨터를 Hub로 전환하시겠습니까?",description:"이 컴퓨터의 Client 공유를 중지하고 Hub 역할을 저장한 뒤 로컬 런타임을 재시작하여 같은 창에서 Wall을 엽니다.",restartNotice:"VuvoDesk가 재시작되는 동안 이 컴퓨터의 원격 스트림이 종료됩니다.",cancel:"취소",confirm:"Hub로 전환",closeLabel:"Hub 전환 확인 닫기"},ja:{eyebrow:"コンピューターの役割を変更",title:"このコンピューターを Hub に切り替えますか?",description:"このコンピューターの Client 共有を停止し、Hub の役割を保存してローカルランタイムを再起動し、同じウィンドウで Wall を開きます。",restartNotice:"VuvoDesk の再起動中、このコンピューターのリモートストリームは終了します。",cancel:"キャンセル",confirm:"Hub に切り替える",closeLabel:"Hub 切り替え確認を閉じる"},zh:{eyebrow:"更改电脑角色",title:"将此电脑切换为 Hub?",description:"VuvoDesk 将停止此电脑的 Client 共享,保存 Hub 角色,重启本地运行时,并在同一窗口中打开 Wall。",restartNotice:"VuvoDesk 重启期间,此电脑的远程流将会结束。",cancel:"取消",confirm:"切换为 Hub",closeLabel:"关闭 Hub 切换确认"},"zh-TW":{eyebrow:"變更電腦角色",title:"要將此電腦切換為 Hub 嗎?",description:"VuvoDesk 將停止此電腦的 Client 分享、儲存 Hub 角色、重新啟動本機執行階段,並在同一視窗中開啟 Wall。",restartNotice:"VuvoDesk 重新啟動期間,此電腦的遠端串流將會結束。",cancel:"取消",confirm:"切換為 Hub",closeLabel:"關閉 Hub 切換確認"},es:{eyebrow:"Cambiar función del equipo",title:"¿Cambiar este equipo a Hub?",description:"VuvoDesk dejará de compartir este equipo como Client, guardará la función Hub, reiniciará el entorno local y abrirá Wall en esta misma ventana.",restartNotice:"Los streams remotos de este equipo terminarán mientras VuvoDesk se reinicia.",cancel:"Cancelar",confirm:"Cambiar a Hub",closeLabel:"Cerrar confirmación de cambio a Hub"},fr:{eyebrow:"Changer le rôle de l’ordinateur",title:"Basculer cet ordinateur vers Hub ?",description:"VuvoDesk arrêtera le partage Client de cet ordinateur, enregistrera le rôle Hub, redémarrera le runtime local et ouvrira Wall dans cette même fenêtre.",restartNotice:"Les flux distants de cet ordinateur prendront fin pendant le redémarrage de VuvoDesk.",cancel:"Annuler",confirm:"Basculer vers Hub",closeLabel:"Fermer la confirmation de bascule vers Hub"},de:{eyebrow:"Computerrolle ändern",title:"Diesen Computer auf Hub umstellen?",description:"VuvoDesk beendet die Client-Freigabe dieses Computers, speichert die Hub-Rolle, startet die lokale Laufzeit neu und öffnet Wall im selben Fenster.",restartNotice:"Die Remote-Streams dieses Computers enden während des VuvoDesk-Neustarts.",cancel:"Abbrechen",confirm:"Auf Hub umstellen",closeLabel:"Bestätigung für Hub-Wechsel schließen"},"pt-BR":{eyebrow:"Alterar função do computador",title:"Mudar este computador para Hub?",description:"O VuvoDesk interromperá o compartilhamento deste computador como Client, salvará a função Hub, reiniciará o runtime local e abrirá o Wall nesta mesma janela.",restartNotice:"Os streams remotos deste computador serão encerrados enquanto o VuvoDesk reinicia.",cancel:"Cancelar",confirm:"Mudar para Hub",closeLabel:"Fechar confirmação de mudança para Hub"},it:{eyebrow:"Cambia ruolo del computer",title:"Passare questo computer a Hub?",description:"VuvoDesk interromperà la condivisione Client di questo computer, salverà il ruolo Hub, riavvierà il runtime locale e aprirà Wall nella stessa finestra.",restartNotice:"Gli stream remoti di questo computer termineranno durante il riavvio di VuvoDesk.",cancel:"Annulla",confirm:"Passa a Hub",closeLabel:"Chiudi la conferma del passaggio a Hub"},id:{eyebrow:"Ubah peran komputer",title:"Alihkan komputer ini menjadi Hub?",description:"VuvoDesk akan menghentikan berbagi komputer ini sebagai Client, menyimpan peran Hub, memulai ulang runtime lokal, lalu membuka Wall di jendela yang sama.",restartNotice:"Stream jarak jauh dari komputer ini akan berakhir saat VuvoDesk dimulai ulang.",cancel:"Batal",confirm:"Alihkan ke Hub",closeLabel:"Tutup konfirmasi peralihan Hub"},vi:{eyebrow:"Đổi vai trò máy tính",title:"Chuyển máy tính này thành Hub?",description:"VuvoDesk sẽ dừng chia sẻ máy tính này dưới dạng Client, lưu vai trò Hub, khởi động lại runtime cục bộ và mở Wall trong cùng cửa sổ.",restartNotice:"Các luồng từ xa của máy tính này sẽ kết thúc trong khi VuvoDesk khởi động lại.",cancel:"Hủy",confirm:"Chuyển sang Hub",closeLabel:"Đóng xác nhận chuyển sang Hub"},th:{eyebrow:"เปลี่ยนบทบาทคอมพิวเตอร์",title:"เปลี่ยนคอมพิวเตอร์เครื่องนี้เป็น Hub หรือไม่",description:"VuvoDesk จะหยุดแชร์คอมพิวเตอร์เครื่องนี้ในฐานะ Client บันทึกบทบาท Hub รีสตาร์ทรันไทม์ภายในเครื่อง และเปิด Wall ในหน้าต่างเดิม",restartNotice:"สตรีมระยะไกลจากคอมพิวเตอร์เครื่องนี้จะสิ้นสุดลงระหว่างที่ VuvoDesk รีสตาร์ท",cancel:"ยกเลิก",confirm:"เปลี่ยนเป็น Hub",closeLabel:"ปิดการยืนยันการเปลี่ยนเป็น Hub"},hi:{eyebrow:"कंप्यूटर की भूमिका बदलें",title:"इस कंप्यूटर को Hub में बदलें?",description:"VuvoDesk इस कंप्यूटर की Client साझेदारी बंद करेगा, Hub भूमिका सहेजेगा, स्थानीय रनटाइम पुनः आरंभ करेगा और इसी विंडो में Wall खोलेगा।",restartNotice:"VuvoDesk के पुनः आरंभ होने के दौरान इस कंप्यूटर की रिमोट स्ट्रीम समाप्त हो जाएँगी।",cancel:"रद्द करें",confirm:"Hub में बदलें",closeLabel:"Hub परिवर्तन की पुष्टि बंद करें"},ar:{eyebrow:"تغيير دور الكمبيوتر",title:"هل تريد تحويل هذا الكمبيوتر إلى Hub؟",description:"سيوقف VuvoDesk مشاركة هذا الكمبيوتر كـ Client، ويحفظ دور Hub، ويعيد تشغيل وقت التشغيل المحلي، ثم يفتح Wall في النافذة نفسها.",restartNotice:"ستنتهي التدفقات البعيدة من هذا الكمبيوتر أثناء إعادة تشغيل VuvoDesk.",cancel:"إلغاء",confirm:"التحويل إلى Hub",closeLabel:"إغلاق تأكيد التحويل إلى Hub"},tr:{eyebrow:"Bilgisayar rolünü değiştir",title:"Bu bilgisayar Hub rolüne geçirilsin mi?",description:"VuvoDesk bu bilgisayarın Client paylaşımını durdurur, Hub rolünü kaydeder, yerel çalışma zamanını yeniden başlatır ve Wall’u aynı pencerede açar.",restartNotice:"VuvoDesk yeniden başlatılırken bu bilgisayarın uzak akışları sona erer.",cancel:"İptal",confirm:"Hub’a geçir",closeLabel:"Hub geçişi onayını kapat"}},sg={eyebrow:"Computer role",title:"Use this computer as Hub?",description:"Hub connects to and manages Client computers.",restartNotice:"If another computer is Hub, this computer will become the new Hub.",cancel:"Cancel",confirm:"Use as Hub",closeLabel:"Close Hub confirmation"},Uy={en:sg,ko:{eyebrow:"컴퓨터 역할",title:"이 컴퓨터를 Hub로 사용할까요?",description:"Hub는 Client 컴퓨터를 연결하고 관리합니다.",restartNotice:"다른 컴퓨터가 Hub라면 이 컴퓨터가 새 Hub가 됩니다.",cancel:"취소",confirm:"Hub로 설정",closeLabel:"Hub 설정 확인 닫기"}};function dx(e){const t=Vd(e);return zy[t]||ig}function qy(e){const t=Vd(e);return Uy[t]||sg}const Gy="https://otbyfkjxrkngvjziawki.supabase.co",Ky="sb_publishable_NpUs0RDJH2YnllsqTKO6TQ_1jTdSsNQ",Yy={getItem:()=>null,setItem:()=>{},removeItem:()=>{}},Yu=typeof window<"u"&&!!window.liveDesk,Mt=Oy(Gy,Ky,{auth:{autoRefreshToken:!Yu,persistSession:!Yu,storage:Yu?Yy:void 0,detectSessionInUrl:!0,flowType:"pkce",storageKey:"livedesk.mindexec.supabase.auth"}});function Qy({eligibleCandidates:e,fallbackHubBaseUrl:t,publicConsole:a,authenticated:r}){const c=String(t||"").trim();if(a&&r&&c)return Object.freeze({candidates:Object.freeze([c]),transport:"p2p",reason:"authenticated-public-console-p2p"});const u=[...new Set((Array.isArray(e)?e:[]).map(p=>String(p||"").trim()).filter(Boolean))];return u.length>0?Object.freeze({candidates:Object.freeze(u),transport:"auto",reason:"direct-candidate"}):Object.freeze({candidates:Object.freeze([]),transport:"auto",reason:"unavailable"})}function Xy({expectedWorkspaceId:e,expectedWorkspaceKind:t,verifiedPublicDirect:a,statusWorkspace:r}){const c=String(e||"").trim(),u=String(t||"").trim().toLowerCase();if(!c)return!0;const p=String(r?.workspaceId||"").trim(),h=String(r?.kind||"").trim().toLowerCase();return p?p===c&&h===u:a===!0&&u==="personal"}function Qu(e,t){const a=e?.hasSnapshot===!0;switch(t){case"reset-idle":return Object.freeze({phase:"idle",hasSnapshot:!1});case"reset-enabled":return Object.freeze({phase:"connecting",hasSnapshot:!1});case"success":return Object.freeze({phase:"online",hasSnapshot:!0});case"failure":return Object.freeze({phase:a?"reconnecting":"unavailable",hasSnapshot:a});case"retry":return Object.freeze({phase:a?"reconnecting":"connecting",hasSnapshot:a});default:throw new Error(`Unknown Hub snapshot connection event: ${String(t||"")}`)}}function Jy({authLoading:e,phase:t,recoveryOverlayEligible:a=!1}){const r=String(t||"idle"),c=r==="reconnecting",u=c&&a===!0;return Object.freeze({statusVisible:e!==!0&&r!=="connecting"&&(!c||!u),recoveryVisible:u})}const Zy=Object.freeze([50,100,250,600,1e3,2e3,4e3]);function ew(e={}){const t=typeof e.readVisible=="function"?e.readVisible:()=>document.visibilityState==="visible",a=typeof e.commitVisibility=="function"?e.commitVisibility:()=>{},r=typeof e.schedule=="function"?e.schedule:(ie,J)=>setTimeout(ie,J),c=typeof e.cancel=="function"?e.cancel:ie=>clearTimeout(ie),u=Array.isArray(e.recheckDelaysMs)&&e.recheckDelaysMs.length>0?e.recheckDelaysMs.map(ie=>Math.max(1,Math.floor(Number(ie)||1))):Zy;let p=!1,h=0,f=!1,k=null,M=0,b=0,T=Object.prototype.hasOwnProperty.call(e,"initialCommittedVisible")?e.initialCommittedVisible===!0:!!t();const A=()=>{k!==null&&(c(k),k=null)},x=ie=>{const J=ie===!0;return T===J?!1:(T=J,a(J),!0)},E=ie=>{h+=1,f=!1,M=0,A(),x(ie)},B=ie=>{if(p||!f||ie!==h)return!1;if(M>=u.length)return f=!1,M=0,!1;const J=u[M];M+=1;const de=r(()=>{if(k===de&&(k=null,!(p||!f||ie!==h))){if(b+=1,t()){E(!0);return}B(ie)}},J);return k=de,!0};return Object.freeze({handleForegroundHint:()=>{if(p)return!1;if(t())return E(!0),!0;if(x(!1),f)return!1;f=!0,M=0;const ie=h+1;return h=ie,B(ie),!1},handlePageHide:()=>{p||E(!1)},handleVisibilityChange:()=>{if(p)return!1;const ie=!!t();return E(ie),ie},dispose:()=>{p||(p=!0,h+=1,f=!1,M=0,A())},inspect:()=>Object.freeze({active:f,timerCount:k===null?0:1,runGeneration:h,checkCount:b,committedVisible:T})})}function ka(e,t,a){if(a<0||t<0||t+a>e.length)throw new Error("Invalid LZO1X block: input overrun.")}function Xu(e,t,a){let r=0;for(;ka(e,t.inputIndex,1),e[t.inputIndex]===0;)r+=1,t.inputIndex+=1;const c=r*255+a+e[t.inputIndex];return t.inputIndex+=1,c}function nl(e,t,a,r){if(ka(e,t.inputIndex,r),t.outputIndex+r>a.length)throw new Error("Invalid LZO1X block: output overrun.");a.set(e.subarray(t.inputIndex,t.inputIndex+r),t.outputIndex),t.inputIndex+=r,t.outputIndex+=r}function tw(e,t,a,r){const c=t-a;if(c<=0||r<=0)throw new Error("Invalid LZO1X block: invalid match distance.");let u=Math.min(c,r);for(e.set(e.subarray(a,a+u),t);u<r;){const p=Math.min(u,r-u);e.copyWithin(t+u,t,t+p),u+=p}return t+r}function cg(e,t){if(!(e instanceof Uint8Array)||e.length<3||t<0)throw new Error("Invalid LZO1X block.");const a=new Uint8Array(t),r={inputIndex:0,outputIndex:0};let c=0,u=0;if(e[r.inputIndex]>=22){const p=e[r.inputIndex]-17;r.inputIndex+=1,nl(e,r,a,p),c=4}else e[r.inputIndex]>=18&&(c=e[r.inputIndex]-17,r.inputIndex+=1,nl(e,r,a,c));for(;;){ka(e,r.inputIndex,1);const p=e[r.inputIndex];r.inputIndex+=1;let h,f;if((p&192)!==0)ka(e,r.inputIndex,1),f=r.outputIndex-((e[r.inputIndex]<<3)+(p>>2&7)+1),r.inputIndex+=1,u=(p>>5)+1,h=p&3;else if((p&32)!==0){u=(p&31)+2,u===2&&(u+=Xu(e,r,31)),ka(e,r.inputIndex,2);const k=e[r.inputIndex]|e[r.inputIndex+1]<<8;r.inputIndex+=2,f=r.outputIndex-((k>>2)+1),h=k&3}else if((p&16)!==0){u=(p&7)+2,u===2&&(u+=Xu(e,r,7)),ka(e,r.inputIndex,2);const k=e[r.inputIndex]|e[r.inputIndex+1]<<8;if(r.inputIndex+=2,f=r.outputIndex-(((p&8)<<11)+(k>>2)),h=k&3,f===r.outputIndex)break;f-=16384}else if(c===0){let k=p+3;k===3&&(k+=Xu(e,r,15)),nl(e,r,a,k),c=4;continue}else c!==4?(ka(e,r.inputIndex,1),h=p&3,f=r.outputIndex-((p>>2)+(e[r.inputIndex]<<2)+1),r.inputIndex+=1,u=2):(ka(e,r.inputIndex,1),h=p&3,f=r.outputIndex-((p>>2)+(e[r.inputIndex]<<2)+2049),r.inputIndex+=1,u=3);if(f<0||r.outputIndex+u+h>a.length)throw new Error("Invalid LZO1X block: lookbehind overrun.");r.outputIndex=tw(a,r.outputIndex,f,u),c=h,nl(e,r,a,h)}if(u!==3||r.inputIndex!==e.length||r.outputIndex!==a.length)throw new Error("Invalid LZO1X block: incomplete output.");return a}const mf=16,pf=8,nw=24*1024*1024,lg=new Uint8Array(new Uint32Array([16909060]).buffer)[0]===4,xd=new Uint32Array(65536);for(let e=0;e<xd.length;e+=1){const t=Math.round((e>>11&31)*255/31),a=Math.round((e>>5&63)*255/63),r=Math.round((e&31)*255/31);xd[e]=lg?(t|a<<8|r<<16|4278190080)>>>0:(t<<24|a<<16|r<<8|255)>>>0}function Sa(e,t){return e[t]|e[t+1]<<8}function rw(e,t){const a=Number(t);if(!Number.isSafeInteger(a)||a<mf||a>nw)throw new Error(`Invalid Mode 5 packet length: ${t}.`);const r=e instanceof Uint8Array?e:new Uint8Array(e),c=cg(r,a);if(c[0]!==76||c[1]!==68||c[2]!==53||c[3]!==68)throw new Error("Invalid Mode 5 packet magic.");if(c[4]!==1)throw new Error(`Unsupported Mode 5 packet version: ${c[4]}.`);const u=(c[5]&1)!==0,p=Sa(c,6),h=Sa(c,8),f=Sa(c,10),k=Sa(c,12);if(p<=0||h<=0||p>3840||h>2160)throw new Error(`Invalid Mode 5 frame size: ${p}x${h}.`);if(f<=0||f>256||k>8192)throw new Error(`Invalid Mode 5 tile header: ${f}/${k}.`);const M=[];let b=mf;for(let T=0;T<k;T+=1){if(b+pf>c.length)throw new Error("Mode 5 tile header is truncated.");const A=Sa(c,b),x=Sa(c,b+2),E=Sa(c,b+4),B=Sa(c,b+6);b+=pf;const q=E*B*2;if(E<=0||B<=0||E>f||B>f||A+E>p||x+B>h||b+q>c.length)throw new Error(`Invalid Mode 5 tile ${T}.`);M.push({x:A,y:x,width:E,height:B,pixels:c.subarray(b,b+q)}),b+=q}if(b!==c.length)throw new Error(`Mode 5 packet has ${c.length-b} trailing bytes.`);return{keyFrame:u,width:p,height:h,tileSize:f,tiles:M}}function aw(e,t,a,r){if(!(e instanceof Uint8ClampedArray)||e.length!==t*a*4||r.width!==t||r.height!==a)throw new Error("Mode 5 canvas state does not match the packet dimensions.");let c=t,u=a,p=0,h=0;const f=new Uint32Array(e.buffer,e.byteOffset,e.byteLength>>>2);for(const k of r.tiles){const M=lg&&(k.pixels.byteOffset&1)===0?new Uint16Array(k.pixels.buffer,k.pixels.byteOffset,k.pixels.byteLength>>>1):null;let b=0;for(let T=0;T<k.height;T+=1){let A=(k.y+T)*t+k.x;for(let x=0;x<k.width;x+=1){const E=b<<1,B=M?M[b]:k.pixels[E]|k.pixels[E+1]<<8;f[A]=xd[B],b+=1,A+=1}}c=Math.min(c,k.x),u=Math.min(u,k.y),p=Math.max(p,k.x+k.width),h=Math.max(h,k.y+k.height)}return r.tiles.length>0?{x:c,y:u,width:p-c,height:h-u}:null}function ow(e){if(!e)return!0;const t=_t.get(e);return!t||t.hardwareAcceleration==="prefer-hardware"}const _t=new WeakMap,ff=854,hf=480,iw=3840,sw=2160,cw=500,Ps=new WeakMap,Rd=new WeakMap,xo=new Set,ko=new Set,na=new WeakMap,Mo=new Set,Mi=new WeakMap,Ad=new WeakMap,Id=new WeakMap,Ml=new WeakMap,ug=4,lw=2,vi=4,uw=2,dw=2,mw=18,pw=0,fw=250,dg=80,hw=5,gw=150,bw=1200,vw=18,yw=.65,mg=80,pg=125,ww=4,Sw=2*1024*1024,Cw=8,kw=16,Mw=180,xw=3,zd=2e3,fg=64,hg=32*1024*1024,Rw=500,Aw=25,Iw=45,Tw=20,gg=new Uint8Array(0),Ud=250,Pw=globalThis.LIVEDESK_ENABLE_CANVAS_VISUAL_SAMPLING===!0;let bg=1,vg=0,yg=0,Td=0,wg=0;const ws=[];let Fs=0,Sg=0,Cg,kg=0,Mg,xg;function Ds(e,t){ws.push({sequence:++wg,type:e,canvasId:Mi.get(t)||0,observedAt:Date.now(),activeDecoderCount:xo.size,hardwareLeaseCount:ko.size,hardwareReleaseGeneration:Fs}),ws.length>256&&ws.splice(0,ws.length-256)}let Fr={h264DecodeAcceleration:"prefer-hardware"};function Ew(e){e.h264DecodeAcceleration&&(Fr={...Fr,h264DecodeAcceleration:e.h264DecodeAcceleration})}function Nw(e){return e.payload.byteLength===0?e:{...e,payload:gg}}function Rg(e,t){const a=String(e.streamPurpose||"").trim().toLowerCase();return a==="wall"?!0:a==="control"?!1:t>=45e3}function Ag(e){try{return e.paintIsCancelled()}catch{return!0}}function El(e,t){const a=e.pendingFrames.get(t);if(a)return e.pendingFrames.delete(t),e.pendingFrameBytes=Math.max(0,e.pendingFrameBytes-a.encodedByteLength),e.pendingFrames.size===0&&e.pendingTrimTimer!==null&&(window.clearTimeout(e.pendingTrimTimer),e.pendingTrimTimer=null),a}function Fw(e){const t=e.pendingFrames.entries().next().value;return t?El(e,t[0]):void 0}function Ig(e){e.pendingTrimTimer!==null&&(window.clearTimeout(e.pendingTrimTimer),e.pendingTrimTimer=null),e.pendingFrames.clear(),e.pendingFrameBytes=0,e.pendingFrameEvictedThroughTimestamp=-1}function Nl(e,t=performance.now()){for(;e.pendingFrames.size>0;){const a=e.pendingFrames.entries().next().value;if(!a)break;const r=t-a[1].queuedAt>zd,c=e.pendingFrames.size>fg,u=e.pendingFrameBytes>hg;if(!r&&!c&&!u)break;e.pendingFrameEvictedThroughTimestamp=Math.max(e.pendingFrameEvictedThroughTimestamp,a[0]),El(e,a[0]),e.pendingFrameEvictionCount+=1}}function Dw(e,t,a,r,c,u=performance.now()){El(e,t);const p={frame:a,queuedAt:u,queueSize:r,encodedByteLength:Math.max(0,Math.floor(Number(a.payload.byteLength||0))),paintIsCancelled:c};e.pendingFrames.set(t,p),e.pendingFrameBytes+=p.encodedByteLength,Nl(e,u),e.pendingFrameHighWaterMark=Math.max(e.pendingFrameHighWaterMark,e.pendingFrames.size),e.pendingFrameByteHighWaterMark=Math.max(e.pendingFrameByteHighWaterMark,e.pendingFrameBytes)}function Tg(e,t){if(t.pendingTrimTimer!==null||t.pendingFrames.size===0)return;const a=t.pendingFrames.values().next().value;if(!a)return;const r=Math.max(1,zd-(performance.now()-a.queuedAt)+1);t.pendingTrimTimer=window.setTimeout(()=>{t.pendingTrimTimer=null,_t.get(e)===t&&(Nl(t),Tg(e,t))},r)}function Pg(e){return ko.delete(e)?(Fs+=1,Ds("hardware-release",e),!0):!1}function Lw(e,t,a){if(t!=="prefer-hardware"||!a)return!1;const r=na.get(e);return!r||r.requested!==t||r.actual!=="prefer-software"||Fs<=r.failedHardwareReleaseGeneration?!1:(na.delete(e),Mo.delete(e),Sg+=1,Cg=Date.now(),!0)}function Pd(e,t=Fr.h264DecodeAcceleration){const a=na.get(e);return a?.requested===t?(a.actual!=="prefer-hardware"&&(ko.delete(e),Mo.add(e)),a.actual):(a&&(na.delete(e),Mo.delete(e)),t!=="prefer-hardware"?(Pg(e),Mo.delete(e),t):(ko.has(e)||ko.add(e),"prefer-hardware"))}function Ls(e,t,a){if(t!=="prefer-hardware")return!1;const r=na.get(e),c=_t.get(e),u=Date.now();return Mi.has(e)||Mi.set(e,bg++),na.set(e,{requested:t,actual:"prefer-software",reason:a,failedAt:u,failureCount:(r?.requested===t?r.failureCount:0)+1,codec:c?.codec||r?.codec||"",latencyMode:c?.latencyMode||r?.latencyMode||"smooth",inputCount:c?.inputSerial??r?.inputCount??0,outputCount:c?.outputSerial??r?.outputCount??0,lastInputAt:c?.lastInputAt??r?.lastInputAt??0,lastOutputAt:c?.lastOutputAt??r?.lastOutputAt??0,lastPaintAt:c?.lastPaintAt??r?.lastPaintAt??0,decodeQueueHighWaterMark:Math.max(c?.decodeQueueHighWaterMark??0,r?.decodeQueueHighWaterMark??0),decodeQueueOverflowSamples:Math.max(c?.decodeQueueOverflowSamples??0,r?.decodeQueueOverflowSamples??0),decodeQueueOverflowAgeMs:c?.decodeQueueOverflowStartedAt?Math.max(0,performance.now()-c.decodeQueueOverflowStartedAt):r?.decodeQueueOverflowAgeMs,failedHardwareReleaseGeneration:Fs}),ko.delete(e),Mo.add(e),kg+=1,Mg=a,xg=u,!0}function Pa(e){e.interactivePipelineFallbackTimer!==null&&(window.clearTimeout(e.interactivePipelineFallbackTimer),e.interactivePipelineFallbackTimer=null),e.interactivePipelineFallbackFrame!==null&&(window.cancelAnimationFrame(e.interactivePipelineFallbackFrame),e.interactivePipelineFallbackFrame=null),e.interactivePipelineRecoveryFrames=[],e.interactivePipelineRecoveryBytes=0,e.interactivePipelinePaintIsCancelled=void 0,e.interactivePipelineGuardTimestampUs=null}function Eg(e,t){const a=t.interactivePipelineRecoveryFrames,r=t.interactivePipelinePaintIsCancelled,c=t.onBeforePaint,u=t.onPaint;if(Pa(t),a.length===0||r?.()||_t.get(e)!==t||t.hardwareAcceleration!=="prefer-hardware"||!Ls(e,t.requestedAcceleration,"interactive-pipeline-latency"))return!1;const p=t.requestedAcceleration,h=t.latencyMode;kn(e);try{for(const f of a)Gd(e,f,u,p,h,r,!1,c)}catch{kn(e)}return!0}function Ow(e,t,a){const r=Math.max(0,Number(t.payload.byteLength||0));return e.interactivePipelineRecoveryFrames.length>=ww||e.interactivePipelineRecoveryBytes+r>Sw?(Pa(e),!1):(e.interactivePipelineRecoveryFrames.push({...t,payload:t.payload.slice()}),e.interactivePipelineRecoveryBytes+=r,e.interactivePipelinePaintIsCancelled=a,!0)}function _w(e,t,a,r,c=performance.now()){const u=()=>{if(!(_t.get(e)!==t||t.interactivePipelineGuardTimestampUs!==a)){if(!t.pendingFrames.has(a)){Pa(t);return}Eg(e,t)}},p=h=>{if(t.interactivePipelineFallbackFrame=null,!(_t.get(e)!==t||t.interactivePipelineGuardTimestampUs!==a)){if(!t.pendingFrames.has(a)){Pa(t);return}if(h-c>=r){u();return}t.interactivePipelineFallbackFrame=window.requestAnimationFrame(p)}};t.interactivePipelineFallbackTimer=window.setTimeout(u,r),t.interactivePipelineFallbackFrame=window.requestAnimationFrame(p)}function jw(e,t,a,r=64){try{let c=Ad.get(e);c||(c={canvas:document.createElement("canvas"),lastHash:"",initialized:!1},Ad.set(e,c));const u=Math.max(8,Math.min(64,Math.round(r))),p=Math.max(1,Math.round(u*Math.max(1,a)/Math.max(1,t)));(c.canvas.width!==u||c.canvas.height!==p)&&(c.canvas.width=u,c.canvas.height=p);const h=c.canvas.getContext("2d",{willReadFrequently:!0});if(!h)return{visualHash:"",visualChanged:!0};h.drawImage(e,0,0,Math.max(1,t),Math.max(1,a),0,0,u,p);const f=h.getImageData(0,0,u,p).data;let k=2166136261;for(let T=0;T<f.length;T+=4)k^=f[T],k=Math.imul(k,16777619),k^=f[T+1],k=Math.imul(k,16777619),k^=f[T+2],k=Math.imul(k,16777619);const M=(k>>>0).toString(16).padStart(8,"0"),b=!c.initialized||M!==c.lastHash;return c.initialized=!0,c.lastHash=M,{visualHash:M,visualChanged:b}}catch{return{visualHash:"",visualChanged:!0}}}function Ed(e,t,a,r=Ud,c=64,u){if(!Pw&&u)return Ng(e,u);let p=Id.get(e);p||(p={lastHash:"",initialized:!1,lastCanvasSampleAt:0},Id.set(e,p));const h=performance.now();if(p.initialized&&r>0&&h-p.lastCanvasSampleAt<r)return{visualHash:p.lastHash,visualChanged:!1};const f=jw(e,t,a,c);return p.initialized=!0,p.lastHash=f.visualHash,p.lastCanvasSampleAt=h,f}function Ng(e,t){let a=Ml.get(e);a||(a={lastHash:"",initialized:!1},Ml.set(e,a));const r=String(t.contentHash||""),c=!a.initialized||!r||r!==a.lastHash;return a.initialized=!0,a.lastHash=r,{visualHash:r,visualChanged:c}}function Fg(e,t,a=!1){const r=Rd.get(e);if(r)return r;const c=e.getContext("2d",{alpha:!1,desynchronized:t==="interactive",willReadFrequently:a});if(c){const u=c.getContextAttributes?.(),p={context:c,presentation:u?.desynchronized?"desync":"sync"};return Rd.set(e,p),p}return null}function Bw(e){const t=String(e.frameMode||e.mode||"").toLowerCase(),a=String(e.compression||"").toLowerCase(),r=String(e.mimeType||"").toLowerCase();return t==="mode2-lzo"||a==="lzo1x"||r==="application/vnd.livedesk.lzo-rgb565"||t==="mode2-lz4"||String(e.compression||"").toLowerCase()==="lz4"||r==="application/vnd.livedesk.lz4-raw"}function Hw(e){return String(e.frameMode||e.mode||"").toLowerCase()==="mode3-h264-hw"||String(e.codec||"").toLowerCase()==="h264"||String(e.mimeType||"").toLowerCase()==="video/h264"}function Ww(e){const t=String(e.frameMode||e.mode||"").toLowerCase(),a=String(e.mimeType||"").toLowerCase();return t==="mode5-lzo-delta"||a==="application/vnd.livedesk.lzo-rgb565-delta"}function gf(e,t,a){let r=a,c=t;if(r===15){let u=255;for(;u===255;){if(c>=e.length)throw new Error("Invalid LZ4 block: length overrun.");u=e[c],c+=1,r+=u}}return{length:r,cursor:c}}function $w(e,t){const a=new Uint8Array(t);let r=0,c=0;for(;r<e.length;){const u=e[r];r+=1;const p=gf(e,r,u>>4);r=p.cursor;const h=p.length;if(r+h>e.length||c+h>a.length)throw new Error("Invalid LZ4 block: literal overrun.");if(a.set(e.subarray(r,r+h),c),r+=h,c+=h,r>=e.length)break;if(r+2>e.length)throw new Error("Invalid LZ4 block: missing offset.");const f=e[r]|e[r+1]<<8;if(r+=2,f<=0||f>c)throw new Error("Invalid LZ4 block: bad match offset.");const k=gf(e,r,u&15);r=k.cursor;const M=k.length+4;if(c+M>a.length)throw new Error("Invalid LZ4 block: match overrun.");let b=c-f;for(let T=0;T<M;T+=1)a[c]=a[b],c+=1,b+=1}if(c!==a.length)throw new Error("Invalid LZ4 block: incomplete output.");return a}function Vw(e){const t=Math.max(1,Math.floor(e.width||0)),a=Math.max(1,Math.floor(e.height||0)),r=String(e.compression||"").toLowerCase(),c=String(e.pixelFormat||e.codec||"").toLowerCase();if(r==="lzo1x"||String(e.frameMode||e.mode||"").toLowerCase()==="mode2-lzo"||String(e.mimeType||"").toLowerCase()==="application/vnd.livedesk.lzo-rgb565"){const M=Math.max(1,Math.floor(e.bytesPerPixel||2)),b=t*a*2,T=Math.floor(e.uncompressedByteLength||b);if(M!==2||T!==b)throw new Error(`Invalid mode2 RGB565 frame size: ${T} for ${t}x${a}.`);if(c&&c!=="rgb565le"&&c!=="rgb565")throw new Error(`Unsupported mode2 pixel format: ${c}`);const A=cg(e.payload,b),x=new Uint8ClampedArray(t*a*4);for(let E=0,B=0;E<A.length;E+=2,B+=4){const q=A[E]|A[E+1]<<8,G=q>>11&31,ne=q>>5&63,re=q&31;x[B]=G<<3|G>>2,x[B+1]=ne<<2|ne>>4,x[B+2]=re<<3|re>>2,x[B+3]=255}return new ImageData(x,t,a)}const p=Math.max(1,Math.floor(e.bytesPerPixel||4)),h=Math.max(t*a*p,Math.floor(e.uncompressedByteLength||0)),f=$w(e.payload,h);if(p!==4)throw new Error(`Unsupported mode2 pixel size: ${p}`);const k=new Uint8ClampedArray(t*a*4);if(c==="rgba32"||c==="rgba")k.set(f.subarray(0,k.length));else for(let M=0,b=0;b<k.length;M+=4,b+=4)k[b]=f[M+2],k[b+1]=f[M+1],k[b+2]=f[M],k[b+3]=f[M+3];return new ImageData(k,t,a)}function bf(e,t="smooth",a=Fr.h264DecodeAcceleration){const r=window.VideoDecoder;if(!r||!window.EncodedVideoChunk)throw new Error("WebCodecs H.264 decode is not supported in this browser.");const c=_t.get(e);if(c&&c.decoder.state!=="closed"&&c.latencyMode===t)return c;c&&kn(e);let u;const p=new r({output:h=>{if(_t.get(e)!==u){h.close();return}const f=Number(h.timestamp||0),k=performance.now();u.outputSerial+=1,Nl(u,k);let M=El(u,f);if(!M&&f>u.pendingFrameEvictedThroughTimestamp&&u.pendingFrames.size>0&&(M=Fw(u),u.timestampFallbacks+=1),!M){u.pendingFrameUnmatchedOutputCount+=1,u.droppedForLatency+=1,u.lastOutputAt=k,h.close();return}const b=u.interactivePipelineGuardTimestampUs===f;if(Ag(M)){b&&Pa(u),u.droppedForLatency+=1,u.lastOutputAt=k,h.close();return}const T=h.displayWidth||h.codedWidth||e.width||960,A=h.displayHeight||h.codedHeight||e.height||540,x=Number(M?.frame.durationUs||0),E=Number(h.duration||0),B=Math.max(16,Math.min(250,(x>0?x:E||83333)/1e3));u.targetPaintIntervalMs=B;const q=Math.max(0,k-M.queuedAt),ne=Rg(M.frame,x>0?x:Math.round(B*1e3))?pg:mg;if(u.latencyMode==="interactive"&&u.hardwareAcceleration==="prefer-hardware"&&b&&u.interactivePipelineRecoveryFrames.length>0&&q>ne){h.close(),u.droppedForLatency+=1,Eg(e,u);return}b&&Pa(u),Math.abs(u.interactiveBurstOutputCadenceMs-B)>1&&(u.interactiveBurstOutputTimeCursor=0,u.interactiveBurstOutputTimeCount=0,u.interactiveBurstOutputCadenceMs=B,u.interactiveBurstOutputWindowMs=0),u.interactiveBurstOutputTimes[u.interactiveBurstOutputTimeCursor]=k,u.interactiveBurstOutputTimeCursor=(u.interactiveBurstOutputTimeCursor+1)%vi,u.interactiveBurstOutputTimeCount=Math.min(vi,u.interactiveBurstOutputTimeCount+1);const re=u.interactiveBurstOutputTimeCount>=vi?k-u.interactiveBurstOutputTimes[u.interactiveBurstOutputTimeCursor]:0;for(u.interactiveBurstOutputWindowMs=Math.max(0,re),u.decodedFrames.push({videoFrame:h,pending:M,decodedAt:k,width:T,height:A,durationMs:B}),u.latencyMode==="interactive"&&u.targetPaintIntervalMs>20&&u.interactiveBurstOutputTimeCount>=vi&&re<=Math.min(Iw,Math.max(Aw,u.targetPaintIntervalMs-5))&&(u.interactiveBurstTailHoldArmed=!0),u.lastOutputAt=k;u.decodedFrames.length>qd(u);)xl(u,u.decodedFrames.shift(),"capacity");u.renderQueueHighWaterMark=Math.max(u.renderQueueHighWaterMark,u.decodedFrames.length),Lg(u),u.renderTimer!==null&&u.renderScheduledAt>0&&performance.now()-u.renderScheduledAt>Rw&&(typeof document>"u"||document.visibilityState==="visible")&&(window.cancelAnimationFrame(u.renderTimer),u.renderTimer=null,u.renderScheduledAt=0),u.renderTimer!==null&&u.decodedFrames.length>=ug&&(window.cancelAnimationFrame(u.renderTimer),u.renderTimer=null,u.renderScheduledAt=0),Rl(e,u)},error:()=>{_t.get(e)===u&&(Ls(e,u.requestedAcceleration,"decoder-error"),kn(e))}});return vg+=1,Mi.has(e)||Mi.set(e,bg++),u={decoder:p,configured:!1,configKey:"",codec:"",requestedAcceleration:a,hardwareAcceleration:Pd(e,a),latencyMode:t,keyFrameSeen:!1,droppedForLatency:0,pendingFrames:new Map,pendingFrameBytes:0,pendingFrameHighWaterMark:0,pendingFrameByteHighWaterMark:0,pendingFrameEvictionCount:0,pendingFrameUnmatchedOutputCount:0,pendingFrameEvictedThroughTimestamp:-1,pendingTrimTimer:null,decodedFrames:[],renderQueueHighWaterMark:0,renderQueueCapacityDropCount:0,renderQueueAgeDropCount:0,renderTimer:null,renderScheduledAt:0,flushTimer:null,flushInFlight:!1,flushCount:0,timestampFallbacks:0,inputSerial:0,outputSerial:0,lastFlushInputSerial:0,lastOutputAt:0,lastPaintAt:0,lastInputAt:0,interactiveBufferPrimed:!1,interactiveBufferStartedAt:0,interactiveBufferWaitCount:0,interactiveBufferWaitMs:0,interactiveQueueDrainCount:0,interactiveBurstTailHoldArmed:!1,interactiveBurstTailHoldCount:0,interactiveBurstOutputTimes:new Float64Array(vi),interactiveBurstOutputTimeCursor:0,interactiveBurstOutputTimeCount:0,interactiveBurstOutputCadenceMs:0,interactiveBurstOutputWindowMs:0,interactivePipelineFallbackTimer:null,interactivePipelineFallbackFrame:null,interactivePipelineGuardTimestampUs:null,interactivePipelineRecoveryFrames:[],interactivePipelineRecoveryBytes:0,interactivePipelinePaintIsCancelled:void 0,interactiveBackingWidth:0,interactiveBackingHeight:0,interactiveBackingSourceWidth:0,interactiveBackingSourceHeight:0,interactiveBackingMeasuredAt:0,lastInputFrameSeq:void 0,targetPaintIntervalMs:1e3/12,nextChunkTimestampUs:0,healthSampleStartedAt:performance.now(),healthInputSerial:0,healthOutputSerial:0,decodeQueueHighWaterMark:0,decodeQueueOverflowStartedAt:0,decodeQueueOverflowSamples:0},_t.set(e,u),xo.add(e),Td=Math.max(Td,xo.size),Ds("create",e),u}function Dg(e){Pa(e),e.renderTimer!==null&&(window.cancelAnimationFrame(e.renderTimer),e.renderTimer=null),e.renderScheduledAt=0,e.flushTimer!==null&&(window.clearTimeout(e.flushTimer),e.flushTimer=null),e.flushInFlight=!1;const t=e.decodedFrames;e.decodedFrames=[];for(const a of t)try{a.videoFrame.close()}catch{}e.interactiveBufferPrimed=!1,e.interactiveBufferStartedAt=0,e.interactiveBurstTailHoldArmed=!1,e.interactiveBurstOutputTimeCursor=0,e.interactiveBurstOutputTimeCount=0,e.interactiveBurstOutputCadenceMs=0,e.interactiveBurstOutputWindowMs=0}function xl(e,t,a="other"){t&&(t.videoFrame.close(),e.droppedForLatency+=1,a==="capacity"?e.renderQueueCapacityDropCount+=1:a==="age"&&(e.renderQueueAgeDropCount+=1))}function qd(e){return e.latencyMode==="interactive"?e.targetPaintIntervalMs<=20?uw:vi:String(e.decodedFrames[0]?.pending?.frame.frameMode||e.decodedFrames[0]?.pending?.frame.mode||"").toLowerCase()==="mode4-h264-atlas"?lw:ug}function Lg(e,t=performance.now()){const a=qd(e);for(;e.decodedFrames.length>a;)xl(e,e.decodedFrames.shift(),"capacity");const r=e.latencyMode==="interactive"?dg:fw;let c=e.decodedFrames[0];for(;e.decodedFrames.length>0&&c&&t-c.decodedAt>r;)xl(e,e.decodedFrames.shift(),"age"),c=e.decodedFrames[0]}function Og(e,t){if(t.hardwareAcceleration!=="prefer-hardware"||t.latencyMode==="interactive"||t.flushTimer!==null||t.flushInFlight)return;const a=gw;t.flushTimer=window.setTimeout(async()=>{t.flushTimer=null;const r=performance.now();if(Nl(t,r),_t.get(e)!==t||t.decoder.state!=="configured"||t.pendingFrames.size===0||t.inputSerial<=t.lastFlushInputSerial||t.lastOutputAt>0&&r-t.lastOutputAt<a)return;const c=t.inputSerial;t.flushInFlight=!0,t.flushCount+=1,t.keyFrameSeen=!1;try{await t.decoder.flush(),t.lastFlushInputSerial=Math.max(t.lastFlushInputSerial,c)}catch{_t.get(e)===t&&yl(t)}finally{t.flushInFlight=!1,_t.get(e)===t&&t.inputSerial>c&&t.pendingFrames.size>0&&performance.now()-t.lastOutputAt>=a&&Og(e,t)}},a)}function zw(e,t,a,r){const c=performance.now();if(t.interactiveBackingWidth>0&&t.interactiveBackingHeight>0&&c-t.interactiveBackingMeasuredAt<cw)return{width:Math.min(a,t.interactiveBackingWidth),height:Math.min(r,t.interactiveBackingHeight)};const u=typeof e.getBoundingClientRect=="function"?e.getBoundingClientRect():{width:Number(e.clientWidth||e.width||0),height:Number(e.clientHeight||e.height||0)},p=Math.max(1,Math.min(2,Number(globalThis.devicePixelRatio)||1)),h=Math.max(0,Number(e.width||0)),f=Math.max(0,Number(e.height||0)),k=u.width>0?Math.round(u.width*p):h||ff,M=u.height>0?Math.round(u.height*p):f||hf,b=Math.min(1,k/a,M/r),T=Math.min(1,Math.max(ff/a,hf/r)),A=Math.min(1,iw/a,sw/r),x=Math.max(.01,Math.min(A,Math.max(T,b)));return t.interactiveBackingWidth=Math.max(1,Math.round(a*x)),t.interactiveBackingHeight=Math.max(1,Math.round(r*x)),t.interactiveBackingMeasuredAt=c,{width:t.interactiveBackingWidth,height:t.interactiveBackingHeight}}function vf(e,t,a){const r=performance.now();try{if(!a.pending||Ag(a.pending)){t.droppedForLatency+=1;return}let c=1;try{const M=t.onBeforePaint?.(a.pending.frame);typeof M=="number"&&Number.isFinite(M)&&(c=Math.max(.05,Math.min(1,M)))}catch{}const u=t.latencyMode==="interactive"?zw(e,t,a.width,a.height):{width:a.width,height:a.height},p=u.width,h=u.height,f=e.width!==p||e.height!==h;f&&(e.width=p,e.height=h);const k=Fg(e,t.latencyMode,t.hardwareAcceleration==="prefer-software");if(k){const M=k.context.globalAlpha;k.context.globalAlpha=f||t.lastPaintAt<=0||t.hardwareAcceleration!=="prefer-hardware"?1:c;try{k.context.drawImage(a.videoFrame,0,0,a.width,a.height,0,0,p,h)}finally{k.context.globalAlpha=M}}if(a.pending){const M=performance.now(),T=t.latencyMode==="interactive"?Ng(e,a.pending.frame):Ed(e,a.width,a.height,Ud,64,a.pending.frame),A=Nw(a.pending.frame);try{t.onPaint?.(A,{deviceId:A.deviceId,frameSeq:A.frameSeq,mode:A.frameMode||A.mode||A.codec||A.mimeType,width:a.width,height:a.height,byteLength:A.byteLength,queuedForMs:Math.max(0,r-a.pending.queuedAt),decodedForMs:Math.max(0,a.decodedAt-a.pending.queuedAt),scheduledForMs:Math.max(0,r-a.decodedAt),drawMs:Math.max(0,M-r),queueSize:a.pending.queueSize,renderQueueSize:t.decodedFrames.length,droppedForLatency:t.droppedForLatency,h264DecodeAcceleration:t.hardwareAcceleration,decoderLabel:t.hardwareAcceleration,decoderFlushCount:t.flushCount,decoderTimestampFallbacks:t.timestampFallbacks,decoderInputCount:t.inputSerial,decoderOutputCount:t.outputSerial,targetPaintIntervalMs:t.targetPaintIntervalMs,canvasPresentation:k?.presentation||"sync",interactiveBufferWaitCount:t.interactiveBufferWaitCount,interactiveBufferWaitMs:t.interactiveBufferWaitMs,interactiveQueueDrainCount:t.interactiveQueueDrainCount,interactiveBurstOutputWindowMs:t.interactiveBurstOutputWindowMs,interactiveBurstTailHoldCount:t.interactiveBurstTailHoldCount,visualHash:T.visualHash,visualChanged:T.visualChanged,paintedAt:M})}catch{}}t.lastPaintAt=performance.now()}finally{a.videoFrame.close()}}function Rl(e,t){if(t.renderTimer!==null||t.decodedFrames.length===0)return;const a=Math.max(16,Math.min(250,t.targetPaintIntervalMs||1e3/12)),r=()=>{if(t.renderTimer=null,t.renderScheduledAt=0,t.decodedFrames.length===0)return;const c=performance.now();if(Lg(t,c),t.decodedFrames.length===0){t.interactiveBurstTailHoldArmed=!1;return}if(t.latencyMode==="interactive"){const f=t.targetPaintIntervalMs<=20;if(f&&!t.interactiveBufferPrimed){t.interactiveBufferStartedAt<=0&&(t.interactiveBufferStartedAt=c,t.interactiveBufferWaitCount+=1);const M=t.decodedFrames.length>=dw,b=c-t.interactiveBufferStartedAt>=mw;if(!M&&!b){t.renderScheduledAt=performance.now(),t.renderTimer=window.requestAnimationFrame(r);return}t.interactiveBufferWaitMs+=Math.max(0,c-t.interactiveBufferStartedAt),t.interactiveBufferPrimed=!0}else f||(t.interactiveBufferPrimed=!0);if(!f&&t.interactiveBurstTailHoldArmed&&t.decodedFrames.length===1&&c-t.decodedFrames[0].decodedAt<=dg-Tw){t.interactiveBurstTailHoldArmed=!1,t.interactiveBurstTailHoldCount+=1,t.renderScheduledAt=performance.now(),t.renderTimer=window.requestAnimationFrame(r);return}const k=t.decodedFrames.shift();if(k)try{vf(e,t,k)}catch{}t.decodedFrames.length===0&&(t.interactiveQueueDrainCount+=1,t.interactiveBufferPrimed=!1,t.interactiveBufferStartedAt=0,t.interactiveBurstTailHoldArmed=!1),Rl(e,t);return}const u=t.lastPaintAt>0?t.lastPaintAt+a:c+pw;if(!(c+hw>=u||t.decodedFrames.length>=Math.max(1,qd(t)-1))){t.renderScheduledAt=performance.now(),t.renderTimer=window.requestAnimationFrame(r);return}const h=t.decodedFrames.shift();if(h)try{vf(e,t,h)}catch{}Rl(e,t)};t.renderScheduledAt=performance.now(),t.renderTimer=window.requestAnimationFrame(r)}function _g(e,t){if(_t.get(e)!==t||t.decoder.state==="closed")return!1;for(t.renderTimer!==null&&(window.cancelAnimationFrame(t.renderTimer),t.renderTimer=null),t.renderScheduledAt=0;t.decodedFrames.length>1;)xl(t,t.decodedFrames.shift());return t.lastPaintAt=0,t.interactiveBufferPrimed=!1,t.interactiveBufferStartedAt=0,t.interactiveBurstTailHoldArmed=!1,t.interactiveBurstOutputTimeCursor=0,t.interactiveBurstOutputTimeCount=0,t.interactiveBurstOutputCadenceMs=0,t.interactiveBurstOutputWindowMs=0,Rl(e,t),!0}function Ju(){if(!(typeof document>"u"||document.visibilityState!=="visible"))for(const e of xo){const t=_t.get(e);if(!t||t.decoder.state==="closed"){xo.delete(e);continue}_g(e,t)}}typeof document<"u"&&typeof window<"u"&&(document.addEventListener("visibilitychange",Ju),window.addEventListener("focus",Ju),window.addEventListener("pageshow",Ju));function kn(e){Pg(e),xo.delete(e),Ml.delete(e);const t=_t.get(e);if(t){_t.delete(e),yg+=1,Ig(t),t.onBeforePaint=void 0,t.onPaint=void 0,Dg(t);try{t.decoder.state!=="closed"&&t.decoder.reset()}catch{}try{t.decoder.state!=="closed"&&t.decoder.close()}catch{}Ds("close",e)}}function fi(e){e&&(na.delete(e),Mo.delete(e),Rd.delete(e),Id.delete(e),Ad.delete(e),Ml.delete(e),Ps.delete(e),kn(e))}function Uw(e,t){const a=_t.get(e),r=na.get(e);if(!a&&!r)return null;const c=p=>p>0?Math.max(0,t-p):void 0,u=a?.pendingFrames.values().next().value;return{canvasId:Mi.get(e)||0,canvasWidth:Math.max(0,Number(e.width||0)),canvasHeight:Math.max(0,Number(e.height||0)),decoderState:a?.decoder.state||"fallback-pending",configured:a?.configured||!1,keyFrameSeen:a?.keyFrameSeen||!1,codec:a?.codec||r?.codec||"",requestedAcceleration:a?.requestedAcceleration||r?.requested||Fr.h264DecodeAcceleration,configuredAcceleration:a?.hardwareAcceleration||r?.actual||Fr.h264DecodeAcceleration,latencyMode:a?.latencyMode||r?.latencyMode||"smooth",decodeQueueSize:Math.max(0,Number(a?.decoder.decodeQueueSize||0)),decodeQueueHighWaterMark:Math.max(0,Number(a?.decodeQueueHighWaterMark??0),Number(r?.decodeQueueHighWaterMark??0)),decodeQueueOverflowSamples:Math.max(0,Number(a?.decodeQueueOverflowSamples??0),Number(r?.decodeQueueOverflowSamples??0)),decodeQueueOverflowAgeMs:a?.decodeQueueOverflowStartedAt?Math.max(0,t-a.decodeQueueOverflowStartedAt):r?.decodeQueueOverflowAgeMs,pendingFrameCount:a?.pendingFrames.size||0,pendingFrameBytes:a?.pendingFrameBytes||0,pendingFrameHighWaterMark:a?.pendingFrameHighWaterMark||0,pendingFrameByteHighWaterMark:a?.pendingFrameByteHighWaterMark||0,pendingFrameEvictionCount:a?.pendingFrameEvictionCount||0,pendingFrameUnmatchedOutputCount:a?.pendingFrameUnmatchedOutputCount||0,pendingFrameOldestAgeMs:u?Math.max(0,t-u.queuedAt):void 0,pendingFrameMaxCount:fg,pendingFrameMaxBytes:hg,pendingFrameMaxAgeMs:zd,renderQueueSize:a?.decodedFrames.length||0,renderQueueHighWaterMark:a?.renderQueueHighWaterMark||0,renderQueueCapacityDropCount:a?.renderQueueCapacityDropCount||0,renderQueueAgeDropCount:a?.renderQueueAgeDropCount||0,interactiveBurstTailHoldCount:a?.interactiveBurstTailHoldCount||0,interactiveBurstOutputWindowMs:Math.max(0,Number(a?.interactiveBurstOutputWindowMs||0)),interactivePipelineRecoveryBytes:Math.max(0,Number(a?.interactivePipelineRecoveryBytes||0)),targetPaintIntervalMs:Math.max(0,Number(a?.targetPaintIntervalMs||0)),droppedForLatency:Math.max(0,Number(a?.droppedForLatency||0)),inputCount:a?.inputSerial??r?.inputCount??0,outputCount:a?.outputSerial??r?.outputCount??0,lastInputAgeMs:c(a?.lastInputAt??r?.lastInputAt??0),lastOutputAgeMs:c(a?.lastOutputAt??r?.lastOutputAt??0),lastPaintAgeMs:c(a?.lastPaintAt??r?.lastPaintAt??0),softwareFallbackReason:r?.reason,softwareFallbackAt:r?.failedAt,softwareFallbackCount:r?.failureCount||0}}function ps(e,t={}){const a=performance.now(),c=(e?[e]:[...new Set([...xo,...Mo])]).map(h=>Uw(h,a)).filter(h=>h!==null),u=c.reduce((h,f)=>h+f.pendingFrameCount,0),p=c.reduce((h,f)=>h+f.pendingFrameBytes,0);return{capturedAt:Date.now(),hardwareRequestPolicy:"all-active",activeDecoderCount:c.filter(h=>h.decoderState!=="fallback-pending").length,hardwareLeaseCount:ko.size,hardwareReleaseGeneration:Fs,hardwareRecoveryProbeCount:Sg,lastHardwareRecoveryProbeAt:Cg,activeSoftwareFallbackCount:c.filter(h=>h.configuredAcceleration==="prefer-software"&&h.requestedAcceleration==="prefer-hardware").length,decoderCreateCount:vg,decoderCloseCount:yg,activeDecoderHighWaterMark:Td,decoderLifecycleSequence:wg,decoderLifecycleEvents:t.includeLifecycleEvents===!1?[]:ws.map(h=>({...h})),softwareFallbackEventCount:kg,lastSoftwareFallbackReason:Mg,lastSoftwareFallbackAt:xg,pendingFrameCount:u,pendingFrameBytes:p,canvases:c}}function yl(e,t=1){try{e.decoder.state!=="closed"&&e.decoder.reset()}catch{}e.configured=!1,e.configKey="",e.keyFrameSeen=!1,Ig(e),Dg(e),e.lastPaintAt=0,e.lastOutputAt=0,e.lastInputAt=0,e.interactiveBufferPrimed=!1,e.interactiveBufferStartedAt=0,e.lastInputFrameSeq=void 0,e.nextChunkTimestampUs=0,e.healthSampleStartedAt=performance.now(),e.healthInputSerial=e.inputSerial,e.healthOutputSerial=e.outputSerial,e.decodeQueueOverflowStartedAt=0,e.decodeQueueOverflowSamples=0,e.droppedForLatency+=Math.max(1,Math.min(1e4,Math.floor(t)))}function qw(e,t,a=performance.now()){const r=Math.max(0,Number.isFinite(t)?t:0);if(e.decodeQueueHighWaterMark=Math.max(e.decodeQueueHighWaterMark,r),r<=Cw)return e.decodeQueueOverflowStartedAt=0,e.decodeQueueOverflowSamples=0,!1;e.decodeQueueOverflowStartedAt<=0?(e.decodeQueueOverflowStartedAt=a,e.decodeQueueOverflowSamples=1):e.decodeQueueOverflowSamples+=1;const c=Math.max(0,a-e.decodeQueueOverflowStartedAt);return r>=kw||e.decodeQueueOverflowSamples>=xw&&c>=Mw}function Gw(e,t,a,r,c,u){t.decoder.configure(a),t.configured=!0,t.configKey=r,t.codec=a.codec,t.requestedAcceleration=u,t.hardwareAcceleration=c,t.keyFrameSeen=!1,t.nextChunkTimestampUs=0,t.lastInputFrameSeq=void 0,Ds("configure",e)}function Kw(e,t){if(t.latencyMode!=="interactive"||t.hardwareAcceleration!=="prefer-hardware")return!1;const a=performance.now();if(a-t.healthSampleStartedAt<bw)return!1;const r=t.inputSerial-t.healthInputSerial,c=t.outputSerial-t.healthOutputSerial;return t.healthSampleStartedAt=a,t.healthInputSerial=t.inputSerial,t.healthOutputSerial=t.outputSerial,r<vw||c/Math.max(1,r)>=yw?!1:(Ls(e,t.requestedAcceleration,"interactive-health"),kn(e),!0)}function hi(e,t=1){if(!e)return!1;const a=_t.get(e);return a?(a.droppedForLatency+=Math.max(1,Math.min(1e4,Math.floor(t))),kn(e),!0):!1}function Yw(e){if(!e)return"none";const t=_t.get(e),a=na.get(e);if(!t&&!a)return"none";const r=t?.requestedAcceleration||a?.requested||Fr.h264DecodeAcceleration,u=(t?.hardwareAcceleration||a?.actual||r)==="prefer-hardware"&&Ls(e,r,"paint-stall");return t&&(t.droppedForLatency+=1),kn(e),u?"software-fallback":"decoder-reset"}function Qw(e){if(!e)return!1;const t=_t.get(e);return t?_g(e,t):!1}function Xw(e,t,a,r="interactive",c){kn(e);const u=performance.now(),p=rw(t.payload,t.uncompressedByteLength||0),h=String(t.streamId||"mode5");let f=Ps.get(e);if(!f||f.streamId!==h||f.width!==p.width||f.height!==p.height){const B=new Uint8ClampedArray(p.width*p.height*4);for(let q=3;q<B.length;q+=4)B[q]=255;f={streamId:h,width:p.width,height:p.height,rgba:B,imageData:new ImageData(B,p.width,p.height),keyFrameSeen:!1,inputSerial:0,outputSerial:0},Ps.set(e,f)}if(!f)throw new Error("Mode 5 canvas state could not be initialized.");f.inputSerial+=1;const M=Number(t.streamFrameSeq||0);if(M>0&&(f.lastStreamFrameSeq=M),!p.keyFrame&&!f.keyFrameSeen)return;p.keyFrame&&(f.keyFrameSeen=!0);const b=aw(f.rgba,f.width,f.height,p),T=performance.now();try{c?.(t)}catch{}(e.width!==f.width||e.height!==f.height)&&(e.width=f.width,e.height=f.height);const A=Fg(e,r),x=performance.now();b&&A?.context.putImageData(f.imageData,0,0,b.x,b.y,b.width,b.height);const E=performance.now();f.outputSerial+=1,a?.(t,{deviceId:t.deviceId,frameSeq:t.frameSeq,mode:t.frameMode||t.mode||t.mimeType,width:f.width,height:f.height,byteLength:t.byteLength,queuedForMs:Math.max(0,E-u),decodedForMs:Math.max(0,T-u),scheduledForMs:0,drawMs:Math.max(0,E-x),queueSize:0,renderQueueSize:0,droppedForLatency:0,h264DecodeAcceleration:"prefer-software",decoderLabel:"lzo-rgb565-delta",decoderFlushCount:0,decoderTimestampFallbacks:0,decoderInputCount:f.inputSerial,decoderOutputCount:f.outputSerial,targetPaintIntervalMs:Math.max(1,Number(t.durationUs||0)/1e3||1e3/30),canvasPresentation:A?.presentation||"sync",interactiveBufferWaitCount:0,interactiveBufferWaitMs:0,interactiveQueueDrainCount:0,visualHash:String(t.contentHash||""),visualChanged:Number(t.deltaVisualTileCount||0)>0,paintedAt:E})}const Zu=[{code:30,maxFrameSize:1620,maxMacroblocksPerSecond:40500},{code:31,maxFrameSize:3600,maxMacroblocksPerSecond:108e3},{code:32,maxFrameSize:5120,maxMacroblocksPerSecond:216e3},{code:40,maxFrameSize:8192,maxMacroblocksPerSecond:245760},{code:41,maxFrameSize:8192,maxMacroblocksPerSecond:245760},{code:42,maxFrameSize:8704,maxMacroblocksPerSecond:522240},{code:50,maxFrameSize:22080,maxMacroblocksPerSecond:589824},{code:51,maxFrameSize:36864,maxMacroblocksPerSecond:983040},{code:52,maxFrameSize:36864,maxMacroblocksPerSecond:2073600}];function yf(e,t){for(let a=Math.max(0,t);a+3<e.length;a+=1)if(!(e[a]!==0||e[a+1]!==0)){if(e[a+2]===1)return{index:a,length:3};if(e[a+2]===0&&e[a+3]===1)return{index:a,length:4}}return null}function Jw(e){let t=0;for(;t<e.length;){const a=yf(e,t);if(!a)break;const r=a.index+a.length,c=yf(e,r),u=c?.index??e.length;if(r<u&&(e[r]&31)===7){const p=[];let h=0;for(let f=r+1;f<u;f+=1){const k=e[f];if(h>=2&&k===3){h=0;continue}p.push(k),h=k===0?h+1:0}if(p.length>=3)return`avc1.${p.slice(0,3).map(f=>f.toString(16).toUpperCase().padStart(2,"0")).join("")}`}t=c?c.index:e.length}return""}function Zw(e,t,a,r,c=""){const u=Math.ceil(e/16)*Math.ceil(t/16),p=a>0?1e6/a:30,h=u*p,f=Zu.find(k=>u<=k.maxFrameSize&&h<=k.maxMacroblocksPerSecond)||Zu[Zu.length-1];return Jw(r)||c||`avc1.42E0${f.code.toString(16).toUpperCase().padStart(2,"0")}`}function Gd(e,t,a,r,c="smooth",u=()=>!1,p=!0,h){Ps.delete(e);const f=String(t.h264Format||"").toLowerCase()==="avc"?"avc":"annexb",k=Math.max(1,Math.floor(t.width||960)),M=Math.max(1,Math.floor(t.height||540)),b=Math.max(1,Math.floor(t.durationUs||1e6/12)),T=r||Fr.h264DecodeAcceleration,A=t.isKeyFrame===!0||String(t.chunkType||"").toLowerCase()==="key";Lw(e,T,A);let x=bf(e,c,T);const E=Zw(k,M,b,t.payload,x.codec);let B=Pd(e,T),q="";const G=()=>{q=[t.streamId||"",t.commandId||"",k,M,E,f,T,B,c].join("|")};G(),x.onBeforePaint=h,x.onPaint=a,x.configured&&x.decoder.state!=="configured"&&(x.configured=!1,x.configKey=""),x.configured&&x.configKey!==q&&(kn(e),x=bf(e,c,T),x.onBeforePaint=h,x.onPaint=a,B=Pd(e,T),G());const ne=()=>({codec:E,codedWidth:k,codedHeight:M,hardwareAcceleration:B,optimizeForLatency:!0,avc:{format:f}}),re=P=>x.hardwareAcceleration!=="prefer-hardware"||!Ls(e,x.requestedAcceleration,P)?!1:(kn(e),p&&A&&Gd(e,t,a,T,c,u,!1,h),!0),O=()=>{try{return Gw(e,x,ne(),q,B,T),!0}catch(P){if(re("configure-error"))return!1;throw kn(e),P}};if(!x.configured&&!O())return;const ie=Number(t.streamFrameSeq||0);if(ie>0&&x.lastInputFrameSeq!==void 0&&(ie<=x.lastInputFrameSeq&&(!A||ie===x.lastInputFrameSeq||(yl(x,x.lastInputFrameSeq-ie+1),!O()))||ie>x.lastInputFrameSeq+1&&(yl(x,ie-x.lastInputFrameSeq-1),!A||!O()))||(ie>0&&(x.lastInputFrameSeq=ie),!A&&!x.keyFrameSeen))return;A&&(x.keyFrameSeen=!0);const J=Number(x.decoder.decodeQueueSize||0);if(qw(x,J)){if(x.latencyMode==="interactive"&&x.hardwareAcceleration==="prefer-hardware"){re("decode-queue-overflow");return}if(yl(x),!A||!O())return;x.keyFrameSeen=!0}const de=x.nextChunkTimestampUs;x.nextChunkTimestampUs+=b,Dw(x,de,t,J,u),Tg(e,x),x.inputSerial+=1,x.lastInputAt=performance.now(),x.inputSerial===1&&Ds("first-input",e);const se=t.payload.buffer,pe=se instanceof ArrayBuffer?[se]:[],ce=Rg(t,b),W=!ce&&x.outputSerial>0,ee=A&&x.latencyMode==="interactive"&&x.hardwareAcceleration==="prefer-hardware"&&(ce||W),L=ce?pg:mg;ee&&(Pa(x),x.interactivePipelineGuardTimestampUs=de);const _=x.interactivePipelineGuardTimestampUs!==null&&x.interactivePipelineRecoveryFrames.length>0,K=ee||_?Ow(x,t,u):!1,ue=new EncodedVideoChunk({type:A?"key":"delta",timestamp:de,duration:b,data:t.payload,transfer:pe});t.payload=gg;try{x.decoder.decode(ue)}catch(P){if(re("decode-error"))return;throw kn(e),P}K&&_t.get(e)===x&&x.interactivePipelineGuardTimestampUs===de&&ee&&_w(e,x,de,L),Og(e,x),Kw(e,x)}async function ed(e,t,a,r,c,u="smooth",p=a,h){if(Ww(t)){a()||Xw(e,t,r,u,h);return}if(Hw(t)){a()||Gd(e,t,r,c,u,p,!0,h);return}if(Ps.delete(e),Bw(t)){kn(e);const A=Vw(t);if(a())return;try{h?.(t)}catch{}(e.width!==A.width||e.height!==A.height)&&(e.width=A.width,e.height=A.height);const x=e.getContext("2d"),E=performance.now();x?.putImageData(A,0,0);const B=performance.now(),q=Ed(e,A.width,A.height,Ud,64,t);r?.(t,{deviceId:t.deviceId,frameSeq:t.frameSeq,mode:t.frameMode||t.mode||t.codec||t.mimeType,width:A.width,height:A.height,byteLength:t.byteLength,queuedForMs:0,decodedForMs:0,scheduledForMs:0,drawMs:Math.max(0,B-E),queueSize:0,renderQueueSize:0,droppedForLatency:0,h264DecodeAcceleration:Fr.h264DecodeAcceleration,decoderLabel:"lzo-rgb565",decoderFlushCount:0,decoderTimestampFallbacks:0,decoderInputCount:0,decoderOutputCount:0,targetPaintIntervalMs:0,canvasPresentation:"sync",interactiveBufferWaitCount:0,interactiveBufferWaitMs:0,interactiveQueueDrainCount:0,visualHash:q.visualHash,visualChanged:q.visualChanged,paintedAt:B});return}kn(e);const f=new Blob([t.payload],{type:t.mimeType}),k=await createImageBitmap(f);if(a()){k.close();return}const M=t.width||k.width||960,b=t.height||k.height||540;try{h?.(t)}catch{}(e.width!==M||e.height!==b)&&(e.width=M,e.height=b);const T=e.getContext("2d");if(T){const A=performance.now();T.clearRect(0,0,M,b),T.drawImage(k,0,0,M,b);const x=performance.now(),E=Ed(e,M,b);r?.(t,{deviceId:t.deviceId,frameSeq:t.frameSeq,mode:t.frameMode||t.mode||t.codec||t.mimeType,width:M,height:b,byteLength:t.byteLength,queuedForMs:0,decodedForMs:0,scheduledForMs:0,drawMs:Math.max(0,x-A),queueSize:0,renderQueueSize:0,droppedForLatency:0,h264DecodeAcceleration:Fr.h264DecodeAcceleration,decoderLabel:"image",decoderFlushCount:0,decoderTimestampFallbacks:0,decoderInputCount:0,decoderOutputCount:0,targetPaintIntervalMs:0,canvasPresentation:"sync",interactiveBufferWaitCount:0,interactiveBufferWaitMs:0,interactiveQueueDrainCount:0,visualHash:E.visualHash,visualChanged:E.visualChanged,paintedAt:x})}k.close()}function eS(e){queueMicrotask(e)}function tS(e){return e?(e.width=0,e.height=0,!0):!1}function Fl(e,t){if(!e)return!1;try{t?.(e)}finally{tS(e)}return!0}function Kd(e,t){if(!e||!t)return 0;const a=Math.max(0,Number(e.get(t)||0))+1;return e.set(t,a),a}function nS(e,t){if(!e||!t)return 0;const a=Number(e.get(t)||0);return Number.isSafeInteger(a)&&a>0?a:Kd(e,t)}function wf(e,t){return Kd(e,t)}function Sf(e,t,a){return!!e&&!!t&&Number(a)>0&&Number(e.get(t)||0)===Number(a)}function rS(e,t,a){if(!e||!e.has(t))return!1;const r=e.get(t);return e.delete(t),Fl(r,a)}function aS(e,t,a){const r=new Set;for(const c of e||[])if(c){for(const u of c.values())u&&r.add(u);c.clear()}for(const c of t||[])c&&r.add(c);for(const c of r)Fl(c,a);return r.size}function oS(e,{isCurrent:t,dispose:a,schedule:r=eS}){return!e||typeof t!="function"?!1:(r(()=>{t(e)||Fl(e,a)}),!0)}const iS=new Uint8Array(0);function So(e){if(!e||typeof e!="object")return e;const t=e.payload;return t instanceof Uint8Array&&t.byteLength===0?e:{...e,payload:iS}}function sS(e,t){const a=So(t);return e.set(t.deviceId,a),a}function cS(e,t){for(const[a,r]of t.entries())e.set(a,So(r));return t.clear(),new Map(e)}function rl(e){return!!e&&typeof e=="object"}function td(e){let t=e;return rl(t)&&"data"in t&&(t=t.data),rl(t)&&"session"in t&&(t=t.session),!rl(t)||typeof t.access_token!="string"||!t.access_token||!rl(t.user)||typeof t.user.id!="string"||!t.user.id?null:t}function mx(e){return e?.access_token?e.refresh_token?"":"refresh-token-required":"access-token-required"}const Cf=Object.freeze(["nativeCaptureTelemetryAvailable","nativeCaptureTelemetryVersion","nativeEncoderHardwareAccelerationKnown","nativeEncoderHardwareAccelerated","nativeEncoderHardwareQueryStatus","nativeCaptureDisplayId","nativeCaptureFps","nativeCompressionFps","nativeEncodedFps","nativeCaptureSampleCount","nativeEncodableFrameCount","nativeSkippedFrameCount","nativeCompressionOutputCount","nativeEncodedFrameCount","nativeEncodeFramesInFlight","nativeEncodePendingFrameCount","nativeEncodeTimestampOwnerCount","nativeEncodeTimestampOwnerHighWatermark","nativeBackpressureCoalescedFrameCount","nativeBackpressureSkippedFrameCount","nativeEncodePendingReplacedFrameCount","nativeIdleSkippedFrameCount","nativeVideoToolboxActiveSessionCount","nativeVideoToolboxSessionHighWatermark","nativeOutputQueueDepth","nativeOutputQueueBytes","nativeOutputQueueOldestAgeMs","nativeOutputQueueHighWatermark","nativeOutputQueueDroppedCount","nativeOutputQueueAwaitingKeyFrame","nativeCopyTelemetryAvailable","nativeAnnexBAccessUnitAllocationCount","nativeAnnexBPayloadCopyCount","nativeAnnexBPayloadCopiedBytes","nativeAndPipeResidenceAgeMs","pipePayloadAllocationCount","pipePayloadCopyCount","pipePayloadCopiedBytes","handoffDroppedFrameCount","handoffRecoveryKeyFrameRequestCount","handoffOldestFrameAgeMs","nativeCaptureResourceTelemetryAvailable","nativeCaptureTelemetryAt"]),lS=Object.freeze(["nativeEncodeFramesInFlight","nativeEncodePendingFrameCount","nativeEncodeTimestampOwnerCount","nativeEncodeTimestampOwnerHighWatermark","nativeBackpressureCoalescedFrameCount","nativeBackpressureSkippedFrameCount","nativeEncodePendingReplacedFrameCount","nativeIdleSkippedFrameCount","nativeVideoToolboxActiveSessionCount","nativeVideoToolboxSessionHighWatermark","nativeOutputQueueDepth","nativeOutputQueueBytes","nativeOutputQueueOldestAgeMs","nativeOutputQueueHighWatermark","nativeOutputQueueDroppedCount","nativeOutputQueueAwaitingKeyFrame","nativeCopyTelemetryAvailable","nativeAnnexBAccessUnitAllocationCount","nativeAnnexBPayloadCopyCount","nativeAnnexBPayloadCopiedBytes","nativeAndPipeResidenceAgeMs","pipePayloadAllocationCount","pipePayloadCopyCount","pipePayloadCopiedBytes","handoffDroppedFrameCount","handoffRecoveryKeyFrameRequestCount","handoffOldestFrameAgeMs"]);function uS(e){return[String(e?.deviceId||""),String(e?.sessionId||""),String(e?.streamId||""),String(e?.commandId||""),String(Number(e?.captureGeneration||0)||0),String(Number.isFinite(Number(e?.monitorIndex))?Number(e.monitorIndex):-1),String(e?.streamPurpose||"")].join("\0")}function dS(e,t){return!!t&&String(e?.deviceId||"")===String(t.deviceId||"")&&String(e?.sessionId||"")===String(t.sessionId||"")&&String(e?.streamId||"")===String(t.streamId||"")&&String(e?.commandId||"")===String(t.commandId||"")&&(Number(e?.captureGeneration||0)||0)===(Number(t.captureGeneration||0)||0)&&(Number.isFinite(Number(e?.monitorIndex))?Number(e.monitorIndex):-1)===(Number.isFinite(Number(t.monitorIndex))?Number(t.monitorIndex):-1)&&String(e?.streamPurpose||"")===String(t.streamPurpose||"")}function mS(){return{ownerKey:"",values:Object.create(null)}}function kf(e){e&&(e.ownerKey="",e.values=Object.create(null))}function pS(e,t,a){if(!e||!t||!dS(e,a))return!1;const r=uS(a);if(t.ownerKey!==r&&(t.ownerKey=r,t.values=Object.create(null)),e.nativeCaptureTelemetryAvailable===!1){for(const c of Cf)c!=="nativeCaptureTelemetryAvailable"&&(delete t.values[c],delete e[c]);return t.values.nativeCaptureTelemetryAvailable=!1,!0}if(e.nativeCaptureResourceTelemetryAvailable===!1)for(const c of lS)delete t.values[c],delete e[c];for(const c of Cf)Object.prototype.hasOwnProperty.call(e,c)?t.values[c]=e[c]:Object.prototype.hasOwnProperty.call(t.values,c)&&(e[c]=t.values[c]);return!0}const jg=new ArrayBuffer(0);function fS(e){return`${String(e?.streamId||"")}:${Number(e?.frameSeq||0)}`}function hS(e){return!e||typeof e!="object"||e.payload instanceof ArrayBuffer&&e.payload.byteLength===0?e:{...e,payload:jg}}function gS(){let e=null,t="";return{accept(a){e=hS(a)},publish(){const a=e;if(e=null,!a)return null;const r=fS(a);return r===t?null:(t=r,a)},clear(){e=null,t=""},inspect(){return{pending:e?1:0,pendingPayloadBytes:Number(e?.payload?.byteLength||0),publishedKey:t}}}}const bS=0,vS=1,Mf=3,xf=Object.freeze([750,1500,3e3,5e3]);function mn(e){return Math.max(0,Math.floor(Number(e)||0))}function Zn(e,t){return!t||t.active||t.socket!==null||t.audioContext!==null||t.reconnectTimer!==null||t.statsTimer!==null||t.scheduledSourceCount!==0||t.pendingDecodeCount!==0||t.workletNodeCount!==0||t.workletPortCount!==0||t.pcmRingCapacityBytes!==0||t.pcmRingBufferedBytes!==0||t.pendingWorkletPacketCount!==0||t.pendingWorkletPacketBytes!==0||t.retainedFrameCount!==0||t.retainedPayloadBytes!==0?!1:e.delete(t)}function yS(){const e=new Set;let t=null;const a={ownerCount:0,socketCount:0,audioContextCount:0,workletNodeCount:0,workletPortCount:0},r=()=>{let c=0,u=0,p=0,h=0;for(const f of e){const k=Number(f.socket?.readyState);c+=f.socket&&k!==Mf?1:0,u+=f.audioContext===null?0:1,p+=mn(f.workletNodeCount),h+=mn(f.workletPortCount)}a.ownerCount=Math.max(a.ownerCount,e.size),a.socketCount=Math.max(a.socketCount,c),a.audioContextCount=Math.max(a.audioContextCount,u),a.workletNodeCount=Math.max(a.workletNodeCount,p),a.workletPortCount=Math.max(a.workletPortCount,h)};return{createOwner({deviceId:c,socket:u,audioContext:p,reconnectTimer:h=null,statsTimer:f=null}){t=null;const k={deviceId:String(c||""),active:!0,socket:u||null,audioContext:p||null,reconnectTimer:h,statsTimer:f,scheduledSourceCount:0,pendingDecodeCount:0,workletNodeCount:0,workletPortCount:0,workletNodeCreateCount:0,pcmRingCapacityBytes:0,pcmRingBufferedBytes:0,pendingWorkletPacketCount:0,pendingWorkletPacketBytes:0,pendingWorkletPacketHighWater:0,pendingWorkletByteHighWater:0,retainedFrameCount:0,retainedPayloadBytes:0};return e.add(k),r(),k},recordTerminalFailure(c,u,p="playback"){return e.has(c)?(t={deviceId:c.deviceId,phase:String(p||"playback").slice(0,64),message:String(u||"Remote audio playback failed.").slice(0,512)},!0):!1},deactivate(c){return e.has(c)?(c.active=!1,Zn(e,c)):!1},setSocket(c,u){return e.has(c)?(c.socket=u||null,r(),Zn(e,c)):!1},setAudioContext(c,u){return e.has(c)?(c.audioContext=u||null,r(),Zn(e,c)):!1},setReconnectTimer(c,u){return e.has(c)?(c.reconnectTimer=u??null,Zn(e,c)):!1},setStatsTimer(c,u){return e.has(c)?(c.statsTimer=u??null,Zn(e,c)):!1},setScheduledSourceCount(c,u){return e.has(c)?(c.scheduledSourceCount=mn(u),Zn(e,c)):!1},setPendingDecodeCount(c,u){return e.has(c)?(c.pendingDecodeCount=mn(u),Zn(e,c)):!1},setWorkletNode(c,u,p,h=c?.workletNodeCreateCount){return e.has(c)?(c.workletNodeCount=mn(u),c.workletPortCount=mn(p),c.workletNodeCreateCount=mn(h),r(),Zn(e,c)):!1},setPcmRing(c,u,p){return e.has(c)?(c.pcmRingCapacityBytes=mn(u),c.pcmRingBufferedBytes=Math.min(c.pcmRingCapacityBytes,mn(p)),Zn(e,c)):!1},setPendingWorkletPackets(c,u,p,h=c?.pendingWorkletPacketHighWater,f=c?.pendingWorkletByteHighWater){return e.has(c)?(c.pendingWorkletPacketCount=mn(u),c.pendingWorkletPacketBytes=mn(p),c.pendingWorkletPacketHighWater=Math.max(c.pendingWorkletPacketHighWater,mn(h)),c.pendingWorkletByteHighWater=Math.max(c.pendingWorkletByteHighWater,mn(f)),Zn(e,c)):!1},setRetainedFrame(c,u,p=0){return e.has(c)?(c.retainedFrameCount=mn(u),c.retainedPayloadBytes=mn(p),Zn(e,c)):!1},releaseIfDrained(c){return Zn(e,c)},hasOwner(c){return e.has(c)},snapshot(){const c=[...e].map(p=>{const h=Number(p.socket?.readyState),f=p.socket&&h!==Mf?1:0;return{deviceId:p.deviceId,active:p.active,socketCount:f,openSocketCount:h===vS?1:0,connectingSocketCount:h===bS?1:0,audioContextCount:p.audioContext===null?0:1,reconnectTimerCount:p.reconnectTimer===null?0:1,statsTimerCount:p.statsTimer===null?0:1,scheduledSourceCount:p.scheduledSourceCount,pendingDecodeCount:p.pendingDecodeCount,workletNodeCount:p.workletNodeCount,workletPortCount:p.workletPortCount,workletNodeCreateCount:p.workletNodeCreateCount,pcmRingCapacityBytes:p.pcmRingCapacityBytes,pcmRingBufferedBytes:p.pcmRingBufferedBytes,pendingWorkletPacketCount:p.pendingWorkletPacketCount,pendingWorkletPacketBytes:p.pendingWorkletPacketBytes,pendingWorkletPacketHighWater:p.pendingWorkletPacketHighWater,pendingWorkletByteHighWater:p.pendingWorkletByteHighWater,retainedFrameCount:p.retainedFrameCount,retainedPayloadBytes:p.retainedPayloadBytes}}),u=p=>c.reduce((h,f)=>h+mn(f[p]),0);return{ownerCount:c.length,activeOwnerCount:c.filter(p=>p.active).length,socketCount:u("socketCount"),openSocketCount:u("openSocketCount"),connectingSocketCount:u("connectingSocketCount"),audioContextCount:u("audioContextCount"),reconnectTimerCount:u("reconnectTimerCount"),statsTimerCount:u("statsTimerCount"),scheduledSourceCount:u("scheduledSourceCount"),pendingDecodeCount:u("pendingDecodeCount"),workletNodeCount:u("workletNodeCount"),workletPortCount:u("workletPortCount"),workletNodeCreateCount:u("workletNodeCreateCount"),pcmRingCapacityBytes:u("pcmRingCapacityBytes"),pcmRingBufferedBytes:u("pcmRingBufferedBytes"),pendingWorkletPacketCount:u("pendingWorkletPacketCount"),pendingWorkletPacketBytes:u("pendingWorkletPacketBytes"),pendingWorkletPacketHighWater:u("pendingWorkletPacketHighWater"),pendingWorkletByteHighWater:u("pendingWorkletByteHighWater"),retainedFrameCount:u("retainedFrameCount"),retainedPayloadBytes:u("retainedPayloadBytes"),ownerHighWater:a.ownerCount,socketHighWater:a.socketCount,audioContextHighWater:a.audioContextCount,workletNodeHighWater:a.workletNodeCount,workletPortHighWater:a.workletPortCount,lastTerminalFailure:t,owners:c}}}}function wS(e){const t=Math.max(0,Math.floor(Number(e)||0));return xf[Math.min(t,xf.length-1)]}function SS({schedule:e=(c,u)=>setTimeout(c,u),cancel:t=c=>clearTimeout(c),onTimerChange:a=()=>{},onReconnect:r=()=>{}}={}){let c=null,u=null,p=null,h=0,f=!1;const k=()=>{if(p===null)return!1;const b=p;return p=null,t(b),a(null),!0},M={replaceSocket(b){return f||!b?!1:(c=b,u=null,!0)},isCurrent(b){return!f&&c===b},markHealthy(b){return M.isCurrent(b)?(h=0,!0):!1},isTerminalSocket(b){return f&&u===b},retireTerminalSocket(b){return M.isTerminalSocket(b)?(u=null,!0):!1},scheduleReconnect(b){if(!M.isCurrent(b)||p!==null)return!1;const T=wS(h);h+=1;let A=null;return A=e(()=>{if(p===A&&(p=null,a(null),!!M.isCurrent(b)))try{r(b)}catch{M.scheduleReconnect(b)}},T),p=A,a(A),!0},stop(){return f?!1:(f=!0,k(),u=c,c=null,!0)},inspect(){return Object.freeze({active:!f,hasSocket:c!==null,hasTerminalSocket:u!==null,reconnectTimerCount:p===null?0:1,reconnectAttempt:h})}};return M}function Rf({reconnectOwner:e,lifecycleLedger:t,lifecycleOwner:a,socket:r}){const c=e?.isCurrent?.(r)===!0,u=e?.isTerminalSocket?.(r)===!0;return!c&&!u||u&&e.retireTerminalSocket(r)!==!0?"stale":(t?.setSocket?.(a,null),c?"current":"terminal")}const Ot=yS();function CS(){let e=Promise.resolve(),t=0,a=0,r=0;return{acquire(c){const u=++r;let p=!1,h=!1,f=!1,k;const M=new Promise(x=>{k=x}),b=Promise.resolve(e).catch(()=>{});e=b.then(()=>M);const T=()=>f?!1:(f=!0,p&&(t=Math.max(0,t-1)),k(),!0),A=b.then(async()=>{if(h||f)return T(),null;p=!0,t+=1,a=Math.max(a,t);try{return await c({ownerId:u,release:T})}catch(x){throw T(),x}});return{ownerId:u,ready:A,release:T,cancel(){h=!0,p||T()}}},snapshot(){return{activeOwnerCount:t,ownerHighWater:a,nextOwnerId:r}}}}const kS=CS(),Af=1e3;function MS({enabled:e,now:t,lastPublishedAt:a,intervalMs:r=Af}){if(!e)return!1;const c=Math.max(0,Number(t)||0),u=Math.max(0,Number(a)||0),p=Math.max(1,Number(r)||Af);return u<=0||c-u>=p}const Bg="livedesk-remote-audio-v1",xS=250,RS=160,Nd=4;function AS(e){const t=String(e||"").toLowerCase();return t.includes("audio/pcm")||t.includes("f32le")||t.includes("s16le")}function Fd(e={},t={}){const a=String(t.deviceId||""),r=String(t.streamId||"");return!!a&&!!r&&String(e.deviceId||"")===a&&String(e.streamId||"")===r}function IS(e={},t={}){if(!Fd(e,t))return{accepted:!1,reason:"owner-mismatch",nextFrameSeq:Math.max(0,Math.floor(Number(t.lastFrameSeq)||0))};const a=Math.max(0,Math.floor(Number(e.frameSeq)||0)),r=Math.max(0,Math.floor(Number(t.lastFrameSeq)||0));return a>0&&a<=r?{accepted:!1,reason:"sequence-not-newer",nextFrameSeq:r}:{accepted:!0,reason:"",nextFrameSeq:a}}function TS(e={}){const t=String(e.capturePhase||"").toLowerCase(),a=String(e.backendKind||"").toLowerCase(),r=e.captureAlive===!0?!0:e.captureAlive===!1?!1:null,c=e.helperAlive===!0?!0:e.helperAlive===!1?!1:null,u=Math.max(0,Math.floor(Number(e.helperPid)||0)),p=a==="windows-wasapi-in-process",h=a==="macos-screencapturekit-helper"||a==="linux-system-audio-helper",f=p||h,k=e.helperRequired===!0?!0:e.helperRequired===!1?!1:h?!0:p?!1:null,M=k===!1?!0:k===!0?c===!0&&u>0:!1,b=t==="starting"||t==="capture-active-awaiting-current-pcm",T=t==="active"&&r===!0&&f&&M,A=t==="failed"||t==="stopped"||r===!1||t==="active"&&(!f||!M);let x="";return b?x="awaiting-current-pcm":!p&&!h?x="backend-unknown":t!=="active"?x=t?`phase-${t}`:"phase-unknown":r!==!0?x="capture-not-alive":k===!0&&c!==!0?x="external-helper-not-alive":k===!0&&u<=0&&(x="external-helper-pid-missing"),{capturePhase:t,backendKind:a,captureAlive:r,helperAlive:c,helperPid:u,helperRequired:k,inProcessBackend:p,externalHelperBackend:h,backendKnown:f,helperReady:M,awaitingCurrentPcm:b,healthy:T,failed:A,reason:x}}function Ea(e,t){const a=Math.floor(Number(e));return Number.isFinite(a)&&a>0?a:t}function Yd(e={}){const t=Math.max(8e3,Math.min(192e3,Ea(e.sampleRate,48e3))),a=Math.max(1,Math.min(8,Ea(e.channels,2))),r=String(e.mimeType||"").toLowerCase(),u=String(e.sampleFormat||"").toLowerCase()==="s16le"||r.includes("s16le")||r.includes("audio/l16")?"s16le":"f32le";return{sampleRate:t,channels:a,sampleFormat:u}}function Qd(e={}){const t=Yd(e),a=Math.max(1,Math.min(250,Ea(e.maxDurationMs,250))),r=Math.max(1,Math.ceil(t.sampleRate*a/1e3));return{...t,maxDurationMs:a,capacityFrames:r,capacityBytes:r*t.channels*Float32Array.BYTES_PER_ELEMENT}}function PS(e={}){const t=Qd(e),a=Math.max(0,Math.min(t.maxDurationMs,Ea(e.targetLeadMs,160))),r=Math.min(t.capacityFrames,Math.max(1,Math.ceil(t.sampleRate*a/1e3)));let c=new Float32Array(t.capacityFrames*t.channels),u=0,p=0,h=0,f=0,k=!1,M=!1,b=0,T=0,A=0;const x={acceptedFrames:0,droppedFrames:0},E=()=>(A+=1,{sampleRate:t.sampleRate,channels:t.channels,sampleFormat:t.sampleFormat,maxDurationMs:t.maxDurationMs,targetLeadMs:a,capacityFrames:M?0:t.capacityFrames,capacityBytes:M?0:t.capacityBytes,bufferedFrames:M?0:h,bufferedBytes:M?0:h*t.channels*Float32Array.BYTES_PER_ELEMENT,bufferedMs:M?0:h*1e3/t.sampleRate,droppedFrames:b,underflowCount:T,started:!M&&k,disposed:M}),B=()=>{u=0,p=0,h=0,f=0,k=!1},q=()=>{M||(B(),c=new Float32Array(0),M=!0)},G=(O,ie=0,J,de=t.sampleFormat)=>{if(x.acceptedFrames=0,x.droppedFrames=0,M||!(O instanceof ArrayBuffer))return x;const se=Math.max(0,Math.floor(Number(ie)||0)),pe=Math.max(0,O.byteLength-se),ce=Math.min(pe,Math.max(0,Math.floor(Number(J??pe)||0))),W=de==="s16le",ee=W?2:4,L=ee*t.channels,_=Math.floor(ce/L);if(_<=0)return x;const K=Math.min(_,t.capacityFrames),ue=_-K,P=Math.max(0,h+K-t.capacityFrames);P>0&&(u=(u+P)%t.capacityFrames,h-=P);const N=ue+P;b+=N;const te=new DataView(O,se,ce);for(let we=ue;we<_;we+=1){const me=p*t.channels,Fe=we*t.channels;for(let H=0;H<t.channels;H+=1){const Se=(Fe+H)*ee,Ce=W?te.getInt16(Se,!0)/32768:te.getFloat32(Se,!0);c[me+H]=Number.isFinite(Ce)?Math.max(-1,Math.min(1,Ce)):0}p=(p+1)%t.capacityFrames}return h+=K,!k&&h>=r&&(k=!0),x.acceptedFrames=K,x.droppedFrames=N,x};return{writePcm:(O={})=>G(O.buffer,O.byteOffset,O.byteLength,O.sampleFormat),writePcmBuffer:G,readToChannels:(O,ie=t.sampleRate)=>{if(!Array.isArray(O)||O.length===0)return;let J=Number.POSITIVE_INFINITY;for(let pe=0;pe<O.length;pe+=1){const ce=O[pe];J=Math.min(J,ce?.length||0)}if(M||!Number.isFinite(J)||J<=0||!k){for(let pe=0;pe<O.length;pe+=1)O[pe]?.fill?.(0);return}const de=Math.max(8e3,Math.min(192e3,Ea(ie,t.sampleRate))),se=t.sampleRate/de;for(let pe=0;pe<J;pe+=1){if(h<=0){k=!1,T+=1,f=0;for(let ee=0;ee<O.length;ee+=1)O[ee].fill(0,pe);break}const ce=u*t.channels;for(let ee=0;ee<O.length;ee+=1){const L=Math.min(ee,t.channels-1);O[ee][pe]=c[ce+L]}f+=se;const W=Math.min(h,Math.floor(f));W>0&&(u=(u+W)%t.capacityFrames,h-=W,f-=W)}},flush:B,dispose:q,snapshot:E,getSnapshotCount:()=>A}}function ES(e={}){const t=Math.max(1,Math.min(Nd,Ea(e.maxPendingPackets,Nd))),a=Math.max(1,Ea(e.maxPendingBytes,1)),r=new Map;let c=0,u=0,p=0,h=0,f=0,k=!1;const M=()=>({terminal:k,maxPendingPackets:t,maxPendingBytes:a,pendingPacketCount:r.size,pendingPacketBytes:c,pendingPacketHighWater:u,pendingByteHighWater:p,acceptedCount:h,droppedCount:f});return{claim(b,T){const A=typeof b=="number"&&Number.isFinite(b)?b:String(b||""),x=Math.max(0,Math.floor(Number(T)||0));return k||!A||x<=0||r.has(A)||r.size>=t||c+x>a?(f+=1,!1):(r.set(A,x),c+=x,u=Math.max(u,r.size),p=Math.max(p,c),h+=1,!0)},acknowledge(b){const T=typeof b=="number"&&Number.isFinite(b)?b:String(b||""),A=r.get(T);return A===void 0?!1:(r.delete(T),c=Math.max(0,c-A),!0)},terminate(){return r.clear(),c=0,k=!0,M()},getPendingPacketCount:()=>r.size,getPendingPacketBytes:()=>c,getPendingPacketHighWater:()=>u,getPendingByteHighWater:()=>p,snapshot:M}}function Dl(e,t){const a=String(e?.name||"");if(!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(a)||!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(t))throw new Error("Remote Audio worklet function binding name is invalid.");const r=`const ${a} = ${Function.prototype.toString.call(e)};`;return a===t?r:`${r}
|
|
4
4
|
const ${t} = ${a};`}const NS=Dl(Ea,"positiveInteger"),FS=Dl(Yd,"normalizeRemoteAudioPcmFormat"),DS=Dl(Qd,"remoteAudioPcmRingCapacity"),LS=Dl(PS,"createRemoteAudioPcmRing"),OS=`
|
|
5
5
|
const REMOTE_AUDIO_PCM_RING_MAX_MS = ${xS};
|
|
@@ -177,6 +177,6 @@ ${se?.id||""}
|
|
|
177
177
|
${se?.currentUserRole||""}`:"",Se=s.useRef({key:R,generation:0});Se.current.key!==R&&(Se.current={key:R,generation:Se.current.generation+1});const[Ce,Ve]=s.useState(!1),[Ze,_e]=s.useState(""),[z,Me]=s.useState(null),[Be,Ge]=s.useState(!1),[xt,Pe]=s.useState(""),[He,Y]=s.useState(se?.name||""),[ve,st]=s.useState(""),it=()=>({...Se.current}),bt=oe=>Se.current.generation===oe.generation&&Se.current.key===oe.key&&oe.key===R,Rt=dl[p],ae=s.useMemo(()=>!Number.isFinite(k)||k<=0?0:Math.min(100,Math.round(f/k*100)),[f,k]),$=()=>{Se.current={key:"",generation:Se.current.generation+1},pe()};if(H.current=$,s.useEffect(()=>{if(!e)return;Fe.current=document.activeElement instanceof HTMLElement?document.activeElement:null;const oe=window.requestAnimationFrame(()=>me.current?.focus()),Ee=We=>{if(We.key==="Escape"){We.preventDefault(),H.current();return}if(We.key!=="Tab"||!we.current)return;const vt=Array.from(we.current.querySelectorAll('button:not([disabled]), a[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'));if(vt.length===0){We.preventDefault(),we.current.focus();return}const et=vt[0],Tt=vt[vt.length-1];We.shiftKey&&document.activeElement===et?(We.preventDefault(),Tt.focus()):!We.shiftKey&&document.activeElement===Tt&&(We.preventDefault(),et.focus())};return window.addEventListener("keydown",Ee),()=>{window.cancelAnimationFrame(oe),window.removeEventListener("keydown",Ee),Fe.current?.focus(),Fe.current=null}},[e]),s.useEffect(()=>{Me(null),_e(""),Ge(!1),Pe(""),Ve(!1),st(""),Y(se?.name||"")},[R,se?.name]),s.useEffect(()=>{ve||Y(se?.name||"")},[ve,se?.name]),!e)return null;const ye=async()=>{if(!K||Ce||x||!R)return;const oe=it(),Ee=()=>bt(oe);Ve(!0),_e(""),Ge(!1);try{const We=await K(xt);if(!Ee())return;if(!We?.url)throw new Error("The invite link was not returned.");Me(We),Pe("")}catch(We){if(!Ee())return;_e(We instanceof Error?We.message:"The invite link could not be created.")}finally{Ee()&&Ve(!1)}},V=async()=>{if(!N||ve)return;const oe=it(),Ee=He.trim();if(!Ee){_e("Enter a Team Space name.");return}st("rename"),_e("");try{if(await N(Ee),!bt(oe))return}catch(We){if(!bt(oe))return;_e(We instanceof Error?We.message:"The Team Space could not be renamed.")}finally{bt(oe)&&st("")}},Ke=async()=>{if(!te||ve)return;const oe=it();st("leave"),_e("");try{if(await te(),!bt(oe))return;$()}catch(Ee){if(!bt(oe))return;_e(Ee instanceof Error?Ee.message:"The Team Space could not be left.")}finally{bt(oe)&&st("")}},Ct=async oe=>{if(ve)return;const Ee=it(),We=oe.status==="invited"?P:ue;if(We){st(`member:${oe.id}`),_e("");try{if(await We(oe.id),!bt(Ee))return}catch(vt){if(!bt(Ee))return;_e(vt instanceof Error?vt.message:"The Team member could not be changed.")}finally{bt(Ee)&&st("")}}},I=async()=>{if(z?.url)try{await navigator.clipboard.writeText(z.url),Ge(!0),window.setTimeout(()=>Ge(!1),1800)}catch{_e("Copy failed. Select and copy the invite link manually.")}};return i.jsx("div",{className:"account-dialog-backdrop",role:"presentation",onPointerDown:oe=>{oe.currentTarget===oe.target&&$()},children:i.jsxs("section",{id:"vuvodesk-account-dialog",ref:we,className:"account-dialog",role:"dialog","aria-modal":"true","aria-labelledby":"account-dialog-title",tabIndex:-1,onPointerDown:oe=>oe.stopPropagation(),children:[i.jsxs("header",{className:"account-dialog-header",children:[i.jsxs("div",{className:"account-dialog-identity",children:[i.jsx("span",{className:"account-dialog-avatar",children:t&&u?i.jsx("img",{src:u,alt:"",referrerPolicy:"no-referrer"}):t?i.jsx("span",{children:c}):i.jsx(kl,{size:21,"aria-hidden":"true"})}),i.jsxs("span",{children:[i.jsx("small",{children:"VuvoDesk account"}),i.jsx("strong",{id:"account-dialog-title",children:t?a:"Sign in to manage VuvoDesk"}),i.jsx("span",{children:r||"Your computers and plan stay with your account."})]})]}),i.jsx("button",{ref:me,className:"account-dialog-close",onClick:$,type:"button","aria-label":"Close account",children:i.jsx(xa,{size:20,"aria-hidden":"true"})})]}),i.jsxs("div",{className:"account-dialog-body",children:[ie&&i.jsxs("div",{className:"account-session-revocation-error",role:"alert",children:[i.jsx("strong",{children:"Hub sign-out is not confirmed"}),i.jsx("span",{children:"Wall and Control stay blocked. Retry when the Hub is reachable so its browser permission is removed."}),ee&&i.jsx("button",{onClick:()=>{ee()},disabled:A,type:"button",children:A?"Retrying…":"Retry Hub sign-out"})]}),O&&i.jsxs("section",{className:"account-workspace-switcher","aria-labelledby":"account-workspace-title","aria-busy":x,children:[i.jsxs("div",{children:[i.jsx("span",{id:"account-workspace-title",children:"Workspaces"}),i.jsx("small",{children:"Keep Personal separate from every Team you join."})]}),i.jsx("div",{className:"account-workspace-list",children:J.map(oe=>i.jsxs("button",{className:oe.id===de?"active":"",onClick:()=>{oe.id!==de&&_?.(oe.id)},disabled:x||oe.id!==de&&!_,"aria-pressed":oe.id===de,type:"button",children:[i.jsx("span",{children:oe.kind==="team"?i.jsx(Ts,{size:15,"aria-hidden":"true"}):i.jsx(Xh,{size:15,"aria-hidden":"true"})}),i.jsxs("span",{children:[i.jsx("strong",{children:oe.name}),i.jsx("small",{children:oe.kind==="team"?oe.role==="operator"?"Operator · Wall and Control":oe.memberCount===void 0?"Owner · Team Space":`Owner · ${oe.memberCount} people`:"Personal workspace"})]}),i.jsx("em",{children:dl[oe.plan].shortName})]},oe.id))})]}),i.jsxs("section",{className:`account-current-plan plan-${p}`,"aria-label":h?"Current VuvoDesk plan":"VuvoDesk plan policy",children:[i.jsxs("div",{className:"account-current-plan-copy",children:[i.jsx("span",{className:"account-current-plan-icon",children:sh(p)}),i.jsxs("span",{children:[i.jsx("small",{children:h?"Current plan":"Plan policy"}),i.jsx("strong",{children:h?Rt.name:"Plan is managed at the Hub"}),i.jsx("span",{children:M})]})]}),i.jsxs("div",{className:"account-device-usage",children:[i.jsxs("span",{children:[i.jsx(Aa,{size:15,"aria-hidden":"true"})," ",h?"Computer usage":"This Client computer"]}),i.jsxs("strong",{children:[f," ",h&&i.jsxs("small",{children:["/ ",ih(k)]})]}),h&&Number.isFinite(k)&&i.jsx("span",{className:"account-device-meter","aria-label":`${f} of ${ih(k)} computers used`,children:i.jsx("i",{style:{width:`${ae}%`}})})]}),i.jsxs("dl",{className:"account-runtime-facts",children:[i.jsxs("div",{children:[i.jsx("dt",{children:"Hub"}),i.jsx("dd",{children:b})]}),i.jsxs("div",{children:[i.jsx("dt",{children:"Remote access"}),i.jsx("dd",{children:T})]})]})]}),i.jsxs("section",{className:"account-plan-section","aria-labelledby":"account-plan-section-title",children:[i.jsxs("div",{className:"account-section-heading",children:[i.jsxs("div",{children:[i.jsx("span",{children:"License and features"}),i.jsx("h2",{id:"account-plan-section-title",children:"One account, the right way to manage your computers"})]}),i.jsx("small",{children:"Team members never share a Google login."})]}),i.jsx("div",{className:"account-plan-grid",children:Object.keys(dl).map(oe=>{const Ee=dl[oe],We=h&&p===oe,vt=h&&ah[oe]<ah[p],et=ne&&!We&&!vt&&oe!=="free";return i.jsxs("article",{className:`account-plan-card plan-${oe} ${We?"current":""}`,children:[i.jsxs("div",{className:"account-plan-card-title",children:[i.jsxs("span",{children:[sh(oe)," ",Ee.name]}),We&&i.jsxs("em",{children:[i.jsx(bl,{size:13,"aria-hidden":"true"})," Current"]})]}),i.jsx("p",{children:Ee.audience}),i.jsx("span",{className:"account-plan-price",children:Ee.price}),Ee.ltdPrice&&i.jsxs("span",{className:"account-plan-ltd-price",children:[Ee.ltdPrice," · one-time"]}),i.jsx("strong",{children:Ee.deviceText}),i.jsx("ul",{children:Ee.features.map(Tt=>i.jsxs("li",{children:[i.jsx(bl,{size:14,"aria-hidden":"true"})," ",Tt]},Tt))}),We||vt||oe==="free"||!ne?i.jsx("span",{className:"account-plan-state",children:We?"Your current plan":vt?"Included in your plan":!ne&&oe!=="free"?re:"Free plan"}):oe==="plus"||oe==="business"?i.jsxs("div",{className:"account-plan-actions",children:[i.jsxs("button",{className:"account-plan-action secondary",onClick:()=>{L(oe==="plus"?"plus_monthly":"pro_monthly")},disabled:!et||!q||A||x||E,type:"button",children:[i.jsx(Ra,{size:15,"aria-hidden":"true"}),ne?q?`Choose ${Ee.billingName} · ${Ee.price}`:"Monthly · Coming soon":re]}),i.jsxs("button",{className:"account-plan-action",onClick:()=>{L(oe==="plus"?"plus_ltd":"pro_ltd")},disabled:!et||!B||A||x||E,type:"button",children:[i.jsx(Ra,{size:15,"aria-hidden":"true"}),ne?B?`Buy ${Ee.billingName} · ${Ee.ltdPrice}`:"LTD · Coming soon":re]})]}):i.jsxs("button",{className:"account-plan-action",onClick:()=>{L("team_monthly")},disabled:!et||!G||A||x||E,type:"button",children:[i.jsx(Ts,{size:15,"aria-hidden":"true"}),ne?G?`Choose Team · ${Ee.price}`:"Team · Coming soon":re]})]},oe)})})]}),(p==="team"||se)&&i.jsxs("section",{className:"account-team-panel","aria-labelledby":"account-team-title",children:[i.jsxs("div",{className:"account-section-heading",children:[i.jsxs("div",{children:[i.jsx("span",{children:"Team Space"}),i.jsx("h2",{id:"account-team-title",children:se?.name||"Your shared computer workspace"})]}),se&&se.currentUserRole==="owner"&&i.jsxs("small",{children:[se.memberCount??se.members.length,"/",se.memberLimit," members"]})]}),se?i.jsxs(i.Fragment,{children:[se.currentUserRole==="owner"&&N&&i.jsxs("div",{className:"account-team-rename",children:[i.jsx("label",{htmlFor:"account-team-name",children:"Team Space name"}),i.jsxs("span",{children:[i.jsx("input",{id:"account-team-name",value:He,onChange:oe=>Y(oe.target.value),maxLength:80,disabled:x||!!ve}),i.jsx("button",{onClick:()=>{V()},disabled:x||!!ve||!He.trim()||He.trim()===se.name,type:"button",children:ve==="rename"?"Saving…":"Save name"})]})]}),se.currentUserRole==="owner"&&i.jsx("ul",{className:"account-team-members",children:se.members.map(oe=>i.jsxs("li",{children:[i.jsx("span",{className:"account-member-avatar",children:(oe.displayName||oe.email).slice(0,1).toUpperCase()}),i.jsxs("span",{children:[i.jsx("strong",{children:oe.displayName||oe.email}),i.jsx("small",{children:oe.email})]}),i.jsx("em",{children:oe.role==="owner"?"Owner":"Operator"}),i.jsx("span",{className:`account-member-status status-${oe.status}`,children:oe.status}),se.currentUserRole==="owner"&&oe.role!=="owner"&&(oe.status==="invited"&&P||oe.status==="active"&&ue)&&i.jsx("button",{onClick:()=>{Ct(oe)},disabled:x||!!ve,type:"button","aria-label":`${oe.status==="invited"?"Cancel invitation for":"Remove"} ${oe.email}`,children:oe.status==="invited"?"Cancel":"Remove"})]},oe.id))}),se.currentUserRole==="owner"&&i.jsxs("div",{className:"account-team-invite",children:[i.jsx("label",{children:"Invite an Operator"}),z?i.jsxs("span",{className:"account-team-invite-result",children:[i.jsx("input",{"aria-label":"Team invite link",value:z.url,readOnly:!0,onFocus:oe=>oe.currentTarget.select()}),i.jsxs("button",{onClick:()=>{I()},type:"button",children:[Be?i.jsx(bl,{size:16,"aria-hidden":"true"}):i.jsx(my,{size:16,"aria-hidden":"true"}),Be?"Copied":"Copy link"]}),z.expiresAt&&i.jsxs("small",{children:["Expires ",z.expiresAt]})]}):i.jsxs("span",{className:"account-team-invite-compose",children:[i.jsx("input",{type:"email",value:xt,onChange:oe=>Pe(oe.target.value),placeholder:"operator@example.com","aria-label":"Operator Google account email",autoComplete:"email",disabled:x||!se.invitationsEnabled||se.currentUserRole!=="owner"||Ce}),i.jsxs("button",{className:"account-create-invite",onClick:()=>{ye()},type:"button",disabled:x||!K||!xt.trim()||!se.invitationsEnabled||se.currentUserRole!=="owner"||Ce,children:[i.jsx(py,{size:16,"aria-hidden":"true"}),Ce?"Creating…":"Create invite link"]})]}),i.jsx("p",{children:"Share this one-time link yourself. VuvoDesk does not email the invite."})]}),se.currentUserRole==="operator"&&i.jsx("p",{className:"account-team-operator-note",children:"Operator · Wall and Control. The owner manages settings, billing, members, files, and Agents."}),Ze&&i.jsx("small",{className:"account-team-error",role:"alert",children:Ze}),se.currentUserRole==="operator"&&te&&i.jsx("button",{className:"account-team-leave",onClick:()=>{Ke()},disabled:x||!!ve,type:"button",children:ve==="leave"?"Leaving…":"Leave this Team Space"})]}):i.jsx("p",{className:"account-team-empty",children:"Team member management will appear here as soon as this account is connected to a Team Space."})]})]}),i.jsxs("footer",{className:"account-dialog-footer",children:[i.jsxs("span",{children:[i.jsx(fy,{size:16,"aria-hidden":"true"})," Licenses belong to this VuvoDesk account, not to one computer."]}),t?i.jsxs("button",{className:"account-auth-action",onClick:()=>{W()},disabled:A,type:"button",children:[i.jsx(hy,{size:16,"aria-hidden":"true"}),"Sign out"]}):i.jsxs("button",{className:"account-auth-action primary",onClick:()=>{ce()},disabled:A,type:"button",children:[i.jsx(kl,{size:16,"aria-hidden":"true"}),"Sign in with Google"]})]})]})})}const ch=Object.freeze({plus_monthly:"ltd",plus_ltd:"ltd",pro_monthly:"pro",pro_ltd:"pro",team_monthly:"team"}),_0=new Set(["plus_monthly","pro_monthly","team_monthly"]);function j0(e){return Object.prototype.hasOwnProperty.call(ch,e)?ch[e]:null}function lh(e){return _0.has(e)}function cd(e){return e==="team_monthly"}function B0(e){let t=Promise.resolve();return a=>{const r=t.then(()=>e(a),()=>e(a));return t=r.then(()=>{},()=>{}),r}}const H0=1e3;function W0({now:e=()=>Date.now(),minimumForegroundIntervalMs:t=H0}={}){let a="",r=0,c=null,u=null,p=Number.NEGATIVE_INFINITY;const h=M=>{const b=String(M||"");b!==a&&(a=b,r+=1,c=null,u=null,p=Number.NEGATIVE_INFINITY)},f=(M,b,T)=>{const A=Promise.resolve().then(()=>a===M&&r===b?T():null);return c=A,A.finally(()=>{if(c!==A||a!==M||r!==b)return;c=null;const x=u;u=null,x&&f(M,b,x).catch(()=>{})}).catch(()=>{}),A};return Object.freeze({recover:(M,b,T)=>{const A=String(M||"");if(!A||typeof T!="function"||A!==a)return Promise.resolve(null);if(c)return b==="auth"&&(u=T),c;if(b==="foreground"){const x=Number(e());if(x-p<t)return Promise.resolve(null);p=x}return f(A,r,T)},switchOwner:h,snapshot:()=>Object.freeze({ownerKey:a,inFlight:!!c,queuedAuthRecovery:!!u,lastForegroundRecoveryAt:p})})}const Pl="team_invite",ld="vuvodesk.pending-team-invite",Ns=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,tm=/^[0-9a-f]{64}$/i,ud=[],dd=[],md=[];function Co(e){return Array.isArray(e)?e[0]||null:e||null}function Si(e,t){return new Error(String(e?.reason||t).replaceAll("-"," "))}function $0(e){if(e==null)return Number.POSITIVE_INFINITY;const t=Number(e);return Number.isFinite(t)&&t>=0?t:Number.POSITIVE_INFINITY}function uh(e,t){const a=String(e.workspace_id||"").trim(),r=String(e.workspace_kind||"").trim().toLowerCase(),c=String(e.role||"").trim().toLowerCase(),u=String(e.plan||"free").trim().toLowerCase(),p=Number(e.membership_revision||0);return!Ns.test(a)||!["personal","team"].includes(r)||!["owner","operator"].includes(c)||!["free","ltd","pro","team"].includes(u)||!Number.isSafeInteger(p)||p<1?null:{id:a,name:String(e.workspace_name||(r==="personal"?"Personal":"Team")).trim().slice(0,80),kind:r,role:c,membershipRevision:p,plan:u,entitlementStatus:String(e.entitlement_status||"free").trim().toLowerCase(),deviceLimit:$0(e.device_limit),memberLimit:Math.max(1,Number(e.member_limit||1)),commercialUse:e.commercial_use===!0,isActive:t&&e.is_active===!0}}function V0(){if(typeof window>"u")return;const e=new URL(window.location.href);e.searchParams.has(Pl)&&(e.searchParams.delete(Pl),window.history.replaceState(window.history.state,"",`${e.pathname}${e.search}${e.hash}`))}function z0(){if(typeof window>"u")return"";const e=String(new URL(window.location.href).searchParams.get(Pl)||"").trim().toLowerCase();return tm.test(e)?e:""}function U0(e,t=0){const a=e?.user?.id||"",r=a,[c,u]=Xt(r,ud),[p,h]=Xt(r,null),[f,k]=Xt(r,!!a),[M,b]=Xt(r,""),[T,A]=Xt(r,""),x=s.useRef(0),E=s.useRef(0),B=s.useRef(null),q=s.useRef(""),G=s.useRef(new Set),ne=s.useRef(a);ne.current=a;const re=s.useRef(null);re.current||(re.current=W0());const O=s.useRef(null);O.current||(O.current=B0(async W=>{if(!W.userId||ne.current!==W.userId)throw new Error("workspace selection owner changed");const{data:ee,error:L}=await Mt.rpc("set_livedesk_active_workspace",{p_workspace_id:W.workspaceId});if(L)throw L;const _=Co(ee);if(!_?.ok)throw Si(_,"workspace selection failed");return _}));const ie=s.useCallback(W=>O.current({userId:a,workspaceId:W}),[a]),J=s.useCallback(async(W="",ee=!1)=>{const L=x.current+1;x.current=L;const _=()=>x.current===L&&ne.current===a,K=ee?E.current+1:0;if(ee&&(E.current=K,B.current={token:K,workspaceId:W},q.current=""),!a)return q.current="",ee&&B.current?.token===K&&(B.current=null),u(r,ud),h(r,null),k(r,!1),b(r,""),null;k(r,!0),ee&&h(r,null);const ue=Hg({timeoutMs:8e3,code:"workspace-restore-timeout"});try{if(!_())return null;const{error:P}=await ue.waitFor(()=>Mt.rpc("ensure_livedesk_personal_workspace"));if(P)throw P;if(!_()||(ee&&await ue.waitFor(()=>ie(W)),!_()))return null;const{data:N,error:te}=await ue.waitFor(()=>Mt.rpc("list_livedesk_workspaces"));if(te)throw te;if(!_())return null;const we=(Array.isArray(N)?N:[]).map(_e=>uh(_e,!0)).filter(_e=>!!_e),me=W?we.find(_e=>_e.id===W):null,Fe=we.find(_e=>_e.isActive),H=we.find(_e=>_e.kind==="personal"&&_e.id===a),R=me||Fe||H||we[0]||null;if(!R)throw new Error("VuvoDesk did not return an accessible workspace.");if(!R.isActive&&!ee&&await ue.waitFor(()=>ie(R.id)),!_())return null;const{data:Se,error:Ce}=await ue.waitFor(()=>Mt.rpc("get_livedesk_workspace_access",{p_workspace_id:R.id}));if(Ce)throw Ce;const Ve=Co(Se);if(!Ve||Ve.ok!==!0)throw new Error(String(Ve?.reason||"workspace access denied").replaceAll("-"," "));const Ze=uh(Ve,!1);if(!Ze)throw new Error("VuvoDesk returned an invalid workspace access record.");return _()?(q.current=Ze.id,u(r,we.map(_e=>({..._e,isActive:_e.id===Ze.id}))),h(r,Ze),b(r,""),k(r,!1),Ze):null}catch(P){return _()&&(b(r,P instanceof Error?P.message:String(P)),k(r,!1)),null}finally{ue.dispose(),ee&&B.current?.token===K&&(B.current=null)}},[ie,h,b,k,u,r,a]),de=s.useCallback(()=>B.current?Promise.resolve(null):J(),[J]),se=s.useCallback(W=>{if(!a||W!=="initial"&&document.visibilityState==="hidden"||B.current||q.current)return Promise.resolve(null);const ee=r;return re.current.recover(ee,W,()=>ne.current!==a||B.current||q.current?null:J())},[J,r,a]),pe=s.useCallback(W=>!!W&&ne.current===a&&B.current===null&&q.current===W,[a]);s.useEffect(()=>{if(re.current.switchOwner(r),x.current+=1,u(r,ud),h(r,null),b(r,""),A(r,""),q.current="",B.current=null,!a){k(r,!1);return}return se("initial"),()=>{x.current+=1,re.current?.switchOwner("")}},[h,b,A,k,u,se,r,a]),s.useEffect(()=>{!a||t<1||se("auth")},[se,t,a]),s.useEffect(()=>{if(!a)return;const W=()=>{document.visibilityState!=="hidden"&&se("foreground")},ee=()=>W();return window.addEventListener("pageshow",W),window.addEventListener("online",W),window.addEventListener("focus",W),document.addEventListener("visibilitychange",ee),()=>{window.removeEventListener("pageshow",W),window.removeEventListener("online",W),window.removeEventListener("focus",W),document.removeEventListener("visibilitychange",ee)}},[se,a]),s.useEffect(()=>{const W=z0();if(W)try{window.sessionStorage.setItem(ld,W)}catch{}if(!a)return;let ee=W;if(!ee)try{ee=String(window.sessionStorage.getItem(ld)||"").trim().toLowerCase()}catch{}if(!tm.test(ee))return;const L=`${a}:${ee}`;if(G.current.has(L))return;G.current.add(L),V0();try{window.sessionStorage.removeItem(ld)}catch{}let _=!1;return(async()=>{const{data:K,error:ue}=await Mt.rpc("accept_livedesk_workspace_invite",{p_invite_token:ee});if(_)return;if(ue){A(r,ue.message);return}const P=Co(K),N=String(P?.workspace_id||"").trim();if(!P?.ok||!Ns.test(N)){A(r,Si(P,"team invite could not be accepted").message);return}const te=await J(N,!0);!_&&te&&A(r,`Joined ${te.name}.`)})(),()=>{_=!0}},[J,A,r,a]),s.useEffect(()=>{if(!a||!p?.id)return;const W=p.id,ee=`${a}-${W}`.replace(/[^a-zA-Z0-9]/g,"");let L=null;const _=()=>{L===null&&(L=window.setTimeout(()=>{L=null,pe(W)&&de()},80))},K=Mt.channel(`livedesk-workspace-session-${ee}`).on("postgres_changes",{event:"*",schema:"public",table:"livedesk_workspaces",filter:`id=eq.${W}`},_).on("postgres_changes",{event:"*",schema:"public",table:"livedesk_workspace_members",filter:`workspace_id=eq.${W}`},_).subscribe();return()=>{L!==null&&window.clearTimeout(L),Mt.removeChannel(K)}},[p?.id,pe,de,a]);const ce=s.useCallback(W=>Ns.test(String(W||"").trim())?J(W,!0):Promise.reject(new Error("Choose a valid VuvoDesk workspace.")),[J]);return{workspaces:c,activeWorkspace:p,loading:f,error:M,inviteNotice:T,refresh:de,selectWorkspace:ce,isWorkspaceActionCurrent:pe}}function q0(e,t,a,r,c){const u=e?.user?.id||"",p=t?.kind==="team"?t.id:"",h=t?.membershipRevision||0,f=`${u}
|
|
178
178
|
${p}
|
|
179
179
|
${h}`,[k,M]=Xt(f,dd),[b,T]=Xt(f,md),[A,x]=Xt(f,!1),[E,B]=Xt(f,""),q=s.useRef(0),G=`${u}
|
|
180
|
-
${p}`,ne=s.useRef(G);ne.current=G;const re=s.useCallback((pe,ce)=>{if(ne.current!==pe||!c(ce))throw new Error("The active VuvoDesk workspace changed. Please try again in the current workspace.")},[c]),O=s.useCallback(async()=>{const pe=q.current+1;q.current=pe;const ce=()=>q.current===pe;if(!u||!p){M(f,dd),T(f,md),x(f,!1),B(f,"");return}x(f,!0);try{const W=t?.role==="owner"?Mt.rpc("list_livedesk_workspace_members",{p_workspace_id:p}):Promise.resolve({data:[],error:null}),ee=t?.role==="owner"?Mt.rpc("list_livedesk_workspace_invites",{p_workspace_id:p}):Promise.resolve({data:[],error:null}),[L,_]=await Promise.all([W,ee]);if(!ce())return;if(L.error)throw L.error;if(_.error)throw _.error;M(f,(Array.isArray(L.data)?L.data:[]).map(K=>({id:String(K.user_id||""),email:String(K.email||""),displayName:String(K.display_name||""),role:String(K.role||"")==="owner"?"owner":"operator",joinedAt:String(K.joined_at||"")})).filter(K=>Ns.test(K.id))),T(f,(Array.isArray(_.data)?_.data:[]).map(K=>({id:String(K.invite_id||""),email:String(K.email||""),role:"operator",createdAt:String(K.created_at||""),expiresAt:String(K.expires_at||"")})).filter(K=>Ns.test(K.id))),B(f,""),x(f,!1)}catch(W){if(!ce())return;B(f,W instanceof Error?W.message:String(W)),x(f,!1)}},[t?.role,f,B,T,x,M,u,p]);s.useEffect(()=>(q.current+=1,M(f,dd),T(f,md),B(f,""),O(),()=>{q.current+=1}),[f,B,T,M,O,h]);const ie=s.useCallback(async pe=>{if(!p||t?.role!=="owner")throw new Error("Only the Team owner can create invitations.");const ce=G,W=String(pe||"").trim().toLowerCase();if(!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(W))throw new Error("Enter the Google account email to invite.");const{data:ee,error:L}=await Mt.rpc("invite_livedesk_workspace_member",{p_workspace_id:p,p_email:W,p_role:"operator"});if(re(ce,p),L)throw L;const _=Co(ee),K=String(_?.invite_token||"").trim().toLowerCase();if(!_?.ok||!tm.test(K))throw Si(_,"team invite creation failed");const ue=new URL("/app",window.location.origin);return ue.searchParams.set(Pl,K),re(ce,p),await Promise.all([O(),r()]),{url:ue.toString(),expiresAt:_.expires_at}},[t?.role,re,O,r,p,G]),J=s.useCallback(async pe=>{if(!p||t?.role!=="owner")throw new Error("Only the Team owner can remove members.");const ce=G,{data:W,error:ee}=await Mt.rpc("remove_livedesk_workspace_member",{p_workspace_id:p,p_user_id:pe});if(re(ce,p),ee)throw ee;const L=Co(W);if(!L?.ok)throw Si(L,"team member removal failed");let _=!0;try{await Ue(`/api/remote/workspace/members/${encodeURIComponent(pe)}/revoke`,{method:"POST",body:JSON.stringify({workspaceId:p})},a)}catch{_=!1}return re(ce,p),await Promise.all([O(),r()]),{revokedImmediately:_}},[t?.role,re,a,O,r,p,G]),de=s.useCallback(async pe=>{if(!p||t?.role!=="owner")throw new Error("Only the Team owner can revoke invitations.");const ce=G,{data:W,error:ee}=await Mt.rpc("revoke_livedesk_workspace_invite",{p_workspace_id:p,p_invite_id:pe});if(re(ce,p),ee)throw ee;const L=Co(W);if(!L?.ok)throw Si(L,"team invite revocation failed");await Promise.all([O(),r()])},[t?.role,re,O,r,p,G]),se=s.useCallback(async()=>{if(!p||t?.role!=="operator")throw new Error("Only an Operator can leave this Team Space.");const pe=G,{data:ce,error:W}=await Mt.rpc("leave_livedesk_workspace",{p_workspace_id:p});if(re(pe,p),W)throw W;const ee=Co(ce);if(!ee?.ok)throw Si(ee,"leaving team workspace failed")},[t?.role,re,p,G]);return s.useMemo(()=>({members:k,invites:b,loading:A,error:E,refresh:O,createInvite:ie,removeMember:J,revokeInvite:de,leaveWorkspace:se}),[ie,E,b,se,A,k,O,J,de])}function Jg({state:e}){return e==="ok"?i.jsx(Cn,{size:15,"aria-hidden":"true"}):i.jsx(vy,{size:15,"aria-hidden":"true"})}function dh({active:e,refreshing:t,onClick:a}){return i.jsx("button",{className:`remote-status-button ${e?"active":""}`,type:"button",title:"Check Remote Status","aria-label":"Check Remote Status","aria-pressed":e,"aria-busy":t,onClick:a,children:t?i.jsx("span",{className:"remote-status-spinner","aria-hidden":"true"}):i.jsx(gy,{size:18,"aria-hidden":"true"})})}function mh({active:e,refreshing:t,onClick:a}){return i.jsx("button",{className:`remote-status-button debug-status-button ${e?"active":""}`,type:"button",title:"Check Debug Status","aria-label":"Check Debug Status","aria-pressed":e,"aria-busy":t,onClick:a,children:t?i.jsx("span",{className:"remote-status-spinner","aria-hidden":"true"}):i.jsx(by,{size:18,"aria-hidden":"true"})})}function ph({active:e,refreshing:t,onClick:a}){return i.jsx("button",{className:`remote-status-button hub-status-button ${e?"active":""}`,type:"button",title:"Check Hub Status","aria-label":"Check Hub Status","aria-pressed":e,"aria-busy":t,onClick:a,children:t?i.jsx("span",{className:"remote-status-spinner","aria-hidden":"true"}):i.jsx(Ci,{size:18,"aria-hidden":"true"})})}function Zg({items:e,mode:t="remote"}){return i.jsx("span",{className:`remote-status-lines mode-${t}`,role:"status","aria-label":t==="debug"?"Debug status":"Remote status",onPointerDown:t==="debug"?a=>a.stopPropagation():void 0,onClick:t==="debug"?a=>a.stopPropagation():void 0,onDoubleClick:t==="debug"?a=>a.stopPropagation():void 0,children:e.map(a=>i.jsxs("span",{className:`remote-status-line state-${a.state}`,title:a.detail,children:[i.jsx(Jg,{state:a.state}),i.jsxs("span",{children:[i.jsx("strong",{children:a.label}),i.jsx("small",{children:a.detail})]})]},a.id))})}function G0({items:e,collectedAt:t,onClose:a}){return i.jsxs("section",{className:"remote-status-dialog hub-status-dialog",role:"dialog","aria-modal":"false","aria-labelledby":"hub-status-dialog-title",children:[i.jsxs("header",{children:[i.jsx("span",{className:"remote-status-dialog-mark","aria-hidden":"true",children:i.jsx(Ci,{size:19})}),i.jsxs("span",{children:[i.jsx("small",{children:"Hub measurements"}),i.jsx("h2",{id:"hub-status-dialog-title",children:"Hub Status"})]}),i.jsx("button",{type:"button",onClick:a,title:"Close Hub status","aria-label":"Close Hub status",children:i.jsx(xa,{size:17})})]}),i.jsx("p",{children:"VuvoDesk collects these Hub and browser signals continuously. This check refreshed the latest snapshot instead of starting a one-time benchmark."}),i.jsx("div",{className:"remote-status-dialog-list",children:e.map(r=>i.jsxs("article",{className:`remote-status-dialog-row state-${r.state}`,children:[i.jsx(Jg,{state:r.state}),i.jsxs("span",{children:[i.jsx("strong",{children:r.label}),i.jsx("small",{children:r.detail})]})]},r.id))}),i.jsxs("footer",{children:["Checked ",new Date(t).toLocaleTimeString()]})]})}async function K0(e,t={}){const a=e.filter(b=>b.canvas&&b.canvas.width>0&&b.canvas.height>0),r=Math.max(320,t.maxWidth||1920),c=Math.max(180,t.maxHeight||1080),u=a.length<=1?1:a.length<=4?2:a.length<=9?3:4,p=Math.max(1,Math.ceil(Math.max(1,a.length)/u)),h=Math.floor(r/u),f=Math.floor(c/p),k=document.createElement("canvas");k.width=Math.max(320,h*u),k.height=Math.max(180,f*p);const M=k.getContext("2d",{alpha:!1});if(!M)return k;M.fillStyle="#0b1220",M.fillRect(0,0,k.width,k.height),M.font="600 14px system-ui, sans-serif",M.textBaseline="bottom";for(let b=0;b<a.length;b+=1){const T=a[b],A=b%u,x=Math.floor(b/u),E=A*h,B=x*f,q=T.canvas,G=Math.min(h/q.width,f/q.height),ne=Math.max(1,Math.floor(q.width*G)),re=Math.max(1,Math.floor(q.height*G)),O=E+Math.floor((h-ne)/2),ie=B+Math.floor((f-re)/2);M.drawImage(q,O,ie,ne,re),t.includeLabels!==!1&&(M.fillStyle="rgba(4, 10, 20, .74)",M.fillRect(E,B+f-28,h,28),M.fillStyle="#f8fafc",M.fillText(T.label,E+9,B+f-9))}return k}function Y0(e){return e?.signature||"none"}function Q0(e){return e?.label||"No capture target"}function fh(e){return{...e,deviceIds:[...e.deviceIds],sourceCanvas:e.sourceCanvas||null}}function eb(e){return{type:e.type,deviceIds:e.deviceIds,monitorIndex:e.monitorIndex,label:e.label}}async function tb(e){try{return(await e.json()).error||`${e.status} ${e.statusText}`}catch{return`${e.status} ${e.statusText}`}}async function nb(e,t,a){const r=encodeURIComponent(JSON.stringify({kind:t.kind,fileName:t.fileName,mimeType:e.type||"application/octet-stream",durationMs:t.durationMs,target:eb(t.target)})),c=await Qh(`/api/captures?metadata=${r}`,{method:"POST",headers:{"Content-Type":e.type||"application/octet-stream"},body:e},a);if(!c.ok)throw new Error(await tb(c));return await c.json()}async function X0(e,t){return await Ue("/api/capture-sessions",{method:"POST",body:JSON.stringify({...e,target:eb(e.target)})},t)}async function J0(e,t,a,r){const c=await Qh(`/api/capture-sessions/${encodeURIComponent(e)}/chunks/${t}`,{method:"PUT",headers:{"Content-Type":a.type||"application/octet-stream"},body:a},r);if(!c.ok)throw new Error(await tb(c));return await c.json()}async function Z0(e,t,a){return await Ue(`/api/capture-sessions/${encodeURIComponent(e)}/finalize`,{method:"POST",body:JSON.stringify({durationMs:t})},a)}async function hh(e,t){await Ue(`/api/capture-sessions/${encodeURIComponent(e)}`,{method:"DELETE"},t)}async function px(e){return await Ue("/api/captures",void 0,e)}function fx(e,t){return`${Yh(t)}/api/captures/${encodeURIComponent(e)}/content`}async function hx(e,t){return await Ue(`/api/captures/${encodeURIComponent(e)}`,{method:"DELETE"},t)}function ek(){const e=new Date,t=a=>String(a).padStart(2,"0");return`${e.getFullYear()}${t(e.getMonth()+1)}${t(e.getDate())}_${t(e.getHours())}${t(e.getMinutes())}${t(e.getSeconds())}`}function tk(e){return e.replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,80)||"Wall"}function nk(e){return`VuvoDesk_${e.type==="wall"||e.type==="selection"?"Wall":`${tk(e.label)}_Monitor-${Number(e.monitorIndex||0)+1}`}_${ek()}.png`}async function rk(e,t,a){const r=await new Promise((u,p)=>e.toBlob(h=>h?u(h):p(new Error("Screenshot could not be encoded.")),"image/png")),c=await nb(r,{kind:"screenshot",fileName:nk(t),target:t},a);try{await navigator.clipboard.write([new ClipboardItem({"image/png":r})])}catch{}return c.capture}function rb(){return["video/webm;codecs=vp9","video/webm;codecs=vp8","video/webm"].find(t=>typeof MediaRecorder<"u"&&MediaRecorder.isTypeSupported(t))||""}function ak(e,t){const a=new Date().toISOString().replace(/[-:]/g,"").replace(/\.\d{3}Z$/,"").replace("T","_"),r=t.label.replace(/[^a-zA-Z0-9._-]+/g,"-").slice(0,70)||"Wall";return e==="timelapse"?`VuvoDesk_Timelapse_${r}_${a}.webm`:`VuvoDesk_Recording_${r}_${a}.webm`}async function ab(e){if(typeof MediaRecorder>"u"||typeof e.canvas.captureStream!="function")throw new Error("This browser does not support video recording.");const t=rb();if(!t)throw new Error("This browser does not support WebM recording.");const a=e.kind||"recording",r=await X0({kind:a,fileName:ak(a,e.target),mimeType:t,target:e.target},e.hubUrl),c=e.canvas.captureStream(e.frameRequests?0:e.fps),u=new MediaRecorder(c,{mimeType:t,videoBitsPerSecond:a==="timelapse"?2e6:4e6}),p=performance.now();let h=0,f=!1,k=null,M=Promise.resolve();return u.ondataavailable=b=>{if(!b.data||b.data.size===0)return;const T=h++;M=M.then(()=>J0(r.sessionId,T,b.data,e.hubUrl).then(()=>{})).catch(A=>{k=k||(A instanceof Error?A:new Error(String(A))),e.onError?.(k)})},u.onerror=()=>{k=new Error("Video recording stopped unexpectedly."),e.onError?.(k)},u.start(1e3),{requestFrame:()=>{c.getVideoTracks()[0]?.requestFrame?.()},stop:async()=>{if(!f){if(f=!0,await new Promise(b=>{u.addEventListener("stop",()=>b(),{once:!0}),u.stop()}),c.getTracks().forEach(b=>b.stop()),await M,k)throw await hh(r.sessionId,e.hubUrl).catch(()=>{}),k;await Z0(r.sessionId,Math.max(0,performance.now()-p),e.hubUrl)}},cancel:async()=>{f||(f=!0,u.stop(),c.getTracks().forEach(b=>b.stop()),await hh(r.sessionId,e.hubUrl).catch(()=>{}))}}}class ok{recorder=null;stream=null;segments=[];totalBytes=0;targetSignature="";startedAt=0;maxDurationMs=3e4;maxBytes=128*1024*1024;get seconds(){return!this.startedAt||this.segments.length===0?0:Math.min(30,Math.max(0,(performance.now()-this.segments[0].at)/1e3))}get active(){return this.recorder!==null}async start(t,a){if(this.recorder&&this.targetSignature===a.signature)return;if(this.stop(),typeof MediaRecorder>"u"||typeof t.captureStream!="function")throw new Error("This browser does not support Last 30s.");const r=rb();if(!r)throw new Error("This browser does not support WebM recording.");this.targetSignature=a.signature,this.stream=t.captureStream(20),this.recorder=new MediaRecorder(this.stream,{mimeType:r,videoBitsPerSecond:3e6}),this.startedAt=performance.now(),this.recorder.ondataavailable=c=>{if(!c.data.size)return;const u=performance.now();for(this.segments.push({blob:c.data,at:u}),this.totalBytes+=c.data.size;this.segments.length>1&&(u-this.segments[0].at>this.maxDurationMs||this.totalBytes>this.maxBytes);){const p=this.segments.shift();this.totalBytes-=p.blob.size}},this.recorder.start(1e3)}stop(){const t=this.recorder;this.recorder=null,t&&t.state!=="inactive"&&(t.ondataavailable=null,t.stop()),this.stream?.getTracks().forEach(a=>a.stop()),this.stream=null,this.segments=[],this.totalBytes=0,this.startedAt=0}async save(t,a){if(this.segments.length===0)throw new Error("The Last 30s buffer is not ready yet.");const r=new Blob(this.segments.map(p=>p.blob),{type:this.segments[0].blob.type||"video/webm"}),u=`VuvoDesk_Last30s_${t.label.replace(/[^a-zA-Z0-9._-]+/g,"-").slice(0,70)||"Wall"}_${new Date().toISOString().replace(/[-:]/g,"").replace(/\.\d{3}Z$/,"").replace("T","_")}.webm`;return await nb(r,{kind:"last-30s",fileName:u,target:t,durationMs:Math.min(3e4,this.segments.length*1e3)},a)}}async function ik(e,t,a,r,c){const u=await ab({canvas:e,target:t,kind:"timelapse",fps:30,frameRequests:!0,hubUrl:r,onError:c});u.requestFrame?.();const p=window.setInterval(()=>u.requestFrame?.(),Math.max(5,a)*1e3);return{stop:async()=>{window.clearInterval(p),await u.stop()},cancel:async()=>{window.clearInterval(p),await u.cancel()}}}const ob="livedesk.captureSettings";function sk(){const e={rollingEnabled:!1,recordingQuality:"standard",timelapseIntervalSeconds:10,includeRemoteCursor:!0};try{const t=JSON.parse(localStorage.getItem(ob)||"null");return{...e,...t&&typeof t=="object"?t:{}}}catch{return e}}function ck(e){const[t,a]=s.useState(sk),[r,c]=s.useState(0),[u,p]=s.useState(0),[h,f]=s.useState(0),[k,M]=s.useState(!1),b=s.useRef(void 0),T=s.useRef(!1),A=s.useRef(""),x=s.useRef(null),E=s.useRef(null),B=s.useRef(null),q=s.useRef(null),G=s.useRef(new ok),ne=e.sourceRegistry.resolveCurrentTarget(),re=Y0(ne),O=Q0(ne),ie=typeof MediaRecorder<"u"&&typeof HTMLCanvasElement<"u"&&"captureStream"in HTMLCanvasElement.prototype;s.useEffect(()=>{if(localStorage.setItem(ob,JSON.stringify(t)),!e.remoteSettingsEnabled||!e.hubUrl||!T.current)return;const P=JSON.stringify(t);P!==A.current&&(A.current=P,Ue("/api/settings",{method:"PATCH",body:JSON.stringify({revision:b.current,filesAudio:{rollingBufferEnabled:t.rollingEnabled,recordingQuality:t.recordingQuality,timelapseIntervalSeconds:t.timelapseIntervalSeconds,includeRemoteCursor:t.includeRemoteCursor}})},e.hubUrl).then(N=>{b.current=Number(N.revision||b.current||0)}).catch(()=>{}))},[e.hubUrl,e.remoteSettingsEnabled,t]),s.useEffect(()=>{if(!e.remoteSettingsEnabled||!e.hubUrl){T.current=!1;return}let P=!0;return Ue("/api/settings",void 0,e.hubUrl).then(N=>{if(!P)return;const te=N.settings?.filesAudio||{},we=typeof te.rollingBufferEnabled=="boolean"?te.rollingBufferEnabled:t.rollingEnabled,me=te.recordingQuality==="high"?"high":"standard",Fe=[5,10,30,60].includes(Number(te.timelapseIntervalSeconds))?Number(te.timelapseIntervalSeconds):t.timelapseIntervalSeconds,H=typeof te.includeRemoteCursor=="boolean"?te.includeRemoteCursor:t.includeRemoteCursor,R={rollingEnabled:we,recordingQuality:me,timelapseIntervalSeconds:Fe,includeRemoteCursor:H};b.current=Number(N.revision||0),A.current=JSON.stringify(R),T.current=!0,a(R)}).catch(()=>{T.current=!0}),()=>{P=!1}},[e.hubUrl,e.remoteSettingsEnabled]);const J=s.useCallback(async P=>{if(P.sourceCanvas&&P.sourceCanvas.width>0&&P.sourceCanvas.height>0)return{target:fh(P),canvas:P.sourceCanvas,cleanup:()=>{}};const N=await e.sourceRegistry.composeWall(P.deviceIds,{maxWidth:1920,maxHeight:1080,includeLabels:!0});let te=!1;const we=window.setInterval(async()=>{if(te)return;const me=await e.sourceRegistry.composeWall(P.deviceIds,{maxWidth:1920,maxHeight:1080,includeLabels:!0}).catch(()=>null);!me||te||((N.width!==me.width||N.height!==me.height)&&(N.width=me.width,N.height=me.height),N.getContext("2d")?.drawImage(me,0,0))},100);return{target:fh(P),canvas:N,cleanup:()=>{te=!0,window.clearInterval(we)}}},[e.sourceRegistry]);s.useEffect(()=>{const P=G.current;if(!t.rollingEnabled||!ne||!ie){P.stop(),f(0);return}let N=!1,te=null;return(async()=>{try{if(te=await J(ne),N)return;await P.start(te.canvas,te.target);const me=window.setInterval(()=>f(Math.round(P.seconds)),500),Fe=()=>{window.clearInterval(me),te?.cleanup()};P.__cleanup=Fe}catch(me){N||e.onToast(me instanceof Error?me.message:String(me))}})(),()=>{N=!0,P.stop(),P.__cleanup?.(),P.__cleanup=void 0,f(0)}},[J,e.onToast,t.rollingEnabled,re,ie]);const de=s.useCallback(P=>a(N=>({...N,rollingEnabled:P})),[]),se=s.useCallback(P=>a(N=>({...N,recordingQuality:P})),[]),pe=s.useCallback(P=>a(N=>({...N,timelapseIntervalSeconds:P})),[]),ce=s.useCallback(async()=>{const P=e.sourceRegistry.resolveCurrentTarget();if(!P)throw new Error("화면이 준비된 후 다시 시도하세요.");M(!0);let N=null;try{N=await J(P),await rk(N.canvas,N.target,e.hubUrl),e.onToast("Screenshot saved")}finally{N?.cleanup(),M(!1)}},[J,e.hubUrl,e.onToast,e.sourceRegistry]),W=s.useCallback(async()=>{if(B.current)throw new Error("Stop the timelapse before recording.");const P=e.sourceRegistry.resolveCurrentTarget();if(!P)throw new Error("화면이 준비된 후 다시 시도하세요.");const N=await J(P),te=await ab({canvas:N.canvas,target:N.target,fps:P.type==="control"?30:15,hubUrl:e.hubUrl,onError:we=>e.onToast(we.message)});E.current=N.cleanup,x.current=te,c(Date.now()),e.onToast("Recording started")},[J,e.hubUrl,e.onToast,e.sourceRegistry]),ee=s.useCallback(async()=>{const P=x.current;if(P){M(!0);try{await P.stop(),e.onToast("Recording saved")}finally{x.current=null,E.current?.(),E.current=null,c(0),M(!1)}}},[e.onToast]),L=s.useCallback(async()=>{if(x.current||B.current)throw new Error("Last 30s is unavailable during a recording.");const P=e.sourceRegistry.resolveCurrentTarget();if(!P)throw new Error("화면이 준비된 후 다시 시도하세요.");M(!0);try{await G.current.save(P,e.hubUrl),e.onToast("Last 30 seconds saved")}finally{M(!1)}},[e.hubUrl,e.onToast,e.sourceRegistry]),_=s.useCallback(async()=>{if(x.current)throw new Error("Stop the recording before starting a timelapse.");const P=e.sourceRegistry.resolveCurrentTarget();if(!P)throw new Error("화면이 준비된 후 다시 시도하세요.");const N=await J(P),te=await ik(N.canvas,N.target,t.timelapseIntervalSeconds,e.hubUrl,we=>e.onToast(we.message));q.current=N.cleanup,B.current=te,p(Date.now()),e.onToast("Timelapse started")},[J,e.hubUrl,e.onToast,e.sourceRegistry,t.timelapseIntervalSeconds]),K=s.useCallback(async()=>{const P=B.current;if(P){M(!0);try{await P.stop(),e.onToast("Timelapse saved")}finally{B.current=null,q.current?.(),q.current=null,p(0),M(!1)}}},[e.onToast]);return s.useEffect(()=>{const P=N=>{!x.current&&!B.current||(N.preventDefault(),N.returnValue="")};return window.addEventListener("beforeunload",P),()=>window.removeEventListener("beforeunload",P)},[]),s.useEffect(()=>()=>{G.current.stop(),x.current?.cancel(),B.current?.cancel(),E.current?.(),q.current?.()},[]),{state:s.useMemo(()=>({recording:!!x.current,recordingStartedAt:r,timelapse:!!B.current,timelapseStartedAt:u,bufferSeconds:h,bufferEnabled:t.rollingEnabled,busy:k,targetLabel:O}),[h,k,r,t.rollingEnabled,O,u]),settings:t,videoSupported:ie,targetKey:re,setRollingEnabled:de,setRecordingQuality:se,setTimelapseInterval:pe,takeScreenshot:ce,startRecording:W,stopRecording:ee,saveLast30Seconds:L,startTimelapse:_,stopTimelapse:K}}function lk(){if(typeof window>"u")return{isIos:!1,isAndroid:!1,isSafari:!1,browserName:"browser"};const e=window.navigator.userAgent,t=window.navigator.standalone,a=e0(e,window.navigator.platform,window.navigator.maxTouchPoints,t),r=/Android/i.test(e),c=a&&/CriOS/i.test(e),u=a&&/Safari/i.test(e)&&!/(CriOS|FxiOS|EdgiOS|OPiOS|DuckDuckGo)/i.test(e);return{isIos:a,isAndroid:r,isSafari:u,browserName:c?"Chrome":u?"Safari":"browser"}}const gh=s.lazy(()=>mr(()=>import("./AgentsPage-DEdUBoe0.js"),__vite__mapDeps([0,1,2,3,4,5])).then(e=>({default:e.AgentsPage}))),uk=s.lazy(()=>mr(()=>import("./ShareFilesPage-BiCS0Nyd.js"),__vite__mapDeps([6,1,2,3,4,7])).then(e=>({default:e.ShareFilesPage}))),In="".trim().toLowerCase()==="true",Ca="".trim().toLowerCase()==="true",Zr="".trim().toLowerCase()==="true",dk=s.lazy(()=>mr(()=>import("./SupportPage-D241Vkb1.js"),__vite__mapDeps([8,1,2,3,4,9,10,11])).then(e=>({default:e.SupportPage}))),mk=s.lazy(()=>mr(()=>import("./SettingsPage-BoFLQBfH.js"),__vite__mapDeps([12,1,2,3,4])).then(e=>({default:e.SettingsPage}))),pk=s.lazy(()=>mr(()=>import("./SettingsTabs-D0zQN-Mo.js"),__vite__mapDeps([13,1,2,3,4])).then(e=>({default:e.PinSettingsTab}))),fk=s.lazy(()=>mr(()=>import("./AgentSettingsTab-D0271Ynp.js"),__vite__mapDeps([14,1,2,3,4])).then(e=>({default:e.AgentSettingsTab}))),hk=s.lazy(()=>mr(()=>import("./DesktopUpdatePanel-uMaTnBsl.js"),__vite__mapDeps([15,1,2,3,4])).then(e=>({default:e.DesktopUpdatePanel}))),gk=s.lazy(()=>mr(()=>import("./CaptureGallery-C0xqFLap.js"),__vite__mapDeps([16,1,2,3,4,9,10])).then(e=>({default:e.CaptureGallery})));function bs({children:e}){return i.jsx(s.Suspense,{fallback:i.jsx("div",{className:"deferred-feature-loading",role:"status",children:"Loading…"}),children:e})}const bk=120,vk=999,ib="livedesk.remoteDirectory",$d="livedesk.localHubAccessEnabled",yk="livedesk.streamSettings",wk=18,Sk="livedesk.controlStreamSettings",Ck=10,sb="livedesk.wallCadence",cb="livedesk.wallViewScale",lb="livedesk.mobileWallStatsVisible",kk=1e3,ub="livedesk.wallMonitorSelections",db=2,pd=512*1024,Mk=250,xk=15e3,Rk=!1;function Ak(){return typeof navigator>"u"?!1:/Mac|iPhone|iPad|iPod/i.test(`${navigator.platform} ${navigator.userAgent}`)}function Ik(e){let t="";for(let a=0;a<e.length;a+=32*1024)t+=String.fromCharCode(...e.subarray(a,Math.min(e.length,a+32*1024)));return window.btoa(t)}function bh(e){const t=window.atob(String(e||"")),a=new Uint8Array(t.length);for(let r=0;r<t.length;r+=1)a[r]=t.charCodeAt(r);return a}async function mb(e){const t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t),a=>a.toString(16).padStart(2,"0")).join("")}async function Tk(e){const t=navigator.clipboard;let a="text",r="clipboard.txt",c="text/plain",u=null;if(typeof t?.read=="function"){const h=await t.read(),f=h.find(k=>k.types.includes("image/png"));if(f){const k=await f.getType("image/png");a="image",r="clipboard.png",c="image/png",u=new Uint8Array(await k.arrayBuffer())}else{const k=h.find(M=>M.types.includes("text/plain"));if(k){const M=await k.getType("text/plain");u=new TextEncoder().encode(await M.text())}}}if(!u&&typeof t?.readText=="function"&&(u=new TextEncoder().encode(await t.readText())),!u)throw new Error("The browser did not provide text or a PNG image from the clipboard.");return{manifest:Ld({operationId:e,contentKind:a,totalBytes:u.byteLength,items:[{itemIndex:0,kind:a,name:r,mimeType:c,size:u.byteLength,lastModified:Date.now(),sha256:await mb(u),storageName:"item-0.bin"}]},e),payloads:[u]}}async function Pk(e){const{manifest:t,payloads:a}=e,r=a[0];if(!r||t.items.length!==1)throw new Error("clipboard-browser-snapshot-invalid");if(t.contentKind==="text"){await navigator.clipboard.writeText(new TextDecoder().decode(r));return}if(t.contentKind==="image"&&typeof ClipboardItem<"u"){await navigator.clipboard.write([new ClipboardItem({"image/png":new Blob([r],{type:"image/png"})})]);return}throw new Error("Multiple files require the VuvoDesk desktop app.")}"".trim();"".trim();const Ek=Object.freeze([{code:"ShiftLeft",label:"Shift"},{code:"ControlLeft",label:"Ctrl"},{code:"AltLeft",label:"Alt"},{code:"MetaLeft",label:"Win"}]),Nk=1e3/60,fd=1500,Fk=650,Dk=1800,Lk=650,Ok=2500,hd=1500,vh=15e3,yh=120,_k=.72,pb=6,jk=640*360,Bk=8;function Hk(e){let t=2166136261;for(let a=0;a<e.length;a+=1)t=Math.imul(t^e.charCodeAt(a),16777619);return(t>>>0)%pb}const wh=100,Sh=20,Wk=6e4,$k=6e4,Ch=240,Vk=1024,zk=640,Uk=360,kh="Connected VuvoDesk clients are updating in batches. Hub will restart after every target reconnects on the requested versions.",ml="VuvoDesk is replacing the Hub and verifying the requested version.",pl=5*6e4,qk=5e3,Mh=2e3,Gk=8e3;function xh(e,t){return`${e}:${t.deviceId}:${t.completedAt||t.candidateSessionId||t.commandId||"completed"}`}function bo({label:e,tooltip:t,disabled:a=!1,active:r=!1,danger:c=!1,pressed:u,onClick:p,children:h}){return i.jsx("span",{className:`manual-action-tooltip ${a?"disabled":""}`.trim(),"data-tooltip":t,children:i.jsx("button",{className:`manual-action ${r?"active":""} ${c?"danger":""}`.trim(),onClick:p,disabled:a,"aria-label":e,"aria-pressed":u,type:"button",children:h})})}function Kk(e,t){if(t.deviceId!==e.deviceId)return!1;const a=Number(t.browserReceivedEpochMs);if(!Number.isFinite(a)||a<e.startedAtEpochMs)return!1;const r=Number(t.monitorIndex);if(Number.isFinite(r)&&Math.floor(r)!==e.monitorIndex)return!1;const c=String(t.frameMode||t.mode||"").trim().toLowerCase();return!c||c===e.frameMode}const Yk={"mode3-h264-hw":30};function Rh(e,t){const a=p=>{const f=String(p||"").trim().replace(/^v/i,"").match(/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/);if(!f)return null;const k=f[4]?f[4].split(".").map(M=>/^\d+$/.test(M)?M.length>1&&M.startsWith("0")?Number.NaN:Number(M):M):[];return k.some(M=>typeof M=="number"&&!Number.isFinite(M))?null:{core:[Number(f[1]),Number(f[2]),Number(f[3])],prerelease:k}},r=a(e),c=a(t);if(!r||!c)return!1;for(let p=0;p<3;p+=1){if(r.core[p]>c.core[p])return!0;if(r.core[p]<c.core[p])return!1}if(r.prerelease.length===0||c.prerelease.length===0)return r.prerelease.length===0;const u=Math.max(r.prerelease.length,c.prerelease.length);for(let p=0;p<u;p+=1){const h=r.prerelease[p],f=c.prerelease[p];if(h===void 0||f===void 0)return f===void 0;if(h!==f){if(typeof h=="number"&&typeof f=="number")return h>f;if(typeof h=="number")return!1;if(typeof f=="number"||h>f)return!0;if(h<f)return!1}}return!0}const Qk=1024;function ut(e,t){return`${e}:${t}`}function er(e){return[e.deviceId,e.sessionId||"",e.streamId||"",e.commandId||"",Number(e.captureGeneration||0),Number(e.monitorIndex??-1),e.streamPurpose||""].join("|")}const Xk={frameMode:"mode3-h264-hw",h264DecodeAcceleration:"prefer-hardware",fps:Yk["mode3-h264-hw"],maxWidth:1920,maxHeight:1080,atlasTileWidth:320,atlasTileHeight:180,atlasTileSizeMode:"auto",quality:75,autoStartLive:!0,showScreenStatus:!0,visibleOnlyLive:!0,adaptiveLoadShedding:!0,adaptiveSizeByWall:!0},Jk={frameMode:"mode3-h264-hw",h264DecodeAcceleration:"prefer-hardware",fps:30,maxWidth:3840,maxHeight:2160,quality:75,showScreenStatus:!1},Ah={maxWidth:3840,maxHeight:2160};function vs(e,t){if(e.length===0)return 0;const a=[...e].sort((c,u)=>c-u),r=Math.max(0,Math.min(a.length-1,Math.ceil(a.length*t)-1));return a[r]}function fb(e,t){e.push(t),e.length>Ch&&e.splice(0,e.length-Ch)}function fl(e,t){e.sampleFrames=0,e.sampleStartedAt=t,e.intervalCount=0,e.intervalSumMs=0,e.minIntervalMs=Number.POSITIVE_INFINITY,e.maxIntervalMs=0,e.intervalSamplesMs.length=0,e.seqGapCount=0,e.maxSeqGap=0}function Ih(e,t,a){if(e.lastAt!==void 0){const r=Math.max(0,t-e.lastAt);e.intervalCount+=1,e.intervalSumMs+=r,e.minIntervalMs=Math.min(e.minIntervalMs,r),e.maxIntervalMs=Math.max(e.maxIntervalMs,r),fb(e.intervalSamplesMs,r)}if(e.lastFrameSeq!==void 0){const r=a-e.lastFrameSeq;r!==1&&(e.seqGapCount+=1,e.maxSeqGap=Math.max(e.maxSeqGap,Math.abs(r)))}e.lastAt=t,e.lastFrameSeq=a}function Th(e){return!e||e.intervalCount<=0?"waiting":`${Math.round(e.averageIntervalMs)}ms avg / p95 ${Math.round(e.p95IntervalMs)}ms / max ${Math.round(e.maxIntervalMs)}ms`}function Ph(e){return!e||e.seqGapCount<=0?"none":`${e.seqGapCount} gaps / max ${e.maxSeqGap}`}function Zk(e){return Number.isFinite(e)?String(e):"Unlimited"}const hb=[1,2,5,8,12,20,30],Eh={large:{maxWidth:1920,maxHeight:1080},medium:{maxWidth:1280,maxHeight:720},list:{maxWidth:960,maxHeight:540}},ur={visibleRootMargin:"520px 0px 760px 0px",fallbackVisibleCounts:{large:12,medium:18,list:32},maxWallBytesPerSecond:80*1024*1024,maxFrameGapMs:280,downshiftCooldownMs:1800,downshiftStableSampleMs:St.adaptiveDownshiftStableMs,downshiftConsecutiveSamples:St.adaptiveDownshiftConsecutiveSamples,recoveryCooldownMs:14e3,minFps:5},gd=2200,eM=2500,tM=8e3,nM=3500,Nh=7e3,rM=2,aM=2500,Fh=7e3,Dh=2600,oM=4200,iM=750,sM=2,cM=2,Lh=2500,Oh=4200,_h=2200;function jh(e,t){return Math.min(3e4,e*2**Math.min(3,Math.max(0,t)))}function yi(e,t){const a=e.capabilities?.[t];return typeof a=="boolean"?a:/^(1|true|yes|on)$/i.test(String(a||"").trim())}function Qt(e){return e.deviceName||e.hostname||e.deviceId}function lM(){return"npx -y --prefer-online livedesk@latest client"}function uM(){return"npx -y --prefer-online livedesk@latest"}function dM(){try{return localStorage.getItem(ib)||""}catch{return""}}function mM(){try{return localStorage.getItem($d)==="1"}catch{return!1}}function gi(e){try{e?localStorage.setItem($d,"1"):localStorage.removeItem($d)}catch{}}function dr(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function Ma(e){const t=dr(e.status),a=dr(t.screens),r=dr(e.capabilities),c=dr(e.latestLiveFrame),u=dr(e.activeLiveStream),h=[t.monitorCount,t.screenCount,a.count,r.monitorCount,r.screenCount,c.monitorCount,u.monitorCount,Array.isArray(a.displays)?a.displays.length:0,Array.isArray(t.displays)?t.displays.length:0,Array.isArray(t.monitors)?t.monitors.length:0].map(Number).filter(f=>Number.isFinite(f)&&f>0).map(f=>Math.max(1,Math.min(64,Math.floor(f))));return h.length>0?Math.max(...h):1}function Ta(e){const t=Number(e);return Number.isFinite(t)&&t>0?Math.floor(t):0}function gb(e){const t=dr(e.status),r=[dr(t.screens).displays,t.displays,t.monitors];for(const c of r)if(!(!Array.isArray(c)||c.length===0))return c.map(u=>dr(u));return[]}function nm(e,t){const a=gb(e),r=a.find(f=>Number(f.index)===t)||a[t]||a[0]||{},c=Ta(r.width),u=Ta(r.height),p=[r.name,r.displayName,r.deviceName,r.id].find(f=>typeof f=="string"&&f.trim()),h=typeof p=="string"?p.trim():`Display ${t+1}`;return{index:t,name:h,width:c,height:u,primary:r.primary===!0||r.isPrimary===!0}}function pM(e){const t=Ma(e);return Array.from({length:t},(a,r)=>nm(e,r))}function fM(e){const t=gb(e);if(t.length===0)return"";const a=t.map((r,c)=>{const u=Number(r.index),p=[r.name,r.displayName,r.deviceName,r.id].find(f=>typeof f=="string"&&f.trim()),h=f=>{const k=Number(f);return Number.isFinite(k)?k:null};return[Number.isFinite(u)?Math.floor(u):c,typeof p=="string"?p.trim().toLowerCase():"",h(r.left),h(r.top),h(r.width),h(r.height),r.primary===!0||r.isPrimary===!0]}).sort((r,c)=>r[0]-c[0]);return JSON.stringify(a)}function hM(e){const t=[e.name||`Display ${e.index+1}`];return e.width>0&&e.height>0&&t.push(`${e.width}x${e.height}`),e.primary&&t.push("Primary"),t.join(" - ")}function bb(e,t){const a=nm(e,t);if(a.width>0&&a.height>0)return{width:a.width,height:a.height};const r=dr(e.status),c=Ta(r.screenWidth||r.width),u=Ta(r.screenHeight||r.height);return c>0&&u>0?{width:c,height:u}:null}function vb(e){if(!e)return null;const t=Ta(e.sourceWidth)||Ta(e.width),a=Ta(e.sourceHeight)||Ta(e.height);return t>0&&a>0?{width:t,height:a}:null}function gM(e,t,a){const u=((typeof t?.monitorIndex=="number"?Ss(t.monitorIndex,Math.max(1,t.monitorCount||1)):a)===a?vb(t):null)||bb(e,a);return u?Math.max(.25,Math.min(4,u.width/u.height)):16/9}const hl=16/9;function Ss(e,t){const a=Math.max(1,Math.min(64,Math.floor(Number(t)||1))),r=Math.floor(Number(e));return Number.isFinite(r)?Math.max(0,Math.min(a-1,r)):0}function _n(e,t){return UC(t,Ma(e),e.platform)}function bM(){try{const e=localStorage.getItem(ub);if(!e)return{selections:{},topologyFingerprints:{}};const t=JSON.parse(e),a=t&&typeof t=="object"&&!Array.isArray(t)?t.selections:void 0;if(Number(t?.version)!==db||!a||typeof a!="object"||Array.isArray(a))return{selections:{},topologyFingerprints:{}};const r={},c={};for(const[u,p]of Object.entries(a)){const h=u.trim(),f=dr(p),k=f.monitorIndex,M=Math.floor(Number(k));if(!h||!Number.isFinite(M))continue;r[h]=Math.max(0,Math.min(63,M));const b=typeof f.topologyFingerprint=="string"?f.topologyFingerprint.trim():"";b&&(c[h]=b)}return{selections:r,topologyFingerprints:c}}catch{return{selections:{},topologyFingerprints:{}}}}function vM(e,t){try{const a=Object.fromEntries(Object.entries(e).map(([r,c])=>[r,{monitorIndex:c,topologyFingerprint:t[r]||""}]));localStorage.setItem(ub,JSON.stringify({version:db,selections:a}))}catch{}}function yM(){return{...Xk}}function wM(e){try{localStorage.setItem(yk,JSON.stringify({...e,version:wk}))}catch{}}function SM(){return{...Jk}}function CM(e){try{localStorage.setItem(Sk,JSON.stringify({...e,version:Ck}))}catch{}}function kM(){try{return localStorage.getItem(sb)==="slow"?"slow":"fast"}catch{return"fast"}}function MM(e){try{localStorage.setItem(sb,e)}catch{}}function xM(){try{return localStorage.getItem(lb)==="true"}catch{return!1}}function RM(e){try{localStorage.setItem(lb,String(e))}catch{}}function AM(){try{const e=localStorage.getItem(cb);return e===null?ta:xi(Number(e))}catch{return ta}}function IM(e){try{localStorage.setItem(cb,String(xi(e)))}catch{}}function bd(e,t){return e.length!==t.length?!1:e.every((a,r)=>a===t[r])}function vd(e){return[...new Set(e.filter(Boolean))].sort()}function TM(e){return ur.fallbackVisibleCounts[e]||ur.fallbackVisibleCounts.large}function Bh(e,t,a){if(e.frameMode==="mode4-h264-atlas")return e.atlasTileSizeMode==="auto"?t==="large"?{maxWidth:640,maxHeight:360}:{maxWidth:320,maxHeight:180}:{maxWidth:e.atlasTileWidth,maxHeight:e.atlasTileHeight};if(!e.adaptiveSizeByWall)return{maxWidth:e.maxWidth,maxHeight:e.maxHeight};const r=Eh[t]||Eh.large;return{maxWidth:Math.min(e.maxWidth,r.maxWidth),maxHeight:Math.min(e.maxHeight,r.maxHeight)}}function PM(e,t=ur.minFps){const a=[...hb].sort((c,u)=>c-u),r=Math.max(t,Math.floor(e/2));return[...a].reverse().find(c=>c<e&&c>=t)||r}function EM(e,t){return[...hb].sort((r,c)=>r-c).find(r=>r>e&&r<=t)||t}function Cs(e){if(!Number.isFinite(e)||e<=0)return"0 B";const t=["B","KB","MB","GB","TB"];let a=e,r=0;for(;a>=1024&&r<t.length-1;)a/=1024,r+=1;const c=r===0||a>=100?0:1;return`${a.toFixed(c)} ${t[r]}`}function Hh(e){if(!Number.isFinite(e)||!e||e<=0)return"0GB";const t=1024**4,a=1024**3;return e>=t?`${Math.max(1,Math.round(e/t))}TB`:`${Math.max(1,Math.round(e/a))}GB`}function yd(e,t){if(!Number.isFinite(e)||!e||e<=0)return"not reported";const a=Math.max(0,e-Math.max(0,Number(t||0)));return`${Hh(a)} / ${Hh(e)}`}function NM(e){const t=new Uint8Array(e),a=32768;let r="";for(let c=0;c<t.length;c+=a){const u=t.subarray(c,c+a);r+=String.fromCharCode(...u)}return btoa(r)}function Wh(e){return Array.from(e).filter(t=>t.size>=0).map(t=>{const a=t.webkitRelativePath||t.name;return{file:t,relativePath:a,fingerprint:`${t.size}:${t.lastModified}`}})}function ys(e){return e===1?"middle":e===2?"right":"left"}function $h(e,...t){for(const a of t){const r=e?.[a];if(typeof r=="string"&&r.trim())return r.trim()}return""}function Vh(e){const t=Number(e);return Number.isInteger(t)&&t>=1&&t<=vk?t:0}const FM={cpu:"CPU",memory:"MEM",disk:"Disk",gpu:"GPU",vram:"VRAM",npu:"NPU",temp:"Temp",network:"Net"};function DM(e,t,a){if(e==="online")return"Online";if(e==="busy")return"Busy";if(e==="stale")return"Stale";if(e==="offline")return"Offline";if(a==="failed")return"Task failed";const r=e==="critical"?"critical":"warn",c=t.find(p=>p.state===r)||t.find(p=>p.state==="critical"||p.state==="warn");if(!c)return e==="critical"?"Issue":"Check";const u=FM[c.id]||c.label;return c.value&&c.value!=="-"?`${u} ${c.value}`:u}function yb(e,t){const a=t.split(".");let r=e;for(const c of a){if(r==null)return;if(Array.isArray(r)){const u=Number(c);r=Number.isInteger(u)?r[u]:void 0;continue}if(typeof r=="object"){r=r[c];continue}return}return r}function Lt(e,...t){for(const a of t){const r=yb(e,a),c=Number(r);if(Number.isFinite(c))return c}}function Er(e,...t){for(const a of t){const r=yb(e,a);if(typeof r=="string"&&r.trim())return r.trim();if(typeof r=="number"&&Number.isFinite(r))return String(r)}return""}function ea(e){const t=Number(e);if(Number.isFinite(t))return Math.max(0,Math.min(1,t>1?t/100:t))}function wd(e,t){if(!(typeof e!="number"||typeof t!="number"||!Number.isFinite(e)||!Number.isFinite(t)||e<=0))return ea((e-Math.max(0,t))/e)}function bi(e){return e===void 0?"-":`${Math.round(e*100)}%`}function Sd(e){return e===void 0||!Number.isFinite(e)?"":e>=1e3?`${(e/1e3).toFixed(e>=1e4?0:1)}Gb/s`:`${Math.round(e)}Mb/s`}function vo(e,t=.92,a=.78){return e===void 0?"unknown":e>=t?"critical":e>=a?"warn":"good"}function LM(e){return!Number.isFinite(e)||!e||e<=0?"-":e<3600?`${Math.round(e/60)}m`:e<86400?`${Math.round(e/3600)}h`:`${Math.round(e/86400)}d`}function wb(e){const t=e.status||{},a=Lt(t,"cpu.cores","cpuCores","processorCount"),r=Lt(t,"loadavg.0","cpu.load1"),c=ea(Lt(t,"cpu.usedRatio","cpu.usageRatio","cpu.ratio","cpu.usedPct","cpu.usagePct","cpu.percent")??(a&&r!==void 0?r/Math.max(1,a):void 0)),u=Lt(t,"memory.totalBytes","totalMem"),p=Lt(t,"memory.freeBytes","freeMem"),h=ea(Lt(t,"memory.usedRatio","memory.usedPct","usedMemRatio"))??wd(u,p),f=Lt(t,"disk.totalBytes","rootDisk.totalBytes","storage.totalBytes"),k=Lt(t,"disk.freeBytes","rootDisk.freeBytes","storage.freeBytes"),M=ea(Lt(t,"disk.usedRatio","disk.usedPct","rootDisk.usedRatio","storage.usedRatio"))??wd(f,k),b=Lt(t,"thermal.cpuC","temperatureC","cpu.temperatureC","gpu.temperatureC"),T=ea(Lt(t,"gpu.usedRatio","gpu.usageRatio","gpu.usedPct","gpu.usagePct","gpu.percent","accelerators.gpu.usageRatio")),A=Er(t,"gpu.name","gpu.model","accelerators.gpu.name"),x=Lt(t,"gpu.memory.totalBytes","gpu.totalMemoryBytes","gpu.vramTotalBytes"),E=Lt(t,"gpu.memory.freeBytes","gpu.freeMemoryBytes","gpu.vramFreeBytes"),B=ea(Lt(t,"gpu.memory.usedRatio","gpu.vramUsedRatio"))??wd(x,E),q=Lt(t,"gpu.temperatureC","thermal.gpuC"),G=ea(Lt(t,"npu.usedRatio","npu.usageRatio","npu.usedPct","npu.usagePct","npu.percent","accelerators.npu.usageRatio")),ne=Er(t,"npu.name","npu.model","accelerators.npu.name"),re=Lt(t,"npu.tops","npu.topsInt8","accelerators.npu.tops"),O=Lt(t,"network.rxMbps","network.receiveMbps","network.downMbps"),ie=Lt(t,"network.txMbps","network.transmitMbps","network.upMbps"),J=Lt(t,"network.latencyMs","network.rttMs"),de=ea(Lt(t,"network.usedRatio","network.usageRatio","network.saturationRatio")),se=Er(t,"network.link","network.interface","network.name"),pe=Math.max(b??Number.NEGATIVE_INFINITY,q??Number.NEGATIVE_INFINITY),ce=Number.isFinite(pe)?pe:void 0,W=ce===void 0?void 0:ea((ce-35)/60),ee=b!==void 0&&q!==void 0?`CPU ${Math.round(b)}° · GPU ${Math.round(q)}°`:b!==void 0?`CPU ${Math.round(b)}°`:q!==void 0?`GPU ${Math.round(q)}°`:"-",L=Er(t,"workload.role","role","lane")||(yi(e,"taskDispatch")?"Command-ready Client":"Local machine"),_=Er(e.latestTask,"status")||Er(t,"workload.status")||"idle",K=Er(e.latestTask,"title","instructionPreview")||Er(t,"workload.title"),ue=Er(e.latestTask,"resultSummary","error","instructionPreview")||Er(t,"workload.summary"),P=Date.parse(e.lastSeenAt||e.connectedAt||""),N=Number.isFinite(P)?Date.now()-P:0;let te="online";e.connected?N>5*6e4?te="stale":(b??0)>=86||(q??0)>=88||(c??0)>=.94||(T??0)>=.96||(B??0)>=.96||(G??0)>=.96||(h??0)>=.94||(M??0)>=.94||(J??0)>=200||_==="failed"?te="critical":(b??0)>=78||(q??0)>=80||(c??0)>=.82||(T??0)>=.86||(B??0)>=.88||(G??0)>=.86||(h??0)>=.82||(M??0)>=.86||(J??0)>=80?te="warn":["queued","running","targeted"].includes(_)&&(te="busy"):te="offline";const we=[{id:"cpu",label:"CPU",value:bi(c),detail:a?`${a} cores`:r!==void 0?`load ${r.toFixed(1)}`:"not reported",ratio:c,state:vo(c,.92,.78)},{id:"memory",label:"RAM",value:bi(h),detail:yd(u,p),ratio:h,state:vo(h,.92,.78)},{id:"disk",label:"DISK",value:bi(M),detail:yd(f,k),ratio:M,state:vo(M,.92,.82)},{id:"gpu",label:"GPU",value:bi(T),detail:A||(x&&E!==void 0?`${Cs(E)} VRAM free`:q!==void 0?`${Math.round(q)}C`:"not reported"),ratio:T,state:q!==void 0&&q>=88?"critical":q!==void 0&&q>=80?"warn":vo(T,.96,.86)},{id:"vram",label:"VRAM",value:bi(B),detail:yd(x,E),ratio:B,state:vo(B,.96,.88)},{id:"npu",label:"NPU",value:G!==void 0?bi(G):re!==void 0?`${Math.round(re)} TOPS`:"-",detail:ne||(re!==void 0?"neural engine":"not reported"),ratio:G,state:vo(G,.96,.86)},{id:"temp",label:"TEMP",value:ee,detail:`uptime ${LM(Lt(t,"uptimeSec"))}`,ratio:W,state:ce===void 0?"unknown":ce>=86?"critical":ce>=78?"warn":"good"},{id:"network",label:"NET",value:Sd(O)||(J!==void 0?`${Math.round(J)}ms`:se||"-"),detail:Sd(ie)?`${Sd(ie)} up`:se||"not reported",ratio:de,state:J!==void 0&&J>=200?"critical":J!==void 0&&J>=80?"warn":vo(de,.9,.75)}];return{state:te,label:DM(te,we,_),role:L,taskLabel:K||(_==="idle"?"idle":_),taskStatus:_,taskSummary:ue,metrics:we}}const zh=[{id:"slow",label:"Slow",fps:Rs("slow")},{id:"fast",label:"Fast",fps:Rs("fast")}],OM=[{id:"list",label:"List"},{id:"medium",label:"Small"},{id:"large",label:"Large"}],_M=[{id:"list",label:"List"},{id:"large",label:"Wall"}],Uh=[{id:"sync-server",label:"Hub",icon:Ci,accent:"blue",tooltip:"hub"},{id:"wall",label:"Wall",icon:Zh,accent:"blue",tooltip:"wall"},{id:"control",label:"Control",icon:Ms,accent:"red",tooltip:"control"},{id:"share-files",label:"Share Files",icon:eg,accent:"green",tooltip:"share-files"},{id:"agents",label:"Agents",icon:vl,accent:"violet",tooltip:"agents"}],qh=[{id:"doc",label:"Doc",icon:kd,accent:"amber"},{id:"support",label:"Support",icon:yy,accent:"violet"},{id:"pricing",label:"Pricing",icon:Ra,accent:"green"}];function jM(e){return e.replaceAll("npx -y @livedesk/client","npx -y --prefer-online livedesk@latest client").replaceAll("npx @livedesk/client","npx -y --prefer-online livedesk@latest client").replaceAll("npx -y livedesk client","npx -y --prefer-online livedesk@latest client").replaceAll("npx livedesk client","npx -y --prefer-online livedesk@latest client").replaceAll("npx -y livedesk","npx -y --prefer-online livedesk@latest").replaceAll("npx livedesk","npx -y --prefer-online livedesk@latest")}function Ft(e){return jM(e).replaceAll("Sync Server","Hub").replace(/\bRemoteHub\b/g,"Hub client endpoint").replace(/\bManagers\b/g,"Hubs").replace(/\bManager\b/g,"Hub").replace(/\bmanager\b/g,"Hub").replace(/\bMANAGER\b/g,"HUB").replace(/매니저/g,"Hub")}function yo(e){return e.map(t=>Ft(t))}function pn(e){return{languageName:e.languageName,languageLabel:e.languageLabel,eyebrow:e.eyebrow,title:Ft(e.title),intro:Ft(e.intro),sections:[{title:Ft(e.managerTitle),body:Ft(e.managerBody),points:yo(e.managerPoints)},{title:Ft(e.clientTitle),body:Ft(e.clientBody),points:yo(e.clientPoints)},{title:Ft(e.syncTitle),body:Ft(e.syncBody),points:yo(e.syncPoints)},...e.agentTitle&&e.agentBody&&e.agentPoints?[{title:Ft(e.agentTitle),body:Ft(e.agentBody),points:yo(e.agentPoints)}]:[],{title:Ft(e.platformTitle),body:Ft(e.platformBody),points:yo(e.platformPoints)}],sync:{title:Ft(e.syncTitle),body:Ft(e.syncBody),points:yo(e.syncPoints)},firewall:{title:Ft(e.firewallTitle),body:Ft(e.firewallBody),points:yo(e.firewallPoints)},commands:{title:Ft(e.commandsTitle),body:Ft(e.commandsBody),manager:Ft(e.managerCommandLabel),primary:Ft(e.clientCommandLabel),slot:Ft(e.slotCommandLabel),manual:Ft(e.manualCommandLabel)}}}const ki={ko:pn({languageName:"한국어",languageLabel:"문서 언어",eyebrow:"VuvoDesk Manual",title:"한 줄로 여는 로컬 Screen Wall",intro:"VuvoDesk는 매니저 PC 한 대에서 여러 작업 PC, 미니 PC, 맥미니, 개발 장비를 한 화면에 모니터링하고 필요한 제어를 실행하는 npm-first 원격 작업 데크입니다.",managerTitle:"1. 매니저 실행",managerBody:"화면을 모아 볼 컴퓨터에서 VuvoDesk 매니저를 실행합니다. 매니저는 UI와 로컬 서버를 같이 열고 브라우저를 http://127.0.0.1:5179 로 띄웁니다.",managerPoints:["명령은 npx -y livedesk 입니다.","매니저는 Screen Wall/API 포트 5179와 클라이언트 접속 포트 5197을 사용합니다.","기존 VuvoDesk 포트가 남아 있으면 기본적으로 정리하고 새로 시작합니다. 필요하면 --no-clean 을 붙입니다."],clientTitle:"2. 워크스테이션 연결",clientBody:"모니터링할 PC에서는 Google 로그인 또는 Hub 화면의 6자리 PIN으로 연결합니다. Hub가 꺼져 있으면 실시간 온라인 알림을 기다리고 적응형 간격으로 다시 확인합니다.",clientPoints:["빈 자리에 자동 배치하려면 npx -y livedesk client 를 실행합니다.","자리 번호를 고정하려면 npx -y livedesk client 3 처럼 번호를 붙입니다.","브라우저 연결 페이지에서 Google 버튼 또는 6자리 PIN 입력 중 하나를 선택합니다."],syncTitle:"3. Sync Server와 자동 발견",syncBody:"Sync Server는 이 매니저를 현재 계정의 활성 Screen Wall로 Supabase에 등록합니다. 클라이언트는 같은 Google 계정으로 로그인한 뒤 그 기록을 읽고 접속 후보들을 순서대로 시도합니다.",syncPoints:["등록 정보에는 host instance, LAN/private 주소, public 후보 주소, pair token, 짧은 lease가 포함됩니다.","같은 LAN 후보를 먼저 쓰고, 필요하면 외부 주소 후보를 시도합니다.","매니저 위치, VPN, 방화벽, 공유기 설정이 바뀌었거나 개발 중 활성 매니저를 바꿀 때 Sync Server를 누릅니다.","이제 vuvodesk.com의 Chrome Local Network Access 허용은 기본 실행 경로가 아닙니다. npm 매니저 앱이 실제 서버입니다."],agentTitle:"4. Agent로 여러 장비 작업하기",agentBody:"Agents 화면은 Hub에서 실행되는 Codex 기반 Agent가 연결된 장비를 확인하고, 선택한 권한 범위 안에서 작업을 실행하는 공간입니다. 클라이언트 PC에 Codex 앱이나 Codex SDK를 설치할 필요는 없습니다.",agentPoints:["Suggested tasks에는 일반적인 읽기·운영 명령 템플릿이 있으며, 검색과 권한·플랫폼·capability 조건으로 실행 가능 항목을 안내합니다.","Ask, Safe Auto, Full Access, Custom 권한 모드를 선택할 수 있습니다. 위험한 변경 작업은 승인 카드와 장비 capability 검사를 거칩니다.","All connected 또는 Selected로 대상 장비를 제한하고, 결과는 장비별 상태 칩과 실제 RAM·디스크·GPU·프로세스 요약으로 확인합니다.","Hub의 Codex Agent는 지시를 승인된 VuvoDesk 도구로 변환하고 컴퓨터별 실행 상태와 결과를 표시합니다."],platformTitle:"5. 현재 플랫폼과 스트림 상태",platformBody:"Windows의 Wall, Control, 파일 전송, 원격 오디오와 RemoteFast 경로를 현재 기준으로 확인했습니다. macOS와 Linux는 같은 npm 명령 경로를 유지하면서 권한과 캡처 백엔드를 확장하고 있습니다.",platformPoints:["자동 Wall과 Control은 모든 Client에서 직접 H.264를 사용합니다. RGB565/LZO Atlas는 내부 진단 실험에만 남고 자동 전송 경로에는 사용되지 않습니다.","원격 오디오는 선택한 장비가 capability를 광고할 때 사용할 수 있으며, 브라우저는 queue·drop·resync·automatic restart 상태를 진단합니다.","macOS: 화면 캡처와 제어에는 Screen Recording/Accessibility 권한이 필요합니다. RemoteFast 로그는 필요한 상태 중심으로 제한됩니다.","Linux: linux-x64 runtime, X11/XTEST 입력과 PipeWire/PulseAudio 기본 출력 오디오 캡처를 지원합니다."],firewallTitle:"방화벽과 외부 장소 연결",firewallBody:"VuvoDesk는 인증된 Direct TCP와 암호화된 UDP/WebRTC P2P로 화면과 제어를 직접 연결합니다. rendezvous 서비스는 상대 찾기와 P2P 연결 정보 교환만 하며 화면·입력 데이터는 중계하지 않습니다.",firewallPoints:["LAN Direct TCP의 기본 클라이언트 포트는 5197입니다.","클라이언트와 매니저는 상대 찾기와 P2P signaling을 위해 설정된 rendezvous 서버로 나가는 연결이 가능해야 합니다.","영상과 입력 데이터는 Direct TCP 또는 암호화된 UDP/WebRTC P2P로 장치끼리 직접 전송합니다.","외부망 Direct TCP에는 TCP 5197 포트포워딩이나 VPN/IP allowlist를 설정합니다. P2P가 막히면 VuvoDesk가 직접 연결을 다시 시도합니다.","Screen Wall/API 포트 5179는 외부 브라우저가 Wall을 직접 열 때만 노출합니다."],commandsTitle:"현재 사용 명령",commandsBody:"웹사이트를 찾아가 설치 파일을 받는 방식보다 터미널 한 줄로 모든 운영체제에서 거의 같은 흐름을 쓰는 것이 VuvoDesk의 기본 방향입니다.",managerCommandLabel:"매니저 시작",clientCommandLabel:"워크스테이션 연결",slotCommandLabel:"3번 슬롯에 고정",manualCommandLabel:"고급 수동 연결"}),en:pn({languageName:"English",languageLabel:"Document language",eyebrow:"VuvoDesk Manual",title:"Open a local Screen Wall with one command",intro:"VuvoDesk is an npm-first remote work deck for monitoring Clients, mini PCs, Mac minis, and development machines from one manager PC.",managerTitle:"1. Run the manager",managerBody:"Run VuvoDesk on the computer that will watch the screens. The manager starts the UI and local server together, then opens http://127.0.0.1:5179.",managerPoints:["The command is npx -y livedesk.","The manager uses port 5179 for the Screen Wall/API and port 5197 for client connections.","If an old VuvoDesk process still owns those ports, startup cleans it by default. Add --no-clean when you want to keep it."],clientTitle:"2. Connect a Client",clientBody:"On each monitored computer, connect with Google sign-in or the 6-digit PIN shown on the Hub screen. If no manager is online yet, the client waits for a live online signal and falls back to adaptive retries.",clientPoints:["Run npx -y livedesk client for first available placement.","Run npx -y livedesk client 3 to pin the machine to slot 3.","The browser connection page lets you choose Google or a 6-digit PIN."],syncTitle:"3. Sync Server and discovery",syncBody:"Sync Server publishes this manager as the active Screen Wall for the signed-in account. Clients read that Supabase record after Google sign-in and try the endpoint candidates in order.",syncPoints:["The record includes host instance, LAN/private addresses, public endpoint candidates, pair token, and a short lease.","LAN candidates are preferred first, then public candidates if needed.","Press Sync Server after manager moves, VPN/firewall/router changes, or when this development machine should take over as active manager.","Chrome Local Network Access on vuvodesk.com is no longer the default runtime path. The npm manager app is the real server."],agentTitle:"4. Run multi-Client tasks with Agent",agentBody:"The Agents page runs a Codex-based Agent in the Hub to inspect connected Clients and perform actions within the selected permission scope. Client PCs do not need the Codex app or Codex SDK installed.",agentPoints:["Suggested tasks provide generic read-only and operational command templates with search plus permission, platform, and capability checks.","Choose Ask, Safe Auto, Full Access, or Custom. Risky changes go through approval cards and explicit Client capability checks.","Limit targets with All connected or Selected. Results use compact per-device status chips and show real RAM, disk, GPU, and process summaries.","The Hub-hosted Codex Agent turns instructions into approved VuvoDesk tool calls and shows progress and results for each computer."],platformTitle:"5. Current platform and stream state",platformBody:"Windows Wall, Control, file transfer, remote audio, and the RemoteFast path are verified against the current implementation. macOS and Linux keep the same npm command path while capture and permission backends expand.",platformPoints:["Automatic Wall and Control use direct H.264 for every Client. The RGB565/LZO Atlas remains only for internal diagnostic experiments and is never selected automatically.","Remote audio is available when the selected Client advertises the capability, with queue, drop, resync, and automatic-restart diagnostics in the browser.","macOS requires Screen Recording and Accessibility permissions for capture and control. RemoteFast logs focus on actionable state.","Linux includes the linux-x64 runtime, X11/XTEST input, and default-output audio capture through PipeWire or PulseAudio."],firewallTitle:"Firewall and remote locations",firewallBody:"VuvoDesk connects screen and control payloads directly through authenticated Direct TCP and encrypted UDP/WebRTC P2P. The rendezvous service only finds peers and exchanges P2P connection details; it never carries screen or input payloads.",firewallPoints:["The default LAN Direct TCP client port is 5197.","Clients and the manager need outbound access to the configured rendezvous server for peer discovery and P2P signaling.","Screen and input payloads travel device-to-device through Direct TCP or encrypted UDP/WebRTC P2P.","For Direct TCP across networks, forward TCP 5197 or configure VPN/IP allowlists. When P2P is blocked, VuvoDesk keeps retrying a direct connection.","Expose Screen Wall/API port 5179 only when a remote browser must open the Wall directly."],commandsTitle:"Current commands",commandsBody:"The product direction is one terminal command across operating systems instead of finding a website, downloading, and installing manually.",managerCommandLabel:"Start manager",clientCommandLabel:"Connect Client",slotCommandLabel:"Pin to slot 3",manualCommandLabel:"Advanced manual connection"}),ja:pn({languageName:"日本語",languageLabel:"ドキュメント言語",eyebrow:"VuvoDesk Manual",title:"1行でローカル Screen Wall を開く",intro:"VuvoDesk は、複数の作業 PC、mini PC、Mac mini、開発機を1台の manager PC から監視する npm-first のリモート作業デッキです。",managerTitle:"1. manager を実行",managerBody:"画面を集めて見るコンピューターで VuvoDesk manager を実行します。UI とローカルサーバーが同時に起動し、http://127.0.0.1:5179 が開きます。",managerPoints:["コマンドは npx -y livedesk です。","Screen Wall/API は 5179、client 接続は 5197 を使います。","古い VuvoDesk プロセスがポートを使っている場合は、基本的に自動で整理して起動します。"],clientTitle:"2. Client を接続",clientBody:"監視される PC で同じ Google アカウントにログインします。manager がまだ無い場合、client はオンライン通知を待ち、適応型の間隔で再確認します。",clientPoints:["空きスロットに入れるには npx -y livedesk client を実行します。","スロットを固定するには npx -y livedesk client 3 のように番号を付けます。","大量の PC でも再ログインなしで待ち続けます。"],syncTitle:"3. Sync Server と自動検出",syncBody:"Sync Server はこの manager を現在の Google アカウントの active Screen Wall として Supabase に登録します。",syncPoints:["host instance、LAN/private アドレス、public 候補、pair token、短い lease を登録します。","client は LAN 候補を優先し、必要なら public 候補も試します。","VPN、firewall、router、manager の場所が変わったら Sync Server を押します。","vuvodesk.com の Chrome Local Network Access は標準実行経路ではありません。npm manager アプリが実際のサーバーです。"],platformTitle:"4. 現在のプラットフォーム状態",platformBody:"Windows は live screen transfer まで確認済みです。macOS と Linux も同じ npm コマンド経路を目標に対応を広げています。",platformPoints:["Windows: 動作確認済み。","macOS: 画面取得と制御には Screen Recording/Accessibility 権限が必要です。","Linux: linux-x64 runtime、grim/gnome-screenshot/import/scrot capture、X11/XTEST input backend を追加済み。audio は未対応です。"],firewallTitle:"Firewall と外部拠点",firewallBody:"VuvoDesk は認証済み Direct TCP と暗号化 UDP/WebRTC P2P で画面と操作を直接接続します。rendezvous サービスは相手の発見と P2P 接続情報の交換だけを行い、画面や入力データを中継しません。",firewallPoints:["LAN の Direct TCP client 既定ポートは 5197 です。","client と manager は相手の発見と P2P signaling のため、設定済み rendezvous server へ outbound 接続できる必要があります。","画面と入力データは Direct TCP または暗号化 UDP/WebRTC P2P で端末間を直接移動します。","ネットワーク越しの Direct TCP には TCP 5197 の転送または VPN/IP allowlist を設定します。P2P が遮断された場合は直接接続を再試行します。","5179 は外部ブラウザが Wall を直接開く場合だけ公開します。"],commandsTitle:"現在のコマンド",commandsBody:"Web サイトから installer を探すより、OS をまたいで terminal 1行で動かす方向です。",managerCommandLabel:"manager 起動",clientCommandLabel:"Client 接続",slotCommandLabel:"slot 3 に固定",manualCommandLabel:"高度な手動接続"}),"zh-CN":pn({languageName:"简体中文",languageLabel:"文档语言",eyebrow:"VuvoDesk Manual",title:"用一条命令打开本地 Screen Wall",intro:"VuvoDesk 是 npm-first 的远程工作台,用一台 manager PC 监控多台工作电脑、迷你主机、Mac mini 和开发机器。",managerTitle:"1. 运行 manager",managerBody:"在负责查看屏幕的电脑上运行 VuvoDesk manager。它会同时启动 UI 和本地服务器,并打开 http://127.0.0.1:5179。",managerPoints:["命令是 npx -y livedesk。","Screen Wall/API 使用 5179,client 连接使用 5197。","如果旧的 VuvoDesk 进程占用端口,默认会清理后重新启动。"],clientTitle:"2. 连接 Client",clientBody:"在被监控的电脑上使用同一个 Google 账号登录。如果 manager 尚未在线,client 会等待上线通知,并以自适应间隔重新检查。",clientPoints:["自动放入空位: npx -y livedesk client。","固定到 3 号位置: npx -y livedesk client 3。","大量电脑也可以持续等待,不需要反复登录。"],syncTitle:"3. Sync Server 和自动发现",syncBody:"Sync Server 会把当前 manager 作为该账号的 active Screen Wall 写入 Supabase。client 登录后读取记录并依次尝试连接候选地址。",syncPoints:["记录包括 host instance、LAN/private 地址、public 候选、pair token 和短 lease。","优先尝试同一 LAN 地址,需要时再尝试外部地址。","manager 位置、VPN、防火墙或路由变化后请点击 Sync Server。","vuvodesk.com 的 Chrome Local Network Access 不再是默认运行方式。npm manager app 才是真正服务器。"],platformTitle:"4. 当前平台状态",platformBody:"Windows 已确认可传输实时画面。macOS 和 Linux 正按同一 npm 命令路径扩展支持。",platformPoints:["Windows: 已确认可用。","macOS: 画面捕获和控制需要 Screen Recording/Accessibility 权限。","Linux: 已加入 linux-x64 runtime、grim/gnome-screenshot/import/scrot 捕获、X11/XTEST 输入后端。音频尚未启用。"],firewallTitle:"防火墙和外部地点",firewallBody:"VuvoDesk 通过经过认证的 Direct TCP 和加密 UDP/WebRTC P2P 直接传送画面与控制。rendezvous 服务只负责发现对端和交换 P2P 连接信息,不会转发画面或输入数据。",firewallPoints:["LAN Direct TCP 的默认 client 端口是 5197。","client 和 manager 必须能向已配置的 rendezvous server 建立出站连接,用于发现对端和 P2P signaling。","画面和输入数据通过 Direct TCP 或加密 UDP/WebRTC P2P 在设备之间直接传送。","跨网络使用 Direct TCP 时请转发 TCP 5197 或配置 VPN/IP 白名单。P2P 被阻断时会继续重试直连。","只有远程浏览器需要直接打开 Wall 时才暴露 5179。"],commandsTitle:"当前命令",commandsBody:"产品方向是跨操作系统使用一条终端命令,而不是先找网站、下载、安装。",managerCommandLabel:"启动 manager",clientCommandLabel:"连接 Client",slotCommandLabel:"固定到 slot 3",manualCommandLabel:"高级手动连接"}),"zh-TW":pn({languageName:"繁體中文",languageLabel:"文件語言",eyebrow:"VuvoDesk Manual",title:"用一行指令開啟本機 Screen Wall",intro:"VuvoDesk 是 npm-first 的遠端工作台,用一台 manager PC 監看多台工作電腦、迷你主機、Mac mini 與開發機。",managerTitle:"1. 執行 manager",managerBody:"在負責看畫面的電腦上執行 VuvoDesk manager。它會同時啟動 UI 與本機伺服器,並開啟 http://127.0.0.1:5179。",managerPoints:["指令是 npx -y livedesk。","Screen Wall/API 使用 5179,client 連線使用 5197。","若舊的 VuvoDesk 程序占用連接埠,預設會清理後重新啟動。"],clientTitle:"2. 連接 Client",clientBody:"在被監看的電腦上使用同一個 Google 帳號登入。如果 manager 尚未上線,client 會等待上線通知,並以自適應間隔重新檢查。",clientPoints:["自動放入空位: npx -y livedesk client。","固定到 3 號位置: npx -y livedesk client 3。","大量電腦也能持續等待,不需要反覆登入。"],syncTitle:"3. Sync Server 與自動探索",syncBody:"Sync Server 會把目前 manager 登錄為此帳號的 active Screen Wall。client 登入後讀取 Supabase 記錄並依序嘗試連線候選地址。",syncPoints:["記錄包含 host instance、LAN/private 位址、public 候選、pair token 與短 lease。","優先嘗試 LAN 位址,需要時再嘗試外部位址。","manager 位置、VPN、防火牆或路由設定改變後請按 Sync Server。","vuvodesk.com 的 Chrome Local Network Access 不再是預設執行路徑。npm manager app 才是真正伺服器。"],platformTitle:"4. 目前平台狀態",platformBody:"Windows 已確認可傳輸即時畫面。macOS 與 Linux 也沿用相同 npm 指令路徑擴充支援。",platformPoints:["Windows: 已確認可用。","macOS: 畫面擷取與控制需要 Screen Recording/Accessibility 權限。","Linux: 已加入 linux-x64 runtime、grim/gnome-screenshot/import/scrot capture、X11/XTEST input backend。音訊尚未啟用。"],firewallTitle:"防火牆與外部地點",firewallBody:"VuvoDesk 透過已驗證的 Direct TCP 與加密 UDP/WebRTC P2P 直接傳送畫面和控制。rendezvous 服務只負責尋找對端與交換 P2P 連線資訊,不會轉送畫面或輸入資料。",firewallPoints:["LAN Direct TCP 的預設 client 連接埠是 5197。","client 與 manager 必須能向已設定的 rendezvous server 建立外送連線,以尋找對端並進行 P2P signaling。","畫面與輸入資料透過 Direct TCP 或加密 UDP/WebRTC P2P 在裝置間直接傳送。","跨網路使用 Direct TCP 時請轉送 TCP 5197 或設定 VPN/IP allowlist。P2P 受阻時會持續重試直連。","只有遠端瀏覽器需要直接開啟 Wall 時才公開 5179。"],commandsTitle:"目前指令",commandsBody:"產品方向是跨作業系統用一行 terminal 指令,而不是先找網站、下載、安裝。",managerCommandLabel:"啟動 manager",clientCommandLabel:"連接 Client",slotCommandLabel:"固定到 slot 3",manualCommandLabel:"進階手動連線"}),es:pn({languageName:"Español",languageLabel:"Idioma del documento",eyebrow:"VuvoDesk Manual",title:"Abre un Screen Wall local con un comando",intro:"VuvoDesk es una consola npm-first para vigilar equipos de trabajo, mini PC, Mac mini y equipos de desarrollo desde un PC manager.",managerTitle:"1. Ejecuta el manager",managerBody:"Ejecuta VuvoDesk en el equipo que verá las pantallas. El manager inicia la UI y el servidor local juntos y abre http://127.0.0.1:5179.",managerPoints:["El comando es npx -y livedesk.","El manager usa 5179 para Screen Wall/API y 5197 para conexiones client.","Si un proceso antiguo ocupa los puertos, el arranque lo limpia por defecto."],clientTitle:"2. Conecta una Client",clientBody:"En cada equipo monitoreado, inicia sesión con la misma cuenta Google. Si el manager aún no está activo, el client espera una señal en tiempo real y vuelve a comprobar con intervalos adaptativos.",clientPoints:["Usa npx -y livedesk client para el primer slot libre.","Usa npx -y livedesk client 3 para fijar el equipo al slot 3.","Los clients siguen esperando para no repetir login en muchas máquinas."],syncTitle:"3. Sync Server y descubrimiento",syncBody:"Sync Server publica este manager como Screen Wall activo para la cuenta. Los clients leen el registro en Supabase y prueban los endpoints.",syncPoints:["Incluye host instance, direcciones LAN/private, candidatos public, pair token y lease corto.","Primero se prueban candidatos LAN, luego públicos si hace falta.","Pulsa Sync Server después de cambios de manager, VPN, firewall o router.","Chrome Local Network Access en vuvodesk.com ya no es el flujo principal. La app npm manager es el servidor real."],platformTitle:"4. Estado de plataformas",platformBody:"Windows ya fue verificado con transferencia de pantalla. macOS y Linux siguen el mismo camino npm.",platformPoints:["Windows: verificado.","macOS: captura y control requieren permisos Screen Recording/Accessibility.","Linux: runtime linux-x64, entrada X11/XTEST y audio de salida mediante PipeWire o PulseAudio."],firewallTitle:"Firewall y sedes remotas",firewallBody:"VuvoDesk conecta pantalla y control directamente mediante Direct TCP autenticado y UDP/WebRTC P2P cifrado. El servicio rendezvous solo localiza pares e intercambia datos de conexión P2P; no reenvía pantallas ni entradas.",firewallPoints:["El puerto client predeterminado para Direct TCP en LAN es 5197.","Clients y manager necesitan acceso saliente al servidor rendezvous configurado para descubrir pares y hacer signaling P2P.","Pantalla e input viajan entre dispositivos por Direct TCP o UDP/WebRTC P2P cifrado.","Para Direct TCP entre redes, reenvía TCP 5197 o configura VPN/allowlist de IP. Si P2P está bloqueado, VuvoDesk sigue intentando una conexión directa.","Expón 5179 solo si un navegador remoto debe abrir el Wall directamente."],commandsTitle:"Comandos actuales",commandsBody:"La dirección del producto es un comando de terminal común entre sistemas, no descargar e instalar desde una web.",managerCommandLabel:"Iniciar manager",clientCommandLabel:"Conectar Client",slotCommandLabel:"Fijar al slot 3",manualCommandLabel:"Conexión manual avanzada"}),fr:pn({languageName:"Français",languageLabel:"Langue du document",eyebrow:"VuvoDesk Manual",title:"Ouvrir un Screen Wall local en une commande",intro:"VuvoDesk est un deck npm-first pour surveiller plusieurs postes, mini PC, Mac mini et machines dev depuis un PC manager.",managerTitle:"1. Lancer le manager",managerBody:"Lancez VuvoDesk sur l’ordinateur qui observe les écrans. Le manager démarre l’UI et le serveur local, puis ouvre http://127.0.0.1:5179.",managerPoints:["La commande est npx -y livedesk.","Le manager utilise 5179 pour Screen Wall/API et 5197 pour les connexions client.","Si un ancien processus utilise les ports, le démarrage le nettoie par défaut."],clientTitle:"2. Connecter une Client",clientBody:"Sur chaque ordinateur surveillé, connectez-vous avec le même compte Google. Si le manager n’est pas encore actif, le client réessaie toutes les 5 secondes.",clientPoints:["Utilisez npx -y livedesk client pour le premier slot libre.","Utilisez npx -y livedesk client 3 pour fixer la machine au slot 3.","Les clients continuent d’attendre pour éviter les reconnexions répétées."],syncTitle:"3. Sync Server et découverte",syncBody:"Sync Server publie ce manager comme Screen Wall actif du compte. Les clients lisent l’enregistrement Supabase et testent les endpoints.",syncPoints:["Il contient host instance, adresses LAN/private, candidats public, pair token et lease court.","Les candidats LAN sont essayés en premier, puis les candidats publics si besoin.","Cliquez Sync Server après un changement de manager, VPN, firewall ou routeur.","Chrome Local Network Access sur vuvodesk.com n’est plus le chemin par défaut. L’app npm manager est le vrai serveur."],platformTitle:"4. État des plateformes",platformBody:"Windows est vérifié avec transfert d’écran live. macOS et Linux suivent le même chemin npm.",platformPoints:["Windows: vérifié.","macOS: capture et contrôle nécessitent Screen Recording/Accessibility.","Linux: runtime linux-x64, entrée X11/XTEST et audio de sortie via PipeWire ou PulseAudio."],firewallTitle:"Firewall et sites distants",firewallBody:"VuvoDesk relie directement l’écran et le contrôle par Direct TCP authentifié et UDP/WebRTC P2P chiffré. Le service rendezvous sert uniquement à trouver les pairs et à échanger les informations P2P ; il ne transmet ni écran ni saisie.",firewallPoints:["Le port client Direct TCP par défaut sur le LAN est 5197.","Clients et manager doivent accéder au serveur rendezvous configuré pour la découverte et le signaling P2P.","Écran et saisie passent directement entre appareils par Direct TCP ou UDP/WebRTC P2P chiffré.","Pour Direct TCP entre réseaux, redirigez TCP 5197 ou configurez VPN/allowlist IP. Si le P2P est bloqué, VuvoDesk retente une connexion directe.","Exposez 5179 uniquement si un navigateur distant doit ouvrir directement le Wall."],commandsTitle:"Commandes actuelles",commandsBody:"La direction produit est une commande terminal commune aux OS, plutôt qu’un téléchargement manuel depuis un site.",managerCommandLabel:"Démarrer manager",clientCommandLabel:"Connecter Client",slotCommandLabel:"Fixer au slot 3",manualCommandLabel:"Connexion manuelle avancée"}),de:pn({languageName:"Deutsch",languageLabel:"Dokumentsprache",eyebrow:"VuvoDesk Manual",title:"Lokale Screen Wall mit einem Befehl öffnen",intro:"VuvoDesk ist ein npm-first Arbeitsdeck, um viele Clients, Mini-PCs, Mac minis und Dev-Rechner von einem Manager-PC zu überwachen.",managerTitle:"1. Manager starten",managerBody:"Starte VuvoDesk auf dem Computer, der die Screens sieht. Der Manager startet UI und lokalen Server zusammen und öffnet http://127.0.0.1:5179.",managerPoints:["Der Befehl ist npx -y livedesk.","Der Manager nutzt 5179 für Screen Wall/API und 5197 für Client-Verbindungen.","Wenn alte VuvoDesk-Prozesse Ports belegen, werden sie beim Start standardmäßig bereinigt."],clientTitle:"2. Client verbinden",clientBody:"Melde dich auf jedem überwachten Computer mit demselben Google-Konto an. Wenn kein Manager online ist, wartet der Client auf ein Live-Signal und prüft mit adaptiven Intervallen erneut.",clientPoints:["npx -y livedesk client nutzt den ersten freien Slot.","npx -y livedesk client 3 fixiert den Rechner auf Slot 3.","Clients warten weiter, damit große Setups kein wiederholtes Login brauchen."],syncTitle:"3. Sync Server und Discovery",syncBody:"Sync Server veröffentlicht diesen Manager als aktive Screen Wall des Kontos. Clients lesen den Supabase-Eintrag und testen Endpoints der Reihe nach.",syncPoints:["Enthält host instance, LAN/private Adressen, public Kandidaten, pair token und kurze lease.","LAN-Kandidaten werden zuerst versucht, danach public Kandidaten.","Nach Änderungen an Manager, VPN, Firewall oder Router Sync Server drücken.","Chrome Local Network Access auf vuvodesk.com ist nicht mehr der Standardpfad. Die npm Manager App ist der echte Server."],platformTitle:"4. Plattformstatus",platformBody:"Windows wurde mit Live-Screen-Transfer geprüft. macOS und Linux folgen demselben npm-Pfad.",platformPoints:["Windows: verifiziert.","macOS: Capture und Control brauchen Screen Recording/Accessibility Rechte.","Linux: linux-x64 Runtime, X11/XTEST Eingabe und Ausgangsaudio über PipeWire oder PulseAudio."],firewallTitle:"Firewall und entfernte Standorte",firewallBody:"VuvoDesk verbindet Bildschirm und Steuerung direkt über authentifiziertes Direct TCP und verschlüsseltes UDP/WebRTC P2P. Der Rendezvous-Dienst findet nur Peers und tauscht P2P-Verbindungsdaten aus; Bildschirm- und Eingabedaten werden nicht weitergeleitet.",firewallPoints:["Der Standardport für LAN Direct TCP Clients ist 5197.","Clients und Manager benötigen ausgehenden Zugriff auf den konfigurierten Rendezvous-Server für Peer-Erkennung und P2P-Signaling.","Bildschirm- und Eingabedaten laufen direkt zwischen Geräten über Direct TCP oder verschlüsseltes UDP/WebRTC P2P.","Für Direct TCP zwischen Netzwerken TCP 5197 weiterleiten oder VPN/IP-Allowlist einrichten. Wenn P2P blockiert ist, versucht VuvoDesk die direkte Verbindung erneut.","5179 nur öffnen, wenn ein Remote-Browser die Wall direkt laden muss."],commandsTitle:"Aktuelle Befehle",commandsBody:"Die Produktlinie ist ein Terminalbefehl über Betriebssysteme hinweg, statt Website suchen, herunterladen und installieren.",managerCommandLabel:"Manager starten",clientCommandLabel:"Client verbinden",slotCommandLabel:"An Slot 3 fixieren",manualCommandLabel:"Erweiterte manuelle Verbindung"}),"pt-BR":pn({languageName:"Português",languageLabel:"Idioma do documento",eyebrow:"VuvoDesk Manual",title:"Abra um Screen Wall local com um comando",intro:"VuvoDesk é um deck npm-first para monitorar várias estações, mini PCs, Mac minis e máquinas dev a partir de um PC manager.",managerTitle:"1. Execute o manager",managerBody:"Rode VuvoDesk no computador que verá as telas. O manager inicia a UI e o servidor local juntos e abre http://127.0.0.1:5179.",managerPoints:["O comando é npx -y livedesk.","O manager usa 5179 para Screen Wall/API e 5197 para conexões client.","Se um processo antigo ocupa as portas, a inicialização limpa por padrão."],clientTitle:"2. Conecte uma Client",clientBody:"Em cada computador monitorado, entre com a mesma conta Google. Se o manager ainda não estiver online, o client aguarda um sinal em tempo real e verifica novamente em intervalos adaptativos.",clientPoints:["Use npx -y livedesk client para o primeiro slot livre.","Use npx -y livedesk client 3 para fixar no slot 3.","Clients continuam tentando para evitar login repetido em muitos PCs."],syncTitle:"3. Sync Server e descoberta",syncBody:"Sync Server publica este manager como Screen Wall ativo da conta. Clients leem o registro no Supabase e testam endpoints.",syncPoints:["Inclui host instance, endereços LAN/private, candidatos public, pair token e lease curto.","Candidatos LAN vêm primeiro; public depois se necessário.","Clique Sync Server após mudanças de manager, VPN, firewall ou roteador.","Chrome Local Network Access em vuvodesk.com não é mais o caminho padrão. O app npm manager é o servidor real."],platformTitle:"4. Estado das plataformas",platformBody:"Windows foi verificado com transferência de tela. macOS e Linux seguem o mesmo caminho npm.",platformPoints:["Windows: verificado.","macOS: captura e controle precisam de permissões Screen Recording/Accessibility.","Linux: runtime linux-x64, captura grim/gnome-screenshot/import/scrot e entrada X11/XTEST adicionados. Áudio ainda desativado."],firewallTitle:"Firewall e locais remotos",firewallBody:"VuvoDesk conecta tela e controle diretamente por Direct TCP autenticado e UDP/WebRTC P2P criptografado. O serviço rendezvous apenas encontra os pares e troca dados de conexão P2P; ele não encaminha tela nem entrada.",firewallPoints:["A porta client padrão para Direct TCP na LAN é 5197.","Clients e manager precisam de acesso de saída ao servidor rendezvous configurado para descoberta e signaling P2P.","Tela e entrada trafegam diretamente entre dispositivos por Direct TCP ou UDP/WebRTC P2P criptografado.","Para Direct TCP entre redes, encaminhe TCP 5197 ou configure VPN/allowlist IP. Se o P2P estiver bloqueado, VuvoDesk continua tentando conexão direta.","Exponha 5179 somente se um navegador remoto precisar abrir o Wall diretamente."],commandsTitle:"Comandos atuais",commandsBody:"A direção do produto é um comando de terminal comum entre sistemas, não baixar e instalar manualmente.",managerCommandLabel:"Iniciar manager",clientCommandLabel:"Conectar Client",slotCommandLabel:"Fixar no slot 3",manualCommandLabel:"Conexão manual avançada"}),it:pn({languageName:"Italiano",languageLabel:"Lingua documento",eyebrow:"VuvoDesk Manual",title:"Apri uno Screen Wall locale con un comando",intro:"VuvoDesk è un deck npm-first per monitorare Client, mini PC, Mac mini e macchine dev da un solo PC manager.",managerTitle:"1. Avvia il manager",managerBody:"Esegui VuvoDesk sul computer che guarderà gli schermi. Il manager avvia UI e server locale e apre http://127.0.0.1:5179.",managerPoints:["Il comando è npx -y livedesk.","Il manager usa 5179 per Screen Wall/API e 5197 per connessioni client.","Se vecchi processi occupano le porte, l’avvio le pulisce di default."],clientTitle:"2. Connetti una Client",clientBody:"Su ogni computer monitorato, accedi con lo stesso account Google. Se il manager non è online, il client riprova ogni 5 secondi.",clientPoints:["npx -y livedesk client usa il primo slot libero.","npx -y livedesk client 3 fissa la macchina allo slot 3.","I client continuano a provare per evitare login ripetuti."],syncTitle:"3. Sync Server e discovery",syncBody:"Sync Server pubblica questo manager come Screen Wall attivo dell’account. I client leggono Supabase e provano gli endpoint.",syncPoints:["Include host instance, indirizzi LAN/private, candidati public, pair token e lease breve.","Prima LAN, poi public se necessario.","Premi Sync Server dopo cambi di manager, VPN, firewall o router.","Chrome Local Network Access su vuvodesk.com non è più il percorso principale. L’app npm manager è il server reale."],platformTitle:"4. Stato piattaforme",platformBody:"Windows è verificato con trasferimento schermo live. macOS e Linux seguono lo stesso percorso npm.",platformPoints:["Windows: verificato.","macOS: capture e control richiedono permessi Screen Recording/Accessibility.","Linux: aggiunti runtime linux-x64, capture grim/gnome-screenshot/import/scrot e input X11/XTEST. Audio disattivato."],firewallTitle:"Firewall e sedi remote",firewallBody:"VuvoDesk collega schermo e controllo direttamente con Direct TCP autenticato e UDP/WebRTC P2P cifrato. Il servizio rendezvous trova solo i peer e scambia le informazioni P2P; non inoltra schermo o input.",firewallPoints:["La porta client predefinita per Direct TCP in LAN è 5197.","Client e manager devono accedere al server rendezvous configurato per discovery e signaling P2P.","Schermo e input viaggiano direttamente tra dispositivi tramite Direct TCP o UDP/WebRTC P2P cifrato.","Per Direct TCP tra reti, inoltra TCP 5197 o configura VPN/allowlist IP. Se il P2P è bloccato, VuvoDesk ritenta la connessione diretta.","Esponi 5179 soltanto se un browser remoto deve aprire direttamente la Wall."],commandsTitle:"Comandi attuali",commandsBody:"La direzione è un comando terminale comune tra sistemi operativi, invece di download e install manuale.",managerCommandLabel:"Avvia manager",clientCommandLabel:"Connetti Client",slotCommandLabel:"Fissa allo slot 3",manualCommandLabel:"Connessione manuale avanzata"}),id:pn({languageName:"Bahasa Indonesia",languageLabel:"Bahasa dokumen",eyebrow:"VuvoDesk Manual",title:"Buka Screen Wall lokal dengan satu perintah",intro:"VuvoDesk adalah deck npm-first untuk memantau banyak Client, mini PC, Mac mini, dan mesin dev dari satu PC manager.",managerTitle:"1. Jalankan manager",managerBody:"Jalankan VuvoDesk di komputer yang melihat layar. Manager membuka UI dan server lokal bersama, lalu membuka http://127.0.0.1:5179.",managerPoints:["Perintahnya npx -y livedesk.","Manager memakai 5179 untuk Screen Wall/API dan 5197 untuk koneksi client.","Jika proses lama memakai port itu, startup membersihkannya secara default."],clientTitle:"2. Hubungkan Client",clientBody:"Di komputer yang dipantau, masuk dengan akun Google yang sama. Jika manager belum online, client tetap mencoba tiap 5 detik.",clientPoints:["npx -y livedesk client memakai slot kosong pertama.","npx -y livedesk client 3 mengunci mesin ke slot 3.","Client terus mencoba agar banyak PC tidak perlu login berulang."],syncTitle:"3. Sync Server dan discovery",syncBody:"Sync Server menerbitkan manager ini sebagai Screen Wall aktif untuk akun. Client membaca Supabase dan mencoba endpoint.",syncPoints:["Berisi host instance, alamat LAN/private, kandidat public, pair token, dan lease pendek.","Kandidat LAN dicoba lebih dulu, lalu public jika perlu.","Tekan Sync Server setelah perubahan manager, VPN, firewall, atau router.","Chrome Local Network Access di vuvodesk.com bukan jalur utama lagi. App npm manager adalah server sebenarnya."],platformTitle:"4. Status platform",platformBody:"Windows sudah diverifikasi dengan live screen transfer. macOS dan Linux mengikuti jalur npm yang sama.",platformPoints:["Windows: terverifikasi.","macOS: capture dan control perlu izin Screen Recording/Accessibility.","Linux: runtime linux-x64, capture grim/gnome-screenshot/import/scrot, dan input X11/XTEST sudah ditambahkan. Audio belum aktif."],firewallTitle:"Firewall dan lokasi luar",firewallBody:"VuvoDesk menghubungkan layar dan kontrol secara langsung melalui Direct TCP terautentikasi dan UDP/WebRTC P2P terenkripsi. Layanan rendezvous hanya menemukan peer dan menukar informasi koneksi P2P; tidak meneruskan layar atau input.",firewallPoints:["Port client default untuk Direct TCP di LAN adalah 5197.","Client dan manager memerlukan akses keluar ke server rendezvous untuk discovery dan signaling P2P.","Layar dan input bergerak langsung antardevice melalui Direct TCP atau UDP/WebRTC P2P terenkripsi.","Untuk Direct TCP antarjaringan, forward TCP 5197 atau atur VPN/IP allowlist. Jika P2P diblokir, VuvoDesk terus mencoba koneksi langsung.","Buka 5179 hanya jika browser jarak jauh harus membuka Wall secara langsung."],commandsTitle:"Perintah saat ini",commandsBody:"Arah produk adalah satu perintah terminal lintas OS, bukan download dan instal manual.",managerCommandLabel:"Mulai manager",clientCommandLabel:"Hubungkan Client",slotCommandLabel:"Kunci ke slot 3",manualCommandLabel:"Koneksi manual lanjutan"}),vi:pn({languageName:"Tiếng Việt",languageLabel:"Ngôn ngữ tài liệu",eyebrow:"VuvoDesk Manual",title:"Mở Screen Wall cục bộ bằng một lệnh",intro:"VuvoDesk là deck npm-first để giám sát nhiều Client, mini PC, Mac mini và máy dev từ một PC manager.",managerTitle:"1. Chạy manager",managerBody:"Chạy VuvoDesk trên máy dùng để xem màn hình. Manager khởi động UI và server cục bộ cùng lúc, rồi mở http://127.0.0.1:5179.",managerPoints:["Lệnh là npx -y livedesk.","Manager dùng 5179 cho Screen Wall/API và 5197 cho kết nối client.","Nếu tiến trình cũ giữ port, startup mặc định sẽ dọn và khởi động lại."],clientTitle:"2. Kết nối Client",clientBody:"Trên mỗi máy được giám sát, đăng nhập cùng tài khoản Google. Nếu manager chưa online, client tiếp tục thử mỗi 5 giây.",clientPoints:["npx -y livedesk client dùng slot trống đầu tiên.","npx -y livedesk client 3 ghim máy vào slot 3.","Client tiếp tục chờ để nhiều máy không cần đăng nhập lại."],syncTitle:"3. Sync Server và tự phát hiện",syncBody:"Sync Server đăng manager này là Screen Wall đang hoạt động của tài khoản. Client đọc Supabase và thử các endpoint.",syncPoints:["Bao gồm host instance, địa chỉ LAN/private, public candidate, pair token và lease ngắn.","Ưu tiên LAN trước, sau đó thử public nếu cần.","Bấm Sync Server sau thay đổi manager, VPN, firewall hoặc router.","Chrome Local Network Access trên vuvodesk.com không còn là đường chạy chính. App npm manager mới là server thật."],platformTitle:"4. Trạng thái nền tảng",platformBody:"Windows đã được kiểm chứng với truyền màn hình live. macOS và Linux đi theo cùng đường npm.",platformPoints:["Windows: đã kiểm chứng.","macOS: capture và control cần quyền Screen Recording/Accessibility.","Linux: đã thêm runtime linux-x64, capture grim/gnome-screenshot/import/scrot và input X11/XTEST. Audio chưa bật."],firewallTitle:"Firewall và địa điểm ngoài",firewallBody:"VuvoDesk kết nối trực tiếp màn hình và control bằng Direct TCP đã xác thực và UDP/WebRTC P2P mã hóa. Dịch vụ rendezvous chỉ tìm peer và trao đổi thông tin kết nối P2P; không chuyển tiếp màn hình hoặc input.",firewallPoints:["Port client mặc định cho Direct TCP trong LAN là 5197.","Client và manager cần kết nối outbound tới rendezvous server để discovery và signaling P2P.","Màn hình và input đi trực tiếp giữa các thiết bị qua Direct TCP hoặc UDP/WebRTC P2P mã hóa.","Để dùng Direct TCP giữa các mạng, hãy forward TCP 5197 hoặc cấu hình VPN/IP allowlist. Khi P2P bị chặn, VuvoDesk tiếp tục thử kết nối trực tiếp.","Chỉ mở 5179 khi browser từ xa cần mở Wall trực tiếp."],commandsTitle:"Lệnh hiện tại",commandsBody:"Hướng sản phẩm là một lệnh terminal dùng chung giữa các OS, thay vì tải và cài thủ công.",managerCommandLabel:"Khởi động manager",clientCommandLabel:"Kết nối Client",slotCommandLabel:"Ghim vào slot 3",manualCommandLabel:"Kết nối thủ công nâng cao"}),th:pn({languageName:"ไทย",languageLabel:"ภาษาของเอกสาร",eyebrow:"VuvoDesk Manual",title:"เปิด Screen Wall ภายในด้วยคำสั่งเดียว",intro:"VuvoDesk คือ deck แบบ npm-first สำหรับดู Client, mini PC, Mac mini และเครื่อง dev หลายเครื่องจาก manager PC เครื่องเดียว",managerTitle:"1. รัน manager",managerBody:"รัน VuvoDesk บนเครื่องที่ใช้ดูหน้าจอ Manager จะเปิด UI และ local server พร้อมกัน แล้วเปิด http://127.0.0.1:5179",managerPoints:["คำสั่งคือ npx -y livedesk","Manager ใช้ 5179 สำหรับ Screen Wall/API และ 5197 สำหรับ client connection","ถ้า process เก่ายังใช้ port อยู่ startup จะล้างให้โดย default"],clientTitle:"2. เชื่อม Client",clientBody:"บนเครื่องที่ต้อง monitor ให้ login ด้วย Google account เดียวกัน ถ้า manager ยังไม่ออนไลน์ client จะลองใหม่ทุก 5 วินาที",clientPoints:["npx -y livedesk client จะใช้ slot ว่างแรก","npx -y livedesk client 3 จะตรึงเครื่องไว้ที่ slot 3","Client จะรอต่อเนื่องเพื่อไม่ต้อง login ซ้ำเมื่อมีหลายเครื่อง"],syncTitle:"3. Sync Server และ discovery",syncBody:"Sync Server จะ publish manager นี้เป็น active Screen Wall ของ account แล้ว client อ่านข้อมูลจาก Supabase และลอง endpoint ต่างๆ",syncPoints:["มี host instance, LAN/private address, public candidate, pair token และ short lease","ลอง LAN ก่อน แล้วค่อยลอง public ถ้าจำเป็น","กด Sync Server หลังเปลี่ยน manager, VPN, firewall หรือ router","Chrome Local Network Access บน vuvodesk.com ไม่ใช่ runtime หลักแล้ว app npm manager คือ server จริง"],platformTitle:"4. สถานะ platform",platformBody:"Windows ตรวจสอบแล้วว่าส่งภาพ live ได้ macOS และ Linux ใช้เส้นทาง npm เดียวกัน",platformPoints:["Windows: verified","macOS: capture/control ต้องใช้สิทธิ์ Screen Recording/Accessibility","Linux: เพิ่ม linux-x64 runtime, grim/gnome-screenshot/import/scrot capture และ X11/XTEST input แล้ว audio ยังปิดอยู่"],firewallTitle:"Firewall และเครื่องต่างสถานที่",firewallBody:"VuvoDesk เชื่อมหน้าจอและ control โดยตรงด้วย Direct TCP ที่ยืนยันตัวตนและ UDP/WebRTC P2P ที่เข้ารหัส บริการ rendezvous ใช้เพียงค้นหา peer และแลกข้อมูลการเชื่อมต่อ P2P โดยไม่ส่งต่อหน้าจอหรือ input",firewallPoints:["Port client เริ่มต้นสำหรับ Direct TCP ใน LAN คือ 5197","Client และ manager ต้องเชื่อมต่อ outbound ไปยัง rendezvous server เพื่อ discovery และ P2P signaling","หน้าจอและ input ส่งตรงระหว่าง device ผ่าน Direct TCP หรือ UDP/WebRTC P2P ที่เข้ารหัส","หากต้องใช้ Direct TCP ข้าม network ให้ forward TCP 5197 หรือตั้ง VPN/IP allowlist เมื่อ P2P ถูกบล็อก VuvoDesk จะลองเชื่อมตรงอีกครั้ง","เปิด 5179 เฉพาะเมื่อ browser ระยะไกลต้องเปิด Wall โดยตรง"],commandsTitle:"คำสั่งปัจจุบัน",commandsBody:"ทิศทาง product คือคำสั่ง terminal เดียวข้าม OS ไม่ใช่ download/install จากเว็บไซต์",managerCommandLabel:"เริ่ม manager",clientCommandLabel:"เชื่อม Client",slotCommandLabel:"ตรึง slot 3",manualCommandLabel:"manual connection ขั้นสูง"}),hi:pn({languageName:"हिन्दी",languageLabel:"दस्तावेज़ भाषा",eyebrow:"VuvoDesk Manual",title:"एक कमांड से local Screen Wall खोलें",intro:"VuvoDesk एक npm-first remote work deck है जिससे एक manager PC से कई Client, mini PC, Mac mini और dev machines देखे जा सकते हैं।",managerTitle:"1. manager चलाएं",managerBody:"जिस computer से screens देखनी हैं उस पर VuvoDesk manager चलाएं। यह UI और local server साथ में शुरू करता है और http://127.0.0.1:5179 खोलता है।",managerPoints:["कमांड है npx -y livedesk।","Manager Screen Wall/API के लिए 5179 और client connections के लिए 5197 इस्तेमाल करता है।","अगर पुराने VuvoDesk ports बचे हों तो startup default रूप से साफ करता है।"],clientTitle:"2. Client जोड़ें",clientBody:"हर monitored computer पर उसी Google account से sign in करें। Manager online न हो तब भी client बंद नहीं होता और हर 5 सेकंड retry करता है।",clientPoints:["npx -y livedesk client पहला खाली slot लेता है।","npx -y livedesk client 3 machine को slot 3 पर pin करता है।","बहुत सी machines हों तब भी बार-बार login की जरूरत नहीं रहती।"],syncTitle:"3. Sync Server और discovery",syncBody:"Sync Server इस manager को account का active Screen Wall बनाकर Supabase में publish करता है। Clients record पढ़कर endpoints try करते हैं।",syncPoints:["इसमें host instance, LAN/private addresses, public candidates, pair token और short lease होता है।","LAN candidates पहले try होते हैं, जरूरत हो तो public candidates।","Manager, VPN, firewall या router बदलने के बाद Sync Server दबाएं।","vuvodesk.com का Chrome Local Network Access अब default runtime नहीं है। npm manager app ही real server है।"],platformTitle:"4. Platform status",platformBody:"Windows live screen transfer के साथ verified है। macOS और Linux भी इसी npm path पर आगे बढ़ रहे हैं।",platformPoints:["Windows: verified.","macOS: capture/control के लिए Screen Recording/Accessibility permissions चाहिए।","Linux: linux-x64 runtime, X11/XTEST input और PipeWire/PulseAudio output audio capture उपलब्ध हैं।"],firewallTitle:"Firewall और remote locations",firewallBody:"VuvoDesk authenticated Direct TCP और encrypted UDP/WebRTC P2P से screen और control को सीधे जोड़ता है। rendezvous service केवल peers खोजती और P2P connection info बदलती है; screen या input data आगे नहीं भेजती।",firewallPoints:["LAN Direct TCP का default client port 5197 है।","Peer discovery और P2P signaling के लिए Clients और manager को configured rendezvous server तक outbound access चाहिए।","Screen और input data Direct TCP या encrypted UDP/WebRTC P2P से device-to-device सीधे जाते हैं।","Networks के बीच Direct TCP के लिए TCP 5197 forward या VPN/IP allowlist सेट करें। P2P block होने पर VuvoDesk direct connection फिर आज़माता है।","5179 तभी expose करें जब remote browser को Wall सीधे खोलना हो।"],commandsTitle:"Current commands",commandsBody:"Product direction है OS के बीच एक terminal command, website से download/install नहीं।",managerCommandLabel:"Start manager",clientCommandLabel:"Connect Client",slotCommandLabel:"Pin to slot 3",manualCommandLabel:"Advanced manual connection"}),ar:pn({languageName:"العربية",languageLabel:"لغة المستند",eyebrow:"VuvoDesk Manual",title:"افتح Screen Wall محلي بأمر واحد",intro:"VuvoDesk هو deck بنمط npm-first لمراقبة عدة Clients وأجهزة mini PC وMac mini وأجهزة تطوير من كمبيوتر manager واحد.",managerTitle:"1. شغل manager",managerBody:"شغل VuvoDesk على الكمبيوتر الذي سيعرض الشاشات. يبدأ manager الواجهة والخادم المحلي معا ويفتح http://127.0.0.1:5179.",managerPoints:["الأمر هو npx -y livedesk.","يستخدم manager المنفذ 5179 للواجهة/API والمنفذ 5197 لاتصالات client.","إذا بقيت عملية VuvoDesk قديمة على المنافذ، يتم تنظيفها افتراضيا عند التشغيل."],clientTitle:"2. وصل Client",clientBody:"على كل كمبيوتر تتم مراقبته، سجل الدخول بنفس حساب Google. إذا لم يكن manager متاحا، يبقى client يعمل ويحاول كل 5 ثوان.",clientPoints:["npx -y livedesk client يختار أول slot فارغ.","npx -y livedesk client 3 يثبت الجهاز في slot 3.","clients تستمر بالمحاولة لتجنب تكرار تسجيل الدخول عند كثرة الأجهزة."],syncTitle:"3. Sync Server والاكتشاف",syncBody:"Sync Server ينشر هذا manager كـ active Screen Wall للحساب. يقرأ clients سجل Supabase ويجربون endpoints بالترتيب.",syncPoints:["السجل يتضمن host instance وعناوين LAN/private وpublic candidates وpair token وlease قصير.","يتم تفضيل LAN أولا، ثم public عند الحاجة.","اضغط Sync Server بعد تغيير manager أو VPN أو firewall أو router.","Chrome Local Network Access على vuvodesk.com لم يعد مسار التشغيل الافتراضي. تطبيق npm manager هو الخادم الحقيقي."],platformTitle:"4. حالة المنصات",platformBody:"Windows تم التحقق منه مع نقل شاشة live. macOS وLinux يتبعان نفس مسار npm.",platformPoints:["Windows: تم التحقق.","macOS: capture/control يحتاجان أذونات Screen Recording/Accessibility.","Linux: تمت إضافة linux-x64 runtime وgrim/gnome-screenshot/import/scrot capture وX11/XTEST input. الصوت ما زال معطلا."],firewallTitle:"Firewall والمواقع البعيدة",firewallBody:"يربط VuvoDesk الشاشة والتحكم مباشرة عبر Direct TCP موثق وUDP/WebRTC P2P مشفر. تقتصر خدمة rendezvous على اكتشاف الأطراف وتبادل معلومات اتصال P2P، ولا تمرر الشاشة أو بيانات الإدخال.",firewallPoints:["منفذ client الافتراضي لاتصال Direct TCP داخل LAN هو 5197.","يحتاج client وmanager إلى اتصال outbound بخادم rendezvous للاكتشاف وP2P signaling.","تنتقل الشاشة وبيانات الإدخال مباشرة بين الأجهزة عبر Direct TCP أو UDP/WebRTC P2P المشفر.","لاستخدام Direct TCP بين الشبكات وجه TCP 5197 أو اضبط VPN/IP allowlist. عند حظر P2P يعيد VuvoDesk محاولة الاتصال المباشر.","اكشف 5179 فقط إذا كان browser بعيد يحتاج فتح Wall مباشرة."],commandsTitle:"الأوامر الحالية",commandsBody:"اتجاه المنتج هو أمر terminal واحد عبر الأنظمة، وليس تحميل وتثبيت يدوي من موقع.",managerCommandLabel:"Start manager",clientCommandLabel:"Connect Client",slotCommandLabel:"Pin to slot 3",manualCommandLabel:"Advanced manual connection"}),tr:pn({languageName:"Türkçe",languageLabel:"Belge dili",eyebrow:"VuvoDesk Manual",title:"Yerel Screen Wall tek komutla açılsın",intro:"VuvoDesk, tek bir manager PC üzerinden birçok Client, mini PC, Mac mini ve dev machine izlemek için npm-first bir çalışma deckidir.",managerTitle:"1. Manager çalıştır",managerBody:"Ekranları izleyecek bilgisayarda VuvoDesk manager çalıştır. Manager UI ve local server birlikte başlar ve http://127.0.0.1:5179 açılır.",managerPoints:["Komut: npx -y livedesk.","Manager Screen Wall/API için 5179, client bağlantıları için 5197 kullanır.","Eski VuvoDesk process portları tutuyorsa başlangıç varsayılan olarak temizler."],clientTitle:"2. Client bağla",clientBody:"İzlenecek bilgisayarda aynı Google hesabıyla giriş yap. Manager henüz online değilse client kapanmaz ve her 5 saniyede tekrar dener.",clientPoints:["npx -y livedesk client ilk boş slota yerleşir.","npx -y livedesk client 3 makineyi slot 3’e sabitler.","Çok makinede tekrar tekrar login gerekmesin diye client beklemeye devam eder."],syncTitle:"3. Sync Server ve discovery",syncBody:"Sync Server bu managerı hesabın active Screen Wall kaydı olarak Supabase’e yazar. Clients bu kaydı okuyup endpoint adaylarını dener.",syncPoints:["Host instance, LAN/private adresler, public adaylar, pair token ve kısa lease içerir.","Önce LAN adayları, gerekirse public adaylar denenir.","Manager, VPN, firewall veya router değişince Sync Server’a bas.","vuvodesk.com üzerindeki Chrome Local Network Access artık default runtime yolu değil. Gerçek server npm manager app."],platformTitle:"4. Platform durumu",platformBody:"Windows live screen transfer ile doğrulandı. macOS ve Linux aynı npm yolunu takip ediyor.",platformPoints:["Windows: doğrulandı.","macOS: capture/control için Screen Recording/Accessibility izinleri gerekir.","Linux: linux-x64 runtime, grim/gnome-screenshot/import/scrot capture ve X11/XTEST input backend eklendi. Audio kapalı."],firewallTitle:"Firewall ve uzak konumlar",firewallBody:"VuvoDesk ekranı ve kontrolü doğrulanmış Direct TCP ve şifreli UDP/WebRTC P2P ile doğrudan bağlar. Rendezvous hizmeti yalnızca eşleri bulur ve P2P bağlantı bilgilerini değiştirir; ekran veya girdi verisini taşımaz.",firewallPoints:["LAN Direct TCP için varsayılan client portu 5197dir.","Client ve manager, eş keşfi ve P2P signaling için yapılandırılmış rendezvous servera outbound erişebilmelidir.","Ekran ve girdi verileri Direct TCP veya şifreli UDP/WebRTC P2P ile cihazdan cihaza doğrudan gider.","Ağlar arasında Direct TCP için TCP 5197 yönlendirme veya VPN/IP allowlist yapılandırın. P2P engellenirse VuvoDesk doğrudan bağlantıyı yeniden dener.","5179u yalnız uzak browser Wallu doğrudan açacaksa expose et."],commandsTitle:"Güncel komutlar",commandsBody:"Ürün yönü, webden indirip kurmak yerine işletim sistemleri arasında ortak tek terminal komutu.",managerCommandLabel:"Manager başlat",clientCommandLabel:"Client bağla",slotCommandLabel:"Slot 3’e sabitle",manualCommandLabel:"Gelişmiş manuel bağlantı"})},BM=Object.entries(ki).map(([e,t])=>({id:e,label:t.languageName}));function HM(){if(typeof navigator>"u")return"en";const e=navigator.languages?.length?navigator.languages:[navigator.language];for(const t of e){const a=t.toLowerCase();if(ki[t])return t;if(a.startsWith("zh-tw")||a.startsWith("zh-hk"))return"zh-TW";if(a.startsWith("pt"))return"pt-BR";const r=a.split("-")[0];if(ki[r])return r}return"en"}function Gh({index:e}){const t=e+1;return i.jsx("article",{className:"device-tile placeholder-tile","aria-label":`Empty slot ${t}`,children:i.jsxs("div",{className:"tile-screen","aria-hidden":"true",children:[i.jsx("span",{className:"slot-grid","aria-hidden":"true"}),i.jsxs("span",{className:"empty-screen",children:[i.jsx(Aa,{size:24}),i.jsxs("strong",{children:["Slot ",String(t).padStart(3,"0")]})]})]})})}const WM=["cpu","gpu","memory","vram","network","disk","temp"];function $M({device:e,slotNumber:t,selected:a,updateIndicator:r,remoteDiagnostics:c,diagnosticsMode:u="remote",onSelect:p,onOpenControl:h}){const f=wb(e),k=new Map(f.metrics.map(b=>[b.id,b])),M=r?.label||f.label;return i.jsxs("div",{className:`wall-device-list-row state-${f.state} ${a?"selected":""}`,role:"row","aria-selected":a,tabIndex:0,onClick:p,onDoubleClick:b=>{b.preventDefault(),h()},onKeyDown:b=>{(b.key==="Enter"||b.key===" ")&&(b.preventDefault(),p())},children:[i.jsxs("span",{className:"wall-device-name",role:"gridcell",children:[i.jsx("span",{className:"wall-device-icon","aria-hidden":"true",children:i.jsx(Aa,{size:17})}),i.jsxs("span",{children:[i.jsx("strong",{children:Qt(e)}),i.jsxs("small",{children:["Slot ",String(t).padStart(3,"0"),e.platform?` · ${e.platform}`:"",e.arch?` · ${e.arch}`:""]})]}),a&&i.jsx(bl,{size:16,strokeWidth:3,"aria-label":"Selected"})]}),i.jsxs("span",{className:`wall-device-list-status state-${f.state} ${r?`update-${r.state}`:""}`,role:"gridcell",title:r?.error||M,children:[i.jsx("i",{"aria-hidden":"true"}),i.jsx("strong",{children:M})]}),WM.map(b=>{const T=k.get(b);return i.jsxs("span",{className:`wall-device-list-metric state-${T?.state||"unknown"}`,role:"gridcell",title:T?`${T.label}: ${T.value} · ${T.detail}`:"Not reported",children:[i.jsx("strong",{children:T?.value||"-"}),i.jsx("small",{children:T?.detail||"not reported"}),T?.ratio!==void 0&&i.jsx("i",{style:{width:`${Math.round(T.ratio*100)}%`},"aria-hidden":"true"})]},b)}),c&&i.jsx("span",{className:"wall-device-list-diagnostics",role:"gridcell",children:i.jsx(Zg,{items:c,mode:u})})]})}function VM(e){if(!e)return!1;const t=String(e.platform||"").trim().toLowerCase();return Nr(t)&&e.capabilities?.screenRecordingPermission===!1}function Nr(e){const t=String(e||"").trim().toLowerCase();return t==="macos"||t==="darwin"||t==="mac"||t==="macosx"}function zM(e){const t=String(e||"").trim().toLowerCase();return t==="linux"||t.startsWith("linux ")}function Kh(e){const t=String(e||"").trim().toLowerCase();return["win32","windows","win32nt"].includes(t)?"mode5-lzo-delta":Nr(t)?"mode1-jpeg":""}function Cd({device:e,frame:t,selected:a,controlEnabled:r,showStatus:c,showDeviceTitle:u=!0,monitorIndex:p,monitorCount:h,onSelect:f,onFocusDevice:k,onOpenControl:M,onCycleMonitor:b,onCanvasReady:T,sendInput:A,remotePointerFeedback:x,remoteModifierState:E,updateIndicator:B,presentationReady:q,showPresentationSpinner:G=!1,remoteDiagnostics:ne,diagnosticsMode:re="remote"}){const O=s.useRef(null),ie=s.useRef(null),J=s.useRef(null),de=s.useRef(0),se=s.useRef(null),pe=s.useRef(null),ce=s.useRef(new Map),W=s.useRef(null),ee=s.useRef(PC()),L=s.useRef(AC()),_=s.useRef(!1),K=s.useRef([]),ue=s.useRef(Al()),P=s.useRef(null),N=s.useRef(null),te=wb(e),we=["cpu","gpu","memory","vram"].map(g=>te.metrics.find(U=>U.id===g)).filter(g=>!!g),me=em(p),Fe=h>1,H=q??!!t,R=VM(e)&&!H,Se=G&&e.connected&&!H&&!R,Ce=gM(e,t,me),Ve=Ce>=hl?100:Ce/hl*100,Ze=Ce>=hl?hl/Ce*100:100,_e={"--screen-aspect":Ce.toFixed(5),"--screen-content-width":`${Math.max(1,Math.min(100,Ve)).toFixed(3)}%`,"--screen-content-height":`${Math.max(1,Math.min(100,Ze)).toFixed(3)}%`},z=r?{transformOrigin:"0 0",transform:`translate3d(${ue.current.translateX.toFixed(2)}px, ${ue.current.translateY.toFixed(2)}px, 0) scale(${ue.current.scale.toFixed(4)})`}:void 0,Me=!!(r&&H&&x?.nativeInputBackend==="win32-window-message"&&x.deviceId===e.deviceId&&x.monitorIndex===me),Be=Me?{left:`${Math.max(0,Math.min(1,x.normalizedX))*100}%`,top:`${Math.max(0,Math.min(1,x.normalizedY))*100}%`}:void 0,Ge=s.useCallback(g=>{ue.current=g;const U=O.current;U&&(U.style.transformOrigin="0 0",U.style.transform=`translate3d(${g.translateX.toFixed(2)}px, ${g.translateY.toFixed(2)}px, 0) scale(${g.scale.toFixed(4)})`,U.dataset.touchZoom=g.scale.toFixed(2))},[]),xt=s.useCallback(g=>{if(O.current=g,g&&r){const U=ue.current;g.style.transformOrigin="0 0",g.style.transform=`translate3d(${U.translateX.toFixed(2)}px, ${U.translateY.toFixed(2)}px, 0) scale(${U.scale.toFixed(4)})`,g.dataset.touchZoom=U.scale.toFixed(2)}T(e.deviceId,g)},[r,e.deviceId,T]),Pe=(g,U,F)=>TC(g,U,F.getBoundingClientRect()),He=g=>Pe(g.clientX,g.clientY,g.currentTarget),Y=g=>jC(g,E),ve=s.useCallback(()=>{se.current!==null&&(window.cancelAnimationFrame(se.current),se.current=null)},[]),st=s.useCallback(()=>{const g=P.current;g&&(window.clearTimeout(g.timerId),P.current=null);const U=N.current;U&&window.clearTimeout(U.timerId),N.current=null},[]),it=s.useCallback(()=>{const g=J.current;if(!g)return;J.current=null;const U=Number(g.input.normalizedX),F=Number(g.input.normalizedY);if(!Number.isFinite(U)||!Number.isFinite(F))return;A(e.deviceId,{...g.input,normalizedX:U,normalizedY:F})&&(de.current=performance.now())},[e.deviceId,A]),bt=s.useCallback(()=>{se.current===null&&(se.current=window.requestAnimationFrame(()=>{se.current=null,it()}))},[it]);s.useEffect(()=>{L.current.reset(),_.current=!1,K.current=[];const g=Al();return Ge(g),()=>{ve(),st(),J.current=null,pe.current=null,ce.current.clear(),W.current=null,L.current.reset(),_.current=!1,K.current=[]}},[me,Ge,st,ve,r,e.deviceId]);const Rt=(g,U)=>{if(!r)return;const F={...g,type:U};if(U==="pointermove"){const he=performance.now();J.current={input:F},he-de.current>=Nk&&(ve(),it()),bt();return}J.current&&(ve(),it()),A(e.deviceId,F)},ae=(g,U,F=ys(g.button),he="")=>{Rt({monitorIndex:me,...He(g),button:F,...he?{inputSource:he}:{},...Y(g)},U)},$=(g,U)=>{A(e.deviceId,{...g,type:"pointerdown",button:U}),A(e.deviceId,{...g,type:"pointerup",button:U})},ye=(g,U,F)=>({monitorIndex:me,...Pe(g,U,F),shiftKey:!!E?.shiftKey,ctrlKey:!!E?.ctrlKey,altKey:!!E?.altKey,metaKey:!!E?.metaKey}),V=(g,U)=>{const F=P.current;F&&(window.clearTimeout(F.timerId),P.current=null,$(F.input,"left"));const he={tap:g,input:U,timerId:0};he.timerId=window.setTimeout(()=>{P.current===he&&(P.current=null,$(U,"left"))},Od),P.current=he},Ke=(g,U,F)=>{if(ce.current.set(g,{clientX:U,clientY:F}),W.current)return;const he=pe.current;if(he&&he.pointerId!==g){const Ye=ce.current.get(he.pointerId),dt=ce.current.get(g),Re=ie.current?.getBoundingClientRect();Ye&&dt&&Re&&(ve(),J.current=null,st(),pe.current=null,W.current={gesture:EC(Ye,dt,ue.current,Re),pointerIds:[he.pointerId,g]});return}const Q=performance.now(),Te=P.current,ge={clientX:U,clientY:F,at:Q};if(Te&&$f(Te.tap,ge)){window.clearTimeout(Te.timerId),P.current=null;const Ye={...Te,timerId:0};Ye.timerId=window.setTimeout(()=>{N.current===Ye&&(N.current=null,$(Ye.input,"left"))},Math.max(0,Te.tap.at+Od-Q)),N.current=Ye}else N.current=null,Te&&(window.clearTimeout(Te.timerId),P.current=null,$(Te.input,"left"));pe.current=FC(g,U,F),k()},Ct=(g,U,F,he)=>{ce.current.set(g,{clientX:U,clientY:F});const Q=W.current;if(Q){const Ye=ce.current.get(Q.pointerIds[0]),dt=ce.current.get(Q.pointerIds[1]);Ye&&dt&&Ge(NC(Q.gesture,Ye,dt));return}const Te=pe.current;if(!Te||Te.pointerId!==g)return;const ge=Ug(Te,g,U,F);if(pe.current=ge,ge?.dragged&&N.current){const Ye=N.current;window.clearTimeout(Ye.timerId),N.current=null,$(Ye.input,"left")}ge?.dragged&&Rt(ye(U,F,he),"pointermove")},I=(g,U,F,he)=>{if(ce.current.set(g,{clientX:U,clientY:F}),W.current){ce.current.delete(g),ce.current.size===0&&(W.current=null);return}const Q=DC(pe.current,g,U,F,performance.now());if(ce.current.delete(g),Q.kind==="ignore")return;Q.kind==="drag"&&(Rt(ye(U,F,he),"pointermove"),ve(),it()),pe.current=null;const Te=N.current;if(Te&&window.clearTimeout(Te.timerId),N.current=null,Q.kind==="tap"&&Q.tap){const ge=ye(U,F,he);Te&&$f(Te.tap,Q.tap)?$(ge,"right"):(Te&&$(Te.input,"left"),V(Q.tap,ge))}else Te&&$(Te.input,"left")},oe=g=>{if(ce.current.delete(g),W.current){ce.current.size===0&&(W.current=null);return}if(pe.current?.pointerId===g){ve(),J.current=null,pe.current=null;const U=N.current;U&&(window.clearTimeout(U.timerId),$(U.input,"left")),N.current=null}},Ee=g=>{if(g.pointerType!=="touch")return!1;if(g.preventDefault(),g.stopPropagation(),ee.current.shouldHandlePointerEvent()){Ke(g.pointerId,g.clientX,g.clientY);try{g.currentTarget.setPointerCapture(g.pointerId)}catch{}}return!0},We=g=>g.pointerType!=="touch"?!1:(g.preventDefault(),ee.current.shouldHandlePointerEvent()&&Ct(g.pointerId,g.clientX,g.clientY,g.currentTarget),!0),vt=g=>g.pointerType!=="touch"?!1:(g.preventDefault(),g.stopPropagation(),ee.current.shouldHandlePointerEvent()&&I(g.pointerId,g.clientX,g.clientY,g.currentTarget),g.currentTarget.hasPointerCapture(g.pointerId)&&g.currentTarget.releasePointerCapture(g.pointerId),!0),et=g=>g.pointerType!=="touch"?!1:(g.preventDefault(),g.stopPropagation(),ee.current.shouldHandlePointerEvent()&&oe(g.pointerId),g.currentTarget.hasPointerCapture(g.pointerId)&&g.currentTarget.releasePointerCapture(g.pointerId),!0),Tt=g=>{if(r){g.preventDefault(),g.stopPropagation(),ee.current.shouldHandlePointerEvent()&&(ee.current.claimNativeTouchEvents(),pe.current=null,ce.current.clear(),W.current=null);for(const U of Array.from(g.changedTouches))Ke(U.identifier,U.clientX,U.clientY)}},jt=g=>{if(!r)return;g.preventDefault(),g.stopPropagation();for(const he of Array.from(g.touches))ce.current.set(he.identifier,{clientX:he.clientX,clientY:he.clientY});const U=pe.current?.pointerId,F=Array.from(g.touches).find(he=>he.identifier===U)||g.touches.item(0);F&&Ct(F.identifier,F.clientX,F.clientY,g.currentTarget)},Jt=g=>{if(r){g.preventDefault(),g.stopPropagation();for(const U of Array.from(g.changedTouches))I(U.identifier,U.clientX,U.clientY,g.currentTarget)}},At=g=>{if(r){g.preventDefault(),g.stopPropagation();for(const U of Array.from(g.changedTouches))oe(U.identifier)}},zt=s.useCallback(g=>{const U=document.activeElement;U instanceof HTMLElement&&g.contains(U)&&U.classList.contains("monitor-cycle-button")&&U.blur()},[]);return i.jsx("article",{className:`device-tile ${a?"selected":""} ${e.connected?"online":"offline"}`,"data-live-device-id":e.deviceId,style:_e,children:i.jsxs("div",{className:`tile-screen ${H?"has-frame":"is-empty"}`,role:"button",tabIndex:r?-1:0,"aria-pressed":a,onClick:g=>{g.target instanceof Element&&g.target.closest(".monitor-cycle")||r||f()},onKeyDown:g=>{g.target instanceof Element&&g.target.closest(".monitor-cycle")||r||(g.key==="Enter"||g.key===" ")&&(g.preventDefault(),f())},onDoubleClick:g=>{if(!(g.target instanceof Element&&g.target.closest(".monitor-cycle"))){if(g.preventDefault(),r){g.stopPropagation();return}M()}},onPointerLeave:g=>zt(g.currentTarget),children:[i.jsxs("span",{ref:ie,className:`screen-content ${H?"has-frame":"is-empty"}`,children:[i.jsx("canvas",{ref:xt,className:`remote-canvas ${H?"has-frame":"is-empty"} ${r?"control-input-enabled":""}`,"data-monitor-index":me,"data-touch-zoom":ue.current.scale.toFixed(2),style:z,tabIndex:r?0:-1,onPointerDown:g=>{if(r&&!Ee(g)){_.current=!1,L.current.observePointerEvent("down",g),g.preventDefault(),g.stopPropagation(),k(),g.currentTarget.focus(),ae(g,"pointerdown");try{g.currentTarget.setPointerCapture(g.pointerId)}catch{}}},onPointerMove:g=>{r&&g.preventDefault(),!We(g)&&(r&&(_.current=!1,L.current.observePointerEvent("move",g)),ae(g,"pointermove"))},onPointerLeave:g=>{r&&g.pointerType!=="touch"&&(_.current=!1,L.current.observePointerEvent("leave",g),ae(g,"pointermove"),ve(),it())},onPointerUp:g=>{r&&(vt(g)||(_.current=!1,L.current.observePointerEvent("up",g),g.preventDefault(),g.stopPropagation(),ae(g,"pointerup"),g.currentTarget.hasPointerCapture(g.pointerId)&&g.currentTarget.releasePointerCapture(g.pointerId)))},onPointerCancel:g=>{et(g)||(r&&(g.preventDefault(),g.stopPropagation(),ae(g,"pointerup")),g.currentTarget.hasPointerCapture(g.pointerId)&&g.currentTarget.releasePointerCapture(g.pointerId))},onMouseDown:g=>{if(!r||!L.current.shouldHandleMouseEvent("down",g))return;g.preventDefault(),g.stopPropagation(),_.current=!0,k(),g.currentTarget.focus();const U=ys(g.button);K.current.includes(U)||K.current.push(U),ae(g,"pointerdown",U,"legacy-mouse")},onMouseMove:g=>{!r||!L.current.shouldHandleMouseEvent("move",g)||(g.preventDefault(),_.current=!0,ae(g,"pointermove",ys(g.button),"legacy-mouse"))},onMouseLeave:g=>{if(!r||!L.current.shouldHandleMouseEvent("leave",g))return;_.current=!0,ae(g,"pointermove",ys(g.button),"legacy-mouse"),ve(),it();const U=K.current.splice(0).reverse();for(const F of U)ae(g,"pointerup",F,"legacy-mouse")},onMouseUp:g=>{if(!r||!L.current.shouldHandleMouseEvent("up",g))return;g.preventDefault(),g.stopPropagation(),_.current=!0;const U=ys(g.button);ae(g,"pointerup",U,"legacy-mouse"),K.current=K.current.filter(F=>F!==U)},onTouchStart:Tt,onTouchMove:jt,onTouchEnd:Jt,onTouchCancel:At,onWheel:g=>{r&&(g.preventDefault(),A(e.deviceId,{type:"wheel",monitorIndex:me,...He(g),deltaX:g.deltaX,deltaY:g.deltaY,..._.current?{inputSource:"legacy-mouse"}:{},...Y(g)}))},onContextMenu:g=>r&&g.preventDefault(),onDoubleClick:g=>{r&&(g.preventDefault(),g.stopPropagation())}},`${e.deviceId}:monitor:${me}`),Me&&i.jsx("span",{className:"remote-pointer-feedback","data-input-seq":x.inputSeq,"data-native-input-backend":x.nativeInputBackend,style:Be,"aria-hidden":"true",children:i.jsx(Ms,{size:22,strokeWidth:2.2})})]}),!H&&i.jsx("span",{className:"empty-screen",children:i.jsx(Aa,{size:26})}),u&&i.jsx("span",{className:"wall-device-title",title:Qt(e),children:Qt(e)}),Se&&i.jsxs("span",{className:"wall-presentation-loading",role:"status","aria-live":"polite",children:[i.jsx("span",{className:"wall-presentation-spinner","aria-hidden":"true"}),i.jsx("strong",{children:"Preparing video"})]}),R&&i.jsxs("span",{className:"wall-presentation-loading permission-required",role:"status","aria-live":"polite",children:[i.jsx(wo,{size:24,"aria-hidden":"true"}),i.jsx("strong",{children:"Screen Recording permission required"}),i.jsx("small",{children:"Allow the terminal app on this Mac, then restart VuvoDesk."})]}),B&&i.jsxs("span",{className:`wall-update-status state-${B.state}`,role:"status","aria-live":"polite",title:B.error||B.label,children:[B.state==="updated"?i.jsx(Cn,{size:20,"aria-hidden":"true"}):B.state==="failed"?i.jsx(xa,{size:22,"aria-hidden":"true"}):B.state==="offline"?i.jsx(tg,{size:22,"aria-hidden":"true"}):i.jsx("span",{className:"wall-update-spinner","aria-hidden":"true"}),i.jsx("strong",{children:B.label}),B.error?i.jsx("small",{children:B.error}):null]}),c&&i.jsxs(i.Fragment,{children:[i.jsx("span",{className:`tile-health-pill state-${te.state}`,children:te.label}),i.jsx("span",{className:"tile-metrics","aria-label":`${Qt(e)} status`,children:we.map(g=>i.jsxs("span",{className:`tile-metric state-${g.state}`,children:[i.jsx("b",{children:g.label}),i.jsx("em",{children:g.value}),g.ratio!==void 0&&i.jsx("i",{style:{width:`${Math.round(g.ratio*100)}%`}})]},g.id))})]}),ne&&i.jsx(Zg,{items:ne,mode:re}),Fe&&i.jsxs("span",{className:"monitor-cycle","aria-label":`${Qt(e)} display ${me+1} of ${h}`,onPointerDown:g=>g.stopPropagation(),onClick:g=>g.stopPropagation(),onDoubleClick:g=>g.stopPropagation(),children:[i.jsx("button",{className:"monitor-cycle-button previous",onClick:g=>{g.preventDefault(),g.stopPropagation(),b(-1),g.currentTarget.blur()},title:"Previous display",type:"button",children:i.jsx(ng,{size:18})}),i.jsxs("span",{className:"monitor-cycle-count",children:["Screen ",me+1,"/",h]}),i.jsx("button",{className:"monitor-cycle-button next",onClick:g=>{g.preventDefault(),g.stopPropagation(),b(1),g.currentTarget.blur()},title:"Next display",type:"button",children:i.jsx(rg,{size:18})})]})]})})}function UM({visible:e}){const t=Rk;return s.useEffect(()=>{},[t]),null}function gx({runtimeBaseUrl:e=""}){const t=typeof window<"u"&&!!window.liveDesk,a=t,{session:r,sessionHydrationRevision:c,loading:u,hubSessionRevoking:p,hubSessionBlocked:h,hubSessionRevocationError:f,revokeHubSession:k}=XS(),{workspaces:M,activeWorkspace:b,loading:T,error:A,inviteNotice:x,refresh:E,selectWorkspace:B,isWorkspaceActionCurrent:q}=U0(r,c),G=b?.id||"",ne=b?.membershipRevision||0,re=b?.kind==="team"&&b.role==="operator",O=b?`${r?.user.id||""}:${b.id}:${b.role}`:"",ie=s.useRef(O);ie.current=O,ry(r&&b&&!h&&!p?{accessToken:r.access_token,refreshToken:r.refresh_token,expiresAt:r.expires_at,user:{id:r.user.id,email:r.user.email},workspaceId:b.id,workspaceKind:b.kind,workspaceRole:b.role,membershipRevision:b.membershipRevision}:null);const{target:J,error:de,refresh:se}=ZS(r,G,ne),pe=s.useMemo(()=>{if(!J?.active)return null;const n=J.expires_at?Date.parse(J.expires_at):Number.POSITIVE_INFINITY;return Number.isFinite(n)&&n<=Date.now()?null:J},[J]),ce=s.useMemo(()=>Zp(pe),[pe]),W=wi(),ee=e.trim().replace(/\/+$/,""),L=s.useMemo(()=>[...new Set((W?ce:[ee,...ce,Tn]).filter(Boolean))],[W,ce,ee]),[_,K]=s.useState(null),[ue]=s.useState(lk),[P,N]=s.useState(!1),[te,we]=s.useState(()=>typeof window>"u"?!1:!!window.navigator.standalone||window.matchMedia("(display-mode: standalone), (display-mode: fullscreen)").matches),[me,Fe]=s.useState(()=>typeof window<"u"&&Qf(window.matchMedia(Gf).matches,te,window.matchMedia("(pointer: coarse)").matches)),H=W&&me;s.useEffect(()=>{if(!W){K(null);return}const n=window.matchMedia("(display-mode: standalone), (display-mode: fullscreen)"),o=()=>we(n.matches||!!window.navigator.standalone),l=d=>{d.preventDefault(),K(d)},m=()=>{K(null),we(!0)};return o(),n.addEventListener("change",o),window.addEventListener("beforeinstallprompt",l),window.addEventListener("appinstalled",m),()=>{n.removeEventListener("change",o),window.removeEventListener("beforeinstallprompt",l),window.removeEventListener("appinstalled",m)}},[W]);const R=s.useCallback(async()=>{const n=_;if(!n){ue.isIos&&N(!0);return}K(null);try{await n.prompt(),(await n.userChoice).outcome==="accepted"&&we(!0)}catch(o){K(n),console.warn("[VuvoDesk] PWA install prompt failed.",o)}},[ue.isIos,_]);s.useEffect(()=>{const n=window.matchMedia(Gf),o=window.matchMedia("(pointer: coarse)"),l=()=>Fe(Qf(n.matches,te,o.matches));return l(),n.addEventListener("change",l),o.addEventListener("change",l),()=>{n.removeEventListener("change",l),o.removeEventListener("change",l)}},[te]),s.useLayoutEffect(()=>{const n=document.documentElement,o=()=>{n.classList.remove("livedesk-mobile-console-active"),n.style.removeProperty("--livedesk-mobile-viewport-height"),n.style.removeProperty("--livedesk-mobile-viewport-top"),n.style.removeProperty("--livedesk-mobile-viewport-width"),n.style.removeProperty("--livedesk-mobile-viewport-left"),n.style.removeProperty("--livedesk-mobile-ios-top-guard")};if(!me){o();return}n.classList.add("livedesk-mobile-console-active");const l=window.visualViewport,m=document.createElement("div");m.setAttribute("aria-hidden","true"),m.style.cssText="position:fixed;visibility:hidden;pointer-events:none;padding-top:env(safe-area-inset-top);",document.body.appendChild(m);let d=0;const C=()=>{d=0;const S=Math.max(window.innerHeight,document.documentElement.clientHeight),y=i0(l,S,window.innerWidth,te||ue.isIos,te||ue.isIos||ue.isAndroid),w=Number.parseFloat(window.getComputedStyle(m).paddingTop),Z=o0({isIos:ue.isIos,standalone:te,safeAreaTop:w,screenHeight:window.screen.height,layoutViewportHeight:S});n.style.setProperty("--livedesk-mobile-viewport-height",`${y.height}px`),n.style.setProperty("--livedesk-mobile-viewport-top",`${y.offsetTop}px`),n.style.setProperty("--livedesk-mobile-viewport-width",`${y.width}px`),n.style.setProperty("--livedesk-mobile-viewport-left",`${y.offsetLeft}px`),n.style.setProperty("--livedesk-mobile-ios-top-guard",`${Z}px`)},v=()=>{d||(d=window.requestAnimationFrame(C))};return C(),l?.addEventListener("resize",v),l?.addEventListener("scroll",v),window.addEventListener("resize",v),window.addEventListener("orientationchange",v),window.addEventListener("pageshow",v),()=>{d&&window.cancelAnimationFrame(d),l?.removeEventListener("resize",v),l?.removeEventListener("scroll",v),window.removeEventListener("resize",v),window.removeEventListener("orientationchange",v),window.removeEventListener("pageshow",v),m.remove(),o()}},[ue.isAndroid,ue.isIos,me,te]);const[Se,Ce]=s.useState(mM),Ve=s.useMemo(()=>L.some(n=>!!gl(n)),[L]),Ze=!!(r&&b&&!h&&!p&&!f),_e=vC({workspaceReady:Ze,desktopShell:t,publicConsole:W,authenticated:!!r,managerNeedsLocalAccess:Ve,localHubAccessEnabled:Se}),{status:z,devices:Me,error:Be,connectionState:Ge,failure:xt,refresh:Pe,retry:He,hubBaseUrl:Y}=JS(L,_e,r?.access_token||"",O,G,b?.kind||""),ve=s.useRef(null),st=s.useRef(0),[it,bt]=s.useState(0),Rt=s.useCallback(n=>{const o=l=>{ve.current===n&&n.record({type:"hub.request.failed",component:"pwa-diagnostic-control",state:"failed",reason:l instanceof Error?l.message:String(l),details:{transport:"authenticated-hub-http"}})};n.flushWithOneFollowUp(o)},[]),ae=s.useCallback(n=>{const o=ve.current;if(!o)return!1;let l=!1;for(const m of n)l=o.record(m).accepted||l;return l&&Rt(o),l},[Rt]),$=s.useCallback(n=>ae([n]),[ae]);s.useEffect(()=>{const n=String(r?.user?.id||"").trim(),o=String(Y||"").trim();if(t||!Ze||!n||!o){ve.current=null;return}const l=st.current+1;st.current=l;let m=!1,d=null;return mr(async()=>{const{createPwaRuntimeDiagnosticLane:C}=await import("./pwa-runtime-diagnostic-lane-CXJ3zl5c.js");return{createPwaRuntimeDiagnosticLane:C}},[]).then(({createPwaRuntimeDiagnosticLane:C})=>{m||l!==st.current||(d=C({owner:{clientId:n,sessionId:"unknown"},sendBatch:(v,{signal:S})=>Ue("/api/remote/pwa-diagnostics",{method:"POST",signal:S,timeoutMs:15e3,body:JSON.stringify(v)},o)}),ve.current=d,d.record({type:"client.started",component:"pwa-runtime",state:"active",reason:"diagnostic-owner-created",details:{ownerGeneration:l,workspaceId:G||"unknown",workspaceRole:b?.role||"unknown",managerHubUrl:o,startup:ay()}}),d.record({type:"visibility.changed",component:"document",state:document.visibilityState==="visible"?"visible":"hidden",reason:"initial-current-visibility",details:{source:"current-document-state"}}),Rt(d),bt(v=>v+1))}).catch(()=>{m||console.warn("[VuvoDesk] PWA lifecycle diagnostics are unavailable.")}),()=>{m=!0,ve.current===d&&(ve.current=null),d?.dispose()}},[b?.role,G,t,Rt,Y,r?.user?.id,O,Ze]),s.useEffect(()=>{if(!ve.current)return;const n=_u();ae([{type:"session.changed",component:"authenticated-workspace",state:Ze?"ready":"unknown",reason:`workspace:${G||"unknown"}:revision:${ne}:role:${b?.role||"unknown"}`,details:{clientId:r?.user?.id||"unknown",workspaceId:G||"unknown",workspaceRevision:ne,workspaceRole:b?.role||"unknown"}},{type:"session.changed",component:"hub-manager",state:String(Ge||(z?.started?"ready":"unknown")),reason:Be?`error:${Be}:manager:${z?.deviceId||"unknown"}`:`manager:${z?.deviceId||"unknown"}:version:${z?.managerVersion||"unknown"}:role:${z?.runtimeRole||"unknown"}`,details:{managerHubUrl:Y||"unknown",managerDeviceId:z?.deviceId||"unknown",managerPackage:z?.managerPackage||"unknown",managerVersion:z?.managerVersion||"unknown",runtimeRole:z?.runtimeRole||"unknown",hubError:Be||"unknown",directStage:n.stage||"unknown",directReady:n.directReady===!0}}])},[b?.role,G,ne,Ge,Be,Y,it,ae,r?.user?.id,z?.deviceId,z?.managerPackage,z?.managerVersion,z?.runtimeRole,z?.started,Ze]);const ye=s.useCallback(()=>E(),[E]),V=q0(r,b,Y,ye,q),[Ke,Ct]=s.useState(!1);s.useEffect(()=>{if(!z?.started){Ct(!1);return}const n=new AbortController;return Ue("/api/remote/wall-preferences",{signal:n.signal},Y).then(o=>{Ct(o.wallPreferences?.showThisComputer===!0)}).catch(o=>{n.signal.aborted||(Ct(!1),console.warn("[VuvoDesk] Computer visibility setting could not be loaded.",o))}),()=>n.abort()},[Y,z?.started]);const{entitlement:I,licensed:oe,loading:Ee,error:We,refresh:vt}=eC(r,G,ne,b?.plan,b?.entitlementStatus,ye),[et,Tt]=s.useState([]),[jt,Jt]=s.useState(""),[At,zt]=s.useState(""),[g,U]=s.useState(""),[F,he]=s.useState(""),[Q,Te]=s.useState(""),[ge,Ye]=s.useState("idle"),dt=s.useRef("idle"),Re=s.useCallback(n=>{const o=typeof n=="function"?n(dt.current):n;dt.current=o,Ye(o)},[]),[Qe,je]=s.useState(!1),[Bt,ft]=s.useState(""),[ct,ht]=s.useState(null),Xe=s.useRef(null),[yt,Ut]=s.useState(""),Ri=s.useRef("");Ri.current=F;const[Mn,jn]=s.useState(!1);s.useLayoutEffect(()=>{Ct(!1),Tt([]),Jt(""),zt(""),U(""),he(""),Re("idle"),je(!1),ht(null),jn(!1)},[O]);const[Ai,Os]=s.useState([]),Ll=s.useRef(null),Ii=s.useRef(null),rm=s.useRef(null),_s=s.useRef(!1),am=s.useRef({key:"",source:"",at:0}),[om,im]=s.useState(!1),[Zt,Dr]=s.useState(!1),Na=s.useRef(""),mt=s.useRef(new Map),Ro=s.useRef(0),js=s.useRef(!1),Bs=s.useRef(""),sm=s.useRef(O),Ol=s.useRef(O);Ol.current=O;const Hs=s.useRef(null);Hs.current||(Hs.current=h0());const _l=s.useRef(document.visibilityState==="visible"),[ra,cm]=s.useState({}),at=s.useRef({}),Ti=s.useRef(new Set),aa=s.useRef(new Map),Fa=s.useRef(new Map),[Ao,lm]=s.useState({}),Pi=s.useMemo(()=>new Set(Object.keys(ra)),[ra]),Ws=s.useCallback((n,o)=>{if(!n)return;const l={...at.current};o?l[n]=o:delete l[n],at.current=l,cm(l)},[]),Io=s.useCallback((n,o)=>{n&&lm(l=>{if(!!l[n]===o)return l;const m={...l};return o?m[n]=!0:delete m[n],m})},[]),um=s.useCallback((n,o)=>{n&&Fa.current.set(n,{paused:o,expiresAt:Date.now()+Gk})},[]),[nt,xn]=s.useState(""),[an,To]=s.useState(""),[Po,jl]=s.useState(!1),dm=s.useRef(null),mm=s.useRef(null);s.useEffect(()=>{nt==="auth"&&r?.access_token&&xn("")},[nt,r?.access_token]);const[Bl,pm]=s.useState(""),[Da,$s]=s.useState(null),tr=s.useRef(null),Sb=s.useRef(0),Vs=s.useRef(0),zs=s.useCallback((n,o,l)=>{const m=String(n||"").trim();if(pm(m),tr.current!==null&&(window.clearTimeout(tr.current),tr.current=null),!m)return Vs.current=0,$s(null),0;const d=++Sb.current;if(Vs.current=d,$s({id:d,message:m,tone:o}),!l)return d;const C=window.setTimeout(()=>{$s(v=>v?.id===d?null:v),tr.current===C&&(tr.current=null)},5e3);return tr.current=C,d},[]),j=s.useCallback((n,o="info")=>zs(n,o,!0),[zs]);s.useEffect(()=>{A&&j(A,"error")},[j,A]),s.useEffect(()=>{x&&j(x,/joined/i.test(x)?"success":"error")},[x,j]),s.useEffect(()=>{V.error&&j(V.error,"error")},[j,V.error]),s.useEffect(()=>{f&&j("Hub sign-out could not be confirmed. Wall and Control remain blocked; open Account and retry when the Hub is reachable.","error")},[f,j]);const fm=s.useCallback((n,o)=>{const l=String(o||"").trim();!l||n<=0||Vs.current!==n||(Vs.current=0,tr.current!==null&&(window.clearTimeout(tr.current),tr.current=null),pm(m=>m===l?"":m),$s(m=>m?.id===n&&m.message===l?null:m))},[]),Bn=s.useCallback(n=>{zs(n,"progress",!1)},[zs]);s.useEffect(()=>()=>{tr.current!==null&&window.clearTimeout(tr.current)},[]);const[Pt,La]=s.useState(()=>typeof window>"u"?"wall":window.location.pathname.startsWith("/support")?"support":new URLSearchParams(window.location.search).get("view")==="pricing"?"pricing":"wall");s.useEffect(()=>{const n=()=>{La(window.location.pathname.startsWith("/support")?"support":o=>o==="support"?"wall":o)};return window.addEventListener("popstate",n),()=>window.removeEventListener("popstate",n)},[]);const[Eo,hm]=s.useState(AM),[Oa,gm]=s.useState(kM),_a=s.useRef(Eo),oa=s.useRef(Oa);_a.current=Eo,oa.current=Oa;const Hn=Rs(Oa),[Pn,No]=s.useState(Hn),Hl=s.useRef(null);Hl.current||(Hl.current=p0(O));const En=Hl.current;En.switchOwner(O);const Lr=s.useRef(null),Wn=s.useRef(null);s.useLayoutEffect(()=>{Wn.current!==null&&(window.clearTimeout(Wn.current),Wn.current=null),Lr.current=null,oa.current="fast",_a.current=ta,gm("fast"),No(Rs("fast")),hm(ta)},[O]);const ia=s.useCallback(n=>{const o=Xg(n,{cadence:oa.current,viewScale:_a.current});return oa.current!==o.cadence&&(oa.current=o.cadence,gm(o.cadence),No(Rs(o.cadence)),MM(o.cadence)),_a.current!==o.viewScale&&(_a.current=o.viewScale,hm(o.viewScale),IM(o.viewScale)),o},[]);s.useEffect(()=>{const n=z?.wallPreferences;if(!n)return;const o=Math.max(0,Number(n.revision)||0);if(!En.acceptSnapshot(O,o))return;const l=Lr.current;l&&(l.cadence!==n.cadence||l.viewScale!==xi(n.viewScale))||(l&&(Lr.current=null),ia(n))},[ia,z?.wallPreferences,En,O]);const Us=s.useCallback(async(n,o)=>{const l=()=>En.ownsWrite(o)&&ie.current===O;if(!l())return;let m=!1;const d=S=>m||!l0({error:S,publicConsole:wi(),workspaceKind:b?.kind,workspaceRole:b?.role,workspaceId:G,userId:r?.user.id})?!1:(m=!0,!0);let C=En.readRevision(O);if(C===void 0)try{for(;;)try{const S=await Ue(sd(m),void 0,Y);if(!l()||(C=Math.max(0,Number(S.revision)||0),!En.commitWriteRevision(o,C)))return;break}catch(S){if(!l())return;if(d(S))continue;throw S}}catch{if(!l())return;Lr.current=null,Pe(),j("Wall view changed here, but Hub synchronization failed.","error");return}let v=!1;for(let S=0;S<3;S+=1)try{const y=await Ue(sd(m),{method:"PATCH",body:JSON.stringify(u0({legacy:m,revision:C,preferences:n}))},Y);if(!l()||!En.commitWriteRevision(o,y.revision))return;const w=d0(y,m);if(!c0(w,n)){Lr.current=null,Pe(),j("Update the Hub to synchronize Wall controls.","error");return}Lr.current=null,ia(w),Pe();return}catch(y){if(!l())return;if(d(y))continue;if(/^409\s/.test(y instanceof Error?y.message:String(y))&&!v)try{const Z=await Ue(sd(m),void 0,Y);if(!l()||(C=Math.max(0,Number(Z.revision)||0),!En.commitWriteRevision(o,C)))return;v=!0;continue}catch{}Lr.current=null,Pe(),j("Wall view changed here, but Hub synchronization failed.","error");return}},[b?.kind,b?.role,G,ia,Y,Pe,r?.user.id,j,En,O]),qs=s.useCallback((n,o)=>{Wn.current!==null&&(window.clearTimeout(Wn.current),Wn.current=null);const l=ia({cadence:n,viewScale:o}),m=En.beginWrite(O);m&&(Lr.current=l,Us(l,m))},[ia,Us,En,O]),Cb=s.useCallback(n=>{const o=ia({cadence:oa.current,viewScale:xi(n)}),l=En.beginWrite(O);return l&&(Lr.current=o,Wn.current!==null&&window.clearTimeout(Wn.current),Wn.current=window.setTimeout(()=>{Wn.current=null,Us({cadence:oa.current,viewScale:_a.current},l)},250)),o},[ia,Us,En,O]);s.useEffect(()=>()=>{Wn.current!==null&&window.clearTimeout(Wn.current)},[]);const Ht=D0(Eo),bm=s0(Eo),vm=s.useCallback(n=>{qs(oa.current,n==="list"?Tl:n==="medium"?E0:ta)},[qs]),ym=s.useCallback(n=>{qs(n,_a.current)},[qs]),[kb,wm]=s.useState(!1);s.useEffect(()=>{if(wm(!1),Ht!=="list")return;const n=window.setTimeout(()=>{wm(!0)},Wd);return()=>window.clearTimeout(n)},[Ht]);const Ei=m0({wallSize:Ht,elapsedMs:kb?Wd:0});s.useLayoutEffect(()=>{!re||Pt==="wall"||Pt==="control"||Pt==="doc"||Pt==="support"||(La("wall"),jn(!1))},[Pt,re]);const Wl=L0(Eo),Sm=s.useMemo(()=>({"--wall-tile-min-width":`${Wl}px`}),[Wl]),Mb=Ht==="list"?"List view":`${Ht==="medium"?"Small":"Large"} tiles, ${Wl} pixel minimum width`,[Ni,xb]=s.useState(xM),[fn,Gs]=s.useState(!1),[qt,Ks]=s.useState(!1),[pr,Ys]=s.useState(!1),[Fi,Rb]=s.useState(null),[$n,Fo]=s.useState(null),[Do,Lo]=s.useState(!1),[Ab,Qs]=s.useState(Date.now),Or=s.useRef(null),Cm=s.useRef(null),$l=s.useRef(null),sa=s.useRef(0);s.useEffect(()=>()=>{sa.current+=1,Or.current!==null&&window.clearTimeout(Or.current)},[]);const[ja,Ib]=s.useState(HM),[Ba,km]=s.useState(!1),[ca,_r]=s.useState(!1),Xs=s.useRef(ca);s.useLayoutEffect(()=>{Xs.current=ca},[ca]);const[qM,GM]=s.useState(!1),[Oo,Mm]=s.useState(dM),[De]=s.useState(yM),xm=me?Ni:De.showScreenStatus,[on]=s.useState(SM),[Vl]=s.useState(bM),[gt,zl]=s.useState(Vl.selections),Rm=s.useRef({...Vl.topologyFingerprints}),Di=s.useRef({}),Am=s.useRef({...Vl.selections}),[tt,fr]=s.useState(null),[Js,Ul]=s.useState({}),ql=s.useRef(new Set),[Gl,Zs]=s.useState([]),[Li,Tb]=s.useState(""),[Pb,Eb]=s.useState(0),[Nb,Im]=s.useState(0),[Fb,Db]=s.useState(0),[Kl,Oi]=s.useState(()=>new Set),lt=s.useRef(new Map),hn=s.useRef(new Map),jr=s.useRef(new Map),_i=s.useRef(new Set),Et=s.useRef(new Map),Ha=s.useRef(null),Wa=s.useRef(new Map),Br=s.useRef(new Set),la=s.useRef(new Map),_o=s.useRef(new Map),$a=s.useRef(new Map),Vn=s.useRef(new Map),ec=s.useRef(new WeakMap),tc=s.useRef(new WeakMap),ua=s.useRef(""),Rn=s.useRef(null),Tm=s.useRef(Promise.resolve()),nc=s.useRef(0),jo=s.useRef(null),Nn=s.useRef(null),ji=s.useRef(""),en=s.useRef(new Map),Bo=s.useRef(null),Bi=s.useRef(0),da=s.useRef(new Map),rc=s.useRef(typeof window<"u"&&new URLSearchParams(window.location.search).get("livedeskTransmissionProbe")==="1"),ac=s.useRef(new Map),Yl=s.useRef([]),Pm=s.useRef(0),[oc,Ql]=s.useState({}),Va=s.useRef(new Map),[ic,sc]=s.useState({}),cc=s.useRef(null),[Xl,gn]=s.useState(!1),lc=s.useRef(null),Lb=s.useRef(0),Hr=s.useRef(null),Em=s.useRef(new Map),nr=s.useRef(null),zn=s.useRef(null),wt=s.useRef(null),Hi=s.useRef(!1),Nm=s.useRef(0),Wt=s.useRef(0),sn=s.useRef(""),Fm=s.useRef(Promise.resolve()),Ho=s.useRef(""),ke=s.useRef(null),Un=s.useRef(""),za=s.useRef(null),Wo=s.useRef(0),Wi=s.useRef(""),Wr=s.useRef(new Map),hr=s.useRef(new Map),uc=s.useRef(performance.now()),ma=s.useRef(new Map),Fn=s.useRef(new Map),pa=s.useRef(new Map),$r=s.useRef(new Map),Vr=s.useRef(new Map),gr=s.useRef(new Map),qn=s.useRef(document.visibilityState==="visible"),rr=s.useRef(1),Jl=s.useRef([]),[Gt,Ob]=s.useState(document.visibilityState==="visible"),[_b,jb]=s.useState(0),$i=s.useRef(0),dc=s.useRef(0),mc=s.useRef(0),pc=s.useRef(0),Zl=s.useRef(0),eu=s.useRef(new Map),Vi=s.useRef([]),Dm=s.useRef(new Map),Lm=s.useRef(new Map),Nt=s.useRef(new Map),zr=s.useRef(new Map),$o=s.useRef(new Map),tu=s.useRef({}),fc=s.useRef(new Set),kt=s.useCallback((n,o,l,m,d)=>{const C=ut(n,o),v=performance.now(),S=Wr.current.get(C)||0,y=hr.current.get(C)||0,w=n==="control"?ke.current:null,Z=w?.deviceId===o?er({...w,streamPurpose:"control"}):Vn.current.get(o)||"",be=n==="control"?Et.current.get(o)||null:lt.current.get(o)||null,D=be?ps(be,{includeLifecycleEvents:!1}).canvases[0]:void 0,fe=D?{state:String(D.decoderState||"unknown"),requestedAcceleration:String(D.requestedAcceleration||"unknown"),configuredAcceleration:String(D.configuredAcceleration||"unknown"),inputCount:Math.max(0,Number(D.inputCount||0)),outputCount:Math.max(0,Number(D.outputCount||0)),lastInputAgeMs:Number.isFinite(Number(D.lastInputAgeMs))?Math.max(0,Number(D.lastInputAgeMs)):"unknown",lastOutputAgeMs:Number.isFinite(Number(D.lastOutputAgeMs))?Math.max(0,Number(D.lastOutputAgeMs)):"unknown",lastPaintAgeMs:Number.isFinite(Number(D.lastPaintAgeMs))?Math.max(0,Number(D.lastPaintAgeMs)):"unknown",decodeQueueSize:Math.max(0,Number(D.decodeQueueSize||0)),renderQueueSize:Math.max(0,Number(D.renderQueueSize||0)),softwareFallbackReason:String(D.softwareFallbackReason||"none"),softwareFallbackCount:Math.max(0,Number(D.softwareFallbackCount||0)),forcedSoftware:n==="wall"&&_i.current.has(o)}:void 0,xe={scope:n,deviceId:o,stage:l,reason:m,at:Date.now(),attempts:Math.max(0,Math.floor(Number(d)||0)),receiveAgeMs:S>0?Math.max(0,v-S):-1,paintAgeMs:y>0?Math.max(0,v-y):-1,bindingKey:Z,decoder:fe};$o.current.set(C,xe),console.info("[VuvoDesk frame recovery]",xe);const Oe=ve.current;if(!Oe)return;const ze={type:"frame.recovery.changed",component:`frame-recovery:${n}:${o}`,state:l,reason:m,details:{scope:n,deviceId:o,attempts:xe.attempts,receiveAgeMs:xe.receiveAgeMs>=0?xe.receiveAgeMs:"unknown",paintAgeMs:xe.paintAgeMs>=0?xe.paintAgeMs:"unknown",bindingKey:Z||"unknown",decoder:fe||"unknown"}};if(l==="stable"){queueMicrotask(()=>{ve.current===Oe&&Oe.record(ze).accepted&&Rt(Oe)});return}$(ze)},[Rt,$]),Vo=s.useCallback(n=>nS(ec.current,n),[]),zo=s.useCallback(n=>Kd(tc.current,n),[]),Ua=s.useCallback((n,o)=>Sf(tc.current,n,o),[]),Vt=s.useCallback(n=>{const o=wf(ec.current,n);return wf(tc.current,n),o},[]),Uo=s.useCallback((n,o)=>Sf(ec.current,n,o),[]),Om=s.useCallback(n=>Nn.current===n||Ha.current===n?!0:[lt.current,hn.current,jr.current,Et.current,en.current].some(l=>Array.from(l.values()).some(m=>m===n)),[]),bn=s.useCallback(n=>{n&&(Vt(n),fc.current.add(n),oS(n,{isCurrent:Om,dispose:fi,schedule:o=>queueMicrotask(()=>{try{o()}finally{fc.current.delete(n)}})}))},[Om,Vt]),vn=s.useCallback(n=>(Vt(n),Fl(n,fi)),[Vt]),_m=s.useCallback(()=>{const n=Nn.current,o=Ha.current,l=[...fc.current];Nn.current=null,Ha.current=null,fc.current.clear(),ec.current=new WeakMap,tc.current=new WeakMap,Vn.current.clear(),_i.current.clear(),ji.current="",aS([lt.current,hn.current,jr.current,Et.current,en.current],[n,o,...l],fi),Bo.current=null,Bi.current=0,Wa.current.clear(),Br.current.clear(),la.current.clear(),_o.current.clear(),$a.current.clear(),da.current.clear(),ac.current.clear(),Yl.current.length=0,Va.current.clear(),Wr.current.clear(),hr.current.clear(),ma.current.clear(),Fn.current.clear(),pa.current.clear(),$r.current.clear(),Vr.current.clear(),gr.current.clear(),Nt.current.clear(),zr.current.clear(),$o.current.clear(),Ti.current.clear()},[]);s.useEffect(()=>()=>{_m()},[_m]);const Ur=s.useCallback((n,o,l={})=>{const m=ut(n,o);Wr.current.delete(m),hr.current.delete(m),ma.current.delete(m),Fn.current.delete(m),gr.current.delete(m),Nt.current.delete(m),zr.current.delete(m),l.preserveLatestDiagnostic!==!0&&$o.current.delete(m),Va.current.delete(m),da.current.delete(m),pa.current.delete(m),$r.current.delete(m),Vr.current.delete(m),sc(d=>{if(!Object.prototype.hasOwnProperty.call(d,m))return d;const C={...d};return delete C[m],C}),Ql(d=>{if(!Object.prototype.hasOwnProperty.call(d,m))return d;const C={...d};return delete C[m],C})},[]),Dt=s.useCallback((n,o,l={})=>{const m=ut(n,o),d=performance.now();Ur(n,o,l),n==="control"?$r.current.set(m,d):Vr.current.set(m,d)},[Ur]),[qa,fa]=s.useState(null),[Bb,nu]=s.useState(!1),[KM,Hb]=s.useState([]),[qo,Wb]=s.useState("all"),[Go,ru]=s.useState([]),[YM,QM]=s.useState(!1),[XM,$b]=s.useState(!0),jm=s.useRef(null),Bm=s.useRef(null),Vb=s.useRef(null),zb=s.useRef(null),Ub=s.useRef(!1),au=s.useRef(!1),zi=s.useRef(0),br=s.useRef(0),vr=s.useRef(0),ar=s.useRef(0),Ui=s.useRef(0),qi=s.useRef(""),ou=s.useRef({}),Gi=Pt==="settings"&&!re,Hm=!re&&Pt==="pricing",Wm=Pt==="doc",$m=Pt==="support",Ga=!re&&Pt==="share-files",hc=!re&&Pt==="agents",qr=!Gi&&!Hm&&!Wm&&!$m&&!Ga&&!hc,Ae=Pt==="control",Vm=y0(Pt),or=Gt&&Pt==="wall"&&!Ei,zm=s.useRef(or);zm.current=or;const qb=!H&&Vm&&Vi.current.length>0,yr=Gt&&(Pt==="wall"&&!Ei||!H&&Ae||qb),Ko=s.useRef(yr);Ko.current=yr;const gc=Gt&&(Ae||or),Yo=Gt&&(gc||Vm&&(ge==="connecting"||ge==="active")),iu=s.useRef({active:yr,epoch:rr.current});iu.current.active!==yr&&(rr.current+=1,iu.current={active:yr,epoch:rr.current}),s.useEffect(()=>{qr||(Gs(!1),Ks(!1),Ys(!1))},[qr]);const rt=De.frameMode==="mode4-h264-atlas",Gn=Q||on.frameMode,Gb=Gn!=="mode3-h264-hw"?Math.min(30,on.fps):on.fps,Ki=n0(Gb,H),Qo=Me.find(n=>n.deviceId===At),Kb=Qo?.platform,Yb=Qo?_n(Qo,gt[Qo.deviceId]):0,bc=Qo?nm(Qo,Yb):null,Um=zM(Kb)?{maxWidth:1280,maxHeight:720}:Ah,qm=Gn!=="mode3-h264-hw"?{maxWidth:1920,maxHeight:1080}:Ah,vc={maxWidth:Math.min(qm.maxWidth,Um.maxWidth,on.maxWidth),maxHeight:Math.min(qm.maxHeight,Um.maxHeight,on.maxHeight)},wr={maxWidth:bc?.width?Math.min(vc.maxWidth,bc.width):vc.maxWidth,maxHeight:bc?.height?Math.min(vc.maxHeight,bc.height):vc.maxHeight};s.useEffect(()=>{if(b?.kind!=="team"&&z?.started){if(!r?.access_token){Ue("/api/remote/license",{method:"DELETE"},Y).catch(()=>{});return}Ue("/api/remote/license/sync",{method:"POST",headers:{Authorization:`Bearer ${r.access_token}`},body:JSON.stringify({workspaceId:G})},Y).catch(n=>{console.warn("[VuvoDesk] Hub license sync failed",n)})}},[b?.entitlementStatus,b?.kind,G,ne,Y,r?.access_token,z?.started]),s.useEffect(()=>{!r?.access_token||b?.kind!=="personal"||b.role!=="owner"||!z?.started||z.runtimeRole!=="hub"||!z.deviceId||(async()=>{try{const{data:n,error:o}=await Mt.rpc("register_livedesk_device",{p_device_id:z.deviceId,p_device_name:z.deviceName||z.deviceId,p_role:"hub",p_assigned_hub_id:null,p_platform:navigator.platform||navigator.userAgent,p_os_version:navigator.userAgent,p_app_version:z.managerVersion||z.managerPackage||""}),l=Array.isArray(n)?n[0]:n;(o||l?.ok===!1)&&console.warn("[VuvoDesk] Hub device role registration failed",o||l?.reason||"unknown-error")}catch(n){console.warn("[VuvoDesk] Hub device role registration failed",n)}})()},[b?.kind,b?.role,r?.access_token,z?.deviceId,z?.deviceName,z?.managerPackage,z?.managerVersion,z?.runtimeRole,z?.started]);const Gr=z?.runtimeRole==="hub"?String(z.deviceId||"").trim():"",Le=s.useMemo(()=>Me.filter(n=>n.connected&&(me||Ke||!Gr||n.deviceId!==Gr)),[Me,Gr,me,Ke]),Ka=s.useMemo(()=>Le.filter(n=>!Gr||n.deviceId!==Gr),[Le,Gr]);s.useEffect(()=>{const n={...at.current},o=Date.now();let l=!1;lm(m=>{const d={...m};let C=!1;for(const v of Me){const S=String(v.liveCapturePause?.token||"").trim(),y=Fa.current.get(v.deviceId);if(y)if((y.paused?!!S:!S)||y.expiresAt<=o)Fa.current.delete(v.deviceId);else continue;const w=!!S&&(v.liveCapturePause?.captureStopConfirmed!==!0||v.liveCapturePause?.phase==="stop-unconfirmed");!!d[v.deviceId]!==w&&(C=!0,w?d[v.deviceId]=!0:delete d[v.deviceId])}return C?d:m});for(const m of Me){const d=String(m.liveCapturePause?.token||"").trim(),C=String(n[m.deviceId]||""),v=Fa.current.get(m.deviceId);if(v)if((v.paused?!!d:!d)||v.expiresAt<=o)Fa.current.delete(m.deviceId);else continue;d&&d!==C?(n[m.deviceId]=d,l=!0):!d&&C&&(delete n[m.deviceId],aa.current.delete(m.deviceId),l=!0)}l&&(at.current=n,cm(n))},[Me]);const Gm=qo==="all"?Le.length:Go.filter(n=>Le.some(o=>o.deviceId===n)).length,Qb=s.useMemo(()=>Le.reduce((n,o)=>Math.max(n,Vh(o.slotNumber)),0),[Le]),yc=Math.max(bk,Le.length,Qb),ha=s.useMemo(()=>{const n=Array(yc).fill(null),o=[];for(const l of Le){const m=Vh(l.slotNumber);m>0&&m<=yc&&!n[m-1]?n[m-1]=l:o.push(l)}for(const l of o){const m=n.findIndex(d=>!d);m<0?n.push(l):n[m]=l}return n},[Le,yc]),Km=s.useMemo(()=>me?ha.filter(n=>!!n):ha,[me,ha]),Ym=s.useMemo(()=>ha.flatMap((n,o)=>n?[{device:n,slotNumber:o+1}]:[]),[ha]),wc=s.useMemo(()=>Le.map(n=>n.deviceId),[Le]),Ya=s.useMemo(()=>new Set(et),[et]),cn=s.useMemo(()=>Le.filter(n=>Ya.has(n.deviceId)),[Le,Ya]),ga=s.useMemo(()=>Me.find(n=>n.deviceId===jt)||cn[0]||null,[Me,jt,cn]),tn=s.useMemo(()=>Me.find(n=>n.deviceId===At)||null,[At,Me]),ir=tn?_n(tn,gt[tn.deviceId]):0,X=Ae?tn:ga,Qm=s.useMemo(()=>new Set(Go),[Go]),Xb=s.useMemo(()=>qo==="all"?Le.map(n=>n.deviceId):Le.filter(n=>Qm.has(n.deviceId)).map(n=>n.deviceId),[Le,Qm,qo]),Jb=X?yi(X,"control"):!1,su=Nr(X?.platform)&&(X?.capabilities?.controlPermission===!1||X?.capabilities?.accessibilityPermission===!1),sr=X?yi(X,"audio")||yi(X,"remoteAudio"):!1,Xo=(Array.isArray(X?.capabilities?.agentTools)?X.capabilities.agentTools.map(String):[]).includes("system.power"),cu=b?.entitlementStatus==="active"&&b.plan!=="free"?b.plan:oe?I?.plan:null,Je=cu==="team"?"team":cu==="pro"?"pro":cu==="ltd"?"ltd":"free",Xm=$e[Je],Sc=b?.deviceLimit??Xm.limit,Sr=s.useMemo(()=>{const n=new Set(k0(Ka,Sc));return Gr&&n.add(Gr),n},[Sc,Gr,Ka]),pt=!X||Sr.has(X.deviceId),Jo=Je==="ltd"?`Plus includes up to ${ds} Clients. Upgrade to Pro for schools, academies, commercial use, and larger walls.`:Je==="pro"?`Pro includes up to ${ju} Clients for schools, academies, and commercial use.`:Je==="team"?"Team includes every connected Client in this shared commercial workspace.":`Free includes up to ${Bu} Clients. Upgrade to Plus for ${ds} devices and no ads.`,Zb=Je==="free",Cr=pt&&!!X&&Jb,Jm=pt&&!!X&&sr,Yi=s.useMemo(()=>Ae?X?[X]:[]:cn.length>0?cn:X?[X]:[],[X,cn,Ae]),Dn=s.useMemo(()=>Yi.filter(n=>Sr.has(n.deviceId)),[Sr,Yi]),Cc=Dn.some(n=>String(ra[n.deviceId]||"").startsWith("pending:")||Ao[n.deviceId]===!0),Qi=!(Dn.length>0&&Dn.every(n=>{const o=String(ra[n.deviceId]||"");return!!o&&!o.startsWith("pending:")&&Ao[n.deviceId]!==!0}))||Cc,kc=s.useMemo(()=>ha.filter(n=>!!n?.connected).slice(0,TM(Ht)).map(n=>n.deviceId),[ha,Ht]),Mc=s.useMemo(()=>yr?or?rt||Ht==="list"?wc:De.visibleOnlyLive?Gl.length>0?Gl:kc:wc:Vi.current.length>0?Vi.current:wc:[],[kc,rt,Gl,De.visibleOnlyLive,wc,yr,or,Ht]),Kn=s.useMemo(()=>{const n=vd(Mc.filter(o=>Sr.has(o)));return t0(n,H,ga?.deviceId||"")},[H,Sr,Mc,ga?.deviceId]);Vi.current=Kn;const kr=s.useMemo(()=>Kn.filter(n=>n!==Li&&!Pi.has(n)),[Pi,Kn,Li]),xc=s.useMemo(()=>new Map(Le.map(n=>[n.deviceId,n.platform])),[Le]),yn=s.useMemo(()=>{const n=Object.fromEntries(Le.map(o=>[o.deviceId,String(o.sessionId||"").trim()]));return v0(tu.current,n)},[Le]);s.useLayoutEffect(()=>{tu.current=yn},[yn]);const ev=Jf(ou.current,yn)?Hn:Pn;s.useLayoutEffect(()=>{const n=ou.current,o=Jf(n,yn);ou.current={...yn};const l=new Set([...Object.keys(n),...Object.keys(yn)]),m=ve.current?[]:null;for(const d of l){const C=String(n[d]||"").trim(),v=String(yn[d]||"").trim();C!==v&&(console.info("[VuvoDesk frame session]",{deviceId:d,previousSessionId:C,currentSessionId:v,action:v?"fresh-recovery-owner":"owner-released"}),m?.push({type:"session.changed",component:`remote-device:${d}`,state:v?"connected":"disconnected",reason:`session:${v||C||"unknown"}`,details:{deviceId:d,previousSessionId:C||"unknown",currentSessionId:v||"unknown",action:v?"fresh-recovery-owner":"owner-released"}}),_i.current.delete(d),v?(Dt("wall",d),Dt("control",d)):(Ur("wall",d),Ur("control",d)))}m&&m.length>0&&ae(m),o&&(No(Hn),zi.current=Date.now(),br.current=0,vr.current=0,ar.current=0,Ui.current=0,qi.current="")},[Ur,yn,ae,Dt,Hn]),s.useEffect(()=>{if(!ve.current)return;const n=Object.entries(yn).filter(([,o])=>!!o).map(([o,l])=>({type:"session.changed",component:`remote-device:${o}`,state:"connected",reason:`session:${l}`,details:{deviceId:o,currentSessionId:l,action:"current-connected-owner"}}));n.length>0&&ae(n)},[yn,it,ae]);const Mr=M0(rt,Kn.length),nn=s.useMemo(()=>rt?kr.filter(n=>gs({mode4Enabled:rt,directMode4WallEnabled:Mr,isMac:Nr(xc.get(n))})==="atlas"):[],[Mr,rt,xc,kr]),Kt=s.useMemo(()=>kr.filter(n=>gs({mode4Enabled:rt,directMode4WallEnabled:Mr,isMac:Nr(xc.get(n))})==="direct"),[Mr,rt,xc,kr]),Zm=s.useMemo(()=>{const n=De.autoStartLive?kr.map(o=>ut("wall",o)):[];return Yo&&pt&&g&&Sr.has(g)&&(ge==="connecting"||ge==="active"||ge==="warm")&&n.push(ut("control",g)),[...new Set(n)].sort()},[Yo,g,ge,pt,Sr,De.autoStartLive,kr]);s.useEffect(()=>{const n=new Set(Kn);Oi(o=>{let l=!1;const m=new Set;for(const d of o)n.has(d)?m.add(d):l=!0;return l?m:o})},[Kn]);const tv=s.useMemo(()=>{const n=d=>Le.find(C=>C.deviceId===d)||null,o=d=>{const C=n(d);return C?_n(C,gt[d]):0},l=(d,C=o(d))=>d===g&&(ge==="connecting"||ge==="active"||ge==="warm")?Et.current.get(d)||hn.current.get(d)||null:rt?en.current.get(d)||lt.current.get(d)||null:lt.current.get(d)||null,m=(d,C=o(d))=>{const v=n(d);return`${v?Qt(v):d} · Monitor ${C+1}`};return{resolveCurrentTarget(){if(Ae&&tn){const y=ir;return{type:"control",deviceIds:[tn.deviceId],monitorIndex:y,label:`${Qt(tn)} · Monitor ${y+1}`,sourceCanvas:l(tn.deviceId,y),signature:`control:${tn.deviceId}:${y}:${on.frameMode}`}}const d=cn.map(y=>y.deviceId).filter(y=>kr.includes(y)),C=ga&&kr.includes(ga.deviceId)?ga.deviceId:"",v=d.length>0?d:C?[C]:kr,S=d.length===0&&!C;if(v.length===0)return null;if(v.length===1){const y=v[0],w=o(y);return{type:S?"wall":d.length>1?"selection":"device",deviceIds:v,monitorIndex:w,label:S?"Wall":m(y,w),sourceCanvas:S?null:l(y,w),signature:`${S?"wall":"device"}:${y}:${w}:${rt?"atlas":"direct"}`}}return{type:d.length>1?"selection":"wall",deviceIds:v,label:d.length>1?`${v.length} selected Clients`:"Wall",sourceCanvas:null,signature:`${d.length>1?"selection":"wall"}:${v.join(",")}:${Ht}`}},getDeviceCanvas:l,composeWall(d,C={}){return K0(d.map(v=>{const S=o(v);return{deviceId:v,label:m(v,S),canvas:l(v,S)}}),C)}}},[Le,tn,g,ge,on.frameMode,lt,rt,gt,ir,cn,Ae,kr,ga,Ht]),ep=ck({hubUrl:Y,remoteSettingsEnabled:!!(z?.started&&Y),sourceRegistry:tv,onToast:j}),Kr=s.useMemo(()=>w0({captureOwnershipActive:Yo,localFeatureAccess:pt,controlSessionDeviceId:g,planAllowed:Sr.has(g),sessionState:ge,controlFocusVisible:Ae,presentationCanvasMounted:Bt===g,wallPresentationVisible:or,wallPresentationCanvasMounted:lt.current.has(g)||en.current.has(g),decoderOwnerExists:Et.current.has(g)})?[g]:[],[Yo,g,ge,pt,Bt,Sr,Ae,or]),lu=s.useMemo(()=>vd([...Kn,...Kr]),[Kr,Kn]),Rc=s.useMemo(()=>Bh(De,Ht),[De,Ht]),Zo=s.useMemo(()=>Bh(De,"large"),[De]),Ac=x0({mode4Enabled:rt,directMode4WallEnabled:Mr,adaptiveFps:ev,directDeviceCount:Kt.length,adaptive:De.adaptiveLoadShedding}),ln=r0({fps:Ac,maxWidth:Zo.maxWidth,maxHeight:Zo.maxHeight,quality:De.quality},H,Kt.length),uu=T0({deviceCount:nn.length,targetFps:Pn,adaptive:De.adaptiveLoadShedding});rt&&nn.length>0;const Yr=s.useCallback((n,o,l,m=1)=>{if(n.width<=0||n.height<=0)return!1;if(n===o)return!0;const d=l?Math.min(1,l.maxWidth/n.width,l.maxHeight/n.height):1,C=Math.max(1,Math.round(n.width*d)),v=Math.max(1,Math.round(n.height*d)),S=o.width!==C||o.height!==v;S&&(o.width=C,o.height=v);const y=o.getContext("2d",{alpha:!1});if(!y)return!1;y.imageSmoothingEnabled=!0,y.imageSmoothingQuality="low";const w=y.globalAlpha;y.globalAlpha=S?1:Math.max(.05,Math.min(1,m));try{y.drawImage(n,0,0,n.width,n.height,0,0,o.width,o.height)}finally{y.globalAlpha=w}return!0},[]),Ic=s.useCallback((n,o)=>{const l=Math.max(0,Number(o.clientWidth||0)),m=Math.max(0,Number(o.clientHeight||0)),d=Math.max(1,Number(window.devicePixelRatio||1)),C=l>0&&m>0?{maxWidth:Math.ceil(l*d),maxHeight:Math.ceil(m*d)}:void 0;return Yr(n,o,C)},[Yr]),Tc=s.useCallback((n,o,l)=>{const m=Math.max(0,Math.floor(Number(n?.frameSeq||0))),d=o||(n?lt.current.get(n.deviceId):null),C=l||d,v=Math.max(0,Number(C?.width||0))*Math.max(0,Number(C?.height||0)),S=Math.max(lt.current.size,en.current.size);return a&&m>0&&(m+Hk(n?.deviceId||""))%pb===0&&S<=Bk&&ow(d)&&v>0&&v<=jk?_k:1},[a]),ei=s.useCallback((n,o,l)=>{if(!rc.current)return;const m=`${n}:${o.deviceId}`,d=ac.current.get(m)||{bindingKey:"",totalPaints:0,lastPaintAt:0,lastFrameSeq:0};d.bindingKey=er(o),d.totalPaints+=1,d.lastPaintAt=performance.now(),d.lastFrameSeq=Number(o.frameSeq||0),ac.current.set(m,d);const C=++Pm.current,v={sequence:C,scope:n,deviceId:o.deviceId,bindingKey:d.bindingKey,frameSeq:d.lastFrameSeq,paintedAt:d.lastPaintAt,sourceGapMs:Number(o.sourceGapMs||0),agentSendGapMs:Number(o.agentSendGapMs||0),agentSendDurationMs:Number(o.agentSendDurationMs||0),agentSendDurationFrameSeq:Number(o.agentSendDurationFrameSeq||0),agentFrameAgeMs:Number(o.agentFrameAgeMs||0),timestampUs:Number(o.timestampUs||0),queuedForMs:Number(l?.queuedForMs||0),decodedForMs:Number(l?.decodedForMs||0),scheduledForMs:Number(l?.scheduledForMs||0),interactiveBurstOutputWindowMs:Number(l?.interactiveBurstOutputWindowMs||0),interactiveBurstTailHoldCount:Number(l?.interactiveBurstTailHoldCount||0)};Yl.current[(C-1)%Qk]=v},[]),xr=s.useCallback(n=>{n&&Oi(o=>{if(o.has(n))return o;const l=new Set(o);return l.add(n),l})},[]),Rr=s.useCallback(n=>{n&&Oi(o=>{if(!o.has(n))return o;const l=new Set(o);return l.delete(n),l})},[]),Qa=s.useCallback((n,o)=>{if(!o||o.width<=0||o.height<=0)return!1;const l=document.createElement("canvas");if(l.width=o.width,l.height=o.height,!Yr(o,l))return bn(l),!1;const m=jr.current.get(n);return jr.current.set(n,l),m&&m!==l&&vn(m),xr(n),!0},[xr,Yr,vn,bn]),Yt=s.useCallback(n=>{rS(jr.current,n,fi)},[]),Pc=s.useCallback((n,o)=>{const l=jr.current.get(n),m=lt.current.get(n)===o||en.current.get(n)===o;return at.current[n]?(Yt(n),!1):!l||!m||l.width<=0||l.height<=0?!1:Yr(l,o)?!0:(Yt(n),!1)},[Yr,Yt]),Qr=s.useCallback((n,o=!1,l)=>{if(at.current[n]||!Br.current.has(n))return!1;const m=Math.max(1,Math.min(Hn,St.controlWallReuseMaxFps,Ki)),d=performance.now(),C=_o.current.get(n)||0,v=Et.current.get(n)||hn.current.get(n),S=lt.current.get(n)||en.current.get(n);if(!v||!S||!S.isConnected)return!1;const y=C0({cadenceCredit:la.current.get(n)||0,targetFps:m,sourceFps:Ki,elapsedSincePaintMs:C>0?d-C:0,nowMs:d,scheduledPaintAtMs:$a.current.get(n)||0,force:o});if(!y.shouldPaint)return la.current.set(n,y.nextCadenceCredit),!1;const w=Math.max(0,Number(S.clientWidth||0)),Z=Math.max(0,Number(S.clientHeight||0)),be=Math.max(1,Number(window.devicePixelRatio||1)),D=w>0&&Z>0?{maxWidth:Math.min(Rc.maxWidth,Math.ceil(w*be)),maxHeight:Math.min(Rc.maxHeight,Math.ceil(Z*be))}:Rc;return Yr(v,S,D,l?Tc(l,v,S):1)?(la.current.set(n,y.nextCadenceCredit),y.nextScheduledPaintAtMs>0&&$a.current.set(n,y.nextScheduledPaintAtMs),_o.current.set(n,performance.now()),y.sourceCadencePassthrough&&(la.current.delete(n),$a.current.delete(n)),l&&ei("wall-reuse-visible",l),xr(n),Yt(n),!0):!1},[Ki,Rc,xr,Yr,ei,Yt,Tc,Hn]);s.useEffect(()=>{ua.current=Li},[Li]);const Ec=s.useCallback((n,o)=>{const l=Hr.current;if(!l||l.deviceId!==n)return;const m=Date.now();Em.current.set(n,{...l,source:o,completedAtEpochMs:m,durationMs:Math.max(0,performance.now()-l.startedAt)}),Hr.current=null},[]),tp=s.useCallback((n,o)=>{const l=lt.current.get(n);if(o&&l&&l!==o&&Qa(n,l),o){if(lt.current.set(n,o),l&&l!==o&&bn(l),at.current[n]){Yt(n),vn(o),Rr(n);return}jr.current.get(n)&&Pc(n,o)&&xr(n),Qr(n,!0);return}if(l&&Ko.current&&Vi.current.includes(n)){Qa(n,l),lt.current.delete(n),bn(l);return}lt.current.delete(n),Yt(n),bn(l),Rr(n)},[Rr,xr,Qr,Pc,Qa,vn,Yt,bn]),nv=s.useCallback((n,o)=>{const l=hn.current.get(n);if(o){hn.current.set(n,o),ft(n),l&&l!==o&&bn(l);const m=g===n&&Qe?Et.current.get(n):null;m&&Ic(m,o)&&n===At&&(Ec(n,"warm-reuse"),gn(!0)),m&&m!==o&&S0({decodeWidth:m.width,decodeHeight:m.height,presentationCssWidth:o.getBoundingClientRect().width,presentationCssHeight:o.getBoundingClientRect().height,devicePixelRatio:window.devicePixelRatio,sourceWidth:wr.maxWidth,sourceHeight:wr.maxHeight})&&(Et.current.set(n,o),bn(m));return}hn.current.delete(n),ft(m=>m===n?"":m),bn(l)},[Ec,At,g,Qe,wr.maxHeight,wr.maxWidth,Ic,bn]),Nc=s.useCallback((n,o,l)=>{const m=performance.now(),d=ut(n,l.deviceId);let C=l;if(n==="control"&&l.visualChanged){const Z=String(o.inputFeedbackEventId||""),be=Number(o.inputFeedbackInputSeq||0),D=Number(o.inputFeedbackIssuedAtEpochMs||0),fe=Number(o.browserReceivedEpochMs||0),xe=Dm.current.get(l.deviceId)||"",Oe=D>0?Math.max(0,Date.now()-D):Number.POSITIVE_INFINITY;if(Z.length>0&&be>0&&Z!==xe&&Oe<=hd){const qe=Lm.current.get(l.deviceId)||[];qe.push(Oe),qe.length>yh&&qe.splice(0,qe.length-yh),Lm.current.set(l.deviceId,qe),C={...l,inputFeedbackSeq:be,inputFeedbackMs:Oe,inputFeedbackAt:m,inputFeedbackExact:!0,inputFeedbackEventId:Z,inputFeedbackInputType:o.inputFeedbackInputType,inputFeedbackInputToFrameMs:fe>0?Math.max(0,fe-D):void 0,inputFeedbackFrameToPaintMs:fe>0?Math.max(0,Date.now()-fe):void 0,inputFeedbackAgentApplyMs:o.inputFeedbackAgentApplyMs,inputFeedbackApplyToCaptureMs:o.inputFeedbackApplyToCaptureMs,inputFeedbackSampleCount:qe.length,inputFeedbackP50Ms:vs(qe,.5),inputFeedbackP95Ms:vs(qe,.95)},Dm.current.set(l.deviceId,Z),eu.current.set(l.deviceId,be)}else if(!Z){const qe=cC(l.deviceId),$t=eu.current.get(l.deviceId)||0,Jr=qe?m-qe.sentAt:Number.POSITIVE_INFINITY;qe&&qe.inputSeq>$t&&Jr<=hd&&(C={...l,inputFeedbackSeq:qe.inputSeq,inputFeedbackMs:Math.max(0,Jr),inputFeedbackAt:m,inputFeedbackExact:!1},eu.current.set(l.deviceId,qe.inputSeq))}}const v=Nt.current.get(d)||0,S=v>0&&hr.current.get(d)||0;if(hr.current.set(d,m),Fn.current.delete(d),n==="control"&&pa.current.delete(d),gr.current.delete(d),v>0){const Z=Wy({restartAttempts:v,healthySinceAt:zr.current.get(d)||0,previousPaintAt:S,paintedAt:m,maximumHealthyGapMs:n==="control"?gd:Dh,stableForMs:n==="control"?Nh:Fh});Z.resetAttempts?(Nt.current.delete(d),zr.current.delete(d),kt(n,o.deviceId,"stable","stable-paint-window",v)):Z.healthySinceAt>0&&zr.current.set(d,Z.healthySinceAt)}const y=da.current.get(d)||{totalFrames:0,totalChangedFrames:0,sampleFrames:0,sampleChangedFrames:0,sampleStartedAt:m,intervalCount:0,intervalSumMs:0,minIntervalMs:Number.POSITIVE_INFINITY,maxIntervalMs:0,intervalSamplesMs:[],seqGapCount:0,maxSeqGap:0,sampleDecoderInputBase:0,sampleDecoderOutputBase:0},w=er(o);y.bindingKey!==w&&(y.bindingKey=w,y.lastAt=void 0,y.lastFrameSeq=void 0,y.sampleChangedFrames=0,y.sampleDecoderInputBase=Number(l.decoderInputCount||0),y.sampleDecoderOutputBase=Number(l.decoderOutputCount||0),fl(y,m)),n==="control"&&C.inputFeedbackMs===void 0&&y.lastInfo?.inputFeedbackMs!==void 0&&y.lastInfo.inputFeedbackAt!==void 0&&m-y.lastInfo.inputFeedbackAt<=hd&&(C={...C,inputFeedbackSeq:y.lastInfo.inputFeedbackSeq,inputFeedbackMs:y.lastInfo.inputFeedbackMs,inputFeedbackAt:y.lastInfo.inputFeedbackAt,inputFeedbackExact:y.lastInfo.inputFeedbackExact,inputFeedbackEventId:y.lastInfo.inputFeedbackEventId,inputFeedbackInputType:y.lastInfo.inputFeedbackInputType,inputFeedbackInputToFrameMs:y.lastInfo.inputFeedbackInputToFrameMs,inputFeedbackFrameToPaintMs:y.lastInfo.inputFeedbackFrameToPaintMs,inputFeedbackAgentApplyMs:y.lastInfo.inputFeedbackAgentApplyMs,inputFeedbackApplyToCaptureMs:y.lastInfo.inputFeedbackApplyToCaptureMs,inputFeedbackSampleCount:y.lastInfo.inputFeedbackSampleCount,inputFeedbackP50Ms:y.lastInfo.inputFeedbackP50Ms,inputFeedbackP95Ms:y.lastInfo.inputFeedbackP95Ms}),y.totalFrames+=1,y.sampleFrames+=1,Ih(y,m,C.frameSeq),C.visualChanged&&(y.totalChangedFrames+=1,y.sampleChangedFrames+=1),y.lastInfo=C,da.current.set(d,y)},[kt]),Fc=s.useCallback((n,o)=>{if(at.current[n.deviceId]||ua.current===n.deviceId||n.currentGenerationVerified!==!0||Vn.current.get(n.deviceId)!==er(n))return;Nc("wall",n,o);const l=Qe&&g===n.deviceId,m=lt.current.get(n.deviceId)||en.current.get(n.deviceId);rc.current&&!Ae&&!l&&m?.isConnected&&ei("wall-visible",n,o),n.kind==="live"&&(xr(n.deviceId),Yt(n.deviceId)),ua.current!==n.deviceId&&!l&&(Br.current.delete(n.deviceId),la.current.delete(n.deviceId),_o.current.delete(n.deviceId),$a.current.delete(n.deviceId))},[g,Qe,xr,Nc,ei,Yt,Ae]),np=s.useCallback((n,o)=>{if(at.current[n.deviceId]||On(wt.current,ke.current)||wa(wt.current,ke.current)||wt.current&&ke.current&&dn(wt.current,ke.current)&&ho(wt.current,ke.current.deviceId,ke.current.sessionId)&&wt.current.monitorIndex===ke.current.monitorIndex||!qu(n,ke.current))return;Nc("control",n,o),Ut(v=>v&&"");const l=Et.current.get(n.deviceId),m=hn.current.get(n.deviceId);let d=!1;l&&l.width>0&&l.height>0&&(m&&Ae&&n.deviceId===At&&(d=Ic(l,m),d&&ei("control-visible",n,o)),Wa.current.set(n.deviceId,So(n)),Br.current.add(n.deviceId),n.deviceId===g&&(je(!0),Re(v=>v==="connecting"?"active":v)),Qr(n.deviceId,!1,n));const C=lc.current;!C||!Kk(C,n)||!d||(Ec(n.deviceId,"fresh-frame"),gn(!0))},[Ec,At,g,Qr,Ic,Nc,ei,Ae]),Xa=s.useCallback((n,o)=>{const l=performance.now(),m=ut(n,o.deviceId);Wr.current.set(m,l),n!=="control"&&Vr.current.delete(m);const d=Va.current.get(m)||{totalFrames:0,sampleFrames:0,sampleStartedAt:l,intervalCount:0,intervalSumMs:0,minIntervalMs:Number.POSITIVE_INFINITY,maxIntervalMs:0,intervalSamplesMs:[],seqGapCount:0,maxSeqGap:0,sampleBytes:0,sampleH264Frames:0,sampleTinyFrames:0,sampleRepeatedFrames:0,sourceSendIntervalsMs:[]},C=er(o);if(d.bindingKey!==C&&(d.bindingKey=C,d.lastAt=void 0,d.lastFrameSeq=void 0,d.lastContentHash=void 0,d.sampleBytes=0,d.sampleH264Frames=0,d.sampleTinyFrames=0,d.sampleRepeatedFrames=0,d.sourceSendIntervalsMs.length=0,fl(d,l)),d.totalFrames+=1,d.sampleFrames+=1,d.sampleBytes+=Math.max(0,Number(o.byteLength||0)),String(o.frameMode||o.mode||o.codec||o.mimeType||"").toLowerCase().includes("h264")){d.sampleH264Frames+=1,Number(o.byteLength||0)<=Vk&&(d.sampleTinyFrames+=1);const w=String(o.contentHash||"");w&&d.lastContentHash===w&&(d.sampleRepeatedFrames+=1),d.lastContentHash=w}const y=Number(o.agentSendGapMs||0);y>0&&y<1e3&&fb(d.sourceSendIntervalsMs,y),d.lastFrame=So(o),Ih(d,l,o.frameSeq),Va.current.set(m,d)},[]);s.useEffect(()=>{const n=new Set(Zm),o=new Set([...Wr.current.keys(),...hr.current.keys(),...ma.current.keys(),...Fn.current.keys(),...gr.current.keys(),...Nt.current.keys(),...zr.current.keys(),...$o.current.keys(),...pa.current.keys(),...$r.current.keys(),...Vr.current.keys(),...da.current.keys(),...Va.current.keys()]);for(const d of o){if(n.has(d))continue;const C=d.indexOf(":"),v=d.slice(0,C),S=d.slice(C+1);(v==="wall"||v==="control")&&S&&Ur(v,S)}const l=d=>{const C=Object.entries(d).filter(([v])=>n.has(v));return C.length===Object.keys(d).length?d:Object.fromEntries(C)};if(Ql(l),sc(l),n.size===0)return;const m=window.setInterval(()=>{const d=performance.now(),C={},v={};for(const S of n){const y=da.current.get(S);if(y){const D=Math.max(1,d-y.sampleStartedAt);C[S]={bindingKey:y.bindingKey||"",totalFrames:y.totalFrames,totalChangedFrames:y.totalChangedFrames,framesPerSecond:y.sampleFrames*1e3/D,changedFramesPerSecond:y.sampleChangedFrames*1e3/D,averageIntervalMs:y.intervalCount>0?y.intervalSumMs/y.intervalCount:0,minIntervalMs:Number.isFinite(y.minIntervalMs)?y.minIntervalMs:0,maxIntervalMs:y.maxIntervalMs,p95IntervalMs:vs(y.intervalSamplesMs,.95),intervalCount:y.intervalCount,seqGapCount:y.seqGapCount,maxSeqGap:y.maxSeqGap,decoderInputFps:Math.max(0,(Number(y.lastInfo?.decoderInputCount||0)-y.sampleDecoderInputBase)*1e3/D),decoderOutputFps:Math.max(0,(Number(y.lastInfo?.decoderOutputCount||0)-y.sampleDecoderOutputBase)*1e3/D),sampleMs:D,lastInfo:y.lastInfo},y.sampleDecoderInputBase=Number(y.lastInfo?.decoderInputCount||0),y.sampleDecoderOutputBase=Number(y.lastInfo?.decoderOutputCount||0),y.sampleChangedFrames=0,fl(y,d)}const w=Va.current.get(S);if(!w)continue;const Z=Math.max(1,d-w.sampleStartedAt),be=w.lastFrame?So(w.lastFrame):void 0;w.lastFrame=be,v[S]={totalFrames:w.totalFrames,framesPerSecond:w.sampleFrames*1e3/Z,averageIntervalMs:w.intervalCount>0?w.intervalSumMs/w.intervalCount:0,minIntervalMs:Number.isFinite(w.minIntervalMs)?w.minIntervalMs:0,maxIntervalMs:w.maxIntervalMs,p95IntervalMs:vs(w.intervalSamplesMs,.95),intervalCount:w.intervalCount,seqGapCount:w.seqGapCount,maxSeqGap:w.maxSeqGap,averageFrameBytes:w.sampleFrames>0?w.sampleBytes/w.sampleFrames:0,tinyFrameRatio:w.sampleH264Frames>0?w.sampleTinyFrames/w.sampleH264Frames:0,repeatedFrameRatio:w.sampleH264Frames>0?w.sampleRepeatedFrames/w.sampleH264Frames:0,sourceSendAverageMs:w.sourceSendIntervalsMs.length>0?w.sourceSendIntervalsMs.reduce((D,fe)=>D+fe,0)/w.sourceSendIntervalsMs.length:0,sourceSendP95Ms:vs(w.sourceSendIntervalsMs,.95),sourceSendSampleCount:w.sourceSendIntervalsMs.length,sampleMs:Z,lastFrame:be},w.sampleBytes=0,w.sampleH264Frames=0,w.sampleTinyFrames=0,w.sampleRepeatedFrames=0,w.sourceSendIntervalsMs.length=0,fl(w,d)}Ql(C),sc(v)},1e3);return cc.current=m,()=>{window.clearInterval(m),cc.current===m&&(cc.current=null)}},[Zm,Ur]);const rp=s.useCallback(n=>{const o=O;if(ie.current!==o)return;const l=n.deviceId,m=er(n);if(at.current[l]||ua.current===l||n.currentGenerationVerified!==!0||Vn.current.get(l)!==m)return;Xa("wall",n);const d=lt.current.get(l);if(!d)return;const C=Vo(d),v=zo(d),S=()=>lt.current.get(l)!==d||!Uo(d,C)||ie.current!==o||!!at.current[l]||ua.current===l||Vn.current.get(l)!==m,y=()=>S()||!Ua(d,v),w=P0(rt,De.h264DecodeAcceleration),Z=_i.current.has(l)?"prefer-software":w.acceleration;ed(d,n,y,Fc,Z,w.latencyMode,S,Tc).catch(()=>{})},[Vo,Ua,Uo,zo,Fc,rt,Xa,Tc,De.h264DecodeAcceleration,O]),ap=s.useCallback(n=>{const o=O;if(ie.current!==o)return;const l=n.deviceId;if(at.current[l]||On(wt.current,ke.current)||wa(wt.current,ke.current)||wt.current&&ke.current&&dn(wt.current,ke.current)&&ho(wt.current,ke.current.deviceId,ke.current.sessionId)&&wt.current.monitorIndex===ke.current.monitorIndex||!qu(n,ke.current))return;let m=Et.current.get(l);if(!m){const fe=hn.current.get(l),xe=Ha.current;m=fe||xe||document.createElement("canvas"),fe&&xe&&xe!==fe&&vn(xe),Ha.current=null,m!==fe&&m.setAttribute("aria-hidden","true"),Et.current.set(l,m)}const d=m,C=n,v=Vo(d),S=zo(d),y=()=>Et.current.get(l)!==d||!Uo(d,v)||ie.current!==o||!!at.current[l]||!qu(C,ke.current),w=()=>y()||!Ua(d,S),Z=Ri.current,be=String(n.frameMode||n.mode||n.codec||n.mimeType||"").toLowerCase().includes("h264");be||Xa("control",n);const D=ed(d,n,w,np,on.h264DecodeAcceleration,"interactive",y);be&&Xa("control",n),D.catch(fe=>{Ri.current!==Z||Et.current.get(l)!==d||!Ua(d,S)||y()||g!==l||Ut(fe instanceof Error?fe.message:String(fe||"Control H.264 decode failed"))})},[Vo,Ua,Uo,zo,g,on.h264DecodeAcceleration,np,Xa,vn,O]),rv=s.useCallback(n=>{const o=Nn.current;Nn.current=n,o&&o!==n&&bn(o),$i.current=0,dc.current=0,mc.current=0,pc.current=0,Zl.current=0,Bi.current=0},[bn]),ti=s.useCallback(()=>{const n=new Set,o=O;if(ie.current!==o)return n;const l=Nn.current,m=Bo.current;if(!l||!m||l.width<=0||l.height<=0||Bi.current!==m.layoutVersion)return n;for(const d of m.tiles){if(at.current[d.deviceId])continue;const C=en.current.get(d.deviceId);if(!C||d.width<=0||d.height<=0)continue;const v=Math.max(1,Math.round(d.width)),S=Math.max(1,Math.round(d.height)),y=zk,w=Uk;(C.width!==y||C.height!==w)&&(C.width=y,C.height=w);const Z=C.getContext("2d",{alpha:!1});if(Z){Z.imageSmoothingEnabled=!0,Z.imageSmoothingQuality="high";try{Z.drawImage(l,Math.round(d.x),Math.round(d.y),v,S,0,0,y,w),n.add(d.deviceId)}catch{}}}return n},[O]),av=s.useCallback((n,o)=>{const l=en.current.get(n);if(o&&l&&l!==o&&Qa(n,l),o){if(en.current.set(n,o),l&&l!==o&&bn(l),at.current[n]){Yt(n),vn(o),Rr(n);return}jr.current.get(n)&&Pc(n,o)&&xr(n),window.requestAnimationFrame(()=>{ti().has(n)&&Yt(n)}),window.requestAnimationFrame(()=>Qr(n,!0));return}en.current.delete(n),Yt(n),bn(l),Rr(n)},[Rr,xr,ti,Qr,Pc,Qa,vn,Yt,bn]),op=s.useCallback((n,o)=>{if(ie.current!==O)return;mc.current=performance.now(),Bi.current=Number(n.layoutVersion||0),ti();const l=Bo.current?.tiles||[],m=l.length>0?Math.round(n.byteLength/l.length):n.byteLength;for(const d of l){if(at.current[d.deviceId])continue;const C={...n,deviceId:d.deviceId,width:d.width,height:d.height,sourceWidth:d.width,sourceHeight:d.height,byteLength:m};Fc(C,{...o,deviceId:d.deviceId,width:d.width,height:d.height,byteLength:m}),ua.current===d.deviceId&&Qr(d.deviceId,!0)}},[Fc,ti,Qr,O]),ov=s.useCallback(n=>{const o=O;if(ie.current!==o)return;const l=performance.now();$i.current<=0&&($i.current=l),dc.current=l;const m=Nn.current;if(!m)return;const d=er(n);ji.current!==d&&(ji.current=d,Vt(m));const C=Vo(m),v=zo(m),S=()=>Nn.current!==m||ji.current!==d||ie.current!==o||!Uo(m,C),y=()=>S()||!Ua(m,v),w=Bo.current?.tiles||[],Z=w.length>0?Math.round(n.byteLength/w.length):n.byteLength;for(const be of w)at.current[be.deviceId]||Xa("wall",{...n,deviceId:be.deviceId,width:be.width,height:be.height,sourceWidth:be.width,sourceHeight:be.height,byteLength:Z});ed(m,n,y,op,void 0,"smooth",S).catch(()=>{})},[Vo,Ua,Uo,zo,op,Xa,Vt,O]),ip=s.useCallback(n=>{const o=H&&n.streamPurpose==="control"&&n.readOnlyControlBorrow===!0&&n.presentationPurpose==="wall";if(n.streamPurpose!=="wall"&&!o||at.current[n.deviceId])return;const l=er(n);Vn.current.get(n.deviceId)!==l&&(Vn.current.set(n.deviceId,l),Vt(lt.current.get(n.deviceId)),ve.current&&$({type:"frame.owner.changed",component:`wall-owner:${n.deviceId}`,state:"bound",reason:`owner:${n.sessionId||"unknown"}:${n.captureGeneration||"unknown"}:${n.monitorIndex}`,details:{deviceId:n.deviceId,sessionId:n.sessionId||"unknown",streamId:n.streamId||"unknown",commandId:n.commandId||"unknown",captureGeneration:n.captureGeneration||"unknown",monitorIndex:n.monitorIndex,streamPurpose:n.streamPurpose||"unknown",presentationPurpose:n.presentationPurpose||"unknown"}}))},[H,$,Vt]),du=s.useMemo(()=>({fps:ln.fps,maxWidth:ln.maxWidth,maxHeight:ln.maxHeight,quality:ln.quality,mode:rt?"mode3-h264-hw":De.frameMode,frameMode:rt?"mode3-h264-hw":De.frameMode,streamPurpose:"wall",allowReadOnlyControlBorrow:H,configurationRefreshMs:kk,connectionSessionIds:yn,monitorSelections:gt,onFrame:rp,onStreamReady:ip}),[yn,rp,ip,H,rt,gt,De.frameMode,ln.fps,ln.maxHeight,ln.maxWidth,ln.quality]),Dc=s.useCallback(n=>{const o=dt.current;if(o!=="connecting"&&o!=="active"&&o!=="warm"&&o!=="stopping")return kt("control",n.deviceId,"stop-deferred",`stream-binding-ignored-during-${o}`,Nt.current.get(ut("control",n.deviceId))||0),null;const l=ke.current;if(at.current[n.deviceId]||!l||l.deviceId!==n.deviceId||n.deviceId!==g||n.streamPurpose!=="control"||n.monitorIndex!==ir)return null;const m=tu.current[n.deviceId]||"";if(!m||m!==n.sessionId)return null;const d=Gu(l.deviceId,l.transitionGeneration,n),C=dn(l,d)&&ho(l,d.deviceId,d.sessionId)&&l.monitorIndex===d.monitorIndex;return!Ku(l,d)&&!wa(l,d)&&!C?(kt("control",n.deviceId,"owner-replaced","stale-stream-binding-ignored",Nt.current.get(ut("control",n.deviceId))||0),null):(Ku(l,d)||(ke.current=d,ve.current&&$({type:"frame.owner.changed",component:`control-owner:${n.deviceId}`,state:"bound",reason:`owner:${n.sessionId||"unknown"}:${n.captureGeneration||"unknown"}:${n.monitorIndex}`,details:{deviceId:n.deviceId,sessionId:n.sessionId||"unknown",streamId:n.streamId||"unknown",commandId:n.commandId||"unknown",captureGeneration:n.captureGeneration||"unknown",monitorIndex:n.monitorIndex,streamPurpose:n.streamPurpose}}),kt("control",n.deviceId,"owner-bound","hub-start-descriptor",Nt.current.get(ut("control",n.deviceId))||0)),d)},[g,kt,$,ir]),sp=s.useCallback(n=>{const o=Dc(n);if(!o)return;const l=wt.current;if(On(l,o)||wa(l,o)||!!l&&dn(l,o)&&ho(l,o.deviceId,o.sessionId)&&l.monitorIndex===o.monitorIndex)return;wt.current&&(wt.current=null,kt("control",n.deviceId,"owner-replaced","stream-ready-superseded-stale-downshift",Nt.current.get(ut("control",n.deviceId))||0));const d=dt.current;if(d!=="connecting"&&d!=="active"&&d!=="warm"){kt("control",n.deviceId,"stop-deferred",`stream-ready-ignored-during-${d}`,Nt.current.get(ut("control",n.deviceId))||0);return}const C=Xe.current;(!C||er(C)!==er(n))&&Vt(Et.current.get(n.deviceId)),Xe.current=n,ht(n),Re($y)},[Dc,kt,Vt]);s.useEffect(()=>{Vt(Et.current.get(g)),Xe.current=null,ht(null)},[g,F,Gn,Vt,ir]);const Lc=F?`${F}-monitor-${ir}`:"",mu=s.useMemo(()=>({fps:Ki,maxWidth:wr.maxWidth,maxHeight:wr.maxHeight,quality:on.quality,mode:Gn,frameMode:Gn,streamPurpose:"control",forceRestart:Lc!=="",forceRestartToken:Lc,restartReason:Lc?"control-session-or-monitor-change":"",connectionSessionIds:yn,monitorSelections:gt,onFrame:ap,onStreamBound:Dc,onStreamReady:sp}),[yn,Lc,on.quality,ap,Ki,Gn,wr.maxHeight,wr.maxWidth,Dc,sp,gt]),{frames:cp,state:Xi,error:Oc,stats:Ja,restartLive:lp,reconnectLive:pu}=Nf(Kt,De.autoStartLive&&Kt.length>0,Y,du,O);s.useEffect(()=>{const n=new Set(Kt),o=ve.current?[]:null;for(const l of Vn.current.keys())n.has(l)||(Vn.current.delete(l),Vt(lt.current.get(l)),o?.push({type:"frame.owner.changed",component:`wall-owner:${l}`,state:"unbound",reason:"device-no-longer-requested",details:{deviceId:l}}));o&&o.length>0&&ae(o)},[Kt,ae,Vt]);const{frame:ni,layout:Za,state:Ji,stats:iv,refreshInputs:up}=pC(nn,rt&&De.autoStartLive&&nn.length>0,Y,{fps:St.atlasOutputFps,inputFps:uu,width:1920,height:1080,tileWidth:Zo.maxWidth,tileHeight:Zo.maxHeight,captureDeviceIds:nn,connectionSessionIds:yn,monitorSelections:gt,onFrame:ov},O);s.useEffect(()=>{Bo.current=Za,Za&&window.requestAnimationFrame(ti)},[Za,ti]),s.useEffect(()=>{if(!rt||Ji!=="open"){$i.current=0,dc.current=0,mc.current=0;return}const n=window.setInterval(()=>{const o=Nn.current,l=performance.now();if(!o||document.visibilityState!=="visible"||l-uc.current<fd)return;const m=dc.current,d=$i.current;if(m<=0||d<=0||l-m>500)return;const C=mc.current||d,v=l-C;if(v>=Dk&&l-Zl.current>=Ok){hi(o)&&(Zl.current=l,pc.current=l);return}v>=Fk&&l-pc.current>=Lk&&Qw(o)&&(pc.current=l)},250);return()=>window.clearInterval(n)},[Ji,rt]);const{frames:Zi,state:_c,error:eo,stats:sv,restartLive:jc,reconnectLive:es}=Nf(Kr,Kr.length>0,Y,mu,O);s.useEffect(()=>{if(!ve.current)return;const n=_u(),o={stage:n.stage||"unknown",generation:Number(n.generation||0),directReady:n.directReady===!0,logicalChannels:Number(n.logicalChannels||0),openLogicalChannels:Number(n.openLogicalChannels||0),consecutiveMediaLogicalOpenFailures:Number(n.consecutiveMediaLogicalOpenFailures||0),logicalChannelFailureCount:Number(n.logicalChannelFailureCount||0),lastLogicalChannelFailure:n.lastLogicalChannelFailure||null};ae([{type:"frame.transport.changed",component:"wall-frame-socket",state:Xi||"unknown",reason:Oc||`desired-owners:${Kt.length}`,details:{desiredOwnerCount:Kt.length,frameMode:du.frameMode,managerHubUrl:Y||"unknown",direct:o}},{type:"frame.transport.changed",component:"control-frame-socket",state:_c||"unknown",reason:eo||`desired-owners:${Kr.length}`,details:{desiredOwnerCount:Kr.length,frameMode:mu.frameMode,managerHubUrl:Y||"unknown",direct:o}},{type:"frame.transport.changed",component:"atlas-frame-socket",state:Ji||"unknown",reason:`desired-owners:${nn.length}`,details:{desiredOwnerCount:nn.length,enabled:rt,managerHubUrl:Y||"unknown",direct:o}},{type:"stream.state.changed",component:"wall-subscription",state:yr&&De.autoStartLive?"requested":"idle",reason:Gt?`tool:${Pt}:desired-owners:${Kt.length}`:"document-hidden",details:{documentVisible:Gt,captureOwnershipActive:yr,autoStartLive:De.autoStartLive,activeTool:Pt,desiredOwnerCount:Kt.length}},{type:"stream.state.changed",component:`control-session:${g||"unknown"}`,state:ge,reason:`frame-transport:${_c||"unknown"}`,details:{deviceId:g||"unknown",bindingSessionId:ct?.sessionId||"unknown",bindingStreamId:ct?.streamId||"unknown",bindingCaptureGeneration:ct?.captureGeneration||"unknown",bindingMonitorIndex:ct?.monitorIndex??"unknown"}}])},[Pt,Ji,Kr.length,eo,_c,mu.frameMode,g,ge,ct,Kt.length,Gt,Y,nn.length,rt,it,ae,De.autoStartLive,yr,Oc,Xi,du.frameMode]),s.useEffect(()=>{const n=Am.current,o=new Set([...Object.keys(n),...Object.keys(gt)]);for(const l of o){const m=Math.max(0,Math.floor(Number(n[l])||0)),d=Math.max(0,Math.floor(Number(gt[l])||0));m!==d&&(Vn.current.delete(l),Vt(lt.current.get(l)),Vt(Et.current.get(l)),Vt(en.current.get(l)),Dt("wall",l),Dt("control",l),hi(lt.current.get(l)||null),hi(Et.current.get(l)||null))}o.size>0&&(Vt(Nn.current),hi(Nn.current)),Am.current={...gt}},[gt,Dt,Vt]);const ri=s.useMemo(()=>{const n=(l,m)=>{const d=Le.find(v=>v.deviceId===l),C=d?_n(d,gt[l]):0;return!Number.isFinite(Number(m.monitorIndex))||Number(m.monitorIndex)===C},o=new Map;for(const[l,m]of cp.entries())n(l,m)&&o.set(l,m);if(rt&&ni&&nn.length>0){const l=new Map((Za?.tiles||[]).map(d=>[d.deviceId,d])),m=Math.max(1,l.size);for(const d of nn){const C=l.get(d);C&&o.set(d,{...ni,deviceId:d,width:C.width,height:C.height,sourceWidth:C.width,sourceHeight:C.height,byteLength:Math.round(ni.byteLength/m)})}}for(const[l,m]of Zi.entries())n(l,m)&&o.set(l,m);for(const l of Mc){if(!Br.current.has(l)||o.has(l))continue;const m=Wa.current.get(l);m&&n(l,m)&&o.set(l,m)}return o},[ni,Za,Le,Zi,nn,rt,gt,cp,Mc,Fb]),fu=Ae&&Kr.length>0?_c:nn.length>0?Ji:Xi,Bc=Ae&&Kr.length>0?sv:nn.length>0?iv:Ja;s.useCallback((n,o="browser-stale")=>{const l=lp(n,o),m=jc(n,o);return l||m},[jc,lp]),s.useEffect(()=>{rt&&nn.length>0&&!Ae&&up()},[nn.length,rt,up,Ae]);const ai=s.useCallback((n,o,l)=>{const m=o==="control"?Et.current.get(n)||null:lt.current.get(n)||null;if(!m)return!1;const d=l==="decoder-paint-stale"?Yw(m):hi(m)?"decoder-reset":"none";if(d==="none")return!1;o==="wall"&&l==="decoder-paint-stale"&&_i.current.add(n);const C=performance.now();return gr.current.set(ut(o,n),C),kt(o,n,"fallback",`${l}:${d}`,Nt.current.get(ut(o,n))||0),!0},[kt]),ts=s.useCallback(n=>{if(Gn!=="mode3-h264-hw"||!g||Q)return!1;const o=Le.find(S=>S.deviceId===g)||tn,l=Kh(o?.platform);if(!l)return!1;const m=ut("control",g),d=Nt.current.get(m)||0;kt("control",g,"fallback",n,d),Dt("control",g,{preserveLatestDiagnostic:!0}),hi(Et.current.get(g)||null),es([g],"control-decode-fallback"),Te(l),he(`control-${l}-fallback-${g}-${Date.now()}`),je(!1),gn(!1);const C=n==="no first frame"||n==="control-first-frame-timeout",v=l==="mode1-jpeg"?"Mode 1 JPEG":"Mode 5";return Ut(S=>S||(C?`Control frame transport timeout; retrying Control with ${v} (${n})`:`H.264 decode failed; retrying Control with ${v} (${n})`)),Re("connecting"),!0},[Le,tn,g,Q,Gn,es,kt,Dt]);s.useEffect(()=>{const n=Ae?tn:null;if(n){lc.current={deviceId:n.deviceId,monitorIndex:ir,frameMode:Gn,startedAtEpochMs:Date.now()},gn(g===n.deviceId&&Qe);return}lc.current=null,gn(!1)},[tn?.sessionId,At,g,Qe,Gn,ir,Ae]);const dp=s.useCallback(async(n,o)=>{const l=String(o.streamId||"").trim(),m=String(o.streamPurpose||"").trim(),d=String(o.sessionId||"").trim(),C=String(o.commandId||"").trim(),v=Number(o.captureGeneration||0),S=Number(o.monitorIndex??-1);if(!l||!["wall","atlas"].includes(m)||!d||!C||!Number.isSafeInteger(v)||v<=0||!Number.isSafeInteger(S)||S<0)throw new Error("wall-start-owner-incomplete");const y=performance.now()+3e3;for(;;){const w=await Ue(`/api/remote/devices/${encodeURIComponent(n)}/live/stop`,{method:"POST",body:JSON.stringify({streamId:l,streamPurpose:m,expectedSessionId:d,expectedCommandId:C,expectedCaptureGeneration:v,expectedMonitorIndex:S,requireNoPresentationOwner:!0,reason:"wall-start-presentation-revoked"})},Y);if(w?.ok===!1)throw new Error(w.error||"revoked-wall-start-stop-failed");if(w?.captureStopConfirmed===!0||w?.alreadyStopped===!0||w?.staleOwner===!0)return w;if(w?.presentationOwnerActive===!0||w?.retainedForPresentation===!0){if(qn.current&&Ko.current)return w;if(performance.now()<y){await new Promise(Z=>window.setTimeout(Z,50));continue}throw new Error("revoked-wall-start-presentation-owner-did-not-release")}throw new Error("revoked-wall-start-stop-unconfirmed")}},[Y]),to=s.useCallback(async n=>{if(at.current[n])throw new Error("LIVE_CAPTURE_PAUSED");if(!qn.current||!Ko.current)return{ok:!0,skipped:!0,reason:"wall-capture-owner-hidden"};const o=rr.current,l=Me.find(v=>v.deviceId===n);gs({mode4Enabled:rt,directMode4WallEnabled:Mr,isMac:Nr(l?.platform)});const m=l?_n(l,gt[n]):0,d={fps:ln.fps,maxWidth:ln.maxWidth,maxHeight:ln.maxHeight,quality:ln.quality,mode:rt?"mode3-h264-hw":De.frameMode,frameMode:rt?"mode3-h264-hw":De.frameMode,streamPurpose:"wall",monitorIndex:m},C=await Ue(`/api/remote/devices/${encodeURIComponent(n)}/live/start`,{method:"POST",body:JSON.stringify(d)},Y);if(C?.ok===!1)throw new Error(C.error||"wall-stream-start-failed");return o!==rr.current||!qn.current||!Ko.current?(await dp(n,C),{...C,skipped:!0,reason:"wall-presentation-owner-revoked",compensated:!0}):C},[uu,Me,Mr,Y,rt,gt,dp,De.frameMode,Zo.maxHeight,Zo.maxWidth,ln.fps,ln.maxHeight,ln.maxWidth,ln.quality]),mp=s.useCallback(async n=>{const o=Me.find(m=>m.deviceId===n);gs({mode4Enabled:rt,directMode4WallEnabled:Mr,isMac:Nr(o?.platform)});const l=await Ue(`/api/remote/devices/${encodeURIComponent(n)}/live/stop`,{method:"POST",body:JSON.stringify({streamPurpose:"wall",reason:"control-active"})},Y);if(l?.ok===!1)throw new Error(l.error||"wall-stream-stop-failed");return l},[Me,Mr,Y,rt]),pp=s.useCallback(async(n,o="control-session-stop")=>{if(!el(n))return kt("control",n.deviceId,"stop-deferred",`${o}:unbound-stop-deferred-to-frame-owner`,Nt.current.get(ut("control",n.deviceId))||0),{ok:!0,pendingOwner:!0,deferredToFrameOwner:!0};const m=await Ue(`/api/remote/devices/${encodeURIComponent(n.deviceId)}/live/stop`,{method:"POST",body:JSON.stringify({streamId:n.streamId,expectedSessionId:n.sessionId,expectedCommandId:n.commandId,expectedCaptureGeneration:n.captureGeneration,expectedMonitorIndex:n.monitorIndex,streamPurpose:"control",reason:o})},Y);if(m?.ok===!1)throw new Error(m.error||"control-stream-stop-failed");return(m?.staleOwner===!0||m?.retainedNewerOwner===!0)&&kt("control",n.deviceId,"owner-replaced",`${o}:hub-retained-newer-owner`,Nt.current.get(ut("control",n.deviceId))||0),m},[Y,kt]),An=s.useCallback((n,o={})=>{wt.current?.deviceId===n&&(wt.current=null);const l=Et.current.get(n);if(l){const d=jr.current.has(n)||lt.current.has(n)||en.current.has(n);o.preservePresentation!==!1&&!d&&Qa(n,l),Et.current.delete(n),vn(l),!(hn.current.get(n)||lt.current.get(n)||en.current.get(n))&&!Ha.current&&(Ha.current=l)}const m=hn.current.get(n);m&&fi(m),Wa.current.delete(n),Br.current.delete(n),la.current.delete(n),_o.current.delete(n),$a.current.delete(n),Ur("control",n)},[Ur,Qa,vn]),Hc=s.useCallback(n=>{const o=[ut("wall",n),ut("control",n)];for(const l of o){const m=Va.current.get(l);m?.lastFrame&&(m.lastFrame=So(m.lastFrame))}sc(l=>{let m=!1;const d={...l};for(const C of o){const v=l[C];!v?.lastFrame||v.lastFrame.payload.byteLength===0||(d[C]={...v,lastFrame:So(v.lastFrame)},m=!0)}return m?d:l})},[]),hu=s.useCallback(n=>{Vn.current.delete(n),Yt(n),An(n,{preservePresentation:!1});const o=new Set;for(const l of[hn.current.get(n),lt.current.get(n),en.current.get(n)])l&&o.add(l);for(const l of o)vn(l);Rr(n),g===n&&(lc.current=null,gn(!1),je(!1)),Ti.current.add(n),Hc(n)},[Rr,g,vn,An,Hc,Yt]);s.useEffect(()=>{const n=new Set(Object.keys(ra));for(const o of n)Ti.current.has(o)||hu(o);for(const o of Ti.current)n.has(o)||Ti.current.delete(o)},[hu,ra]);const oi=s.useCallback(n=>{const o=uf(Tm.current,n);return Tm.current=o.tail,o.result},[]),Yn=s.useCallback(n=>{const o=uf(Fm.current,n);return Fm.current=o.tail,o.result},[]),Qn=s.useCallback(n=>{Rn.current=n,nc.current=0;const o=n?.deviceId||"";ua.current=o,Tb(o),o&&Br.current.add(o)},[]),ii=s.useCallback(n=>oi(async()=>{if(at.current[n.deviceId])return!1;const o=Rn.current;return!dn(o,n)||!tl(n.deviceId,n,ke.current)?!1:(await to(n.deviceId),dn(Rn.current,n)&&Qn(null),!0)}),[Qn,oi,to]),fp=s.useCallback((n,o,l)=>oi(async()=>{const m=Rn.current;if(dn(m,n))return l.stoppedWallDeviceId=n.deviceId,!0;if(m)if(at.current[m.deviceId])dn(Rn.current,m)&&Qn(null);else{if(!tl(m.deviceId,m,ke.current))return!1;await to(m.deviceId),dn(Rn.current,m)&&Qn(null)}if(!o())return!1;if(await mp(n.deviceId),l.stoppedWallDeviceId=n.deviceId,!o()){if(tl(l.stoppedWallDeviceId,n,ke.current))try{await to(l.stoppedWallDeviceId)}catch(d){throw Qn(n),d}finally{l.stoppedWallDeviceId=""}return!1}return fi(lt.current.get(n.deviceId)||null),Qn(n),!0}),[Qn,oi,to,mp]),Wc=s.useCallback(async(n,o)=>{if(o.stoppedWallDeviceId){if(dn(Rn.current,n)){try{await ii(n)}catch(l){j(l instanceof Error?l.message:String(l))}finally{o.stoppedWallDeviceId=""}return}await oi(async()=>{if(!o.stoppedWallDeviceId||!tl(o.stoppedWallDeviceId,n,ke.current))return;const l=o.stoppedWallDeviceId;try{await to(l)}catch(m){Qn(n),j(m instanceof Error?m.message:String(m))}finally{o.stoppedWallDeviceId=""}})}},[Qn,oi,ii,j,to]),Xn=s.useCallback(async(n,o,l={})=>{const m=l.allowStopFailure===!0,d=l.resumeWall!==!1,C=S=>{const y=ke.current;if(!y)return S;const w=el(y)&&dn(y,S)&&ho(S,y.deviceId,y.sessionId)&&S.monitorIndex===y.monitorIndex;return On(y,S)||wa(S,y)||w?y:S};let v=C(n);for(let S=0;S<2;S+=1){try{await pp(v,o)}catch(w){if(!m)throw w}const y=C(v);if(On(y,v)||Ku(y,v)||!el(y)||!dn(y,v))break;v=y}if(!On(ke.current,v))return!1;if(ke.current=null,Xe.current=null,ht(null),An(v.deviceId),je(!1),he(""),Te(""),Ut(""),U(S=>S===v.deviceId?"":S),!d)return dn(Rn.current,v)&&Qn(null),!0;try{await ii(v)}catch(S){j(S instanceof Error?S.message:String(S))}return!0},[Qn,An,ii,j,pp]),hp=(Gt&&Ae&&pt&&At&&!Pi.has(At)&&Le.find(n=>n.deviceId===At)||null)?.deviceId||"";s.useEffect(()=>{Ho.current=hp},[hp]),s.useEffect(()=>{const n=At&&Le.find(C=>C.deviceId===At)||null;if(!Gt||!Ae||!pt||!n){sn.current&&(++Wt.current,sn.current="");return}if(at.current[n.deviceId]){sn.current&&(++Wt.current,sn.current=""),g===n.deviceId&&Re("paused");return}if(Un.current){if(Un.current===n.deviceId)return;Un.current=""}if(g===n.deviceId&&ho(ke.current,n.deviceId,n.sessionId||"")&&(ge==="active"||ge==="warm"||ge==="connecting")){Re(C=>C==="warm"?"active":C);return}if(sn.current===n.deviceId)return;const o=++Wt.current,l=Gu(n.deviceId,o,{sessionId:n.sessionId,monitorIndex:ir});sn.current=n.deviceId;const m={stoppedWallDeviceId:""},d=()=>o===Wt.current&&Ho.current===l.deviceId;Yn(async()=>{if(!d())return;const C=ke.current;if(C){Re("stopping");try{await Xn(C,"control-session-switch")}catch(y){d()&&(Re("error"),j(y instanceof Error?y.message:String(y)));return}if(!d()){ke.current||Re("idle");return}}try{if(!await fp(l,d,m)||!d()){await Wc(l,m),ke.current||Re("idle");return}}catch(y){await Wc(l,m),d()&&(Re("error"),j(y instanceof Error?y.message:String(y)));return}if(!d()){await Wc(l,m);return}ke.current=l,wt.current=null,Un.current="",za.current=null,Wo.current=0,Wi.current="",m.stoppedWallDeviceId="";const v=ut("control",l.deviceId),S=`control-session-${o}-${l.deviceId}`;$r.current.set(v,performance.now()),Wr.current.delete(v),hr.current.delete(v),ma.current.delete(v),Fn.current.delete(v),gr.current.delete(v),Nt.current.delete(v),zr.current.delete(v),pa.current.delete(v),Te(""),Ut(""),he(S),U(l.deviceId),je(!1),Re("connecting")}).catch(C=>{d()&&(Re("error"),j(C instanceof Error?C.message:String(C)))}).finally(()=>{Wt.current===o&&sn.current===l.deviceId&&(sn.current="")})},[Le,At,g,ge,Gt,Yn,pt,fp,Wc,ir,j,Ae,Xn,ra]),s.useEffect(()=>{if(!g||Le.some(l=>l.deviceId===g))return;const n=g;++Wt.current,sn.current="";const o=ke.current;Re("stopping"),Yn(async()=>{o&&o.deviceId===n?await Xn(o,"control-device-disconnected",{allowStopFailure:!0}):(An(n),U(l=>l===n?"":l)),ke.current||Re("idle")})},[Le,g,Yn,An,Xn]),s.useEffect(()=>{if(zn.current!==null&&(window.clearTimeout(zn.current),zn.current=null),!or||Ae||!g||at.current[g]||ge!=="connecting"&&ge!=="active"&&ge!=="warm")return;const n=g,o=ke.current;if(!o||o.deviceId!==n)return;const l=window.setTimeout(()=>{zn.current===l&&(zn.current=null);const m=ke.current,d=S=>On(S,o)||wa(o,S)||!!S&&dn(S,o)&&ho(o,S.deviceId,S.sessionId)&&o.monitorIndex===S.monitorIndex;if(Ho.current||at.current[n]||!d(m))return;const C=m||o;wt.current=C;const v=++Wt.current;sn.current="",Re("stopping"),Yn(async()=>{if(v!==Wt.current||Ho.current||!d(ke.current)){(On(wt.current,C)||wa(wt.current,C))&&(wt.current=null);const S=ke.current;Ho.current&&el(S)&&S?.deviceId===n&&Re("active");return}try{await Xn(C,"control-session-wall-downshift")}catch(S){(On(wt.current,C)||wa(wt.current,C))&&(wt.current=null),v===Wt.current&&!Ho.current&&d(ke.current)&&(Re("active"),j(S instanceof Error?S.message:String(S)));return}wt.current=null,v===Wt.current&&!ke.current&&Re("idle")})},$k);return zn.current=l,()=>{zn.current===l&&(window.clearTimeout(l),zn.current=null)}},[g,ge,Yn,j,Ae,Xn,ra,or]);const $c=s.useCallback(n=>{if(Nm.current===n)return;Nm.current=n;const o=ke.current,l=o?.deviceId||g,m=++Wt.current;sn.current="",Xe.current=null,Hi.current=!0,ht(null),je(!1),gn(!1),l&&(Dt("control",l),An(l,{preservePresentation:!1}),Re("stopping"),Yn(async()=>{if(o&&o.deviceId===l)try{await Xn(o,"control-session-document-hidden",{resumeWall:!1})}catch(d){!qn.current&&rr.current===n&&(Re("error"),j(d instanceof Error?d.message:String(d)));return}else An(l,{preservePresentation:!1}),U(d=>d===l?"":d);!ke.current&&Wt.current===m&&Re("idle")}))},[g,Yn,An,Dt,j,Xn]);s.useEffect(()=>{if(nr.current!==null&&(window.clearTimeout(nr.current),nr.current=null),!g||ge==="idle"||ge==="paused"||ge==="error")return;if(!Gt){$c(rr.current);return}if(ge==="stopping"||Yo){g&&gc&&ge==="connecting"&&(Hi.current=!1),g&&gc&&Hi.current&&(ge==="warm"||ge==="active")&&(Hi.current=!1,Xe.current=null,ht(null),je(!1),gn(!1),Dt("control",g),he(`control-presentation-resume-${Date.now()}-${g}`),Re("connecting"));return}Xe.current=null,Hi.current=!0,ht(null),je(!1),gn(!1),Re(o=>o==="idle"||o==="stopping"?o:"warm");const n=g;return An(n,{preservePresentation:!1}),nr.current=window.setTimeout(()=>{nr.current=null,++Wt.current,sn.current="";const o=ke.current;Re("stopping"),Yn(async()=>{if(o&&o.deviceId===n)try{await Xn(o,"control-session-warm-timeout")}catch(l){Re("error"),j(l instanceof Error?l.message:String(l));return}else An(n),U(l=>l===n?"":l);ke.current||Re("idle")})},Wk),()=>{nr.current!==null&&(window.clearTimeout(nr.current),nr.current=null)}},[Yo,gc,g,ge,Gt,Yn,An,$c,Dt,j,Xn]),s.useEffect(()=>()=>{nr.current!==null&&window.clearTimeout(nr.current),zn.current!==null&&(window.clearTimeout(zn.current),zn.current=null),wt.current=null},[]);const Vc=s.useCallback(()=>{const n=new Set(Jl.current),o=ke.current?.deviceId||"";g&&n.add(g),o&&n.add(o),Jl.current=[];for(const m of n){Vn.current.delete(m),Yt(m),An(m,{preservePresentation:!1});for(const d of[lt.current.get(m),hn.current.get(m),en.current.get(m)])d&&vn(d);Rr(m),Dt("wall",m),Dt("control",m),Hc(m)}const l=Nn.current;l&&vn(l),ji.current="",Bo.current=null,Bi.current=0},[Rr,g,vn,An,Hc,Yt,Dt]);s.useEffect(()=>{if(Gt){Jl.current=[...lu];return}Vc()},[Gt,lu,Vc]),s.useEffect(()=>{const n=Rn.current,o=ke.current;if(!or||!n||at.current[n.deviceId]||o&&o.deviceId===n.deviceId){nc.current=0;return}const l=nc.current,m=Math.min(5e3,500*2**Math.min(l,4)),d=window.setTimeout(()=>{jo.current===d&&(jo.current=null);const C=Rn.current;!zm.current||!C||at.current[C.deviceId]||!dn(C,n)||(nc.current=l+1,ii(C).catch(v=>{j(v instanceof Error?v.message:String(v)),dn(Rn.current,C)&&!ke.current&&Eb(S=>S+1)}))},m);return jo.current=d,()=>{window.clearTimeout(d),jo.current===d&&(jo.current=null)}},[ge,ii,j,or,Pb,Li]);const ba=g&&Le.find(n=>n.deviceId===g)||null,va=ba?.deviceId||"",cv=!!(Gt&&Ae&&Mn&&Cr),ns=!!(Ae&&Mn&&ge==="active"&&ba?.sessionId&&ct?.deviceId===ba.deviceId&&ct.sessionId===ba.sessionId&&ct.streamPurpose==="control"&&ct.commandId&&ct.captureGeneration>0&&ct.monitorIndex===ir),gp=ba?.capabilities?.clipboardProtocol==="livedesk.clipboard.v1",bp=gp&&yi(ba,"clipboardCopy"),vp=gp&&yi(ba,"clipboardPaste"),{state:rs,connectionId:no,routeReady:zc,sendInput:yp,stats:Ar,error:wp,remotePointerFeedback:ro}=fC(cv,Y,va,O),ao=ba?.sessionId||"",oo=ct?.commandId||"",io=Number(ct?.captureGeneration||0),si=Number(ct?.monitorIndex||0),lv=ro&&ro.deviceId===va&&ro.monitorIndex===si&&ro.controlSessionId===ao&&ro.controlCommandId===oo&&ro.captureGeneration===io?ro:null,as=s.useCallback((n,o)=>{const l=String(o.type||"").trim().toLowerCase();return Xs.current&&l!=="keyboard.reset"||!qn.current||!ns||!va||!ao||!oo||io<=0||n!==va?!1:yp(n,{...o,monitorIndex:si,controlSessionId:ao,controlCommandId:oo,captureGeneration:io})},[ns,io,oo,va,si,ao,yp]),Uc=[va,ao,oo,io,si,no].join("|"),gu=s.useRef(Uc);gu.current=Uc;const qc=s.useRef(null),wn=s.useCallback(async(n,o,l,m,d=15e3)=>{if(!no||gu.current!==m)throw new Error("Remote Control changed before the clipboard transfer completed.");const C=await Ue(`/api/remote/devices/${encodeURIComponent(va)}/clipboard`,{method:"POST",timeoutMs:d,body:JSON.stringify({action:n,hubConnectionId:no,operationId:o,binding:{sessionId:ao,commandId:oo,captureGeneration:io,monitorIndex:si},payload:l})},Y);if(gu.current!==m)throw new Error("Remote Control changed before the clipboard transfer completed.");if(C?.ok===!1)throw new Error(C.error||"Remote clipboard transfer failed.");return C},[io,oo,va,si,ao,no,Y]),Sp=s.useCallback(async(n,o)=>{const l=window.liveDesk?.clipboard;let m=!1,d=!1;try{await wn("clipboard.prepare",n,{clipboardDirection:"copy"},o),await wn("clipboard.copy",n,{clipboardDirection:"copy"},o),d=!0;const C=await wn("clipboard.copy.begin",n,{},o),v=Ld(C.manifest,n);if(l?.beginWrite&&l.writeChunk&&l.commitWrite){await l.beginWrite(v),m=!0;for(const S of v.items)for(const y of od(S.size)){const w=await wn("clipboard.copy.chunk",n,{itemIndex:S.itemIndex,offset:y.offset,maxBytes:wl},o),Z=bh(String(w.dataBase64||""));if(Number(w.itemIndex)!==S.itemIndex||Number(w.offset)!==y.offset||Number(w.bytes)!==y.byteLength||Z.byteLength!==y.byteLength||w.final===!0!==y.final)throw new Error("Remote clipboard chunk did not match the requested file range.");await l.writeChunk({operationId:n,itemIndex:S.itemIndex,offset:y.offset,dataBase64:String(w.dataBase64||""),final:y.final})}await l.commitWrite(n),m=!1}else{if(v.contentKind==="files")throw new Error("Multiple files require the VuvoDesk desktop app.");const S=[];for(const y of v.items){const w=new Uint8Array(y.size);for(const Z of od(y.size)){const be=await wn("clipboard.copy.chunk",n,{itemIndex:y.itemIndex,offset:Z.offset,maxBytes:wl},o),D=bh(String(be.dataBase64||""));if(D.byteLength!==Z.byteLength)throw new Error("Remote clipboard chunk was incomplete.");w.set(D,Z.offset)}if(await mb(w)!==y.sha256)throw new Error("Remote clipboard content check failed.");S.push(w)}await Pk({manifest:v,payloads:S})}await wn("clipboard.copy.end",n,{},o),d=!1,j(v.contentKind==="files"?`${v.items.length} remote file${v.items.length===1?"":"s"} copied.`:v.contentKind==="image"?"Remote image copied.":"Remote text copied.","success")}catch(C){throw m&&await l?.cancelWrite?.(n).catch(()=>{}),d&&await wn("clipboard.copy.end",n,{},o).catch(()=>{}),C}},[wn,j]),Cp=s.useCallback(async(n,o)=>{const l=window.liveDesk?.clipboard;let m=null,d,C=!1;try{l?.readSnapshot&&l.readChunk?d=Ld(await l.readSnapshot(n),n):(m=await Tk(n),d=m.manifest),await wn("clipboard.prepare",n,{clipboardDirection:"paste",manifest:d},o),C=!0,await wn("clipboard.paste.begin",n,{manifest:d},o);for(const y of d.items)for(const w of od(y.size)){const Z=l?.readChunk?await l.readChunk({operationId:n,itemIndex:y.itemIndex,offset:w.offset,maxBytes:w.byteLength||wl}):{operationId:n,itemIndex:y.itemIndex,offset:w.offset,byteLength:w.byteLength,dataBase64:Ik(m.payloads[y.itemIndex].subarray(w.offset,w.offset+w.byteLength)),final:w.final};if(Z.offset!==w.offset||Z.byteLength!==w.byteLength||Z.final!==w.final)throw new Error("Local clipboard changed during transfer.");const be=await wn("clipboard.paste.chunk",n,{itemIndex:y.itemIndex,offset:w.offset,dataBase64:Z.dataBase64,final:w.final},o);if(Number(be.itemIndex)!==y.itemIndex||Number(be.offset)!==w.offset||Number(be.bytes)!==w.byteLength||be.final===!0!==w.final)throw new Error("Remote clipboard did not confirm the requested file range.")}await wn("clipboard.paste",n,{clipboardDirection:"paste"},o);const v=Date.now()+xk;let S=!1;for(;Date.now()<v;){const y=await wn("clipboard.operation.status",n,{},o,Math.max(250,v-Date.now())),w=String(y.status||"").toLowerCase();if(["completed","complete","applied","pasted"].includes(w)){S=!0;break}if(["failed","cancelled","expired"].includes(w))throw new Error(`Remote clipboard paste ${w}.`);await new Promise(Z=>window.setTimeout(Z,Mk))}if(!S)throw new Error("Remote clipboard paste confirmation timed out.");C=!1,j(d.contentKind==="files"?`${d.items.length} file${d.items.length===1?"":"s"} pasted on the remote computer.`:d.contentKind==="image"?"Image pasted on the remote computer.":"Text pasted on the remote computer.","success")}catch(v){throw C&&await wn("clipboard.paste.cancel",n,{},o).catch(()=>{}),v}finally{await l?.releaseRead?.(n).catch(()=>{})}},[wn,j]),kp=s.useCallback(async n=>{if(!ns||!zc||rs!=="open"||!no){j("Remote input is not ready for clipboard transfer.","error");return}if(qc.current){j("Another clipboard transfer is still running.");return}const o=MC(n),l=Uc;qc.current={operationId:o,direction:n,bindingKey:l};try{Bn(n==="copy"?"Copying from the remote computer…":"Pasting on the remote computer…"),n==="copy"?await Sp(o,l):await Cp(o,l)}catch(m){j(m instanceof Error?m.message:String(m),"error")}finally{qc.current?.operationId===o&&(qc.current=null)}},[Uc,ns,Sp,no,zc,rs,Cp,j,Bn]),Ir=Gt&&qn.current&&ns&&rs==="open"&&zc&&!!no,bu={shiftKey:Ai.includes("ShiftLeft"),ctrlKey:Ai.includes("ControlLeft"),altKey:Ai.includes("AltLeft"),metaKey:Ai.includes("MetaLeft")},cr=s.useCallback(n=>Hs.current.enqueueStop(n),[]),so=s.useCallback(n=>Hs.current.enqueueStart(n),[]),un=s.useCallback((n,o=Bs.current)=>(js.current=n,Bs.current=n?String(o||""):"",sm.current=Ol.current,Ro.current+=1,Ro.current),[]),lr=s.useCallback((n,o,l)=>sm.current===Ol.current&&g0({generation:n,currentGeneration:Ro.current,enabled:js.current,deviceId:o,currentDeviceId:Bs.current,documentVisible:qn.current,presentationVisible:_l.current,streamId:l,currentStreamId:mt.current.get(o)||""}),[]),Jn=s.useCallback(async(n,o,l)=>{if(!o)return{ok:!0,alreadyStopped:!0,captureStopConfirmed:!0,noExactOwner:!0};const d=await(v=>Ue(`/api/remote/devices/${encodeURIComponent(n)}/audio/stop`,{method:"POST",body:JSON.stringify({...v?{streamId:v}:{},reason:l})},Y))(o),C=b0(d);if(C.staleOwner)return d;if(!C.confirmed)throw new Error(d?.error||"Remote audio capture stop was not confirmed.");return d},[Y]),vu=s.useCallback(async(n,o)=>{const l=await Ue(`/api/remote/devices/${encodeURIComponent(n)}/audio/stop`,{method:"POST",body:JSON.stringify({reason:o})},Y);if(l?.ok===!1||l?.captureStopConfirmed!==!0&&l?.alreadyStopped!==!0)throw new Error(l?.error||"Remote audio stop-all was not confirmed.");return l},[Y]),uv=s.useCallback(n=>{const o=Ro.current,l=mt.current.get(n)||"";return cr(()=>Jn(n,l,"remote-audio-automatic-restart")).then(()=>so(async()=>{if(o!==Ro.current||!js.current||Bs.current!==n||!qn.current||!_l.current||!pt||!sr||(Na.current||X?.deviceId||"")!==n)return"";const m=`audio-restart-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;if(mt.current.set(n,m),!lr(o,n,m))return mt.current.delete(n),"";const d=await Ue(`/api/remote/devices/${encodeURIComponent(n)}/audio/start`,{method:"POST",body:JSON.stringify({streamId:m,mimeType:"audio/pcm;format=f32le",sampleRate:48e3,channels:2})},Y);if(d?.ok===!1)throw mt.current.get(n)===m&&mt.current.delete(n),new Error(d.error||"Remote audio restart failed.");return lr(o,n,m)?m:(await Jn(n,m,"remote-audio-stale-restart-compensation"),mt.current.get(n)===m&&mt.current.delete(n),"")}))},[so,cr,pt,Y,lr,sr,X?.deviceId,Jn]),Mp=X?.deviceId&&mt.current.get(X.deviceId)||"",dv=s.useCallback(async(n,o,l)=>{un(!1),Dr(!1),await cr(()=>Jn(n,o,l)),mt.current.get(n)===o&&mt.current.delete(n)},[cr,un,Jn]),{state:yu,lastFrame:wu,stats:It,error:Su}=bC(X?.deviceId||"",Gt&&Jm&&Zt,Y,_b,fn||qt||rc.current,Mp,uv,dv,O),co=s.useRef(new Map);s.useEffect(()=>{const n=[["hub",Be],["registry",de],["license",We],["wall-stream",Oc],["control-stream",eo],["control-decode",yt],["remote-input",wp],["remote-audio",Su]];for(const[o,l]of n){const m=String(l||"").trim(),d=ke.current;if(o==="wall-stream"&&m==="CONTROL_CAPTURE_OWNS_DEVICE"&&!!d&&ua.current===d.deviceId){co.current.delete(o);continue}if(o==="hub"&&tt?.requiresHubRestart&&tt.stage==="updating"){co.current.delete(o);continue}if(o==="hub"&&W&&(xt?.kind==="signal-service-unavailable"||xt?.kind==="p2p-unavailable")){co.current.delete(o);continue}if(!m){const S=co.current.get(o);co.current.delete(o),o==="remote-input"&&S&&fm(S.noticeId,S.message);continue}if(co.current.get(o)?.message===m)continue;const v=j(m);co.current.set(o,{message:m,noticeId:v})}},[Su,fm,yt,eo,Be,xt?.kind,wp,We,W,de,j,Oc,tt]);const Gc=X?.deviceId||"",xp=X?_n(X,gt[Gc]):0;s.useEffect(()=>{if(ca||!Mn||!Cr||!Ir||!Gc)return;const n=WC(),o=Gc,l=xp,m=D=>{if(!D)return!1;const fe=as(o,{...D,monitorIndex:l});return!fe&&D.type!=="keyboard.reset"&&(n.reset("browser-input-send-rejected"),Os([])),fe},d=(D,fe)=>{if(Xs.current)return;const xe=D.target,Oe=xe?.tagName?.toLowerCase(),ze=xe?.isContentEditable||Oe==="input"||Oe==="textarea"||Oe==="select",qe=n.isPressed(D);if(ze&&(fe==="keydown"||!qe))return;const $t=fe==="keydown"?kC(D,Ak()):"";if($t&&($t==="copy"?bp:$t==="paste"?vp:!1)){D.preventDefault(),D.stopPropagation();const us=n.reset("remote-clipboard-shortcut",!0);us&&m(us),Os([]),kp($t);return}const fo=n.event(D,fe);fo&&(D.preventDefault(),D.stopPropagation(),m(fo))},C=D=>d(D,"keydown"),v=D=>d(D,"keyup"),S=(D,fe=!1)=>{const xe=n.reset(D,fe);xe&&(m(xe),Os([]))};Ll.current=D=>{const fe=n.snapshot().latchedCodes.includes(D),xe=n.modifier(D,!fe);xe&&(m(xe),Os(Oe=>fe?Oe.filter(ze=>ze!==D):[...Oe.filter(ze=>ze!==D),D]))};const y=D=>{const fe=sl(D);if(!fe)return!1;const xe=n.snapshot(),Oe={...fe,shiftKey:xe.shiftKey,ctrlKey:xe.ctrlKey,altKey:xe.altKey,metaKey:xe.metaKey},ze=n.event(Oe,"keydown");if(!ze||!m(ze))return!1;const qe=n.event(Oe,"keyup");return!!qe&&m(qe)};Ii.current={sendKey:y,sendText:D=>{let fe=!1;const xe=String(D??"").split(/(\r\n|\r|\n)/);for(const Oe of xe)if(Oe){if(Oe==="\r"||Oe===`
|
|
180
|
+
${p}`,ne=s.useRef(G);ne.current=G;const re=s.useCallback((pe,ce)=>{if(ne.current!==pe||!c(ce))throw new Error("The active VuvoDesk workspace changed. Please try again in the current workspace.")},[c]),O=s.useCallback(async()=>{const pe=q.current+1;q.current=pe;const ce=()=>q.current===pe;if(!u||!p){M(f,dd),T(f,md),x(f,!1),B(f,"");return}x(f,!0);try{const W=t?.role==="owner"?Mt.rpc("list_livedesk_workspace_members",{p_workspace_id:p}):Promise.resolve({data:[],error:null}),ee=t?.role==="owner"?Mt.rpc("list_livedesk_workspace_invites",{p_workspace_id:p}):Promise.resolve({data:[],error:null}),[L,_]=await Promise.all([W,ee]);if(!ce())return;if(L.error)throw L.error;if(_.error)throw _.error;M(f,(Array.isArray(L.data)?L.data:[]).map(K=>({id:String(K.user_id||""),email:String(K.email||""),displayName:String(K.display_name||""),role:String(K.role||"")==="owner"?"owner":"operator",joinedAt:String(K.joined_at||"")})).filter(K=>Ns.test(K.id))),T(f,(Array.isArray(_.data)?_.data:[]).map(K=>({id:String(K.invite_id||""),email:String(K.email||""),role:"operator",createdAt:String(K.created_at||""),expiresAt:String(K.expires_at||"")})).filter(K=>Ns.test(K.id))),B(f,""),x(f,!1)}catch(W){if(!ce())return;B(f,W instanceof Error?W.message:String(W)),x(f,!1)}},[t?.role,f,B,T,x,M,u,p]);s.useEffect(()=>(q.current+=1,M(f,dd),T(f,md),B(f,""),O(),()=>{q.current+=1}),[f,B,T,M,O,h]);const ie=s.useCallback(async pe=>{if(!p||t?.role!=="owner")throw new Error("Only the Team owner can create invitations.");const ce=G,W=String(pe||"").trim().toLowerCase();if(!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(W))throw new Error("Enter the Google account email to invite.");const{data:ee,error:L}=await Mt.rpc("invite_livedesk_workspace_member",{p_workspace_id:p,p_email:W,p_role:"operator"});if(re(ce,p),L)throw L;const _=Co(ee),K=String(_?.invite_token||"").trim().toLowerCase();if(!_?.ok||!tm.test(K))throw Si(_,"team invite creation failed");const ue=new URL("/app",window.location.origin);return ue.searchParams.set(Pl,K),re(ce,p),await Promise.all([O(),r()]),{url:ue.toString(),expiresAt:_.expires_at}},[t?.role,re,O,r,p,G]),J=s.useCallback(async pe=>{if(!p||t?.role!=="owner")throw new Error("Only the Team owner can remove members.");const ce=G,{data:W,error:ee}=await Mt.rpc("remove_livedesk_workspace_member",{p_workspace_id:p,p_user_id:pe});if(re(ce,p),ee)throw ee;const L=Co(W);if(!L?.ok)throw Si(L,"team member removal failed");let _=!0;try{await Ue(`/api/remote/workspace/members/${encodeURIComponent(pe)}/revoke`,{method:"POST",body:JSON.stringify({workspaceId:p})},a)}catch{_=!1}return re(ce,p),await Promise.all([O(),r()]),{revokedImmediately:_}},[t?.role,re,a,O,r,p,G]),de=s.useCallback(async pe=>{if(!p||t?.role!=="owner")throw new Error("Only the Team owner can revoke invitations.");const ce=G,{data:W,error:ee}=await Mt.rpc("revoke_livedesk_workspace_invite",{p_workspace_id:p,p_invite_id:pe});if(re(ce,p),ee)throw ee;const L=Co(W);if(!L?.ok)throw Si(L,"team invite revocation failed");await Promise.all([O(),r()])},[t?.role,re,O,r,p,G]),se=s.useCallback(async()=>{if(!p||t?.role!=="operator")throw new Error("Only an Operator can leave this Team Space.");const pe=G,{data:ce,error:W}=await Mt.rpc("leave_livedesk_workspace",{p_workspace_id:p});if(re(pe,p),W)throw W;const ee=Co(ce);if(!ee?.ok)throw Si(ee,"leaving team workspace failed")},[t?.role,re,p,G]);return s.useMemo(()=>({members:k,invites:b,loading:A,error:E,refresh:O,createInvite:ie,removeMember:J,revokeInvite:de,leaveWorkspace:se}),[ie,E,b,se,A,k,O,J,de])}function Jg({state:e}){return e==="ok"?i.jsx(Cn,{size:15,"aria-hidden":"true"}):i.jsx(vy,{size:15,"aria-hidden":"true"})}function dh({active:e,refreshing:t,onClick:a}){return i.jsx("button",{className:`remote-status-button ${e?"active":""}`,type:"button",title:"Check Remote Status","aria-label":"Check Remote Status","aria-pressed":e,"aria-busy":t,onClick:a,children:t?i.jsx("span",{className:"remote-status-spinner","aria-hidden":"true"}):i.jsx(gy,{size:18,"aria-hidden":"true"})})}function mh({active:e,refreshing:t,onClick:a}){return i.jsx("button",{className:`remote-status-button debug-status-button ${e?"active":""}`,type:"button",title:"Check Debug Status","aria-label":"Check Debug Status","aria-pressed":e,"aria-busy":t,onClick:a,children:t?i.jsx("span",{className:"remote-status-spinner","aria-hidden":"true"}):i.jsx(by,{size:18,"aria-hidden":"true"})})}function ph({active:e,refreshing:t,onClick:a}){return i.jsx("button",{className:`remote-status-button hub-status-button ${e?"active":""}`,type:"button",title:"Check Hub Status","aria-label":"Check Hub Status","aria-pressed":e,"aria-busy":t,onClick:a,children:t?i.jsx("span",{className:"remote-status-spinner","aria-hidden":"true"}):i.jsx(Ci,{size:18,"aria-hidden":"true"})})}function Zg({items:e,mode:t="remote"}){return i.jsx("span",{className:`remote-status-lines mode-${t}`,role:"status","aria-label":t==="debug"?"Debug status":"Remote status",onPointerDown:t==="debug"?a=>a.stopPropagation():void 0,onClick:t==="debug"?a=>a.stopPropagation():void 0,onDoubleClick:t==="debug"?a=>a.stopPropagation():void 0,children:e.map(a=>i.jsxs("span",{className:`remote-status-line state-${a.state}`,title:a.detail,children:[i.jsx(Jg,{state:a.state}),i.jsxs("span",{children:[i.jsx("strong",{children:a.label}),i.jsx("small",{children:a.detail})]})]},a.id))})}function G0({items:e,collectedAt:t,onClose:a}){return i.jsxs("section",{className:"remote-status-dialog hub-status-dialog",role:"dialog","aria-modal":"false","aria-labelledby":"hub-status-dialog-title",children:[i.jsxs("header",{children:[i.jsx("span",{className:"remote-status-dialog-mark","aria-hidden":"true",children:i.jsx(Ci,{size:19})}),i.jsxs("span",{children:[i.jsx("small",{children:"Hub measurements"}),i.jsx("h2",{id:"hub-status-dialog-title",children:"Hub Status"})]}),i.jsx("button",{type:"button",onClick:a,title:"Close Hub status","aria-label":"Close Hub status",children:i.jsx(xa,{size:17})})]}),i.jsx("p",{children:"VuvoDesk collects these Hub and browser signals continuously. This check refreshed the latest snapshot instead of starting a one-time benchmark."}),i.jsx("div",{className:"remote-status-dialog-list",children:e.map(r=>i.jsxs("article",{className:`remote-status-dialog-row state-${r.state}`,children:[i.jsx(Jg,{state:r.state}),i.jsxs("span",{children:[i.jsx("strong",{children:r.label}),i.jsx("small",{children:r.detail})]})]},r.id))}),i.jsxs("footer",{children:["Checked ",new Date(t).toLocaleTimeString()]})]})}async function K0(e,t={}){const a=e.filter(b=>b.canvas&&b.canvas.width>0&&b.canvas.height>0),r=Math.max(320,t.maxWidth||1920),c=Math.max(180,t.maxHeight||1080),u=a.length<=1?1:a.length<=4?2:a.length<=9?3:4,p=Math.max(1,Math.ceil(Math.max(1,a.length)/u)),h=Math.floor(r/u),f=Math.floor(c/p),k=document.createElement("canvas");k.width=Math.max(320,h*u),k.height=Math.max(180,f*p);const M=k.getContext("2d",{alpha:!1});if(!M)return k;M.fillStyle="#0b1220",M.fillRect(0,0,k.width,k.height),M.font="600 14px system-ui, sans-serif",M.textBaseline="bottom";for(let b=0;b<a.length;b+=1){const T=a[b],A=b%u,x=Math.floor(b/u),E=A*h,B=x*f,q=T.canvas,G=Math.min(h/q.width,f/q.height),ne=Math.max(1,Math.floor(q.width*G)),re=Math.max(1,Math.floor(q.height*G)),O=E+Math.floor((h-ne)/2),ie=B+Math.floor((f-re)/2);M.drawImage(q,O,ie,ne,re),t.includeLabels!==!1&&(M.fillStyle="rgba(4, 10, 20, .74)",M.fillRect(E,B+f-28,h,28),M.fillStyle="#f8fafc",M.fillText(T.label,E+9,B+f-9))}return k}function Y0(e){return e?.signature||"none"}function Q0(e){return e?.label||"No capture target"}function fh(e){return{...e,deviceIds:[...e.deviceIds],sourceCanvas:e.sourceCanvas||null}}function eb(e){return{type:e.type,deviceIds:e.deviceIds,monitorIndex:e.monitorIndex,label:e.label}}async function tb(e){try{return(await e.json()).error||`${e.status} ${e.statusText}`}catch{return`${e.status} ${e.statusText}`}}async function nb(e,t,a){const r=encodeURIComponent(JSON.stringify({kind:t.kind,fileName:t.fileName,mimeType:e.type||"application/octet-stream",durationMs:t.durationMs,target:eb(t.target)})),c=await Qh(`/api/captures?metadata=${r}`,{method:"POST",headers:{"Content-Type":e.type||"application/octet-stream"},body:e},a);if(!c.ok)throw new Error(await tb(c));return await c.json()}async function X0(e,t){return await Ue("/api/capture-sessions",{method:"POST",body:JSON.stringify({...e,target:eb(e.target)})},t)}async function J0(e,t,a,r){const c=await Qh(`/api/capture-sessions/${encodeURIComponent(e)}/chunks/${t}`,{method:"PUT",headers:{"Content-Type":a.type||"application/octet-stream"},body:a},r);if(!c.ok)throw new Error(await tb(c));return await c.json()}async function Z0(e,t,a){return await Ue(`/api/capture-sessions/${encodeURIComponent(e)}/finalize`,{method:"POST",body:JSON.stringify({durationMs:t})},a)}async function hh(e,t){await Ue(`/api/capture-sessions/${encodeURIComponent(e)}`,{method:"DELETE"},t)}async function px(e){return await Ue("/api/captures",void 0,e)}function fx(e,t){return`${Yh(t)}/api/captures/${encodeURIComponent(e)}/content`}async function hx(e,t){return await Ue(`/api/captures/${encodeURIComponent(e)}`,{method:"DELETE"},t)}function ek(){const e=new Date,t=a=>String(a).padStart(2,"0");return`${e.getFullYear()}${t(e.getMonth()+1)}${t(e.getDate())}_${t(e.getHours())}${t(e.getMinutes())}${t(e.getSeconds())}`}function tk(e){return e.replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,80)||"Wall"}function nk(e){return`VuvoDesk_${e.type==="wall"||e.type==="selection"?"Wall":`${tk(e.label)}_Monitor-${Number(e.monitorIndex||0)+1}`}_${ek()}.png`}async function rk(e,t,a){const r=await new Promise((u,p)=>e.toBlob(h=>h?u(h):p(new Error("Screenshot could not be encoded.")),"image/png")),c=await nb(r,{kind:"screenshot",fileName:nk(t),target:t},a);try{await navigator.clipboard.write([new ClipboardItem({"image/png":r})])}catch{}return c.capture}function rb(){return["video/webm;codecs=vp9","video/webm;codecs=vp8","video/webm"].find(t=>typeof MediaRecorder<"u"&&MediaRecorder.isTypeSupported(t))||""}function ak(e,t){const a=new Date().toISOString().replace(/[-:]/g,"").replace(/\.\d{3}Z$/,"").replace("T","_"),r=t.label.replace(/[^a-zA-Z0-9._-]+/g,"-").slice(0,70)||"Wall";return e==="timelapse"?`VuvoDesk_Timelapse_${r}_${a}.webm`:`VuvoDesk_Recording_${r}_${a}.webm`}async function ab(e){if(typeof MediaRecorder>"u"||typeof e.canvas.captureStream!="function")throw new Error("This browser does not support video recording.");const t=rb();if(!t)throw new Error("This browser does not support WebM recording.");const a=e.kind||"recording",r=await X0({kind:a,fileName:ak(a,e.target),mimeType:t,target:e.target},e.hubUrl),c=e.canvas.captureStream(e.frameRequests?0:e.fps),u=new MediaRecorder(c,{mimeType:t,videoBitsPerSecond:a==="timelapse"?2e6:4e6}),p=performance.now();let h=0,f=!1,k=null,M=Promise.resolve();return u.ondataavailable=b=>{if(!b.data||b.data.size===0)return;const T=h++;M=M.then(()=>J0(r.sessionId,T,b.data,e.hubUrl).then(()=>{})).catch(A=>{k=k||(A instanceof Error?A:new Error(String(A))),e.onError?.(k)})},u.onerror=()=>{k=new Error("Video recording stopped unexpectedly."),e.onError?.(k)},u.start(1e3),{requestFrame:()=>{c.getVideoTracks()[0]?.requestFrame?.()},stop:async()=>{if(!f){if(f=!0,await new Promise(b=>{u.addEventListener("stop",()=>b(),{once:!0}),u.stop()}),c.getTracks().forEach(b=>b.stop()),await M,k)throw await hh(r.sessionId,e.hubUrl).catch(()=>{}),k;await Z0(r.sessionId,Math.max(0,performance.now()-p),e.hubUrl)}},cancel:async()=>{f||(f=!0,u.stop(),c.getTracks().forEach(b=>b.stop()),await hh(r.sessionId,e.hubUrl).catch(()=>{}))}}}class ok{recorder=null;stream=null;segments=[];totalBytes=0;targetSignature="";startedAt=0;maxDurationMs=3e4;maxBytes=128*1024*1024;get seconds(){return!this.startedAt||this.segments.length===0?0:Math.min(30,Math.max(0,(performance.now()-this.segments[0].at)/1e3))}get active(){return this.recorder!==null}async start(t,a){if(this.recorder&&this.targetSignature===a.signature)return;if(this.stop(),typeof MediaRecorder>"u"||typeof t.captureStream!="function")throw new Error("This browser does not support Last 30s.");const r=rb();if(!r)throw new Error("This browser does not support WebM recording.");this.targetSignature=a.signature,this.stream=t.captureStream(20),this.recorder=new MediaRecorder(this.stream,{mimeType:r,videoBitsPerSecond:3e6}),this.startedAt=performance.now(),this.recorder.ondataavailable=c=>{if(!c.data.size)return;const u=performance.now();for(this.segments.push({blob:c.data,at:u}),this.totalBytes+=c.data.size;this.segments.length>1&&(u-this.segments[0].at>this.maxDurationMs||this.totalBytes>this.maxBytes);){const p=this.segments.shift();this.totalBytes-=p.blob.size}},this.recorder.start(1e3)}stop(){const t=this.recorder;this.recorder=null,t&&t.state!=="inactive"&&(t.ondataavailable=null,t.stop()),this.stream?.getTracks().forEach(a=>a.stop()),this.stream=null,this.segments=[],this.totalBytes=0,this.startedAt=0}async save(t,a){if(this.segments.length===0)throw new Error("The Last 30s buffer is not ready yet.");const r=new Blob(this.segments.map(p=>p.blob),{type:this.segments[0].blob.type||"video/webm"}),u=`VuvoDesk_Last30s_${t.label.replace(/[^a-zA-Z0-9._-]+/g,"-").slice(0,70)||"Wall"}_${new Date().toISOString().replace(/[-:]/g,"").replace(/\.\d{3}Z$/,"").replace("T","_")}.webm`;return await nb(r,{kind:"last-30s",fileName:u,target:t,durationMs:Math.min(3e4,this.segments.length*1e3)},a)}}async function ik(e,t,a,r,c){const u=await ab({canvas:e,target:t,kind:"timelapse",fps:30,frameRequests:!0,hubUrl:r,onError:c});u.requestFrame?.();const p=window.setInterval(()=>u.requestFrame?.(),Math.max(5,a)*1e3);return{stop:async()=>{window.clearInterval(p),await u.stop()},cancel:async()=>{window.clearInterval(p),await u.cancel()}}}const ob="livedesk.captureSettings";function sk(){const e={rollingEnabled:!1,recordingQuality:"standard",timelapseIntervalSeconds:10,includeRemoteCursor:!0};try{const t=JSON.parse(localStorage.getItem(ob)||"null");return{...e,...t&&typeof t=="object"?t:{}}}catch{return e}}function ck(e){const[t,a]=s.useState(sk),[r,c]=s.useState(0),[u,p]=s.useState(0),[h,f]=s.useState(0),[k,M]=s.useState(!1),b=s.useRef(void 0),T=s.useRef(!1),A=s.useRef(""),x=s.useRef(null),E=s.useRef(null),B=s.useRef(null),q=s.useRef(null),G=s.useRef(new ok),ne=e.sourceRegistry.resolveCurrentTarget(),re=Y0(ne),O=Q0(ne),ie=typeof MediaRecorder<"u"&&typeof HTMLCanvasElement<"u"&&"captureStream"in HTMLCanvasElement.prototype;s.useEffect(()=>{if(localStorage.setItem(ob,JSON.stringify(t)),!e.remoteSettingsEnabled||!e.hubUrl||!T.current)return;const P=JSON.stringify(t);P!==A.current&&(A.current=P,Ue("/api/settings",{method:"PATCH",body:JSON.stringify({revision:b.current,filesAudio:{rollingBufferEnabled:t.rollingEnabled,recordingQuality:t.recordingQuality,timelapseIntervalSeconds:t.timelapseIntervalSeconds,includeRemoteCursor:t.includeRemoteCursor}})},e.hubUrl).then(N=>{b.current=Number(N.revision||b.current||0)}).catch(()=>{}))},[e.hubUrl,e.remoteSettingsEnabled,t]),s.useEffect(()=>{if(!e.remoteSettingsEnabled||!e.hubUrl){T.current=!1;return}let P=!0;return Ue("/api/settings",void 0,e.hubUrl).then(N=>{if(!P)return;const te=N.settings?.filesAudio||{},we=typeof te.rollingBufferEnabled=="boolean"?te.rollingBufferEnabled:t.rollingEnabled,me=te.recordingQuality==="high"?"high":"standard",Fe=[5,10,30,60].includes(Number(te.timelapseIntervalSeconds))?Number(te.timelapseIntervalSeconds):t.timelapseIntervalSeconds,H=typeof te.includeRemoteCursor=="boolean"?te.includeRemoteCursor:t.includeRemoteCursor,R={rollingEnabled:we,recordingQuality:me,timelapseIntervalSeconds:Fe,includeRemoteCursor:H};b.current=Number(N.revision||0),A.current=JSON.stringify(R),T.current=!0,a(R)}).catch(()=>{T.current=!0}),()=>{P=!1}},[e.hubUrl,e.remoteSettingsEnabled]);const J=s.useCallback(async P=>{if(P.sourceCanvas&&P.sourceCanvas.width>0&&P.sourceCanvas.height>0)return{target:fh(P),canvas:P.sourceCanvas,cleanup:()=>{}};const N=await e.sourceRegistry.composeWall(P.deviceIds,{maxWidth:1920,maxHeight:1080,includeLabels:!0});let te=!1;const we=window.setInterval(async()=>{if(te)return;const me=await e.sourceRegistry.composeWall(P.deviceIds,{maxWidth:1920,maxHeight:1080,includeLabels:!0}).catch(()=>null);!me||te||((N.width!==me.width||N.height!==me.height)&&(N.width=me.width,N.height=me.height),N.getContext("2d")?.drawImage(me,0,0))},100);return{target:fh(P),canvas:N,cleanup:()=>{te=!0,window.clearInterval(we)}}},[e.sourceRegistry]);s.useEffect(()=>{const P=G.current;if(!t.rollingEnabled||!ne||!ie){P.stop(),f(0);return}let N=!1,te=null;return(async()=>{try{if(te=await J(ne),N)return;await P.start(te.canvas,te.target);const me=window.setInterval(()=>f(Math.round(P.seconds)),500),Fe=()=>{window.clearInterval(me),te?.cleanup()};P.__cleanup=Fe}catch(me){N||e.onToast(me instanceof Error?me.message:String(me))}})(),()=>{N=!0,P.stop(),P.__cleanup?.(),P.__cleanup=void 0,f(0)}},[J,e.onToast,t.rollingEnabled,re,ie]);const de=s.useCallback(P=>a(N=>({...N,rollingEnabled:P})),[]),se=s.useCallback(P=>a(N=>({...N,recordingQuality:P})),[]),pe=s.useCallback(P=>a(N=>({...N,timelapseIntervalSeconds:P})),[]),ce=s.useCallback(async()=>{const P=e.sourceRegistry.resolveCurrentTarget();if(!P)throw new Error("화면이 준비된 후 다시 시도하세요.");M(!0);let N=null;try{N=await J(P),await rk(N.canvas,N.target,e.hubUrl),e.onToast("Screenshot saved")}finally{N?.cleanup(),M(!1)}},[J,e.hubUrl,e.onToast,e.sourceRegistry]),W=s.useCallback(async()=>{if(B.current)throw new Error("Stop the timelapse before recording.");const P=e.sourceRegistry.resolveCurrentTarget();if(!P)throw new Error("화면이 준비된 후 다시 시도하세요.");const N=await J(P),te=await ab({canvas:N.canvas,target:N.target,fps:P.type==="control"?30:15,hubUrl:e.hubUrl,onError:we=>e.onToast(we.message)});E.current=N.cleanup,x.current=te,c(Date.now()),e.onToast("Recording started")},[J,e.hubUrl,e.onToast,e.sourceRegistry]),ee=s.useCallback(async()=>{const P=x.current;if(P){M(!0);try{await P.stop(),e.onToast("Recording saved")}finally{x.current=null,E.current?.(),E.current=null,c(0),M(!1)}}},[e.onToast]),L=s.useCallback(async()=>{if(x.current||B.current)throw new Error("Last 30s is unavailable during a recording.");const P=e.sourceRegistry.resolveCurrentTarget();if(!P)throw new Error("화면이 준비된 후 다시 시도하세요.");M(!0);try{await G.current.save(P,e.hubUrl),e.onToast("Last 30 seconds saved")}finally{M(!1)}},[e.hubUrl,e.onToast,e.sourceRegistry]),_=s.useCallback(async()=>{if(x.current)throw new Error("Stop the recording before starting a timelapse.");const P=e.sourceRegistry.resolveCurrentTarget();if(!P)throw new Error("화면이 준비된 후 다시 시도하세요.");const N=await J(P),te=await ik(N.canvas,N.target,t.timelapseIntervalSeconds,e.hubUrl,we=>e.onToast(we.message));q.current=N.cleanup,B.current=te,p(Date.now()),e.onToast("Timelapse started")},[J,e.hubUrl,e.onToast,e.sourceRegistry,t.timelapseIntervalSeconds]),K=s.useCallback(async()=>{const P=B.current;if(P){M(!0);try{await P.stop(),e.onToast("Timelapse saved")}finally{B.current=null,q.current?.(),q.current=null,p(0),M(!1)}}},[e.onToast]);return s.useEffect(()=>{const P=N=>{!x.current&&!B.current||(N.preventDefault(),N.returnValue="")};return window.addEventListener("beforeunload",P),()=>window.removeEventListener("beforeunload",P)},[]),s.useEffect(()=>()=>{G.current.stop(),x.current?.cancel(),B.current?.cancel(),E.current?.(),q.current?.()},[]),{state:s.useMemo(()=>({recording:!!x.current,recordingStartedAt:r,timelapse:!!B.current,timelapseStartedAt:u,bufferSeconds:h,bufferEnabled:t.rollingEnabled,busy:k,targetLabel:O}),[h,k,r,t.rollingEnabled,O,u]),settings:t,videoSupported:ie,targetKey:re,setRollingEnabled:de,setRecordingQuality:se,setTimelapseInterval:pe,takeScreenshot:ce,startRecording:W,stopRecording:ee,saveLast30Seconds:L,startTimelapse:_,stopTimelapse:K}}function lk(){if(typeof window>"u")return{isIos:!1,isAndroid:!1,isSafari:!1,browserName:"browser"};const e=window.navigator.userAgent,t=window.navigator.standalone,a=e0(e,window.navigator.platform,window.navigator.maxTouchPoints,t),r=/Android/i.test(e),c=a&&/CriOS/i.test(e),u=a&&/Safari/i.test(e)&&!/(CriOS|FxiOS|EdgiOS|OPiOS|DuckDuckGo)/i.test(e);return{isIos:a,isAndroid:r,isSafari:u,browserName:c?"Chrome":u?"Safari":"browser"}}const gh=s.lazy(()=>mr(()=>import("./AgentsPage-DcUy7xPU.js"),__vite__mapDeps([0,1,2,3,4,5])).then(e=>({default:e.AgentsPage}))),uk=s.lazy(()=>mr(()=>import("./ShareFilesPage-C9vhKzGp.js"),__vite__mapDeps([6,1,2,3,4,7])).then(e=>({default:e.ShareFilesPage}))),In="".trim().toLowerCase()==="true",Ca="".trim().toLowerCase()==="true",Zr="".trim().toLowerCase()==="true",dk=s.lazy(()=>mr(()=>import("./SupportPage-C-uQ-RTX.js"),__vite__mapDeps([8,1,2,3,4,9,10,11])).then(e=>({default:e.SupportPage}))),mk=s.lazy(()=>mr(()=>import("./SettingsPage-ChNfBaQo.js"),__vite__mapDeps([12,1,2,3,4])).then(e=>({default:e.SettingsPage}))),pk=s.lazy(()=>mr(()=>import("./SettingsTabs-B-uMhvwn.js"),__vite__mapDeps([13,1,2,3,4])).then(e=>({default:e.PinSettingsTab}))),fk=s.lazy(()=>mr(()=>import("./AgentSettingsTab-CU3kHssT.js"),__vite__mapDeps([14,1,2,3,4])).then(e=>({default:e.AgentSettingsTab}))),hk=s.lazy(()=>mr(()=>import("./DesktopUpdatePanel-C5wDB5zf.js"),__vite__mapDeps([15,1,2,3,4])).then(e=>({default:e.DesktopUpdatePanel}))),gk=s.lazy(()=>mr(()=>import("./CaptureGallery-BPKKxPej.js"),__vite__mapDeps([16,1,2,3,4,9,10])).then(e=>({default:e.CaptureGallery})));function bs({children:e}){return i.jsx(s.Suspense,{fallback:i.jsx("div",{className:"deferred-feature-loading",role:"status",children:"Loading…"}),children:e})}const bk=120,vk=999,ib="livedesk.remoteDirectory",$d="livedesk.localHubAccessEnabled",yk="livedesk.streamSettings",wk=18,Sk="livedesk.controlStreamSettings",Ck=10,sb="livedesk.wallCadence",cb="livedesk.wallViewScale",lb="livedesk.mobileWallStatsVisible",kk=1e3,ub="livedesk.wallMonitorSelections",db=2,pd=512*1024,Mk=250,xk=15e3,Rk=!1;function Ak(){return typeof navigator>"u"?!1:/Mac|iPhone|iPad|iPod/i.test(`${navigator.platform} ${navigator.userAgent}`)}function Ik(e){let t="";for(let a=0;a<e.length;a+=32*1024)t+=String.fromCharCode(...e.subarray(a,Math.min(e.length,a+32*1024)));return window.btoa(t)}function bh(e){const t=window.atob(String(e||"")),a=new Uint8Array(t.length);for(let r=0;r<t.length;r+=1)a[r]=t.charCodeAt(r);return a}async function mb(e){const t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t),a=>a.toString(16).padStart(2,"0")).join("")}async function Tk(e){const t=navigator.clipboard;let a="text",r="clipboard.txt",c="text/plain",u=null;if(typeof t?.read=="function"){const h=await t.read(),f=h.find(k=>k.types.includes("image/png"));if(f){const k=await f.getType("image/png");a="image",r="clipboard.png",c="image/png",u=new Uint8Array(await k.arrayBuffer())}else{const k=h.find(M=>M.types.includes("text/plain"));if(k){const M=await k.getType("text/plain");u=new TextEncoder().encode(await M.text())}}}if(!u&&typeof t?.readText=="function"&&(u=new TextEncoder().encode(await t.readText())),!u)throw new Error("The browser did not provide text or a PNG image from the clipboard.");return{manifest:Ld({operationId:e,contentKind:a,totalBytes:u.byteLength,items:[{itemIndex:0,kind:a,name:r,mimeType:c,size:u.byteLength,lastModified:Date.now(),sha256:await mb(u),storageName:"item-0.bin"}]},e),payloads:[u]}}async function Pk(e){const{manifest:t,payloads:a}=e,r=a[0];if(!r||t.items.length!==1)throw new Error("clipboard-browser-snapshot-invalid");if(t.contentKind==="text"){await navigator.clipboard.writeText(new TextDecoder().decode(r));return}if(t.contentKind==="image"&&typeof ClipboardItem<"u"){await navigator.clipboard.write([new ClipboardItem({"image/png":new Blob([r],{type:"image/png"})})]);return}throw new Error("Multiple files require the VuvoDesk desktop app.")}"".trim();"".trim();const Ek=Object.freeze([{code:"ShiftLeft",label:"Shift"},{code:"ControlLeft",label:"Ctrl"},{code:"AltLeft",label:"Alt"},{code:"MetaLeft",label:"Win"}]),Nk=1e3/60,fd=1500,Fk=650,Dk=1800,Lk=650,Ok=2500,hd=1500,vh=15e3,yh=120,_k=.72,pb=6,jk=640*360,Bk=8;function Hk(e){let t=2166136261;for(let a=0;a<e.length;a+=1)t=Math.imul(t^e.charCodeAt(a),16777619);return(t>>>0)%pb}const wh=100,Sh=20,Wk=6e4,$k=6e4,Ch=240,Vk=1024,zk=640,Uk=360,kh="Connected VuvoDesk clients are updating in batches. Hub will restart after every target reconnects on the requested versions.",ml="VuvoDesk is replacing the Hub and verifying the requested version.",pl=5*6e4,qk=5e3,Mh=2e3,Gk=8e3;function xh(e,t){return`${e}:${t.deviceId}:${t.completedAt||t.candidateSessionId||t.commandId||"completed"}`}function bo({label:e,tooltip:t,disabled:a=!1,active:r=!1,danger:c=!1,pressed:u,onClick:p,children:h}){return i.jsx("span",{className:`manual-action-tooltip ${a?"disabled":""}`.trim(),"data-tooltip":t,children:i.jsx("button",{className:`manual-action ${r?"active":""} ${c?"danger":""}`.trim(),onClick:p,disabled:a,"aria-label":e,"aria-pressed":u,type:"button",children:h})})}function Kk(e,t){if(t.deviceId!==e.deviceId)return!1;const a=Number(t.browserReceivedEpochMs);if(!Number.isFinite(a)||a<e.startedAtEpochMs)return!1;const r=Number(t.monitorIndex);if(Number.isFinite(r)&&Math.floor(r)!==e.monitorIndex)return!1;const c=String(t.frameMode||t.mode||"").trim().toLowerCase();return!c||c===e.frameMode}const Yk={"mode3-h264-hw":30};function Rh(e,t){const a=p=>{const f=String(p||"").trim().replace(/^v/i,"").match(/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/);if(!f)return null;const k=f[4]?f[4].split(".").map(M=>/^\d+$/.test(M)?M.length>1&&M.startsWith("0")?Number.NaN:Number(M):M):[];return k.some(M=>typeof M=="number"&&!Number.isFinite(M))?null:{core:[Number(f[1]),Number(f[2]),Number(f[3])],prerelease:k}},r=a(e),c=a(t);if(!r||!c)return!1;for(let p=0;p<3;p+=1){if(r.core[p]>c.core[p])return!0;if(r.core[p]<c.core[p])return!1}if(r.prerelease.length===0||c.prerelease.length===0)return r.prerelease.length===0;const u=Math.max(r.prerelease.length,c.prerelease.length);for(let p=0;p<u;p+=1){const h=r.prerelease[p],f=c.prerelease[p];if(h===void 0||f===void 0)return f===void 0;if(h!==f){if(typeof h=="number"&&typeof f=="number")return h>f;if(typeof h=="number")return!1;if(typeof f=="number"||h>f)return!0;if(h<f)return!1}}return!0}const Qk=1024;function ut(e,t){return`${e}:${t}`}function er(e){return[e.deviceId,e.sessionId||"",e.streamId||"",e.commandId||"",Number(e.captureGeneration||0),Number(e.monitorIndex??-1),e.streamPurpose||""].join("|")}const Xk={frameMode:"mode3-h264-hw",h264DecodeAcceleration:"prefer-hardware",fps:Yk["mode3-h264-hw"],maxWidth:1920,maxHeight:1080,atlasTileWidth:320,atlasTileHeight:180,atlasTileSizeMode:"auto",quality:75,autoStartLive:!0,showScreenStatus:!0,visibleOnlyLive:!0,adaptiveLoadShedding:!0,adaptiveSizeByWall:!0},Jk={frameMode:"mode3-h264-hw",h264DecodeAcceleration:"prefer-hardware",fps:30,maxWidth:3840,maxHeight:2160,quality:75,showScreenStatus:!1},Ah={maxWidth:3840,maxHeight:2160};function vs(e,t){if(e.length===0)return 0;const a=[...e].sort((c,u)=>c-u),r=Math.max(0,Math.min(a.length-1,Math.ceil(a.length*t)-1));return a[r]}function fb(e,t){e.push(t),e.length>Ch&&e.splice(0,e.length-Ch)}function fl(e,t){e.sampleFrames=0,e.sampleStartedAt=t,e.intervalCount=0,e.intervalSumMs=0,e.minIntervalMs=Number.POSITIVE_INFINITY,e.maxIntervalMs=0,e.intervalSamplesMs.length=0,e.seqGapCount=0,e.maxSeqGap=0}function Ih(e,t,a){if(e.lastAt!==void 0){const r=Math.max(0,t-e.lastAt);e.intervalCount+=1,e.intervalSumMs+=r,e.minIntervalMs=Math.min(e.minIntervalMs,r),e.maxIntervalMs=Math.max(e.maxIntervalMs,r),fb(e.intervalSamplesMs,r)}if(e.lastFrameSeq!==void 0){const r=a-e.lastFrameSeq;r!==1&&(e.seqGapCount+=1,e.maxSeqGap=Math.max(e.maxSeqGap,Math.abs(r)))}e.lastAt=t,e.lastFrameSeq=a}function Th(e){return!e||e.intervalCount<=0?"waiting":`${Math.round(e.averageIntervalMs)}ms avg / p95 ${Math.round(e.p95IntervalMs)}ms / max ${Math.round(e.maxIntervalMs)}ms`}function Ph(e){return!e||e.seqGapCount<=0?"none":`${e.seqGapCount} gaps / max ${e.maxSeqGap}`}function Zk(e){return Number.isFinite(e)?String(e):"Unlimited"}const hb=[1,2,5,8,12,20,30],Eh={large:{maxWidth:1920,maxHeight:1080},medium:{maxWidth:1280,maxHeight:720},list:{maxWidth:960,maxHeight:540}},ur={visibleRootMargin:"520px 0px 760px 0px",fallbackVisibleCounts:{large:12,medium:18,list:32},maxWallBytesPerSecond:80*1024*1024,maxFrameGapMs:280,downshiftCooldownMs:1800,downshiftStableSampleMs:St.adaptiveDownshiftStableMs,downshiftConsecutiveSamples:St.adaptiveDownshiftConsecutiveSamples,recoveryCooldownMs:14e3,minFps:5},gd=2200,eM=2500,tM=8e3,nM=3500,Nh=7e3,rM=2,aM=2500,Fh=7e3,Dh=2600,oM=4200,iM=750,sM=2,cM=2,Lh=2500,Oh=4200,_h=2200;function jh(e,t){return Math.min(3e4,e*2**Math.min(3,Math.max(0,t)))}function yi(e,t){const a=e.capabilities?.[t];return typeof a=="boolean"?a:/^(1|true|yes|on)$/i.test(String(a||"").trim())}function Qt(e){return e.deviceName||e.hostname||e.deviceId}function lM(){return"npx -y --prefer-online livedesk@latest client"}function uM(){return"npx -y --prefer-online livedesk@latest"}function dM(){try{return localStorage.getItem(ib)||""}catch{return""}}function mM(){try{return localStorage.getItem($d)==="1"}catch{return!1}}function gi(e){try{e?localStorage.setItem($d,"1"):localStorage.removeItem($d)}catch{}}function dr(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function Ma(e){const t=dr(e.status),a=dr(t.screens),r=dr(e.capabilities),c=dr(e.latestLiveFrame),u=dr(e.activeLiveStream),h=[t.monitorCount,t.screenCount,a.count,r.monitorCount,r.screenCount,c.monitorCount,u.monitorCount,Array.isArray(a.displays)?a.displays.length:0,Array.isArray(t.displays)?t.displays.length:0,Array.isArray(t.monitors)?t.monitors.length:0].map(Number).filter(f=>Number.isFinite(f)&&f>0).map(f=>Math.max(1,Math.min(64,Math.floor(f))));return h.length>0?Math.max(...h):1}function Ta(e){const t=Number(e);return Number.isFinite(t)&&t>0?Math.floor(t):0}function gb(e){const t=dr(e.status),r=[dr(t.screens).displays,t.displays,t.monitors];for(const c of r)if(!(!Array.isArray(c)||c.length===0))return c.map(u=>dr(u));return[]}function nm(e,t){const a=gb(e),r=a.find(f=>Number(f.index)===t)||a[t]||a[0]||{},c=Ta(r.width),u=Ta(r.height),p=[r.name,r.displayName,r.deviceName,r.id].find(f=>typeof f=="string"&&f.trim()),h=typeof p=="string"?p.trim():`Display ${t+1}`;return{index:t,name:h,width:c,height:u,primary:r.primary===!0||r.isPrimary===!0}}function pM(e){const t=Ma(e);return Array.from({length:t},(a,r)=>nm(e,r))}function fM(e){const t=gb(e);if(t.length===0)return"";const a=t.map((r,c)=>{const u=Number(r.index),p=[r.name,r.displayName,r.deviceName,r.id].find(f=>typeof f=="string"&&f.trim()),h=f=>{const k=Number(f);return Number.isFinite(k)?k:null};return[Number.isFinite(u)?Math.floor(u):c,typeof p=="string"?p.trim().toLowerCase():"",h(r.left),h(r.top),h(r.width),h(r.height),r.primary===!0||r.isPrimary===!0]}).sort((r,c)=>r[0]-c[0]);return JSON.stringify(a)}function hM(e){const t=[e.name||`Display ${e.index+1}`];return e.width>0&&e.height>0&&t.push(`${e.width}x${e.height}`),e.primary&&t.push("Primary"),t.join(" - ")}function bb(e,t){const a=nm(e,t);if(a.width>0&&a.height>0)return{width:a.width,height:a.height};const r=dr(e.status),c=Ta(r.screenWidth||r.width),u=Ta(r.screenHeight||r.height);return c>0&&u>0?{width:c,height:u}:null}function vb(e){if(!e)return null;const t=Ta(e.sourceWidth)||Ta(e.width),a=Ta(e.sourceHeight)||Ta(e.height);return t>0&&a>0?{width:t,height:a}:null}function gM(e,t,a){const u=((typeof t?.monitorIndex=="number"?Ss(t.monitorIndex,Math.max(1,t.monitorCount||1)):a)===a?vb(t):null)||bb(e,a);return u?Math.max(.25,Math.min(4,u.width/u.height)):16/9}const hl=16/9;function Ss(e,t){const a=Math.max(1,Math.min(64,Math.floor(Number(t)||1))),r=Math.floor(Number(e));return Number.isFinite(r)?Math.max(0,Math.min(a-1,r)):0}function _n(e,t){return UC(t,Ma(e),e.platform)}function bM(){try{const e=localStorage.getItem(ub);if(!e)return{selections:{},topologyFingerprints:{}};const t=JSON.parse(e),a=t&&typeof t=="object"&&!Array.isArray(t)?t.selections:void 0;if(Number(t?.version)!==db||!a||typeof a!="object"||Array.isArray(a))return{selections:{},topologyFingerprints:{}};const r={},c={};for(const[u,p]of Object.entries(a)){const h=u.trim(),f=dr(p),k=f.monitorIndex,M=Math.floor(Number(k));if(!h||!Number.isFinite(M))continue;r[h]=Math.max(0,Math.min(63,M));const b=typeof f.topologyFingerprint=="string"?f.topologyFingerprint.trim():"";b&&(c[h]=b)}return{selections:r,topologyFingerprints:c}}catch{return{selections:{},topologyFingerprints:{}}}}function vM(e,t){try{const a=Object.fromEntries(Object.entries(e).map(([r,c])=>[r,{monitorIndex:c,topologyFingerprint:t[r]||""}]));localStorage.setItem(ub,JSON.stringify({version:db,selections:a}))}catch{}}function yM(){return{...Xk}}function wM(e){try{localStorage.setItem(yk,JSON.stringify({...e,version:wk}))}catch{}}function SM(){return{...Jk}}function CM(e){try{localStorage.setItem(Sk,JSON.stringify({...e,version:Ck}))}catch{}}function kM(){try{return localStorage.getItem(sb)==="slow"?"slow":"fast"}catch{return"fast"}}function MM(e){try{localStorage.setItem(sb,e)}catch{}}function xM(){try{return localStorage.getItem(lb)==="true"}catch{return!1}}function RM(e){try{localStorage.setItem(lb,String(e))}catch{}}function AM(){try{const e=localStorage.getItem(cb);return e===null?ta:xi(Number(e))}catch{return ta}}function IM(e){try{localStorage.setItem(cb,String(xi(e)))}catch{}}function bd(e,t){return e.length!==t.length?!1:e.every((a,r)=>a===t[r])}function vd(e){return[...new Set(e.filter(Boolean))].sort()}function TM(e){return ur.fallbackVisibleCounts[e]||ur.fallbackVisibleCounts.large}function Bh(e,t,a){if(e.frameMode==="mode4-h264-atlas")return e.atlasTileSizeMode==="auto"?t==="large"?{maxWidth:640,maxHeight:360}:{maxWidth:320,maxHeight:180}:{maxWidth:e.atlasTileWidth,maxHeight:e.atlasTileHeight};if(!e.adaptiveSizeByWall)return{maxWidth:e.maxWidth,maxHeight:e.maxHeight};const r=Eh[t]||Eh.large;return{maxWidth:Math.min(e.maxWidth,r.maxWidth),maxHeight:Math.min(e.maxHeight,r.maxHeight)}}function PM(e,t=ur.minFps){const a=[...hb].sort((c,u)=>c-u),r=Math.max(t,Math.floor(e/2));return[...a].reverse().find(c=>c<e&&c>=t)||r}function EM(e,t){return[...hb].sort((r,c)=>r-c).find(r=>r>e&&r<=t)||t}function Cs(e){if(!Number.isFinite(e)||e<=0)return"0 B";const t=["B","KB","MB","GB","TB"];let a=e,r=0;for(;a>=1024&&r<t.length-1;)a/=1024,r+=1;const c=r===0||a>=100?0:1;return`${a.toFixed(c)} ${t[r]}`}function Hh(e){if(!Number.isFinite(e)||!e||e<=0)return"0GB";const t=1024**4,a=1024**3;return e>=t?`${Math.max(1,Math.round(e/t))}TB`:`${Math.max(1,Math.round(e/a))}GB`}function yd(e,t){if(!Number.isFinite(e)||!e||e<=0)return"not reported";const a=Math.max(0,e-Math.max(0,Number(t||0)));return`${Hh(a)} / ${Hh(e)}`}function NM(e){const t=new Uint8Array(e),a=32768;let r="";for(let c=0;c<t.length;c+=a){const u=t.subarray(c,c+a);r+=String.fromCharCode(...u)}return btoa(r)}function Wh(e){return Array.from(e).filter(t=>t.size>=0).map(t=>{const a=t.webkitRelativePath||t.name;return{file:t,relativePath:a,fingerprint:`${t.size}:${t.lastModified}`}})}function ys(e){return e===1?"middle":e===2?"right":"left"}function $h(e,...t){for(const a of t){const r=e?.[a];if(typeof r=="string"&&r.trim())return r.trim()}return""}function Vh(e){const t=Number(e);return Number.isInteger(t)&&t>=1&&t<=vk?t:0}const FM={cpu:"CPU",memory:"MEM",disk:"Disk",gpu:"GPU",vram:"VRAM",npu:"NPU",temp:"Temp",network:"Net"};function DM(e,t,a){if(e==="online")return"Online";if(e==="busy")return"Busy";if(e==="stale")return"Stale";if(e==="offline")return"Offline";if(a==="failed")return"Task failed";const r=e==="critical"?"critical":"warn",c=t.find(p=>p.state===r)||t.find(p=>p.state==="critical"||p.state==="warn");if(!c)return e==="critical"?"Issue":"Check";const u=FM[c.id]||c.label;return c.value&&c.value!=="-"?`${u} ${c.value}`:u}function yb(e,t){const a=t.split(".");let r=e;for(const c of a){if(r==null)return;if(Array.isArray(r)){const u=Number(c);r=Number.isInteger(u)?r[u]:void 0;continue}if(typeof r=="object"){r=r[c];continue}return}return r}function Lt(e,...t){for(const a of t){const r=yb(e,a),c=Number(r);if(Number.isFinite(c))return c}}function Er(e,...t){for(const a of t){const r=yb(e,a);if(typeof r=="string"&&r.trim())return r.trim();if(typeof r=="number"&&Number.isFinite(r))return String(r)}return""}function ea(e){const t=Number(e);if(Number.isFinite(t))return Math.max(0,Math.min(1,t>1?t/100:t))}function wd(e,t){if(!(typeof e!="number"||typeof t!="number"||!Number.isFinite(e)||!Number.isFinite(t)||e<=0))return ea((e-Math.max(0,t))/e)}function bi(e){return e===void 0?"-":`${Math.round(e*100)}%`}function Sd(e){return e===void 0||!Number.isFinite(e)?"":e>=1e3?`${(e/1e3).toFixed(e>=1e4?0:1)}Gb/s`:`${Math.round(e)}Mb/s`}function vo(e,t=.92,a=.78){return e===void 0?"unknown":e>=t?"critical":e>=a?"warn":"good"}function LM(e){return!Number.isFinite(e)||!e||e<=0?"-":e<3600?`${Math.round(e/60)}m`:e<86400?`${Math.round(e/3600)}h`:`${Math.round(e/86400)}d`}function wb(e){const t=e.status||{},a=Lt(t,"cpu.cores","cpuCores","processorCount"),r=Lt(t,"loadavg.0","cpu.load1"),c=ea(Lt(t,"cpu.usedRatio","cpu.usageRatio","cpu.ratio","cpu.usedPct","cpu.usagePct","cpu.percent")??(a&&r!==void 0?r/Math.max(1,a):void 0)),u=Lt(t,"memory.totalBytes","totalMem"),p=Lt(t,"memory.freeBytes","freeMem"),h=ea(Lt(t,"memory.usedRatio","memory.usedPct","usedMemRatio"))??wd(u,p),f=Lt(t,"disk.totalBytes","rootDisk.totalBytes","storage.totalBytes"),k=Lt(t,"disk.freeBytes","rootDisk.freeBytes","storage.freeBytes"),M=ea(Lt(t,"disk.usedRatio","disk.usedPct","rootDisk.usedRatio","storage.usedRatio"))??wd(f,k),b=Lt(t,"thermal.cpuC","temperatureC","cpu.temperatureC","gpu.temperatureC"),T=ea(Lt(t,"gpu.usedRatio","gpu.usageRatio","gpu.usedPct","gpu.usagePct","gpu.percent","accelerators.gpu.usageRatio")),A=Er(t,"gpu.name","gpu.model","accelerators.gpu.name"),x=Lt(t,"gpu.memory.totalBytes","gpu.totalMemoryBytes","gpu.vramTotalBytes"),E=Lt(t,"gpu.memory.freeBytes","gpu.freeMemoryBytes","gpu.vramFreeBytes"),B=ea(Lt(t,"gpu.memory.usedRatio","gpu.vramUsedRatio"))??wd(x,E),q=Lt(t,"gpu.temperatureC","thermal.gpuC"),G=ea(Lt(t,"npu.usedRatio","npu.usageRatio","npu.usedPct","npu.usagePct","npu.percent","accelerators.npu.usageRatio")),ne=Er(t,"npu.name","npu.model","accelerators.npu.name"),re=Lt(t,"npu.tops","npu.topsInt8","accelerators.npu.tops"),O=Lt(t,"network.rxMbps","network.receiveMbps","network.downMbps"),ie=Lt(t,"network.txMbps","network.transmitMbps","network.upMbps"),J=Lt(t,"network.latencyMs","network.rttMs"),de=ea(Lt(t,"network.usedRatio","network.usageRatio","network.saturationRatio")),se=Er(t,"network.link","network.interface","network.name"),pe=Math.max(b??Number.NEGATIVE_INFINITY,q??Number.NEGATIVE_INFINITY),ce=Number.isFinite(pe)?pe:void 0,W=ce===void 0?void 0:ea((ce-35)/60),ee=b!==void 0&&q!==void 0?`CPU ${Math.round(b)}° · GPU ${Math.round(q)}°`:b!==void 0?`CPU ${Math.round(b)}°`:q!==void 0?`GPU ${Math.round(q)}°`:"-",L=Er(t,"workload.role","role","lane")||(yi(e,"taskDispatch")?"Command-ready Client":"Local machine"),_=Er(e.latestTask,"status")||Er(t,"workload.status")||"idle",K=Er(e.latestTask,"title","instructionPreview")||Er(t,"workload.title"),ue=Er(e.latestTask,"resultSummary","error","instructionPreview")||Er(t,"workload.summary"),P=Date.parse(e.lastSeenAt||e.connectedAt||""),N=Number.isFinite(P)?Date.now()-P:0;let te="online";e.connected?N>5*6e4?te="stale":(b??0)>=86||(q??0)>=88||(c??0)>=.94||(T??0)>=.96||(B??0)>=.96||(G??0)>=.96||(h??0)>=.94||(M??0)>=.94||(J??0)>=200||_==="failed"?te="critical":(b??0)>=78||(q??0)>=80||(c??0)>=.82||(T??0)>=.86||(B??0)>=.88||(G??0)>=.86||(h??0)>=.82||(M??0)>=.86||(J??0)>=80?te="warn":["queued","running","targeted"].includes(_)&&(te="busy"):te="offline";const we=[{id:"cpu",label:"CPU",value:bi(c),detail:a?`${a} cores`:r!==void 0?`load ${r.toFixed(1)}`:"not reported",ratio:c,state:vo(c,.92,.78)},{id:"memory",label:"RAM",value:bi(h),detail:yd(u,p),ratio:h,state:vo(h,.92,.78)},{id:"disk",label:"DISK",value:bi(M),detail:yd(f,k),ratio:M,state:vo(M,.92,.82)},{id:"gpu",label:"GPU",value:bi(T),detail:A||(x&&E!==void 0?`${Cs(E)} VRAM free`:q!==void 0?`${Math.round(q)}C`:"not reported"),ratio:T,state:q!==void 0&&q>=88?"critical":q!==void 0&&q>=80?"warn":vo(T,.96,.86)},{id:"vram",label:"VRAM",value:bi(B),detail:yd(x,E),ratio:B,state:vo(B,.96,.88)},{id:"npu",label:"NPU",value:G!==void 0?bi(G):re!==void 0?`${Math.round(re)} TOPS`:"-",detail:ne||(re!==void 0?"neural engine":"not reported"),ratio:G,state:vo(G,.96,.86)},{id:"temp",label:"TEMP",value:ee,detail:`uptime ${LM(Lt(t,"uptimeSec"))}`,ratio:W,state:ce===void 0?"unknown":ce>=86?"critical":ce>=78?"warn":"good"},{id:"network",label:"NET",value:Sd(O)||(J!==void 0?`${Math.round(J)}ms`:se||"-"),detail:Sd(ie)?`${Sd(ie)} up`:se||"not reported",ratio:de,state:J!==void 0&&J>=200?"critical":J!==void 0&&J>=80?"warn":vo(de,.9,.75)}];return{state:te,label:DM(te,we,_),role:L,taskLabel:K||(_==="idle"?"idle":_),taskStatus:_,taskSummary:ue,metrics:we}}const zh=[{id:"slow",label:"Slow",fps:Rs("slow")},{id:"fast",label:"Fast",fps:Rs("fast")}],OM=[{id:"list",label:"List"},{id:"medium",label:"Small"},{id:"large",label:"Large"}],_M=[{id:"list",label:"List"},{id:"large",label:"Wall"}],Uh=[{id:"sync-server",label:"Hub",icon:Ci,accent:"blue",tooltip:"hub"},{id:"wall",label:"Wall",icon:Zh,accent:"blue",tooltip:"wall"},{id:"control",label:"Control",icon:Ms,accent:"red",tooltip:"control"},{id:"share-files",label:"Share Files",icon:eg,accent:"green",tooltip:"share-files"},{id:"agents",label:"Agents",icon:vl,accent:"violet",tooltip:"agents"}],qh=[{id:"doc",label:"Doc",icon:kd,accent:"amber"},{id:"support",label:"Support",icon:yy,accent:"violet"},{id:"pricing",label:"Pricing",icon:Ra,accent:"green"}];function jM(e){return e.replaceAll("npx -y @livedesk/client","npx -y --prefer-online livedesk@latest client").replaceAll("npx @livedesk/client","npx -y --prefer-online livedesk@latest client").replaceAll("npx -y livedesk client","npx -y --prefer-online livedesk@latest client").replaceAll("npx livedesk client","npx -y --prefer-online livedesk@latest client").replaceAll("npx -y livedesk","npx -y --prefer-online livedesk@latest").replaceAll("npx livedesk","npx -y --prefer-online livedesk@latest")}function Ft(e){return jM(e).replaceAll("Sync Server","Hub").replace(/\bRemoteHub\b/g,"Hub client endpoint").replace(/\bManagers\b/g,"Hubs").replace(/\bManager\b/g,"Hub").replace(/\bmanager\b/g,"Hub").replace(/\bMANAGER\b/g,"HUB").replace(/매니저/g,"Hub")}function yo(e){return e.map(t=>Ft(t))}function pn(e){return{languageName:e.languageName,languageLabel:e.languageLabel,eyebrow:e.eyebrow,title:Ft(e.title),intro:Ft(e.intro),sections:[{title:Ft(e.managerTitle),body:Ft(e.managerBody),points:yo(e.managerPoints)},{title:Ft(e.clientTitle),body:Ft(e.clientBody),points:yo(e.clientPoints)},{title:Ft(e.syncTitle),body:Ft(e.syncBody),points:yo(e.syncPoints)},...e.agentTitle&&e.agentBody&&e.agentPoints?[{title:Ft(e.agentTitle),body:Ft(e.agentBody),points:yo(e.agentPoints)}]:[],{title:Ft(e.platformTitle),body:Ft(e.platformBody),points:yo(e.platformPoints)}],sync:{title:Ft(e.syncTitle),body:Ft(e.syncBody),points:yo(e.syncPoints)},firewall:{title:Ft(e.firewallTitle),body:Ft(e.firewallBody),points:yo(e.firewallPoints)},commands:{title:Ft(e.commandsTitle),body:Ft(e.commandsBody),manager:Ft(e.managerCommandLabel),primary:Ft(e.clientCommandLabel),slot:Ft(e.slotCommandLabel),manual:Ft(e.manualCommandLabel)}}}const ki={ko:pn({languageName:"한국어",languageLabel:"문서 언어",eyebrow:"VuvoDesk Manual",title:"한 줄로 여는 로컬 Screen Wall",intro:"VuvoDesk는 매니저 PC 한 대에서 여러 작업 PC, 미니 PC, 맥미니, 개발 장비를 한 화면에 모니터링하고 필요한 제어를 실행하는 npm-first 원격 작업 데크입니다.",managerTitle:"1. 매니저 실행",managerBody:"화면을 모아 볼 컴퓨터에서 VuvoDesk 매니저를 실행합니다. 매니저는 UI와 로컬 서버를 같이 열고 브라우저를 http://127.0.0.1:5179 로 띄웁니다.",managerPoints:["명령은 npx -y livedesk 입니다.","매니저는 Screen Wall/API 포트 5179와 클라이언트 접속 포트 5197을 사용합니다.","기존 VuvoDesk 포트가 남아 있으면 기본적으로 정리하고 새로 시작합니다. 필요하면 --no-clean 을 붙입니다."],clientTitle:"2. 워크스테이션 연결",clientBody:"모니터링할 PC에서는 Google 로그인 또는 Hub 화면의 6자리 PIN으로 연결합니다. Hub가 꺼져 있으면 실시간 온라인 알림을 기다리고 적응형 간격으로 다시 확인합니다.",clientPoints:["빈 자리에 자동 배치하려면 npx -y livedesk client 를 실행합니다.","자리 번호를 고정하려면 npx -y livedesk client 3 처럼 번호를 붙입니다.","브라우저 연결 페이지에서 Google 버튼 또는 6자리 PIN 입력 중 하나를 선택합니다."],syncTitle:"3. Sync Server와 자동 발견",syncBody:"Sync Server는 이 매니저를 현재 계정의 활성 Screen Wall로 Supabase에 등록합니다. 클라이언트는 같은 Google 계정으로 로그인한 뒤 그 기록을 읽고 접속 후보들을 순서대로 시도합니다.",syncPoints:["등록 정보에는 host instance, LAN/private 주소, public 후보 주소, pair token, 짧은 lease가 포함됩니다.","같은 LAN 후보를 먼저 쓰고, 필요하면 외부 주소 후보를 시도합니다.","매니저 위치, VPN, 방화벽, 공유기 설정이 바뀌었거나 개발 중 활성 매니저를 바꿀 때 Sync Server를 누릅니다.","이제 vuvodesk.com의 Chrome Local Network Access 허용은 기본 실행 경로가 아닙니다. npm 매니저 앱이 실제 서버입니다."],agentTitle:"4. Agent로 여러 장비 작업하기",agentBody:"Agents 화면은 Hub에서 실행되는 Codex 기반 Agent가 연결된 장비를 확인하고, 선택한 권한 범위 안에서 작업을 실행하는 공간입니다. 클라이언트 PC에 Codex 앱이나 Codex SDK를 설치할 필요는 없습니다.",agentPoints:["Suggested tasks에는 일반적인 읽기·운영 명령 템플릿이 있으며, 검색과 권한·플랫폼·capability 조건으로 실행 가능 항목을 안내합니다.","Ask, Safe Auto, Full Access, Custom 권한 모드를 선택할 수 있습니다. 위험한 변경 작업은 승인 카드와 장비 capability 검사를 거칩니다.","All connected 또는 Selected로 대상 장비를 제한하고, 결과는 장비별 상태 칩과 실제 RAM·디스크·GPU·프로세스 요약으로 확인합니다.","Hub의 Codex Agent는 지시를 승인된 VuvoDesk 도구로 변환하고 컴퓨터별 실행 상태와 결과를 표시합니다."],platformTitle:"5. 현재 플랫폼과 스트림 상태",platformBody:"Windows의 Wall, Control, 파일 전송, 원격 오디오와 RemoteFast 경로를 현재 기준으로 확인했습니다. macOS와 Linux는 같은 npm 명령 경로를 유지하면서 권한과 캡처 백엔드를 확장하고 있습니다.",platformPoints:["자동 Wall과 Control은 모든 Client에서 직접 H.264를 사용합니다. RGB565/LZO Atlas는 내부 진단 실험에만 남고 자동 전송 경로에는 사용되지 않습니다.","원격 오디오는 선택한 장비가 capability를 광고할 때 사용할 수 있으며, 브라우저는 queue·drop·resync·automatic restart 상태를 진단합니다.","macOS: 화면 캡처와 제어에는 Screen Recording/Accessibility 권한이 필요합니다. RemoteFast 로그는 필요한 상태 중심으로 제한됩니다.","Linux: linux-x64 runtime, X11/XTEST 입력과 PipeWire/PulseAudio 기본 출력 오디오 캡처를 지원합니다."],firewallTitle:"방화벽과 외부 장소 연결",firewallBody:"VuvoDesk는 인증된 Direct TCP와 암호화된 UDP/WebRTC P2P로 화면과 제어를 직접 연결합니다. rendezvous 서비스는 상대 찾기와 P2P 연결 정보 교환만 하며 화면·입력 데이터는 중계하지 않습니다.",firewallPoints:["LAN Direct TCP의 기본 클라이언트 포트는 5197입니다.","클라이언트와 매니저는 상대 찾기와 P2P signaling을 위해 설정된 rendezvous 서버로 나가는 연결이 가능해야 합니다.","영상과 입력 데이터는 Direct TCP 또는 암호화된 UDP/WebRTC P2P로 장치끼리 직접 전송합니다.","외부망 Direct TCP에는 TCP 5197 포트포워딩이나 VPN/IP allowlist를 설정합니다. P2P가 막히면 VuvoDesk가 직접 연결을 다시 시도합니다.","Screen Wall/API 포트 5179는 외부 브라우저가 Wall을 직접 열 때만 노출합니다."],commandsTitle:"현재 사용 명령",commandsBody:"웹사이트를 찾아가 설치 파일을 받는 방식보다 터미널 한 줄로 모든 운영체제에서 거의 같은 흐름을 쓰는 것이 VuvoDesk의 기본 방향입니다.",managerCommandLabel:"매니저 시작",clientCommandLabel:"워크스테이션 연결",slotCommandLabel:"3번 슬롯에 고정",manualCommandLabel:"고급 수동 연결"}),en:pn({languageName:"English",languageLabel:"Document language",eyebrow:"VuvoDesk Manual",title:"Open a local Screen Wall with one command",intro:"VuvoDesk is an npm-first remote work deck for monitoring Clients, mini PCs, Mac minis, and development machines from one manager PC.",managerTitle:"1. Run the manager",managerBody:"Run VuvoDesk on the computer that will watch the screens. The manager starts the UI and local server together, then opens http://127.0.0.1:5179.",managerPoints:["The command is npx -y livedesk.","The manager uses port 5179 for the Screen Wall/API and port 5197 for client connections.","If an old VuvoDesk process still owns those ports, startup cleans it by default. Add --no-clean when you want to keep it."],clientTitle:"2. Connect a Client",clientBody:"On each monitored computer, connect with Google sign-in or the 6-digit PIN shown on the Hub screen. If no manager is online yet, the client waits for a live online signal and falls back to adaptive retries.",clientPoints:["Run npx -y livedesk client for first available placement.","Run npx -y livedesk client 3 to pin the machine to slot 3.","The browser connection page lets you choose Google or a 6-digit PIN."],syncTitle:"3. Sync Server and discovery",syncBody:"Sync Server publishes this manager as the active Screen Wall for the signed-in account. Clients read that Supabase record after Google sign-in and try the endpoint candidates in order.",syncPoints:["The record includes host instance, LAN/private addresses, public endpoint candidates, pair token, and a short lease.","LAN candidates are preferred first, then public candidates if needed.","Press Sync Server after manager moves, VPN/firewall/router changes, or when this development machine should take over as active manager.","Chrome Local Network Access on vuvodesk.com is no longer the default runtime path. The npm manager app is the real server."],agentTitle:"4. Run multi-Client tasks with Agent",agentBody:"The Agents page runs a Codex-based Agent in the Hub to inspect connected Clients and perform actions within the selected permission scope. Client PCs do not need the Codex app or Codex SDK installed.",agentPoints:["Suggested tasks provide generic read-only and operational command templates with search plus permission, platform, and capability checks.","Choose Ask, Safe Auto, Full Access, or Custom. Risky changes go through approval cards and explicit Client capability checks.","Limit targets with All connected or Selected. Results use compact per-device status chips and show real RAM, disk, GPU, and process summaries.","The Hub-hosted Codex Agent turns instructions into approved VuvoDesk tool calls and shows progress and results for each computer."],platformTitle:"5. Current platform and stream state",platformBody:"Windows Wall, Control, file transfer, remote audio, and the RemoteFast path are verified against the current implementation. macOS and Linux keep the same npm command path while capture and permission backends expand.",platformPoints:["Automatic Wall and Control use direct H.264 for every Client. The RGB565/LZO Atlas remains only for internal diagnostic experiments and is never selected automatically.","Remote audio is available when the selected Client advertises the capability, with queue, drop, resync, and automatic-restart diagnostics in the browser.","macOS requires Screen Recording and Accessibility permissions for capture and control. RemoteFast logs focus on actionable state.","Linux includes the linux-x64 runtime, X11/XTEST input, and default-output audio capture through PipeWire or PulseAudio."],firewallTitle:"Firewall and remote locations",firewallBody:"VuvoDesk connects screen and control payloads directly through authenticated Direct TCP and encrypted UDP/WebRTC P2P. The rendezvous service only finds peers and exchanges P2P connection details; it never carries screen or input payloads.",firewallPoints:["The default LAN Direct TCP client port is 5197.","Clients and the manager need outbound access to the configured rendezvous server for peer discovery and P2P signaling.","Screen and input payloads travel device-to-device through Direct TCP or encrypted UDP/WebRTC P2P.","For Direct TCP across networks, forward TCP 5197 or configure VPN/IP allowlists. When P2P is blocked, VuvoDesk keeps retrying a direct connection.","Expose Screen Wall/API port 5179 only when a remote browser must open the Wall directly."],commandsTitle:"Current commands",commandsBody:"The product direction is one terminal command across operating systems instead of finding a website, downloading, and installing manually.",managerCommandLabel:"Start manager",clientCommandLabel:"Connect Client",slotCommandLabel:"Pin to slot 3",manualCommandLabel:"Advanced manual connection"}),ja:pn({languageName:"日本語",languageLabel:"ドキュメント言語",eyebrow:"VuvoDesk Manual",title:"1行でローカル Screen Wall を開く",intro:"VuvoDesk は、複数の作業 PC、mini PC、Mac mini、開発機を1台の manager PC から監視する npm-first のリモート作業デッキです。",managerTitle:"1. manager を実行",managerBody:"画面を集めて見るコンピューターで VuvoDesk manager を実行します。UI とローカルサーバーが同時に起動し、http://127.0.0.1:5179 が開きます。",managerPoints:["コマンドは npx -y livedesk です。","Screen Wall/API は 5179、client 接続は 5197 を使います。","古い VuvoDesk プロセスがポートを使っている場合は、基本的に自動で整理して起動します。"],clientTitle:"2. Client を接続",clientBody:"監視される PC で同じ Google アカウントにログインします。manager がまだ無い場合、client はオンライン通知を待ち、適応型の間隔で再確認します。",clientPoints:["空きスロットに入れるには npx -y livedesk client を実行します。","スロットを固定するには npx -y livedesk client 3 のように番号を付けます。","大量の PC でも再ログインなしで待ち続けます。"],syncTitle:"3. Sync Server と自動検出",syncBody:"Sync Server はこの manager を現在の Google アカウントの active Screen Wall として Supabase に登録します。",syncPoints:["host instance、LAN/private アドレス、public 候補、pair token、短い lease を登録します。","client は LAN 候補を優先し、必要なら public 候補も試します。","VPN、firewall、router、manager の場所が変わったら Sync Server を押します。","vuvodesk.com の Chrome Local Network Access は標準実行経路ではありません。npm manager アプリが実際のサーバーです。"],platformTitle:"4. 現在のプラットフォーム状態",platformBody:"Windows は live screen transfer まで確認済みです。macOS と Linux も同じ npm コマンド経路を目標に対応を広げています。",platformPoints:["Windows: 動作確認済み。","macOS: 画面取得と制御には Screen Recording/Accessibility 権限が必要です。","Linux: linux-x64 runtime、grim/gnome-screenshot/import/scrot capture、X11/XTEST input backend を追加済み。audio は未対応です。"],firewallTitle:"Firewall と外部拠点",firewallBody:"VuvoDesk は認証済み Direct TCP と暗号化 UDP/WebRTC P2P で画面と操作を直接接続します。rendezvous サービスは相手の発見と P2P 接続情報の交換だけを行い、画面や入力データを中継しません。",firewallPoints:["LAN の Direct TCP client 既定ポートは 5197 です。","client と manager は相手の発見と P2P signaling のため、設定済み rendezvous server へ outbound 接続できる必要があります。","画面と入力データは Direct TCP または暗号化 UDP/WebRTC P2P で端末間を直接移動します。","ネットワーク越しの Direct TCP には TCP 5197 の転送または VPN/IP allowlist を設定します。P2P が遮断された場合は直接接続を再試行します。","5179 は外部ブラウザが Wall を直接開く場合だけ公開します。"],commandsTitle:"現在のコマンド",commandsBody:"Web サイトから installer を探すより、OS をまたいで terminal 1行で動かす方向です。",managerCommandLabel:"manager 起動",clientCommandLabel:"Client 接続",slotCommandLabel:"slot 3 に固定",manualCommandLabel:"高度な手動接続"}),"zh-CN":pn({languageName:"简体中文",languageLabel:"文档语言",eyebrow:"VuvoDesk Manual",title:"用一条命令打开本地 Screen Wall",intro:"VuvoDesk 是 npm-first 的远程工作台,用一台 manager PC 监控多台工作电脑、迷你主机、Mac mini 和开发机器。",managerTitle:"1. 运行 manager",managerBody:"在负责查看屏幕的电脑上运行 VuvoDesk manager。它会同时启动 UI 和本地服务器,并打开 http://127.0.0.1:5179。",managerPoints:["命令是 npx -y livedesk。","Screen Wall/API 使用 5179,client 连接使用 5197。","如果旧的 VuvoDesk 进程占用端口,默认会清理后重新启动。"],clientTitle:"2. 连接 Client",clientBody:"在被监控的电脑上使用同一个 Google 账号登录。如果 manager 尚未在线,client 会等待上线通知,并以自适应间隔重新检查。",clientPoints:["自动放入空位: npx -y livedesk client。","固定到 3 号位置: npx -y livedesk client 3。","大量电脑也可以持续等待,不需要反复登录。"],syncTitle:"3. Sync Server 和自动发现",syncBody:"Sync Server 会把当前 manager 作为该账号的 active Screen Wall 写入 Supabase。client 登录后读取记录并依次尝试连接候选地址。",syncPoints:["记录包括 host instance、LAN/private 地址、public 候选、pair token 和短 lease。","优先尝试同一 LAN 地址,需要时再尝试外部地址。","manager 位置、VPN、防火墙或路由变化后请点击 Sync Server。","vuvodesk.com 的 Chrome Local Network Access 不再是默认运行方式。npm manager app 才是真正服务器。"],platformTitle:"4. 当前平台状态",platformBody:"Windows 已确认可传输实时画面。macOS 和 Linux 正按同一 npm 命令路径扩展支持。",platformPoints:["Windows: 已确认可用。","macOS: 画面捕获和控制需要 Screen Recording/Accessibility 权限。","Linux: 已加入 linux-x64 runtime、grim/gnome-screenshot/import/scrot 捕获、X11/XTEST 输入后端。音频尚未启用。"],firewallTitle:"防火墙和外部地点",firewallBody:"VuvoDesk 通过经过认证的 Direct TCP 和加密 UDP/WebRTC P2P 直接传送画面与控制。rendezvous 服务只负责发现对端和交换 P2P 连接信息,不会转发画面或输入数据。",firewallPoints:["LAN Direct TCP 的默认 client 端口是 5197。","client 和 manager 必须能向已配置的 rendezvous server 建立出站连接,用于发现对端和 P2P signaling。","画面和输入数据通过 Direct TCP 或加密 UDP/WebRTC P2P 在设备之间直接传送。","跨网络使用 Direct TCP 时请转发 TCP 5197 或配置 VPN/IP 白名单。P2P 被阻断时会继续重试直连。","只有远程浏览器需要直接打开 Wall 时才暴露 5179。"],commandsTitle:"当前命令",commandsBody:"产品方向是跨操作系统使用一条终端命令,而不是先找网站、下载、安装。",managerCommandLabel:"启动 manager",clientCommandLabel:"连接 Client",slotCommandLabel:"固定到 slot 3",manualCommandLabel:"高级手动连接"}),"zh-TW":pn({languageName:"繁體中文",languageLabel:"文件語言",eyebrow:"VuvoDesk Manual",title:"用一行指令開啟本機 Screen Wall",intro:"VuvoDesk 是 npm-first 的遠端工作台,用一台 manager PC 監看多台工作電腦、迷你主機、Mac mini 與開發機。",managerTitle:"1. 執行 manager",managerBody:"在負責看畫面的電腦上執行 VuvoDesk manager。它會同時啟動 UI 與本機伺服器,並開啟 http://127.0.0.1:5179。",managerPoints:["指令是 npx -y livedesk。","Screen Wall/API 使用 5179,client 連線使用 5197。","若舊的 VuvoDesk 程序占用連接埠,預設會清理後重新啟動。"],clientTitle:"2. 連接 Client",clientBody:"在被監看的電腦上使用同一個 Google 帳號登入。如果 manager 尚未上線,client 會等待上線通知,並以自適應間隔重新檢查。",clientPoints:["自動放入空位: npx -y livedesk client。","固定到 3 號位置: npx -y livedesk client 3。","大量電腦也能持續等待,不需要反覆登入。"],syncTitle:"3. Sync Server 與自動探索",syncBody:"Sync Server 會把目前 manager 登錄為此帳號的 active Screen Wall。client 登入後讀取 Supabase 記錄並依序嘗試連線候選地址。",syncPoints:["記錄包含 host instance、LAN/private 位址、public 候選、pair token 與短 lease。","優先嘗試 LAN 位址,需要時再嘗試外部位址。","manager 位置、VPN、防火牆或路由設定改變後請按 Sync Server。","vuvodesk.com 的 Chrome Local Network Access 不再是預設執行路徑。npm manager app 才是真正伺服器。"],platformTitle:"4. 目前平台狀態",platformBody:"Windows 已確認可傳輸即時畫面。macOS 與 Linux 也沿用相同 npm 指令路徑擴充支援。",platformPoints:["Windows: 已確認可用。","macOS: 畫面擷取與控制需要 Screen Recording/Accessibility 權限。","Linux: 已加入 linux-x64 runtime、grim/gnome-screenshot/import/scrot capture、X11/XTEST input backend。音訊尚未啟用。"],firewallTitle:"防火牆與外部地點",firewallBody:"VuvoDesk 透過已驗證的 Direct TCP 與加密 UDP/WebRTC P2P 直接傳送畫面和控制。rendezvous 服務只負責尋找對端與交換 P2P 連線資訊,不會轉送畫面或輸入資料。",firewallPoints:["LAN Direct TCP 的預設 client 連接埠是 5197。","client 與 manager 必須能向已設定的 rendezvous server 建立外送連線,以尋找對端並進行 P2P signaling。","畫面與輸入資料透過 Direct TCP 或加密 UDP/WebRTC P2P 在裝置間直接傳送。","跨網路使用 Direct TCP 時請轉送 TCP 5197 或設定 VPN/IP allowlist。P2P 受阻時會持續重試直連。","只有遠端瀏覽器需要直接開啟 Wall 時才公開 5179。"],commandsTitle:"目前指令",commandsBody:"產品方向是跨作業系統用一行 terminal 指令,而不是先找網站、下載、安裝。",managerCommandLabel:"啟動 manager",clientCommandLabel:"連接 Client",slotCommandLabel:"固定到 slot 3",manualCommandLabel:"進階手動連線"}),es:pn({languageName:"Español",languageLabel:"Idioma del documento",eyebrow:"VuvoDesk Manual",title:"Abre un Screen Wall local con un comando",intro:"VuvoDesk es una consola npm-first para vigilar equipos de trabajo, mini PC, Mac mini y equipos de desarrollo desde un PC manager.",managerTitle:"1. Ejecuta el manager",managerBody:"Ejecuta VuvoDesk en el equipo que verá las pantallas. El manager inicia la UI y el servidor local juntos y abre http://127.0.0.1:5179.",managerPoints:["El comando es npx -y livedesk.","El manager usa 5179 para Screen Wall/API y 5197 para conexiones client.","Si un proceso antiguo ocupa los puertos, el arranque lo limpia por defecto."],clientTitle:"2. Conecta una Client",clientBody:"En cada equipo monitoreado, inicia sesión con la misma cuenta Google. Si el manager aún no está activo, el client espera una señal en tiempo real y vuelve a comprobar con intervalos adaptativos.",clientPoints:["Usa npx -y livedesk client para el primer slot libre.","Usa npx -y livedesk client 3 para fijar el equipo al slot 3.","Los clients siguen esperando para no repetir login en muchas máquinas."],syncTitle:"3. Sync Server y descubrimiento",syncBody:"Sync Server publica este manager como Screen Wall activo para la cuenta. Los clients leen el registro en Supabase y prueban los endpoints.",syncPoints:["Incluye host instance, direcciones LAN/private, candidatos public, pair token y lease corto.","Primero se prueban candidatos LAN, luego públicos si hace falta.","Pulsa Sync Server después de cambios de manager, VPN, firewall o router.","Chrome Local Network Access en vuvodesk.com ya no es el flujo principal. La app npm manager es el servidor real."],platformTitle:"4. Estado de plataformas",platformBody:"Windows ya fue verificado con transferencia de pantalla. macOS y Linux siguen el mismo camino npm.",platformPoints:["Windows: verificado.","macOS: captura y control requieren permisos Screen Recording/Accessibility.","Linux: runtime linux-x64, entrada X11/XTEST y audio de salida mediante PipeWire o PulseAudio."],firewallTitle:"Firewall y sedes remotas",firewallBody:"VuvoDesk conecta pantalla y control directamente mediante Direct TCP autenticado y UDP/WebRTC P2P cifrado. El servicio rendezvous solo localiza pares e intercambia datos de conexión P2P; no reenvía pantallas ni entradas.",firewallPoints:["El puerto client predeterminado para Direct TCP en LAN es 5197.","Clients y manager necesitan acceso saliente al servidor rendezvous configurado para descubrir pares y hacer signaling P2P.","Pantalla e input viajan entre dispositivos por Direct TCP o UDP/WebRTC P2P cifrado.","Para Direct TCP entre redes, reenvía TCP 5197 o configura VPN/allowlist de IP. Si P2P está bloqueado, VuvoDesk sigue intentando una conexión directa.","Expón 5179 solo si un navegador remoto debe abrir el Wall directamente."],commandsTitle:"Comandos actuales",commandsBody:"La dirección del producto es un comando de terminal común entre sistemas, no descargar e instalar desde una web.",managerCommandLabel:"Iniciar manager",clientCommandLabel:"Conectar Client",slotCommandLabel:"Fijar al slot 3",manualCommandLabel:"Conexión manual avanzada"}),fr:pn({languageName:"Français",languageLabel:"Langue du document",eyebrow:"VuvoDesk Manual",title:"Ouvrir un Screen Wall local en une commande",intro:"VuvoDesk est un deck npm-first pour surveiller plusieurs postes, mini PC, Mac mini et machines dev depuis un PC manager.",managerTitle:"1. Lancer le manager",managerBody:"Lancez VuvoDesk sur l’ordinateur qui observe les écrans. Le manager démarre l’UI et le serveur local, puis ouvre http://127.0.0.1:5179.",managerPoints:["La commande est npx -y livedesk.","Le manager utilise 5179 pour Screen Wall/API et 5197 pour les connexions client.","Si un ancien processus utilise les ports, le démarrage le nettoie par défaut."],clientTitle:"2. Connecter une Client",clientBody:"Sur chaque ordinateur surveillé, connectez-vous avec le même compte Google. Si le manager n’est pas encore actif, le client réessaie toutes les 5 secondes.",clientPoints:["Utilisez npx -y livedesk client pour le premier slot libre.","Utilisez npx -y livedesk client 3 pour fixer la machine au slot 3.","Les clients continuent d’attendre pour éviter les reconnexions répétées."],syncTitle:"3. Sync Server et découverte",syncBody:"Sync Server publie ce manager comme Screen Wall actif du compte. Les clients lisent l’enregistrement Supabase et testent les endpoints.",syncPoints:["Il contient host instance, adresses LAN/private, candidats public, pair token et lease court.","Les candidats LAN sont essayés en premier, puis les candidats publics si besoin.","Cliquez Sync Server après un changement de manager, VPN, firewall ou routeur.","Chrome Local Network Access sur vuvodesk.com n’est plus le chemin par défaut. L’app npm manager est le vrai serveur."],platformTitle:"4. État des plateformes",platformBody:"Windows est vérifié avec transfert d’écran live. macOS et Linux suivent le même chemin npm.",platformPoints:["Windows: vérifié.","macOS: capture et contrôle nécessitent Screen Recording/Accessibility.","Linux: runtime linux-x64, entrée X11/XTEST et audio de sortie via PipeWire ou PulseAudio."],firewallTitle:"Firewall et sites distants",firewallBody:"VuvoDesk relie directement l’écran et le contrôle par Direct TCP authentifié et UDP/WebRTC P2P chiffré. Le service rendezvous sert uniquement à trouver les pairs et à échanger les informations P2P ; il ne transmet ni écran ni saisie.",firewallPoints:["Le port client Direct TCP par défaut sur le LAN est 5197.","Clients et manager doivent accéder au serveur rendezvous configuré pour la découverte et le signaling P2P.","Écran et saisie passent directement entre appareils par Direct TCP ou UDP/WebRTC P2P chiffré.","Pour Direct TCP entre réseaux, redirigez TCP 5197 ou configurez VPN/allowlist IP. Si le P2P est bloqué, VuvoDesk retente une connexion directe.","Exposez 5179 uniquement si un navigateur distant doit ouvrir directement le Wall."],commandsTitle:"Commandes actuelles",commandsBody:"La direction produit est une commande terminal commune aux OS, plutôt qu’un téléchargement manuel depuis un site.",managerCommandLabel:"Démarrer manager",clientCommandLabel:"Connecter Client",slotCommandLabel:"Fixer au slot 3",manualCommandLabel:"Connexion manuelle avancée"}),de:pn({languageName:"Deutsch",languageLabel:"Dokumentsprache",eyebrow:"VuvoDesk Manual",title:"Lokale Screen Wall mit einem Befehl öffnen",intro:"VuvoDesk ist ein npm-first Arbeitsdeck, um viele Clients, Mini-PCs, Mac minis und Dev-Rechner von einem Manager-PC zu überwachen.",managerTitle:"1. Manager starten",managerBody:"Starte VuvoDesk auf dem Computer, der die Screens sieht. Der Manager startet UI und lokalen Server zusammen und öffnet http://127.0.0.1:5179.",managerPoints:["Der Befehl ist npx -y livedesk.","Der Manager nutzt 5179 für Screen Wall/API und 5197 für Client-Verbindungen.","Wenn alte VuvoDesk-Prozesse Ports belegen, werden sie beim Start standardmäßig bereinigt."],clientTitle:"2. Client verbinden",clientBody:"Melde dich auf jedem überwachten Computer mit demselben Google-Konto an. Wenn kein Manager online ist, wartet der Client auf ein Live-Signal und prüft mit adaptiven Intervallen erneut.",clientPoints:["npx -y livedesk client nutzt den ersten freien Slot.","npx -y livedesk client 3 fixiert den Rechner auf Slot 3.","Clients warten weiter, damit große Setups kein wiederholtes Login brauchen."],syncTitle:"3. Sync Server und Discovery",syncBody:"Sync Server veröffentlicht diesen Manager als aktive Screen Wall des Kontos. Clients lesen den Supabase-Eintrag und testen Endpoints der Reihe nach.",syncPoints:["Enthält host instance, LAN/private Adressen, public Kandidaten, pair token und kurze lease.","LAN-Kandidaten werden zuerst versucht, danach public Kandidaten.","Nach Änderungen an Manager, VPN, Firewall oder Router Sync Server drücken.","Chrome Local Network Access auf vuvodesk.com ist nicht mehr der Standardpfad. Die npm Manager App ist der echte Server."],platformTitle:"4. Plattformstatus",platformBody:"Windows wurde mit Live-Screen-Transfer geprüft. macOS und Linux folgen demselben npm-Pfad.",platformPoints:["Windows: verifiziert.","macOS: Capture und Control brauchen Screen Recording/Accessibility Rechte.","Linux: linux-x64 Runtime, X11/XTEST Eingabe und Ausgangsaudio über PipeWire oder PulseAudio."],firewallTitle:"Firewall und entfernte Standorte",firewallBody:"VuvoDesk verbindet Bildschirm und Steuerung direkt über authentifiziertes Direct TCP und verschlüsseltes UDP/WebRTC P2P. Der Rendezvous-Dienst findet nur Peers und tauscht P2P-Verbindungsdaten aus; Bildschirm- und Eingabedaten werden nicht weitergeleitet.",firewallPoints:["Der Standardport für LAN Direct TCP Clients ist 5197.","Clients und Manager benötigen ausgehenden Zugriff auf den konfigurierten Rendezvous-Server für Peer-Erkennung und P2P-Signaling.","Bildschirm- und Eingabedaten laufen direkt zwischen Geräten über Direct TCP oder verschlüsseltes UDP/WebRTC P2P.","Für Direct TCP zwischen Netzwerken TCP 5197 weiterleiten oder VPN/IP-Allowlist einrichten. Wenn P2P blockiert ist, versucht VuvoDesk die direkte Verbindung erneut.","5179 nur öffnen, wenn ein Remote-Browser die Wall direkt laden muss."],commandsTitle:"Aktuelle Befehle",commandsBody:"Die Produktlinie ist ein Terminalbefehl über Betriebssysteme hinweg, statt Website suchen, herunterladen und installieren.",managerCommandLabel:"Manager starten",clientCommandLabel:"Client verbinden",slotCommandLabel:"An Slot 3 fixieren",manualCommandLabel:"Erweiterte manuelle Verbindung"}),"pt-BR":pn({languageName:"Português",languageLabel:"Idioma do documento",eyebrow:"VuvoDesk Manual",title:"Abra um Screen Wall local com um comando",intro:"VuvoDesk é um deck npm-first para monitorar várias estações, mini PCs, Mac minis e máquinas dev a partir de um PC manager.",managerTitle:"1. Execute o manager",managerBody:"Rode VuvoDesk no computador que verá as telas. O manager inicia a UI e o servidor local juntos e abre http://127.0.0.1:5179.",managerPoints:["O comando é npx -y livedesk.","O manager usa 5179 para Screen Wall/API e 5197 para conexões client.","Se um processo antigo ocupa as portas, a inicialização limpa por padrão."],clientTitle:"2. Conecte uma Client",clientBody:"Em cada computador monitorado, entre com a mesma conta Google. Se o manager ainda não estiver online, o client aguarda um sinal em tempo real e verifica novamente em intervalos adaptativos.",clientPoints:["Use npx -y livedesk client para o primeiro slot livre.","Use npx -y livedesk client 3 para fixar no slot 3.","Clients continuam tentando para evitar login repetido em muitos PCs."],syncTitle:"3. Sync Server e descoberta",syncBody:"Sync Server publica este manager como Screen Wall ativo da conta. Clients leem o registro no Supabase e testam endpoints.",syncPoints:["Inclui host instance, endereços LAN/private, candidatos public, pair token e lease curto.","Candidatos LAN vêm primeiro; public depois se necessário.","Clique Sync Server após mudanças de manager, VPN, firewall ou roteador.","Chrome Local Network Access em vuvodesk.com não é mais o caminho padrão. O app npm manager é o servidor real."],platformTitle:"4. Estado das plataformas",platformBody:"Windows foi verificado com transferência de tela. macOS e Linux seguem o mesmo caminho npm.",platformPoints:["Windows: verificado.","macOS: captura e controle precisam de permissões Screen Recording/Accessibility.","Linux: runtime linux-x64, captura grim/gnome-screenshot/import/scrot e entrada X11/XTEST adicionados. Áudio ainda desativado."],firewallTitle:"Firewall e locais remotos",firewallBody:"VuvoDesk conecta tela e controle diretamente por Direct TCP autenticado e UDP/WebRTC P2P criptografado. O serviço rendezvous apenas encontra os pares e troca dados de conexão P2P; ele não encaminha tela nem entrada.",firewallPoints:["A porta client padrão para Direct TCP na LAN é 5197.","Clients e manager precisam de acesso de saída ao servidor rendezvous configurado para descoberta e signaling P2P.","Tela e entrada trafegam diretamente entre dispositivos por Direct TCP ou UDP/WebRTC P2P criptografado.","Para Direct TCP entre redes, encaminhe TCP 5197 ou configure VPN/allowlist IP. Se o P2P estiver bloqueado, VuvoDesk continua tentando conexão direta.","Exponha 5179 somente se um navegador remoto precisar abrir o Wall diretamente."],commandsTitle:"Comandos atuais",commandsBody:"A direção do produto é um comando de terminal comum entre sistemas, não baixar e instalar manualmente.",managerCommandLabel:"Iniciar manager",clientCommandLabel:"Conectar Client",slotCommandLabel:"Fixar no slot 3",manualCommandLabel:"Conexão manual avançada"}),it:pn({languageName:"Italiano",languageLabel:"Lingua documento",eyebrow:"VuvoDesk Manual",title:"Apri uno Screen Wall locale con un comando",intro:"VuvoDesk è un deck npm-first per monitorare Client, mini PC, Mac mini e macchine dev da un solo PC manager.",managerTitle:"1. Avvia il manager",managerBody:"Esegui VuvoDesk sul computer che guarderà gli schermi. Il manager avvia UI e server locale e apre http://127.0.0.1:5179.",managerPoints:["Il comando è npx -y livedesk.","Il manager usa 5179 per Screen Wall/API e 5197 per connessioni client.","Se vecchi processi occupano le porte, l’avvio le pulisce di default."],clientTitle:"2. Connetti una Client",clientBody:"Su ogni computer monitorato, accedi con lo stesso account Google. Se il manager non è online, il client riprova ogni 5 secondi.",clientPoints:["npx -y livedesk client usa il primo slot libero.","npx -y livedesk client 3 fissa la macchina allo slot 3.","I client continuano a provare per evitare login ripetuti."],syncTitle:"3. Sync Server e discovery",syncBody:"Sync Server pubblica questo manager come Screen Wall attivo dell’account. I client leggono Supabase e provano gli endpoint.",syncPoints:["Include host instance, indirizzi LAN/private, candidati public, pair token e lease breve.","Prima LAN, poi public se necessario.","Premi Sync Server dopo cambi di manager, VPN, firewall o router.","Chrome Local Network Access su vuvodesk.com non è più il percorso principale. L’app npm manager è il server reale."],platformTitle:"4. Stato piattaforme",platformBody:"Windows è verificato con trasferimento schermo live. macOS e Linux seguono lo stesso percorso npm.",platformPoints:["Windows: verificato.","macOS: capture e control richiedono permessi Screen Recording/Accessibility.","Linux: aggiunti runtime linux-x64, capture grim/gnome-screenshot/import/scrot e input X11/XTEST. Audio disattivato."],firewallTitle:"Firewall e sedi remote",firewallBody:"VuvoDesk collega schermo e controllo direttamente con Direct TCP autenticato e UDP/WebRTC P2P cifrato. Il servizio rendezvous trova solo i peer e scambia le informazioni P2P; non inoltra schermo o input.",firewallPoints:["La porta client predefinita per Direct TCP in LAN è 5197.","Client e manager devono accedere al server rendezvous configurato per discovery e signaling P2P.","Schermo e input viaggiano direttamente tra dispositivi tramite Direct TCP o UDP/WebRTC P2P cifrato.","Per Direct TCP tra reti, inoltra TCP 5197 o configura VPN/allowlist IP. Se il P2P è bloccato, VuvoDesk ritenta la connessione diretta.","Esponi 5179 soltanto se un browser remoto deve aprire direttamente la Wall."],commandsTitle:"Comandi attuali",commandsBody:"La direzione è un comando terminale comune tra sistemi operativi, invece di download e install manuale.",managerCommandLabel:"Avvia manager",clientCommandLabel:"Connetti Client",slotCommandLabel:"Fissa allo slot 3",manualCommandLabel:"Connessione manuale avanzata"}),id:pn({languageName:"Bahasa Indonesia",languageLabel:"Bahasa dokumen",eyebrow:"VuvoDesk Manual",title:"Buka Screen Wall lokal dengan satu perintah",intro:"VuvoDesk adalah deck npm-first untuk memantau banyak Client, mini PC, Mac mini, dan mesin dev dari satu PC manager.",managerTitle:"1. Jalankan manager",managerBody:"Jalankan VuvoDesk di komputer yang melihat layar. Manager membuka UI dan server lokal bersama, lalu membuka http://127.0.0.1:5179.",managerPoints:["Perintahnya npx -y livedesk.","Manager memakai 5179 untuk Screen Wall/API dan 5197 untuk koneksi client.","Jika proses lama memakai port itu, startup membersihkannya secara default."],clientTitle:"2. Hubungkan Client",clientBody:"Di komputer yang dipantau, masuk dengan akun Google yang sama. Jika manager belum online, client tetap mencoba tiap 5 detik.",clientPoints:["npx -y livedesk client memakai slot kosong pertama.","npx -y livedesk client 3 mengunci mesin ke slot 3.","Client terus mencoba agar banyak PC tidak perlu login berulang."],syncTitle:"3. Sync Server dan discovery",syncBody:"Sync Server menerbitkan manager ini sebagai Screen Wall aktif untuk akun. Client membaca Supabase dan mencoba endpoint.",syncPoints:["Berisi host instance, alamat LAN/private, kandidat public, pair token, dan lease pendek.","Kandidat LAN dicoba lebih dulu, lalu public jika perlu.","Tekan Sync Server setelah perubahan manager, VPN, firewall, atau router.","Chrome Local Network Access di vuvodesk.com bukan jalur utama lagi. App npm manager adalah server sebenarnya."],platformTitle:"4. Status platform",platformBody:"Windows sudah diverifikasi dengan live screen transfer. macOS dan Linux mengikuti jalur npm yang sama.",platformPoints:["Windows: terverifikasi.","macOS: capture dan control perlu izin Screen Recording/Accessibility.","Linux: runtime linux-x64, capture grim/gnome-screenshot/import/scrot, dan input X11/XTEST sudah ditambahkan. Audio belum aktif."],firewallTitle:"Firewall dan lokasi luar",firewallBody:"VuvoDesk menghubungkan layar dan kontrol secara langsung melalui Direct TCP terautentikasi dan UDP/WebRTC P2P terenkripsi. Layanan rendezvous hanya menemukan peer dan menukar informasi koneksi P2P; tidak meneruskan layar atau input.",firewallPoints:["Port client default untuk Direct TCP di LAN adalah 5197.","Client dan manager memerlukan akses keluar ke server rendezvous untuk discovery dan signaling P2P.","Layar dan input bergerak langsung antardevice melalui Direct TCP atau UDP/WebRTC P2P terenkripsi.","Untuk Direct TCP antarjaringan, forward TCP 5197 atau atur VPN/IP allowlist. Jika P2P diblokir, VuvoDesk terus mencoba koneksi langsung.","Buka 5179 hanya jika browser jarak jauh harus membuka Wall secara langsung."],commandsTitle:"Perintah saat ini",commandsBody:"Arah produk adalah satu perintah terminal lintas OS, bukan download dan instal manual.",managerCommandLabel:"Mulai manager",clientCommandLabel:"Hubungkan Client",slotCommandLabel:"Kunci ke slot 3",manualCommandLabel:"Koneksi manual lanjutan"}),vi:pn({languageName:"Tiếng Việt",languageLabel:"Ngôn ngữ tài liệu",eyebrow:"VuvoDesk Manual",title:"Mở Screen Wall cục bộ bằng một lệnh",intro:"VuvoDesk là deck npm-first để giám sát nhiều Client, mini PC, Mac mini và máy dev từ một PC manager.",managerTitle:"1. Chạy manager",managerBody:"Chạy VuvoDesk trên máy dùng để xem màn hình. Manager khởi động UI và server cục bộ cùng lúc, rồi mở http://127.0.0.1:5179.",managerPoints:["Lệnh là npx -y livedesk.","Manager dùng 5179 cho Screen Wall/API và 5197 cho kết nối client.","Nếu tiến trình cũ giữ port, startup mặc định sẽ dọn và khởi động lại."],clientTitle:"2. Kết nối Client",clientBody:"Trên mỗi máy được giám sát, đăng nhập cùng tài khoản Google. Nếu manager chưa online, client tiếp tục thử mỗi 5 giây.",clientPoints:["npx -y livedesk client dùng slot trống đầu tiên.","npx -y livedesk client 3 ghim máy vào slot 3.","Client tiếp tục chờ để nhiều máy không cần đăng nhập lại."],syncTitle:"3. Sync Server và tự phát hiện",syncBody:"Sync Server đăng manager này là Screen Wall đang hoạt động của tài khoản. Client đọc Supabase và thử các endpoint.",syncPoints:["Bao gồm host instance, địa chỉ LAN/private, public candidate, pair token và lease ngắn.","Ưu tiên LAN trước, sau đó thử public nếu cần.","Bấm Sync Server sau thay đổi manager, VPN, firewall hoặc router.","Chrome Local Network Access trên vuvodesk.com không còn là đường chạy chính. App npm manager mới là server thật."],platformTitle:"4. Trạng thái nền tảng",platformBody:"Windows đã được kiểm chứng với truyền màn hình live. macOS và Linux đi theo cùng đường npm.",platformPoints:["Windows: đã kiểm chứng.","macOS: capture và control cần quyền Screen Recording/Accessibility.","Linux: đã thêm runtime linux-x64, capture grim/gnome-screenshot/import/scrot và input X11/XTEST. Audio chưa bật."],firewallTitle:"Firewall và địa điểm ngoài",firewallBody:"VuvoDesk kết nối trực tiếp màn hình và control bằng Direct TCP đã xác thực và UDP/WebRTC P2P mã hóa. Dịch vụ rendezvous chỉ tìm peer và trao đổi thông tin kết nối P2P; không chuyển tiếp màn hình hoặc input.",firewallPoints:["Port client mặc định cho Direct TCP trong LAN là 5197.","Client và manager cần kết nối outbound tới rendezvous server để discovery và signaling P2P.","Màn hình và input đi trực tiếp giữa các thiết bị qua Direct TCP hoặc UDP/WebRTC P2P mã hóa.","Để dùng Direct TCP giữa các mạng, hãy forward TCP 5197 hoặc cấu hình VPN/IP allowlist. Khi P2P bị chặn, VuvoDesk tiếp tục thử kết nối trực tiếp.","Chỉ mở 5179 khi browser từ xa cần mở Wall trực tiếp."],commandsTitle:"Lệnh hiện tại",commandsBody:"Hướng sản phẩm là một lệnh terminal dùng chung giữa các OS, thay vì tải và cài thủ công.",managerCommandLabel:"Khởi động manager",clientCommandLabel:"Kết nối Client",slotCommandLabel:"Ghim vào slot 3",manualCommandLabel:"Kết nối thủ công nâng cao"}),th:pn({languageName:"ไทย",languageLabel:"ภาษาของเอกสาร",eyebrow:"VuvoDesk Manual",title:"เปิด Screen Wall ภายในด้วยคำสั่งเดียว",intro:"VuvoDesk คือ deck แบบ npm-first สำหรับดู Client, mini PC, Mac mini และเครื่อง dev หลายเครื่องจาก manager PC เครื่องเดียว",managerTitle:"1. รัน manager",managerBody:"รัน VuvoDesk บนเครื่องที่ใช้ดูหน้าจอ Manager จะเปิด UI และ local server พร้อมกัน แล้วเปิด http://127.0.0.1:5179",managerPoints:["คำสั่งคือ npx -y livedesk","Manager ใช้ 5179 สำหรับ Screen Wall/API และ 5197 สำหรับ client connection","ถ้า process เก่ายังใช้ port อยู่ startup จะล้างให้โดย default"],clientTitle:"2. เชื่อม Client",clientBody:"บนเครื่องที่ต้อง monitor ให้ login ด้วย Google account เดียวกัน ถ้า manager ยังไม่ออนไลน์ client จะลองใหม่ทุก 5 วินาที",clientPoints:["npx -y livedesk client จะใช้ slot ว่างแรก","npx -y livedesk client 3 จะตรึงเครื่องไว้ที่ slot 3","Client จะรอต่อเนื่องเพื่อไม่ต้อง login ซ้ำเมื่อมีหลายเครื่อง"],syncTitle:"3. Sync Server และ discovery",syncBody:"Sync Server จะ publish manager นี้เป็น active Screen Wall ของ account แล้ว client อ่านข้อมูลจาก Supabase และลอง endpoint ต่างๆ",syncPoints:["มี host instance, LAN/private address, public candidate, pair token และ short lease","ลอง LAN ก่อน แล้วค่อยลอง public ถ้าจำเป็น","กด Sync Server หลังเปลี่ยน manager, VPN, firewall หรือ router","Chrome Local Network Access บน vuvodesk.com ไม่ใช่ runtime หลักแล้ว app npm manager คือ server จริง"],platformTitle:"4. สถานะ platform",platformBody:"Windows ตรวจสอบแล้วว่าส่งภาพ live ได้ macOS และ Linux ใช้เส้นทาง npm เดียวกัน",platformPoints:["Windows: verified","macOS: capture/control ต้องใช้สิทธิ์ Screen Recording/Accessibility","Linux: เพิ่ม linux-x64 runtime, grim/gnome-screenshot/import/scrot capture และ X11/XTEST input แล้ว audio ยังปิดอยู่"],firewallTitle:"Firewall และเครื่องต่างสถานที่",firewallBody:"VuvoDesk เชื่อมหน้าจอและ control โดยตรงด้วย Direct TCP ที่ยืนยันตัวตนและ UDP/WebRTC P2P ที่เข้ารหัส บริการ rendezvous ใช้เพียงค้นหา peer และแลกข้อมูลการเชื่อมต่อ P2P โดยไม่ส่งต่อหน้าจอหรือ input",firewallPoints:["Port client เริ่มต้นสำหรับ Direct TCP ใน LAN คือ 5197","Client และ manager ต้องเชื่อมต่อ outbound ไปยัง rendezvous server เพื่อ discovery และ P2P signaling","หน้าจอและ input ส่งตรงระหว่าง device ผ่าน Direct TCP หรือ UDP/WebRTC P2P ที่เข้ารหัส","หากต้องใช้ Direct TCP ข้าม network ให้ forward TCP 5197 หรือตั้ง VPN/IP allowlist เมื่อ P2P ถูกบล็อก VuvoDesk จะลองเชื่อมตรงอีกครั้ง","เปิด 5179 เฉพาะเมื่อ browser ระยะไกลต้องเปิด Wall โดยตรง"],commandsTitle:"คำสั่งปัจจุบัน",commandsBody:"ทิศทาง product คือคำสั่ง terminal เดียวข้าม OS ไม่ใช่ download/install จากเว็บไซต์",managerCommandLabel:"เริ่ม manager",clientCommandLabel:"เชื่อม Client",slotCommandLabel:"ตรึง slot 3",manualCommandLabel:"manual connection ขั้นสูง"}),hi:pn({languageName:"हिन्दी",languageLabel:"दस्तावेज़ भाषा",eyebrow:"VuvoDesk Manual",title:"एक कमांड से local Screen Wall खोलें",intro:"VuvoDesk एक npm-first remote work deck है जिससे एक manager PC से कई Client, mini PC, Mac mini और dev machines देखे जा सकते हैं।",managerTitle:"1. manager चलाएं",managerBody:"जिस computer से screens देखनी हैं उस पर VuvoDesk manager चलाएं। यह UI और local server साथ में शुरू करता है और http://127.0.0.1:5179 खोलता है।",managerPoints:["कमांड है npx -y livedesk।","Manager Screen Wall/API के लिए 5179 और client connections के लिए 5197 इस्तेमाल करता है।","अगर पुराने VuvoDesk ports बचे हों तो startup default रूप से साफ करता है।"],clientTitle:"2. Client जोड़ें",clientBody:"हर monitored computer पर उसी Google account से sign in करें। Manager online न हो तब भी client बंद नहीं होता और हर 5 सेकंड retry करता है।",clientPoints:["npx -y livedesk client पहला खाली slot लेता है।","npx -y livedesk client 3 machine को slot 3 पर pin करता है।","बहुत सी machines हों तब भी बार-बार login की जरूरत नहीं रहती।"],syncTitle:"3. Sync Server और discovery",syncBody:"Sync Server इस manager को account का active Screen Wall बनाकर Supabase में publish करता है। Clients record पढ़कर endpoints try करते हैं।",syncPoints:["इसमें host instance, LAN/private addresses, public candidates, pair token और short lease होता है।","LAN candidates पहले try होते हैं, जरूरत हो तो public candidates।","Manager, VPN, firewall या router बदलने के बाद Sync Server दबाएं।","vuvodesk.com का Chrome Local Network Access अब default runtime नहीं है। npm manager app ही real server है।"],platformTitle:"4. Platform status",platformBody:"Windows live screen transfer के साथ verified है। macOS और Linux भी इसी npm path पर आगे बढ़ रहे हैं।",platformPoints:["Windows: verified.","macOS: capture/control के लिए Screen Recording/Accessibility permissions चाहिए।","Linux: linux-x64 runtime, X11/XTEST input और PipeWire/PulseAudio output audio capture उपलब्ध हैं।"],firewallTitle:"Firewall और remote locations",firewallBody:"VuvoDesk authenticated Direct TCP और encrypted UDP/WebRTC P2P से screen और control को सीधे जोड़ता है। rendezvous service केवल peers खोजती और P2P connection info बदलती है; screen या input data आगे नहीं भेजती।",firewallPoints:["LAN Direct TCP का default client port 5197 है।","Peer discovery और P2P signaling के लिए Clients और manager को configured rendezvous server तक outbound access चाहिए।","Screen और input data Direct TCP या encrypted UDP/WebRTC P2P से device-to-device सीधे जाते हैं।","Networks के बीच Direct TCP के लिए TCP 5197 forward या VPN/IP allowlist सेट करें। P2P block होने पर VuvoDesk direct connection फिर आज़माता है।","5179 तभी expose करें जब remote browser को Wall सीधे खोलना हो।"],commandsTitle:"Current commands",commandsBody:"Product direction है OS के बीच एक terminal command, website से download/install नहीं।",managerCommandLabel:"Start manager",clientCommandLabel:"Connect Client",slotCommandLabel:"Pin to slot 3",manualCommandLabel:"Advanced manual connection"}),ar:pn({languageName:"العربية",languageLabel:"لغة المستند",eyebrow:"VuvoDesk Manual",title:"افتح Screen Wall محلي بأمر واحد",intro:"VuvoDesk هو deck بنمط npm-first لمراقبة عدة Clients وأجهزة mini PC وMac mini وأجهزة تطوير من كمبيوتر manager واحد.",managerTitle:"1. شغل manager",managerBody:"شغل VuvoDesk على الكمبيوتر الذي سيعرض الشاشات. يبدأ manager الواجهة والخادم المحلي معا ويفتح http://127.0.0.1:5179.",managerPoints:["الأمر هو npx -y livedesk.","يستخدم manager المنفذ 5179 للواجهة/API والمنفذ 5197 لاتصالات client.","إذا بقيت عملية VuvoDesk قديمة على المنافذ، يتم تنظيفها افتراضيا عند التشغيل."],clientTitle:"2. وصل Client",clientBody:"على كل كمبيوتر تتم مراقبته، سجل الدخول بنفس حساب Google. إذا لم يكن manager متاحا، يبقى client يعمل ويحاول كل 5 ثوان.",clientPoints:["npx -y livedesk client يختار أول slot فارغ.","npx -y livedesk client 3 يثبت الجهاز في slot 3.","clients تستمر بالمحاولة لتجنب تكرار تسجيل الدخول عند كثرة الأجهزة."],syncTitle:"3. Sync Server والاكتشاف",syncBody:"Sync Server ينشر هذا manager كـ active Screen Wall للحساب. يقرأ clients سجل Supabase ويجربون endpoints بالترتيب.",syncPoints:["السجل يتضمن host instance وعناوين LAN/private وpublic candidates وpair token وlease قصير.","يتم تفضيل LAN أولا، ثم public عند الحاجة.","اضغط Sync Server بعد تغيير manager أو VPN أو firewall أو router.","Chrome Local Network Access على vuvodesk.com لم يعد مسار التشغيل الافتراضي. تطبيق npm manager هو الخادم الحقيقي."],platformTitle:"4. حالة المنصات",platformBody:"Windows تم التحقق منه مع نقل شاشة live. macOS وLinux يتبعان نفس مسار npm.",platformPoints:["Windows: تم التحقق.","macOS: capture/control يحتاجان أذونات Screen Recording/Accessibility.","Linux: تمت إضافة linux-x64 runtime وgrim/gnome-screenshot/import/scrot capture وX11/XTEST input. الصوت ما زال معطلا."],firewallTitle:"Firewall والمواقع البعيدة",firewallBody:"يربط VuvoDesk الشاشة والتحكم مباشرة عبر Direct TCP موثق وUDP/WebRTC P2P مشفر. تقتصر خدمة rendezvous على اكتشاف الأطراف وتبادل معلومات اتصال P2P، ولا تمرر الشاشة أو بيانات الإدخال.",firewallPoints:["منفذ client الافتراضي لاتصال Direct TCP داخل LAN هو 5197.","يحتاج client وmanager إلى اتصال outbound بخادم rendezvous للاكتشاف وP2P signaling.","تنتقل الشاشة وبيانات الإدخال مباشرة بين الأجهزة عبر Direct TCP أو UDP/WebRTC P2P المشفر.","لاستخدام Direct TCP بين الشبكات وجه TCP 5197 أو اضبط VPN/IP allowlist. عند حظر P2P يعيد VuvoDesk محاولة الاتصال المباشر.","اكشف 5179 فقط إذا كان browser بعيد يحتاج فتح Wall مباشرة."],commandsTitle:"الأوامر الحالية",commandsBody:"اتجاه المنتج هو أمر terminal واحد عبر الأنظمة، وليس تحميل وتثبيت يدوي من موقع.",managerCommandLabel:"Start manager",clientCommandLabel:"Connect Client",slotCommandLabel:"Pin to slot 3",manualCommandLabel:"Advanced manual connection"}),tr:pn({languageName:"Türkçe",languageLabel:"Belge dili",eyebrow:"VuvoDesk Manual",title:"Yerel Screen Wall tek komutla açılsın",intro:"VuvoDesk, tek bir manager PC üzerinden birçok Client, mini PC, Mac mini ve dev machine izlemek için npm-first bir çalışma deckidir.",managerTitle:"1. Manager çalıştır",managerBody:"Ekranları izleyecek bilgisayarda VuvoDesk manager çalıştır. Manager UI ve local server birlikte başlar ve http://127.0.0.1:5179 açılır.",managerPoints:["Komut: npx -y livedesk.","Manager Screen Wall/API için 5179, client bağlantıları için 5197 kullanır.","Eski VuvoDesk process portları tutuyorsa başlangıç varsayılan olarak temizler."],clientTitle:"2. Client bağla",clientBody:"İzlenecek bilgisayarda aynı Google hesabıyla giriş yap. Manager henüz online değilse client kapanmaz ve her 5 saniyede tekrar dener.",clientPoints:["npx -y livedesk client ilk boş slota yerleşir.","npx -y livedesk client 3 makineyi slot 3’e sabitler.","Çok makinede tekrar tekrar login gerekmesin diye client beklemeye devam eder."],syncTitle:"3. Sync Server ve discovery",syncBody:"Sync Server bu managerı hesabın active Screen Wall kaydı olarak Supabase’e yazar. Clients bu kaydı okuyup endpoint adaylarını dener.",syncPoints:["Host instance, LAN/private adresler, public adaylar, pair token ve kısa lease içerir.","Önce LAN adayları, gerekirse public adaylar denenir.","Manager, VPN, firewall veya router değişince Sync Server’a bas.","vuvodesk.com üzerindeki Chrome Local Network Access artık default runtime yolu değil. Gerçek server npm manager app."],platformTitle:"4. Platform durumu",platformBody:"Windows live screen transfer ile doğrulandı. macOS ve Linux aynı npm yolunu takip ediyor.",platformPoints:["Windows: doğrulandı.","macOS: capture/control için Screen Recording/Accessibility izinleri gerekir.","Linux: linux-x64 runtime, grim/gnome-screenshot/import/scrot capture ve X11/XTEST input backend eklendi. Audio kapalı."],firewallTitle:"Firewall ve uzak konumlar",firewallBody:"VuvoDesk ekranı ve kontrolü doğrulanmış Direct TCP ve şifreli UDP/WebRTC P2P ile doğrudan bağlar. Rendezvous hizmeti yalnızca eşleri bulur ve P2P bağlantı bilgilerini değiştirir; ekran veya girdi verisini taşımaz.",firewallPoints:["LAN Direct TCP için varsayılan client portu 5197dir.","Client ve manager, eş keşfi ve P2P signaling için yapılandırılmış rendezvous servera outbound erişebilmelidir.","Ekran ve girdi verileri Direct TCP veya şifreli UDP/WebRTC P2P ile cihazdan cihaza doğrudan gider.","Ağlar arasında Direct TCP için TCP 5197 yönlendirme veya VPN/IP allowlist yapılandırın. P2P engellenirse VuvoDesk doğrudan bağlantıyı yeniden dener.","5179u yalnız uzak browser Wallu doğrudan açacaksa expose et."],commandsTitle:"Güncel komutlar",commandsBody:"Ürün yönü, webden indirip kurmak yerine işletim sistemleri arasında ortak tek terminal komutu.",managerCommandLabel:"Manager başlat",clientCommandLabel:"Client bağla",slotCommandLabel:"Slot 3’e sabitle",manualCommandLabel:"Gelişmiş manuel bağlantı"})},BM=Object.entries(ki).map(([e,t])=>({id:e,label:t.languageName}));function HM(){if(typeof navigator>"u")return"en";const e=navigator.languages?.length?navigator.languages:[navigator.language];for(const t of e){const a=t.toLowerCase();if(ki[t])return t;if(a.startsWith("zh-tw")||a.startsWith("zh-hk"))return"zh-TW";if(a.startsWith("pt"))return"pt-BR";const r=a.split("-")[0];if(ki[r])return r}return"en"}function Gh({index:e}){const t=e+1;return i.jsx("article",{className:"device-tile placeholder-tile","aria-label":`Empty slot ${t}`,children:i.jsxs("div",{className:"tile-screen","aria-hidden":"true",children:[i.jsx("span",{className:"slot-grid","aria-hidden":"true"}),i.jsxs("span",{className:"empty-screen",children:[i.jsx(Aa,{size:24}),i.jsxs("strong",{children:["Slot ",String(t).padStart(3,"0")]})]})]})})}const WM=["cpu","gpu","memory","vram","network","disk","temp"];function $M({device:e,slotNumber:t,selected:a,updateIndicator:r,remoteDiagnostics:c,diagnosticsMode:u="remote",onSelect:p,onOpenControl:h}){const f=wb(e),k=new Map(f.metrics.map(b=>[b.id,b])),M=r?.label||f.label;return i.jsxs("div",{className:`wall-device-list-row state-${f.state} ${a?"selected":""}`,role:"row","aria-selected":a,tabIndex:0,onClick:p,onDoubleClick:b=>{b.preventDefault(),h()},onKeyDown:b=>{(b.key==="Enter"||b.key===" ")&&(b.preventDefault(),p())},children:[i.jsxs("span",{className:"wall-device-name",role:"gridcell",children:[i.jsx("span",{className:"wall-device-icon","aria-hidden":"true",children:i.jsx(Aa,{size:17})}),i.jsxs("span",{children:[i.jsx("strong",{children:Qt(e)}),i.jsxs("small",{children:["Slot ",String(t).padStart(3,"0"),e.platform?` · ${e.platform}`:"",e.arch?` · ${e.arch}`:""]})]}),a&&i.jsx(bl,{size:16,strokeWidth:3,"aria-label":"Selected"})]}),i.jsxs("span",{className:`wall-device-list-status state-${f.state} ${r?`update-${r.state}`:""}`,role:"gridcell",title:r?.error||M,children:[i.jsx("i",{"aria-hidden":"true"}),i.jsx("strong",{children:M})]}),WM.map(b=>{const T=k.get(b);return i.jsxs("span",{className:`wall-device-list-metric state-${T?.state||"unknown"}`,role:"gridcell",title:T?`${T.label}: ${T.value} · ${T.detail}`:"Not reported",children:[i.jsx("strong",{children:T?.value||"-"}),i.jsx("small",{children:T?.detail||"not reported"}),T?.ratio!==void 0&&i.jsx("i",{style:{width:`${Math.round(T.ratio*100)}%`},"aria-hidden":"true"})]},b)}),c&&i.jsx("span",{className:"wall-device-list-diagnostics",role:"gridcell",children:i.jsx(Zg,{items:c,mode:u})})]})}function VM(e){if(!e)return!1;const t=String(e.platform||"").trim().toLowerCase();return Nr(t)&&e.capabilities?.screenRecordingPermission===!1}function Nr(e){const t=String(e||"").trim().toLowerCase();return t==="macos"||t==="darwin"||t==="mac"||t==="macosx"}function zM(e){const t=String(e||"").trim().toLowerCase();return t==="linux"||t.startsWith("linux ")}function Kh(e){const t=String(e||"").trim().toLowerCase();return["win32","windows","win32nt"].includes(t)?"mode5-lzo-delta":Nr(t)?"mode1-jpeg":""}function Cd({device:e,frame:t,selected:a,controlEnabled:r,showStatus:c,showDeviceTitle:u=!0,monitorIndex:p,monitorCount:h,onSelect:f,onFocusDevice:k,onOpenControl:M,onCycleMonitor:b,onCanvasReady:T,sendInput:A,remotePointerFeedback:x,remoteModifierState:E,updateIndicator:B,presentationReady:q,showPresentationSpinner:G=!1,remoteDiagnostics:ne,diagnosticsMode:re="remote"}){const O=s.useRef(null),ie=s.useRef(null),J=s.useRef(null),de=s.useRef(0),se=s.useRef(null),pe=s.useRef(null),ce=s.useRef(new Map),W=s.useRef(null),ee=s.useRef(PC()),L=s.useRef(AC()),_=s.useRef(!1),K=s.useRef([]),ue=s.useRef(Al()),P=s.useRef(null),N=s.useRef(null),te=wb(e),we=["cpu","gpu","memory","vram"].map(g=>te.metrics.find(U=>U.id===g)).filter(g=>!!g),me=em(p),Fe=h>1,H=q??!!t,R=VM(e)&&!H,Se=G&&e.connected&&!H&&!R,Ce=gM(e,t,me),Ve=Ce>=hl?100:Ce/hl*100,Ze=Ce>=hl?hl/Ce*100:100,_e={"--screen-aspect":Ce.toFixed(5),"--screen-content-width":`${Math.max(1,Math.min(100,Ve)).toFixed(3)}%`,"--screen-content-height":`${Math.max(1,Math.min(100,Ze)).toFixed(3)}%`},z=r?{transformOrigin:"0 0",transform:`translate3d(${ue.current.translateX.toFixed(2)}px, ${ue.current.translateY.toFixed(2)}px, 0) scale(${ue.current.scale.toFixed(4)})`}:void 0,Me=!!(r&&H&&x?.nativeInputBackend==="win32-window-message"&&x.deviceId===e.deviceId&&x.monitorIndex===me),Be=Me?{left:`${Math.max(0,Math.min(1,x.normalizedX))*100}%`,top:`${Math.max(0,Math.min(1,x.normalizedY))*100}%`}:void 0,Ge=s.useCallback(g=>{ue.current=g;const U=O.current;U&&(U.style.transformOrigin="0 0",U.style.transform=`translate3d(${g.translateX.toFixed(2)}px, ${g.translateY.toFixed(2)}px, 0) scale(${g.scale.toFixed(4)})`,U.dataset.touchZoom=g.scale.toFixed(2))},[]),xt=s.useCallback(g=>{if(O.current=g,g&&r){const U=ue.current;g.style.transformOrigin="0 0",g.style.transform=`translate3d(${U.translateX.toFixed(2)}px, ${U.translateY.toFixed(2)}px, 0) scale(${U.scale.toFixed(4)})`,g.dataset.touchZoom=U.scale.toFixed(2)}T(e.deviceId,g)},[r,e.deviceId,T]),Pe=(g,U,F)=>TC(g,U,F.getBoundingClientRect()),He=g=>Pe(g.clientX,g.clientY,g.currentTarget),Y=g=>jC(g,E),ve=s.useCallback(()=>{se.current!==null&&(window.cancelAnimationFrame(se.current),se.current=null)},[]),st=s.useCallback(()=>{const g=P.current;g&&(window.clearTimeout(g.timerId),P.current=null);const U=N.current;U&&window.clearTimeout(U.timerId),N.current=null},[]),it=s.useCallback(()=>{const g=J.current;if(!g)return;J.current=null;const U=Number(g.input.normalizedX),F=Number(g.input.normalizedY);if(!Number.isFinite(U)||!Number.isFinite(F))return;A(e.deviceId,{...g.input,normalizedX:U,normalizedY:F})&&(de.current=performance.now())},[e.deviceId,A]),bt=s.useCallback(()=>{se.current===null&&(se.current=window.requestAnimationFrame(()=>{se.current=null,it()}))},[it]);s.useEffect(()=>{L.current.reset(),_.current=!1,K.current=[];const g=Al();return Ge(g),()=>{ve(),st(),J.current=null,pe.current=null,ce.current.clear(),W.current=null,L.current.reset(),_.current=!1,K.current=[]}},[me,Ge,st,ve,r,e.deviceId]);const Rt=(g,U)=>{if(!r)return;const F={...g,type:U};if(U==="pointermove"){const he=performance.now();J.current={input:F},he-de.current>=Nk&&(ve(),it()),bt();return}J.current&&(ve(),it()),A(e.deviceId,F)},ae=(g,U,F=ys(g.button),he="")=>{Rt({monitorIndex:me,...He(g),button:F,...he?{inputSource:he}:{},...Y(g)},U)},$=(g,U)=>{A(e.deviceId,{...g,type:"pointerdown",button:U}),A(e.deviceId,{...g,type:"pointerup",button:U})},ye=(g,U,F)=>({monitorIndex:me,...Pe(g,U,F),shiftKey:!!E?.shiftKey,ctrlKey:!!E?.ctrlKey,altKey:!!E?.altKey,metaKey:!!E?.metaKey}),V=(g,U)=>{const F=P.current;F&&(window.clearTimeout(F.timerId),P.current=null,$(F.input,"left"));const he={tap:g,input:U,timerId:0};he.timerId=window.setTimeout(()=>{P.current===he&&(P.current=null,$(U,"left"))},Od),P.current=he},Ke=(g,U,F)=>{if(ce.current.set(g,{clientX:U,clientY:F}),W.current)return;const he=pe.current;if(he&&he.pointerId!==g){const Ye=ce.current.get(he.pointerId),dt=ce.current.get(g),Re=ie.current?.getBoundingClientRect();Ye&&dt&&Re&&(ve(),J.current=null,st(),pe.current=null,W.current={gesture:EC(Ye,dt,ue.current,Re),pointerIds:[he.pointerId,g]});return}const Q=performance.now(),Te=P.current,ge={clientX:U,clientY:F,at:Q};if(Te&&$f(Te.tap,ge)){window.clearTimeout(Te.timerId),P.current=null;const Ye={...Te,timerId:0};Ye.timerId=window.setTimeout(()=>{N.current===Ye&&(N.current=null,$(Ye.input,"left"))},Math.max(0,Te.tap.at+Od-Q)),N.current=Ye}else N.current=null,Te&&(window.clearTimeout(Te.timerId),P.current=null,$(Te.input,"left"));pe.current=FC(g,U,F),k()},Ct=(g,U,F,he)=>{ce.current.set(g,{clientX:U,clientY:F});const Q=W.current;if(Q){const Ye=ce.current.get(Q.pointerIds[0]),dt=ce.current.get(Q.pointerIds[1]);Ye&&dt&&Ge(NC(Q.gesture,Ye,dt));return}const Te=pe.current;if(!Te||Te.pointerId!==g)return;const ge=Ug(Te,g,U,F);if(pe.current=ge,ge?.dragged&&N.current){const Ye=N.current;window.clearTimeout(Ye.timerId),N.current=null,$(Ye.input,"left")}ge?.dragged&&Rt(ye(U,F,he),"pointermove")},I=(g,U,F,he)=>{if(ce.current.set(g,{clientX:U,clientY:F}),W.current){ce.current.delete(g),ce.current.size===0&&(W.current=null);return}const Q=DC(pe.current,g,U,F,performance.now());if(ce.current.delete(g),Q.kind==="ignore")return;Q.kind==="drag"&&(Rt(ye(U,F,he),"pointermove"),ve(),it()),pe.current=null;const Te=N.current;if(Te&&window.clearTimeout(Te.timerId),N.current=null,Q.kind==="tap"&&Q.tap){const ge=ye(U,F,he);Te&&$f(Te.tap,Q.tap)?$(ge,"right"):(Te&&$(Te.input,"left"),V(Q.tap,ge))}else Te&&$(Te.input,"left")},oe=g=>{if(ce.current.delete(g),W.current){ce.current.size===0&&(W.current=null);return}if(pe.current?.pointerId===g){ve(),J.current=null,pe.current=null;const U=N.current;U&&(window.clearTimeout(U.timerId),$(U.input,"left")),N.current=null}},Ee=g=>{if(g.pointerType!=="touch")return!1;if(g.preventDefault(),g.stopPropagation(),ee.current.shouldHandlePointerEvent()){Ke(g.pointerId,g.clientX,g.clientY);try{g.currentTarget.setPointerCapture(g.pointerId)}catch{}}return!0},We=g=>g.pointerType!=="touch"?!1:(g.preventDefault(),ee.current.shouldHandlePointerEvent()&&Ct(g.pointerId,g.clientX,g.clientY,g.currentTarget),!0),vt=g=>g.pointerType!=="touch"?!1:(g.preventDefault(),g.stopPropagation(),ee.current.shouldHandlePointerEvent()&&I(g.pointerId,g.clientX,g.clientY,g.currentTarget),g.currentTarget.hasPointerCapture(g.pointerId)&&g.currentTarget.releasePointerCapture(g.pointerId),!0),et=g=>g.pointerType!=="touch"?!1:(g.preventDefault(),g.stopPropagation(),ee.current.shouldHandlePointerEvent()&&oe(g.pointerId),g.currentTarget.hasPointerCapture(g.pointerId)&&g.currentTarget.releasePointerCapture(g.pointerId),!0),Tt=g=>{if(r){g.preventDefault(),g.stopPropagation(),ee.current.shouldHandlePointerEvent()&&(ee.current.claimNativeTouchEvents(),pe.current=null,ce.current.clear(),W.current=null);for(const U of Array.from(g.changedTouches))Ke(U.identifier,U.clientX,U.clientY)}},jt=g=>{if(!r)return;g.preventDefault(),g.stopPropagation();for(const he of Array.from(g.touches))ce.current.set(he.identifier,{clientX:he.clientX,clientY:he.clientY});const U=pe.current?.pointerId,F=Array.from(g.touches).find(he=>he.identifier===U)||g.touches.item(0);F&&Ct(F.identifier,F.clientX,F.clientY,g.currentTarget)},Jt=g=>{if(r){g.preventDefault(),g.stopPropagation();for(const U of Array.from(g.changedTouches))I(U.identifier,U.clientX,U.clientY,g.currentTarget)}},At=g=>{if(r){g.preventDefault(),g.stopPropagation();for(const U of Array.from(g.changedTouches))oe(U.identifier)}},zt=s.useCallback(g=>{const U=document.activeElement;U instanceof HTMLElement&&g.contains(U)&&U.classList.contains("monitor-cycle-button")&&U.blur()},[]);return i.jsx("article",{className:`device-tile ${a?"selected":""} ${e.connected?"online":"offline"}`,"data-live-device-id":e.deviceId,style:_e,children:i.jsxs("div",{className:`tile-screen ${H?"has-frame":"is-empty"}`,role:"button",tabIndex:r?-1:0,"aria-pressed":a,onClick:g=>{g.target instanceof Element&&g.target.closest(".monitor-cycle")||r||f()},onKeyDown:g=>{g.target instanceof Element&&g.target.closest(".monitor-cycle")||r||(g.key==="Enter"||g.key===" ")&&(g.preventDefault(),f())},onDoubleClick:g=>{if(!(g.target instanceof Element&&g.target.closest(".monitor-cycle"))){if(g.preventDefault(),r){g.stopPropagation();return}M()}},onPointerLeave:g=>zt(g.currentTarget),children:[i.jsxs("span",{ref:ie,className:`screen-content ${H?"has-frame":"is-empty"}`,children:[i.jsx("canvas",{ref:xt,className:`remote-canvas ${H?"has-frame":"is-empty"} ${r?"control-input-enabled":""}`,"data-monitor-index":me,"data-touch-zoom":ue.current.scale.toFixed(2),style:z,tabIndex:r?0:-1,onPointerDown:g=>{if(r&&!Ee(g)){_.current=!1,L.current.observePointerEvent("down",g),g.preventDefault(),g.stopPropagation(),k(),g.currentTarget.focus(),ae(g,"pointerdown");try{g.currentTarget.setPointerCapture(g.pointerId)}catch{}}},onPointerMove:g=>{r&&g.preventDefault(),!We(g)&&(r&&(_.current=!1,L.current.observePointerEvent("move",g)),ae(g,"pointermove"))},onPointerLeave:g=>{r&&g.pointerType!=="touch"&&(_.current=!1,L.current.observePointerEvent("leave",g),ae(g,"pointermove"),ve(),it())},onPointerUp:g=>{r&&(vt(g)||(_.current=!1,L.current.observePointerEvent("up",g),g.preventDefault(),g.stopPropagation(),ae(g,"pointerup"),g.currentTarget.hasPointerCapture(g.pointerId)&&g.currentTarget.releasePointerCapture(g.pointerId)))},onPointerCancel:g=>{et(g)||(r&&(g.preventDefault(),g.stopPropagation(),ae(g,"pointerup")),g.currentTarget.hasPointerCapture(g.pointerId)&&g.currentTarget.releasePointerCapture(g.pointerId))},onMouseDown:g=>{if(!r||!L.current.shouldHandleMouseEvent("down",g))return;g.preventDefault(),g.stopPropagation(),_.current=!0,k(),g.currentTarget.focus();const U=ys(g.button);K.current.includes(U)||K.current.push(U),ae(g,"pointerdown",U,"legacy-mouse")},onMouseMove:g=>{!r||!L.current.shouldHandleMouseEvent("move",g)||(g.preventDefault(),_.current=!0,ae(g,"pointermove",ys(g.button),"legacy-mouse"))},onMouseLeave:g=>{if(!r||!L.current.shouldHandleMouseEvent("leave",g))return;_.current=!0,ae(g,"pointermove",ys(g.button),"legacy-mouse"),ve(),it();const U=K.current.splice(0).reverse();for(const F of U)ae(g,"pointerup",F,"legacy-mouse")},onMouseUp:g=>{if(!r||!L.current.shouldHandleMouseEvent("up",g))return;g.preventDefault(),g.stopPropagation(),_.current=!0;const U=ys(g.button);ae(g,"pointerup",U,"legacy-mouse"),K.current=K.current.filter(F=>F!==U)},onTouchStart:Tt,onTouchMove:jt,onTouchEnd:Jt,onTouchCancel:At,onWheel:g=>{r&&(g.preventDefault(),A(e.deviceId,{type:"wheel",monitorIndex:me,...He(g),deltaX:g.deltaX,deltaY:g.deltaY,..._.current?{inputSource:"legacy-mouse"}:{},...Y(g)}))},onContextMenu:g=>r&&g.preventDefault(),onDoubleClick:g=>{r&&(g.preventDefault(),g.stopPropagation())}},`${e.deviceId}:monitor:${me}`),Me&&i.jsx("span",{className:"remote-pointer-feedback","data-input-seq":x.inputSeq,"data-native-input-backend":x.nativeInputBackend,style:Be,"aria-hidden":"true",children:i.jsx(Ms,{size:22,strokeWidth:2.2})})]}),!H&&i.jsx("span",{className:"empty-screen",children:i.jsx(Aa,{size:26})}),u&&i.jsx("span",{className:"wall-device-title",title:Qt(e),children:Qt(e)}),Se&&i.jsxs("span",{className:"wall-presentation-loading",role:"status","aria-live":"polite",children:[i.jsx("span",{className:"wall-presentation-spinner","aria-hidden":"true"}),i.jsx("strong",{children:"Preparing video"})]}),R&&i.jsxs("span",{className:"wall-presentation-loading permission-required",role:"status","aria-live":"polite",children:[i.jsx(wo,{size:24,"aria-hidden":"true"}),i.jsx("strong",{children:"Screen Recording permission required"}),i.jsx("small",{children:"Allow the terminal app on this Mac, then restart VuvoDesk."})]}),B&&i.jsxs("span",{className:`wall-update-status state-${B.state}`,role:"status","aria-live":"polite",title:B.error||B.label,children:[B.state==="updated"?i.jsx(Cn,{size:20,"aria-hidden":"true"}):B.state==="failed"?i.jsx(xa,{size:22,"aria-hidden":"true"}):B.state==="offline"?i.jsx(tg,{size:22,"aria-hidden":"true"}):i.jsx("span",{className:"wall-update-spinner","aria-hidden":"true"}),i.jsx("strong",{children:B.label}),B.error?i.jsx("small",{children:B.error}):null]}),c&&i.jsxs(i.Fragment,{children:[i.jsx("span",{className:`tile-health-pill state-${te.state}`,children:te.label}),i.jsx("span",{className:"tile-metrics","aria-label":`${Qt(e)} status`,children:we.map(g=>i.jsxs("span",{className:`tile-metric state-${g.state}`,children:[i.jsx("b",{children:g.label}),i.jsx("em",{children:g.value}),g.ratio!==void 0&&i.jsx("i",{style:{width:`${Math.round(g.ratio*100)}%`}})]},g.id))})]}),ne&&i.jsx(Zg,{items:ne,mode:re}),Fe&&i.jsxs("span",{className:"monitor-cycle","aria-label":`${Qt(e)} display ${me+1} of ${h}`,onPointerDown:g=>g.stopPropagation(),onClick:g=>g.stopPropagation(),onDoubleClick:g=>g.stopPropagation(),children:[i.jsx("button",{className:"monitor-cycle-button previous",onClick:g=>{g.preventDefault(),g.stopPropagation(),b(-1),g.currentTarget.blur()},title:"Previous display",type:"button",children:i.jsx(ng,{size:18})}),i.jsxs("span",{className:"monitor-cycle-count",children:["Screen ",me+1,"/",h]}),i.jsx("button",{className:"monitor-cycle-button next",onClick:g=>{g.preventDefault(),g.stopPropagation(),b(1),g.currentTarget.blur()},title:"Next display",type:"button",children:i.jsx(rg,{size:18})})]})]})})}function UM({visible:e}){const t=Rk;return s.useEffect(()=>{},[t]),null}function gx({runtimeBaseUrl:e=""}){const t=typeof window<"u"&&!!window.liveDesk,a=t,{session:r,sessionHydrationRevision:c,loading:u,hubSessionRevoking:p,hubSessionBlocked:h,hubSessionRevocationError:f,revokeHubSession:k}=XS(),{workspaces:M,activeWorkspace:b,loading:T,error:A,inviteNotice:x,refresh:E,selectWorkspace:B,isWorkspaceActionCurrent:q}=U0(r,c),G=b?.id||"",ne=b?.membershipRevision||0,re=b?.kind==="team"&&b.role==="operator",O=b?`${r?.user.id||""}:${b.id}:${b.role}`:"",ie=s.useRef(O);ie.current=O,ry(r&&b&&!h&&!p?{accessToken:r.access_token,refreshToken:r.refresh_token,expiresAt:r.expires_at,user:{id:r.user.id,email:r.user.email},workspaceId:b.id,workspaceKind:b.kind,workspaceRole:b.role,membershipRevision:b.membershipRevision}:null);const{target:J,error:de,refresh:se}=ZS(r,G,ne),pe=s.useMemo(()=>{if(!J?.active)return null;const n=J.expires_at?Date.parse(J.expires_at):Number.POSITIVE_INFINITY;return Number.isFinite(n)&&n<=Date.now()?null:J},[J]),ce=s.useMemo(()=>Zp(pe),[pe]),W=wi(),ee=e.trim().replace(/\/+$/,""),L=s.useMemo(()=>[...new Set((W?ce:[ee,...ce,Tn]).filter(Boolean))],[W,ce,ee]),[_,K]=s.useState(null),[ue]=s.useState(lk),[P,N]=s.useState(!1),[te,we]=s.useState(()=>typeof window>"u"?!1:!!window.navigator.standalone||window.matchMedia("(display-mode: standalone), (display-mode: fullscreen)").matches),[me,Fe]=s.useState(()=>typeof window<"u"&&Qf(window.matchMedia(Gf).matches,te,window.matchMedia("(pointer: coarse)").matches)),H=W&&me;s.useEffect(()=>{if(!W){K(null);return}const n=window.matchMedia("(display-mode: standalone), (display-mode: fullscreen)"),o=()=>we(n.matches||!!window.navigator.standalone),l=d=>{d.preventDefault(),K(d)},m=()=>{K(null),we(!0)};return o(),n.addEventListener("change",o),window.addEventListener("beforeinstallprompt",l),window.addEventListener("appinstalled",m),()=>{n.removeEventListener("change",o),window.removeEventListener("beforeinstallprompt",l),window.removeEventListener("appinstalled",m)}},[W]);const R=s.useCallback(async()=>{const n=_;if(!n){ue.isIos&&N(!0);return}K(null);try{await n.prompt(),(await n.userChoice).outcome==="accepted"&&we(!0)}catch(o){K(n),console.warn("[VuvoDesk] PWA install prompt failed.",o)}},[ue.isIos,_]);s.useEffect(()=>{const n=window.matchMedia(Gf),o=window.matchMedia("(pointer: coarse)"),l=()=>Fe(Qf(n.matches,te,o.matches));return l(),n.addEventListener("change",l),o.addEventListener("change",l),()=>{n.removeEventListener("change",l),o.removeEventListener("change",l)}},[te]),s.useLayoutEffect(()=>{const n=document.documentElement,o=()=>{n.classList.remove("livedesk-mobile-console-active"),n.style.removeProperty("--livedesk-mobile-viewport-height"),n.style.removeProperty("--livedesk-mobile-viewport-top"),n.style.removeProperty("--livedesk-mobile-viewport-width"),n.style.removeProperty("--livedesk-mobile-viewport-left"),n.style.removeProperty("--livedesk-mobile-ios-top-guard")};if(!me){o();return}n.classList.add("livedesk-mobile-console-active");const l=window.visualViewport,m=document.createElement("div");m.setAttribute("aria-hidden","true"),m.style.cssText="position:fixed;visibility:hidden;pointer-events:none;padding-top:env(safe-area-inset-top);",document.body.appendChild(m);let d=0;const C=()=>{d=0;const S=Math.max(window.innerHeight,document.documentElement.clientHeight),y=i0(l,S,window.innerWidth,te||ue.isIos,te||ue.isIos||ue.isAndroid),w=Number.parseFloat(window.getComputedStyle(m).paddingTop),Z=o0({isIos:ue.isIos,standalone:te,safeAreaTop:w,screenHeight:window.screen.height,layoutViewportHeight:S});n.style.setProperty("--livedesk-mobile-viewport-height",`${y.height}px`),n.style.setProperty("--livedesk-mobile-viewport-top",`${y.offsetTop}px`),n.style.setProperty("--livedesk-mobile-viewport-width",`${y.width}px`),n.style.setProperty("--livedesk-mobile-viewport-left",`${y.offsetLeft}px`),n.style.setProperty("--livedesk-mobile-ios-top-guard",`${Z}px`)},v=()=>{d||(d=window.requestAnimationFrame(C))};return C(),l?.addEventListener("resize",v),l?.addEventListener("scroll",v),window.addEventListener("resize",v),window.addEventListener("orientationchange",v),window.addEventListener("pageshow",v),()=>{d&&window.cancelAnimationFrame(d),l?.removeEventListener("resize",v),l?.removeEventListener("scroll",v),window.removeEventListener("resize",v),window.removeEventListener("orientationchange",v),window.removeEventListener("pageshow",v),m.remove(),o()}},[ue.isAndroid,ue.isIos,me,te]);const[Se,Ce]=s.useState(mM),Ve=s.useMemo(()=>L.some(n=>!!gl(n)),[L]),Ze=!!(r&&b&&!h&&!p&&!f),_e=vC({workspaceReady:Ze,desktopShell:t,publicConsole:W,authenticated:!!r,managerNeedsLocalAccess:Ve,localHubAccessEnabled:Se}),{status:z,devices:Me,error:Be,connectionState:Ge,failure:xt,refresh:Pe,retry:He,hubBaseUrl:Y}=JS(L,_e,r?.access_token||"",O,G,b?.kind||""),ve=s.useRef(null),st=s.useRef(0),[it,bt]=s.useState(0),Rt=s.useCallback(n=>{const o=l=>{ve.current===n&&n.record({type:"hub.request.failed",component:"pwa-diagnostic-control",state:"failed",reason:l instanceof Error?l.message:String(l),details:{transport:"authenticated-hub-http"}})};n.flushWithOneFollowUp(o)},[]),ae=s.useCallback(n=>{const o=ve.current;if(!o)return!1;let l=!1;for(const m of n)l=o.record(m).accepted||l;return l&&Rt(o),l},[Rt]),$=s.useCallback(n=>ae([n]),[ae]);s.useEffect(()=>{const n=String(r?.user?.id||"").trim(),o=String(Y||"").trim();if(t||!Ze||!n||!o){ve.current=null;return}const l=st.current+1;st.current=l;let m=!1,d=null;return mr(async()=>{const{createPwaRuntimeDiagnosticLane:C}=await import("./pwa-runtime-diagnostic-lane-CXJ3zl5c.js");return{createPwaRuntimeDiagnosticLane:C}},[]).then(({createPwaRuntimeDiagnosticLane:C})=>{m||l!==st.current||(d=C({owner:{clientId:n,sessionId:"unknown"},sendBatch:(v,{signal:S})=>Ue("/api/remote/pwa-diagnostics",{method:"POST",signal:S,timeoutMs:15e3,body:JSON.stringify(v)},o)}),ve.current=d,d.record({type:"client.started",component:"pwa-runtime",state:"active",reason:"diagnostic-owner-created",details:{ownerGeneration:l,workspaceId:G||"unknown",workspaceRole:b?.role||"unknown",managerHubUrl:o,startup:ay()}}),d.record({type:"visibility.changed",component:"document",state:document.visibilityState==="visible"?"visible":"hidden",reason:"initial-current-visibility",details:{source:"current-document-state"}}),Rt(d),bt(v=>v+1))}).catch(()=>{m||console.warn("[VuvoDesk] PWA lifecycle diagnostics are unavailable.")}),()=>{m=!0,ve.current===d&&(ve.current=null),d?.dispose()}},[b?.role,G,t,Rt,Y,r?.user?.id,O,Ze]),s.useEffect(()=>{if(!ve.current)return;const n=_u();ae([{type:"session.changed",component:"authenticated-workspace",state:Ze?"ready":"unknown",reason:`workspace:${G||"unknown"}:revision:${ne}:role:${b?.role||"unknown"}`,details:{clientId:r?.user?.id||"unknown",workspaceId:G||"unknown",workspaceRevision:ne,workspaceRole:b?.role||"unknown"}},{type:"session.changed",component:"hub-manager",state:String(Ge||(z?.started?"ready":"unknown")),reason:Be?`error:${Be}:manager:${z?.deviceId||"unknown"}`:`manager:${z?.deviceId||"unknown"}:version:${z?.managerVersion||"unknown"}:role:${z?.runtimeRole||"unknown"}`,details:{managerHubUrl:Y||"unknown",managerDeviceId:z?.deviceId||"unknown",managerPackage:z?.managerPackage||"unknown",managerVersion:z?.managerVersion||"unknown",runtimeRole:z?.runtimeRole||"unknown",hubError:Be||"unknown",directStage:n.stage||"unknown",directReady:n.directReady===!0}}])},[b?.role,G,ne,Ge,Be,Y,it,ae,r?.user?.id,z?.deviceId,z?.managerPackage,z?.managerVersion,z?.runtimeRole,z?.started,Ze]);const ye=s.useCallback(()=>E(),[E]),V=q0(r,b,Y,ye,q),[Ke,Ct]=s.useState(!1);s.useEffect(()=>{if(!z?.started){Ct(!1);return}const n=new AbortController;return Ue("/api/remote/wall-preferences",{signal:n.signal},Y).then(o=>{Ct(o.wallPreferences?.showThisComputer===!0)}).catch(o=>{n.signal.aborted||(Ct(!1),console.warn("[VuvoDesk] Computer visibility setting could not be loaded.",o))}),()=>n.abort()},[Y,z?.started]);const{entitlement:I,licensed:oe,loading:Ee,error:We,refresh:vt}=eC(r,G,ne,b?.plan,b?.entitlementStatus,ye),[et,Tt]=s.useState([]),[jt,Jt]=s.useState(""),[At,zt]=s.useState(""),[g,U]=s.useState(""),[F,he]=s.useState(""),[Q,Te]=s.useState(""),[ge,Ye]=s.useState("idle"),dt=s.useRef("idle"),Re=s.useCallback(n=>{const o=typeof n=="function"?n(dt.current):n;dt.current=o,Ye(o)},[]),[Qe,je]=s.useState(!1),[Bt,ft]=s.useState(""),[ct,ht]=s.useState(null),Xe=s.useRef(null),[yt,Ut]=s.useState(""),Ri=s.useRef("");Ri.current=F;const[Mn,jn]=s.useState(!1);s.useLayoutEffect(()=>{Ct(!1),Tt([]),Jt(""),zt(""),U(""),he(""),Re("idle"),je(!1),ht(null),jn(!1)},[O]);const[Ai,Os]=s.useState([]),Ll=s.useRef(null),Ii=s.useRef(null),rm=s.useRef(null),_s=s.useRef(!1),am=s.useRef({key:"",source:"",at:0}),[om,im]=s.useState(!1),[Zt,Dr]=s.useState(!1),Na=s.useRef(""),mt=s.useRef(new Map),Ro=s.useRef(0),js=s.useRef(!1),Bs=s.useRef(""),sm=s.useRef(O),Ol=s.useRef(O);Ol.current=O;const Hs=s.useRef(null);Hs.current||(Hs.current=h0());const _l=s.useRef(document.visibilityState==="visible"),[ra,cm]=s.useState({}),at=s.useRef({}),Ti=s.useRef(new Set),aa=s.useRef(new Map),Fa=s.useRef(new Map),[Ao,lm]=s.useState({}),Pi=s.useMemo(()=>new Set(Object.keys(ra)),[ra]),Ws=s.useCallback((n,o)=>{if(!n)return;const l={...at.current};o?l[n]=o:delete l[n],at.current=l,cm(l)},[]),Io=s.useCallback((n,o)=>{n&&lm(l=>{if(!!l[n]===o)return l;const m={...l};return o?m[n]=!0:delete m[n],m})},[]),um=s.useCallback((n,o)=>{n&&Fa.current.set(n,{paused:o,expiresAt:Date.now()+Gk})},[]),[nt,xn]=s.useState(""),[an,To]=s.useState(""),[Po,jl]=s.useState(!1),dm=s.useRef(null),mm=s.useRef(null);s.useEffect(()=>{nt==="auth"&&r?.access_token&&xn("")},[nt,r?.access_token]);const[Bl,pm]=s.useState(""),[Da,$s]=s.useState(null),tr=s.useRef(null),Sb=s.useRef(0),Vs=s.useRef(0),zs=s.useCallback((n,o,l)=>{const m=String(n||"").trim();if(pm(m),tr.current!==null&&(window.clearTimeout(tr.current),tr.current=null),!m)return Vs.current=0,$s(null),0;const d=++Sb.current;if(Vs.current=d,$s({id:d,message:m,tone:o}),!l)return d;const C=window.setTimeout(()=>{$s(v=>v?.id===d?null:v),tr.current===C&&(tr.current=null)},5e3);return tr.current=C,d},[]),j=s.useCallback((n,o="info")=>zs(n,o,!0),[zs]);s.useEffect(()=>{A&&j(A,"error")},[j,A]),s.useEffect(()=>{x&&j(x,/joined/i.test(x)?"success":"error")},[x,j]),s.useEffect(()=>{V.error&&j(V.error,"error")},[j,V.error]),s.useEffect(()=>{f&&j("Hub sign-out could not be confirmed. Wall and Control remain blocked; open Account and retry when the Hub is reachable.","error")},[f,j]);const fm=s.useCallback((n,o)=>{const l=String(o||"").trim();!l||n<=0||Vs.current!==n||(Vs.current=0,tr.current!==null&&(window.clearTimeout(tr.current),tr.current=null),pm(m=>m===l?"":m),$s(m=>m?.id===n&&m.message===l?null:m))},[]),Bn=s.useCallback(n=>{zs(n,"progress",!1)},[zs]);s.useEffect(()=>()=>{tr.current!==null&&window.clearTimeout(tr.current)},[]);const[Pt,La]=s.useState(()=>typeof window>"u"?"wall":window.location.pathname.startsWith("/support")?"support":new URLSearchParams(window.location.search).get("view")==="pricing"?"pricing":"wall");s.useEffect(()=>{const n=()=>{La(window.location.pathname.startsWith("/support")?"support":o=>o==="support"?"wall":o)};return window.addEventListener("popstate",n),()=>window.removeEventListener("popstate",n)},[]);const[Eo,hm]=s.useState(AM),[Oa,gm]=s.useState(kM),_a=s.useRef(Eo),oa=s.useRef(Oa);_a.current=Eo,oa.current=Oa;const Hn=Rs(Oa),[Pn,No]=s.useState(Hn),Hl=s.useRef(null);Hl.current||(Hl.current=p0(O));const En=Hl.current;En.switchOwner(O);const Lr=s.useRef(null),Wn=s.useRef(null);s.useLayoutEffect(()=>{Wn.current!==null&&(window.clearTimeout(Wn.current),Wn.current=null),Lr.current=null,oa.current="fast",_a.current=ta,gm("fast"),No(Rs("fast")),hm(ta)},[O]);const ia=s.useCallback(n=>{const o=Xg(n,{cadence:oa.current,viewScale:_a.current});return oa.current!==o.cadence&&(oa.current=o.cadence,gm(o.cadence),No(Rs(o.cadence)),MM(o.cadence)),_a.current!==o.viewScale&&(_a.current=o.viewScale,hm(o.viewScale),IM(o.viewScale)),o},[]);s.useEffect(()=>{const n=z?.wallPreferences;if(!n)return;const o=Math.max(0,Number(n.revision)||0);if(!En.acceptSnapshot(O,o))return;const l=Lr.current;l&&(l.cadence!==n.cadence||l.viewScale!==xi(n.viewScale))||(l&&(Lr.current=null),ia(n))},[ia,z?.wallPreferences,En,O]);const Us=s.useCallback(async(n,o)=>{const l=()=>En.ownsWrite(o)&&ie.current===O;if(!l())return;let m=!1;const d=S=>m||!l0({error:S,publicConsole:wi(),workspaceKind:b?.kind,workspaceRole:b?.role,workspaceId:G,userId:r?.user.id})?!1:(m=!0,!0);let C=En.readRevision(O);if(C===void 0)try{for(;;)try{const S=await Ue(sd(m),void 0,Y);if(!l()||(C=Math.max(0,Number(S.revision)||0),!En.commitWriteRevision(o,C)))return;break}catch(S){if(!l())return;if(d(S))continue;throw S}}catch{if(!l())return;Lr.current=null,Pe(),j("Wall view changed here, but Hub synchronization failed.","error");return}let v=!1;for(let S=0;S<3;S+=1)try{const y=await Ue(sd(m),{method:"PATCH",body:JSON.stringify(u0({legacy:m,revision:C,preferences:n}))},Y);if(!l()||!En.commitWriteRevision(o,y.revision))return;const w=d0(y,m);if(!c0(w,n)){Lr.current=null,Pe(),j("Update the Hub to synchronize Wall controls.","error");return}Lr.current=null,ia(w),Pe();return}catch(y){if(!l())return;if(d(y))continue;if(/^409\s/.test(y instanceof Error?y.message:String(y))&&!v)try{const Z=await Ue(sd(m),void 0,Y);if(!l()||(C=Math.max(0,Number(Z.revision)||0),!En.commitWriteRevision(o,C)))return;v=!0;continue}catch{}Lr.current=null,Pe(),j("Wall view changed here, but Hub synchronization failed.","error");return}},[b?.kind,b?.role,G,ia,Y,Pe,r?.user.id,j,En,O]),qs=s.useCallback((n,o)=>{Wn.current!==null&&(window.clearTimeout(Wn.current),Wn.current=null);const l=ia({cadence:n,viewScale:o}),m=En.beginWrite(O);m&&(Lr.current=l,Us(l,m))},[ia,Us,En,O]),Cb=s.useCallback(n=>{const o=ia({cadence:oa.current,viewScale:xi(n)}),l=En.beginWrite(O);return l&&(Lr.current=o,Wn.current!==null&&window.clearTimeout(Wn.current),Wn.current=window.setTimeout(()=>{Wn.current=null,Us({cadence:oa.current,viewScale:_a.current},l)},250)),o},[ia,Us,En,O]);s.useEffect(()=>()=>{Wn.current!==null&&window.clearTimeout(Wn.current)},[]);const Ht=D0(Eo),bm=s0(Eo),vm=s.useCallback(n=>{qs(oa.current,n==="list"?Tl:n==="medium"?E0:ta)},[qs]),ym=s.useCallback(n=>{qs(n,_a.current)},[qs]),[kb,wm]=s.useState(!1);s.useEffect(()=>{if(wm(!1),Ht!=="list")return;const n=window.setTimeout(()=>{wm(!0)},Wd);return()=>window.clearTimeout(n)},[Ht]);const Ei=m0({wallSize:Ht,elapsedMs:kb?Wd:0});s.useLayoutEffect(()=>{!re||Pt==="wall"||Pt==="control"||Pt==="doc"||Pt==="support"||(La("wall"),jn(!1))},[Pt,re]);const Wl=L0(Eo),Sm=s.useMemo(()=>({"--wall-tile-min-width":`${Wl}px`}),[Wl]),Mb=Ht==="list"?"List view":`${Ht==="medium"?"Small":"Large"} tiles, ${Wl} pixel minimum width`,[Ni,xb]=s.useState(xM),[fn,Gs]=s.useState(!1),[qt,Ks]=s.useState(!1),[pr,Ys]=s.useState(!1),[Fi,Rb]=s.useState(null),[$n,Fo]=s.useState(null),[Do,Lo]=s.useState(!1),[Ab,Qs]=s.useState(Date.now),Or=s.useRef(null),Cm=s.useRef(null),$l=s.useRef(null),sa=s.useRef(0);s.useEffect(()=>()=>{sa.current+=1,Or.current!==null&&window.clearTimeout(Or.current)},[]);const[ja,Ib]=s.useState(HM),[Ba,km]=s.useState(!1),[ca,_r]=s.useState(!1),Xs=s.useRef(ca);s.useLayoutEffect(()=>{Xs.current=ca},[ca]);const[qM,GM]=s.useState(!1),[Oo,Mm]=s.useState(dM),[De]=s.useState(yM),xm=me?Ni:De.showScreenStatus,[on]=s.useState(SM),[Vl]=s.useState(bM),[gt,zl]=s.useState(Vl.selections),Rm=s.useRef({...Vl.topologyFingerprints}),Di=s.useRef({}),Am=s.useRef({...Vl.selections}),[tt,fr]=s.useState(null),[Js,Ul]=s.useState({}),ql=s.useRef(new Set),[Gl,Zs]=s.useState([]),[Li,Tb]=s.useState(""),[Pb,Eb]=s.useState(0),[Nb,Im]=s.useState(0),[Fb,Db]=s.useState(0),[Kl,Oi]=s.useState(()=>new Set),lt=s.useRef(new Map),hn=s.useRef(new Map),jr=s.useRef(new Map),_i=s.useRef(new Set),Et=s.useRef(new Map),Ha=s.useRef(null),Wa=s.useRef(new Map),Br=s.useRef(new Set),la=s.useRef(new Map),_o=s.useRef(new Map),$a=s.useRef(new Map),Vn=s.useRef(new Map),ec=s.useRef(new WeakMap),tc=s.useRef(new WeakMap),ua=s.useRef(""),Rn=s.useRef(null),Tm=s.useRef(Promise.resolve()),nc=s.useRef(0),jo=s.useRef(null),Nn=s.useRef(null),ji=s.useRef(""),en=s.useRef(new Map),Bo=s.useRef(null),Bi=s.useRef(0),da=s.useRef(new Map),rc=s.useRef(typeof window<"u"&&new URLSearchParams(window.location.search).get("livedeskTransmissionProbe")==="1"),ac=s.useRef(new Map),Yl=s.useRef([]),Pm=s.useRef(0),[oc,Ql]=s.useState({}),Va=s.useRef(new Map),[ic,sc]=s.useState({}),cc=s.useRef(null),[Xl,gn]=s.useState(!1),lc=s.useRef(null),Lb=s.useRef(0),Hr=s.useRef(null),Em=s.useRef(new Map),nr=s.useRef(null),zn=s.useRef(null),wt=s.useRef(null),Hi=s.useRef(!1),Nm=s.useRef(0),Wt=s.useRef(0),sn=s.useRef(""),Fm=s.useRef(Promise.resolve()),Ho=s.useRef(""),ke=s.useRef(null),Un=s.useRef(""),za=s.useRef(null),Wo=s.useRef(0),Wi=s.useRef(""),Wr=s.useRef(new Map),hr=s.useRef(new Map),uc=s.useRef(performance.now()),ma=s.useRef(new Map),Fn=s.useRef(new Map),pa=s.useRef(new Map),$r=s.useRef(new Map),Vr=s.useRef(new Map),gr=s.useRef(new Map),qn=s.useRef(document.visibilityState==="visible"),rr=s.useRef(1),Jl=s.useRef([]),[Gt,Ob]=s.useState(document.visibilityState==="visible"),[_b,jb]=s.useState(0),$i=s.useRef(0),dc=s.useRef(0),mc=s.useRef(0),pc=s.useRef(0),Zl=s.useRef(0),eu=s.useRef(new Map),Vi=s.useRef([]),Dm=s.useRef(new Map),Lm=s.useRef(new Map),Nt=s.useRef(new Map),zr=s.useRef(new Map),$o=s.useRef(new Map),tu=s.useRef({}),fc=s.useRef(new Set),kt=s.useCallback((n,o,l,m,d)=>{const C=ut(n,o),v=performance.now(),S=Wr.current.get(C)||0,y=hr.current.get(C)||0,w=n==="control"?ke.current:null,Z=w?.deviceId===o?er({...w,streamPurpose:"control"}):Vn.current.get(o)||"",be=n==="control"?Et.current.get(o)||null:lt.current.get(o)||null,D=be?ps(be,{includeLifecycleEvents:!1}).canvases[0]:void 0,fe=D?{state:String(D.decoderState||"unknown"),requestedAcceleration:String(D.requestedAcceleration||"unknown"),configuredAcceleration:String(D.configuredAcceleration||"unknown"),inputCount:Math.max(0,Number(D.inputCount||0)),outputCount:Math.max(0,Number(D.outputCount||0)),lastInputAgeMs:Number.isFinite(Number(D.lastInputAgeMs))?Math.max(0,Number(D.lastInputAgeMs)):"unknown",lastOutputAgeMs:Number.isFinite(Number(D.lastOutputAgeMs))?Math.max(0,Number(D.lastOutputAgeMs)):"unknown",lastPaintAgeMs:Number.isFinite(Number(D.lastPaintAgeMs))?Math.max(0,Number(D.lastPaintAgeMs)):"unknown",decodeQueueSize:Math.max(0,Number(D.decodeQueueSize||0)),renderQueueSize:Math.max(0,Number(D.renderQueueSize||0)),softwareFallbackReason:String(D.softwareFallbackReason||"none"),softwareFallbackCount:Math.max(0,Number(D.softwareFallbackCount||0)),forcedSoftware:n==="wall"&&_i.current.has(o)}:void 0,xe={scope:n,deviceId:o,stage:l,reason:m,at:Date.now(),attempts:Math.max(0,Math.floor(Number(d)||0)),receiveAgeMs:S>0?Math.max(0,v-S):-1,paintAgeMs:y>0?Math.max(0,v-y):-1,bindingKey:Z,decoder:fe};$o.current.set(C,xe),console.info("[VuvoDesk frame recovery]",xe);const Oe=ve.current;if(!Oe)return;const ze={type:"frame.recovery.changed",component:`frame-recovery:${n}:${o}`,state:l,reason:m,details:{scope:n,deviceId:o,attempts:xe.attempts,receiveAgeMs:xe.receiveAgeMs>=0?xe.receiveAgeMs:"unknown",paintAgeMs:xe.paintAgeMs>=0?xe.paintAgeMs:"unknown",bindingKey:Z||"unknown",decoder:fe||"unknown"}};if(l==="stable"){queueMicrotask(()=>{ve.current===Oe&&Oe.record(ze).accepted&&Rt(Oe)});return}$(ze)},[Rt,$]),Vo=s.useCallback(n=>nS(ec.current,n),[]),zo=s.useCallback(n=>Kd(tc.current,n),[]),Ua=s.useCallback((n,o)=>Sf(tc.current,n,o),[]),Vt=s.useCallback(n=>{const o=wf(ec.current,n);return wf(tc.current,n),o},[]),Uo=s.useCallback((n,o)=>Sf(ec.current,n,o),[]),Om=s.useCallback(n=>Nn.current===n||Ha.current===n?!0:[lt.current,hn.current,jr.current,Et.current,en.current].some(l=>Array.from(l.values()).some(m=>m===n)),[]),bn=s.useCallback(n=>{n&&(Vt(n),fc.current.add(n),oS(n,{isCurrent:Om,dispose:fi,schedule:o=>queueMicrotask(()=>{try{o()}finally{fc.current.delete(n)}})}))},[Om,Vt]),vn=s.useCallback(n=>(Vt(n),Fl(n,fi)),[Vt]),_m=s.useCallback(()=>{const n=Nn.current,o=Ha.current,l=[...fc.current];Nn.current=null,Ha.current=null,fc.current.clear(),ec.current=new WeakMap,tc.current=new WeakMap,Vn.current.clear(),_i.current.clear(),ji.current="",aS([lt.current,hn.current,jr.current,Et.current,en.current],[n,o,...l],fi),Bo.current=null,Bi.current=0,Wa.current.clear(),Br.current.clear(),la.current.clear(),_o.current.clear(),$a.current.clear(),da.current.clear(),ac.current.clear(),Yl.current.length=0,Va.current.clear(),Wr.current.clear(),hr.current.clear(),ma.current.clear(),Fn.current.clear(),pa.current.clear(),$r.current.clear(),Vr.current.clear(),gr.current.clear(),Nt.current.clear(),zr.current.clear(),$o.current.clear(),Ti.current.clear()},[]);s.useEffect(()=>()=>{_m()},[_m]);const Ur=s.useCallback((n,o,l={})=>{const m=ut(n,o);Wr.current.delete(m),hr.current.delete(m),ma.current.delete(m),Fn.current.delete(m),gr.current.delete(m),Nt.current.delete(m),zr.current.delete(m),l.preserveLatestDiagnostic!==!0&&$o.current.delete(m),Va.current.delete(m),da.current.delete(m),pa.current.delete(m),$r.current.delete(m),Vr.current.delete(m),sc(d=>{if(!Object.prototype.hasOwnProperty.call(d,m))return d;const C={...d};return delete C[m],C}),Ql(d=>{if(!Object.prototype.hasOwnProperty.call(d,m))return d;const C={...d};return delete C[m],C})},[]),Dt=s.useCallback((n,o,l={})=>{const m=ut(n,o),d=performance.now();Ur(n,o,l),n==="control"?$r.current.set(m,d):Vr.current.set(m,d)},[Ur]),[qa,fa]=s.useState(null),[Bb,nu]=s.useState(!1),[KM,Hb]=s.useState([]),[qo,Wb]=s.useState("all"),[Go,ru]=s.useState([]),[YM,QM]=s.useState(!1),[XM,$b]=s.useState(!0),jm=s.useRef(null),Bm=s.useRef(null),Vb=s.useRef(null),zb=s.useRef(null),Ub=s.useRef(!1),au=s.useRef(!1),zi=s.useRef(0),br=s.useRef(0),vr=s.useRef(0),ar=s.useRef(0),Ui=s.useRef(0),qi=s.useRef(""),ou=s.useRef({}),Gi=Pt==="settings"&&!re,Hm=!re&&Pt==="pricing",Wm=Pt==="doc",$m=Pt==="support",Ga=!re&&Pt==="share-files",hc=!re&&Pt==="agents",qr=!Gi&&!Hm&&!Wm&&!$m&&!Ga&&!hc,Ae=Pt==="control",Vm=y0(Pt),or=Gt&&Pt==="wall"&&!Ei,zm=s.useRef(or);zm.current=or;const qb=!H&&Vm&&Vi.current.length>0,yr=Gt&&(Pt==="wall"&&!Ei||!H&&Ae||qb),Ko=s.useRef(yr);Ko.current=yr;const gc=Gt&&(Ae||or),Yo=Gt&&(gc||Vm&&(ge==="connecting"||ge==="active")),iu=s.useRef({active:yr,epoch:rr.current});iu.current.active!==yr&&(rr.current+=1,iu.current={active:yr,epoch:rr.current}),s.useEffect(()=>{qr||(Gs(!1),Ks(!1),Ys(!1))},[qr]);const rt=De.frameMode==="mode4-h264-atlas",Gn=Q||on.frameMode,Gb=Gn!=="mode3-h264-hw"?Math.min(30,on.fps):on.fps,Ki=n0(Gb,H),Qo=Me.find(n=>n.deviceId===At),Kb=Qo?.platform,Yb=Qo?_n(Qo,gt[Qo.deviceId]):0,bc=Qo?nm(Qo,Yb):null,Um=zM(Kb)?{maxWidth:1280,maxHeight:720}:Ah,qm=Gn!=="mode3-h264-hw"?{maxWidth:1920,maxHeight:1080}:Ah,vc={maxWidth:Math.min(qm.maxWidth,Um.maxWidth,on.maxWidth),maxHeight:Math.min(qm.maxHeight,Um.maxHeight,on.maxHeight)},wr={maxWidth:bc?.width?Math.min(vc.maxWidth,bc.width):vc.maxWidth,maxHeight:bc?.height?Math.min(vc.maxHeight,bc.height):vc.maxHeight};s.useEffect(()=>{if(b?.kind!=="team"&&z?.started){if(!r?.access_token){Ue("/api/remote/license",{method:"DELETE"},Y).catch(()=>{});return}Ue("/api/remote/license/sync",{method:"POST",headers:{Authorization:`Bearer ${r.access_token}`},body:JSON.stringify({workspaceId:G})},Y).catch(n=>{console.warn("[VuvoDesk] Hub license sync failed",n)})}},[b?.entitlementStatus,b?.kind,G,ne,Y,r?.access_token,z?.started]),s.useEffect(()=>{!r?.access_token||b?.kind!=="personal"||b.role!=="owner"||!z?.started||z.runtimeRole!=="hub"||!z.deviceId||(async()=>{try{const{data:n,error:o}=await Mt.rpc("register_livedesk_device",{p_device_id:z.deviceId,p_device_name:z.deviceName||z.deviceId,p_role:"hub",p_assigned_hub_id:null,p_platform:navigator.platform||navigator.userAgent,p_os_version:navigator.userAgent,p_app_version:z.managerVersion||z.managerPackage||""}),l=Array.isArray(n)?n[0]:n;(o||l?.ok===!1)&&console.warn("[VuvoDesk] Hub device role registration failed",o||l?.reason||"unknown-error")}catch(n){console.warn("[VuvoDesk] Hub device role registration failed",n)}})()},[b?.kind,b?.role,r?.access_token,z?.deviceId,z?.deviceName,z?.managerPackage,z?.managerVersion,z?.runtimeRole,z?.started]);const Gr=z?.runtimeRole==="hub"?String(z.deviceId||"").trim():"",Le=s.useMemo(()=>Me.filter(n=>n.connected&&(me||Ke||!Gr||n.deviceId!==Gr)),[Me,Gr,me,Ke]),Ka=s.useMemo(()=>Le.filter(n=>!Gr||n.deviceId!==Gr),[Le,Gr]);s.useEffect(()=>{const n={...at.current},o=Date.now();let l=!1;lm(m=>{const d={...m};let C=!1;for(const v of Me){const S=String(v.liveCapturePause?.token||"").trim(),y=Fa.current.get(v.deviceId);if(y)if((y.paused?!!S:!S)||y.expiresAt<=o)Fa.current.delete(v.deviceId);else continue;const w=!!S&&(v.liveCapturePause?.captureStopConfirmed!==!0||v.liveCapturePause?.phase==="stop-unconfirmed");!!d[v.deviceId]!==w&&(C=!0,w?d[v.deviceId]=!0:delete d[v.deviceId])}return C?d:m});for(const m of Me){const d=String(m.liveCapturePause?.token||"").trim(),C=String(n[m.deviceId]||""),v=Fa.current.get(m.deviceId);if(v)if((v.paused?!!d:!d)||v.expiresAt<=o)Fa.current.delete(m.deviceId);else continue;d&&d!==C?(n[m.deviceId]=d,l=!0):!d&&C&&(delete n[m.deviceId],aa.current.delete(m.deviceId),l=!0)}l&&(at.current=n,cm(n))},[Me]);const Gm=qo==="all"?Le.length:Go.filter(n=>Le.some(o=>o.deviceId===n)).length,Qb=s.useMemo(()=>Le.reduce((n,o)=>Math.max(n,Vh(o.slotNumber)),0),[Le]),yc=Math.max(bk,Le.length,Qb),ha=s.useMemo(()=>{const n=Array(yc).fill(null),o=[];for(const l of Le){const m=Vh(l.slotNumber);m>0&&m<=yc&&!n[m-1]?n[m-1]=l:o.push(l)}for(const l of o){const m=n.findIndex(d=>!d);m<0?n.push(l):n[m]=l}return n},[Le,yc]),Km=s.useMemo(()=>me?ha.filter(n=>!!n):ha,[me,ha]),Ym=s.useMemo(()=>ha.flatMap((n,o)=>n?[{device:n,slotNumber:o+1}]:[]),[ha]),wc=s.useMemo(()=>Le.map(n=>n.deviceId),[Le]),Ya=s.useMemo(()=>new Set(et),[et]),cn=s.useMemo(()=>Le.filter(n=>Ya.has(n.deviceId)),[Le,Ya]),ga=s.useMemo(()=>Me.find(n=>n.deviceId===jt)||cn[0]||null,[Me,jt,cn]),tn=s.useMemo(()=>Me.find(n=>n.deviceId===At)||null,[At,Me]),ir=tn?_n(tn,gt[tn.deviceId]):0,X=Ae?tn:ga,Qm=s.useMemo(()=>new Set(Go),[Go]),Xb=s.useMemo(()=>qo==="all"?Le.map(n=>n.deviceId):Le.filter(n=>Qm.has(n.deviceId)).map(n=>n.deviceId),[Le,Qm,qo]),Jb=X?yi(X,"control"):!1,su=Nr(X?.platform)&&(X?.capabilities?.controlPermission===!1||X?.capabilities?.accessibilityPermission===!1),sr=X?yi(X,"audio")||yi(X,"remoteAudio"):!1,Xo=(Array.isArray(X?.capabilities?.agentTools)?X.capabilities.agentTools.map(String):[]).includes("system.power"),cu=b?.entitlementStatus==="active"&&b.plan!=="free"?b.plan:oe?I?.plan:null,Je=cu==="team"?"team":cu==="pro"?"pro":cu==="ltd"?"ltd":"free",Xm=$e[Je],Sc=b?.deviceLimit??Xm.limit,Sr=s.useMemo(()=>{const n=new Set(k0(Ka,Sc));return Gr&&n.add(Gr),n},[Sc,Gr,Ka]),pt=!X||Sr.has(X.deviceId),Jo=Je==="ltd"?`Plus includes up to ${ds} Clients. Upgrade to Pro for schools, academies, commercial use, and larger walls.`:Je==="pro"?`Pro includes up to ${ju} Clients for schools, academies, and commercial use.`:Je==="team"?"Team includes every connected Client in this shared commercial workspace.":`Free includes up to ${Bu} Clients. Upgrade to Plus for ${ds} devices and no ads.`,Zb=Je==="free",Cr=pt&&!!X&&Jb,Jm=pt&&!!X&&sr,Yi=s.useMemo(()=>Ae?X?[X]:[]:cn.length>0?cn:X?[X]:[],[X,cn,Ae]),Dn=s.useMemo(()=>Yi.filter(n=>Sr.has(n.deviceId)),[Sr,Yi]),Cc=Dn.some(n=>String(ra[n.deviceId]||"").startsWith("pending:")||Ao[n.deviceId]===!0),Qi=!(Dn.length>0&&Dn.every(n=>{const o=String(ra[n.deviceId]||"");return!!o&&!o.startsWith("pending:")&&Ao[n.deviceId]!==!0}))||Cc,kc=s.useMemo(()=>ha.filter(n=>!!n?.connected).slice(0,TM(Ht)).map(n=>n.deviceId),[ha,Ht]),Mc=s.useMemo(()=>yr?or?rt||Ht==="list"?wc:De.visibleOnlyLive?Gl.length>0?Gl:kc:wc:Vi.current.length>0?Vi.current:wc:[],[kc,rt,Gl,De.visibleOnlyLive,wc,yr,or,Ht]),Kn=s.useMemo(()=>{const n=vd(Mc.filter(o=>Sr.has(o)));return t0(n,H,ga?.deviceId||"")},[H,Sr,Mc,ga?.deviceId]);Vi.current=Kn;const kr=s.useMemo(()=>Kn.filter(n=>n!==Li&&!Pi.has(n)),[Pi,Kn,Li]),xc=s.useMemo(()=>new Map(Le.map(n=>[n.deviceId,n.platform])),[Le]),yn=s.useMemo(()=>{const n=Object.fromEntries(Le.map(o=>[o.deviceId,String(o.sessionId||"").trim()]));return v0(tu.current,n)},[Le]);s.useLayoutEffect(()=>{tu.current=yn},[yn]);const ev=Jf(ou.current,yn)?Hn:Pn;s.useLayoutEffect(()=>{const n=ou.current,o=Jf(n,yn);ou.current={...yn};const l=new Set([...Object.keys(n),...Object.keys(yn)]),m=ve.current?[]:null;for(const d of l){const C=String(n[d]||"").trim(),v=String(yn[d]||"").trim();C!==v&&(console.info("[VuvoDesk frame session]",{deviceId:d,previousSessionId:C,currentSessionId:v,action:v?"fresh-recovery-owner":"owner-released"}),m?.push({type:"session.changed",component:`remote-device:${d}`,state:v?"connected":"disconnected",reason:`session:${v||C||"unknown"}`,details:{deviceId:d,previousSessionId:C||"unknown",currentSessionId:v||"unknown",action:v?"fresh-recovery-owner":"owner-released"}}),_i.current.delete(d),v?(Dt("wall",d),Dt("control",d)):(Ur("wall",d),Ur("control",d)))}m&&m.length>0&&ae(m),o&&(No(Hn),zi.current=Date.now(),br.current=0,vr.current=0,ar.current=0,Ui.current=0,qi.current="")},[Ur,yn,ae,Dt,Hn]),s.useEffect(()=>{if(!ve.current)return;const n=Object.entries(yn).filter(([,o])=>!!o).map(([o,l])=>({type:"session.changed",component:`remote-device:${o}`,state:"connected",reason:`session:${l}`,details:{deviceId:o,currentSessionId:l,action:"current-connected-owner"}}));n.length>0&&ae(n)},[yn,it,ae]);const Mr=M0(rt,Kn.length),nn=s.useMemo(()=>rt?kr.filter(n=>gs({mode4Enabled:rt,directMode4WallEnabled:Mr,isMac:Nr(xc.get(n))})==="atlas"):[],[Mr,rt,xc,kr]),Kt=s.useMemo(()=>kr.filter(n=>gs({mode4Enabled:rt,directMode4WallEnabled:Mr,isMac:Nr(xc.get(n))})==="direct"),[Mr,rt,xc,kr]),Zm=s.useMemo(()=>{const n=De.autoStartLive?kr.map(o=>ut("wall",o)):[];return Yo&&pt&&g&&Sr.has(g)&&(ge==="connecting"||ge==="active"||ge==="warm")&&n.push(ut("control",g)),[...new Set(n)].sort()},[Yo,g,ge,pt,Sr,De.autoStartLive,kr]);s.useEffect(()=>{const n=new Set(Kn);Oi(o=>{let l=!1;const m=new Set;for(const d of o)n.has(d)?m.add(d):l=!0;return l?m:o})},[Kn]);const tv=s.useMemo(()=>{const n=d=>Le.find(C=>C.deviceId===d)||null,o=d=>{const C=n(d);return C?_n(C,gt[d]):0},l=(d,C=o(d))=>d===g&&(ge==="connecting"||ge==="active"||ge==="warm")?Et.current.get(d)||hn.current.get(d)||null:rt?en.current.get(d)||lt.current.get(d)||null:lt.current.get(d)||null,m=(d,C=o(d))=>{const v=n(d);return`${v?Qt(v):d} · Monitor ${C+1}`};return{resolveCurrentTarget(){if(Ae&&tn){const y=ir;return{type:"control",deviceIds:[tn.deviceId],monitorIndex:y,label:`${Qt(tn)} · Monitor ${y+1}`,sourceCanvas:l(tn.deviceId,y),signature:`control:${tn.deviceId}:${y}:${on.frameMode}`}}const d=cn.map(y=>y.deviceId).filter(y=>kr.includes(y)),C=ga&&kr.includes(ga.deviceId)?ga.deviceId:"",v=d.length>0?d:C?[C]:kr,S=d.length===0&&!C;if(v.length===0)return null;if(v.length===1){const y=v[0],w=o(y);return{type:S?"wall":d.length>1?"selection":"device",deviceIds:v,monitorIndex:w,label:S?"Wall":m(y,w),sourceCanvas:S?null:l(y,w),signature:`${S?"wall":"device"}:${y}:${w}:${rt?"atlas":"direct"}`}}return{type:d.length>1?"selection":"wall",deviceIds:v,label:d.length>1?`${v.length} selected Clients`:"Wall",sourceCanvas:null,signature:`${d.length>1?"selection":"wall"}:${v.join(",")}:${Ht}`}},getDeviceCanvas:l,composeWall(d,C={}){return K0(d.map(v=>{const S=o(v);return{deviceId:v,label:m(v,S),canvas:l(v,S)}}),C)}}},[Le,tn,g,ge,on.frameMode,lt,rt,gt,ir,cn,Ae,kr,ga,Ht]),ep=ck({hubUrl:Y,remoteSettingsEnabled:!!(z?.started&&Y),sourceRegistry:tv,onToast:j}),Kr=s.useMemo(()=>w0({captureOwnershipActive:Yo,localFeatureAccess:pt,controlSessionDeviceId:g,planAllowed:Sr.has(g),sessionState:ge,controlFocusVisible:Ae,presentationCanvasMounted:Bt===g,wallPresentationVisible:or,wallPresentationCanvasMounted:lt.current.has(g)||en.current.has(g),decoderOwnerExists:Et.current.has(g)})?[g]:[],[Yo,g,ge,pt,Bt,Sr,Ae,or]),lu=s.useMemo(()=>vd([...Kn,...Kr]),[Kr,Kn]),Rc=s.useMemo(()=>Bh(De,Ht),[De,Ht]),Zo=s.useMemo(()=>Bh(De,"large"),[De]),Ac=x0({mode4Enabled:rt,directMode4WallEnabled:Mr,adaptiveFps:ev,directDeviceCount:Kt.length,adaptive:De.adaptiveLoadShedding}),ln=r0({fps:Ac,maxWidth:Zo.maxWidth,maxHeight:Zo.maxHeight,quality:De.quality},H,Kt.length),uu=T0({deviceCount:nn.length,targetFps:Pn,adaptive:De.adaptiveLoadShedding});rt&&nn.length>0;const Yr=s.useCallback((n,o,l,m=1)=>{if(n.width<=0||n.height<=0)return!1;if(n===o)return!0;const d=l?Math.min(1,l.maxWidth/n.width,l.maxHeight/n.height):1,C=Math.max(1,Math.round(n.width*d)),v=Math.max(1,Math.round(n.height*d)),S=o.width!==C||o.height!==v;S&&(o.width=C,o.height=v);const y=o.getContext("2d",{alpha:!1});if(!y)return!1;y.imageSmoothingEnabled=!0,y.imageSmoothingQuality="low";const w=y.globalAlpha;y.globalAlpha=S?1:Math.max(.05,Math.min(1,m));try{y.drawImage(n,0,0,n.width,n.height,0,0,o.width,o.height)}finally{y.globalAlpha=w}return!0},[]),Ic=s.useCallback((n,o)=>{const l=Math.max(0,Number(o.clientWidth||0)),m=Math.max(0,Number(o.clientHeight||0)),d=Math.max(1,Number(window.devicePixelRatio||1)),C=l>0&&m>0?{maxWidth:Math.ceil(l*d),maxHeight:Math.ceil(m*d)}:void 0;return Yr(n,o,C)},[Yr]),Tc=s.useCallback((n,o,l)=>{const m=Math.max(0,Math.floor(Number(n?.frameSeq||0))),d=o||(n?lt.current.get(n.deviceId):null),C=l||d,v=Math.max(0,Number(C?.width||0))*Math.max(0,Number(C?.height||0)),S=Math.max(lt.current.size,en.current.size);return a&&m>0&&(m+Hk(n?.deviceId||""))%pb===0&&S<=Bk&&ow(d)&&v>0&&v<=jk?_k:1},[a]),ei=s.useCallback((n,o,l)=>{if(!rc.current)return;const m=`${n}:${o.deviceId}`,d=ac.current.get(m)||{bindingKey:"",totalPaints:0,lastPaintAt:0,lastFrameSeq:0};d.bindingKey=er(o),d.totalPaints+=1,d.lastPaintAt=performance.now(),d.lastFrameSeq=Number(o.frameSeq||0),ac.current.set(m,d);const C=++Pm.current,v={sequence:C,scope:n,deviceId:o.deviceId,bindingKey:d.bindingKey,frameSeq:d.lastFrameSeq,paintedAt:d.lastPaintAt,sourceGapMs:Number(o.sourceGapMs||0),agentSendGapMs:Number(o.agentSendGapMs||0),agentSendDurationMs:Number(o.agentSendDurationMs||0),agentSendDurationFrameSeq:Number(o.agentSendDurationFrameSeq||0),agentFrameAgeMs:Number(o.agentFrameAgeMs||0),timestampUs:Number(o.timestampUs||0),queuedForMs:Number(l?.queuedForMs||0),decodedForMs:Number(l?.decodedForMs||0),scheduledForMs:Number(l?.scheduledForMs||0),interactiveBurstOutputWindowMs:Number(l?.interactiveBurstOutputWindowMs||0),interactiveBurstTailHoldCount:Number(l?.interactiveBurstTailHoldCount||0)};Yl.current[(C-1)%Qk]=v},[]),xr=s.useCallback(n=>{n&&Oi(o=>{if(o.has(n))return o;const l=new Set(o);return l.add(n),l})},[]),Rr=s.useCallback(n=>{n&&Oi(o=>{if(!o.has(n))return o;const l=new Set(o);return l.delete(n),l})},[]),Qa=s.useCallback((n,o)=>{if(!o||o.width<=0||o.height<=0)return!1;const l=document.createElement("canvas");if(l.width=o.width,l.height=o.height,!Yr(o,l))return bn(l),!1;const m=jr.current.get(n);return jr.current.set(n,l),m&&m!==l&&vn(m),xr(n),!0},[xr,Yr,vn,bn]),Yt=s.useCallback(n=>{rS(jr.current,n,fi)},[]),Pc=s.useCallback((n,o)=>{const l=jr.current.get(n),m=lt.current.get(n)===o||en.current.get(n)===o;return at.current[n]?(Yt(n),!1):!l||!m||l.width<=0||l.height<=0?!1:Yr(l,o)?!0:(Yt(n),!1)},[Yr,Yt]),Qr=s.useCallback((n,o=!1,l)=>{if(at.current[n]||!Br.current.has(n))return!1;const m=Math.max(1,Math.min(Hn,St.controlWallReuseMaxFps,Ki)),d=performance.now(),C=_o.current.get(n)||0,v=Et.current.get(n)||hn.current.get(n),S=lt.current.get(n)||en.current.get(n);if(!v||!S||!S.isConnected)return!1;const y=C0({cadenceCredit:la.current.get(n)||0,targetFps:m,sourceFps:Ki,elapsedSincePaintMs:C>0?d-C:0,nowMs:d,scheduledPaintAtMs:$a.current.get(n)||0,force:o});if(!y.shouldPaint)return la.current.set(n,y.nextCadenceCredit),!1;const w=Math.max(0,Number(S.clientWidth||0)),Z=Math.max(0,Number(S.clientHeight||0)),be=Math.max(1,Number(window.devicePixelRatio||1)),D=w>0&&Z>0?{maxWidth:Math.min(Rc.maxWidth,Math.ceil(w*be)),maxHeight:Math.min(Rc.maxHeight,Math.ceil(Z*be))}:Rc;return Yr(v,S,D,l?Tc(l,v,S):1)?(la.current.set(n,y.nextCadenceCredit),y.nextScheduledPaintAtMs>0&&$a.current.set(n,y.nextScheduledPaintAtMs),_o.current.set(n,performance.now()),y.sourceCadencePassthrough&&(la.current.delete(n),$a.current.delete(n)),l&&ei("wall-reuse-visible",l),xr(n),Yt(n),!0):!1},[Ki,Rc,xr,Yr,ei,Yt,Tc,Hn]);s.useEffect(()=>{ua.current=Li},[Li]);const Ec=s.useCallback((n,o)=>{const l=Hr.current;if(!l||l.deviceId!==n)return;const m=Date.now();Em.current.set(n,{...l,source:o,completedAtEpochMs:m,durationMs:Math.max(0,performance.now()-l.startedAt)}),Hr.current=null},[]),tp=s.useCallback((n,o)=>{const l=lt.current.get(n);if(o&&l&&l!==o&&Qa(n,l),o){if(lt.current.set(n,o),l&&l!==o&&bn(l),at.current[n]){Yt(n),vn(o),Rr(n);return}jr.current.get(n)&&Pc(n,o)&&xr(n),Qr(n,!0);return}if(l&&Ko.current&&Vi.current.includes(n)){Qa(n,l),lt.current.delete(n),bn(l);return}lt.current.delete(n),Yt(n),bn(l),Rr(n)},[Rr,xr,Qr,Pc,Qa,vn,Yt,bn]),nv=s.useCallback((n,o)=>{const l=hn.current.get(n);if(o){hn.current.set(n,o),ft(n),l&&l!==o&&bn(l);const m=g===n&&Qe?Et.current.get(n):null;m&&Ic(m,o)&&n===At&&(Ec(n,"warm-reuse"),gn(!0)),m&&m!==o&&S0({decodeWidth:m.width,decodeHeight:m.height,presentationCssWidth:o.getBoundingClientRect().width,presentationCssHeight:o.getBoundingClientRect().height,devicePixelRatio:window.devicePixelRatio,sourceWidth:wr.maxWidth,sourceHeight:wr.maxHeight})&&(Et.current.set(n,o),bn(m));return}hn.current.delete(n),ft(m=>m===n?"":m),bn(l)},[Ec,At,g,Qe,wr.maxHeight,wr.maxWidth,Ic,bn]),Nc=s.useCallback((n,o,l)=>{const m=performance.now(),d=ut(n,l.deviceId);let C=l;if(n==="control"&&l.visualChanged){const Z=String(o.inputFeedbackEventId||""),be=Number(o.inputFeedbackInputSeq||0),D=Number(o.inputFeedbackIssuedAtEpochMs||0),fe=Number(o.browserReceivedEpochMs||0),xe=Dm.current.get(l.deviceId)||"",Oe=D>0?Math.max(0,Date.now()-D):Number.POSITIVE_INFINITY;if(Z.length>0&&be>0&&Z!==xe&&Oe<=hd){const qe=Lm.current.get(l.deviceId)||[];qe.push(Oe),qe.length>yh&&qe.splice(0,qe.length-yh),Lm.current.set(l.deviceId,qe),C={...l,inputFeedbackSeq:be,inputFeedbackMs:Oe,inputFeedbackAt:m,inputFeedbackExact:!0,inputFeedbackEventId:Z,inputFeedbackInputType:o.inputFeedbackInputType,inputFeedbackInputToFrameMs:fe>0?Math.max(0,fe-D):void 0,inputFeedbackFrameToPaintMs:fe>0?Math.max(0,Date.now()-fe):void 0,inputFeedbackAgentApplyMs:o.inputFeedbackAgentApplyMs,inputFeedbackApplyToCaptureMs:o.inputFeedbackApplyToCaptureMs,inputFeedbackSampleCount:qe.length,inputFeedbackP50Ms:vs(qe,.5),inputFeedbackP95Ms:vs(qe,.95)},Dm.current.set(l.deviceId,Z),eu.current.set(l.deviceId,be)}else if(!Z){const qe=cC(l.deviceId),$t=eu.current.get(l.deviceId)||0,Jr=qe?m-qe.sentAt:Number.POSITIVE_INFINITY;qe&&qe.inputSeq>$t&&Jr<=hd&&(C={...l,inputFeedbackSeq:qe.inputSeq,inputFeedbackMs:Math.max(0,Jr),inputFeedbackAt:m,inputFeedbackExact:!1},eu.current.set(l.deviceId,qe.inputSeq))}}const v=Nt.current.get(d)||0,S=v>0&&hr.current.get(d)||0;if(hr.current.set(d,m),Fn.current.delete(d),n==="control"&&pa.current.delete(d),gr.current.delete(d),v>0){const Z=Wy({restartAttempts:v,healthySinceAt:zr.current.get(d)||0,previousPaintAt:S,paintedAt:m,maximumHealthyGapMs:n==="control"?gd:Dh,stableForMs:n==="control"?Nh:Fh});Z.resetAttempts?(Nt.current.delete(d),zr.current.delete(d),kt(n,o.deviceId,"stable","stable-paint-window",v)):Z.healthySinceAt>0&&zr.current.set(d,Z.healthySinceAt)}const y=da.current.get(d)||{totalFrames:0,totalChangedFrames:0,sampleFrames:0,sampleChangedFrames:0,sampleStartedAt:m,intervalCount:0,intervalSumMs:0,minIntervalMs:Number.POSITIVE_INFINITY,maxIntervalMs:0,intervalSamplesMs:[],seqGapCount:0,maxSeqGap:0,sampleDecoderInputBase:0,sampleDecoderOutputBase:0},w=er(o);y.bindingKey!==w&&(y.bindingKey=w,y.lastAt=void 0,y.lastFrameSeq=void 0,y.sampleChangedFrames=0,y.sampleDecoderInputBase=Number(l.decoderInputCount||0),y.sampleDecoderOutputBase=Number(l.decoderOutputCount||0),fl(y,m)),n==="control"&&C.inputFeedbackMs===void 0&&y.lastInfo?.inputFeedbackMs!==void 0&&y.lastInfo.inputFeedbackAt!==void 0&&m-y.lastInfo.inputFeedbackAt<=hd&&(C={...C,inputFeedbackSeq:y.lastInfo.inputFeedbackSeq,inputFeedbackMs:y.lastInfo.inputFeedbackMs,inputFeedbackAt:y.lastInfo.inputFeedbackAt,inputFeedbackExact:y.lastInfo.inputFeedbackExact,inputFeedbackEventId:y.lastInfo.inputFeedbackEventId,inputFeedbackInputType:y.lastInfo.inputFeedbackInputType,inputFeedbackInputToFrameMs:y.lastInfo.inputFeedbackInputToFrameMs,inputFeedbackFrameToPaintMs:y.lastInfo.inputFeedbackFrameToPaintMs,inputFeedbackAgentApplyMs:y.lastInfo.inputFeedbackAgentApplyMs,inputFeedbackApplyToCaptureMs:y.lastInfo.inputFeedbackApplyToCaptureMs,inputFeedbackSampleCount:y.lastInfo.inputFeedbackSampleCount,inputFeedbackP50Ms:y.lastInfo.inputFeedbackP50Ms,inputFeedbackP95Ms:y.lastInfo.inputFeedbackP95Ms}),y.totalFrames+=1,y.sampleFrames+=1,Ih(y,m,C.frameSeq),C.visualChanged&&(y.totalChangedFrames+=1,y.sampleChangedFrames+=1),y.lastInfo=C,da.current.set(d,y)},[kt]),Fc=s.useCallback((n,o)=>{if(at.current[n.deviceId]||ua.current===n.deviceId||n.currentGenerationVerified!==!0||Vn.current.get(n.deviceId)!==er(n))return;Nc("wall",n,o);const l=Qe&&g===n.deviceId,m=lt.current.get(n.deviceId)||en.current.get(n.deviceId);rc.current&&!Ae&&!l&&m?.isConnected&&ei("wall-visible",n,o),n.kind==="live"&&(xr(n.deviceId),Yt(n.deviceId)),ua.current!==n.deviceId&&!l&&(Br.current.delete(n.deviceId),la.current.delete(n.deviceId),_o.current.delete(n.deviceId),$a.current.delete(n.deviceId))},[g,Qe,xr,Nc,ei,Yt,Ae]),np=s.useCallback((n,o)=>{if(at.current[n.deviceId]||On(wt.current,ke.current)||wa(wt.current,ke.current)||wt.current&&ke.current&&dn(wt.current,ke.current)&&ho(wt.current,ke.current.deviceId,ke.current.sessionId)&&wt.current.monitorIndex===ke.current.monitorIndex||!qu(n,ke.current))return;Nc("control",n,o),Ut(v=>v&&"");const l=Et.current.get(n.deviceId),m=hn.current.get(n.deviceId);let d=!1;l&&l.width>0&&l.height>0&&(m&&Ae&&n.deviceId===At&&(d=Ic(l,m),d&&ei("control-visible",n,o)),Wa.current.set(n.deviceId,So(n)),Br.current.add(n.deviceId),n.deviceId===g&&(je(!0),Re(v=>v==="connecting"?"active":v)),Qr(n.deviceId,!1,n));const C=lc.current;!C||!Kk(C,n)||!d||(Ec(n.deviceId,"fresh-frame"),gn(!0))},[Ec,At,g,Qr,Ic,Nc,ei,Ae]),Xa=s.useCallback((n,o)=>{const l=performance.now(),m=ut(n,o.deviceId);Wr.current.set(m,l),n!=="control"&&Vr.current.delete(m);const d=Va.current.get(m)||{totalFrames:0,sampleFrames:0,sampleStartedAt:l,intervalCount:0,intervalSumMs:0,minIntervalMs:Number.POSITIVE_INFINITY,maxIntervalMs:0,intervalSamplesMs:[],seqGapCount:0,maxSeqGap:0,sampleBytes:0,sampleH264Frames:0,sampleTinyFrames:0,sampleRepeatedFrames:0,sourceSendIntervalsMs:[]},C=er(o);if(d.bindingKey!==C&&(d.bindingKey=C,d.lastAt=void 0,d.lastFrameSeq=void 0,d.lastContentHash=void 0,d.sampleBytes=0,d.sampleH264Frames=0,d.sampleTinyFrames=0,d.sampleRepeatedFrames=0,d.sourceSendIntervalsMs.length=0,fl(d,l)),d.totalFrames+=1,d.sampleFrames+=1,d.sampleBytes+=Math.max(0,Number(o.byteLength||0)),String(o.frameMode||o.mode||o.codec||o.mimeType||"").toLowerCase().includes("h264")){d.sampleH264Frames+=1,Number(o.byteLength||0)<=Vk&&(d.sampleTinyFrames+=1);const w=String(o.contentHash||"");w&&d.lastContentHash===w&&(d.sampleRepeatedFrames+=1),d.lastContentHash=w}const y=Number(o.agentSendGapMs||0);y>0&&y<1e3&&fb(d.sourceSendIntervalsMs,y),d.lastFrame=So(o),Ih(d,l,o.frameSeq),Va.current.set(m,d)},[]);s.useEffect(()=>{const n=new Set(Zm),o=new Set([...Wr.current.keys(),...hr.current.keys(),...ma.current.keys(),...Fn.current.keys(),...gr.current.keys(),...Nt.current.keys(),...zr.current.keys(),...$o.current.keys(),...pa.current.keys(),...$r.current.keys(),...Vr.current.keys(),...da.current.keys(),...Va.current.keys()]);for(const d of o){if(n.has(d))continue;const C=d.indexOf(":"),v=d.slice(0,C),S=d.slice(C+1);(v==="wall"||v==="control")&&S&&Ur(v,S)}const l=d=>{const C=Object.entries(d).filter(([v])=>n.has(v));return C.length===Object.keys(d).length?d:Object.fromEntries(C)};if(Ql(l),sc(l),n.size===0)return;const m=window.setInterval(()=>{const d=performance.now(),C={},v={};for(const S of n){const y=da.current.get(S);if(y){const D=Math.max(1,d-y.sampleStartedAt);C[S]={bindingKey:y.bindingKey||"",totalFrames:y.totalFrames,totalChangedFrames:y.totalChangedFrames,framesPerSecond:y.sampleFrames*1e3/D,changedFramesPerSecond:y.sampleChangedFrames*1e3/D,averageIntervalMs:y.intervalCount>0?y.intervalSumMs/y.intervalCount:0,minIntervalMs:Number.isFinite(y.minIntervalMs)?y.minIntervalMs:0,maxIntervalMs:y.maxIntervalMs,p95IntervalMs:vs(y.intervalSamplesMs,.95),intervalCount:y.intervalCount,seqGapCount:y.seqGapCount,maxSeqGap:y.maxSeqGap,decoderInputFps:Math.max(0,(Number(y.lastInfo?.decoderInputCount||0)-y.sampleDecoderInputBase)*1e3/D),decoderOutputFps:Math.max(0,(Number(y.lastInfo?.decoderOutputCount||0)-y.sampleDecoderOutputBase)*1e3/D),sampleMs:D,lastInfo:y.lastInfo},y.sampleDecoderInputBase=Number(y.lastInfo?.decoderInputCount||0),y.sampleDecoderOutputBase=Number(y.lastInfo?.decoderOutputCount||0),y.sampleChangedFrames=0,fl(y,d)}const w=Va.current.get(S);if(!w)continue;const Z=Math.max(1,d-w.sampleStartedAt),be=w.lastFrame?So(w.lastFrame):void 0;w.lastFrame=be,v[S]={totalFrames:w.totalFrames,framesPerSecond:w.sampleFrames*1e3/Z,averageIntervalMs:w.intervalCount>0?w.intervalSumMs/w.intervalCount:0,minIntervalMs:Number.isFinite(w.minIntervalMs)?w.minIntervalMs:0,maxIntervalMs:w.maxIntervalMs,p95IntervalMs:vs(w.intervalSamplesMs,.95),intervalCount:w.intervalCount,seqGapCount:w.seqGapCount,maxSeqGap:w.maxSeqGap,averageFrameBytes:w.sampleFrames>0?w.sampleBytes/w.sampleFrames:0,tinyFrameRatio:w.sampleH264Frames>0?w.sampleTinyFrames/w.sampleH264Frames:0,repeatedFrameRatio:w.sampleH264Frames>0?w.sampleRepeatedFrames/w.sampleH264Frames:0,sourceSendAverageMs:w.sourceSendIntervalsMs.length>0?w.sourceSendIntervalsMs.reduce((D,fe)=>D+fe,0)/w.sourceSendIntervalsMs.length:0,sourceSendP95Ms:vs(w.sourceSendIntervalsMs,.95),sourceSendSampleCount:w.sourceSendIntervalsMs.length,sampleMs:Z,lastFrame:be},w.sampleBytes=0,w.sampleH264Frames=0,w.sampleTinyFrames=0,w.sampleRepeatedFrames=0,w.sourceSendIntervalsMs.length=0,fl(w,d)}Ql(C),sc(v)},1e3);return cc.current=m,()=>{window.clearInterval(m),cc.current===m&&(cc.current=null)}},[Zm,Ur]);const rp=s.useCallback(n=>{const o=O;if(ie.current!==o)return;const l=n.deviceId,m=er(n);if(at.current[l]||ua.current===l||n.currentGenerationVerified!==!0||Vn.current.get(l)!==m)return;Xa("wall",n);const d=lt.current.get(l);if(!d)return;const C=Vo(d),v=zo(d),S=()=>lt.current.get(l)!==d||!Uo(d,C)||ie.current!==o||!!at.current[l]||ua.current===l||Vn.current.get(l)!==m,y=()=>S()||!Ua(d,v),w=P0(rt,De.h264DecodeAcceleration),Z=_i.current.has(l)?"prefer-software":w.acceleration;ed(d,n,y,Fc,Z,w.latencyMode,S,Tc).catch(()=>{})},[Vo,Ua,Uo,zo,Fc,rt,Xa,Tc,De.h264DecodeAcceleration,O]),ap=s.useCallback(n=>{const o=O;if(ie.current!==o)return;const l=n.deviceId;if(at.current[l]||On(wt.current,ke.current)||wa(wt.current,ke.current)||wt.current&&ke.current&&dn(wt.current,ke.current)&&ho(wt.current,ke.current.deviceId,ke.current.sessionId)&&wt.current.monitorIndex===ke.current.monitorIndex||!qu(n,ke.current))return;let m=Et.current.get(l);if(!m){const fe=hn.current.get(l),xe=Ha.current;m=fe||xe||document.createElement("canvas"),fe&&xe&&xe!==fe&&vn(xe),Ha.current=null,m!==fe&&m.setAttribute("aria-hidden","true"),Et.current.set(l,m)}const d=m,C=n,v=Vo(d),S=zo(d),y=()=>Et.current.get(l)!==d||!Uo(d,v)||ie.current!==o||!!at.current[l]||!qu(C,ke.current),w=()=>y()||!Ua(d,S),Z=Ri.current,be=String(n.frameMode||n.mode||n.codec||n.mimeType||"").toLowerCase().includes("h264");be||Xa("control",n);const D=ed(d,n,w,np,on.h264DecodeAcceleration,"interactive",y);be&&Xa("control",n),D.catch(fe=>{Ri.current!==Z||Et.current.get(l)!==d||!Ua(d,S)||y()||g!==l||Ut(fe instanceof Error?fe.message:String(fe||"Control H.264 decode failed"))})},[Vo,Ua,Uo,zo,g,on.h264DecodeAcceleration,np,Xa,vn,O]),rv=s.useCallback(n=>{const o=Nn.current;Nn.current=n,o&&o!==n&&bn(o),$i.current=0,dc.current=0,mc.current=0,pc.current=0,Zl.current=0,Bi.current=0},[bn]),ti=s.useCallback(()=>{const n=new Set,o=O;if(ie.current!==o)return n;const l=Nn.current,m=Bo.current;if(!l||!m||l.width<=0||l.height<=0||Bi.current!==m.layoutVersion)return n;for(const d of m.tiles){if(at.current[d.deviceId])continue;const C=en.current.get(d.deviceId);if(!C||d.width<=0||d.height<=0)continue;const v=Math.max(1,Math.round(d.width)),S=Math.max(1,Math.round(d.height)),y=zk,w=Uk;(C.width!==y||C.height!==w)&&(C.width=y,C.height=w);const Z=C.getContext("2d",{alpha:!1});if(Z){Z.imageSmoothingEnabled=!0,Z.imageSmoothingQuality="high";try{Z.drawImage(l,Math.round(d.x),Math.round(d.y),v,S,0,0,y,w),n.add(d.deviceId)}catch{}}}return n},[O]),av=s.useCallback((n,o)=>{const l=en.current.get(n);if(o&&l&&l!==o&&Qa(n,l),o){if(en.current.set(n,o),l&&l!==o&&bn(l),at.current[n]){Yt(n),vn(o),Rr(n);return}jr.current.get(n)&&Pc(n,o)&&xr(n),window.requestAnimationFrame(()=>{ti().has(n)&&Yt(n)}),window.requestAnimationFrame(()=>Qr(n,!0));return}en.current.delete(n),Yt(n),bn(l),Rr(n)},[Rr,xr,ti,Qr,Pc,Qa,vn,Yt,bn]),op=s.useCallback((n,o)=>{if(ie.current!==O)return;mc.current=performance.now(),Bi.current=Number(n.layoutVersion||0),ti();const l=Bo.current?.tiles||[],m=l.length>0?Math.round(n.byteLength/l.length):n.byteLength;for(const d of l){if(at.current[d.deviceId])continue;const C={...n,deviceId:d.deviceId,width:d.width,height:d.height,sourceWidth:d.width,sourceHeight:d.height,byteLength:m};Fc(C,{...o,deviceId:d.deviceId,width:d.width,height:d.height,byteLength:m}),ua.current===d.deviceId&&Qr(d.deviceId,!0)}},[Fc,ti,Qr,O]),ov=s.useCallback(n=>{const o=O;if(ie.current!==o)return;const l=performance.now();$i.current<=0&&($i.current=l),dc.current=l;const m=Nn.current;if(!m)return;const d=er(n);ji.current!==d&&(ji.current=d,Vt(m));const C=Vo(m),v=zo(m),S=()=>Nn.current!==m||ji.current!==d||ie.current!==o||!Uo(m,C),y=()=>S()||!Ua(m,v),w=Bo.current?.tiles||[],Z=w.length>0?Math.round(n.byteLength/w.length):n.byteLength;for(const be of w)at.current[be.deviceId]||Xa("wall",{...n,deviceId:be.deviceId,width:be.width,height:be.height,sourceWidth:be.width,sourceHeight:be.height,byteLength:Z});ed(m,n,y,op,void 0,"smooth",S).catch(()=>{})},[Vo,Ua,Uo,zo,op,Xa,Vt,O]),ip=s.useCallback(n=>{const o=H&&n.streamPurpose==="control"&&n.readOnlyControlBorrow===!0&&n.presentationPurpose==="wall";if(n.streamPurpose!=="wall"&&!o||at.current[n.deviceId])return;const l=er(n);Vn.current.get(n.deviceId)!==l&&(Vn.current.set(n.deviceId,l),Vt(lt.current.get(n.deviceId)),ve.current&&$({type:"frame.owner.changed",component:`wall-owner:${n.deviceId}`,state:"bound",reason:`owner:${n.sessionId||"unknown"}:${n.captureGeneration||"unknown"}:${n.monitorIndex}`,details:{deviceId:n.deviceId,sessionId:n.sessionId||"unknown",streamId:n.streamId||"unknown",commandId:n.commandId||"unknown",captureGeneration:n.captureGeneration||"unknown",monitorIndex:n.monitorIndex,streamPurpose:n.streamPurpose||"unknown",presentationPurpose:n.presentationPurpose||"unknown"}}))},[H,$,Vt]),du=s.useMemo(()=>({fps:ln.fps,maxWidth:ln.maxWidth,maxHeight:ln.maxHeight,quality:ln.quality,mode:rt?"mode3-h264-hw":De.frameMode,frameMode:rt?"mode3-h264-hw":De.frameMode,streamPurpose:"wall",allowReadOnlyControlBorrow:H,configurationRefreshMs:kk,connectionSessionIds:yn,monitorSelections:gt,onFrame:rp,onStreamReady:ip}),[yn,rp,ip,H,rt,gt,De.frameMode,ln.fps,ln.maxHeight,ln.maxWidth,ln.quality]),Dc=s.useCallback(n=>{const o=dt.current;if(o!=="connecting"&&o!=="active"&&o!=="warm"&&o!=="stopping")return kt("control",n.deviceId,"stop-deferred",`stream-binding-ignored-during-${o}`,Nt.current.get(ut("control",n.deviceId))||0),null;const l=ke.current;if(at.current[n.deviceId]||!l||l.deviceId!==n.deviceId||n.deviceId!==g||n.streamPurpose!=="control"||n.monitorIndex!==ir)return null;const m=tu.current[n.deviceId]||"";if(!m||m!==n.sessionId)return null;const d=Gu(l.deviceId,l.transitionGeneration,n),C=dn(l,d)&&ho(l,d.deviceId,d.sessionId)&&l.monitorIndex===d.monitorIndex;return!Ku(l,d)&&!wa(l,d)&&!C?(kt("control",n.deviceId,"owner-replaced","stale-stream-binding-ignored",Nt.current.get(ut("control",n.deviceId))||0),null):(Ku(l,d)||(ke.current=d,ve.current&&$({type:"frame.owner.changed",component:`control-owner:${n.deviceId}`,state:"bound",reason:`owner:${n.sessionId||"unknown"}:${n.captureGeneration||"unknown"}:${n.monitorIndex}`,details:{deviceId:n.deviceId,sessionId:n.sessionId||"unknown",streamId:n.streamId||"unknown",commandId:n.commandId||"unknown",captureGeneration:n.captureGeneration||"unknown",monitorIndex:n.monitorIndex,streamPurpose:n.streamPurpose}}),kt("control",n.deviceId,"owner-bound","hub-start-descriptor",Nt.current.get(ut("control",n.deviceId))||0)),d)},[g,kt,$,ir]),sp=s.useCallback(n=>{const o=Dc(n);if(!o)return;const l=wt.current;if(On(l,o)||wa(l,o)||!!l&&dn(l,o)&&ho(l,o.deviceId,o.sessionId)&&l.monitorIndex===o.monitorIndex)return;wt.current&&(wt.current=null,kt("control",n.deviceId,"owner-replaced","stream-ready-superseded-stale-downshift",Nt.current.get(ut("control",n.deviceId))||0));const d=dt.current;if(d!=="connecting"&&d!=="active"&&d!=="warm"){kt("control",n.deviceId,"stop-deferred",`stream-ready-ignored-during-${d}`,Nt.current.get(ut("control",n.deviceId))||0);return}const C=Xe.current;(!C||er(C)!==er(n))&&Vt(Et.current.get(n.deviceId)),Xe.current=n,ht(n),Re($y)},[Dc,kt,Vt]);s.useEffect(()=>{Vt(Et.current.get(g)),Xe.current=null,ht(null)},[g,F,Gn,Vt,ir]);const Lc=F?`${F}-monitor-${ir}`:"",mu=s.useMemo(()=>({fps:Ki,maxWidth:wr.maxWidth,maxHeight:wr.maxHeight,quality:on.quality,mode:Gn,frameMode:Gn,streamPurpose:"control",forceRestart:Lc!=="",forceRestartToken:Lc,restartReason:Lc?"control-session-or-monitor-change":"",connectionSessionIds:yn,monitorSelections:gt,onFrame:ap,onStreamBound:Dc,onStreamReady:sp}),[yn,Lc,on.quality,ap,Ki,Gn,wr.maxHeight,wr.maxWidth,Dc,sp,gt]),{frames:cp,state:Xi,error:Oc,stats:Ja,restartLive:lp,reconnectLive:pu}=Nf(Kt,De.autoStartLive&&Kt.length>0,Y,du,O);s.useEffect(()=>{const n=new Set(Kt),o=ve.current?[]:null;for(const l of Vn.current.keys())n.has(l)||(Vn.current.delete(l),Vt(lt.current.get(l)),o?.push({type:"frame.owner.changed",component:`wall-owner:${l}`,state:"unbound",reason:"device-no-longer-requested",details:{deviceId:l}}));o&&o.length>0&&ae(o)},[Kt,ae,Vt]);const{frame:ni,layout:Za,state:Ji,stats:iv,refreshInputs:up}=pC(nn,rt&&De.autoStartLive&&nn.length>0,Y,{fps:St.atlasOutputFps,inputFps:uu,width:1920,height:1080,tileWidth:Zo.maxWidth,tileHeight:Zo.maxHeight,captureDeviceIds:nn,connectionSessionIds:yn,monitorSelections:gt,onFrame:ov},O);s.useEffect(()=>{Bo.current=Za,Za&&window.requestAnimationFrame(ti)},[Za,ti]),s.useEffect(()=>{if(!rt||Ji!=="open"){$i.current=0,dc.current=0,mc.current=0;return}const n=window.setInterval(()=>{const o=Nn.current,l=performance.now();if(!o||document.visibilityState!=="visible"||l-uc.current<fd)return;const m=dc.current,d=$i.current;if(m<=0||d<=0||l-m>500)return;const C=mc.current||d,v=l-C;if(v>=Dk&&l-Zl.current>=Ok){hi(o)&&(Zl.current=l,pc.current=l);return}v>=Fk&&l-pc.current>=Lk&&Qw(o)&&(pc.current=l)},250);return()=>window.clearInterval(n)},[Ji,rt]);const{frames:Zi,state:_c,error:eo,stats:sv,restartLive:jc,reconnectLive:es}=Nf(Kr,Kr.length>0,Y,mu,O);s.useEffect(()=>{if(!ve.current)return;const n=_u(),o={stage:n.stage||"unknown",generation:Number(n.generation||0),directReady:n.directReady===!0,logicalChannels:Number(n.logicalChannels||0),openLogicalChannels:Number(n.openLogicalChannels||0),consecutiveMediaLogicalOpenFailures:Number(n.consecutiveMediaLogicalOpenFailures||0),logicalChannelFailureCount:Number(n.logicalChannelFailureCount||0),lastLogicalChannelFailure:n.lastLogicalChannelFailure||null,partialMediaWireTimeoutCount:Number(n.partialMediaWireTimeoutCount||0),lastPartialMediaWireTimeout:n.lastPartialMediaWireTimeout||null};ae([{type:"frame.transport.changed",component:"wall-frame-socket",state:Xi||"unknown",reason:Oc||`desired-owners:${Kt.length}`,details:{desiredOwnerCount:Kt.length,frameMode:du.frameMode,managerHubUrl:Y||"unknown",direct:o}},{type:"frame.transport.changed",component:"control-frame-socket",state:_c||"unknown",reason:eo||`desired-owners:${Kr.length}`,details:{desiredOwnerCount:Kr.length,frameMode:mu.frameMode,managerHubUrl:Y||"unknown",direct:o}},{type:"frame.transport.changed",component:"atlas-frame-socket",state:Ji||"unknown",reason:`desired-owners:${nn.length}`,details:{desiredOwnerCount:nn.length,enabled:rt,managerHubUrl:Y||"unknown",direct:o}},{type:"stream.state.changed",component:"wall-subscription",state:yr&&De.autoStartLive?"requested":"idle",reason:Gt?`tool:${Pt}:desired-owners:${Kt.length}`:"document-hidden",details:{documentVisible:Gt,captureOwnershipActive:yr,autoStartLive:De.autoStartLive,activeTool:Pt,desiredOwnerCount:Kt.length}},{type:"stream.state.changed",component:`control-session:${g||"unknown"}`,state:ge,reason:`frame-transport:${_c||"unknown"}`,details:{deviceId:g||"unknown",bindingSessionId:ct?.sessionId||"unknown",bindingStreamId:ct?.streamId||"unknown",bindingCaptureGeneration:ct?.captureGeneration||"unknown",bindingMonitorIndex:ct?.monitorIndex??"unknown"}}])},[Pt,Ji,Kr.length,eo,_c,mu.frameMode,g,ge,ct,Kt.length,Gt,Y,nn.length,rt,it,ae,De.autoStartLive,yr,Oc,Xi,du.frameMode]),s.useEffect(()=>{const n=Am.current,o=new Set([...Object.keys(n),...Object.keys(gt)]);for(const l of o){const m=Math.max(0,Math.floor(Number(n[l])||0)),d=Math.max(0,Math.floor(Number(gt[l])||0));m!==d&&(Vn.current.delete(l),Vt(lt.current.get(l)),Vt(Et.current.get(l)),Vt(en.current.get(l)),Dt("wall",l),Dt("control",l),hi(lt.current.get(l)||null),hi(Et.current.get(l)||null))}o.size>0&&(Vt(Nn.current),hi(Nn.current)),Am.current={...gt}},[gt,Dt,Vt]);const ri=s.useMemo(()=>{const n=(l,m)=>{const d=Le.find(v=>v.deviceId===l),C=d?_n(d,gt[l]):0;return!Number.isFinite(Number(m.monitorIndex))||Number(m.monitorIndex)===C},o=new Map;for(const[l,m]of cp.entries())n(l,m)&&o.set(l,m);if(rt&&ni&&nn.length>0){const l=new Map((Za?.tiles||[]).map(d=>[d.deviceId,d])),m=Math.max(1,l.size);for(const d of nn){const C=l.get(d);C&&o.set(d,{...ni,deviceId:d,width:C.width,height:C.height,sourceWidth:C.width,sourceHeight:C.height,byteLength:Math.round(ni.byteLength/m)})}}for(const[l,m]of Zi.entries())n(l,m)&&o.set(l,m);for(const l of Mc){if(!Br.current.has(l)||o.has(l))continue;const m=Wa.current.get(l);m&&n(l,m)&&o.set(l,m)}return o},[ni,Za,Le,Zi,nn,rt,gt,cp,Mc,Fb]),fu=Ae&&Kr.length>0?_c:nn.length>0?Ji:Xi,Bc=Ae&&Kr.length>0?sv:nn.length>0?iv:Ja;s.useCallback((n,o="browser-stale")=>{const l=lp(n,o),m=jc(n,o);return l||m},[jc,lp]),s.useEffect(()=>{rt&&nn.length>0&&!Ae&&up()},[nn.length,rt,up,Ae]);const ai=s.useCallback((n,o,l)=>{const m=o==="control"?Et.current.get(n)||null:lt.current.get(n)||null;if(!m)return!1;const d=l==="decoder-paint-stale"?Yw(m):hi(m)?"decoder-reset":"none";if(d==="none")return!1;o==="wall"&&l==="decoder-paint-stale"&&_i.current.add(n);const C=performance.now();return gr.current.set(ut(o,n),C),kt(o,n,"fallback",`${l}:${d}`,Nt.current.get(ut(o,n))||0),!0},[kt]),ts=s.useCallback(n=>{if(Gn!=="mode3-h264-hw"||!g||Q)return!1;const o=Le.find(S=>S.deviceId===g)||tn,l=Kh(o?.platform);if(!l)return!1;const m=ut("control",g),d=Nt.current.get(m)||0;kt("control",g,"fallback",n,d),Dt("control",g,{preserveLatestDiagnostic:!0}),hi(Et.current.get(g)||null),es([g],"control-decode-fallback"),Te(l),he(`control-${l}-fallback-${g}-${Date.now()}`),je(!1),gn(!1);const C=n==="no first frame"||n==="control-first-frame-timeout",v=l==="mode1-jpeg"?"Mode 1 JPEG":"Mode 5";return Ut(S=>S||(C?`Control frame transport timeout; retrying Control with ${v} (${n})`:`H.264 decode failed; retrying Control with ${v} (${n})`)),Re("connecting"),!0},[Le,tn,g,Q,Gn,es,kt,Dt]);s.useEffect(()=>{const n=Ae?tn:null;if(n){lc.current={deviceId:n.deviceId,monitorIndex:ir,frameMode:Gn,startedAtEpochMs:Date.now()},gn(g===n.deviceId&&Qe);return}lc.current=null,gn(!1)},[tn?.sessionId,At,g,Qe,Gn,ir,Ae]);const dp=s.useCallback(async(n,o)=>{const l=String(o.streamId||"").trim(),m=String(o.streamPurpose||"").trim(),d=String(o.sessionId||"").trim(),C=String(o.commandId||"").trim(),v=Number(o.captureGeneration||0),S=Number(o.monitorIndex??-1);if(!l||!["wall","atlas"].includes(m)||!d||!C||!Number.isSafeInteger(v)||v<=0||!Number.isSafeInteger(S)||S<0)throw new Error("wall-start-owner-incomplete");const y=performance.now()+3e3;for(;;){const w=await Ue(`/api/remote/devices/${encodeURIComponent(n)}/live/stop`,{method:"POST",body:JSON.stringify({streamId:l,streamPurpose:m,expectedSessionId:d,expectedCommandId:C,expectedCaptureGeneration:v,expectedMonitorIndex:S,requireNoPresentationOwner:!0,reason:"wall-start-presentation-revoked"})},Y);if(w?.ok===!1)throw new Error(w.error||"revoked-wall-start-stop-failed");if(w?.captureStopConfirmed===!0||w?.alreadyStopped===!0||w?.staleOwner===!0)return w;if(w?.presentationOwnerActive===!0||w?.retainedForPresentation===!0){if(qn.current&&Ko.current)return w;if(performance.now()<y){await new Promise(Z=>window.setTimeout(Z,50));continue}throw new Error("revoked-wall-start-presentation-owner-did-not-release")}throw new Error("revoked-wall-start-stop-unconfirmed")}},[Y]),to=s.useCallback(async n=>{if(at.current[n])throw new Error("LIVE_CAPTURE_PAUSED");if(!qn.current||!Ko.current)return{ok:!0,skipped:!0,reason:"wall-capture-owner-hidden"};const o=rr.current,l=Me.find(v=>v.deviceId===n);gs({mode4Enabled:rt,directMode4WallEnabled:Mr,isMac:Nr(l?.platform)});const m=l?_n(l,gt[n]):0,d={fps:ln.fps,maxWidth:ln.maxWidth,maxHeight:ln.maxHeight,quality:ln.quality,mode:rt?"mode3-h264-hw":De.frameMode,frameMode:rt?"mode3-h264-hw":De.frameMode,streamPurpose:"wall",monitorIndex:m},C=await Ue(`/api/remote/devices/${encodeURIComponent(n)}/live/start`,{method:"POST",body:JSON.stringify(d)},Y);if(C?.ok===!1)throw new Error(C.error||"wall-stream-start-failed");return o!==rr.current||!qn.current||!Ko.current?(await dp(n,C),{...C,skipped:!0,reason:"wall-presentation-owner-revoked",compensated:!0}):C},[uu,Me,Mr,Y,rt,gt,dp,De.frameMode,Zo.maxHeight,Zo.maxWidth,ln.fps,ln.maxHeight,ln.maxWidth,ln.quality]),mp=s.useCallback(async n=>{const o=Me.find(m=>m.deviceId===n);gs({mode4Enabled:rt,directMode4WallEnabled:Mr,isMac:Nr(o?.platform)});const l=await Ue(`/api/remote/devices/${encodeURIComponent(n)}/live/stop`,{method:"POST",body:JSON.stringify({streamPurpose:"wall",reason:"control-active"})},Y);if(l?.ok===!1)throw new Error(l.error||"wall-stream-stop-failed");return l},[Me,Mr,Y,rt]),pp=s.useCallback(async(n,o="control-session-stop")=>{if(!el(n))return kt("control",n.deviceId,"stop-deferred",`${o}:unbound-stop-deferred-to-frame-owner`,Nt.current.get(ut("control",n.deviceId))||0),{ok:!0,pendingOwner:!0,deferredToFrameOwner:!0};const m=await Ue(`/api/remote/devices/${encodeURIComponent(n.deviceId)}/live/stop`,{method:"POST",body:JSON.stringify({streamId:n.streamId,expectedSessionId:n.sessionId,expectedCommandId:n.commandId,expectedCaptureGeneration:n.captureGeneration,expectedMonitorIndex:n.monitorIndex,streamPurpose:"control",reason:o})},Y);if(m?.ok===!1)throw new Error(m.error||"control-stream-stop-failed");return(m?.staleOwner===!0||m?.retainedNewerOwner===!0)&&kt("control",n.deviceId,"owner-replaced",`${o}:hub-retained-newer-owner`,Nt.current.get(ut("control",n.deviceId))||0),m},[Y,kt]),An=s.useCallback((n,o={})=>{wt.current?.deviceId===n&&(wt.current=null);const l=Et.current.get(n);if(l){const d=jr.current.has(n)||lt.current.has(n)||en.current.has(n);o.preservePresentation!==!1&&!d&&Qa(n,l),Et.current.delete(n),vn(l),!(hn.current.get(n)||lt.current.get(n)||en.current.get(n))&&!Ha.current&&(Ha.current=l)}const m=hn.current.get(n);m&&fi(m),Wa.current.delete(n),Br.current.delete(n),la.current.delete(n),_o.current.delete(n),$a.current.delete(n),Ur("control",n)},[Ur,Qa,vn]),Hc=s.useCallback(n=>{const o=[ut("wall",n),ut("control",n)];for(const l of o){const m=Va.current.get(l);m?.lastFrame&&(m.lastFrame=So(m.lastFrame))}sc(l=>{let m=!1;const d={...l};for(const C of o){const v=l[C];!v?.lastFrame||v.lastFrame.payload.byteLength===0||(d[C]={...v,lastFrame:So(v.lastFrame)},m=!0)}return m?d:l})},[]),hu=s.useCallback(n=>{Vn.current.delete(n),Yt(n),An(n,{preservePresentation:!1});const o=new Set;for(const l of[hn.current.get(n),lt.current.get(n),en.current.get(n)])l&&o.add(l);for(const l of o)vn(l);Rr(n),g===n&&(lc.current=null,gn(!1),je(!1)),Ti.current.add(n),Hc(n)},[Rr,g,vn,An,Hc,Yt]);s.useEffect(()=>{const n=new Set(Object.keys(ra));for(const o of n)Ti.current.has(o)||hu(o);for(const o of Ti.current)n.has(o)||Ti.current.delete(o)},[hu,ra]);const oi=s.useCallback(n=>{const o=uf(Tm.current,n);return Tm.current=o.tail,o.result},[]),Yn=s.useCallback(n=>{const o=uf(Fm.current,n);return Fm.current=o.tail,o.result},[]),Qn=s.useCallback(n=>{Rn.current=n,nc.current=0;const o=n?.deviceId||"";ua.current=o,Tb(o),o&&Br.current.add(o)},[]),ii=s.useCallback(n=>oi(async()=>{if(at.current[n.deviceId])return!1;const o=Rn.current;return!dn(o,n)||!tl(n.deviceId,n,ke.current)?!1:(await to(n.deviceId),dn(Rn.current,n)&&Qn(null),!0)}),[Qn,oi,to]),fp=s.useCallback((n,o,l)=>oi(async()=>{const m=Rn.current;if(dn(m,n))return l.stoppedWallDeviceId=n.deviceId,!0;if(m)if(at.current[m.deviceId])dn(Rn.current,m)&&Qn(null);else{if(!tl(m.deviceId,m,ke.current))return!1;await to(m.deviceId),dn(Rn.current,m)&&Qn(null)}if(!o())return!1;if(await mp(n.deviceId),l.stoppedWallDeviceId=n.deviceId,!o()){if(tl(l.stoppedWallDeviceId,n,ke.current))try{await to(l.stoppedWallDeviceId)}catch(d){throw Qn(n),d}finally{l.stoppedWallDeviceId=""}return!1}return fi(lt.current.get(n.deviceId)||null),Qn(n),!0}),[Qn,oi,to,mp]),Wc=s.useCallback(async(n,o)=>{if(o.stoppedWallDeviceId){if(dn(Rn.current,n)){try{await ii(n)}catch(l){j(l instanceof Error?l.message:String(l))}finally{o.stoppedWallDeviceId=""}return}await oi(async()=>{if(!o.stoppedWallDeviceId||!tl(o.stoppedWallDeviceId,n,ke.current))return;const l=o.stoppedWallDeviceId;try{await to(l)}catch(m){Qn(n),j(m instanceof Error?m.message:String(m))}finally{o.stoppedWallDeviceId=""}})}},[Qn,oi,ii,j,to]),Xn=s.useCallback(async(n,o,l={})=>{const m=l.allowStopFailure===!0,d=l.resumeWall!==!1,C=S=>{const y=ke.current;if(!y)return S;const w=el(y)&&dn(y,S)&&ho(S,y.deviceId,y.sessionId)&&S.monitorIndex===y.monitorIndex;return On(y,S)||wa(S,y)||w?y:S};let v=C(n);for(let S=0;S<2;S+=1){try{await pp(v,o)}catch(w){if(!m)throw w}const y=C(v);if(On(y,v)||Ku(y,v)||!el(y)||!dn(y,v))break;v=y}if(!On(ke.current,v))return!1;if(ke.current=null,Xe.current=null,ht(null),An(v.deviceId),je(!1),he(""),Te(""),Ut(""),U(S=>S===v.deviceId?"":S),!d)return dn(Rn.current,v)&&Qn(null),!0;try{await ii(v)}catch(S){j(S instanceof Error?S.message:String(S))}return!0},[Qn,An,ii,j,pp]),hp=(Gt&&Ae&&pt&&At&&!Pi.has(At)&&Le.find(n=>n.deviceId===At)||null)?.deviceId||"";s.useEffect(()=>{Ho.current=hp},[hp]),s.useEffect(()=>{const n=At&&Le.find(C=>C.deviceId===At)||null;if(!Gt||!Ae||!pt||!n){sn.current&&(++Wt.current,sn.current="");return}if(at.current[n.deviceId]){sn.current&&(++Wt.current,sn.current=""),g===n.deviceId&&Re("paused");return}if(Un.current){if(Un.current===n.deviceId)return;Un.current=""}if(g===n.deviceId&&ho(ke.current,n.deviceId,n.sessionId||"")&&(ge==="active"||ge==="warm"||ge==="connecting")){Re(C=>C==="warm"?"active":C);return}if(sn.current===n.deviceId)return;const o=++Wt.current,l=Gu(n.deviceId,o,{sessionId:n.sessionId,monitorIndex:ir});sn.current=n.deviceId;const m={stoppedWallDeviceId:""},d=()=>o===Wt.current&&Ho.current===l.deviceId;Yn(async()=>{if(!d())return;const C=ke.current;if(C){Re("stopping");try{await Xn(C,"control-session-switch")}catch(y){d()&&(Re("error"),j(y instanceof Error?y.message:String(y)));return}if(!d()){ke.current||Re("idle");return}}try{if(!await fp(l,d,m)||!d()){await Wc(l,m),ke.current||Re("idle");return}}catch(y){await Wc(l,m),d()&&(Re("error"),j(y instanceof Error?y.message:String(y)));return}if(!d()){await Wc(l,m);return}ke.current=l,wt.current=null,Un.current="",za.current=null,Wo.current=0,Wi.current="",m.stoppedWallDeviceId="";const v=ut("control",l.deviceId),S=`control-session-${o}-${l.deviceId}`;$r.current.set(v,performance.now()),Wr.current.delete(v),hr.current.delete(v),ma.current.delete(v),Fn.current.delete(v),gr.current.delete(v),Nt.current.delete(v),zr.current.delete(v),pa.current.delete(v),Te(""),Ut(""),he(S),U(l.deviceId),je(!1),Re("connecting")}).catch(C=>{d()&&(Re("error"),j(C instanceof Error?C.message:String(C)))}).finally(()=>{Wt.current===o&&sn.current===l.deviceId&&(sn.current="")})},[Le,At,g,ge,Gt,Yn,pt,fp,Wc,ir,j,Ae,Xn,ra]),s.useEffect(()=>{if(!g||Le.some(l=>l.deviceId===g))return;const n=g;++Wt.current,sn.current="";const o=ke.current;Re("stopping"),Yn(async()=>{o&&o.deviceId===n?await Xn(o,"control-device-disconnected",{allowStopFailure:!0}):(An(n),U(l=>l===n?"":l)),ke.current||Re("idle")})},[Le,g,Yn,An,Xn]),s.useEffect(()=>{if(zn.current!==null&&(window.clearTimeout(zn.current),zn.current=null),!or||Ae||!g||at.current[g]||ge!=="connecting"&&ge!=="active"&&ge!=="warm")return;const n=g,o=ke.current;if(!o||o.deviceId!==n)return;const l=window.setTimeout(()=>{zn.current===l&&(zn.current=null);const m=ke.current,d=S=>On(S,o)||wa(o,S)||!!S&&dn(S,o)&&ho(o,S.deviceId,S.sessionId)&&o.monitorIndex===S.monitorIndex;if(Ho.current||at.current[n]||!d(m))return;const C=m||o;wt.current=C;const v=++Wt.current;sn.current="",Re("stopping"),Yn(async()=>{if(v!==Wt.current||Ho.current||!d(ke.current)){(On(wt.current,C)||wa(wt.current,C))&&(wt.current=null);const S=ke.current;Ho.current&&el(S)&&S?.deviceId===n&&Re("active");return}try{await Xn(C,"control-session-wall-downshift")}catch(S){(On(wt.current,C)||wa(wt.current,C))&&(wt.current=null),v===Wt.current&&!Ho.current&&d(ke.current)&&(Re("active"),j(S instanceof Error?S.message:String(S)));return}wt.current=null,v===Wt.current&&!ke.current&&Re("idle")})},$k);return zn.current=l,()=>{zn.current===l&&(window.clearTimeout(l),zn.current=null)}},[g,ge,Yn,j,Ae,Xn,ra,or]);const $c=s.useCallback(n=>{if(Nm.current===n)return;Nm.current=n;const o=ke.current,l=o?.deviceId||g,m=++Wt.current;sn.current="",Xe.current=null,Hi.current=!0,ht(null),je(!1),gn(!1),l&&(Dt("control",l),An(l,{preservePresentation:!1}),Re("stopping"),Yn(async()=>{if(o&&o.deviceId===l)try{await Xn(o,"control-session-document-hidden",{resumeWall:!1})}catch(d){!qn.current&&rr.current===n&&(Re("error"),j(d instanceof Error?d.message:String(d)));return}else An(l,{preservePresentation:!1}),U(d=>d===l?"":d);!ke.current&&Wt.current===m&&Re("idle")}))},[g,Yn,An,Dt,j,Xn]);s.useEffect(()=>{if(nr.current!==null&&(window.clearTimeout(nr.current),nr.current=null),!g||ge==="idle"||ge==="paused"||ge==="error")return;if(!Gt){$c(rr.current);return}if(ge==="stopping"||Yo){g&&gc&&ge==="connecting"&&(Hi.current=!1),g&&gc&&Hi.current&&(ge==="warm"||ge==="active")&&(Hi.current=!1,Xe.current=null,ht(null),je(!1),gn(!1),Dt("control",g),he(`control-presentation-resume-${Date.now()}-${g}`),Re("connecting"));return}Xe.current=null,Hi.current=!0,ht(null),je(!1),gn(!1),Re(o=>o==="idle"||o==="stopping"?o:"warm");const n=g;return An(n,{preservePresentation:!1}),nr.current=window.setTimeout(()=>{nr.current=null,++Wt.current,sn.current="";const o=ke.current;Re("stopping"),Yn(async()=>{if(o&&o.deviceId===n)try{await Xn(o,"control-session-warm-timeout")}catch(l){Re("error"),j(l instanceof Error?l.message:String(l));return}else An(n),U(l=>l===n?"":l);ke.current||Re("idle")})},Wk),()=>{nr.current!==null&&(window.clearTimeout(nr.current),nr.current=null)}},[Yo,gc,g,ge,Gt,Yn,An,$c,Dt,j,Xn]),s.useEffect(()=>()=>{nr.current!==null&&window.clearTimeout(nr.current),zn.current!==null&&(window.clearTimeout(zn.current),zn.current=null),wt.current=null},[]);const Vc=s.useCallback(()=>{const n=new Set(Jl.current),o=ke.current?.deviceId||"";g&&n.add(g),o&&n.add(o),Jl.current=[];for(const m of n){Vn.current.delete(m),Yt(m),An(m,{preservePresentation:!1});for(const d of[lt.current.get(m),hn.current.get(m),en.current.get(m)])d&&vn(d);Rr(m),Dt("wall",m),Dt("control",m),Hc(m)}const l=Nn.current;l&&vn(l),ji.current="",Bo.current=null,Bi.current=0},[Rr,g,vn,An,Hc,Yt,Dt]);s.useEffect(()=>{if(Gt){Jl.current=[...lu];return}Vc()},[Gt,lu,Vc]),s.useEffect(()=>{const n=Rn.current,o=ke.current;if(!or||!n||at.current[n.deviceId]||o&&o.deviceId===n.deviceId){nc.current=0;return}const l=nc.current,m=Math.min(5e3,500*2**Math.min(l,4)),d=window.setTimeout(()=>{jo.current===d&&(jo.current=null);const C=Rn.current;!zm.current||!C||at.current[C.deviceId]||!dn(C,n)||(nc.current=l+1,ii(C).catch(v=>{j(v instanceof Error?v.message:String(v)),dn(Rn.current,C)&&!ke.current&&Eb(S=>S+1)}))},m);return jo.current=d,()=>{window.clearTimeout(d),jo.current===d&&(jo.current=null)}},[ge,ii,j,or,Pb,Li]);const ba=g&&Le.find(n=>n.deviceId===g)||null,va=ba?.deviceId||"",cv=!!(Gt&&Ae&&Mn&&Cr),ns=!!(Ae&&Mn&&ge==="active"&&ba?.sessionId&&ct?.deviceId===ba.deviceId&&ct.sessionId===ba.sessionId&&ct.streamPurpose==="control"&&ct.commandId&&ct.captureGeneration>0&&ct.monitorIndex===ir),gp=ba?.capabilities?.clipboardProtocol==="livedesk.clipboard.v1",bp=gp&&yi(ba,"clipboardCopy"),vp=gp&&yi(ba,"clipboardPaste"),{state:rs,connectionId:no,routeReady:zc,sendInput:yp,stats:Ar,error:wp,remotePointerFeedback:ro}=fC(cv,Y,va,O),ao=ba?.sessionId||"",oo=ct?.commandId||"",io=Number(ct?.captureGeneration||0),si=Number(ct?.monitorIndex||0),lv=ro&&ro.deviceId===va&&ro.monitorIndex===si&&ro.controlSessionId===ao&&ro.controlCommandId===oo&&ro.captureGeneration===io?ro:null,as=s.useCallback((n,o)=>{const l=String(o.type||"").trim().toLowerCase();return Xs.current&&l!=="keyboard.reset"||!qn.current||!ns||!va||!ao||!oo||io<=0||n!==va?!1:yp(n,{...o,monitorIndex:si,controlSessionId:ao,controlCommandId:oo,captureGeneration:io})},[ns,io,oo,va,si,ao,yp]),Uc=[va,ao,oo,io,si,no].join("|"),gu=s.useRef(Uc);gu.current=Uc;const qc=s.useRef(null),wn=s.useCallback(async(n,o,l,m,d=15e3)=>{if(!no||gu.current!==m)throw new Error("Remote Control changed before the clipboard transfer completed.");const C=await Ue(`/api/remote/devices/${encodeURIComponent(va)}/clipboard`,{method:"POST",timeoutMs:d,body:JSON.stringify({action:n,hubConnectionId:no,operationId:o,binding:{sessionId:ao,commandId:oo,captureGeneration:io,monitorIndex:si},payload:l})},Y);if(gu.current!==m)throw new Error("Remote Control changed before the clipboard transfer completed.");if(C?.ok===!1)throw new Error(C.error||"Remote clipboard transfer failed.");return C},[io,oo,va,si,ao,no,Y]),Sp=s.useCallback(async(n,o)=>{const l=window.liveDesk?.clipboard;let m=!1,d=!1;try{await wn("clipboard.prepare",n,{clipboardDirection:"copy"},o),await wn("clipboard.copy",n,{clipboardDirection:"copy"},o),d=!0;const C=await wn("clipboard.copy.begin",n,{},o),v=Ld(C.manifest,n);if(l?.beginWrite&&l.writeChunk&&l.commitWrite){await l.beginWrite(v),m=!0;for(const S of v.items)for(const y of od(S.size)){const w=await wn("clipboard.copy.chunk",n,{itemIndex:S.itemIndex,offset:y.offset,maxBytes:wl},o),Z=bh(String(w.dataBase64||""));if(Number(w.itemIndex)!==S.itemIndex||Number(w.offset)!==y.offset||Number(w.bytes)!==y.byteLength||Z.byteLength!==y.byteLength||w.final===!0!==y.final)throw new Error("Remote clipboard chunk did not match the requested file range.");await l.writeChunk({operationId:n,itemIndex:S.itemIndex,offset:y.offset,dataBase64:String(w.dataBase64||""),final:y.final})}await l.commitWrite(n),m=!1}else{if(v.contentKind==="files")throw new Error("Multiple files require the VuvoDesk desktop app.");const S=[];for(const y of v.items){const w=new Uint8Array(y.size);for(const Z of od(y.size)){const be=await wn("clipboard.copy.chunk",n,{itemIndex:y.itemIndex,offset:Z.offset,maxBytes:wl},o),D=bh(String(be.dataBase64||""));if(D.byteLength!==Z.byteLength)throw new Error("Remote clipboard chunk was incomplete.");w.set(D,Z.offset)}if(await mb(w)!==y.sha256)throw new Error("Remote clipboard content check failed.");S.push(w)}await Pk({manifest:v,payloads:S})}await wn("clipboard.copy.end",n,{},o),d=!1,j(v.contentKind==="files"?`${v.items.length} remote file${v.items.length===1?"":"s"} copied.`:v.contentKind==="image"?"Remote image copied.":"Remote text copied.","success")}catch(C){throw m&&await l?.cancelWrite?.(n).catch(()=>{}),d&&await wn("clipboard.copy.end",n,{},o).catch(()=>{}),C}},[wn,j]),Cp=s.useCallback(async(n,o)=>{const l=window.liveDesk?.clipboard;let m=null,d,C=!1;try{l?.readSnapshot&&l.readChunk?d=Ld(await l.readSnapshot(n),n):(m=await Tk(n),d=m.manifest),await wn("clipboard.prepare",n,{clipboardDirection:"paste",manifest:d},o),C=!0,await wn("clipboard.paste.begin",n,{manifest:d},o);for(const y of d.items)for(const w of od(y.size)){const Z=l?.readChunk?await l.readChunk({operationId:n,itemIndex:y.itemIndex,offset:w.offset,maxBytes:w.byteLength||wl}):{operationId:n,itemIndex:y.itemIndex,offset:w.offset,byteLength:w.byteLength,dataBase64:Ik(m.payloads[y.itemIndex].subarray(w.offset,w.offset+w.byteLength)),final:w.final};if(Z.offset!==w.offset||Z.byteLength!==w.byteLength||Z.final!==w.final)throw new Error("Local clipboard changed during transfer.");const be=await wn("clipboard.paste.chunk",n,{itemIndex:y.itemIndex,offset:w.offset,dataBase64:Z.dataBase64,final:w.final},o);if(Number(be.itemIndex)!==y.itemIndex||Number(be.offset)!==w.offset||Number(be.bytes)!==w.byteLength||be.final===!0!==w.final)throw new Error("Remote clipboard did not confirm the requested file range.")}await wn("clipboard.paste",n,{clipboardDirection:"paste"},o);const v=Date.now()+xk;let S=!1;for(;Date.now()<v;){const y=await wn("clipboard.operation.status",n,{},o,Math.max(250,v-Date.now())),w=String(y.status||"").toLowerCase();if(["completed","complete","applied","pasted"].includes(w)){S=!0;break}if(["failed","cancelled","expired"].includes(w))throw new Error(`Remote clipboard paste ${w}.`);await new Promise(Z=>window.setTimeout(Z,Mk))}if(!S)throw new Error("Remote clipboard paste confirmation timed out.");C=!1,j(d.contentKind==="files"?`${d.items.length} file${d.items.length===1?"":"s"} pasted on the remote computer.`:d.contentKind==="image"?"Image pasted on the remote computer.":"Text pasted on the remote computer.","success")}catch(v){throw C&&await wn("clipboard.paste.cancel",n,{},o).catch(()=>{}),v}finally{await l?.releaseRead?.(n).catch(()=>{})}},[wn,j]),kp=s.useCallback(async n=>{if(!ns||!zc||rs!=="open"||!no){j("Remote input is not ready for clipboard transfer.","error");return}if(qc.current){j("Another clipboard transfer is still running.");return}const o=MC(n),l=Uc;qc.current={operationId:o,direction:n,bindingKey:l};try{Bn(n==="copy"?"Copying from the remote computer…":"Pasting on the remote computer…"),n==="copy"?await Sp(o,l):await Cp(o,l)}catch(m){j(m instanceof Error?m.message:String(m),"error")}finally{qc.current?.operationId===o&&(qc.current=null)}},[Uc,ns,Sp,no,zc,rs,Cp,j,Bn]),Ir=Gt&&qn.current&&ns&&rs==="open"&&zc&&!!no,bu={shiftKey:Ai.includes("ShiftLeft"),ctrlKey:Ai.includes("ControlLeft"),altKey:Ai.includes("AltLeft"),metaKey:Ai.includes("MetaLeft")},cr=s.useCallback(n=>Hs.current.enqueueStop(n),[]),so=s.useCallback(n=>Hs.current.enqueueStart(n),[]),un=s.useCallback((n,o=Bs.current)=>(js.current=n,Bs.current=n?String(o||""):"",sm.current=Ol.current,Ro.current+=1,Ro.current),[]),lr=s.useCallback((n,o,l)=>sm.current===Ol.current&&g0({generation:n,currentGeneration:Ro.current,enabled:js.current,deviceId:o,currentDeviceId:Bs.current,documentVisible:qn.current,presentationVisible:_l.current,streamId:l,currentStreamId:mt.current.get(o)||""}),[]),Jn=s.useCallback(async(n,o,l)=>{if(!o)return{ok:!0,alreadyStopped:!0,captureStopConfirmed:!0,noExactOwner:!0};const d=await(v=>Ue(`/api/remote/devices/${encodeURIComponent(n)}/audio/stop`,{method:"POST",body:JSON.stringify({...v?{streamId:v}:{},reason:l})},Y))(o),C=b0(d);if(C.staleOwner)return d;if(!C.confirmed)throw new Error(d?.error||"Remote audio capture stop was not confirmed.");return d},[Y]),vu=s.useCallback(async(n,o)=>{const l=await Ue(`/api/remote/devices/${encodeURIComponent(n)}/audio/stop`,{method:"POST",body:JSON.stringify({reason:o})},Y);if(l?.ok===!1||l?.captureStopConfirmed!==!0&&l?.alreadyStopped!==!0)throw new Error(l?.error||"Remote audio stop-all was not confirmed.");return l},[Y]),uv=s.useCallback(n=>{const o=Ro.current,l=mt.current.get(n)||"";return cr(()=>Jn(n,l,"remote-audio-automatic-restart")).then(()=>so(async()=>{if(o!==Ro.current||!js.current||Bs.current!==n||!qn.current||!_l.current||!pt||!sr||(Na.current||X?.deviceId||"")!==n)return"";const m=`audio-restart-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;if(mt.current.set(n,m),!lr(o,n,m))return mt.current.delete(n),"";const d=await Ue(`/api/remote/devices/${encodeURIComponent(n)}/audio/start`,{method:"POST",body:JSON.stringify({streamId:m,mimeType:"audio/pcm;format=f32le",sampleRate:48e3,channels:2})},Y);if(d?.ok===!1)throw mt.current.get(n)===m&&mt.current.delete(n),new Error(d.error||"Remote audio restart failed.");return lr(o,n,m)?m:(await Jn(n,m,"remote-audio-stale-restart-compensation"),mt.current.get(n)===m&&mt.current.delete(n),"")}))},[so,cr,pt,Y,lr,sr,X?.deviceId,Jn]),Mp=X?.deviceId&&mt.current.get(X.deviceId)||"",dv=s.useCallback(async(n,o,l)=>{un(!1),Dr(!1),await cr(()=>Jn(n,o,l)),mt.current.get(n)===o&&mt.current.delete(n)},[cr,un,Jn]),{state:yu,lastFrame:wu,stats:It,error:Su}=bC(X?.deviceId||"",Gt&&Jm&&Zt,Y,_b,fn||qt||rc.current,Mp,uv,dv,O),co=s.useRef(new Map);s.useEffect(()=>{const n=[["hub",Be],["registry",de],["license",We],["wall-stream",Oc],["control-stream",eo],["control-decode",yt],["remote-input",wp],["remote-audio",Su]];for(const[o,l]of n){const m=String(l||"").trim(),d=ke.current;if(o==="wall-stream"&&m==="CONTROL_CAPTURE_OWNS_DEVICE"&&!!d&&ua.current===d.deviceId){co.current.delete(o);continue}if(o==="hub"&&tt?.requiresHubRestart&&tt.stage==="updating"){co.current.delete(o);continue}if(o==="hub"&&W&&(xt?.kind==="signal-service-unavailable"||xt?.kind==="p2p-unavailable")){co.current.delete(o);continue}if(!m){const S=co.current.get(o);co.current.delete(o),o==="remote-input"&&S&&fm(S.noticeId,S.message);continue}if(co.current.get(o)?.message===m)continue;const v=j(m);co.current.set(o,{message:m,noticeId:v})}},[Su,fm,yt,eo,Be,xt?.kind,wp,We,W,de,j,Oc,tt]);const Gc=X?.deviceId||"",xp=X?_n(X,gt[Gc]):0;s.useEffect(()=>{if(ca||!Mn||!Cr||!Ir||!Gc)return;const n=WC(),o=Gc,l=xp,m=D=>{if(!D)return!1;const fe=as(o,{...D,monitorIndex:l});return!fe&&D.type!=="keyboard.reset"&&(n.reset("browser-input-send-rejected"),Os([])),fe},d=(D,fe)=>{if(Xs.current)return;const xe=D.target,Oe=xe?.tagName?.toLowerCase(),ze=xe?.isContentEditable||Oe==="input"||Oe==="textarea"||Oe==="select",qe=n.isPressed(D);if(ze&&(fe==="keydown"||!qe))return;const $t=fe==="keydown"?kC(D,Ak()):"";if($t&&($t==="copy"?bp:$t==="paste"?vp:!1)){D.preventDefault(),D.stopPropagation();const us=n.reset("remote-clipboard-shortcut",!0);us&&m(us),Os([]),kp($t);return}const fo=n.event(D,fe);fo&&(D.preventDefault(),D.stopPropagation(),m(fo))},C=D=>d(D,"keydown"),v=D=>d(D,"keyup"),S=(D,fe=!1)=>{const xe=n.reset(D,fe);xe&&(m(xe),Os([]))};Ll.current=D=>{const fe=n.snapshot().latchedCodes.includes(D),xe=n.modifier(D,!fe);xe&&(m(xe),Os(Oe=>fe?Oe.filter(ze=>ze!==D):[...Oe.filter(ze=>ze!==D),D]))};const y=D=>{const fe=sl(D);if(!fe)return!1;const xe=n.snapshot(),Oe={...fe,shiftKey:xe.shiftKey,ctrlKey:xe.ctrlKey,altKey:xe.altKey,metaKey:xe.metaKey},ze=n.event(Oe,"keydown");if(!ze||!m(ze))return!1;const qe=n.event(Oe,"keyup");return!!qe&&m(qe)};Ii.current={sendKey:y,sendText:D=>{let fe=!1;const xe=String(D??"").split(/(\r\n|\r|\n)/);for(const Oe of xe)if(Oe){if(Oe==="\r"||Oe===`
|
|
181
181
|
`||Oe===`\r
|
|
182
182
|
`){if(!y("Enter"))return!1;fe=!0;continue}for(const ze of BC(Oe)){const qe=n.snapshot();if(!m({type:"text",text:ze,repeat:!1,pressedCodes:qe.pressedCodes,shiftKey:qe.shiftKey,ctrlKey:qe.ctrlKey,altKey:qe.altKey,metaKey:qe.metaKey}))return!1;fe=!0}}return fe}};const w=()=>S("browser-window-blur"),Z=()=>S("browser-page-hidden"),be=()=>{document.visibilityState==="hidden"&&S("browser-document-hidden")};return window.addEventListener("keydown",C,!0),window.addEventListener("keyup",v,!0),window.addEventListener("blur",w),window.addEventListener("pagehide",Z),document.addEventListener("visibilitychange",be),()=>{window.removeEventListener("keydown",C,!0),window.removeEventListener("keyup",v,!0),window.removeEventListener("blur",w),window.removeEventListener("pagehide",Z),document.removeEventListener("visibilitychange",be),Ll.current=null,Ii.current=null,S("control-keyboard-owner-changed",!0)}},[ca,Cr,Ir,Gc,xp,Mn,bp,vp,kp,as]);const Rp=(n,o)=>{const l=sl(n);if(!l)return!1;const m=performance.now(),d=am.current;return d.key===l.key&&d.source!==o&&m-d.at<80?!0:(am.current={key:l.key,source:o,at:m},Ii.current?.sendKey(l.key)??!1)},Ap=s.useCallback(n=>{_l.current=n;const o=Na.current||X?.deviceId||"";if(!Zt||!o)return;const l=un(js.current,o);if(!n){const d=mt.current.get(o)||"";cr(async()=>{await Jn(o,d,"remote-audio-document-hidden")}).catch(C=>{(Na.current||X?.deviceId||"")===o&&(un(!1),mt.current.delete(o),Dr(!1),j(C instanceof Error?C.message:String(C)))});return}const m=`audio-presentation-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;mt.current.set(o,m),so(async()=>{if(!lr(l,o,m)||!pt||!sr||(Na.current||X?.deviceId||"")!==o)return;const d=await Ue(`/api/remote/devices/${encodeURIComponent(o)}/audio/start`,{method:"POST",body:JSON.stringify({streamId:m,mimeType:"audio/pcm;format=f32le",sampleRate:48e3,channels:2})},Y);if(d?.ok===!1)throw new Error(d.error||"Remote audio presentation resume failed.");lr(l,o,m)||(await Jn(o,m,"remote-audio-stale-presentation-compensation"),mt.current.get(o)===m&&mt.current.delete(o))}).catch(d=>{qn.current&&l===Ro.current&&(un(!1),mt.current.delete(o),Dr(!1),j(d instanceof Error?d.message:String(d)))})},[Zt,so,cr,un,pt,Y,lr,sr,X?.deviceId,j,Jn]);s.useEffect(()=>{const n=v=>{const S=qn.current;v!==S&&(qn.current=v,rr.current+=1,iu.current={active:v&&Ko.current,epoch:rr.current},v||(Vc(),$c(rr.current)),Ap(v),Ob(v),ve.current&&$({type:"visibility.changed",component:"document",state:v?"visible":"hidden",reason:"presentation-visibility-commit",details:{previous:S?"visible":"hidden",presentationOwnershipEpoch:rr.current}}),v&&!S&&(jb(y=>y+1),uc.current=performance.now()))},o=ew({readVisible:()=>document.visibilityState==="visible",initialCommittedVisible:qn.current,commitVisibility:n,schedule:(v,S)=>window.setTimeout(v,S),cancel:v=>window.clearTimeout(v)}),l=()=>o.handleVisibilityChange(),m=()=>o.handlePageHide(),d=()=>o.handleForegroundHint(),C=()=>o.handleForegroundHint();return document.addEventListener("visibilitychange",l),window.addEventListener("pagehide",m),window.addEventListener("pageshow",d),window.addEventListener("focus",C),o.handleForegroundHint(),()=>{document.removeEventListener("visibilitychange",l),window.removeEventListener("pagehide",m),window.removeEventListener("pageshow",d),window.removeEventListener("focus",C),o.dispose()}},[$,Vc,$c,Ap]),s.useEffect(()=>{if(!th({presentationOwnerActive:!!g&&(ge==="connecting"||ge==="active"||ge==="warm"),desiredDeviceCount:g?1:0}))return;const n=g,o=ut("control",n),l=window.setInterval(()=>{const m=performance.now();if(document.visibilityState!=="visible"||m-uc.current<fd)return;const d=Wr.current.get(o)||0,C=hr.current.get(o)||0,v=ma.current.get(o)||0,S=$r.current.get(o)||m;$r.current.has(o)||$r.current.set(o,S);const y=d<=0,w=y?m-S>tM:m-d>gd,Z=eh({lastReceivedAt:d,lastPaintedAt:C,now:m,staleAfterMs:gd}),be=Zf({paintStale:Z,lastRecoveryAt:gr.current.get(o)||0,now:m,recoveryCooldownMs:Oh,transportRecoveryAfterMs:_h});if(!w&&be==="reset-decoder"&&ai(n,"control","decoder-paint-stale")||!w&&be==="wait")return;if(!(w||be==="recover-transport")){Z&&ai(n,"control","decoder-paint-stale"),y&&m-S>eM&&!Fn.current.has(o)&&es([n],"control-frame-socket-recovery")&&(Fn.current.set(o,m),kt("control",n,"socket-reconnect","control-first-frame-socket-recovery",Nt.current.get(o)||0));return}const fe=Fn.current.get(o)||0;if(fe<=0){es([n],"control-frame-socket-recovery")&&(Fn.current.set(o,m),kt("control",n,"socket-reconnect",w?"control-receive-stale":"control-paint-stale",Nt.current.get(o)||0));return}if(m-fe<Lh)return;const xe=pa.current.get(o)||0;if(xe>0){if(m-xe<Nh)return;pa.current.delete(o)}const Oe=Nt.current.get(o)||0,ze=Le.find(Jr=>Jr.deviceId===n)||tn,qe=Kh(ze?.platform);if(!w&&be==="recover-transport"&&qe==="mode1-jpeg"&&ts("mac-control-paint-timeout"))return;if(Oe>=rM){if(ts(y?"no first frame":"stale stream"))return;je(!1),gn(!1),Un.current=n,kt("control",n,"terminal",y?"control-first-frame-restart-limit":"control-stream-restart-limit",Oe),Re("error");return}if(m-v<jh(nM,Oe))return;const $t=y?"control-first-frame-timeout":be==="recover-transport"?"control-paint-timeout":"control-receive-stale";jc([n],$t)&&(Fn.current.delete(o),gr.current.delete(o),ma.current.set(o,m),pa.current.set(o,m),$r.current.set(o,m),Nt.current.set(o,Oe+1),zr.current.delete(o),kt("control",n,"native-restart",$t,Oe+1))},650);return()=>window.clearInterval(l)},[Le,tn,g,ge,ts,es,kt,ai,jc]),s.useEffect(()=>{!yt||g&&at.current[g]||Gn!=="mode3-h264-hw"||ts(yt)||(je(!1),gn(!1),Un.current=ke.current?.deviceId||"",Re("error"))},[yt,g,Gn,ts]),s.useEffect(()=>{!Ae||!g||at.current[g]||!eo||(Un.current=g,Re(n=>n==="error"?n:"error"))},[eo,g,Ae]),s.useEffect(()=>{if(ge!=="error")return;const n=ke.current;if(!n)return;Un.current=n.deviceId,On(za.current,n)||(za.current=n,Wo.current=0);const o=Wo.current,l=o===0?0:Math.min(5e3,500*2**Math.min(o-1,4)),m=window.setTimeout(()=>{On(ke.current,n)&&(++Wt.current,sn.current="",Re("stopping"),Yn(async()=>{if(On(ke.current,n))try{if(!await Xn(n,"control-session-terminal-error"))return;za.current=null,Wo.current=0,Wi.current===n.deviceId?(Wi.current="",Un.current="",Re("idle")):Re("error")}catch(d){if(!On(ke.current,n))return;Wo.current+=1,j(d instanceof Error?d.message:String(d)),Re("error"),Im(C=>C+1)}}))},l);return()=>window.clearTimeout(m)},[ge,Nb,Yn,j,Xn]);const os=s.useCallback(n=>{if(!n||Un.current!==n)return!1;const o=ke.current;return++Wt.current,sn.current="",Wo.current=0,o&&o.deviceId===n?(Wi.current=n,za.current=null,Re("error"),Im(l=>l+1),!0):(Wi.current="",Un.current="",za.current=null,Re("idle"),!0)},[]);s.useEffect(()=>{if(!th({presentationOwnerActive:De.autoStartLive,desiredDeviceCount:Kt.length}))return;const n=window.setInterval(()=>{const o=performance.now();if(document.visibilityState!=="visible"||o-uc.current<fd)return;const l=1e3/Math.max(1,Ac||Hn||1),m=Math.max(Dh,Math.ceil(l*4)),d=[],C=[];for(const v of Kt){if(C.length+d.length>=sM)break;const S=ut("wall",v),y=Wr.current.get(S)||0,w=y<=0,Z=Vr.current.get(S)||o;Vr.current.has(S)||Vr.current.set(S,Z);const be=ma.current.get(S)||0,D=hr.current.get(S)||0,fe=w||o-y>m,xe=eh({lastReceivedAt:y,lastPaintedAt:D,now:o,staleAfterMs:m}),Oe=Zf({paintStale:xe,lastRecoveryAt:gr.current.get(S)||0,now:o,recoveryCooldownMs:Oh,transportRecoveryAfterMs:_h});if(!fe&&Oe==="reset-decoder"&&ai(v,"wall","decoder-paint-stale")||!fe&&Oe==="wait")continue;if(!(fe||Oe==="recover-transport")){xe&&ai(v,"wall","decoder-paint-stale");continue}const qe=Fn.current.get(S)||0;if(qe<=0&&(!w||o-Z>aM)){d.push(v);continue}if(w&&o-Z<=Fh||qe>0&&o-qe<Lh)continue;const $t=Nt.current.get(S)||0;if(!fe&&$t>=cM){$o.current.get(S)?.stage!=="terminal"&&kt("wall",v,"terminal","wall-paint-recovery-limit",$t);continue}o-be>=jh(oM,$t)&&C.push(v)}if(d.length>0&&pu(d,"wall-frame-socket-recovery"))for(const v of d){const S=ut("wall",v);Fn.current.set(S,o),kt("wall",v,"socket-reconnect","wall-frame-socket-recovery",Nt.current.get(S)||0)}if(C.length>0&&pu(C,"wall-frame-lane-retry"))for(const v of C){const S=ut("wall",v),y=(Nt.current.get(S)||0)+1;kt("wall",v,"lane-retry","wall-frame-lane-retry",y),Fn.current.set(S,o),gr.current.delete(S),ma.current.set(S,o),Vr.current.set(S,o),Wr.current.delete(S),hr.current.delete(S),Nt.current.set(S,y),zr.current.delete(S)}},iM);return()=>window.clearInterval(n)},[Ac,Kt,pu,kt,ai,De.autoStartLive,Hn]),s.useEffect(()=>{No(Hn),zi.current=Date.now(),br.current=0,vr.current=0,ar.current=0,Ui.current=0,qi.current=""},[Hn,De.frameMode,De.adaptiveLoadShedding]),s.useEffect(()=>{Ew({h264DecodeAcceleration:De.h264DecodeAcceleration})},[De.h264DecodeAcceleration]),s.useEffect(()=>{if(!pt||Ae||Ht==="list"||!De.visibleOnlyLive){Zs([]);return}const n=jm.current;if(!n||typeof IntersectionObserver>"u"){Zs(kc);return}const o=Array.from(n.querySelectorAll("[data-live-device-id]"));if(o.length===0){Zs([]);return}const l=new Map,m=a0(n,me),d=()=>{const v=vd(o.map(S=>String(S.dataset.liveDeviceId||"")).filter(S=>(l.get(S)||0)>0));Zs(S=>bd(S,v)?S:v)},C=new IntersectionObserver(v=>{for(const S of v){const y=String(S.target.dataset.liveDeviceId||"");y&&l.set(y,S.isIntersecting?S.intersectionRatio||.01:0)}d()},{root:m,rootMargin:me?KC:ur.visibleRootMargin,threshold:[0,.01,.2,.6,1]});return o.forEach(v=>C.observe(v)),d(),()=>C.disconnect()},[kc,pt,me,Ae,ha,De.visibleOnlyLive,Ht]),s.useEffect(()=>{if(!De.adaptiveLoadShedding||!De.autoStartLive||Kt.length===0){vr.current=0,ar.current=0,Ui.current=0,qi.current="";return}const n=Hn;if(Xi!=="open"||Ja.sampleMs<500||Ja.lastUpdatedAt<=0||Ui.current===Ja.lastUpdatedAt)return;Ui.current=Ja.lastUpdatedAt;const o=Date.now(),l=Kt.map(D=>{const fe=ic[ut("wall",D)];return{deviceId:D,receive:fe,paint:oc[ut("wall",D)],intentionalIdle:I0(fe?.lastFrame,o)}});if(!l.every(({receive:D,paint:fe})=>{const xe=D?.lastFrame,Oe=Math.max(0,Number(xe?.requestedFps||0)),ze=xe?er(xe):"";return A0({receiveSampleMs:Number(D?.sampleMs||0),paintSampleMs:Number(fe?.sampleMs||0),currentGenerationVerified:xe?.currentGenerationVerified===!0,frameRequestedFps:Oe,adaptiveFps:Pn})&&fe?.bindingKey===ze})){vr.current=0,ar.current=0,br.current=0;return}const d=[Pn,...l.map(({deviceId:D,receive:fe,intentionalIdle:xe})=>`${D}:${er(fe.lastFrame)}:${xe?"idle":"active"}`).sort()].join("|");if(qi.current!==d){qi.current=d,vr.current=o,ar.current=0,br.current=0;return}if(!vr.current){vr.current=o,ar.current=0;return}if(o-vr.current<ur.downshiftStableSampleMs)return;const C=l.filter(D=>!D.intentionalIdle),v=C.reduce((D,{receive:fe})=>D+Math.max(0,Number(fe?.framesPerSecond||0)),0),S=C.reduce((D,{receive:fe})=>D+Math.max(0,Number(fe?.framesPerSecond||0))*Math.max(0,Number(fe?.averageFrameBytes||0)),0),y=C.reduce((D,{paint:fe})=>D+Math.max(0,Number(fe?.framesPerSecond||0)),0),w=Math.max(0,...C.map(({receive:D})=>Number(D?.maxIntervalMs||0))),Z=Math.max(0,...C.map(({paint:D})=>Number(D?.p95IntervalMs||0))),be=C.length===0?{overloaded:!1,healthyForRecovery:!0}:R0({directDeviceCount:C.length,requestedFps:Pn,measuredFramesPerSecond:v,measuredPaintFramesPerSecond:y,measuredBytesPerSecond:S,maxBytesPerSecond:ur.maxWallBytesPerSecond,worstReceiveGapMs:w,worstPaintP95Ms:Z,maxFrameGapMs:ur.maxFrameGapMs});if(be.overloaded){if(br.current=0,ar.current+=1,ar.current<ur.downshiftConsecutiveSamples)return;const D=ur.minFps;if(o-zi.current>=ur.downshiftCooldownMs&&Pn>D){const fe=Math.max(D,PM(Pn,D));fe<Pn&&(No(fe),zi.current=o,vr.current=0,ar.current=0)}return}if(ar.current=0,!be.healthyForRecovery||Pn>=n){be.healthyForRecovery||(br.current=0);return}if(!br.current){br.current=o;return}if(o-br.current>=ur.recoveryCooldownMs){const D=Math.min(n,EM(Pn,n));D>Pn&&(No(D),zi.current=o,br.current=0,vr.current=0,ar.current=0)}},[Pn,Kt.length,Kt,oc,ic,Xi,Ja.lastUpdatedAt,Ja.sampleMs,De.adaptiveLoadShedding,De.autoStartLive,De.frameMode,Hn]),s.useEffect(()=>{const n=new URLSearchParams(window.location.search).get("checkout");if(n==="success"){j("Checkout returned. Waiting for Dodo confirmation."),vt();const o=window.setInterval(()=>{vt()},4e3),l=window.setTimeout(()=>{window.clearInterval(o)},45e3);return()=>{window.clearInterval(o),window.clearTimeout(l)}}n==="cancelled"&&j("Checkout cancelled.")},[vt]),s.useEffect(()=>{!pt&&Mn&&jn(!1),!pt&&Zt&&(un(!1),Dr(!1))},[Zt,Mn,un,pt]),s.useEffect(()=>{Zt&&(!X||!sr)&&(un(!1),Dr(!1))},[Zt,un,sr,X]),s.useEffect(()=>{const n=X?.deviceId||"",o=Na.current;if(Na.current=n,!o||o===n)return;const l=un(Zt,n),m=n?`audio-${Date.now()}-${Math.random().toString(36).slice(2,8)}`:"";n&&Zt&&mt.current.set(n,m);let d=!0;const C=mt.current.get(o)||"";return(async()=>{try{await cr(async()=>{await Jn(o,C,"remote-audio-device-switch"),mt.current.delete(o)}),await so(async()=>{if(!d||!lr(l,n,m)||!n||!pt||!sr)return;const v=await Ue(`/api/remote/devices/${encodeURIComponent(n)}/audio/start`,{method:"POST",body:JSON.stringify({streamId:m,mimeType:"audio/pcm;format=f32le",sampleRate:48e3,channels:2})},Y);if(v.ok===!1)throw new Error(v.error||"Remote audio start failed.");lr(l,n,m)||(await Jn(n,m,"remote-audio-stale-device-switch-compensation"),mt.current.get(n)===m&&mt.current.delete(n))})}catch(v){d&&(un(!1),mt.current.delete(n),Dr(!1),j(v instanceof Error?v.message:String(v)))}})(),()=>{d=!1}},[Zt,so,cr,un,pt,Y,lr,sr,X?.deviceId,Jn]),s.useEffect(()=>{const n=Le.map(d=>d.deviceId),o=new Set(n),l=new Map(Le.map(d=>[d.deviceId,d])),m=new Map;for(const d of Le){const C=fM(d);if(!C)continue;const v=dr(d.status),S=[d.lastStatusAt,v.capturedAt,v.collectedAt,v.timestamp,v.updatedAt].find(w=>typeof w=="string"&&w.trim()),y=VC(Di.current[d.deviceId],C,S);y&&(Di.current[d.deviceId]=y,m.set(d.deviceId,y),Qg({platform:d.platform,topologyFingerprint:C,consecutiveTopologySamples:y.consecutiveSamples})&&(Rm.current[d.deviceId]=C))}for(const d of Object.keys(Di.current))o.has(d)||delete Di.current[d];Tt(d=>{const C=d.filter(v=>o.has(v));return bd(d,C)?d:C}),Jt(d=>d&&o.has(d)?d:""),zt(d=>d&&o.has(d)?d:""),zl(d=>{let C=!1;const v={};for(const[S,y]of Object.entries(d)){const w=l.get(S);if(!w){v[S]=y;continue}const Z=m.get(S)||Di.current[S],be=zC({requestedIndex:y,monitorCount:Ma(w),platform:w.platform,topologyFingerprint:Z?.fingerprint||"",consecutiveTopologySamples:Z?.consecutiveSamples||0});v[S]=be,be!==y&&(C=!0)}return C?v:d}),ru(d=>{const C=d.filter(v=>o.has(v));return bd(d,C)?d:C})},[Le,yc]),s.useEffect(()=>{Hb([]),$b(!1)},[Qr]),s.useEffect(()=>{!Ga||qo!=="selected"||Go.length>0||cn.length===0||ru(cn.map(n=>n.deviceId))},[cn,Go.length,qo,Ga]),s.useEffect(()=>{try{localStorage.setItem(ib,Oo)}catch{}},[Oo]),s.useEffect(()=>{wM(De)},[De]),s.useEffect(()=>{CM(on)},[on]),s.useEffect(()=>{vM(gt,Rm.current)},[Le,gt]);const Kc=s.useCallback(async()=>{const n=new Set(L);n.add(Tn);try{const C=await Ue("/api/remote/status",void 0,Tn);Zp({endpoint:C.agentEndpoint,endpoint_candidates:[...C.agentEndpointCandidates||[],...C.hostTargetEndpointCandidates||[]]}).forEach(v=>n.add(v))}catch{}const o=[...n].sort((C,v)=>{const S=y=>{const w=gl(y);return w==="local"?0:w==="loopback"?1:2};return S(C)-S(v)||C.localeCompare(v)});let l=!1,m="",d=!1;try{for(const C of o){const v=gl(C);try{if(await Ue("/api/health",void 0,C),v==="local")return Ce(!0),gi(!0),C;v==="loopback"&&(l=!0,m=C)}catch{v==="local"&&(d=!0)}}return l?(d&&j("VuvoDesk Hub is reachable on this PC, but not through the LAN address yet. Restart VuvoDesk Hub to bind 5179 on the network."),Ce(!0),gi(!0),m||Tn):(Ce(!1),gi(!1),"")}catch{return Ce(!1),gi(!1),""}},[L]),Xr=async()=>{if(xn("auth"),_r(!1),window.liveDesk?.auth?.signInWithGoogle){const m=window.liveDesk.auth.signInWithGoogle();Kc();const d=await m;d?.ok===!1&&(j(d.error||"VuvoDesk could not open the system browser for Google sign-in."),xn(""));return}const n=Mt.auth.signInWithOAuth({provider:"google",options:{redirectTo:iy(window.location.href,sy)}});Kc();const{data:o,error:l}=await n;l&&(j(l.message),xn(""))},mv=async()=>{xn("auth"),_r(!1);const n=!!window.liveDesk?.auth?.signOut;try{if(n)(await window.liveDesk.auth.signOut())?.runtimeCleared===!1&&j("Signed out locally. The VuvoDesk runtime could not be reached to clear its session.","error");else{await k();const{error:o}=await Mt.auth.signOut({scope:"local"});if(o)throw o}}catch(o){j(`Sign-out is not complete: ${o instanceof Error?o.message:String(o)}. Remote access stays blocked; open Account and retry.`,"error")}xn("")},Ip=s.useCallback(async(n={})=>{const o=n.silent===!0,l=n.takeover===!0,m=n.requestLocalAccess===!0;if(!r?.user){o||j("Sign in before publishing this host.","error");return}if(W){o||j("Open VuvoDesk on the Hub computer to sync or configure that Hub.","error");return}if(re){o||j("Only the Team owner can sync or configure the Hub.","error");return}if(!G){o||j("Choose a workspace before syncing the Hub.","error");return}if(au.current)return;const d=G,C=O,v=()=>ie.current===C&&q(d),S=()=>{if(!v())throw new Error("The active VuvoDesk workspace changed while Hub sync was running.")};au.current=!0,o||(xn("host"),Bn("Hub · 1/3 · Checking the local runtime…"));try{const y=m?await Kc():"";S();const w=y||Y||Tn,Z=z||await Ue("/api/remote/status",void 0,w);if(S(),!Z.started)throw new Error("Start VuvoDesk on this computer before syncing the server.");o||Bn("Hub · 2/3 · Publishing the current workspace endpoint…"),S();const be=await Ue("/api/hub/sync",{method:"POST",body:JSON.stringify({takeover:l})},w);if(S(),!be.ok)throw new Error(be.error||"host-target-failed");if(!o){Bn("Hub · 3/3 · Verifying the endpoint and lease renewal…");const D=await Ue("/api/hub/status",void 0,w);if(S(),!D.hostTargetActive)throw new Error(D.hostTargetLease?.lastError||"host-target-not-active-after-sync");const fe=D.hostTargetEndpoint||D.agentEndpoint||"endpoint ready",xe=Number(D.connectedDeviceCount||0),Oe=xe>0?`${xe} client${xe===1?"":"s"} connected.`:"No clients connected yet; reconnect the laptop Client.";j(`Hub ready · ${fe} · lease auto-renewal active. ${Oe}`,"success"),(m||Ve)&&(Ce(!0),gi(!0)),Pe()}S(),se()}catch(y){if(!o){if(!v()){j("Hub sync stopped because the active workspace changed.","info");return}const w=y instanceof Error?y.message:String(y);w.includes("local network access")&&(Ce(!1),gi(!1)),j(`Hub setup failed · ${w}`,"error")}}finally{au.current=!1,o||xn(y=>y==="host"?"":y)}},[G,q,Y,Ve,W,Pe,se,Kc,r,j,Bn,z,re,O]),is=s.useCallback((n=!0)=>{nt!=="host"&&(jl(!1),n&&window.requestAnimationFrame(()=>mm.current?.focus()))},[nt]),pv=s.useCallback(()=>{if(nt!=="host"){if(re){j("Only the Team owner can sync or configure the Hub.","error");return}mm.current=document.activeElement instanceof HTMLElement?document.activeElement:null,_r(!1),jl(!0)}},[nt,j,re]),fv=s.useCallback(()=>{jl(!1),Ip({takeover:!0,requestLocalAccess:!0})},[Ip]);s.useEffect(()=>{if(!Po)return;const n=window.requestAnimationFrame(()=>dm.current?.focus()),o=m=>{m.target instanceof Element&&m.target.closest(".client-hub-switch-popover, .hub-sync-trigger")||is(!1)},l=m=>{m.key==="Escape"&&is()};return window.addEventListener("pointerdown",o),window.addEventListener("keydown",l),()=>{window.cancelAnimationFrame(n),window.removeEventListener("pointerdown",o),window.removeEventListener("keydown",l)}},[is,Po]);const Tp=s.useCallback(async()=>{if(!(!z?.update?.canApply||nt==="update")){xn("update");try{const n=await Ue("/api/update/apply",{method:"POST",body:JSON.stringify({})},Y||Tn);if(!n.ok)throw new Error(n.error||"VuvoDesk update could not be started.");const o=[...new Set((n.targets||[]).map(d=>String(d.deviceId||"").trim()).filter(Boolean))],l=!!(n.managerUpdateAvailable||n.clientPackageUpdateAvailable),m=n.state==="hub-restart-requested"?Date.now():void 0;(o.length>0||l)&&fr({operationId:String(n.operationId||`wall-update-${Date.now()}`),targetIds:o,stage:n.state==="clients-updated"?"updated":"updating",requiresHubRestart:l,initialHostInstanceId:String(z.hostInstanceId||""),targetManagerVersion:String(n.latestVersion||z.update?.latestVersion||""),targetClientVersion:String(n.latestClientVersion||z.update?.latestClientVersion||""),restartRequestedAt:m,restartDeadlineAt:m?m+pl:void 0}),Bn(n.state==="hub-restart-requested"?ml:kh),Pe()}catch(n){j(n instanceof Error?n.message:String(n),"error")}finally{xn("")}}},[nt,Y,Pe,j,Bn,z]);s.useEffect(()=>{const n=tt,o=z?.update;if(!n||n.stage!=="updating"||!o)return;const l=o.restartResult?.operationId===n.operationId?o.restartResult:null;if(l?.outcome==="restored"){const y=l.error||`The requested Hub ${l.targetVersion||n.targetManagerVersion||"version"} failed verification.`;fr(w=>w?.operationId===n.operationId?{...w,stage:"restored",error:y}:w),j(`VuvoDesk update did not complete. Hub ${l.fallbackVersion||l.appVersion||"the previous version"} was restored. ${y}`,"error");return}if(l?.outcome==="failed"){const y=l.error||"No verified VuvoDesk Hub replacement could be started.";fr(w=>w?.operationId===n.operationId?{...w,stage:"failed",error:y}:w),j(`VuvoDesk Hub update failed. ${y}`,"error");return}if(o.operationId===n.operationId&&o.state==="failed"){const y=o.error||"VuvoDesk update failed before the Hub replacement completed.";fr(w=>w?.operationId===n.operationId?{...w,stage:"failed",error:y}:w),j(y,"error");return}if(o.operationId===n.operationId){if(o.state==="hub-restart-requested"&&!n.restartDeadlineAt){const y=Date.now();fr(w=>w?.operationId===n.operationId?{...w,restartRequestedAt:y,restartDeadlineAt:y+pl}:w),Bn(ml)}!n.requiresHubRestart&&o.state==="clients-updated"&&(fr(y=>y?.operationId===n.operationId?{...y,stage:"updated"}:y),j("VuvoDesk clients updated and reconnected successfully.","success"));return}if(!n.requiresHubRestart)return;const m=z.started===!0&&(!n.initialHostInstanceId||z.hostInstanceId&&z.hostInstanceId!==n.initialHostInstanceId),d=!!o.checkedAt,C=Rh(o.currentVersion,n.targetManagerVersion),v=!n.targetClientVersion||Rh(o.currentClientVersion,n.targetClientVersion),S=d&&o.state==="idle"&&o.updateAvailable===!1&&C&&v;m&&S&&(fr(y=>y?.operationId===n.operationId?{...y,stage:"updated"}:y),j(`VuvoDesk Hub ${o.currentVersion||l?.appVersion||n.targetManagerVersion} restarted and passed version verification.`,"success"))},[j,Bn,z,tt]),s.useEffect(()=>{const n=tt;if(!n||n.stage!=="updating"||!n.requiresHubRestart||n.restartDeadlineAt)return;const o=()=>{const m=Date.now();fr(d=>d?.operationId===n.operationId&&d.stage==="updating"&&!d.restartDeadlineAt?{...d,restartRequestedAt:m,restartDeadlineAt:m+pl}:d),Bn(ml)};if(z?.update?.state==="hub-restart-requested"){o();return}if(!Be)return;const l=window.setTimeout(o,qk);return()=>window.clearTimeout(l)},[Be,Bn,z?.update?.state,tt]),s.useEffect(()=>{const n=tt;if(!n||n.stage!=="updating"||!n.requiresHubRestart||!n.restartDeadlineAt)return;const o=Math.max(0,n.restartDeadlineAt-Date.now()),l=n.operationId,m=window.setTimeout(()=>{const d=`VuvoDesk Hub did not return and verify ${n.targetManagerVersion||"the requested version"} within ${Math.round(pl/6e4)} minutes. Check the Hub terminal or restart log, then run livedesk@latest manually if the Hub is still offline.`;fr(C=>C?.operationId===l&&C.stage==="updating"?{...C,stage:"failed",error:d}:C),j(d,"error")},o);return()=>window.clearTimeout(m)},[j,tt]),s.useEffect(()=>{if(!tt||tt.stage!=="updated")return;const n=tt.operationId,o=window.setTimeout(()=>{fr(l=>l?.operationId===n?null:l)},Mh);return()=>window.clearTimeout(o)},[tt]),s.useEffect(()=>{ql.current.clear(),Ul({})},[tt?.operationId]),s.useEffect(()=>{if(!tt||z?.update?.operationId!==tt.operationId)return;const n=(z.update.targets||[]).filter(l=>l.state==="completed").map(l=>xh(tt.operationId,l)).filter(l=>!ql.current.has(l));if(n.length===0)return;const o=Date.now()+Mh;for(const l of n)ql.current.add(l);Ul(l=>({...l,...Object.fromEntries(n.map(m=>[m,o]))}))},[z?.update,tt]),s.useEffect(()=>{const n=Math.min(...Object.values(Js));if(!Number.isFinite(n))return;const o=window.setTimeout(()=>{const l=Date.now();Ul(m=>Object.fromEntries(Object.entries(m).filter(([,d])=>d>l)))},Math.max(0,n-Date.now()));return()=>window.clearTimeout(o)},[Js]),s.useEffect(()=>{if(Bl!==kh&&Bl!==ml)return;const n=z?.update;if(String(n?.state||"")==="failed"){j(n?.error||"VuvoDesk update failed.","error");return}tt?.stage==="updated"&&j("")},[Bl,j,z?.update?.error,z?.update?.state,tt?.stage]);const hv=s.useCallback(async()=>{if(!nt){xn("pin");try{const o=await Ue("/api/remote/pairing-pin",{method:"POST"},Y||Tn);if(!o.ok)throw new Error(o.error||"pin-rotation-failed");await Pe(),j("New PIN published.")}catch(n){j(n instanceof Error?n.message:String(n))}finally{xn("")}}},[nt,Y,Pe]),Cu=s.useCallback(n=>{n&&(Jt(n),Tt(o=>o.includes(n)?o:[...o,n]))},[]),ku=s.useCallback(n=>{if(!n)return;const o=Ya.has(n);Jt(l=>o?l===n?"":l:n),Tt(l=>o?l.filter(m=>m!==n):l.includes(n)?l:[...l,n])},[Ya]),ss=s.useCallback(()=>{Tt([]),Jt("")},[Yr]),Pp=s.useCallback(()=>{Tt(Le.map(n=>n.deviceId)),Jt("")},[Le]),Mu=s.useCallback((n,o)=>{const l=Le.find(d=>d.deviceId===n);if(!l)return;const m=Ma(l);if(!(m<=1)&&(zl(d=>{const C=Ss(d[n],m),v=(C+o+m)%m;return v===C?d:{...d,[n]:v}}),Dt("wall",n),Dt("control",n),Oi(d=>{if(!d.has(n))return d;const C=new Set(d);return C.delete(n),C}),Wa.current.delete(n),Br.current.delete(n),Ae)){const d=os(n);je(!1),d||Re("connecting"),gn(!1),zt(n)}},[Le,Dt,os,Ae]);s.useEffect(()=>{const n=o=>{if(Xs.current||Mn&&Cr&&Ir)return;const l=o.target,m=l?.tagName?.toLowerCase();l?.isContentEditable||m==="input"||m==="textarea"||m==="select"||((o.ctrlKey||o.metaKey)&&o.key.toLowerCase()==="a"&&(o.preventDefault(),Pp()),o.key==="Escape"&&ss())};return window.addEventListener("keydown",n),()=>window.removeEventListener("keydown",n)},[Cr,ss,Ir,Mn,Pp]);const gv=(n,o)=>{const l=Le.find(v=>v.deviceId===n),m=l?Ma(l):1,d=Ss(gt[n],m),C=Ss(o,m);if(d!==C&&(zl(v=>({...v,[n]:C})),Oi(v=>{if(!v.has(n))return v;const S=new Set(v);return S.delete(n),S}),Wa.current.delete(n),Br.current.delete(n),la.current.delete(n),_o.current.delete(n),$a.current.delete(n),Dt("wall",n),Dt("control",n)),Ae){const v=os(n);d!==C&&(je(!1),v||Re("connecting")),gn(!1),zt(n)}else Cu(n)},bv=n=>{const o=Na.current||X?.deviceId||"",l=[...new Set([o,n].filter(Boolean))],m=Zt||l.some(d=>mt.current.has(d));un(!1),Dr(!1);for(const d of l)mt.current.delete(d);l.length!==0&&(async()=>{for(const d of l)await cr(()=>vu(d,"remote-audio-control-entry"))})().catch(d=>{m&&j("Remote audio was muted locally, but Client capture stop was not confirmed: "+(d instanceof Error?d.message:String(d)),"error")})},ci=async n=>{const o={requestId:++Lb.current,deviceId:n,startedAt:performance.now(),startedAtEpochMs:Date.now()};if(Hr.current=o,!Sr.has(n)){Hr.current?.requestId===o.requestId&&(Hr.current=null),jn(!1),j(Jo);return}const l=Le.find(d=>d.deviceId===n);if(Nr(l?.platform)&&(l?.capabilities?.controlPermission===!1||l?.capabilities?.accessibilityPermission===!1)){Hr.current?.requestId===o.requestId&&(Hr.current=null),jn(!1),j("Mac remote control needs Accessibility permission. Allow it for the terminal app that starts VuvoDesk, then restart the Mac client.","error");return}bv(n),os(n),gn(!1),zt(n),La("control"),jn(!0),j(`Opening remote control${l?` for ${Qt(l)}`:""}.`,"success")},vv=async()=>{if(!X){j("Select a Client before playing audio.");return}if(!pt){j(Jo);return}if(!sr){j("Selected Client does not report remote audio support yet.");return}if(an)return;const n=!Zt,o=n?`audio-${Date.now()}-${Math.random().toString(36).slice(2,8)}`:mt.current.get(X.deviceId),l=un(n,X.deviceId);n&&o?mt.current.set(X.deviceId,o):n||mt.current.delete(X.deviceId),To("audio"),Dr(n);try{n?(await cr(()=>vu(X.deviceId,"remote-audio-user-enable-reconcile")),await so(async()=>{if(!o||!lr(l,X.deviceId,o))return;const m=await Ue(`/api/remote/devices/${encodeURIComponent(X.deviceId)}/audio/start`,{method:"POST",body:JSON.stringify({streamId:o,mimeType:"audio/pcm;format=f32le",sampleRate:48e3,channels:2})},Y);if(m?.ok===!1)throw new Error(m.error||"Remote audio start failed.");lr(l,X.deviceId,o)||await Jn(X.deviceId,o,"remote-audio-stale-user-start-compensation")})):await cr(()=>vu(X.deviceId,"remote-audio-user-disabled")),j(`${n?"Audio started":"Audio stopped"} for ${Qt(X)}.`,"success")}catch(m){un(!1),n&&mt.current.delete(X.deviceId),Dr(!1),j(m instanceof Error?m.message:String(m),"error")}finally{To("")}},yv=async(n,o)=>{const l=n.deviceId,m=Qt(n),d=String(at.current[l]||""),C=!!d&&Ao[l]===!0;if(o&&d&&!C)return{ok:!0,skipped:!0,action:"pause",deviceId:l,title:m};if(!o&&!d)return{ok:!0,skipped:!0,action:"resume",deviceId:l,title:m};if(!o&&d.startsWith("pending:"))return{ok:!1,action:"resume",deviceId:l,title:m,error:"Pause is still pending confirmation."};if(o){const Z=d||`pending:${Date.now()}:${l}`,be=ke.current?.deviceId===l?ke.current:null,D=!!be||g===l,fe=D?++Wt.current:0,xe=()=>df({deviceId:l,requestTransitionGeneration:fe,currentTransitionGeneration:Wt.current,actualControlOwner:ke.current}),Oe=aa.current.get(l);aa.current.set(l,{deviceId:l,monitorIndex:_n(n,gt[l]??Oe?.monitorIndex),previousControlOwner:be||Oe?.previousControlOwner||null}),um(l,!0),Io(l,!1),Ws(l,Z),hu(l),D&&(sn.current="",Re("paused"));try{const ze=await Ue(`/api/remote/devices/${encodeURIComponent(l)}/live/pause`,{method:"POST",body:JSON.stringify({reason:"user-video-pause"})},Y);if(!ze?.pauseToken)return Fa.current.delete(l),Ws(l,""),Io(l,!1),aa.current.delete(l),xe()&&(Xe.current=null,ht(null),je(!1),he(`control-pause-rollback-${Date.now()}-${l}`),Re("connecting")),{ok:!1,action:"pause",deviceId:l,title:m,error:ze?.error||"video-capture-pause-failed"};const qe=String(at.current[l]||"");if(qe!==Z&&qe!==ze.pauseToken)return{ok:!1,action:"pause",deviceId:l,title:m,error:"Pause ownership changed before confirmation."};const $t=xe(),Jr=$t&&ke.current?.deviceId===l?ke.current:be,fo=aa.current.get(l);return fo&&(fo.previousControlOwner=Jr),$t&&ke.current?.deviceId===l&&(ke.current=null),$t&&(Xe.current=null,ht(null)),Ws(l,ze.pauseToken),$t&&Re("paused"),ze.ok===!1||ze.captureStopConfirmed!==!0?(Io(l,!0),{ok:!1,unconfirmed:!0,action:"pause",deviceId:l,title:m,error:ze.stopError||ze.error||"Client capture shutdown was not confirmed."}):(Io(l,!1),{ok:!0,action:"pause",deviceId:l,title:m})}catch(ze){return Io(l,!0),{ok:!1,unconfirmed:!0,action:"pause",deviceId:l,title:m,error:ze instanceof Error?ze.message:String(ze)}}}const v=aa.current.get(l),S=v?.previousControlOwner||null,y=g===l&&(S!==null||Rn.current?.deviceId===l||ge==="paused"),w=y?Wt.current:0;try{um(l,!1);const Z=await Ue(`/api/remote/devices/${encodeURIComponent(l)}/live/resume`,{method:"POST",body:JSON.stringify({pauseToken:d})},Y);if(Z?.ok===!1)throw new Error(Z.error||"video-capture-resume-failed");if(String(at.current[l]||"")!==d)return{ok:!1,action:"resume",deviceId:l,title:m,error:"Resume ownership changed before confirmation."};const be=aa.current.get(l)||v,D=be?.previousControlOwner||S,fe=y&&df({deviceId:l,requestTransitionGeneration:w,currentTransitionGeneration:Wt.current,actualControlOwner:ke.current});if(Ws(l,""),Io(l,!1),aa.current.delete(l),fe){const xe=++Wt.current;sn.current="";const Oe=Gu(l,xe,{sessionId:n.sessionId||D?.sessionId,monitorIndex:_n(n,gt[l]??be?.monitorIndex)});ke.current=Oe,Qn(Oe),Un.current="",za.current=null,Xe.current=null,ht(null),Te(""),Ut(""),je(!1),Dt("control",l);const ze=`control-video-resume-${xe}-${l}`;he(ze),U(l),Re("connecting")}else Dt("wall",l);return{ok:!0,action:"resume",deviceId:l,title:m}}catch(Z){return Fa.current.delete(l),{ok:!1,action:"resume",deviceId:l,title:m,error:Z instanceof Error?Z.message:String(Z)}}},wv=async()=>{if(Yi.length===0){j("Select one or more Clients before pausing video.");return}if(Dn.length===0){j(Jo);return}if(an)return;const n=Dn.some(l=>{const m=String(at.current[l.deviceId]||"");return!m||m.startsWith("pending:")||Ao[l.deviceId]===!0}),o=Dn.filter(l=>{const m=String(at.current[l.deviceId]||"");return n?!m||m.startsWith("pending:")||Ao[l.deviceId]===!0:!!m});if(o.length===0){j(n?"Selected Clients are already paused.":"Selected Clients are already playing.");return}To("video");try{const l=await Promise.all(o.map(w=>yv(w,n)));Pe();const m=l.filter(w=>w.ok&&!w.skipped),d=l.filter(w=>!w.ok&&w.unconfirmed),C=l.filter(w=>!w.ok&&!w.unconfirmed),v=Dn.length-o.length+l.filter(w=>w.skipped).length,S=Yi.length-Dn.length,y=n?"pause":"resume";if(C.length>0||d.length>0){const w=C.slice(0,2).map(Z=>`${Z.title}: ${Z.error||"unknown error"}`).join(" · ");j([`Video ${y} completed for ${m.length}/${o.length} Clients.`,d.length>0?`${d.length} Client capture stop${d.length===1?"":"s"} remain unconfirmed.`:"",w,S>0?`${S} selected Client${S===1?"":"s"} were outside the current plan limit.`:""].filter(Boolean).join(" "),"error");return}j([`Video ${n?"paused":"resumed"} for ${m.length} Client${m.length===1?"":"s"}.`,v>0?`${v} already ${n?"paused":"playing"}.`:"",S>0?`${S} outside the current plan limit.`:""].filter(Boolean).join(" "),"success")}finally{To("")}},Sv=n=>{const o=n instanceof Error?n.message:String(n);return/remote-actions-disabled|remote-access-blocked-by-settings/i.test(o)?"Remote access is blocked. Change Settings > Remote Access > Access mode first.":/power-actions-disabled|allowPowerActions-blocked-by-settings/i.test(o)?"Power actions are off. Turn on Settings > Remote Access > Power actions first.":/agent-tool-capability-unavailable|unsupported-agent-operation/i.test(o)?"This Client needs a newer VuvoDesk Client for power actions.":/device-not-connected|404 device-not-found/i.test(o)?"The Client disconnected before the action could be sent.":o},xu=async n=>{if(!X||an)return;const o=X,m={sleep:"Sleep",restart:"Restart",shutdown:"Shut down"}[n];if(window.confirm(`${m} ${Qt(o)}? Unsaved work on that computer may be lost.`)){To(n),j(`Sending ${m.toLowerCase()} request to ${Qt(o)}...`);try{const d=await Ue(`/api/remote/devices/${encodeURIComponent(o.deviceId)}/quick-actions`,{method:"POST",body:JSON.stringify({action:n})},Y);if(!d.ok)throw new Error(d.error||"The remote action could not be sent.");j(`${m} request sent to ${Qt(o)}.`,"success"),Pe()}catch(d){j(Sv(d),"error")}finally{To("")}}},Ep=async(n,o,l="files")=>{const m=n.filter(S=>S.file.size>=0);if(m.length===0)return{files:0,bytes:0};if(!pt)throw new Error(Jo);if(o.length===0)throw new Error("Select at least one connected Client.");const d=crypto.randomUUID(),C=m.reduce((S,y)=>S+y.file.size,0);let v=0;fa({id:d,status:"reading",progress:1,message:`Preparing ${m.length} ${l}`});try{for(let S=0;S<m.length;S+=1){const y=m[S],w=y.file,Z=Math.max(1,Math.ceil(w.size/pd));for(let be=0;be<Z;be+=1){const D=be*pd,fe=Math.min(w.size,D+pd),xe=w.size===0?new ArrayBuffer(0):await w.slice(D,fe).arrayBuffer(),Oe=be===Z-1;fa({id:d,status:"sending",progress:Math.max(2,Math.min(98,Math.round(v/Math.max(1,C)*96))),message:`${S+1}/${m.length} ${y.relativePath}`});const ze=await Ue("/api/remote/files/chunk",{method:"POST",body:JSON.stringify({transferId:d,deviceIds:o,remoteDirectory:Oo.trim(),name:w.name,relativePath:y.relativePath,size:w.size,type:w.type,lastModified:w.lastModified,offset:D,totalBytes:w.size,final:Oe,dataBase64:NM(xe)})},Y);if(!ze.ok||ze.queued!==o.length)throw new Error(ze.error||`file-chunk-not-queued-${ze.queued}/${o.length}`);v+=xe.byteLength,await new Promise(qe=>window.setTimeout(qe,0))}}return fa({id:d,status:"queued",progress:100,message:`Sent ${m.length} file${m.length===1?"":"s"} to ${o.length} Client${o.length===1?"":"s"}`}),window.setTimeout(()=>{fa(S=>S?.id===d&&S.status==="queued"?null:S)},4500),{files:m.length,bytes:C}}catch(S){throw fa({id:d,status:"failed",progress:100,message:S instanceof Error?S.message:String(S)}),S}},Np=async n=>{const o=cn.length>0?cn.map(l=>l.deviceId):X?[X.deviceId]:[];try{await Ep(Wh(n),o)}catch(l){j(l instanceof Error?l.message:String(l))}},Fp=async n=>{try{await Ep(Wh(n),Xb)}catch(o){j(o instanceof Error?o.message:String(o))}};s.useEffect(()=>{Ub.current=!1},[]);const Cv=n=>{n.preventDefault(),n.stopPropagation(),nu(!1),Np(n.dataTransfer.files)},lo=async(n="plus_ltd")=>{const o=j0(n);if(!o){j("This VuvoDesk checkout option is not recognized.");return}if(!r){j("Sign in with Google before checkout.");return}if(T||!b){j("Your VuvoDesk workspace is still loading. Try again in a moment.");return}if(re){j("The Team owner manages billing and plan changes.");return}if(!lh(n)&&!In){j("VuvoDesk LTD checkout is not open yet.");return}if(lh(n)&&!cd(n)&&!Ca){j("VuvoDesk Plus and Pro monthly checkout is not open yet.");return}if(cd(n)&&!Zr){j("VuvoDesk Team checkout is not open yet. Contact support to join the Team launch group.");return}const l=b?.kind==="personal"&&b.id===r.user.id;if(o!=="team"&&l&&oe&&o===Je){j("VuvoDesk license is already active.");return}if(o!=="team"&&l&&oe&&Je==="pro"){j("VuvoDesk Pro is already active.");return}xn("checkout");try{let m=r.user.id;if(cd(n)){let v=M.find(S=>S.kind==="team"&&S.role==="owner")?.id||"";if(v)G!==v&&await B(v);else{const{data:S,error:y}=await Mt.rpc("create_livedesk_team_workspace",{p_name:`${uo||"My"} Team`});if(y)throw y;const w=Array.isArray(S)?S[0]:S,Z=String(w?.workspace_id||"").trim();if(!w?.ok||!Z)throw new Error(String(w?.reason||"Team Space could not be created."));await B(Z),v=Z}m=v}const{data:d,error:C}=await Mt.functions.invoke("dodo-checkout",{body:{plan:n,workspace_id:m}});if(C)throw C;if(!d?.checkout_url)throw new Error("Checkout function did not return a checkout URL.");window.location.assign(d.checkout_url)}catch(m){j(m instanceof Error?m.message:String(m)),xn("")}},Yc=lM(),Dp=uM(),Ru=lu.filter(n=>ri.has(n)).length,Au=fu==="open"&&Bc.sampleMs>0?`${Bc.framesPerSecond.toFixed(1)} fps`:fu,le=X?Ae?Zi.get(X.deviceId):ri.get(X.deviceId):void 0,Qc=X?_n(X,gt[X.deviceId]):0,kv=X?pM(X):[],Mv=typeof le?.monitorIndex=="number"?Ss(le.monitorIndex,Math.max(1,le.monitorCount||1)):Qc,Iu=(le&&Mv===Qc?vb(le):null)||(X?bb(X,Qc):null);Iu&&`${Iu.width}${Iu.height}`;const Xc=X?ut(Ae?"control":"wall",X.deviceId):"",rn=Xc?ic[Xc]:void 0,Ln=Xc?oc[Xc]:void 0,Ne=Ln?.lastInfo,xv=rn&&rn.sampleMs>0?`${rn.framesPerSecond.toFixed(1)} fps`:"waiting";rn&&`${rn.totalFrames}${xv}`,Ln&&Ln.sampleMs>0&&`${Ln.framesPerSecond.toFixed(1)}`,Ln&&Ln.sampleMs>0&&`${Ln.changedFramesPerSecond.toFixed(1)}`,Ne&&(`${Ne.frameSeq}${Ne.decoderLabel}${Ne.queueSize}${Ne.renderQueueSize}${Ne.droppedForLatency}${Ne.decoderFlushCount}${Ne.decoderTimestampFallbacks}${Ne.decoderInputCount}${Ne.decoderOutputCount}`,Ne.visualChanged),Ne&&`${Math.round(Ne.queuedForMs)}${Math.round(Ne.decodedForMs)}${Math.round(Ne.scheduledForMs)}${Ne.drawMs.toFixed(1)}`,Ne?.targetPaintIntervalMs&&`${Ne.targetPaintIntervalMs.toFixed(1)}${(1e3/Ne.targetPaintIntervalMs).toFixed(1)}`,Ln&&`${Ln.decoderInputFps.toFixed(1)}${Ln.decoderOutputFps.toFixed(1)}`,Ne?.canvasPresentation,Ne&&`${Ne.interactiveBufferWaitCount}${Math.round(Ne.interactiveBufferWaitMs)}${Ne.interactiveQueueDrainCount}`,rn&&(le?.frameMode==="mode5-lzo-delta"?`${Cs(rn.averageFrameBytes)}${le.deltaVisualTileCount||0}${le.deltaRefreshTileCount||0}${le.deltaTotalTiles||0}`:`${Cs(rn.averageFrameBytes)}${Math.round(rn.tinyFrameRatio*100)}${Math.round(rn.repeatedFrameRatio*100)}`),rn&&rn.sourceSendSampleCount>0&&`${rn.sourceSendAverageMs.toFixed(1)}${rn.sourceSendP95Ms.toFixed(1)}`,Th(rn),Th(Ln),rn&&Ln&&`${Ph(rn)}${Ph(Ln)}`,le?le.frameMode||le.mode||le.codec||le.mimeType:Ae?on.frameMode:De.frameMode,Ae?on.frameMode:De.frameMode,le?`${le.width}${le.height}${Cs(le.byteLength)}`:Ae?`${wr.maxWidth}${wr.maxHeight}`:`${De.maxWidth}${De.maxHeight}`,le&&`${le.isKeyFrame?"key":String(le.chunkType||"delta")}`,le&&le.monitorCount&&((le.monitorIndex??0)+1,`${le.monitorCount}`),le&&[`src ${Math.round(le.sourceGapMs||0)}ms`,`gap ${Math.round(le.agentSendGapMs||0)}ms`,`tx ${Math.round(le.agentSendDurationMs||0)}ms`,`pace ${Math.round(le.agentPaceMs||0)}ms`,`queue ${Math.round(le.agentQueueBeforePaceMs||0)}ms`,`age ${Math.round(le.agentFrameAgeMs||0)}ms`,le.hubPacketTransitAgeMs!==void 0?`sock ${Math.max(0,Math.round(le.hubPacketTransitAgeMs))}ms`:"",le.droppedByAgent?`drop ${le.droppedByAgent}`:"",le.hubIngressDropped?`ingress-drop ${le.hubIngressDropped}`:"",le.hubClientDropped?`ws-drop ${le.hubClientDropped}`:"",le.captureStageMs?`capture ${Math.round(le.captureStageMs)}ms`:"",le.requestedFps?`req ${Math.round(le.requestedFps)}fps`:"",le.effectiveFps?`eff ${Math.round(le.effectiveFps)}fps`:"",le.captureAverageMs?`avg ${Math.round(le.captureAverageMs)}ms`:"",le.captureP95Ms?`p95 ${Math.round(le.captureP95Ms)}ms`:"",le.slowFrameCount?`slow ${Math.round(le.slowFrameCount)}`:"",le.captureHelperRestarts?`helper ${Math.round(le.captureHelperRestarts)}`:"",le.convertMs?`rgb565 ${Math.round(le.convertMs)}ms`:"",le.compressMs?`lzo ${Math.round(le.compressMs)}ms`:"",le.captureSourceSerial?`cap #${le.captureSourceSerial}`:"",le.captureSourceSkipped?`cap skip ${le.captureSourceSkipped}`:"",le.frameMode==="mode5-lzo-delta"?`tiles ${le.deltaVisualTileCount||0}+${le.deltaRefreshTileCount||0}/${le.deltaTotalTiles||0}@${le.deltaTileSize||0}`:"",le.platformProfile||le.hardwareEncoder||"-",le.atlasComposeMs?`atlas ${le.atlasComposeMs.toFixed(1)}ms`:"",le.atlasPoolStarved?`pool ${le.atlasPoolStarved}`:"",le.atlasTileCount?`tiles ${le.atlasReadyTiles||0}/${le.atlasTileCount}`:"",le.atlasInputRevision?`input #${le.atlasInputRevision}`:"",le.atlasSourceMaxAgeMs!==void 0?`input-age ${Math.round(le.atlasSourceMaxAgeMs)}ms`:"",Ne?.inputFeedbackMs!==void 0&&Ne.inputFeedbackAt!==void 0&&performance.now()-Ne.inputFeedbackAt<=vh?`feedback ${Math.round(Ne.inputFeedbackMs)}ms`:"",le.contentHash?`enc ${le.contentHash.slice(0,6)}`:"",Ne?.visualHash?`pix ${Ne.visualHash.slice(0,6)}`:""].filter(Boolean).join(" / "),rs==="open"&&zc&&[`${Ar.sentPerSecond.toFixed(1)} hz`,Ar.lastInputSeq>0?`rtt ${Math.round(Ar.lastRoundTripMs)}ms`:"",Ar.lastInputSeq>0?`apply ${Ar.lastAgentApplyMs.toFixed(1)}ms`:"",Ar.droppedPerSecond>0?`drop ${Ar.droppedPerSecond.toFixed(1)}/s`:"",Ar.bufferedAmount>0?`buf ${Cs(Ar.bufferedAmount)}`:"",Ar.lastInputType||"ready"].filter(Boolean).join(" / "),Ne?.inputFeedbackMs!==void 0&&Ne.inputFeedbackAt!==void 0&&performance.now()-Ne.inputFeedbackAt<=vh&&[Ne.inputFeedbackExact?"exact":"estimated",Ne.inputFeedbackInputType||"",`total ${Math.round(Ne.inputFeedbackMs)}ms`,Ne.inputFeedbackAgentApplyMs!==void 0?`apply ${Ne.inputFeedbackAgentApplyMs.toFixed(1)}ms`:"",Ne.inputFeedbackApplyToCaptureMs!==void 0?`apply→frame ${Math.round(Ne.inputFeedbackApplyToCaptureMs)}ms`:"",Ne.inputFeedbackInputToFrameMs!==void 0?`input→browser ${Math.round(Ne.inputFeedbackInputToFrameMs)}ms`:"",Ne.inputFeedbackFrameToPaintMs!==void 0?`browser→paint ${Math.round(Ne.inputFeedbackFrameToPaintMs)}ms`:"",Ne.inputFeedbackSampleCount?`p50 ${Math.round(Ne.inputFeedbackP50Ms||0)}ms`:"",Ne.inputFeedbackSampleCount?`p95 ${Math.round(Ne.inputFeedbackP95Ms||0)}ms`:"",Ne.inputFeedbackSampleCount?`n=${Ne.inputFeedbackSampleCount}`:"",`input #${Ne.inputFeedbackSeq||0}`].filter(Boolean).join(" / "),le&&`${le.frameSeq}${oy(le.receivedAt||le.capturedAt)}`;const li=Math.max(0,Bc.bytesPerSecond*8/1e6),Lp={activeTool:Pt,audioError:Su,audioMode:Zt,audioState:yu,audioStats:It,lastAudioFrame:wu,selectedAudioCaptureStreamId:Mp,controlFrames:Zi,controlInputReady:Ir,controlMode:Mn,controlPresentationReady:Xl,controlSessionDeviceId:g,controlSessionFrameReady:Qe,controlSessionState:ge,controlStreamBinding:ct,devices:Me,documentPresentationVisible:Gt,focusedDeviceId:jt,frames:ri,localFeatureAccess:pt,quickActionBusy:an,selectedDeviceId:X?.deviceId||"",selectedIds:et,showControlFocus:Ae,videoCaptureStopUnconfirmedByDeviceId:Ao,videoCapturePausedDeviceIds:Pi,wallPresentationReadyDeviceIds:Kl},Op=s.useRef(Lp);Op.current=Lp,s.useEffect(()=>{if(!rc.current)return;const n=window,o=S=>{if(!S)return null;const y=S.sourceGapMs,w=y==null||y===""?null:Number.isFinite(Number(y))?Number(y):null,Z=S;return{deviceId:S.deviceId,sessionId:S.sessionId||"",streamId:S.streamId||"",commandId:S.commandId||"",captureGeneration:Number(S.captureGeneration||0),monitorIndex:Number(S.monitorIndex||0),streamPurpose:S.streamPurpose||"",frameSeq:Number(S.frameSeq||0),frameMode:S.frameMode||"",mimeType:S.mimeType||"",currentGenerationVerified:Z.currentGenerationVerified===!0,receivedAt:Z.receivedAt||"",capturedAt:Z.capturedAt||"",sourceGapMs:w,inputFeedbackEventId:String(S.inputFeedbackEventId||""),inputFeedbackInputSeq:Number(S.inputFeedbackInputSeq||0),inputFeedbackIssuedAtEpochMs:Number(S.inputFeedbackIssuedAtEpochMs||0),inputFeedbackAgentApplyMs:Number(S.inputFeedbackAgentApplyMs||0),inputFeedbackApplyToCaptureMs:Number(S.inputFeedbackApplyToCaptureMs||0)}},l=S=>{if(!S)return null;const y=window.getComputedStyle(S),w=S.getBoundingClientRect(),Z=Math.max(0,Math.min(w.right,window.innerWidth)-Math.max(w.left,0)),be=Math.max(0,Math.min(w.bottom,window.innerHeight)-Math.max(w.top,0)),D=Number(y.opacity),fe=S.isConnected&&y.display!=="none"&&y.visibility!=="hidden"&&y.visibility!=="collapse"&&Number.isFinite(D)&&D>0&&w.width>0&&w.height>0&&Z>0&&be>0;return{connected:S.isConnected,userVisible:fe,width:Math.max(0,Number(S.width||0)),height:Math.max(0,Number(S.height||0)),css:{display:y.display,visibility:y.visibility,opacity:Number.isFinite(D)?D:0},rect:{left:w.left,top:w.top,right:w.right,bottom:w.bottom,width:w.width,height:w.height,viewportIntersectionWidth:Z,viewportIntersectionHeight:be},codec:ps(S)}},m=(S,y)=>{const w=da.current.get(ut(S,y));return w?{bindingKey:w.bindingKey||"",totalFrames:w.totalFrames,totalChangedFrames:w.totalChangedFrames,lastFrameSeq:Number(w.lastFrameSeq||0),lastPaintAgeMs:w.lastAt===void 0?-1:Math.max(0,performance.now()-w.lastAt),lastInfo:w.lastInfo?{frameSeq:Number(w.lastInfo.frameSeq||0),decoderInputCount:Number(w.lastInfo.decoderInputCount||0),decoderOutputCount:Number(w.lastInfo.decoderOutputCount||0),targetPaintIntervalMs:Number(w.lastInfo.targetPaintIntervalMs||0),droppedForLatency:Number(w.lastInfo.droppedForLatency||0),visualChanged:w.lastInfo.visualChanged===!0,inputFeedbackExact:w.lastInfo.inputFeedbackExact===!0,inputFeedbackMs:Number(w.lastInfo.inputFeedbackMs||0),inputFeedbackSampleCount:Number(w.lastInfo.inputFeedbackSampleCount||0),inputFeedbackP50Ms:Number(w.lastInfo.inputFeedbackP50Ms||0),inputFeedbackP95Ms:Number(w.lastInfo.inputFeedbackP95Ms||0),inputFeedbackTargetMs:wh,inputFeedbackTargetMinSamples:Sh,inputFeedbackOnTarget:w.lastInfo.inputFeedbackExact===!0&&Number(w.lastInfo.inputFeedbackSampleCount||0)>=Sh&&Number(w.lastInfo.inputFeedbackP95Ms)<wh}:null}:null},d=(S,y)=>{if(!S)return null;if(y==="wall-visible"){const Z=da.current.get(ut("wall",S));return Z?{bindingKey:Z.bindingKey||"",total:Z.totalFrames,lastFrameSeq:Number(Z.lastFrameSeq||0),lastPaintAgeMs:Z.lastAt===void 0?-1:Math.max(0,performance.now()-Z.lastAt)}:null}if(y!=="control-visible"&&y!=="wall-reuse-visible")return null;const w=ac.current.get(`${y}:${S}`);return w?{bindingKey:w.bindingKey,total:w.totalPaints,lastFrameSeq:w.lastFrameSeq,lastPaintAgeMs:Math.max(0,performance.now()-w.lastPaintAt)}:null},C=(S,y)=>{const w=d(S,y);return w?{bindingKey:w.bindingKey,totalPaints:w.total,lastPaintAgeMs:w.lastPaintAgeMs,lastFrameSeq:w.lastFrameSeq}:null},v={readPresentationCounter(S,y){return d(String(S||""),y)},snapshot(S,y={}){const w=String(S||""),Z=y.includeHistory===!0,be=Math.max(0,Number(y.presentationAfterSequence||0)),D=Op.current,fe=D.devices.find(Pr=>Pr.deviceId===w)?.liveCapturePause,xe=String(at.current[w]||""),Oe=lt.current.get(w)||null,ze=Et.current.get(w)||null,qe=hn.current.get(w)||null,$t=KS(),Jr=_u(),fo=YS(),us={frameStats:cc.current===null?0:1,wallRecovery:jo.current===null?0:1,controlWarm:nr.current===null?0:1,controlWallDownshift:zn.current===null?0:1},Lu=Hr.current?.deviceId===w?Hr.current:null,Jp=Em.current.get(w)||null;return{capturedAt:Date.now(),deviceId:w,activeTool:D.activeTool,documentPresentationVisible:D.documentPresentationVisible,showControlFocus:D.showControlFocus,selectedDeviceId:D.selectedDeviceId,focusedDeviceId:D.focusedDeviceId,selectedDeviceIds:[...D.selectedIds],localFeatureAccess:D.localFeatureAccess,quickActionBusy:D.quickActionBusy,audioMode:D.audioMode,audioState:D.audioState,audioError:D.audioError,audioCaptureStreamId:D.selectedAudioCaptureStreamId,audioFrame:D.lastAudioFrame?{deviceId:D.lastAudioFrame.deviceId,streamId:D.lastAudioFrame.streamId,frameSeq:Number(D.lastAudioFrame.frameSeq||0),mimeType:D.lastAudioFrame.mimeType,sampleRate:Number(D.lastAudioFrame.sampleRate||0),channels:Number(D.lastAudioFrame.channels||0),byteLength:Number(D.lastAudioFrame.byteLength||0)}:null,audioStats:{...D.audioStats},videoCapturePausePhase:xe?xe.startsWith("pending:")?"pending":"confirmed":"none",videoCaptureStopUnconfirmed:D.videoCaptureStopUnconfirmedByDeviceId[w]===!0,authoritativeLiveCapturePause:fe?{phase:fe.phase||"",captureStopConfirmed:fe.captureStopConfirmed===!0,stopAttemptCount:Math.max(0,Number(fe.stopAttemptCount||0)),stopError:fe.stopError||""}:null,controlMode:D.controlMode,controlSessionDeviceId:D.controlSessionDeviceId,controlSessionState:D.controlSessionState,controlSessionFrameReady:D.controlSessionFrameReady,controlPresentationReady:D.controlPresentationReady,controlInputReady:D.controlInputReady,controlConnection:Jp?{...Jp}:null,pendingControlConnection:Lu?{...Lu,elapsedMs:Math.max(0,performance.now()-Lu.startedAt)}:null,videoCapturePaused:D.videoCapturePausedDeviceIds.has(w),wallPresentationReady:D.wallPresentationReadyDeviceIds.has(w),controlBinding:D.controlStreamBinding?.deviceId===w?{...D.controlStreamBinding}:null,actualControlOwner:ke.current?.deviceId===w?{...ke.current}:null,wallCapturePauseOwner:Rn.current?.deviceId===w?{...Rn.current}:null,frameSubscriptions:$t,mobileConsoleDirect:Jr,audioSubscriptions:fo,presentationTimers:{...us,total:Object.values(us).reduce((Pr,Ou)=>Pr+Ou,0)},wallFrame:o(D.frames.get(w)),controlFrame:o(Wa.current.get(w)||D.controlFrames.get(w)),wallPaint:m("wall",w),controlPaint:m("control",w),controlVisiblePaint:C(w,"control-visible"),wallReuseVisiblePaint:C(w,"wall-reuse-visible"),presentationPaintSequence:Pm.current,presentationPaintEvents:Z?Yl.current.filter(Pr=>Pr.deviceId===w&&Pr.sequence>be).sort((Pr,Ou)=>Pr.sequence-Ou.sequence).map(Pr=>({...Pr})):[],wallCanvas:l(Oe),controlDecodeCanvas:l(ze),controlPresentationCanvas:l(qe),globalCodec:ps(void 0,{includeLifecycleEvents:Z})}}};return n.__liveDeskTransmissionProbe=v,()=>{n.__liveDeskTransmissionProbe===v&&delete n.__liveDeskTransmissionProbe}},[]);const _p=s.useCallback(()=>{Lo(!0),Qs(Date.now()),Pe(),Or.current!==null&&window.clearTimeout(Or.current),Or.current=window.setTimeout(()=>{Or.current=null,Qs(Date.now()),Lo(!1)},650)},[Pe]),jp=s.useCallback(()=>{const n=Cm.current;if(n)return Promise.resolve(n);const o=$l.current;if(o)return o;const l=mr(()=>import("./remote-status-Ci5cE6Rj.js"),[]).then(m=>(Cm.current=m,m)).catch(m=>{throw $l.current=null,m});return $l.current=l,l},[]),ui=s.useCallback(n=>{const o=sa.current+1;sa.current=o,Fo(n),n==="remote"?Ks(!1):n==="debug"&&Gs(!1),jp().then(l=>{o===sa.current&&(Rb(l),Fo(null),n==="remote"?Gs(!0):n==="debug"?Ks(!0):Ys(!0),_p())}).catch(()=>{o===sa.current&&(Fo(null),Lo(!1),console.warn("[VuvoDesk] Status diagnostics are unavailable."))})},[jp,_p]),Bp=s.useCallback(()=>{if(fn||$n==="remote"){sa.current+=1,Fo(null),Gs(!1);return}ui("remote")},[ui,$n,fn]),Hp=s.useCallback(()=>{if(qt||$n==="debug"){sa.current+=1,Fo(null),Ks(!1);return}ui("debug")},[qt,ui,$n]),Wp=s.useCallback(()=>{if(pr||$n==="hub"){sa.current+=1,Fo(null),Ys(!1);return}ui("hub")},[pr,ui,$n]),$p=fn||qt,Vp=JSON.stringify(Le.filter(n=>n.connected).map(n=>n.deviceId).sort());s.useEffect(()=>{if(!$p)return;const n=JSON.parse(Vp);if(n.length===0){Lo(!1);return}const o=new AbortController,l=[];let m=!1;return Or.current!==null&&(window.clearTimeout(Or.current),Or.current=null),Lo(!0),Qs(Date.now()),Promise.allSettled(n.map(d=>Ue(`/api/remote/devices/${encodeURIComponent(d)}/status-diagnostic`,{method:"POST",body:JSON.stringify({purpose:"remote-status-current-snapshot"}),signal:o.signal,timeoutMs:1500},Y))).then(()=>{m||[500,1800,4500].forEach((d,C,v)=>{const S=window.setTimeout(()=>{m||(Pe(),Qs(Date.now()),C===v.length-1&&Lo(!1))},d);l.push(S)})}),()=>{m=!0,o.abort();for(const d of l)window.clearTimeout(d)}},[Y,Pe,Vp,$p]);const di=new Map,cs=new Map;if(Fi&&(fn||qt||pr))for(const n of Le){const o=n.deviceId,l=Ae&&g===o,d=ut(l?"control":"wall",o),C=l?Zi.get(o):ri.get(o),v=l?Et.current.get(o)||hn.current.get(o)||null:lt.current.get(o)||(rt?Nn.current:null),S={device:n,frame:C,receiveStat:ic[d],paintStat:oc[d],codec:v?ps(v):{},selectedMonitorIndex:_n(n,gt[o]),control:l,controlInputReady:l&&Ir,controlBinding:l&&ct?.deviceId===o?ct:void 0,recoveryDiagnostic:$o.current.get(d),hubRelay:z?.relay,capturePaused:Pi.has(o),capturePauseConfirmed:n.liveCapturePause?.captureStopConfirmed===!0,capturePauseError:n.liveCapturePause?.stopError||"",clientHeartbeatMs:Number(z?.heartbeatMs||5e3),now:Date.now()},y=["open","playing","silent"].includes(yu),w=It.nativeCallbackDiagnosticsAvailable&&(It.nativeRejectedCallbackCount>0||It.nativeCurrentnessDropCount>0),Z=y&&!w,be=o===X?.deviceId&&Zt?{id:"browser-remote-audio",state:Z?"ok":"warning",label:Z?"Remote audio is healthy":"Remote audio needs attention",detail:It.lastUpdatedAt>0?[yu,`context ${It.audioContextState}`,`queue ${Math.round(It.queuedMs)}ms`,`packet ${Math.round(It.lastPacketAgeMs)}ms`,`capture ${It.captureHealthy?"healthy":It.captureAwaitingCurrentPcm?"awaiting PCM":"down"}`,It.backendKind?`backend ${It.backendKind}`:"backend unknown",It.helperRequired?`helper ${It.helperAlive&&It.helperPid>0?`pid ${It.helperPid}`:"missing"}`:"helper N/A",`drop ${It.drops}`,`restart ${It.automaticRestarts}`,It.nativeCallbackDiagnosticsAvailable?`native reject ${It.nativeRejectedCallbackCount}`:"native callback diagnostics unknown",It.nativeCallbackDiagnosticsAvailable?`native stale ${It.nativeCurrentnessDropCount}`:"",It.nativeLastDropReason?`native reason ${It.nativeLastDropReason}`:"",wu?`frame #${wu.frameSeq}`:"waiting for frame"].filter(Boolean).join(" · "):"Browser audio diagnostics are collecting while Remote or Debug status is open."}:null;if(fn||pr){const D=Fi.buildRemoteDeviceDiagnostics(S);fn&&be&&D.push(be),di.set(o,D)}if(qt){const D=Fi.buildRemoteDeviceDebugDiagnostics(S);be&&D.push(be),cs.set(o,D)}}const Rv=pr&&Fi?Fi.buildHubRemoteDiagnostics({status:z||{},deviceDiagnostics:[...di.values()],codec:ps(),browser:{hardwareConcurrency:navigator.hardwareConcurrency,deviceMemory:Number(navigator.deviceMemory||0)},frameStats:Bc}):[],zp=ni?.atlasReadyTiles??Ru,Tu=ni?.atlasTileCount??Ru,Av=zp===Tu?`${Tu} tiles`:`${zp}/${Tu} tiles`,Iv=nn.length>0;Ae?`${Au}${li.toFixed(li>=10?0:1)}`:Iv?`${Av}${Au}${li.toFixed(li>=10?0:1)}`:`${Ru}${Au}${li.toFixed(li>=10?0:1)}`;const Pu=cn.length,Tv=Ae?X?Qt(X):"No Client":Pu===0?"No Client":Pu>1?`${Pu} selected`:X?Qt(X):"No Client",Pv=Ae?[X?.deviceId].filter(n=>!!n):cn.map(n=>n.deviceId),Sn=ki[ja]||ki.en,Jc=Sn.sync||ki.en.sync,Ev=u||T||Ee?"checking":Je==="team"?re?"Team · Operator access":`Team · ${V.members.length+V.invites.length}/${b?.memberLimit||ef} people`:Je==="pro"?`Pro ${Ka.length}/${ju}`:Je==="ltd"?`Plus ${Ka.length}/${ds}`:`Free ${Ka.length}/${Bu}`,Nv=In?Je!=="free"?Je==="team"?"Team active":Je==="pro"?"Business active":"Upgrade to Pro LTD":r?nt==="checkout"?"Opening checkout":Je==="ltd"?"Buy Pro LTD":"Buy Plus LTD":nt==="auth"?"Opening Google":"Sign in to buy":"LTD · Coming soon",Fv=!In||Je==="pro"||Je==="team"||nt==="checkout"||nt==="auth"||u||T||Ee,Up=r?.user?.user_metadata,ls=$h(Up,"avatar_url","picture"),uo=$h(Up,"full_name","name")||r?.user?.email||"Google",Eu=uo.slice(0,1).toUpperCase(),Dv=z?.started?"Local app ready":"Start VuvoDesk",Lv=J?.active?"Published":r?"Not published":"Sign in required",Ov=oh(Je),_v=M.map(n=>({id:n.id,kind:n.kind,name:n.kind==="personal"?"Personal":n.name,role:n.role,plan:oh(n.plan),memberCount:n.id===G&&n.kind==="team"?V.members.length+V.invites.length:void 0})),mi=b?.kind==="team"?{id:b.id,name:b.name,currentUserRole:b.role,memberLimit:b.memberLimit,memberCount:b.role==="owner"?V.members.length+V.invites.length:void 0,invitationsEnabled:Je==="team"&&b.role==="owner"&&V.members.length+V.invites.length<b.memberLimit,members:[...V.members.map(n=>({id:n.id,email:n.email,displayName:n.displayName,role:n.role,status:"active"})),...V.invites.map(n=>({id:n.id,email:n.email,role:n.role,status:"invited",expiresAt:n.expiresAt}))]}:null,jv=re?Uh.filter(n=>n.id==="wall"||n.id==="control"):Uh,Bv=re?qh.filter(n=>n.id==="doc"||n.id==="support"):qh,Hv=async n=>{if(n===G)return;const o=await B(n);if(!o){j("The VuvoDesk workspace could not be opened.","error");return}j(`Switched to ${o.name}.`,"success")},Wv=async n=>{if(!G||b?.role!=="owner")throw new Error("Only the Team owner can rename this space.");const o=G,{data:l,error:m}=await Mt.rpc("rename_livedesk_workspace",{p_workspace_id:o,p_name:n});if(!q(o))throw new Error("The active VuvoDesk workspace changed. Please try again in the current workspace.");if(m)throw m;const d=Array.isArray(l)?l[0]:l;if(!d?.ok)throw new Error(String(d?.reason||"Team Space rename failed."));await ye(),q(o)&&j("Team Space name saved.","success")},$v=async n=>{const o=G,l=await V.removeMember(n);q(o)&&j(l.revokedImmediately?"Team member removed and active remote access closed.":"Team member removed. The Hub was offline, so its next access check will close any old connection.",l.revokedImmediately?"success":"error")},Vv=async n=>{const o=G;await V.revokeInvite(n),q(o)&&j("Team invitation cancelled.","success")},zv=async()=>{if(!r)throw new Error("Sign in before leaving a Team Space.");if(await V.leaveWorkspace(),!await B(r.user.id))throw new Error("The Team was left, but Personal could not be reopened yet. Retry in a moment.");j("You left the Team Space.","success")},Uv=/^\d{6}$/.test(z?.pairingPin||"")?z?.pairingPin:"------",mo=n=>{if(n==="pricing"&&(u||T)){j("Your VuvoDesk workspace is still loading. Try again in a moment.");return}if(re&&n!=="wall"&&n!=="control"&&n!=="doc"&&n!=="support"){j("Team Operators can use Wall and Control. Ask the Team owner to change settings, billing, files, or Agents."),La("wall"),jn(!1);return}if(typeof window<"u"&&(n==="support"?window.history.pushState({},"","/support"):Pt==="support"&&window.history.pushState({},"",W?"/app":"/")),n==="control"){const o=tn||ga;if(o&&(os(o.deviceId),gn(!1),zt(o.deviceId)),La(n),!pt){jn(!1),j(Jo);return}jn(!0);return}n==="wall"&&Db(o=>o+1),La(n),jn(!1)},Tr=nt==="update"||tt?.stage==="updating"||["dispatching","waiting-for-clients","hub-restart-requested"].includes(z?.update?.state||""),qp=!re&&!!(z?.update?.updateAvailable&&z.update.canApply||Tr||tt?.error||!z&&tt),po=qy(ja),Nu=s.useCallback(n=>{if(!tt?.targetIds.includes(n))return;const o=z?.update?.operationId===tt.operationId?z.update.targets?.find(l=>l.deviceId===n):void 0;switch(o?.state){case"completed":return Js[xh(tt.operationId,o)]?{state:"updated",label:"Updated"}:void 0;case"failed":return{state:"failed",label:"Update failed",error:o.error};case"pending-offline":return{state:"offline",label:"Waiting for reconnect"};case"queued":return tt.stage==="updating"?{state:"queued",label:"Queued"}:void 0;case"waiting":return tt.stage==="updating"?o.candidateSince?{state:"updating",label:"Verifying restart..."}:{state:"updating",label:"Restarting..."}:void 0;default:return tt.stage==="updated"?{state:"updated",label:"Updated"}:tt.stage==="updating"?{state:"updating",label:"Verifying..."}:void 0}},[z?.update,Js,tt]),Fu=me&&!!r&&_e&&Ge==="connecting",ya=me&&!!r&&_e&&(Ge==="reconnecting"||Ge==="unavailable"),Gp=W&&ya&&xt?.kind==="signal-service-unavailable",Kp=W&&ya&&xt?.kind==="p2p-unavailable",Yp=xt?.retryAt?Math.max(0,Math.ceil((xt.retryAt-Date.now())/1e3)):0,qv=u?"checking":Ge==="online"&&z?.started?"online":Fu?"connecting":ya?Ge:"offline",Qp=r&&!Ze?"Restoring your workspace...":"Restoring direct connection...",Zc=Ge==="reconnecting"?Qp:u?"Checking Hub":Ge==="online"&&z?.started?`${Le.length} online`:Fu?"Connecting Hub":Gp?"Signaling unavailable":Kp?"Direct connection unavailable":r?"Hub offline":"Sign in required",pi=Ge==="reconnecting"?"":Ge==="online"&&z?.deviceName?z.deviceName:Fu?"Trying saved Hub routes…":Gp?Yp>0?`Next attempt in ${Yp}s`:"Automatic retry pending":Kp?"This network cannot establish a direct peer connection":ya?"Automatic retry in background":Be?"Desktop Hub unavailable":"Remote management",Du=W&&qr&&!Ae,Xp=Jy({authLoading:u,phase:Ge,recoveryOverlayEligible:Du}),Gv=Xp.statusVisible,Kv=Du&&!!r&&T&&!Ze,Yv=Du&&!!r&&!T&&!Ze&&!!A,Qv=Xp.recoveryVisible||Kv,Xv=t&&qr&&!!r&&(!Ze||!z);return i.jsxs("main",{className:`app-shell ${qr||Ae?"stream-surface-active":""} ${me?"mobile-console-shell":""} ${me&&Ae?"mobile-console-control-active":""}`,"data-mobile-standalone":me&&te?"true":void 0,"data-mobile-ios":me&&ue.isIos?"true":void 0,"data-mobile-android":me&&ue.isAndroid?"true":void 0,children:[i.jsxs("aside",{className:"tool-rail","aria-label":"VuvoDesk tools",children:[i.jsx("div",{className:"rail-brand",title:"VuvoDesk",children:i.jsx(tf,{size:25})}),i.jsx("nav",{className:"rail-tools",children:jv.map(n=>{const o=n.icon,l=og(n.tooltip,ja);return i.jsxs("button",{className:`rail-tool ${n.id==="sync-server"?"sync-server hub-sync-trigger":""} ${Pt===n.id?"active":""} accent-${n.accent}`,onClick:()=>n.id==="sync-server"?pv():mo(n.id),"data-tooltip":n.id==="sync-server"&&Po?void 0:Vy(n.label,n.tooltip,ja),"aria-label":`${n.label}. ${l}`,type:"button",disabled:n.id==="sync-server"&&nt==="host","aria-busy":n.id==="sync-server"&&nt==="host","aria-expanded":n.id==="sync-server"?Po:void 0,"aria-haspopup":n.id==="sync-server"?"dialog":void 0,"aria-controls":n.id==="sync-server"&&Po?"hub-sync-popover":void 0,children:[n.id==="sync-server"&&nt==="host"?i.jsx("span",{className:"sync-server-spinner","aria-hidden":"true"}):i.jsx(o,{size:19}),i.jsx("span",{children:n.id==="sync-server"&&nt==="host"?"Syncing…":n.label})]},n.id)})}),i.jsxs("div",{className:"rail-footer",children:[Bv.map(n=>{const o=n.icon;return i.jsxs("button",{className:`rail-tool compact ${Pt===n.id?"active":""} accent-${n.accent}`,onClick:()=>mo(n.id),title:n.label,type:"button",children:[i.jsx(o,{size:18}),i.jsx("span",{children:n.label})]},n.id)}),!re&&i.jsxs("button",{className:`rail-tool compact local-settings ${Gi?"active":""}`,onClick:()=>{La("settings"),typeof window<"u"&&window.history.pushState({},"","/"),_r(!1),jn(!1),km(!1)},title:"Settings",type:"button",children:[i.jsx(rf,{size:18}),i.jsx("span",{children:"Settings"})]}),i.jsxs("button",{className:`rail-account ${r?"signed-in":""}`,onClick:()=>{_r(n=>!n)},disabled:u||p||nt==="auth","aria-expanded":ca,"aria-haspopup":"dialog","aria-controls":"vuvodesk-account-dialog",title:r?`Account: ${r.user?.email||uo}`:"Sign in with Google",type:"button",children:[r?ls?i.jsx("img",{src:ls,alt:uo,referrerPolicy:"no-referrer"}):i.jsx("span",{className:"avatar-fallback",children:Eu}):i.jsx(kl,{size:18}),i.jsx("span",{children:r?"Account":"Google"})]})]})]}),i.jsx(O0,{open:ca,signedIn:!!r,accountName:uo,accountEmail:r?.user?.email||"",accountInitial:Eu,avatarUrl:ls,currentPlan:Ov,currentPlanKnown:!T&&!Ee,deviceCount:Ka.length,deviceLimit:Sc,licenseLabel:Ev,networkLabel:Dv,accessLabel:Lv,authBusy:u||p||nt==="auth",workspaceBusy:T,checkoutBusy:nt==="checkout"||Ee||V.loading,ltdCheckoutEnabled:In,monthlyCheckoutEnabled:Ca,teamCheckoutEnabled:Zr,planChangesEnabled:!re,sessionRevocationError:f,workspaces:_v,activeWorkspaceId:G,teamWorkspace:mi,onClose:()=>_r(!1),onSignIn:Xr,onSignOut:mv,onRetrySessionRevocation:k,onSelectPlan:n=>{if(!r)return _r(!1),Xr();if(re){j("The Team owner manages billing and plan changes.");return}if((n==="plus_ltd"||n==="pro_ltd")&&!In){j("VuvoDesk LTD checkout is not open yet.");return}if(n==="team_monthly"&&!Zr){j("VuvoDesk Team checkout is not open yet. Contact support to join the Team launch group.");return}return _r(!1),lo(n)},onSelectWorkspace:Hv,onCreateTeamInvite:mi?.currentUserRole==="owner"?V.createInvite:void 0,onRemoveTeamMember:mi?.currentUserRole==="owner"?$v:void 0,onRevokeTeamInvite:mi?.currentUserRole==="owner"?Vv:void 0,onRenameTeamWorkspace:mi?.currentUserRole==="owner"?Wv:void 0,onLeaveTeamWorkspace:mi?.currentUserRole==="operator"?zv:void 0}),me&&P&&i.jsx("div",{className:"mobile-pwa-guide-backdrop",role:"presentation",onClick:()=>N(!1),children:i.jsxs("section",{className:"mobile-pwa-guide",role:"dialog","aria-modal":"true","aria-labelledby":"mobile-pwa-guide-title",onClick:n=>n.stopPropagation(),children:[i.jsxs("header",{children:[i.jsx("span",{className:"mobile-pwa-guide-mark","aria-hidden":"true",children:i.jsx(wy,{size:20})}),i.jsxs("span",{children:[i.jsx("strong",{id:"mobile-pwa-guide-title",children:"Install VuvoDesk on iPhone"}),i.jsx("small",{children:"Open without browser bars and tabs"})]}),i.jsx("button",{type:"button",onClick:()=>N(!1),"aria-label":"Close install guide",children:i.jsx(xa,{size:18,"aria-hidden":"true"})})]}),i.jsxs("ol",{children:[i.jsxs("li",{children:["Tap ",ue.browserName==="browser"?"the browser":ue.browserName,"'s ",i.jsx("strong",{children:"Share"})," button."]}),i.jsxs("li",{children:["Tap ",i.jsx("strong",{children:"Add to Home Screen"}),"."]}),i.jsx("li",{children:ue.isSafari?i.jsxs(i.Fragment,{children:["Turn on ",i.jsx("strong",{children:"Open as Web App"}),", then tap ",i.jsx("strong",{children:"Add"}),"."]}):i.jsxs(i.Fragment,{children:["Confirm the app name, then tap ",i.jsx("strong",{children:"Add"}),"."]})})]}),i.jsx("button",{className:"mobile-pwa-guide-done",type:"button",onClick:()=>N(!1),children:"Got it"})]})}),Po&&i.jsxs("section",{id:"hub-sync-popover",className:"client-hub-switch-popover hub-sync-popover",role:"dialog","aria-modal":"false","aria-labelledby":"hub-sync-title","aria-describedby":"hub-sync-description hub-sync-notice",children:[i.jsxs("header",{className:"client-hub-switch-head",children:[i.jsx("span",{className:"client-hub-switch-mark","aria-hidden":"true",children:i.jsx(Ci,{size:19})}),i.jsx("span",{className:"client-hub-switch-eyebrow",children:po.eyebrow}),i.jsx("button",{className:"client-hub-switch-close",type:"button",onClick:()=>is(),"aria-label":po.closeLabel,children:i.jsx(xa,{size:17})})]}),i.jsx("h2",{id:"hub-sync-title",children:po.title}),i.jsx("p",{id:"hub-sync-description",children:po.description}),i.jsxs("p",{id:"hub-sync-notice",className:"client-hub-switch-notice",children:[i.jsx(wo,{size:16,"aria-hidden":"true"}),i.jsx("span",{children:po.restartNotice})]}),i.jsxs("div",{className:"client-hub-switch-actions",children:[i.jsx("button",{type:"button",onClick:()=>is(),children:po.cancel}),i.jsxs("button",{ref:dm,className:"primary",type:"button",onClick:fv,disabled:nt==="host",children:[i.jsx(Ci,{size:16}),po.confirm]})]})]}),i.jsxs("section",{className:`desk-stage ${qr&&!Ba?"dock-open":""} ${Ae?"control-stage":""} ${hc?"agents-stage":""} ${Ga?"file-share-stage":""}`,children:[me&&i.jsxs("header",{className:"mobile-console-header",children:[i.jsxs("span",{className:"mobile-console-brand","aria-label":"VuvoDesk mobile Console",children:[i.jsx("span",{className:"mobile-console-brand-mark",children:i.jsx(tf,{size:22})}),i.jsxs("span",{children:[i.jsx("strong",{children:"VuvoDesk"}),i.jsx("small",{children:"Mobile Console"})]})]}),Gv&&i.jsxs(i.Fragment,{children:[i.jsxs("button",{className:`mobile-console-hub state-${qv}`,onClick:ya?He:void 0,disabled:!ya,type:"button","aria-label":`${Zc}${pi?`. ${pi}`:""}${ya?" Retry now.":""}`,title:ya?"Retry remote connection now":Zc,children:[i.jsx("i",{"aria-hidden":"true"}),i.jsxs("span",{children:[i.jsx("strong",{children:Zc}),pi&&i.jsx("small",{children:pi})]})]}),i.jsxs("span",{className:"mobile-console-hub-live",role:"status","aria-live":"polite",children:[Zc,pi?`. ${pi}`:""]})]}),i.jsxs("span",{className:"mobile-console-header-actions",children:[i.jsxs("button",{className:`mobile-console-account ${r?"signed-in":""}`,onClick:()=>_r(n=>!n),disabled:u||nt==="auth","aria-expanded":ca,"aria-haspopup":"dialog","aria-controls":"vuvodesk-account-dialog",title:r?`Account: ${r.user?.email||uo}`:"Sign in with Google",type:"button",children:[r?ls?i.jsx("img",{src:ls,alt:uo,referrerPolicy:"no-referrer"}):i.jsx("span",{className:"avatar-fallback",children:Eu}):i.jsx(kl,{size:16}),i.jsx("span",{children:r?"Account":"Google"})]}),W&&!te&&(_||ue.isIos)&&i.jsx("button",{className:"mobile-console-install",onClick:()=>{R()},"aria-label":"Install VuvoDesk app",title:"Install VuvoDesk app",type:"button",children:i.jsx(Sy,{size:19,"aria-hidden":"true"})}),qp&&i.jsx("button",{className:"mobile-console-update",onClick:()=>{Tp()},disabled:Tr||!z?.update?.canApply,"aria-label":Tr?"VuvoDesk update in progress":"Update VuvoDesk","aria-busy":Tr,type:"button",children:Tr?i.jsx("span",{className:"topbar-update-spinner","aria-hidden":"true"}):i.jsx(af,{size:18,"aria-hidden":"true"})})]})]}),me&&qr&&!Ae&&i.jsxs("div",{className:"mobile-wall-preferences","data-list-status-only":Ei?"true":void 0,"aria-label":Ei?"Wall display preferences. List is updating status only.":"Wall display preferences",children:[i.jsx("div",{className:"segmented-control wall-cadence-control","aria-label":"Wall frame speed",children:zh.map(n=>i.jsx("button",{className:Oa===n.id?"active":"",onClick:()=>ym(n.id),title:`${n.label} Wall streaming (${n.fps} fps)`,"aria-pressed":Oa===n.id,type:"button",children:n.label},n.id))}),i.jsx("div",{className:"segmented-control mobile-wall-view-control","aria-label":"Wall view",children:_M.map(n=>i.jsx("button",{className:bm===n.id?"active":"",onClick:()=>vm(n.id),title:n.id==="list"&&Ei?"List status only. Wall video is paused to save data.":n.label,"aria-pressed":bm===n.id,type:"button",children:n.label},n.id))})]}),i.jsxs("header",{className:"topbar",children:[i.jsx("div",{className:"topbar-leading",children:qp?i.jsxs("button",{className:"topbar-update-button",onClick:()=>{Tp()},title:tt?.error?`VuvoDesk Hub update failed: ${tt.error}`:`Update VuvoDesk to ${z?.update?.latestVersion||tt?.targetManagerVersion||"latest"}`,"aria-label":tt?.error?`VuvoDesk Hub update failed: ${tt.error}`:Tr?"VuvoDesk update in progress":`Update VuvoDesk to ${z?.update?.latestVersion||tt?.targetManagerVersion||"latest"}`,type:"button",disabled:Tr||!z?.update?.canApply,"aria-busy":Tr,children:[Tr?i.jsx("span",{className:"topbar-update-spinner","aria-hidden":"true"}):i.jsx(af,{size:19,"aria-hidden":"true"}),Tr&&z?.update?.targetCount?i.jsxs("span",{className:"topbar-update-count","aria-hidden":"true",children:[z.update.completedCount||0,"/",z.update.targetCount]}):null]}):null}),i.jsxs("div",{className:"topbar-tray",children:[Ga&&!Ae&&i.jsxs("div",{className:"file-share-top-route","aria-label":"File distribution route",children:[i.jsxs("div",{children:[i.jsx(Cy,{size:17}),i.jsxs("span",{children:[i.jsx("small",{children:"Source"}),i.jsx("strong",{children:"VuvoDesk Hub"})]})]}),i.jsx(ky,{size:15}),i.jsx(My,{size:16}),i.jsxs("div",{children:[i.jsx("span",{className:"file-share-top-route-laptops",children:"▣ ▣ ▣"}),i.jsxs("span",{children:[i.jsx("small",{children:"Destination"}),i.jsxs("strong",{children:[Gm," Client",Gm===1?"":"s"]}),i.jsx("em",{children:Oo.trim()||"Desktop/VuvoDeskFiles"})]})]})]}),qr&&!Ae&&i.jsxs("div",{className:"top-actions",children:[i.jsx(ph,{active:pr,refreshing:pr&&Do||$n==="hub",onClick:Wp}),i.jsx(dh,{active:fn,refreshing:fn&&Do||$n==="remote",onClick:Bp}),i.jsx(mh,{active:qt,refreshing:qt&&Do||$n==="debug",onClick:Hp}),i.jsx("span",{className:"top-actions-divider","aria-hidden":"true"}),i.jsx(rh,{controller:ep,onError:j}),i.jsx("span",{className:"top-actions-divider","aria-hidden":"true"}),i.jsx("div",{className:"segmented-control wall-cadence-control","aria-label":"Wall frame speed",children:zh.map(n=>i.jsx("button",{className:Oa===n.id?"active":"",onClick:()=>ym(n.id),title:n.label+" Wall streaming ("+n.fps+" fps)","aria-pressed":Oa===n.id,type:"button",children:n.label},n.id))}),i.jsx("span",{className:"top-actions-divider","aria-hidden":"true"}),i.jsxs("div",{className:"wall-view-control",children:[i.jsx("div",{className:"segmented-control","aria-label":"Wall view",children:OM.map(n=>i.jsx("button",{className:Ht===n.id?"active":"",onClick:()=>vm(n.id),"aria-pressed":Ht===n.id,type:"button",children:n.label},n.id))}),i.jsx("label",{className:"wall-view-slider",htmlFor:"wall-view-scale",children:i.jsx("input",{id:"wall-view-scale",type:"range",min:Tl,max:ta,step:1,value:Eo,onChange:n=>Cb(Number(n.currentTarget.value)),"aria-label":"Wall tile size","aria-valuetext":Mb})})]})]}),Ae&&i.jsxs("div",{className:"top-actions",children:[i.jsx(ph,{active:pr,refreshing:pr&&Do||$n==="hub",onClick:Wp}),i.jsx(dh,{active:fn,refreshing:fn&&Do||$n==="remote",onClick:Bp}),i.jsx(mh,{active:qt,refreshing:qt&&Do||$n==="debug",onClick:Hp}),i.jsx("span",{className:"top-actions-divider","aria-hidden":"true"}),i.jsx(rh,{controller:ep,onError:j})]})]})]}),pr&&qr&&i.jsx(G0,{items:Rv,collectedAt:Ab,onClose:()=>Ys(!1)}),Wm?i.jsxs("section",{className:"doc-page",lang:ja,dir:ja==="ar"?"rtl":"ltr",children:[i.jsxs("section",{className:"doc-hero",children:[i.jsxs("div",{className:"doc-hero-copy",children:[i.jsxs("span",{className:"pricing-eyebrow",children:[i.jsx(kd,{size:16}),Sn.eyebrow]}),i.jsx("h2",{children:Sn.title}),i.jsx("p",{children:Sn.intro})]}),i.jsxs("label",{className:"doc-language-picker",children:[i.jsxs("span",{children:[i.jsx(xy,{size:17}),Sn.languageLabel]}),i.jsx("select",{value:ja,onChange:n=>Ib(n.target.value),children:BM.map(n=>i.jsx("option",{value:n.id,children:n.label},n.id))})]})]}),i.jsx("section",{className:"doc-grid",children:Sn.sections.map((n,o)=>{const m=[Ci,vl,of,wo,tg][o]||kd;return i.jsxs("article",{className:"doc-card",children:[i.jsx("div",{className:"doc-card-icon",children:i.jsx(m,{size:19})}),i.jsxs("div",{children:[i.jsx("h3",{children:n.title}),i.jsx("p",{children:n.body}),i.jsx("ul",{children:n.points.map(d=>i.jsx("li",{children:d},d))})]})]},n.title)})}),Jc&&i.jsxs("section",{className:"doc-sync",children:[i.jsxs("div",{className:"doc-sync-head",children:[i.jsx(of,{size:20}),i.jsxs("div",{children:[i.jsx("h3",{children:Jc.title}),i.jsx("p",{children:Jc.body})]})]}),i.jsx("ul",{children:Jc.points.map(n=>i.jsx("li",{children:n},n))})]}),i.jsxs("section",{className:"doc-firewall",children:[i.jsxs("div",{className:"doc-firewall-head",children:[i.jsx(wo,{size:20}),i.jsxs("div",{children:[i.jsx("h3",{children:Sn.firewall.title}),i.jsx("p",{children:Sn.firewall.body})]})]}),i.jsx("ul",{children:Sn.firewall.points.map(n=>i.jsx("li",{children:n},n))})]}),i.jsxs("section",{className:"doc-command-panel",children:[i.jsxs("div",{className:"doc-command-head",children:[i.jsx(vl,{size:20}),i.jsxs("div",{children:[i.jsx("h3",{children:Sn.commands.title}),i.jsx("p",{children:Sn.commands.body})]})]}),i.jsxs("div",{className:"doc-command-list",children:[Sn.commands.manager&&i.jsxs("div",{className:"doc-command-row",children:[i.jsx("span",{children:Sn.commands.manager}),i.jsx("code",{children:Dp}),i.jsx("button",{className:"icon-button",onClick:()=>Hu(Dp),title:"Copy command",type:"button",children:i.jsx(Wu,{size:16})})]}),i.jsxs("div",{className:"doc-command-row",children:[i.jsx("span",{children:Sn.commands.primary}),i.jsx("code",{children:Yc}),i.jsx("button",{className:"icon-button",onClick:()=>Hu(Yc),title:"Copy command",type:"button",children:i.jsx(Wu,{size:16})})]}),i.jsxs("div",{className:"doc-command-row",children:[i.jsx("span",{children:Sn.commands.slot}),i.jsx("code",{children:`${Yc} 3`}),i.jsx("button",{className:"icon-button",onClick:()=>Hu(`${Yc} 3`),title:"Copy command",type:"button",children:i.jsx(Wu,{size:16})})]})]})]})]}):hc?i.jsx(bs,{children:i.jsx(gh,{hubUrl:Y,devices:Me})}):Ga?i.jsx(bs,{children:i.jsx(uk,{hubUrl:Y,devices:Le,localFeatureAccess:pt,upgradeNotice:Jo,remoteDirectory:Oo,onRemoteDirectoryChange:Mm,targetMode:qo,selectedTargetIds:Go,onTargetModeChange:Wb,onTargetToggle:n=>ru(o=>o.includes(n)?o.filter(l=>l!==n):[...o,n]),filePickerRef:Vb,folderPickerRef:zb,onBrowserFileImport:n=>{Fp(n)},onBrowserFolderImport:n=>{Fp(n)},onNotice:j,onTransferChange:n=>{if(!n){fa(null);return}const o=n.state==="failed"||n.state==="partially-failed"||n.state==="cancelled"?"failed":n.state==="completed"?"queued":n.state==="sending"?"sending":"reading";fa({id:n.id,status:o,progress:n.progress,message:n.message}),["completed","partially-failed","failed","cancelled"].includes(n.state)&&window.setTimeout(()=>fa(l=>l?.id===n.id?null:l),4500)}})}):$m?i.jsx(bs,{children:i.jsx(dk,{session:r,currentProductKey:"livedesk",appVersion:"",onSignIn:Xr})}):Gi?i.jsx(bs,{children:i.jsx(mk,{hubUrl:Y,mobileLayout:me,runtimeRole:z?.runtimeRole||"hub",runtimeDeviceId:z?.deviceId||"",sessionAccessToken:r?.access_token||"",showThisComputerSetting:!me&&z?.runtimeRole==="hub",onShowThisComputerChange:Ct,pin:i.jsxs(pk,{children:[i.jsx("div",{className:"settings-section-grid",children:i.jsxs("section",{className:"settings-section-card settings-pairing-card",children:[i.jsxs("div",{className:"settings-section-heading",children:[i.jsxs("div",{children:[i.jsx("span",{children:"Pair a Client"}),i.jsx("h3",{children:"Connect another local PC"})]}),i.jsx(Aa,{size:20})]}),i.jsxs("div",{className:"settings-pin-display",children:[i.jsx("span",{children:"Hub PIN"}),i.jsx("strong",{children:Uv}),i.jsxs("button",{className:"text-button ghost compact",onClick:hv,disabled:!z?.started||nt==="pin",type:"button",children:[i.jsx(Ry,{size:15}),nt==="pin"?"Creating":"New PIN"]})]})]})}),i.jsxs("section",{className:"settings-section-card",children:[i.jsxs("div",{className:"settings-section-heading",children:[i.jsxs("div",{children:[i.jsx("span",{children:"File transfer"}),i.jsx("h3",{children:"Client destination folder"})]}),i.jsx($u,{size:20})]}),i.jsxs("label",{className:"settings-field",children:[i.jsx("span",{children:"Remote folder"}),i.jsx("input",{value:Oo,onChange:n=>Mm(n.target.value),placeholder:"Desktop/VuvoDeskFiles"})]}),i.jsx("p",{className:"settings-help",children:"Blank uses Desktop/VuvoDeskFiles on each Client."})]})]}),desktopUpdate:i.jsx(hk,{}),agent:i.jsx(fk,{hubUrl:Y,showToast:j}),captureGallery:i.jsx(gk,{hubUrl:Y,onToast:j})})}):Hm?i.jsxs("section",{className:"pricing-page",children:[i.jsxs("header",{className:"pricing-header",children:[i.jsxs("div",{children:[i.jsxs("span",{className:"pricing-eyebrow",children:[i.jsx(Ay,{size:15})," VuvoDesk plans"]}),i.jsx("h2",{children:"Choose the plan that fits your wall"}),i.jsx("p",{children:"Use one account for Personal or Business, or let each operator use a separate Google account in one Team Space."})]}),i.jsx("button",{className:"pricing-close",onClick:()=>mo("wall"),title:"Close pricing",type:"button",children:i.jsx(xa,{size:18})})]}),i.jsxs("div",{className:"pricing-status","aria-live":"polite",children:[i.jsx("span",{children:"Current plan"}),i.jsx("strong",{children:Xm.name}),i.jsxs("small",{children:[Ka.length,"/",Zk(Sc)," managed Clients"]})]}),i.jsxs("div",{className:"pricing-cards","aria-label":"VuvoDesk plans",children:[i.jsxs("article",{className:`pricing-plan-card ${Je==="free"?"current":""}`,children:[i.jsxs("div",{className:"pricing-plan-topline",children:[i.jsx("span",{className:"pricing-plan-badge free",children:"Free"}),i.jsx("strong",{children:$e.free.price})]}),i.jsx("p",{className:"pricing-plan-audience",children:$e.free.audience}),i.jsx("h3",{children:"Free personal screen wall"}),i.jsx("p",{children:$e.free.note}),i.jsxs("ul",{children:[i.jsxs("li",{children:[i.jsx(Cn,{size:16})," Up to ",Bu," devices"]}),i.jsxs("li",{children:[i.jsx(Cn,{size:16})," Live view and local control"]}),i.jsxs("li",{children:[i.jsx(Cn,{size:16})," Standard banner helps keep Free available"]})]}),i.jsx("span",{className:"pricing-current-label",children:Je==="free"?"Current plan":"Included for everyone"})]}),i.jsxs("article",{className:`pricing-plan-card featured ${Je==="ltd"?"current":""}`,children:[i.jsxs("div",{className:"pricing-plan-topline",children:[i.jsxs("span",{className:"pricing-plan-badge plus",children:[i.jsx(Jh,{size:14})," Plus"]}),i.jsxs("span",{className:"pricing-plan-price",children:[i.jsx("strong",{children:$e.ltd.price}),i.jsx("small",{children:"/ month"})]})]}),i.jsx("p",{className:"pricing-plan-audience",children:$e.ltd.audience}),i.jsx("h3",{children:"Ad-free personal wall"}),i.jsxs("p",{children:["Monitor up to ",ds," personal computers without the standard banner."]}),i.jsxs("ul",{children:[i.jsxs("li",{children:[i.jsx(Cn,{size:16})," Up to ",ds," devices"]}),i.jsxs("li",{children:[i.jsx(Cn,{size:16})," No standard ad banner"]})]}),i.jsxs("div",{className:"pricing-ltd-offer",children:[i.jsx("span",{children:"Plus LTD"}),i.jsx("strong",{children:$e.ltd.ltd}),i.jsx("small",{children:In?"One-time · available now":"One-time · coming soon"})]}),i.jsxs("div",{className:"pricing-plan-actions",children:[i.jsxs("button",{className:"pricing-plan-button secondary",onClick:Ca?r?()=>lo("plus_monthly"):Xr:void 0,disabled:!Ca||Je!=="free"||nt==="checkout"||nt==="auth"||u||T||Ee,type:"button",children:[i.jsx(Ra,{size:16}),Je!=="free"?"Plus active":Ca?r?`Choose Plus · ${$e.ltd.price}/month`:"Sign in for Plus monthly":"Monthly · Coming soon"]}),i.jsxs("button",{className:"pricing-plan-button",onClick:In?r?()=>lo("plus_ltd"):Xr:void 0,disabled:!In||Je!=="free"||nt==="checkout"||nt==="auth"||u||T||Ee,type:"button",children:[i.jsx(Ra,{size:16}),Je!=="free"?"Plus active":In?r?`Buy Plus · ${$e.ltd.ltd}`:"Sign in for Plus LTD":"LTD · Coming soon"]})]})]}),i.jsxs("article",{className:`pricing-plan-card pro ${Je==="pro"?"current":""}`,children:[i.jsxs("div",{className:"pricing-plan-topline",children:[i.jsxs("span",{className:"pricing-plan-badge pro",children:[i.jsx(wo,{size:14})," Pro / Business"]}),i.jsxs("span",{className:"pricing-plan-price",children:[i.jsx("strong",{children:$e.pro.price}),i.jsx("small",{children:"/ month"})]})]}),i.jsx("p",{className:"pricing-plan-audience",children:$e.pro.audience}),i.jsx("h3",{children:"School and commercial monitoring"}),i.jsx("p",{children:"For schools, academies, studios, offices, and other commercial use."}),i.jsxs("ul",{children:[i.jsxs("li",{children:[i.jsx(Cn,{size:16})," Up to ",ju," connected Clients"]}),i.jsxs("li",{children:[i.jsx(Cn,{size:16})," Ad-free school, academy, and commercial use"]})]}),i.jsxs("div",{className:"pricing-ltd-offer pro",children:[i.jsx("span",{children:"Pro LTD"}),i.jsx("strong",{children:$e.pro.ltd}),i.jsx("small",{children:In?"One-time · available now":"One-time · coming soon"})]}),i.jsxs("div",{className:"pricing-plan-actions",children:[i.jsxs("button",{className:"pricing-plan-button secondary",onClick:Ca?r?()=>lo("pro_monthly"):Xr:void 0,disabled:!Ca||Je==="pro"||Je==="team"||nt==="checkout"||nt==="auth"||u||T||Ee,type:"button",children:[i.jsx(Ra,{size:16}),Je==="pro"?"Business active":Je==="team"?"Included with Team":Ca?r?`Choose Pro · ${$e.pro.price}/month`:"Sign in for Pro monthly":"Monthly · Coming soon"]}),i.jsxs("button",{className:"pricing-plan-button",onClick:In?r?()=>lo("pro_ltd"):Xr:void 0,disabled:!In||Je==="pro"||Je==="team"||nt==="checkout"||nt==="auth"||u||T||Ee,type:"button",children:[i.jsx(Ra,{size:16}),Je==="pro"?"Business active":Je==="team"?"Included with Team":In?r?`Buy Pro · ${$e.pro.ltd}`:"Sign in for Pro LTD":"LTD · Coming soon"]})]})]}),i.jsxs("article",{className:`pricing-plan-card team ${Je==="team"?"current":""}`,children:[i.jsxs("div",{className:"pricing-plan-topline",children:[i.jsxs("span",{className:"pricing-plan-badge team",children:[i.jsx(Ts,{size:14})," Team"]}),i.jsxs("span",{className:"pricing-plan-price",children:[i.jsx("strong",{children:$e.team.price}),i.jsx("small",{children:"/ month"})]})]}),i.jsx("p",{className:"pricing-plan-audience",children:$e.team.audience}),i.jsx("h3",{children:"One Team Space, separate logins"}),i.jsx("p",{children:"Share the same computers without sharing one Google account."}),i.jsxs("ul",{children:[i.jsxs("li",{children:[i.jsx(Cn,{size:16})," Up to ",ef," people"]}),i.jsxs("li",{children:[i.jsx(Cn,{size:16})," Commercial use"]}),i.jsxs("li",{children:[i.jsx(Cn,{size:16})," Owner and Operator roles"]}),i.jsxs("li",{children:[i.jsx(Cn,{size:16})," One controller per computer"]})]}),i.jsxs("div",{className:"pricing-team-readiness",children:[i.jsx("span",{children:Zr?"Team subscription":"Team launch group"}),i.jsx("strong",{children:Zr?`${$e.team.price} monthly`:"Contact support"}),i.jsx("small",{children:Zr?"Separate member accounts":"Checkout stays closed until recurring billing is ready"})]}),i.jsxs("button",{className:"pricing-plan-button",onClick:Zr?r?()=>lo("team_monthly"):Xr:void 0,disabled:!Zr||Je==="team"||nt==="checkout"||nt==="auth"||u||T||Ee,type:"button",children:[i.jsx(Ts,{size:16}),Je==="team"?"Team active":Zr?r?`Choose Team · ${$e.team.price}/month`:"Sign in for Team":"Team · Coming soon"]})]})]}),i.jsxs("section",{className:"pricing-includes",children:[i.jsxs("div",{children:[i.jsx(Aa,{size:17}),i.jsx("span",{children:"Screen wall"}),i.jsx("strong",{children:"120+ layout slots"})]}),i.jsxs("div",{children:[i.jsx(Ms,{size:17}),i.jsx("span",{children:"Focused control"}),i.jsx("strong",{children:"Local-first"})]}),i.jsxs("div",{children:[i.jsx(sf,{size:17}),i.jsx("span",{children:"Remote audio"}),i.jsx("strong",{children:"Available"})]}),i.jsxs("div",{children:[i.jsx($u,{size:17}),i.jsx("span",{children:"File transfer"}),i.jsx("strong",{children:"Included"})]})]}),i.jsxs("p",{className:"pricing-note",children:[i.jsx(Cn,{size:15})," Free and Plus are personal. Pro / Business covers one person in a school, academy, or other commercial organization. Team gives each operator a separate account in one shared space."]}),i.jsxs("button",{className:"pricing-primary-cta",onClick:In?r?()=>lo(Je==="ltd"?"pro_ltd":"plus_ltd"):Xr:void 0,disabled:Fv,type:"button",children:[i.jsx(Ra,{size:18}),Nv]})]}):i.jsx(i.Fragment,{children:i.jsxs("section",{className:`monitor-layout ${Ba?"dock-collapsed":""}`,children:[i.jsxs("section",{ref:jm,className:`screen-wall-panel ${Bb?"drop-active":""}`,onClick:n=>{n.currentTarget===n.target&&ss()},onDragEnter:n=>{n.preventDefault(),nu(!0)},onDragOver:n=>{n.preventDefault(),n.dataTransfer.dropEffect="copy"},onDragLeave:n=>{n.currentTarget===n.target&&nu(!1)},onDrop:Cv,children:[Xv&&i.jsx("div",{className:"desktop-hub-recovery-overlay",children:i.jsxs("div",{className:"desktop-hub-recovery-message",role:"status","aria-live":"polite",children:[i.jsx("span",{className:"desktop-hub-recovery-spinner","aria-hidden":"true"}),i.jsx("strong",{children:"Restoring VuvoDesk…"}),i.jsx("small",{children:"Connected computers and video will return automatically."})]})}),Qv&&i.jsx("div",{className:"mobile-hub-recovery-overlay",children:i.jsxs("div",{className:"mobile-hub-recovery-message",role:"status","aria-live":"polite",children:[i.jsx("span",{className:"mobile-hub-recovery-spinner","aria-hidden":"true"}),i.jsx("strong",{children:Qp})]})}),Yv&&i.jsx("div",{className:"mobile-workspace-recovery-failure",children:i.jsxs("div",{className:"mobile-workspace-recovery-failure-message",role:"alert",children:[i.jsx("strong",{children:"Workspace could not be restored"}),i.jsx("small",{children:A}),i.jsx("button",{type:"button",onClick:()=>{E()},children:"Try again"})]})}),nn.length>0&&i.jsx("canvas",{ref:rv,className:"atlas-source-canvas",width:Za?.width||1920,height:Za?.height||1080,"aria-hidden":"true"}),Ae?i.jsx("section",{className:"control-focus",children:i.jsxs("div",{className:"control-wall",children:[X&&i.jsxs("div",{className:"control-monitor-tabs","aria-label":`Select monitor for ${Qt(X)}`,children:[i.jsx("strong",{className:"control-computer-name",title:Qt(X),children:Qt(X)}),kv.map(n=>i.jsxs("button",{className:n.index===Qc?"active":"",onClick:()=>gv(X.deviceId,n.index),title:hM(n),type:"button",children:[i.jsx("span",{children:n.name||`Display ${n.index+1}`}),n.width>0&&n.height>0&&i.jsxs("small",{children:[n.width,"x",n.height]})]},n.index))]}),X&&Ir&&i.jsxs("div",{className:"control-modifier-bar","aria-label":"Hold remote modifier keys",children:[me&&i.jsxs(i.Fragment,{children:[i.jsx("button",{className:`remote-keyboard-button ${om?"active":""}`,type:"button","aria-pressed":om,"aria-label":"Open remote keyboard",title:"Open the phone keyboard for the remote computer",onClick:()=>{const n=rm.current;n&&(n.focus({preventScroll:!0}),n.setSelectionRange(n.value.length,n.value.length))},children:i.jsx(Iy,{size:15,"aria-hidden":"true"})}),i.jsx("textarea",{ref:rm,className:"remote-keyboard-input","aria-label":"Type on the remote computer",autoComplete:"off",autoCorrect:"off",autoCapitalize:"sentences",enterKeyHint:"enter",spellCheck:!1,rows:1,onFocus:()=>im(!0),onBlur:()=>{_s.current=!1,im(!1)},onCompositionStart:()=>{_s.current=!0},onCompositionEnd:n=>{_s.current=!1;const o=n.currentTarget.value;n.currentTarget.value="",Ii.current?.sendText(o)},onInput:n=>{if(_s.current)return;const o=n.currentTarget.value;n.currentTarget.value="",Ii.current?.sendText(o)},onKeyDown:n=>{n.nativeEvent.isComposing||!sl(n.key)||(n.preventDefault(),n.stopPropagation(),Rp(n.key,"keydown"))},onBeforeInput:n=>{const o=n.nativeEvent.inputType||"";sl(o)&&(n.preventDefault(),n.stopPropagation(),Rp(o,"beforeinput"))}})]}),Ek.map(n=>{const o=n.code==="MetaLeft"&&Nr(X.platform)?"Cmd":n.label,l=Ai.includes(n.code);return i.jsx("button",{className:l?"active":"",type:"button","aria-pressed":l,title:`Hold ${o} on the remote computer`,onClick:()=>Ll.current?.(n.code),children:o},n.code)})]}),X?i.jsx(Cd,{device:X,frame:le,selected:!1,controlEnabled:Cr&&Mn&&Ir,showStatus:on.showScreenStatus,showDeviceTitle:!1,monitorIndex:_n(X,gt[X.deviceId]),monitorCount:Ma(X),onSelect:()=>{},onFocusDevice:()=>zt(X.deviceId),onOpenControl:()=>ci(X.deviceId),onCycleMonitor:n=>Mu(X.deviceId,n),onCanvasReady:nv,sendInput:as,remotePointerFeedback:lv,remoteModifierState:bu,presentationReady:Xl,remoteDiagnostics:qt?cs.get(X.deviceId):fn?di.get(X.deviceId):void 0,diagnosticsMode:qt?"debug":"remote"},X.deviceId):i.jsxs("div",{className:"control-empty",children:[i.jsx(Aa,{size:30}),i.jsx("strong",{children:"No Client"}),i.jsx("span",{children:"Open a Client from the Wall."})]}),X&&su&&i.jsxs("div",{className:"control-connection-overlay",role:"alert",children:[i.jsx(wo,{size:22,"aria-hidden":"true"}),i.jsx("strong",{children:"Accessibility permission required"}),i.jsx("small",{children:"On the Mac, allow Accessibility for the terminal app that starts VuvoDesk, then restart the Mac client."})]}),X&&!su&&!Xl&&i.jsxs("div",{className:"control-connection-overlay",role:"status","aria-live":"polite",children:[ge!=="error"&&i.jsx("span",{className:"control-connection-spinner","aria-hidden":"true"}),i.jsx("strong",{children:ge==="error"?"Connection failed":"Connecting"}),i.jsx("small",{children:ge==="error"?"See the notification for details. Reopen Control to retry.":eo||yt?"Control stream is recovering. See the notification for details.":fu==="open"?"Preparing the first control frame":"Opening the Control stream"})]})]})}):Ht==="list"?i.jsxs("div",{className:"wall-device-list",role:"grid","aria-label":"Computer status list",children:[i.jsxs("div",{className:"wall-device-list-head",role:"row",children:[i.jsx("span",{role:"columnheader",children:"Computer"}),i.jsx("span",{role:"columnheader",children:"Status"}),i.jsx("span",{role:"columnheader",children:"CPU"}),i.jsx("span",{role:"columnheader",children:"GPU"}),i.jsx("span",{role:"columnheader",children:"RAM"}),i.jsx("span",{role:"columnheader",children:"VRAM"}),i.jsx("span",{role:"columnheader",children:"Network"}),i.jsx("span",{role:"columnheader",children:"HDD"}),i.jsx("span",{role:"columnheader",children:"Temp"})]}),Ym.length>0?Ym.map(({device:n,slotNumber:o})=>i.jsx($M,{device:n,slotNumber:o,selected:Ya.has(n.deviceId),updateIndicator:Nu(n.deviceId),remoteDiagnostics:qt?cs.get(n.deviceId):fn?di.get(n.deviceId):void 0,diagnosticsMode:qt?"debug":"remote",onSelect:()=>ku(n.deviceId),onOpenControl:()=>ci(n.deviceId)},n.deviceId)):i.jsxs("div",{className:"wall-device-list-empty",children:[i.jsx(Aa,{size:24,"aria-hidden":"true"}),i.jsx("strong",{children:"No connected computers"})]})]}):rt?i.jsx("div",{className:`screen-wall atlas-slot-wall size-${Ht}`,style:Sm,onClick:n=>{n.currentTarget===n.target&&ss()},children:Km.map((n,o)=>n?i.jsx(Cd,{device:n,frame:ri.get(n.deviceId),selected:Ya.has(n.deviceId),controlEnabled:!1,showStatus:xm,monitorIndex:_n(n,gt[n.deviceId]),monitorCount:Ma(n),onSelect:()=>ku(n.deviceId),onFocusDevice:()=>Cu(n.deviceId),onOpenControl:()=>ci(n.deviceId),onCycleMonitor:l=>Mu(n.deviceId,l),onCanvasReady:gs({mode4Enabled:rt,directMode4WallEnabled:Mr,isMac:Nr(n.platform)})==="direct"?tp:av,sendInput:as,remoteModifierState:bu,updateIndicator:Nu(n.deviceId),presentationReady:De.autoStartLive&&Kn.includes(n.deviceId)?Kl.has(n.deviceId):void 0,showPresentationSpinner:De.autoStartLive&&Kn.includes(n.deviceId),remoteDiagnostics:qt?cs.get(n.deviceId):fn?di.get(n.deviceId):void 0,diagnosticsMode:qt?"debug":"remote"},n.deviceId):i.jsx(Gh,{index:o},`slot-${o}`))}):i.jsx("div",{className:`screen-wall size-${Ht}`,style:Sm,onClick:n=>{n.currentTarget===n.target&&ss()},children:Km.map((n,o)=>n?i.jsx(Cd,{device:n,frame:ri.get(n.deviceId),selected:Ya.has(n.deviceId),controlEnabled:Cr&&Mn&&Ir&&X?.deviceId===n.deviceId,showStatus:xm,monitorIndex:_n(n,gt[n.deviceId]),monitorCount:Ma(n),onSelect:()=>ku(n.deviceId),onFocusDevice:()=>Cu(n.deviceId),onOpenControl:()=>ci(n.deviceId),onCycleMonitor:l=>Mu(n.deviceId,l),onCanvasReady:tp,sendInput:as,remoteModifierState:bu,updateIndicator:Nu(n.deviceId),presentationReady:De.autoStartLive&&Kn.includes(n.deviceId)?Kl.has(n.deviceId):void 0,showPresentationSpinner:De.autoStartLive&&Kn.includes(n.deviceId),remoteDiagnostics:qt?cs.get(n.deviceId):fn?di.get(n.deviceId):void 0,diagnosticsMode:qt?"debug":"remote"},n.deviceId):i.jsx(Gh,{index:o},`slot-${o}`))}),i.jsx(UM,{visible:Zb&&!Ae})]}),!Gi&&!me&&i.jsxs("aside",{className:`right-dock actions-mode ${Ba?"collapsed":""}`,"aria-label":"VuvoDesk tools",children:[i.jsx("button",{className:"dock-toggle",onClick:()=>km(n=>!n),"aria-label":Ba?"Show control panel":"Hide control panel",title:Ba?"Show control panel":"Hide control panel",type:"button",children:Ba?i.jsx(ng,{size:18}):i.jsx(rg,{size:18})}),!Ba&&i.jsxs(i.Fragment,{children:[i.jsxs("section",{className:"action-dock",children:[i.jsx("input",{ref:Bm,className:"hidden-file-input",type:"file",multiple:!0,onChange:n=>{n.currentTarget.files&&Np(n.currentTarget.files),n.currentTarget.value=""}}),i.jsxs("div",{className:"manual-action-bar",role:"toolbar","aria-label":"Manual Client controls",children:[i.jsx(bo,{label:"Control",tooltip:X?su?"Allow Accessibility for the terminal app that starts VuvoDesk, then restart the Mac client.":Cr?Ir?"Keyboard and mouse control is ready":"Waiting for the current Control capture session":"Remote control is not available on this Client":"Select a Client to use Control",onClick:()=>{if(X){if(Ae&&Mn){jn(!1),j("Remote control paused. Screen viewing stays on.");return}ci(X.deviceId)}},disabled:!Cr||!!an,active:Mn,pressed:Ae&&Mn,children:i.jsx(Ms,{size:17})}),i.jsx(bo,{label:"Audio",tooltip:X?sr?Zt?"Stop hearing this Client":"Hear this Client":"Audio is not available on this Client":"Select a Client to use Audio",onClick:()=>{vv()},disabled:!Jm||!!an,active:Zt,pressed:Zt,children:an==="audio"?i.jsx(ms,{className:"spin",size:17}):i.jsx(sf,{size:17})}),i.jsx(bo,{label:Cc?"Retry pause":Qi?"Pause video":"Resume video",tooltip:Yi.length===0?"Select one or more Clients to pause video":Cc?"Retry every selected Client whose capture shutdown is unconfirmed":Qi?`Pause video for ${Dn.length} selected Client${Dn.length===1?"":"s"}`:`Resume video for ${Dn.length} selected Client${Dn.length===1?"":"s"}`,onClick:()=>{wv()},disabled:Dn.length===0||!!an,active:!Qi,pressed:!Qi,children:an==="video"?i.jsx(ms,{className:"spin",size:17}):!Qi&&!Cc?i.jsx(Ty,{size:17}):i.jsx(Py,{size:17})}),i.jsx(bo,{label:"Send files",tooltip:cn.length===0&&!Ae?"Select one or more Clients to send files":X?"Choose files and send them to the selected Client":"Select a Client to send files",onClick:()=>{j(`Choose files to send to ${Tv}.`),Bm.current?.click()},disabled:!!an||!pt||(Ae?!X:cn.length===0),children:i.jsx($u,{size:17})}),i.jsx(bo,{label:"Restart",tooltip:X?Xo?"Restart Client":"Restart is not available on this Client":"Select a Client to restart",onClick:()=>{xu("restart")},disabled:!X||!pt||!!an||!Xo,children:an==="restart"?i.jsx(ms,{className:"spin",size:17}):i.jsx(Ey,{size:17})}),i.jsx(bo,{label:"Sleep",tooltip:X?Xo?"Put Client to sleep":"Sleep is not available on this Client":"Select a Client to put to sleep",onClick:()=>{xu("sleep")},disabled:!X||!pt||!!an||!Xo,children:an==="sleep"?i.jsx(ms,{className:"spin",size:17}):i.jsx(Ny,{size:17})}),i.jsx(bo,{label:"Shut down",tooltip:X?Xo?"Shut down Client":"Shut down is not available on this Client":"Select a Client to shut down",onClick:()=>{xu("shutdown")},disabled:!X||!pt||!!an||!Xo,danger:!0,children:an==="shutdown"?i.jsx(ms,{className:"spin",size:17}):i.jsx(Fy,{size:17})})]})]}),i.jsx(bs,{children:i.jsx(gh,{hubUrl:Y,devices:Me,variant:"dock",selectedDeviceIds:Pv})})]})]})]})})]}),me&&i.jsxs("nav",{className:"mobile-console-nav","aria-label":"Mobile Console pages",children:[i.jsxs("button",{className:Ni?"active":"",onClick:()=>xb(n=>{const o=!n;return RM(o),o}),type:"button","aria-label":Ni?"Hide computer stats":"Show computer stats","aria-pressed":Ni,title:Ni?"Hide CPU, GPU, RAM, and online status":"Show CPU, GPU, RAM, and online status",children:[i.jsx(Dy,{size:19}),i.jsx("span",{children:"Stats"})]}),i.jsxs("button",{className:Pt==="wall"?"active":"",onClick:()=>mo("wall"),type:"button",children:[i.jsx(Zh,{size:19}),i.jsx("span",{children:"Wall"})]}),i.jsxs("button",{className:Ae?"active":"",onClick:()=>X&&void ci(X.deviceId),disabled:!X||!Cr,type:"button",children:[i.jsx(Ms,{size:19}),i.jsx("span",{children:"Control"})]}),!re&&i.jsxs(i.Fragment,{children:[i.jsxs("button",{className:Ga?"active":"",onClick:()=>mo("share-files"),type:"button",children:[i.jsx(eg,{size:19}),i.jsx("span",{children:"Files"})]}),i.jsxs("button",{className:hc?"active":"",onClick:()=>mo("agents"),type:"button",children:[i.jsx(vl,{size:19}),i.jsx("span",{children:"Agents"})]}),i.jsxs("button",{className:Gi?"active":"",onClick:()=>mo("settings"),type:"button",children:[i.jsx(rf,{size:19}),i.jsx("span",{children:"Settings"})]})]})]}),qa&&i.jsxs("aside",{className:`transfer-bar state-${qa.status}`,"aria-live":"polite",children:[i.jsx("span",{className:"transfer-bar-icon","aria-hidden":"true",children:qa.status==="queued"?i.jsx(Cn,{size:18}):qa.status==="failed"?i.jsx(xa,{size:18}):i.jsx(Ly,{size:18})}),i.jsxs("div",{className:"transfer-bar-copy",children:[i.jsx("p",{children:qa.message}),i.jsx("div",{className:"transfer-bar-track",children:i.jsx("span",{style:{width:`${Math.max(0,Math.min(100,qa.progress))}%`}})})]}),i.jsxs("strong",{children:[Math.max(0,Math.min(100,qa.progress)),"%"]})]}),Da&&i.jsxs("aside",{className:`livedesk-toast tone-${Da.tone}`,role:Da.tone==="error"?"alert":"status","aria-live":Da.tone==="error"?"assertive":"polite","aria-busy":Da.tone==="progress",children:[Da.tone==="progress"&&i.jsx("span",{className:"livedesk-toast-spinner","aria-hidden":"true"}),i.jsx("span",{children:Da.message}),i.jsx("button",{className:"livedesk-toast-close",onClick:()=>j(""),type:"button","aria-label":"Dismiss notification",title:"Dismiss notification",children:i.jsx(xa,{size:15})})]})]})}export{O0 as A,gx as H,og as a,dx as b,fx as c,hx as d,Vy as f,mx as g,px as l,td as n,Vd as r,Mt as s};
|