livedesk 0.1.656 → 0.1.658

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.
Files changed (42) hide show
  1. package/hub/src/remote-hub.js +47 -24
  2. package/hub/src/server.js +200 -13
  3. package/hub/src/shared-wall-profile-contract.mjs +40 -0
  4. package/hub/src/shared-wall-profile-contract.test.mjs +38 -0
  5. package/package.json +1 -1
  6. package/web/dist/app.html +5 -11
  7. package/web/dist/app.webmanifest +1 -1
  8. package/web/dist/assets/AgentSettingsTab-8WnOGkVa.js +1 -0
  9. package/web/dist/assets/{AgentsPage-DEdUBoe0.js → AgentsPage-CCO7AwAO.js} +6 -6
  10. package/web/dist/assets/CaptureGallery-7NXD-vaQ.js +1 -0
  11. package/web/dist/assets/DesktopUpdatePanel-CiGXFhqj.js +1 -0
  12. package/web/dist/assets/{App-DK9GZcvU.js → HubApp-AhKLyz3K.js} +13 -13
  13. package/web/dist/assets/MonitorStackIcon-DBuXI_Oa.js +8 -0
  14. package/web/dist/assets/SettingsPage-DnOdy3MQ.js +1 -0
  15. package/web/dist/assets/SettingsTabs-DfjoCvK4.js +1 -0
  16. package/web/dist/assets/{ShareFilesPage-BiCS0Nyd.js → ShareFilesPage-C3Jv7EII.js} +3 -3
  17. package/web/dist/assets/SupportPage-B16Jl8Jq.js +2 -0
  18. package/web/dist/assets/VuvoDeskApp-CU4N6t3c.js +1 -0
  19. package/web/dist/assets/app--miKlon3.js +2 -0
  20. package/web/dist/assets/client-8jUbxy3j.js +1 -0
  21. package/web/dist/assets/icons-CuXJn-Hz.js +1 -0
  22. package/web/dist/assets/main-DVNv6hc-.js +2 -0
  23. package/web/dist/assets/preload-helper-DD1OZmLC.js +1 -0
  24. package/web/dist/assets/pwa-bootstrap-BCid3CYk.js +1 -0
  25. package/web/dist/assets/pwa-startup-xxamnV7P.js +1 -0
  26. package/web/dist/assets/react-rvm9rmed.js +9 -0
  27. package/web/dist/index.html +11 -7
  28. package/web/dist/sw.js +14 -4
  29. package/web/dist/vuvodesk-build-evidence.json +93 -73
  30. package/web/dist/assets/AgentSettingsTab-D0271Ynp.js +0 -1
  31. package/web/dist/assets/CaptureGallery-C0xqFLap.js +0 -1
  32. package/web/dist/assets/DesktopUpdatePanel-uMaTnBsl.js +0 -1
  33. package/web/dist/assets/SettingsPage-BoFLQBfH.js +0 -1
  34. package/web/dist/assets/SettingsTabs-D0zQN-Mo.js +0 -1
  35. package/web/dist/assets/SupportPage-D241Vkb1.js +0 -2
  36. package/web/dist/assets/VuvoDeskApp-36bRXXS2.js +0 -1
  37. package/web/dist/assets/app-hMd5uyvT.js +0 -1
  38. package/web/dist/assets/icons-CacEbnZu.js +0 -1
  39. package/web/dist/assets/main-DT492iHt.js +0 -2
  40. package/web/dist/assets/react-Cfedt3N5.js +0 -1
  41. package/web/dist/assets/styles-Ba1tPFHg.js +0 -16
  42. /package/web/dist/assets/{App-DFLBNvIi.css → HubApp-DFLBNvIi.css} +0 -0
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "kind": "livedesk-production-web-source-evidence",
4
- "generatedAt": "2026-09-01T13:20:07.258Z",
5
- "pwaRelease": "0.1.656",
6
- "sourceHash": "730d651deeee0a276c058b8c5d59ef18949b7e2a94acc03e36dc98501fce35ff",
7
- "sourceFileCount": 221,
8
- "sourceBytes": 2988821,
4
+ "generatedAt": "2026-09-02T01:30:31.673Z",
5
+ "pwaRelease": "0.1.658",
6
+ "sourceHash": "f8ec762e5597592f2b68e685cafd4e896f3522a5108bc71446616c4ef4983b4d",
7
+ "sourceFileCount": 223,
8
+ "sourceBytes": 3001265,
9
9
  "viteEnvironmentHash": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
10
- "outputHash": "f603dff833b1d9d799a616e466c518d0b157e1eac87ad3faa11ac90df270bf78",
11
- "outputFileCount": 43,
12
- "outputBytes": 1898328,
10
+ "outputHash": "f1302402116ef038772eae72fe43dfccc463a9158b7710e317ae3c0dc43e0594",
11
+ "outputFileCount": 47,
12
+ "outputBytes": 1904705,
13
13
  "outputManifest": [
14
14
  {
15
15
  "path": "_headers",
@@ -18,13 +18,13 @@
18
18
  },
19
19
  {
20
20
  "path": "app.html",
21
- "bytes": 6337,
22
- "sha256": "e2449ac9f0bd02f7298e7c8a96bf51b4f148c28965ee5ca24747bddb8edb8a56"
21
+ "bytes": 5910,
22
+ "sha256": "b279c45614c77cc171c25749ca4671024029e872809796dd4b0c130c36e3045e"
23
23
  },
24
24
  {
25
25
  "path": "app.webmanifest",
26
26
  "bytes": 841,
27
- "sha256": "f6c4f7bf2d419f45816c3fedf1067ff15497c9300d2c29a932a67e37e84043cd"
27
+ "sha256": "9f99b377d367c8ab346fa4d56c65f87a838e3087bcc706c2f0aec72246ec4d0e"
28
28
  },
29
29
  {
30
30
  "path": "apple-touch-icon.png",
@@ -32,9 +32,14 @@
32
32
  "sha256": "0c8f7e411c993a1acaa1c41046b952cf412dbc5ff53b9d5a8fc17158ee1f0520"
33
33
  },
34
34
  {
35
- "path": "assets/AgentSettingsTab-D0271Ynp.js",
36
- "bytes": 4493,
37
- "sha256": "ab4f098afb94ccbc10a750276569199497ecc882f795f681615f54c81132fa66"
35
+ "path": "assets/AgentSettingsTab-8WnOGkVa.js",
36
+ "bytes": 4547,
37
+ "sha256": "594964815b991576186c53fe3f6a0c66ba9197da3c508272970d4525d102849c"
38
+ },
39
+ {
40
+ "path": "assets/AgentsPage-CCO7AwAO.js",
41
+ "bytes": 65762,
42
+ "sha256": "acb08fb1442682faf74143494909ffc201deb2d3a4087ecd4044627a684206b8"
38
43
  },
39
44
  {
40
45
  "path": "assets/AgentsPage-D29gvPcH.css",
@@ -42,29 +47,19 @@
42
47
  "sha256": "fe349e23f92e35f98583c791185a73d99b3e9e263d2151b404e3937b0212a4aa"
43
48
  },
44
49
  {
45
- "path": "assets/AgentsPage-DEdUBoe0.js",
46
- "bytes": 65689,
47
- "sha256": "94d7aaa361a6d78c4b09f95829e567866d0f597d3dc6e03936919af03c0396fe"
48
- },
49
- {
50
- "path": "assets/App-DFLBNvIi.css",
51
- "bytes": 22235,
52
- "sha256": "2b6174a109112146b0f176b5d0068885bb7b2a9d832398884e49194d81ad5cad"
53
- },
54
- {
55
- "path": "assets/App-DK9GZcvU.js",
56
- "bytes": 519662,
57
- "sha256": "4f50a293af829f9924b3b0d512508befc4a9042234e2278aa316579b354b7b81"
50
+ "path": "assets/app--miKlon3.js",
51
+ "bytes": 2193,
52
+ "sha256": "8d40eb2436b74f581384458b7d65cb05496f145a8b4b2709bd49c9f9bceea7ce"
58
53
  },
59
54
  {
60
- "path": "assets/app-hMd5uyvT.js",
61
- "bytes": 422,
62
- "sha256": "2991b7a1e5f5aef2848c17995e31ef5c3531a4739ba75ba95e71be63425513f0"
55
+ "path": "assets/CaptureGallery-7NXD-vaQ.js",
56
+ "bytes": 2580,
57
+ "sha256": "343f539130bfe24e935e7fb172404e98094a50e479db8b082a4e8cb43efde6ef"
63
58
  },
64
59
  {
65
- "path": "assets/CaptureGallery-C0xqFLap.js",
66
- "bytes": 2491,
67
- "sha256": "77bf10f6a662aea602d7525dae1ffa0601f9db67e776ff9cfa8d013355487adb"
60
+ "path": "assets/client-8jUbxy3j.js",
61
+ "bytes": 504,
62
+ "sha256": "da7369fc03cfca463750e9117c321b137ad353a8698a13ecfadd06c5a09680f7"
68
63
  },
69
64
  {
70
65
  "path": "assets/desktop-auth-renderer-contract-CBeQI8Qu.js",
@@ -72,9 +67,9 @@
72
67
  "sha256": "49bb16009a16e6296627e1a30bae3c5eff22d59ab9b0fdb7d5938ce1cc16aabb"
73
68
  },
74
69
  {
75
- "path": "assets/DesktopUpdatePanel-uMaTnBsl.js",
76
- "bytes": 4387,
77
- "sha256": "a3a1e68caab104e3340703488f496c098f158b7ca1bfc6317374a98a73f65bab"
70
+ "path": "assets/DesktopUpdatePanel-CiGXFhqj.js",
71
+ "bytes": 4394,
72
+ "sha256": "84d93816cc760a623e68e8f5bf5b18aeac8a5b3343b3c2abfd7ba3ce10b87ee5"
78
73
  },
79
74
  {
80
75
  "path": "assets/frame-lifecycle-esOdP-EY.js",
@@ -82,9 +77,19 @@
82
77
  "sha256": "2c545f43649e84b8e811124438e8902c3be143d4790bde273fba1c5ad975de0a"
83
78
  },
84
79
  {
85
- "path": "assets/icons-CacEbnZu.js",
86
- "bytes": 34490,
87
- "sha256": "e95c67620eb3d7f0bbcbc563fe7f4e2bd18036558690b2de6502583cd666a45a"
80
+ "path": "assets/HubApp-AhKLyz3K.js",
81
+ "bytes": 520141,
82
+ "sha256": "a419798de59291f8c99f2823af0043bd9e0764925b4e3c826ed5e908570a0cc8"
83
+ },
84
+ {
85
+ "path": "assets/HubApp-DFLBNvIi.css",
86
+ "bytes": 22235,
87
+ "sha256": "2b6174a109112146b0f176b5d0068885bb7b2a9d832398884e49194d81ad5cad"
88
+ },
89
+ {
90
+ "path": "assets/icons-CuXJn-Hz.js",
91
+ "bytes": 34890,
92
+ "sha256": "629394d30c5273d6a00f023b2fa01801feaecaa49b72dc4b42f3622467f78bc5"
88
93
  },
89
94
  {
90
95
  "path": "assets/main-CLwaKs4-.css",
@@ -92,9 +97,24 @@
92
97
  "sha256": "79594d3b1207b6999ede1360efd55ef03c4fd3f5ac2dceed986d0c1c3e3b1483"
93
98
  },
94
99
  {
95
- "path": "assets/main-DT492iHt.js",
96
- "bytes": 36645,
97
- "sha256": "769bdb512becf75352101990a6ebde03e3b5a92ce4ca7cd8924e01b7a44b071f"
100
+ "path": "assets/main-DVNv6hc-.js",
101
+ "bytes": 36921,
102
+ "sha256": "b1805bfead2df592dfc2200e15c42d54b1a14f1a81a79897fe29bc95dfd9b31d"
103
+ },
104
+ {
105
+ "path": "assets/MonitorStackIcon-DBuXI_Oa.js",
106
+ "bytes": 52877,
107
+ "sha256": "258a181e364f0f7d0b1800f35bc11f2aa276d5f9bb42be9000707b4c2efcac69"
108
+ },
109
+ {
110
+ "path": "assets/preload-helper-DD1OZmLC.js",
111
+ "bytes": 1820,
112
+ "sha256": "d161c8ac37addb3cb4ff1d1618bc83d91b1e3962ef00dafc0af8db1cc4c4a054"
113
+ },
114
+ {
115
+ "path": "assets/pwa-bootstrap-BCid3CYk.js",
116
+ "bytes": 4160,
117
+ "sha256": "89f328138f5fa749f1304f5bc4c83006934e1b761373a1132f16a32c40c97b0d"
98
118
  },
99
119
  {
100
120
  "path": "assets/pwa-runtime-diagnostic-lane-CXJ3zl5c.js",
@@ -102,9 +122,14 @@
102
122
  "sha256": "e9f68fc5fb49049db581e88e052bc48525335aa943bd393ba4b4d1a4e4b4c540"
103
123
  },
104
124
  {
105
- "path": "assets/react-Cfedt3N5.js",
106
- "bytes": 3654,
107
- "sha256": "b47c95f891c79e91dc0c07e174c823551745f219400cffb35a313f59afd73a66"
125
+ "path": "assets/pwa-startup-xxamnV7P.js",
126
+ "bytes": 2413,
127
+ "sha256": "a9a5b7c60a1b96ed1cfdb2cc81f3602500434a9dc78f74bd1bb4565b933a0b94"
128
+ },
129
+ {
130
+ "path": "assets/react-rvm9rmed.js",
131
+ "bytes": 184033,
132
+ "sha256": "9abe9bfd61861de9768b637d78ab0069b983c8720589a25b5e3fdead64e13cec"
108
133
  },
109
134
  {
110
135
  "path": "assets/remote-status-Ci5cE6Rj.js",
@@ -112,14 +137,14 @@
112
137
  "sha256": "9ffcc619bc1785028bd28eaabd19c577d22228f06c0182500dec58a378fe17bc"
113
138
  },
114
139
  {
115
- "path": "assets/SettingsPage-BoFLQBfH.js",
116
- "bytes": 9684,
117
- "sha256": "cdea02cecb2415b424265aa11d388835acee4679fc761c9da3e56a81f2f43bc3"
140
+ "path": "assets/SettingsPage-DnOdy3MQ.js",
141
+ "bytes": 9734,
142
+ "sha256": "1daba413d1ba5d8588be9300bc4b13d4ae4c9c9b1667e4316d56165b1eeef1df"
118
143
  },
119
144
  {
120
- "path": "assets/SettingsTabs-D0zQN-Mo.js",
121
- "bytes": 217,
122
- "sha256": "8f3dd7625350932b46c63261ce643b0ef6348d46f2b117a38f2f1bb11d19b40a"
145
+ "path": "assets/SettingsTabs-DfjoCvK4.js",
146
+ "bytes": 230,
147
+ "sha256": "7d82dade2daf05af6b9c624c033bcc527a76d5d3a5793d25a5883e014f0ed4ca"
123
148
  },
124
149
  {
125
150
  "path": "assets/ShareFilesPage-BCCMoGKE.css",
@@ -127,14 +152,9 @@
127
152
  "sha256": "8eed16509e17695b37a28790e25e12f8a00a50b8f5fcc11c5c68fae0687c9c98"
128
153
  },
129
154
  {
130
- "path": "assets/ShareFilesPage-BiCS0Nyd.js",
131
- "bytes": 188619,
132
- "sha256": "0719550c1f30993a1745c3d47e9d44346b9f6de0a25a9a5b4e0f34f2a8ea7ba9"
133
- },
134
- {
135
- "path": "assets/styles-Ba1tPFHg.js",
136
- "bytes": 239814,
137
- "sha256": "932c10c218ada7497afec7679875306bccee249df231cffdcc83e6a19e7c106c"
155
+ "path": "assets/ShareFilesPage-C3Jv7EII.js",
156
+ "bytes": 188712,
157
+ "sha256": "12399f046cc32fc6d8e8c84e0a5f33e5acaeded357912caf4b162d5ab786ccac"
138
158
  },
139
159
  {
140
160
  "path": "assets/styles-DDKP4MTD.css",
@@ -146,26 +166,26 @@
146
166
  "bytes": 210756,
147
167
  "sha256": "35040fe06fc7d7d25c730105638388ca6400835dac8caff268cf553d6639b886"
148
168
  },
169
+ {
170
+ "path": "assets/SupportPage-B16Jl8Jq.js",
171
+ "bytes": 30715,
172
+ "sha256": "aef0d6db8ff46c2ad2c913f9843bd8f6bdd4afb3605958aee91232b9a03ec2ea"
173
+ },
149
174
  {
150
175
  "path": "assets/SupportPage-Cxx61WwR.css",
151
176
  "bytes": 14643,
152
177
  "sha256": "59a383e6d7382973d103d21b4817bd53b124b9fa908c459bf5c418c9e4c88e82"
153
178
  },
154
- {
155
- "path": "assets/SupportPage-D241Vkb1.js",
156
- "bytes": 30635,
157
- "sha256": "f704885526d540ecf19b47dc3e50e401b839521c706f51aee067879d385466f4"
158
- },
159
- {
160
- "path": "assets/VuvoDeskApp-36bRXXS2.js",
161
- "bytes": 32525,
162
- "sha256": "62138be635a880ffd4e9acc825af7a8de912c49ecd1d594e9957877a60375c39"
163
- },
164
179
  {
165
180
  "path": "assets/VuvoDeskApp-ao5vkK6F.css",
166
181
  "bytes": 26355,
167
182
  "sha256": "46b020c1806e59e07b454da8ab61ae111f5835f09b12f6df6364e94d146dbd56"
168
183
  },
184
+ {
185
+ "path": "assets/VuvoDeskApp-CU4N6t3c.js",
186
+ "bytes": 32604,
187
+ "sha256": "6f2e7fdf762711feb3f99ee09a95150feafab7bc176ba339ea63916c840199ba"
188
+ },
169
189
  {
170
190
  "path": "desktop-auth-callback.html",
171
191
  "bytes": 3194,
@@ -188,8 +208,8 @@
188
208
  },
189
209
  {
190
210
  "path": "index.html",
191
- "bytes": 7469,
192
- "sha256": "d07be89e0abc4e4da876e7c39a0b3697d0ae0f897affe4f0b062e848894a8506"
211
+ "bytes": 7820,
212
+ "sha256": "63802c96afec2f1434e69a6aee58b7dee983b2f00355f366f1b9335240b01c27"
193
213
  },
194
214
  {
195
215
  "path": "offline.html",
@@ -223,8 +243,8 @@
223
243
  },
224
244
  {
225
245
  "path": "sw.js",
226
- "bytes": 2296,
227
- "sha256": "6cc38e3eae377271f6ac94d48f0a387de49fea7696dc9e53e09cdaa824e256a1"
246
+ "bytes": 2946,
247
+ "sha256": "0fa6fa1e55a403b6d36463f41d2773f4581f3a47c1eb46762f529860ad579bd6"
228
248
  }
229
249
  ]
230
250
  }
@@ -1 +0,0 @@
1
- import{h as x,j as t}from"./styles-Ba1tPFHg.js";import{a as c,a5 as A,k as q,a6 as I,a7 as z}from"./icons-CacEbnZu.js";import"./react-Cfedt3N5.js";const E={enabled:!0};function w(a){return{enabled:a?.enabled===!0}}async function L(a,p,f){let l=null;for(let s=0;s<2;s+=1){const g=await x("/api/settings",{signal:f},p);if(g.settings.agent?.enabled===a)return;try{await x("/api/settings",{method:"PATCH",signal:f,body:JSON.stringify({revision:g.revision,agent:{enabled:a}})},p);return}catch(i){if(l=i,s!==0||!String(i instanceof Error?i.message:i).startsWith("409 "))throw i}}throw l}function F({hubUrl:a,showToast:p}){const[f,l]=c.useState(E),[s,g]=c.useState(null),[i,m]=c.useState(""),[j,v]=c.useState(""),[y,d]=c.useState(""),b=c.useRef(0),u=c.useRef(null);c.useEffect(()=>{let e=!0;u.current?.abort();const n=new AbortController;u.current=n;const h=++b.current;return g(null),l(E),m(""),d(""),v(""),x("/api/settings/agent",{signal:n.signal},a).then(o=>{!e||n.signal.aborted||h!==b.current||(g(o.settings),l(w(o.settings)))}).catch(o=>{e&&!n.signal.aborted&&h===b.current&&d(o instanceof Error?o.message:String(o))}),()=>{e=!1,n.abort(),u.current===n&&(u.current=null)}},[a]);const k=(e,n)=>l(h=>({...h,[e]:n})),C=e=>{g(e),l(w(e))},S=()=>({generation:b.current,controller:u.current}),r=e=>e.generation===b.current&&e.controller!==null&&e.controller===u.current&&!e.controller.signal.aborted,R=async()=>{if(!s){d("Agent settings are not available yet.");return}const e=S();if(r(e)){m("save"),d(""),v("");try{if(await L(f.enabled,a,e.controller.signal),!r(e))return;const n=await x("/api/settings/agent",{signal:e.controller.signal},a);if(!r(e))return;C(n.settings),v("Codex Agent settings saved.")}catch(n){r(e)&&d(n instanceof Error?n.message:String(n))}finally{r(e)&&m("")}}},D=async()=>{const e=S();if(r(e)){m("test"),d(""),v("");try{const n=await x("/api/settings/agent/test",{method:"POST",signal:e.controller.signal,body:JSON.stringify({})},a);if(!r(e))return;const h=await x("/api/settings/agent",{signal:e.controller.signal},a);if(!r(e))return;C(h.settings);const o=Number.isFinite(n.connection?.latencyMs)?Math.max(0,Math.round(n.connection.latencyMs)):null;p(`Codex Agent connection verified${o!==null?` in ${o} ms.`:"."}`,"success")}catch(n){r(e)&&d(n instanceof Error?n.message:String(n))}finally{r(e)&&m("")}}},T=s?.codexInstallation==="installed"&&s.codexAuth==="signed-in",N=s!==null;return t.jsxs("div",{className:"settings-tab-content agent-settings-content",children:[t.jsxs("section",{className:"settings-section-card agent-enable-card",children:[t.jsxs("label",{className:"settings-toggle agent-enable-toggle",children:[t.jsx("input",{type:"checkbox",checked:f.enabled,onChange:e=>k("enabled",e.target.checked),disabled:!N||i!==""}),t.jsx("span",{children:"Enable Codex Agent"})]}),t.jsxs("p",{className:"settings-help",children:[t.jsx(A,{size:12})," Enabled by default. Agent commands use only the Codex account signed in on this Hub."]})]}),y&&t.jsx("div",{className:"agent-settings-alert error",role:"alert",children:y}),j&&t.jsx("div",{className:"agent-settings-alert success",role:"status",children:j}),t.jsxs("section",{className:"settings-section-card",children:[t.jsxs("div",{className:"settings-section-heading",children:[t.jsxs("div",{children:[t.jsx("span",{children:"Connection"}),t.jsx("h3",{children:"Codex SDK / CLI"})]}),t.jsx(q,{size:20})]}),t.jsxs("div",{className:"agent-connection-row",children:[t.jsx("span",{className:`agent-connection-dot ${T?"connected":s?.codexAuth==="not-signed-in"?"unavailable":""}`}),t.jsx("span",{children:s?.codexInstallation==="not-installed"?"Codex SDK not installed":s?.codexAuth==="signed-in"?"Codex CLI signed in":s?.codexAuth==="not-signed-in"?"Codex CLI sign-in required":"Codex status not tested"}),t.jsxs("button",{className:"settings-reset",onClick:()=>{D()},disabled:i!=="",type:"button",children:[t.jsx(I,{size:15})," ",i==="test"?"Testing":"Test connection"]})]}),t.jsxs("p",{className:"settings-help",children:[t.jsx(A,{size:12})," The Hub uses the installed Codex SDK / CLI to plan approved commands and run them through VuvoDesk Agent tools on selected computers. VuvoDesk never asks for separate credentials."]})]}),t.jsx("div",{className:"settings-action-row agent-settings-actions",children:t.jsxs("button",{className:"text-button primary",onClick:()=>{R()},disabled:!N||i!=="",type:"button",children:[t.jsx(z,{size:15})," ",i==="save"?"Saving":"Save Agent settings"]})})]})}export{F as AgentSettingsTab};
@@ -1 +0,0 @@
1
- import{j as e}from"./styles-Ba1tPFHg.js";import{a as r,Y as p,a8 as j,D as u,a9 as g,a1 as f}from"./icons-CacEbnZu.js";import{l as b,c as d,d as y}from"./App-DK9GZcvU.js";import"./react-Cfedt3N5.js";import"./supabase-C7qjtLN3.js";import"./frame-lifecycle-esOdP-EY.js";function D({hubUrl:t,onToast:i}){const[o,m]=r.useState([]),[h,c]=r.useState(!0),n=r.useCallback(async()=>{c(!0);try{m((await b(t)).captures||[])}catch(a){i(a instanceof Error?a.message:String(a))}finally{c(!1)}},[t,i]);r.useEffect(()=>{n()},[n]);const x=async a=>{const s=d(a.id,t);if(navigator.share)try{await navigator.share({title:a.fileName,url:s});return}catch{}window.open(s,"_blank","noopener,noreferrer")};return e.jsxs("section",{className:"capture-gallery",children:[e.jsxs("header",{children:[e.jsxs("div",{children:[e.jsx("span",{className:"settings-eyebrow",children:"Capture Gallery"}),e.jsx("h2",{children:"Saved captures"})]}),e.jsxs("button",{className:"text-button",onClick:()=>{n()},type:"button",children:[e.jsx(p,{size:15})," Refresh"]})]}),h?e.jsx("p",{className:"settings-help",children:"Loading captures..."}):o.length===0?e.jsx("p",{className:"settings-help",children:"No captures saved yet."}):e.jsx("div",{className:"capture-gallery-grid",children:o.map(a=>{const s=d(a.id,t);return e.jsxs("article",{className:"capture-gallery-card",children:[a.mimeType.startsWith("image/")?e.jsx("img",{src:s,alt:a.target.label}):e.jsx("video",{src:s,controls:!0,preload:"metadata"}),e.jsxs("div",{className:"capture-gallery-card-body",children:[e.jsx("strong",{children:a.fileName}),e.jsxs("small",{children:[a.target.label," · ",new Date(a.createdAt).toLocaleString()," · ",Math.ceil(a.sizeBytes/1024)," KB"]}),e.jsxs("div",{children:[e.jsx("button",{className:"icon-button",title:"Open","aria-label":"Open",onClick:()=>window.open(s,"_blank","noopener,noreferrer"),type:"button",children:e.jsx(j,{size:15})}),e.jsx("a",{className:"icon-button",title:"Download","aria-label":"Download",href:`${s}?download=1`,download:a.fileName,children:e.jsx(u,{size:15})}),e.jsx("button",{className:"icon-button",title:"Share","aria-label":"Share",onClick:()=>{x(a)},type:"button",children:e.jsx(g,{size:15})}),e.jsx("button",{className:"icon-button danger",title:"Delete","aria-label":"Delete",onClick:()=>{window.confirm(`Delete ${a.fileName}?`)&&y(a.id,t).then(()=>n()).catch(l=>i(l instanceof Error?l.message:String(l)))},type:"button",children:e.jsx(f,{size:15})})]})]})]},a.id)})})]})}export{D as CaptureGallery};
@@ -1 +0,0 @@
1
- import{j as e}from"./styles-Ba1tPFHg.js";import{a as r,D as y,a4 as j,Y as b}from"./icons-CacEbnZu.js";import"./react-Cfedt3N5.js";function D(t){if(!t)return"Reading the installed version...";const n=String(t.errorCode||t.error||"");switch(t.state){case"checking":return"Checking for a newer VuvoDesk version...";case"available":return`Version ${t.availableVersion||""} is available.`;case"downloading":return`Downloading version ${t.availableVersion||""} (${Math.round(t.progress||0)}%).`;case"downloaded":return`Version ${t.availableVersion||""} is ready. Restart to install it.`;case"installing":return"Closing VuvoDesk safely and starting the update...";case"current":return"This computer has the latest VuvoDesk version.";case"error":return/runtime-recovery-failed/i.test(n)?"The local VuvoDesk service could not restart. Quit VuvoDesk completely and reopen it.":/owner-cleanup-stuck|owner-reset-failed/i.test(n)?"The Windows update service could not reset. Quit VuvoDesk completely, reopen it, and check again.":/installer-launch-failed/i.test(n)?"The installer could not start. VuvoDesk restored its local service so you can retry.":/version-mismatch/i.test(n)?"The downloaded update did not match the expected version. VuvoDesk will retry safely.":/stalled|timed-out/i.test(n)?"The update connection stopped responding. VuvoDesk will retry automatically.":"The update server could not be reached. VuvoDesk will retry automatically.";case"development":return"Desktop updates are available in an installed VuvoDesk build.";case"unavailable":return"Updates are not available for this desktop build.";default:return"VuvoDesk checks once when the desktop app starts."}}function C(){const t=window.liveDesk?.updates,n=window.liveDesk?.app,[s,i]=r.useState(null),[f,u]=r.useState(!1),[o,p]=r.useState(null),[g,h]=r.useState(!1);if(r.useEffect(()=>{if(!t)return;let a=!0;t.getStatus?.().then(c=>{a&&i(c)});const d=t.onStatus?.(c=>{a&&i(c)});return()=>{a=!1,d?.()}},[t]),r.useEffect(()=>{if(!n?.getAutoStart)return;let a=!0;return n.getAutoStart().then(d=>{a&&p(d)}),()=>{a=!1}},[n]),!t)return null;const v=s?.state==="downloaded"||s?.downloaded===!0,k=!!s?.reopenRequired||/runtime-recovery-failed|owner-cleanup-stuck|owner-reset-failed/i.test(String(s?.errorCode||"")),l=f||s?.state==="checking"||s?.state==="downloading"||s?.state==="installing",m=s?.channel==="dev"?"Development":s?.channel==="stable"?"Stable":s?.channel||"Unknown",x=async()=>{u(!0);try{const a=v?await t.install?.():await t.check?.();a&&i(a)}finally{u(!1)}},w=async a=>{if(n?.setAutoStart){h(!0);try{p(await n.setAutoStart(a))}finally{h(!1)}}};return e.jsxs("section",{className:"settings-section-card desktop-update-card",children:[e.jsxs("div",{className:"settings-section-heading",children:[e.jsxs("div",{children:[e.jsx("span",{children:"Desktop app"}),e.jsx("h3",{children:"VuvoDesk updates"})]}),e.jsx(y,{size:20})]}),e.jsx("p",{className:"settings-help","aria-live":"polite",children:D(s)}),e.jsxs("div",{className:"desktop-update-meta",children:[e.jsx("span",{children:"Installed"}),e.jsx("strong",{children:s?.currentVersion||"Unknown"}),e.jsx("span",{children:"Channel"}),e.jsx("strong",{children:m}),s?.availableVersion&&e.jsxs(e.Fragment,{children:[e.jsx("span",{children:"Available"}),e.jsx("strong",{children:s.availableVersion})]})]}),n?.getAutoStart&&e.jsxs("div",{className:"desktop-auto-start-setting",children:[e.jsxs("div",{className:"desktop-auto-start-copy",children:[e.jsx(j,{size:18}),e.jsxs("span",{children:[e.jsx("strong",{children:"Start automatically after sign-in"}),e.jsx("small",{children:"Reconnect this computer quietly after Windows, macOS, or Linux sign-in."})]})]}),e.jsxs("label",{className:"settings-toggle desktop-auto-start-toggle",children:[e.jsx("input",{type:"checkbox",checked:o?.enabled??!0,onChange:a=>{w(a.target.checked)},disabled:!o?.supported||g}),e.jsx("span",{children:o?.enabled===!1?"Off":"On"})]}),o?.error&&e.jsx("p",{className:"desktop-auto-start-error",role:"alert",children:"Automatic start could not be updated. VuvoDesk will retry next time it opens."})]}),e.jsxs("button",{className:"settings-reset desktop-update-action",onClick:()=>{x()},disabled:l||k,type:"button",children:[e.jsx(b,{size:15,className:l?"desktop-update-spin":""}),k?"Reopen VuvoDesk":v?"Restart and update":l?"Updating...":"Check for updates"]})]})}export{C as DesktopUpdatePanel};
@@ -1 +0,0 @@
1
- import{h as C,j as e,w as je,n as ve}from"./styles-Ba1tPFHg.js";import{a as i,W as be,k as ee,a3 as O,S as we,c as F,F as Re,Z as Se,a4 as ye,J as $}from"./icons-CacEbnZu.js";import"./react-Cfedt3N5.js";const x={revision:0,settings:{connection:{showThisComputer:!1},security:{accessMode:"trusted-only"},control:{allowKeyboardMouse:!0,allowRemoteRestart:!1},filesAudio:{allowFileTransfer:!0,allowRemoteAudio:!0,rollingBufferEnabled:!1,recordingQuality:"standard",timelapseIntervalSeconds:10,includeRemoteCursor:!0}}},Y=[{id:"connection",label:"Connection",icon:be},{id:"remote-access",label:"Remote Access",icon:ee},{id:"capture-audio",label:"Capture & Audio",icon:O},{id:"agent",label:"Agent",icon:we}];function A(t,n){return t?.settings?.[n]||x.settings[n]||{}}function _(t,n){return{...t,settings:{...t.settings,[n.section]:{...A(t,n.section),[n.key]:n.value}}}}function J(t){return{revision:Number(t.revision||0),updatedAt:t.updatedAt,settings:t.settings}}function g({icon:t,title:n,description:d,children:m,recommended:a=!1}){return e.jsxs("div",{className:"product-setting-row",children:[e.jsx("div",{className:"product-setting-control",children:m}),t&&e.jsx("span",{className:"product-setting-icon",children:e.jsx(t,{size:17})}),e.jsxs("div",{className:"product-setting-copy",children:[e.jsx("strong",{children:n}),a&&e.jsx("em",{children:"Recommended"}),e.jsx("small",{children:d})]})]})}function R({checked:t,onChange:n,label:d}){return e.jsxs("label",{className:"product-switch",children:[e.jsx("input",{"aria-label":d,type:"checkbox",checked:t,onChange:m=>n(m.target.checked)}),e.jsx("span",{})]})}function U({value:t,onChange:n,options:d,label:m}){return e.jsx("select",{"aria-label":m,value:String(t),onChange:a=>n(a.target.value),children:d.map(([a,M])=>e.jsx("option",{value:a,children:M},a))})}function ke({hubUrl:t="",mobileLayout:n=!1,runtimeRole:d="hub",runtimeDeviceId:m="",sessionAccessToken:a="",showThisComputerSetting:M=!0,onShowThisComputerChange:D,initialTab:Q="connection",pin:te,agent:se,captureGallery:ne,desktopUpdate:ie}){const[r,q]=i.useState(()=>n&&Q==="connection"?"remote-access":Q),[j,k]=i.useState(null),[oe,v]=i.useState("loading"),[G,T]=i.useState(""),[K,E]=i.useState("idle"),[V,z]=i.useState(""),b=i.useRef(null),u=i.useRef(null),p=i.useRef([]),B=i.useRef(Promise.resolve()),re=i.useRef(0),f=i.useRef(0);i.useEffect(()=>{const s=++f.current;let l=!0;return p.current=[],u.current=null,b.current=null,B.current=Promise.resolve(),v("loading"),C("/api/settings",void 0,t).then(o=>{if(!l||s!==f.current)return;const c=J(o);u.current=c,b.current=c,k(c),v("saved")}).catch(o=>{!l||s!==f.current||(T(o instanceof Error?o.message:String(o)),u.current=x,b.current=x,k(x),v("failed"))}),()=>{l=!1}},[t]);const ce=async(s,l,o)=>{const c={id:++re.current,section:s,key:l,value:o},H=f.current;p.current.push(c);const L=_(b.current||u.current||x,c);b.current=L,k(L),v("saving"),T(""),B.current=B.current.then(async()=>{if(H!==f.current)return;let S=null,y=null;for(let N=0;N<2&&!S;N+=1){const xe=u.current||x;try{const w=await C("/api/settings",{method:"PATCH",body:JSON.stringify({revision:xe.revision,[c.section]:{[c.key]:c.value}})},t);S=J(w)}catch(w){if(y=w,N!==0||!String(w instanceof Error?w.message:w).startsWith("409 "))break;try{const W=await C("/api/settings",void 0,t);if(H!==f.current)return;u.current=J(W)}catch(W){y=W;break}}}if(H!==f.current)return;p.current=p.current.filter(N=>N.id!==c.id),S&&(u.current=S);const fe=u.current||x,X=p.current.reduce(_,fe);b.current=X,k(X),S?(T(""),v(p.current.length>0?"saving":"saved")):(v(p.current.length>0?"saving":"failed"),T(y instanceof Error?y.message:String(y||"Settings could not be saved.")))}),await B.current},h=(s,l)=>o=>{ce(s,l,o)},ae=async()=>{if(d!=="hub"||!m||!a){E("failed"),z("Sign in to this Hub before changing its runtime role.");return}E("changing"),z("");try{const s=await C("/api/runtime/status",void 0,t);await C("/api/runtime/role",{method:"POST",headers:{Authorization:`Bearer ${a}`},body:JSON.stringify({role:"client"})},t),E("accepted"),await je({baseUrl:t,targetRole:"client",previousRuntimePid:Number(s.runtimePid||0),allowedStates:["running","waiting-auth"]}),ve(5179)}catch(s){E("failed"),z(s instanceof Error?s.message:String(s))}},le=A(j,"security"),Z=A(j,"control"),P=A(j,"filesAudio"),I=A(j,"connection"),de=`settings-panel-${r}`,ue=n?Y.filter(s=>s.id!=="connection"):Y;i.useEffect(()=>{n&&r==="connection"&&q("remote-access")},[r,n]),i.useEffect(()=>{j&&D?.(!!I.showThisComputer)},[I.showThisComputer,D,j]);const he=e.jsxs("div",{className:"settings-tab-content product-settings-content",children:[te,ie,M&&e.jsxs("section",{className:"settings-section-card",children:[e.jsxs("div",{className:"settings-section-heading",children:[e.jsxs("div",{children:[e.jsx("span",{children:"Hub computer list"}),e.jsx("h3",{children:"This computer"})]}),e.jsx(F,{size:20})]}),e.jsx(g,{icon:F,title:"Show this computer",description:"Show this Hub computer in its own Wall and computer lists. It stays available from other computers and the mobile app when hidden.",children:e.jsx(R,{checked:!!I.showThisComputer,onChange:h("connection","showThisComputer"),label:"Show this computer"})})]}),e.jsxs("section",{className:"settings-section-card runtime-role-settings",children:[e.jsxs("div",{className:"settings-section-heading",children:[e.jsxs("div",{children:[e.jsx("span",{children:"Runtime role"}),e.jsx("h3",{children:"Use this computer as a Client"})]}),e.jsx(Re,{size:20})]}),e.jsx("p",{className:"settings-help",children:"Stop hosting from this computer and reconnect it to the selected Hub."}),K==="accepted"?e.jsx("p",{className:"settings-help runtime-role-success",children:"VuvoDesk is restarting as Client."}):V?e.jsx("p",{className:"settings-help runtime-role-error",role:"alert",children:V}):null,e.jsx("button",{className:"settings-reset",onClick:()=>{ae()},disabled:K==="changing"||d!=="hub",type:"button",children:K==="changing"?"Switching role...":"Switch this computer to Client"})]})]}),ge=e.jsxs("div",{className:"settings-tab-content product-settings-content",children:[e.jsxs("section",{className:"settings-section-card",children:[e.jsxs("div",{className:"settings-section-heading",children:[e.jsxs("div",{children:[e.jsx("span",{children:"Remote access"}),e.jsx("h3",{children:"Who may connect?"})]}),e.jsx(Se,{size:20})]}),e.jsx(g,{icon:ee,title:"Access mode",description:"Choose the default permission boundary for remote sessions.",recommended:!0,children:e.jsx(U,{value:String(le.accessMode),onChange:h("security","accessMode"),label:"Access mode",options:[["trusted-only","Trusted devices only"],["block-remote-access","Block remote access"]]})})]}),e.jsxs("section",{className:"settings-section-card",children:[e.jsxs("div",{className:"settings-section-heading",children:[e.jsxs("div",{children:[e.jsx("span",{children:"Session permissions"}),e.jsx("h3",{children:"What may remote users do?"})]}),e.jsx(F,{size:20})]}),e.jsx(g,{icon:F,title:"Keyboard and mouse control",description:"Allow Control to send keyboard and pointer input.",recommended:!0,children:e.jsx(R,{checked:!!Z.allowKeyboardMouse,onChange:h("control","allowKeyboardMouse"),label:"Keyboard and mouse control"})}),e.jsx(g,{icon:ye,title:"Power actions",description:"Allow confirmed sleep, restart, and shut down commands from the Hub.",children:e.jsx(R,{checked:!!Z.allowRemoteRestart,onChange:h("control","allowRemoteRestart"),label:"Power actions"})}),e.jsx(g,{icon:O,title:"File transfer",description:"Allow files to be delivered to connected computers.",children:e.jsx(R,{checked:!!P.allowFileTransfer,onChange:h("filesAudio","allowFileTransfer"),label:"File transfer"})}),e.jsx(g,{icon:$,title:"Remote audio",description:"Allow sound capture from connected computers.",children:e.jsx(R,{checked:!!P.allowRemoteAudio,onChange:h("filesAudio","allowRemoteAudio"),label:"Remote audio"})})]})]}),me=e.jsxs("div",{className:"settings-tab-content product-settings-content",children:[e.jsxs("section",{className:"settings-section-card",children:[e.jsxs("div",{className:"settings-section-heading",children:[e.jsxs("div",{children:[e.jsx("span",{children:"Capture"}),e.jsx("h3",{children:"Recording defaults"})]}),e.jsx(O,{size:20})]}),e.jsx(g,{icon:$,title:"Keep a Last 30s buffer",description:"Keep recent video in memory until you explicitly save it.",children:e.jsx(R,{checked:!!P.rollingBufferEnabled,onChange:h("filesAudio","rollingBufferEnabled"),label:"Keep a Last 30s buffer"})}),e.jsx(g,{icon:$,title:"Timelapse interval",description:"Choose how often a timelapse frame is captured.",children:e.jsx(U,{value:Number(P.timelapseIntervalSeconds),onChange:s=>h("filesAudio","timelapseIntervalSeconds")(Number(s)),label:"Timelapse interval",options:[["5","5 seconds"],["10","10 seconds"],["30","30 seconds"],["60","60 seconds"]]})})]}),ne]}),pe=r==="connection"?he:r==="remote-access"?ge:r==="capture-audio"?me:se;return e.jsxs("section",{className:"settings-page",children:[e.jsx("div",{className:"settings-page-tabs",role:"tablist","aria-label":"VuvoDesk settings",children:ue.map(({id:s,label:l,icon:o})=>e.jsxs("button",{className:r===s?"active":"",id:`settings-tab-${s}`,role:"tab","aria-selected":r===s,"aria-controls":`settings-panel-${s}`,tabIndex:r===s?0:-1,onClick:()=>q(s),type:"button",children:[e.jsx(o,{size:16}),l]},s))}),oe==="saving"&&e.jsx("div",{className:"product-save-state",role:"status",children:"Saving settings..."}),G&&e.jsx("div",{className:"agent-settings-alert error",role:"alert",children:G}),e.jsx("section",{className:"settings-page-panel",id:de,role:"tabpanel","aria-labelledby":`settings-tab-${r}`,tabIndex:0,children:pe})]})}export{ke as SettingsPage};
@@ -1 +0,0 @@
1
- import{j as i}from"./styles-Ba1tPFHg.js";import"./icons-CacEbnZu.js";import"./react-Cfedt3N5.js";function r({children:t}){return i.jsx("div",{className:"settings-tab-content",children:t})}export{r as PinSettingsTab};
@@ -1,2 +0,0 @@
1
- import{j as e}from"./styles-Ba1tPFHg.js";import{a as c,ab as X,k as T,Y as xe,aI as Ke,az as ye,X as Q,o as be,l as ee,aJ as je,Z as V,$ as Xe,aK as et,aL as ve,aM as _e,aN as tt,D as st,b as at,aO as it,ax as nt,aP as rt,aQ as ot}from"./icons-CacEbnZu.js";import{s as u}from"./App-DK9GZcvU.js";import"./react-Cfedt3N5.js";import"./supabase-C7qjtLN3.js";import"./frame-lifecycle-esOdP-EY.js";const ct=new Set(["browserLanguage","platform","online","viewport","timezone","screen"]),lt={id:"browser-safe-v1",collect(){if(typeof navigator>"u")return{};const s={browserLanguage:navigator.language||"",platform:navigator.platform||"",online:navigator.onLine,timezone:typeof Intl>"u"?"":Intl.DateTimeFormat().resolvedOptions().timeZone||"",viewport:typeof window>"u"?void 0:{width:window.innerWidth,height:window.innerHeight},screen:typeof window>"u"?void 0:{width:window.screen.width,height:window.screen.height}};return Object.fromEntries(Object.entries(s).filter(([i,n])=>ct.has(i)&&n!==void 0))}};function dt(s,i="Support request failed."){if(s&&typeof s=="object"&&"message"in s){const n=String(s.message||"").trim();if(n)return n.replace(/^.*Support request failed:\s*/i,"")}return s instanceof Error?s.message:i}function pt(s=lt){return s.collect()}async function ut(s,i="livedesk"){const{data:n,error:d}=await u.from("app_admins").select("role").eq("user_id",s).limit(1);if(d)throw d;const o=n?.[0]?.role||"user";if(o!=="owner"){const{error:x}=await u.rpc("register_product_access",{p_product_key:i,p_access_type:"free"});if(x)throw x}const[y,m,P]=await Promise.all([u.from("products").select("id, product_key, name, description, sort_order").order("sort_order"),u.from("product_admins").select("product_id, role").eq("user_id",s),u.from("user_products").select("product_id").eq("user_id",s).eq("is_active",!0)]);if(y.error)throw y.error;if(m.error)throw m.error;if(P.error)throw P.error;const j=y.data||[],z=(m.data||[]).map(x=>String(x.product_id)),L=(P.data||[]).map(x=>String(x.product_id)),S=o==="owner",k=S?j.map(x=>x.id):[...new Set([...z,...L])];return{products:j,access:{userId:s,globalRole:o,accessibleProductIds:k,managedProductIds:S?j.map(x=>x.id):z,canViewAllProducts:S,canViewAllPrivatePosts:S,canManageAllProducts:S,canCreateAnnouncements:S||z.length>0}}}async function ht(s=""){const{data:i,error:n}=await u.rpc("search_support_posts",{p_query:s.trim()||null,p_limit:250});if(n)throw n;return i||[]}async function mt(s){const{data:i,error:n}=await u.from("support_attachments").select("*").eq("post_id",s).order("created_at");if(n)throw n;const d=i||[];return Promise.all(d.map(async o=>{const y=await u.storage.from("support-attachments").createSignedUrl(o.storage_path,3600);return{...o,signed_url:y.data?.signedUrl||void 0}}))}async function ft(){const{data:s,error:i}=await u.from("support_notifications").select("*").order("created_at",{ascending:!1}).limit(30);if(i)throw i;return s||[]}async function xt(s){const{error:i}=await u.rpc("mark_support_notification_read",{p_notification_id:s});if(i)throw i}async function ge(s){const{data:i,error:n}=await u.from("support_comments").select("*").eq("post_id",s).order("created_at");if(n)throw n;return i||[]}async function yt(s){const{data:i,error:n}=await u.from("support_votes").select("post_id").eq("user_id",s);if(n)throw n;return new Set((i||[]).map(d=>String(d.post_id)))}async function bt(s){const{data:i,error:n}=await u.rpc("create_support_post",{p_product_id:s.productId,p_post_type:s.postType,p_title:s.title,p_body:s.body,p_visibility:s.visibility,p_app_version:s.appVersion||null,p_platform:typeof navigator>"u"?null:navigator.platform||null,p_os_version:typeof navigator>"u"?null:navigator.platform||null,p_environment:s.includeEnvironment?pt():{}});if(n)throw n;const d=Array.isArray(i)?i[0]?.post_id:i?.post_id;if(!d)throw new Error("Support post was not created.");return String(d)}const jt=new Set(["image/png","image/jpeg","image/webp","text/plain","text/markdown","application/json","application/pdf"]);async function vt(s,i){if(!jt.has(i.type))throw new Error("This file type is not allowed.");if(i.size<=0||i.size>10*1024*1024)throw new Error("Attachments must be smaller than 10 MB.");const n=i.name.replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"attachment",d=typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now()}-${Math.random().toString(16).slice(2)}`,o=`${s}/${d}-${n}`,y=await u.storage.from("support-attachments").upload(o,i,{contentType:i.type,upsert:!1});if(y.error)throw y.error;const{data:m,error:P}=await u.rpc("add_support_attachment",{p_post_id:s,p_storage_path:o,p_file_name:n,p_mime_type:i.type,p_size_bytes:i.size});if(P)throw await u.storage.from("support-attachments").remove([o]),P;const j=Array.isArray(m)?m[0]?.attachment_id:m?.attachment_id;if(!j)throw new Error("Attachment metadata was not created.");return String(j)}async function _t(s,i,n,d){const{error:o}=await u.rpc("update_support_post",{p_post_id:s,p_title:i,p_body:n,p_visibility:d});if(o)throw o}async function gt(s,i){const{error:n}=await u.rpc("add_support_comment",{p_post_id:s,p_body:i});if(n)throw n}async function wt(s){const{data:i,error:n}=await u.rpc("toggle_support_vote",{p_post_id:s});if(n)throw n;const d=Array.isArray(i)?i[0]:i;return{voted:!!d?.voted,totalVotes:Number(d?.total_votes||0)}}async function St(s,i){const{error:n}=await u.rpc("change_support_post_status",{p_post_id:s,p_target_status:i});if(n)throw n}async function Nt(s){const{error:i}=await u.rpc("set_support_post_hidden",{p_post_id:s,p_hidden:!0});if(i)throw i}async function Pt(s,i){const{error:n}=await u.rpc("set_support_post_locked",{p_post_id:s,p_locked:i});if(n)throw n}async function kt(s,i){const{error:n}=await u.rpc("set_support_post_pinned",{p_post_id:s,p_pinned:i});if(n)throw n}async function Ct(s,i){const{error:n}=await u.rpc("mark_support_duplicate",{p_post_id:s,p_duplicate_of_post_id:i});if(n)throw n}async function At(s,i){const{error:n}=await u.rpc("accept_support_answer",{p_post_id:s,p_comment_id:i});if(n)throw n}async function qt(s,i=!0){const{error:n}=await u.rpc("hide_support_comment",{p_comment_id:s,p_hidden:i});if(n)throw n}const ae=[{id:"question",label:"Questions",shortLabel:"Question"},{id:"issue",label:"Issues",shortLabel:"Issue"},{id:"feature",label:"Feature Requests",shortLabel:"Feature"},{id:"announcement",label:"Announcements",shortLabel:"Announcement"}],zt=[{id:"all",label:"All statuses"},{id:"needs-response",label:"Needs response"},{id:"open",label:"Open"},{id:"needs-info",label:"Needs more information"},{id:"in-progress",label:"In progress"},{id:"planned",label:"Planned"},{id:"released",label:"Released"},{id:"closed",label:"Closed"}],Et={question:["open","answered","resolved","closed"],issue:["open","needs-info","confirmed","in-progress","fixed","closed"],feature:["under-review","planned","in-progress","released","declined","closed"],announcement:["published","archived"]},Tt={type:"all",product:"",status:"all",visibility:"all",sort:"recent",query:""};function te(){if(typeof window>"u")return Tt;const s=new URLSearchParams(window.location.search),i=window.location.pathname.match(/^\/support\/(questions|issues|features|announcements)$/)?.[1],n=s.get("type")||i||"",d=n==="questions"||n==="question"?"question":n==="issues"||n==="issue"?"issue":n==="features"||n==="feature"?"feature":n==="announcements"||n==="announcement"?"announcement":"all",o=s.get("visibility"),y=s.get("sort");return{type:d,product:s.get("product")||"",status:s.get("status")||"all",visibility:o==="public"||o==="private"?o:"all",sort:y==="votes"||y==="newest"?y:"recent",query:s.get("q")||""}}function It(s){return s==="all"?"":s==="question"?"questions":s==="issue"?"issues":s==="feature"?"features":"announcements"}function Dt(s,i){const n={...s,...i},d=new URLSearchParams;n.product&&d.set("product",n.product),n.status!=="all"&&d.set("status",n.status),n.visibility!=="all"&&d.set("visibility",n.visibility),n.sort!=="recent"&&d.set("sort",n.sort),n.query&&d.set("q",n.query);const o=It(n.type),y=d.toString();return`/support${o?`/${o}`:""}${y?`?${y}`:""}`}function G(s){const i=new Date(s);return Number.isFinite(i.getTime())?i.toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"}):s}function se(s){return s.replaceAll("-"," ").replace(/\b\w/g,i=>i.toUpperCase())}function we(s){return s==="question"?it:s==="issue"?nt:s==="feature"?rt:ot}function Se(s){return ae.find(i=>i.id===s)?.shortLabel||s}function b(s){const i=dt(s);return/relation .* does not exist|function .* does not exist|schema cache/i.test(i)?"Support Board database is not installed yet. Apply the latest Supabase migration first.":/not-authenticated|jwt/i.test(i)?"Sign in again to use Support.":/product-access-denied|product-not-found/i.test(i)?"You do not have access to this product.":i}function Bt({session:s,currentProductKey:i="livedesk",appVersion:n="",onSignIn:d}){const[o,y]=c.useState(()=>te()),[m,P]=c.useState(null),[j,z]=c.useState([]),[L,S]=c.useState([]),[k,x]=c.useState(""),[R,U]=c.useState([]),[$,ie]=c.useState([]),[M,W]=c.useState([]),[ne,re]=c.useState(()=>new Set),[Z,J]=c.useState(!0),[v,f]=c.useState(""),[oe,p]=c.useState(""),[Ne,O]=c.useState(!1),[Pe,B]=c.useState(!1),[F,ce]=c.useState(""),[le,K]=c.useState(()=>te().query),[ke,de]=c.useState(!1),[Ce,Ae]=c.useState(!1),[qe,ze]=c.useState(""),[pe,Ee]=c.useState(""),[Te,Ie]=c.useState("free"),[De,Ve]=c.useState(""),[ue,Le]=c.useState(""),[Re,Ue]=c.useState("admin"),[I,he]=c.useState(""),[me,Vt]=c.useState(""),[Y,fe]=c.useState([]),[h,A]=c.useState({productId:"",postType:"question",title:"",body:"",visibility:"public",includeEnvironment:!0,files:[]}),N=c.useCallback(t=>{const r={...o,...t};y(r),typeof window<"u"&&window.history.pushState({},"",Dt(o,t))},[o]);c.useEffect(()=>{const t=()=>y(te());return window.addEventListener("popstate",t),()=>window.removeEventListener("popstate",t)},[]);const _=c.useCallback(async()=>{const t=await ht(o.query);return S(t),s?.user.id&&re(await yt(s.user.id)),t},[o.query,s?.user.id]),H=c.useCallback(async()=>{if(!s?.user.id){P(null),z([]),S([]),x(""),W([]),J(!1);return}J(!0),p("");try{const t=await ut(s.user.id,i);P(t.access),z(t.products),await _(),W(await ft())}catch(t){p(b(t))}finally{J(!1)}},[i,_,s?.user.id]);c.useEffect(()=>{H()},[H]);const g=c.useMemo(()=>{if(!m)return[];const t=j.find(r=>r.product_key===i);return t?m.canViewAllProducts||m.accessibleProductIds.includes(t.id)?[t]:[]:[]},[m,i,j]),D=g[0]?.id||"",q=c.useMemo(()=>{const t=new Map(j.map(l=>[l.id,l.product_key]));return[...L.filter(l=>o.type!=="all"&&l.post_type!==o.type||!D||l.product_id!==D||o.status==="needs-response"&&!["open","needs-info"].includes(l.status)||o.status!=="all"&&o.status!=="needs-response"&&l.status!==o.status||o.visibility!=="all"&&l.visibility!==o.visibility?!1:t.has(l.product_id))].sort((l,w)=>o.sort==="votes"?w.vote_count-l.vote_count||w.updated_at.localeCompare(l.updated_at):o.sort==="newest"?w.created_at.localeCompare(l.created_at):Number(w.is_pinned)-Number(l.is_pinned)||w.updated_at.localeCompare(l.updated_at))},[L,j,o.sort,o.status,o.type,o.visibility,D]),a=q.find(t=>t.id===k)||q[0]||null,E=!!(a&&m&&(m.canViewAllProducts||m.managedProductIds.includes(a.product_id))),$e=!!(a&&s?.user.id===a.author_id)||E;c.useEffect(()=>{if(!a){x(""),U([]),B(!1);return}a.id!==k&&x(a.id)},[a,k]),c.useEffect(()=>{let t=!0;return k?(ge(k).then(r=>{t&&U(r)}).catch(r=>{t&&p(b(r))}),mt(k).then(r=>{t&&ie(r)}).catch(r=>{t&&p(b(r))}),()=>{t=!1}):(U([]),ie([]),()=>{t=!1})},[k]),c.useEffect(()=>{!h.productId&&g[0]&&A(t=>({...t,productId:D||g[0].id}))},[g,h.productId,D]),c.useEffect(()=>{K(o.query)},[o.query]),c.useEffect(()=>{!pe&&g[0]&&Ee(g[0].id),!ue&&g[0]&&Le(g[0].id)},[g,pe,ue]);const C=t=>{a&&S(r=>r.map(l=>l.id===a.id?{...l,...t}:l))},Me=async t=>{if(t.preventDefault(),!(!s||!h.productId)){f("create"),p("");try{const r=await bt({productId:h.productId,postType:h.postType,title:h.title,body:h.body,visibility:h.postType==="announcement"?"public":h.visibility,appVersion:n,includeEnvironment:h.postType==="issue"&&h.includeEnvironment});for(const w of Y)await vt(r,w);const l=await _();O(!1),fe([]),A(w=>({...w,title:"",body:"",files:[]})),x(r),l.some(w=>w.id===r)||await H()}catch(r){p(b(r))}finally{f("")}}},Oe=async t=>{if(t.preventDefault(),!!a){f("edit"),p("");try{await _t(a.id,a.title,a.body,a.visibility),B(!1),await _()}catch(r){p(b(r))}finally{f("")}}},Be=async t=>{if(t.preventDefault(),!(!a||!F.trim())){f("comment"),p("");try{await gt(a.id,F),ce(""),U(await ge(a.id)),await _()}catch(r){p(b(r))}finally{f("")}}},Fe=async()=>{if(!(!a||a.post_type!=="feature")){f("vote"),p("");try{const t=await wt(a.id);re(r=>{const l=new Set(r);return t.voted?l.add(a.id):l.delete(a.id),l}),C({vote_count:t.totalVotes})}catch(t){p(b(t))}finally{f("")}}},Ye=async t=>{if(a){f("status"),p("");try{await St(a.id,t),C({status:t}),await _()}catch(r){p(b(r))}finally{f("")}}},He=async()=>{if(!(!a||!window.confirm("Hide this Support post from the board?"))){f("hide"),p("");try{await Nt(a.id),x(""),await _()}catch(t){p(b(t))}finally{f("")}}},Qe=async()=>{if(a){f("lock"),p("");try{await Pt(a.id,!a.is_locked),C({is_locked:!a.is_locked}),await _()}catch(t){p(b(t))}finally{f("")}}},Ge=async()=>{if(a){f("pin"),p("");try{await kt(a.id,!a.is_pinned),C({is_pinned:!a.is_pinned}),await _()}catch(t){p(b(t))}finally{f("")}}},We=async t=>{if(a){f(`accept-${t}`),p("");try{await At(a.id,t),C({accepted_comment_id:t,status:a.post_type==="question"?"answered":a.status}),await _()}catch(r){p(b(r))}finally{f("")}}},Ze=async()=>{if(!(!a||!I||I===a.id)){f("duplicate"),p("");try{await Ct(a.id,I),x(""),he(""),await _()}catch(t){p(b(t))}finally{f("")}}},Je=async t=>{if(!t.read_at)try{await xt(t.id),W(r=>r.map(l=>l.id===t.id?{...l,read_at:new Date().toISOString()}:l))}catch(r){p(b(r))}t.post_id&&x(t.post_id),de(!1)};return s?Z&&!m?e.jsxs("section",{className:"support-page support-loading",children:[e.jsx(xe,{className:"support-spin",size:23})," Loading Support Board..."]}):e.jsxs("section",{className:"support-page",children:[e.jsx("header",{className:"support-page-header support-page-actions-only",children:e.jsxs("div",{className:"support-header-actions",children:[e.jsxs("div",{className:"support-notification-wrap",children:[e.jsxs("button",{className:"support-secondary-button",type:"button",onClick:()=>de(t=>!t),title:"Notifications",children:[e.jsx(Ke,{size:16})," ",M.filter(t=>!t.read_at).length>0&&e.jsx("b",{children:M.filter(t=>!t.read_at).length})]}),ke&&e.jsxs("div",{className:"support-notification-popover",children:[e.jsx("strong",{children:"Notifications"}),M.length===0?e.jsx("span",{className:"support-muted",children:"No notifications yet."}):M.map(t=>e.jsxs("button",{type:"button",className:t.read_at?"":"unread",onClick:()=>{Je(t)},children:[e.jsx("b",{children:t.title}),e.jsx("span",{children:t.body}),e.jsx("small",{children:G(t.created_at)})]},t.id))]})]}),m?.canViewAllProducts&&e.jsxs("button",{className:"support-secondary-button",type:"button",onClick:()=>Ae(t=>!t),children:[e.jsx(T,{size:16})," Admin"]}),e.jsxs("button",{className:"support-secondary-button",type:"button",onClick:()=>{H()},disabled:Z,children:[e.jsx(xe,{size:16,className:Z?"support-spin":""})," Refresh"]}),e.jsxs("button",{className:"support-primary-button",type:"button",onClick:()=>O(!0),disabled:g.length===0,children:[e.jsx(ye,{size:17})," New request"]})]})}),oe&&e.jsxs("div",{className:"support-error",role:"alert",children:[e.jsx(Q,{size:17})," ",e.jsx("span",{children:oe}),e.jsx("button",{type:"button",onClick:()=>p(""),"aria-label":"Dismiss error",children:e.jsx(Q,{size:15})})]}),Ne&&e.jsxs("form",{className:"support-composer",onSubmit:t=>{Me(t)},children:[e.jsxs("div",{className:"support-section-heading",children:[e.jsxs("div",{children:[e.jsx("span",{children:"New Support request"}),e.jsx("strong",{children:"Describe one actionable problem or idea."})]}),e.jsx("button",{className:"support-icon-button",type:"button",onClick:()=>O(!1),"aria-label":"Close composer",children:e.jsx(Q,{size:18})})]}),e.jsxs("div",{className:"support-form-grid",children:[e.jsxs("label",{children:[e.jsx("span",{children:"Type"}),e.jsx("select",{value:h.postType,onChange:t=>A(r=>({...r,postType:t.target.value})),children:ae.filter(t=>t.id!=="announcement"||m?.canCreateAnnouncements).map(t=>e.jsx("option",{value:t.id,children:t.label},t.id))})]}),e.jsxs("label",{className:"support-form-wide",children:[e.jsx("span",{children:"Title"}),e.jsx("input",{required:!0,minLength:3,maxLength:180,value:h.title,onChange:t=>A(r=>({...r,title:t.target.value})),placeholder:"A short, searchable summary"})]}),e.jsxs("label",{className:"support-form-wide",children:[e.jsx("span",{children:h.postType==="issue"?"What happened?":h.postType==="feature"?"Describe the desired behavior":h.postType==="announcement"?"Announcement":"Question"}),e.jsx("textarea",{required:!0,value:h.body,onChange:t=>A(r=>({...r,body:t.target.value})),placeholder:"Include the context another person needs to respond.",rows:6})]}),e.jsxs("label",{children:[e.jsx("span",{children:"Visibility"}),e.jsxs("select",{value:h.visibility,disabled:h.postType==="announcement",onChange:t=>A(r=>({...r,visibility:t.target.value})),children:[e.jsx("option",{value:"public",children:"Public"}),e.jsx("option",{value:"private",children:"Private"})]})]}),h.postType==="issue"&&e.jsxs("label",{className:"support-checkbox",children:[e.jsx("input",{type:"checkbox",checked:h.includeEnvironment,onChange:t=>A(r=>({...r,includeEnvironment:t.target.checked}))}),e.jsx("span",{children:"Attach safe browser/runtime details"})]}),e.jsxs("label",{className:"support-form-wide",children:[e.jsx("span",{children:"Attachments"}),e.jsx("input",{type:"file",multiple:!0,accept:"image/png,image/jpeg,image/webp,text/plain,text/markdown,application/json,application/pdf",onChange:t=>fe(Array.from(t.target.files||[]).slice(0,5))}),e.jsx("small",{className:"support-muted",children:"Up to 5 files, 10 MB each. Images, text, JSON, Markdown, and PDF."})]})]}),e.jsxs("div",{className:"support-composer-footer",children:[e.jsx("span",{children:Y.length>0?`${Y.length} attachment${Y.length===1?"":"s"} selected.`:"Private posts are visible only to you and VuvoDesk Support."}),e.jsxs("button",{className:"support-primary-button",type:"submit",disabled:v==="create",children:[e.jsx(be,{size:16})," ",v==="create"?"Submitting...":"Submit request"]})]})]}),e.jsxs("div",{className:"support-tabs",role:"tablist","aria-label":"Support post type",children:[e.jsx("button",{className:o.type==="all"?"active":"",type:"button",onClick:()=>N({type:"all"}),children:"All"}),ae.map(t=>{const r=we(t.id);return e.jsxs("button",{className:o.type===t.id?"active":"",type:"button",onClick:()=>N({type:t.id}),children:[e.jsx(r,{size:15})," ",t.label]},t.id)})]}),Ce&&m?.canViewAllProducts&&e.jsxs("section",{className:"support-admin-panel",children:[e.jsxs("div",{className:"support-section-heading",children:[e.jsxs("div",{children:[e.jsx("span",{children:"VuvoDesk owner controls"}),e.jsx("strong",{children:"Manage VuvoDesk support access and staff roles by email."})]}),e.jsx(T,{size:19})]}),e.jsxs("div",{className:"support-admin-grid",children:[e.jsxs("form",{onSubmit:t=>{},children:[e.jsx("strong",{children:"Grant VuvoDesk access"}),e.jsx("input",{type:"email",required:!0,placeholder:"User email",value:qe,onChange:t=>ze(t.target.value)}),e.jsxs("select",{value:Te,onChange:t=>Ie(t.target.value),children:[e.jsx("option",{value:"free",children:"Free"}),e.jsx("option",{value:"user",children:"User"}),e.jsx("option",{value:"paid",children:"Paid"}),e.jsx("option",{value:"beta",children:"Beta"}),e.jsx("option",{value:"staff",children:"Staff"})]}),e.jsxs("button",{className:"support-secondary-button",type:"submit",disabled:me==="access",children:[e.jsx(ee,{size:15})," Grant access"]})]}),e.jsxs("form",{onSubmit:t=>{},children:[e.jsx("strong",{children:"Assign VuvoDesk staff"}),e.jsx("input",{type:"email",required:!0,placeholder:"Staff email",value:De,onChange:t=>Ve(t.target.value)}),e.jsxs("select",{value:Re,onChange:t=>Ue(t.target.value),children:[e.jsx("option",{value:"admin",children:"Admin"}),e.jsx("option",{value:"support",children:"Support"}),e.jsx("option",{value:"moderator",children:"Moderator"})]}),e.jsxs("button",{className:"support-secondary-button",type:"submit",disabled:me==="product-admin",children:[e.jsx(T,{size:15})," Assign staff"]})]})]})]}),e.jsxs("form",{className:"support-search-bar",onSubmit:t=>{t.preventDefault(),N({query:le.trim()})},children:[e.jsxs("label",{children:[e.jsx("span",{children:"Search Support"}),e.jsx("input",{value:le,onChange:t=>K(t.target.value),placeholder:"Search titles and request details"})]}),e.jsxs("button",{className:"support-secondary-button",type:"submit",children:[e.jsx(je,{size:15})," Search"]}),o.query&&e.jsx("button",{className:"support-icon-button",type:"button",onClick:()=>{K(""),N({query:""})},"aria-label":"Clear search",children:e.jsx(Q,{size:16})})]}),e.jsxs("div",{className:"support-filter-bar",children:[e.jsxs("div",{className:"support-filter-title",children:[e.jsx(je,{size:16}),e.jsx("span",{children:"Filter"})]}),e.jsxs("label",{children:[e.jsx("span",{children:"Status"}),e.jsx("select",{value:o.status,onChange:t=>N({status:t.target.value}),children:zt.map(t=>e.jsx("option",{value:t.id,children:t.label},t.id))})]}),e.jsxs("label",{children:[e.jsx("span",{children:"Visibility"}),e.jsxs("select",{value:o.visibility,onChange:t=>N({visibility:t.target.value}),children:[e.jsx("option",{value:"all",children:"All visibility"}),e.jsx("option",{value:"public",children:"Public"}),e.jsx("option",{value:"private",children:"Private"})]})]}),e.jsxs("label",{children:[e.jsx("span",{children:"Sort"}),e.jsxs("select",{value:o.sort,onChange:t=>N({sort:t.target.value}),children:[e.jsx("option",{value:"recent",children:"Recently updated"}),e.jsx("option",{value:"newest",children:"Newest"}),e.jsx("option",{value:"votes",children:"Most votes"})]})]})]}),m?.canViewAllProducts&&e.jsxs("div",{className:"support-admin-shortcuts",children:[e.jsxs("span",{children:[e.jsx(T,{size:15})," VuvoDesk owner"]}),e.jsx("button",{type:"button",onClick:()=>N({status:"needs-response"}),children:"Needs response"}),e.jsx("button",{type:"button",onClick:()=>N({visibility:"private"}),children:"Private requests"}),e.jsx("button",{type:"button",onClick:()=>N({type:"feature",status:"all",sort:"votes"}),children:"High-vote features"})]}),e.jsxs("div",{className:"support-board-layout",children:[e.jsxs("section",{className:"support-post-list","aria-label":"Support posts",children:[e.jsxs("div",{className:"support-list-heading",children:[e.jsxs("span",{children:[q.length," request",q.length===1?"":"s"]}),e.jsx("small",{children:"VuvoDesk"})]}),q.length===0?e.jsxs("div",{className:"support-list-empty",children:[e.jsx(X,{size:25}),e.jsx("strong",{children:"No posts match these filters."}),e.jsx("span",{children:"Start with a focused question, issue report, or feature request."}),g.length>0&&e.jsxs("button",{className:"support-secondary-button",type:"button",onClick:()=>O(!0),children:[e.jsx(ye,{size:16})," Create the first request"]})]}):q.map(t=>{const r=we(t.post_type);return e.jsxs("button",{type:"button",className:`support-post-row ${t.id===a?.id?"active":""}`,onClick:()=>{x(t.id),B(!1)},children:[e.jsx("span",{className:"support-post-row-icon",children:e.jsx(r,{size:17})}),e.jsxs("span",{className:"support-post-row-copy",children:[e.jsxs("span",{className:"support-post-row-meta",children:[e.jsx("em",{children:Se(t.post_type)}),t.visibility==="private"&&e.jsx(V,{size:13})]}),e.jsx("strong",{children:t.title}),e.jsxs("small",{children:[se(t.status)," · ",G(t.updated_at)," · ",t.comment_count," comments"]})]}),t.post_type==="feature"&&e.jsxs("span",{className:"support-vote-count",children:[e.jsx(Xe,{size:14})," ",t.vote_count]})]},t.id)})]}),e.jsx("section",{className:"support-post-detail","aria-label":"Support post detail",children:a?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"support-detail-head",children:[e.jsxs("div",{className:"support-detail-badges",children:[e.jsx("span",{className:"support-type-badge",children:Se(a.post_type)}),e.jsx("span",{className:`support-status-badge status-${a.status}`,children:se(a.status)}),a.visibility==="private"&&e.jsxs("span",{className:"support-private-badge",children:[e.jsx(V,{size:13})," Private"]})]}),e.jsxs("div",{className:"support-detail-actions",children:[$e&&e.jsx("button",{className:"support-icon-button",type:"button",onClick:()=>B(t=>!t),title:"Edit post",children:e.jsx(et,{size:16})}),E&&e.jsxs(e.Fragment,{children:[e.jsx("button",{className:"support-icon-button",type:"button",onClick:()=>{Ge()},disabled:v==="pin",title:a.is_pinned?"Unpin post":"Pin post",children:e.jsx(ve,{size:16})}),e.jsx("button",{className:"support-icon-button",type:"button",onClick:()=>{Qe()},disabled:v==="lock",title:a.is_locked?"Unlock post":"Lock post",children:e.jsx(V,{size:16})}),e.jsx("button",{className:"support-icon-button danger",type:"button",onClick:()=>{He()},disabled:v==="hide",title:"Hide post",children:e.jsx(_e,{size:16})})]})]})]}),Pe?e.jsxs("form",{className:"support-edit-form",onSubmit:t=>{Oe(t)},children:[e.jsx("input",{value:a.title,onChange:t=>C({title:t.target.value}),minLength:3,maxLength:180,required:!0}),e.jsx("textarea",{value:a.body,onChange:t=>C({body:t.target.value}),rows:9,required:!0}),e.jsxs("div",{className:"support-edit-actions",children:[e.jsxs("select",{value:a.visibility,onChange:t=>C({visibility:t.target.value}),children:[e.jsx("option",{value:"public",children:"Public"}),e.jsx("option",{value:"private",children:"Private"})]}),e.jsxs("button",{className:"support-primary-button",type:"submit",disabled:v==="edit",children:[e.jsx(ee,{size:16})," Save changes"]})]})]}):e.jsxs(e.Fragment,{children:[e.jsx("h3",{children:a.title}),e.jsx("div",{className:"support-detail-body",children:a.body.split(`
2
- `).map((t,r)=>e.jsx("p",{children:t||" "},`${a.id}-body-${r}`))})]}),e.jsxs("div",{className:"support-detail-meta",children:[e.jsxs("span",{children:["Opened ",G(a.created_at)]}),a.app_version&&e.jsxs("span",{children:["Version ",a.app_version]}),a.platform&&e.jsx("span",{children:a.platform}),a.is_locked&&e.jsxs("span",{children:[e.jsx(V,{size:13})," Locked"]}),a.is_pinned&&e.jsxs("span",{children:[e.jsx(ve,{size:13})," Pinned"]})]}),e.jsxs("div",{className:"support-detail-controls",children:[a.post_type==="feature"&&e.jsxs("button",{className:`support-vote-button ${ne.has(a.id)?"voted":""}`,type:"button",onClick:()=>{Fe()},disabled:v==="vote",children:[e.jsx(tt,{size:16})," ",ne.has(a.id)?"Voted":"Vote"," ",e.jsx("b",{children:a.vote_count})]}),E&&e.jsxs("label",{className:"support-status-control",children:[e.jsx("span",{children:"Change status"}),e.jsx("select",{value:a.status,onChange:t=>{Ye(t.target.value)},disabled:v==="status",children:(Et[a.post_type]||[]).map(t=>e.jsx("option",{value:t,children:se(t)},t))})]}),E&&e.jsxs(e.Fragment,{children:[e.jsxs("select",{className:"support-status-control",value:I,onChange:t=>he(t.target.value),children:[e.jsx("option",{value:"",children:"Duplicate of..."}),q.filter(t=>t.id!==a.id&&t.product_id===a.product_id).map(t=>e.jsx("option",{value:t.id,children:t.title.slice(0,55)},t.id))]}),e.jsx("button",{className:"support-secondary-button",type:"button",onClick:()=>{Ze()},disabled:!I||v==="duplicate",children:"Merge duplicate"})]})]}),$.length>0&&e.jsxs("div",{className:"support-attachments",children:[e.jsx("div",{className:"support-section-heading",children:e.jsxs("div",{children:[e.jsx("span",{children:"Attachments"}),e.jsxs("strong",{children:[$.length," file",$.length===1?"":"s"]})]})}),$.map(t=>e.jsxs("a",{href:t.signed_url,target:"_blank",rel:"noreferrer",children:[e.jsx(st,{size:14})," ",t.file_name,e.jsxs("small",{children:[Math.ceil(t.size_bytes/1024)," KB"]})]},t.id))]}),e.jsxs("div",{className:"support-comments",children:[e.jsxs("div",{className:"support-section-heading",children:[e.jsxs("div",{children:[e.jsx("span",{children:"Discussion"}),e.jsxs("strong",{children:[R.length," comment",R.length===1?"":"s"]})]}),a.is_locked&&e.jsxs("span",{className:"support-locked-label",children:[e.jsx(V,{size:14})," Locked"]})]}),R.length===0?e.jsx("p",{className:"support-muted",children:"No response yet. Keep the conversation focused on this request."}):e.jsx("div",{className:"support-comment-list",children:R.map(t=>e.jsxs("article",{className:`support-comment ${t.is_staff_answer?"staff":""} ${a.accepted_comment_id===t.id?"accepted":""}`,children:[e.jsxs("div",{className:"support-comment-head",children:[e.jsx("strong",{children:t.is_staff_answer?"VuvoDesk Support":t.author_id===s.user.id?"You":"Support user"}),t.is_staff_answer&&e.jsxs("span",{children:[e.jsx(T,{size:13})," Staff answer"]}),a.accepted_comment_id===t.id&&e.jsxs("span",{children:[e.jsx(at,{size:13})," Accepted"]}),e.jsx("time",{children:G(t.created_at)})]}),e.jsx("p",{children:t.body}),e.jsxs("div",{className:"support-comment-actions",children:[(s.user.id===a.author_id||E)&&a.post_type==="question"&&a.accepted_comment_id!==t.id&&e.jsxs("button",{className:"support-secondary-button",type:"button",onClick:()=>{We(t.id)},disabled:v===`accept-${t.id}`,children:[e.jsx(ee,{size:14})," Accept answer"]}),E&&e.jsx("button",{className:"support-icon-button danger",type:"button",onClick:()=>{qt(t.id)},title:"Hide comment",children:e.jsx(_e,{size:14})})]})]},t.id))}),!a.is_locked&&e.jsxs("form",{className:"support-comment-form",onSubmit:t=>{Be(t)},children:[e.jsx("textarea",{value:F,onChange:t=>ce(t.target.value),placeholder:"Add a focused reply...",rows:3}),e.jsxs("button",{className:"support-primary-button",type:"submit",disabled:v==="comment"||!F.trim(),children:[e.jsx(be,{size:15})," Reply"]})]})]})]}):e.jsxs("div",{className:"support-detail-empty",children:[e.jsx(X,{size:28}),e.jsx("strong",{children:"Select a Support request"}),e.jsx("span",{children:"Its discussion and staff actions will appear here."})]})})]})]}):e.jsx("section",{className:"support-page support-auth-page",children:e.jsxs("div",{className:"support-empty-hero",children:[e.jsx("span",{className:"support-hero-icon",children:e.jsx(X,{size:28})}),e.jsx("p",{className:"support-eyebrow",children:"VuvoDesk Support"}),e.jsx("h2",{children:"Get help, report issues, and shape the product."}),e.jsx("p",{children:"Sign in to view VuvoDesk support and submit a private or public request."}),e.jsxs("button",{className:"support-primary-button",type:"button",onClick:d,children:[e.jsx(T,{size:17})," Sign in with Google"]})]})})}export{Bt as SupportPage};
@@ -1 +0,0 @@
1
- import{j as e,M as qe,w as Ye,i as Qe,D as te,e as Ze,h as et}from"./styles-Ba1tPFHg.js";import{a as r,g as ne,c as ce,aa as tt,ab as nt,ac as st,ad as De,ae as Ie,X as Se,k as $e,af as it,b as Fe,w as rt,ag as ke,ah as at,ai as ot,O as Ne,W as ct,aj as lt,ak as ut,a2 as dt,J as ht,al as mt}from"./icons-CacEbnZu.js";import{SupportPage as ft}from"./SupportPage-D241Vkb1.js";import{s as V,g as Ce,n as pt,r as gt,a as Ee,b as bt,f as Te,A as wt,H as vt}from"./App-DK9GZcvU.js";import{DesktopUpdatePanel as xt}from"./DesktopUpdatePanel-uMaTnBsl.js";import"./react-Cfedt3N5.js";import"./supabase-C7qjtLN3.js";import"./frame-lifecycle-esOdP-EY.js";function yt(i=[]){return[...new Set(i.filter(t=>typeof t=="string").map(t=>t.trim()).filter(Boolean))]}function jt(i=[],t=new Set){return i.find(c=>!t.has(c))||""}function St(i=[],t=new Set){const c=new Set(i);return new Set([...t].filter(o=>c.has(o)))}const kt="client-runtime-connection-unavailable",Nt="VuvoDesk Client is reconnecting to the service on this computer.",Ct=/failed to fetch|fetch failed|network request failed|networkerror when attempting to fetch resource|load failed|signal timed out|operation was aborted due to timeout|the operation timed out/i;function Oe(i,t){if(!i||typeof i!="object")return"";const c=i[t];return typeof c=="string"?c.trim():""}function le(i){return typeof i=="string"?i.trim():Oe(i,"message")||String(i??"").trim()}function Re(i){return/supabase-user-verification-failed:(401|403)/i.test(i)?"Saved sign-in needs refresh. VuvoDesk will retry it automatically.":i}function Ae(i){const t=le(i)||"Client status could not be refreshed.",c=Oe(i,"name").toLowerCase();return c==="timeouterror"||c==="aborterror"||Ct.test(t)?{key:kt,message:Nt}:{key:`client-status-poll:${t}`,message:t}}function Et({actionError:i="",discoveryWakeError:t=null,statusPollError:c=null,runtimeError:o=""}={}){const u=le(i);if(u)return{key:`client-action:${u}`,message:Re(u)};if(t?.key&&t?.message)return t;if(c?.key&&c?.message)return c;const p=le(o);return p?{key:`client-runtime:${p}`,message:Re(p)}:null}function Tt(i,t){if(!t?.message)return{nextKey:"",message:null};const c=String(t.key||t.message).trim();return String(i||"")===c?{nextKey:c,message:null}:{nextKey:c,message:t.message}}const Rt=[{id:"docs",label:"Doc",icon:tt},{id:"support",label:"Support",icon:nt},{id:"pricing",label:"Pricing",icon:st},{id:"settings",label:"Settings",icon:De}],Pe=[0,1e3,2e3,5e3,1e4,2e4,3e4],At=15e3;function Pt(i=""){const t=i.trim().replace(/\/+$/,"");return t||(typeof window>"u"?"":window.location.port==="5179"?window.location.origin:"http://127.0.0.1:5179")}async function H(i,t=!1){const c=t?"":sessionStorage.getItem("livedesk.client.csrf");if(c)return c;const o=await fetch(`${i}/api/runtime/status`,{cache:"no-store"}),u=await o.json().catch(()=>({}));if(!o.ok)throw new Error(u.error||`Client runtime returned HTTP ${o.status}.`);const p=String(u.csrfToken||"");return p&&sessionStorage.setItem("livedesk.client.csrf",p),p}function ue(i){return`${Math.max(0,Math.min(100,Number(i||0))).toFixed(0)}%`}function oe(i){return Number.isFinite(i)?`${Math.max(0,Math.min(100,Number(i))).toFixed(0)}%`:"—"}function Me(i){return Number.isFinite(i)?ue(Number(i)):"0%"}function U(i){const t=Number(i);return!Number.isFinite(t)||t<0?"—":t>=1024**4?`${(t/1024**4).toFixed(t>=10*1024**4?0:1)} TB`:t>=1024**3?`${(t/1024**3).toFixed(t>=10*1024**3?0:1)} GB`:`${(t/1024**2).toFixed(0)} MB`}function Le(i){const t=Math.max(0,Number(i||0));return t>=1024**3?`${(t/1024**3).toFixed(1)} GB/s`:t>=1024**2?`${(t/1024**2).toFixed(1)} MB/s`:t>=1024?`${(t/1024).toFixed(1)} KB/s`:`${t.toFixed(0)} B/s`}function Lt(i,t){const c=Number(i||0)/1073741824,o=Number(t||0)/1024**3;return o>0?`${c.toFixed(1)} / ${o.toFixed(1)} GB`:"Checking..."}function Dt(i,t){return!Number.isFinite(t)||Number(t)<=0?"Dedicated memory unavailable":Number.isFinite(i)?`${U(i)} / ${U(t)}`:`${U(t)} available`}function It(i){const t=Math.max(0,Math.floor(Number(i||0)/60)),c=Math.floor(t/1440),o=Math.floor(t%1440/60),u=t%60;return c>0?`${c}d ${o}h`:o>0?`${o}h ${u}m`:`${u}m`}function ee({icon:i,label:t,value:c,detail:o,percent:u}){return e.jsxs("article",{className:"client-resource-metric",children:[e.jsxs("div",{className:"client-resource-metric-head",children:[e.jsx(i,{size:17}),e.jsx("span",{children:t}),e.jsx("strong",{children:c})]}),e.jsx("small",{title:o,children:o}),e.jsx("i",{"aria-hidden":"true",children:e.jsx("b",{style:{width:Me(u)}})})]})}function $t(i,t){const c=i?.user.user_metadata||{},o=c.full_name||c.name||c.preferred_username||i?.user.email||i?.user.id||t?.userName||t?.auth?.name||t?.userEmail||t?.userId||"Account";return String(o).trim()||"Account"}function Ft(i,t){const c=i?.user.user_metadata||{};return yt([c.avatar_url,c.picture,t?.userAvatarUrl,t?.auth?.avatarUrl])}function Ot({page:i,status:t}){const o={docs:{label:"DOC",title:"Using this computer",body:"This computer connects to its assigned Hub automatically. Keep VuvoDesk running and manage screens, files, and remote control from the Hub."},pricing:{label:"PRICING",title:"VuvoDesk plans",body:"Plans are based on how many computers the Hub manages. This Client computer does not need a separate subscription or setup."},settings:{label:"SETTINGS",title:"Computer preferences",body:"VuvoDesk keeps the verified sign-in on this computer and reconnects to the assigned Hub automatically."}}[i];return e.jsxs("section",{className:"client-service-page",children:[e.jsx("span",{className:"client-unified-section-label",children:o.label}),e.jsx("h2",{children:o.title}),e.jsx("p",{children:o.body}),e.jsxs("div",{className:"client-service-page-card",children:[i==="docs"&&e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"Automatic connection"}),e.jsx("span",{children:"Start VuvoDesk. This computer signs in, finds the Hub, and becomes available without another action."})]}),i==="pricing"&&e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"One plan, managed at the Hub"}),e.jsx("span",{children:"Computer access follows the account and plan used by the Hub."})]}),i==="settings"&&e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"Saved sign-in"}),e.jsx("span",{children:t?.auth?.persisted?"Enabled on this computer":"Sign in once to enable automatic reconnection"})]})]}),i==="settings"&&e.jsx(xt,{})]})}function Mt({session:i,status:t,pin:c,roleChangeMessage:o,videoAccelerationBusy:u,slotInput:p,slotBusy:v,onSignIn:R,onPinChange:_,onSubmitPin:C,onSlotInputChange:d,onSaveSlot:A,onEnableVideoAcceleration:k}){const j=t?.connectionState==="connected",g=t?.videoAcceleration,$=u||g?.busy||g?.state==="installing",b=g?.ready?`${g.encoder||"H.264"} · ${g.driver||"VAAPI"}`:$?"Setting up…":g?.message||"Setup available",y=t?.system?.memoryTotalBytes?Number(t.system.memoryUsedBytes||0)/t.system.memoryTotalBytes*100:0,P=t?.system?.gpus||[],w=P.find(h=>Number.isFinite(h.usagePercent)||Number.isFinite(h.memoryTotalBytes))||P[0],z=Number.isFinite(w?.usagePercent)?Number(w?.usagePercent):null,G=Number.isFinite(w?.memoryTotalBytes)&&Number(w?.memoryTotalBytes)>0&&Number.isFinite(w?.memoryUsedBytes)?Number(w?.memoryUsedBytes)/Number(w?.memoryTotalBytes)*100:null,E=t?.system?.disks||[],T=t?.system?.network,B=!!T?.sampledAt,N=T?.interfaces||[],S=[...new Set(N.map(h=>h.name).filter(Boolean))],L=N.map(h=>h.address).filter(Boolean);return e.jsxs("section",{className:"client-home-page",children:[e.jsxs("header",{className:"client-home-heading",children:[e.jsxs("div",{children:[e.jsx("p",{className:"client-unified-eyebrow",children:"THIS COMPUTER"}),e.jsx("h2",{children:t?.deviceName||"This Computer"})]}),e.jsxs("span",{className:`client-unified-role-chip ${j?"connected":""}`,children:[e.jsx(ce,{size:15})," ",j?"Online":"Connecting"]})]}),e.jsxs("div",{className:"client-home-layout",children:[e.jsxs("section",{className:"client-main-surface","aria-label":"Client computer",children:[e.jsxs("div",{className:"client-main-surface-head",children:[e.jsxs("div",{children:[e.jsx("span",{className:"client-unified-section-label",children:"SYSTEM STATUS"}),e.jsx("strong",{children:"Hardware at a glance"})]}),e.jsxs("small",{children:[e.jsx(rt,{size:14})," Uptime ",It(t?.system?.uptimeSeconds)]})]}),e.jsxs("div",{className:"client-system-dashboard",children:[e.jsxs("section",{className:"client-performance-panel","aria-label":"Performance",children:[e.jsxs("div",{className:"client-system-subhead",children:[e.jsxs("div",{children:[e.jsx("span",{className:"client-unified-section-label",children:"PERFORMANCE"}),e.jsx("strong",{children:"Live resources"})]}),e.jsx("small",{children:"Live updates"})]}),e.jsxs("div",{className:"client-live-metrics",children:[e.jsx(ee,{icon:ke,label:"CPU",value:ue(t?.system?.cpuUsagePercent),detail:t?.system?.cpuLogicalCores?`${t.system.cpuLogicalCores} logical cores · Current processor usage`:"Current processor usage",percent:t?.system?.cpuUsagePercent}),e.jsx(ee,{icon:at,label:"Memory",value:ue(y),detail:Lt(t?.system?.memoryUsedBytes,t?.system?.memoryTotalBytes),percent:y}),e.jsx(ee,{icon:ot,label:"GPU",value:oe(z),detail:w?.name||(t?.system?.hardwareCollecting?"Detecting graphics hardware…":"Graphics usage unavailable"),percent:z}),e.jsx(ee,{icon:ne,label:"VRAM",value:oe(G),detail:Dt(w?.memoryUsedBytes,w?.memoryTotalBytes),percent:G})]})]}),e.jsxs("section",{className:"client-storage-panel","aria-label":"Local storage",children:[e.jsxs("div",{className:"client-system-subhead",children:[e.jsxs("div",{children:[e.jsx("span",{className:"client-unified-section-label",children:"STORAGE"}),e.jsx("strong",{children:"Local drives"})]}),e.jsx("small",{children:E.length>0?`${E.length} ${E.length===1?"drive":"drives"}`:t?.system?.hardwareCollecting?"Detecting…":"Unavailable"})]}),e.jsxs("div",{className:"client-disk-list",children:[E.map(h=>e.jsxs("article",{className:"client-disk-row",children:[e.jsxs("div",{className:"client-disk-row-head",children:[e.jsxs("span",{children:[e.jsx(Ne,{size:16}),e.jsx("strong",{children:h.mount||"Disk"}),e.jsx("small",{children:h.name||"Local disk"})]}),e.jsx("strong",{children:oe(h.usedPercent)})]}),e.jsxs("small",{children:[U(h.freeBytes)," free · ",U(h.totalBytes)," total"]}),e.jsx("i",{"aria-hidden":"true",children:e.jsx("b",{style:{width:Me(h.usedPercent)}})})]},`${h.mount}-${h.name||""}`)),E.length===0&&e.jsxs("div",{className:"client-disk-empty",children:[e.jsx(Ne,{size:18}),e.jsx("span",{children:t?.system?.hardwareCollecting?"Detecting local drives…":"Storage information is not available."})]})]})]}),e.jsxs("section",{className:"client-network-panel","aria-label":"Network activity",children:[e.jsxs("div",{className:"client-system-subhead",children:[e.jsxs("div",{children:[e.jsx("span",{className:"client-unified-section-label",children:"NETWORK"}),e.jsx("strong",{children:"Live traffic"})]}),e.jsx("small",{children:S.length>0?S.join(", "):"Detecting adapter"})]}),e.jsxs("div",{className:"client-network-live",children:[e.jsxs("div",{className:"client-network-adapter",children:[e.jsx(ct,{size:18}),e.jsxs("span",{children:[e.jsx("strong",{children:S.join(", ")||"Network"}),e.jsx("small",{children:L.join(" / ")||"Checking active connection"})]})]}),e.jsxs("div",{className:"client-network-rate download",children:[e.jsx(lt,{size:17}),e.jsxs("span",{children:[e.jsx("small",{children:"Receive"}),e.jsx("strong",{children:Le(B?T?.receiveBytesPerSecond:void 0)})]})]}),e.jsxs("div",{className:"client-network-rate upload",children:[e.jsx(ut,{size:17}),e.jsxs("span",{children:[e.jsx("small",{children:"Send"}),e.jsx("strong",{children:Le(B?T?.sendBytesPerSecond:void 0)})]})]}),e.jsx("small",{className:"client-network-total",children:B?`Total ${U(T?.receivedBytes)} received / ${U(T?.sentBytes)} sent`:"Traffic has not been measured yet."})]})]})]})]}),e.jsxs("aside",{className:"client-connection-panel",children:[e.jsx("span",{className:"client-unified-section-label",children:"LIVEDESK SERVICES"}),e.jsx("h3",{children:j?"Connected to the Hub":t?.authenticated?"Finding the Hub":"Connect this computer"}),j?e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"client-unified-copy",children:"This computer is available from the VuvoDesk Hub."}),e.jsxs("div",{className:"client-service-status-list",children:[e.jsxs("div",{children:[e.jsx(ce,{size:17}),e.jsxs("span",{children:[e.jsx("strong",{children:"Screen sharing"}),e.jsx("small",{children:t?.permissions?.screenCapture?"Active":"Waiting"})]})]}),e.jsxs("div",{children:[e.jsx($e,{size:17}),e.jsxs("span",{children:[e.jsx("strong",{children:"Remote control"}),e.jsx("small",{children:t?.permissions?.remoteInput?"Available":"Unavailable"})]})]}),e.jsxs("div",{children:[e.jsx(dt,{size:17}),e.jsxs("span",{children:[e.jsx("strong",{children:"File delivery"}),e.jsx("small",{children:t?.permissions?.files?"Ready to receive":"Unavailable"})]})]}),e.jsxs("div",{children:[e.jsx(ht,{size:17}),e.jsxs("span",{children:[e.jsx("strong",{children:"Computer audio"}),e.jsx("small",{children:t?.permissions?.audio?"Available":"Unavailable"})]})]})]})]}):e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"client-unified-copy",children:t?.authenticated?"VuvoDesk is checking the registered Hub endpoints. A temporary Hub PIN can be used as a fallback.":"Sign in once on this computer. VuvoDesk saves the verified session, finds the Hub, and starts screen sharing automatically."}),!i&&!t?.authenticated?e.jsxs("button",{className:"client-unified-primary",type:"button",onClick:R,children:[e.jsx(Ie,{size:16})," Sign in with Google"]}):e.jsxs("p",{className:"client-unified-success",children:[e.jsx(Fe,{size:16})," Signed in as ",i?.user.email||i?.user.id||t?.userEmail||t?.userId||"saved account"]}),e.jsxs("div",{className:"client-unified-pin-row",children:[e.jsx(mt,{size:16}),e.jsx("input",{value:c,onChange:h=>_(h.target.value),placeholder:"6-digit Hub PIN",inputMode:"numeric","aria-label":"6-digit Hub PIN"}),e.jsx("button",{className:"client-unified-secondary",type:"button",onClick:C,disabled:c.length!==6,children:"Connect"})]})]}),g?.supported&&e.jsxs("div",{className:`client-video-acceleration state-${g.ready?"ready":g.state||"setup-required"}`,children:[e.jsx(ke,{size:17}),e.jsxs("span",{children:[e.jsx("strong",{children:"Hardware video"}),e.jsx("small",{children:b})]}),!g.ready&&g.canInstall&&e.jsx("button",{type:"button",onClick:k,disabled:$,title:"Install and verify Linux FFmpeg hardware video support",children:$?"Setting up":"Enable"})]}),o&&e.jsx("p",{className:"client-unified-success",children:o}),e.jsxs("div",{className:"client-slot-setting",children:[e.jsxs("label",{htmlFor:"client-slot-number",children:[e.jsx("span",{children:"Slot"}),e.jsx("input",{id:"client-slot-number",value:p,onChange:h=>d(h.target.value),inputMode:"numeric",pattern:"[0-9]*",placeholder:"1-999","aria-label":"Wall slot number",disabled:!j||v})]}),e.jsxs("button",{type:"button",onClick:A,disabled:!j||v||!p,"aria-label":"Save slot number",title:"Save slot number",children:[e.jsx(De,{size:17}),e.jsx("span",{children:v?"Saving":"Set"})]})]})]})]})]})}function Ht({runtimeBaseUrl:i=""}){const[t,c]=r.useState(null),[o,u]=r.useState(null),[p,v]=r.useState(!1),[R,_]=r.useState(""),[C,d]=r.useState(""),[A,k]=r.useState(null),[j,g]=r.useState(null),[$,b]=r.useState(""),[y,P]=r.useState(!1),[w,z]=r.useState(!1),[G,E]=r.useState(""),[T,B]=r.useState(!1),[N,S]=r.useState(null),[L,h]=r.useState(!1),[D,de]=r.useState("computer"),[he,q]=r.useState(!1),me=r.useRef(null),fe=r.useRef(null),se=r.useRef(!1),Y=r.useRef(null),Q=r.useRef(null),pe=r.useRef(!1),W=r.useRef(!1),ge=r.useRef(0),ie=r.useRef(!1),be=r.useRef(""),m=r.useMemo(()=>Pt(i),[i]),re=r.useMemo(()=>$t(o,t),[o,t]),ae=r.useMemo(()=>Ft(o,t),[o,t]),He=JSON.stringify(ae),[Ue,we]=r.useState(()=>new Set),K=jt(ae,Ue),ve=re.slice(0,1).toUpperCase()||"L";r.useEffect(()=>{we(n=>St(ae,n))},[He]);const _e=r.useCallback(n=>{we(s=>{if(!n||s.has(n))return s;const a=new Set(s);return a.add(n),a})},[]),F=r.useCallback(async()=>{if(d(""),window.liveDesk?.auth?.signInWithGoogle){const n=await window.liveDesk.auth.signInWithGoogle();return n?.ok===!1?(d(n.error||"VuvoDesk could not open the system browser for Google sign-in."),!1):!0}return window.location.assign(`${m}/auth/google`),!0},[m]),xe=r.useCallback(async()=>{W.current||(W.current=!0,d("Your saved Google sign-in is incomplete. VuvoDesk is reopening sign-in once to repair it."),await V.auth.signOut({scope:"local"}).catch(()=>{}),u(null),await F()||(W.current=!1))},[F]),ye=r.useCallback(async n=>{const s=Ce(n);if(s)throw new Error(s);if(se.current)return!1;se.current=!0;try{if(window.liveDesk?.auth?.persistSession){const a=await window.liveDesk.auth.persistSession(n);if(a?.ok===!1)throw new Error(a.error||"VuvoDesk could not validate the desktop session.");return d(""),!0}for(let a=0;a<2;a+=1){const l=await H(m,a>0),f=await fetch(`${m}/api/auth/session`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":l},signal:AbortSignal.timeout(1e4),body:JSON.stringify({accessToken:n.access_token,refreshToken:n.refresh_token,expiresAt:n.expires_at,user:{id:n.user.id,email:n.user.email}})}),M=await f.json().catch(()=>({}));if(f.status===403&&a===0){sessionStorage.removeItem("livedesk.client.csrf");continue}if(!f.ok)throw new Error(M.error||`Client runtime returned HTTP ${f.status}.`);return d(""),!0}throw new Error("Client runtime rejected the session transfer.")}finally{se.current=!1}},[m]),x=r.useCallback(()=>{const n=Y.current;if(n)return n;const s=(async()=>{try{const a=await fetch(`${m}/api/client/status`,{cache:"no-store",signal:AbortSignal.timeout(1500)}),l=await a.json().catch(()=>({}));if(!a.ok)throw new Error(l.error||`Client runtime returned HTTP ${a.status}.`);if(l.csrfToken&&sessionStorage.setItem("livedesk.client.csrf",l.csrfToken),String(l.role||"").toLowerCase()==="hub")throw new Error("This computer is assigned to the Hub role.");c(l),k(null),g(null)}catch(a){k(Ae(a))}})();return Y.current=s,s.finally(()=>{Y.current===s&&(Y.current=null)}),s},[m]),je=r.useCallback(()=>{const n=Q.current;if(n)return n;const s=(async()=>{const a=await fetch(`${m}/api/client/diagnostics`,{cache:"no-store",signal:AbortSignal.timeout(8e3)}),l=await a.json().catch(()=>({}));if(!a.ok)throw new Error(l.error||`Client diagnostics returned HTTP ${a.status}.`);if(String(l.role||"").toLowerCase()==="hub")throw new Error("This computer is assigned to the Hub role.");c(l)})();return Q.current=s,s.finally(()=>{Q.current===s&&(Q.current=null)}),s},[m]);r.useEffect(()=>{let n=!1,s=null;const a=async()=>{await x(),n||(s=window.setTimeout(()=>{a()},2e3))};return a(),()=>{n=!0,s!==null&&window.clearTimeout(s)}},[x]),r.useEffect(()=>{if(D!=="computer")return;let n=!1,s=null;const a=()=>{n||(s=window.setTimeout(()=>{l()},At))},l=async()=>{document.visibilityState==="visible"&&await je().catch(()=>{}),a()},f=()=>{document.visibilityState==="visible"&&(s!==null&&(window.clearTimeout(s),s=null),l())};return document.addEventListener("visibilitychange",f),l(),()=>{n=!0,document.removeEventListener("visibilitychange",f),s!==null&&window.clearTimeout(s)}},[D,je]),r.useEffect(()=>{if(ie.current)return;const n=Number(t?.slotNumber||0);E(n>0?String(n):"")},[t?.slotNumber]),r.useEffect(()=>{if(!N)return;const n=window.setTimeout(()=>S(null),5e3);return()=>window.clearTimeout(n)},[N]),r.useEffect(()=>{const n=Et({actionError:C,discoveryWakeError:j,statusPollError:A,runtimeError:t?.lastError}),s=Tt(be.current,n);be.current=s.nextKey,s.message&&S({kind:"error",message:s.message})},[j,C,A,t?.lastError]);const Z=r.useCallback(async()=>{const n=Date.now();if(!(!t?.authenticated||t.connectionState==="connected"||!["waiting","reconnecting"].includes(String(t.agent?.state||""))||n-ge.current<4e3)){ge.current=n;try{const s=await fetch(`${m}/api/client/reconnect`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":await H(m)},body:JSON.stringify({onlyIfWaiting:!0,reason:"app-active"})});if(!s.ok)throw new Error(`Client reconnect returned HTTP ${s.status}.`);g(null),await x()}catch(s){g(Ae(s))}}},[m,x,t]);r.useEffect(()=>{const n=()=>{Z()},s=()=>{Z()},a=()=>{document.visibilityState==="visible"&&Z()};return window.addEventListener("online",n),window.addEventListener("focus",s),document.addEventListener("visibilitychange",a),()=>{window.removeEventListener("online",n),window.removeEventListener("focus",s),document.removeEventListener("visibilitychange",a)}},[Z]),r.useEffect(()=>{if(!p||!t||!o?.access_token||t.authenticated)return;if(Ce(o)==="refresh-token-required"){xe().catch(f=>{W.current=!1,d(f instanceof Error?f.message:String(f))});return}let n=!1,s,a=0;const l=async()=>{if(n)return;try{const M=await ye(o);if(await x(),M)return}catch(M){d(M instanceof Error?M.message:String(M))}if(n)return;const f=Pe[Math.min(a,Pe.length-1)];a+=1,s=window.setTimeout(()=>{l()},f)};return l(),()=>{n=!0,s!==void 0&&window.clearTimeout(s)}},[p,x,xe,o,t,ye]),r.useEffect(()=>{const n=new URLSearchParams(window.location.search),s=n.get("auth_error");if(!s)return;d(s),n.delete("auth_error");const a=n.toString();window.history.replaceState(window.history.state,"",`${window.location.pathname}${a?`?${a}`:""}${window.location.hash}`)},[]),r.useEffect(()=>{let n=!0;if(!window.liveDesk?.auth)return u(null),v(!0),x(),()=>{n=!1};const s=window.liveDesk?.auth?.onComplete?.(l=>{l.ok&&l.session?V.auth.setSession(l.session).catch(f=>d(f instanceof Error?f.message:String(f))):l.ok&&l.signedOut?(u(null),v(!0),V.auth.signOut({scope:"local"})):l.error&&d(l.error)});(async()=>{try{const l=window.liveDesk?.auth?.getSession?await window.liveDesk.auth.getSession():await V.auth.getSession();if(!n)return;const f=pt(l);u(f),x()}catch(l){n&&d(l instanceof Error?l.message:String(l))}finally{n&&v(!0)}})();const{data:a}=V.auth.onAuthStateChange((l,f)=>{if(n){if(!f&&window.liveDesk?.auth){v(!0);return}u(f),v(!0),x()}});return()=>{n=!1,s?.(),a.subscription.unsubscribe()}},[x]),r.useEffect(()=>{if(!p||!t||pe.current||W.current||o||t.authenticated)return;const n=new URLSearchParams(window.location.search);if(!n.has("livedesk_launch"))return;pe.current=!0,n.delete("livedesk_launch");const s=n.toString();window.history.replaceState(window.history.state,"",`${window.location.pathname}${s?`?${s}`:""}${window.location.hash}`),F().catch(a=>d(a instanceof Error?a.message:String(a)))},[p,o,F,t]);const Be=async()=>{q(!1),window.liveDesk?.auth?.signOut?(await V.auth.signOut({scope:"local"}),(await window.liveDesk.auth.signOut())?.runtimeCleared===!1&&d("Signed out locally. The VuvoDesk runtime could not be reached to clear its session.")):await fetch(`${m}/api/auth/session`,{method:"DELETE",headers:{"X-LiveDesk-CSRF":await H(m)}}).catch(()=>{}),u(null),await x()},X=r.useCallback((n=!0)=>{y||(h(!1),n&&window.requestAnimationFrame(()=>fe.current?.focus()))},[y]),Ve=r.useCallback(()=>{y||!t?.authenticated||(fe.current=document.activeElement instanceof HTMLElement?document.activeElement:null,b(""),h(!0))},[y,t?.authenticated]);r.useEffect(()=>{if(!L)return;const n=window.requestAnimationFrame(()=>me.current?.focus()),s=l=>{l.target instanceof Element&&l.target.closest(".client-hub-switch-popover, .client-hub-switch-trigger")||X(!1)},a=l=>{l.key==="Escape"&&X()};return window.addEventListener("pointerdown",s),window.addEventListener("keydown",a),()=>{window.cancelAnimationFrame(n),window.removeEventListener("pointerdown",s),window.removeEventListener("keydown",a)}},[X,L]);const ze=async()=>{d("");try{const n=await fetch(`${m}/api/client/pin`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":await H(m)},body:JSON.stringify({pin:R})}),s=await n.json().catch(()=>({}));if(!n.ok||s?.ok===!1)throw new Error(s?.error||"PIN could not be accepted.");_(""),await x()}catch(n){d(n instanceof Error?n.message:String(n))}},Ge=async()=>{h(!1),P(!0),b(""),d("");try{const n=await fetch(`${m}/api/runtime/switch-role`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":await H(m)},body:JSON.stringify({role:"hub"})}),s=await n.json().catch(()=>({}));if(!n.ok||s?.ok===!1)throw new Error(s?.error||`Role change failed with HTTP ${n.status}.`);b("Hub role accepted. VuvoDesk is restarting this computer with the Hub Wall.");const a=Number(t?.runtimePid||0);await Ye({baseUrl:m,targetRole:"hub",previousRuntimePid:a,allowedStates:["running"]}),window.location.reload()}catch(n){d(n instanceof Error?n.message:String(n)),P(!1)}},We=async()=>{if(T)return;const n=Number(G);if(!Number.isInteger(n)||n<1||n>999){S({kind:"error",message:"Enter a slot number from 1 to 999."});return}B(!0),S(null);try{const s=await fetch(`${m}/api/client/slot`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":await H(m)},body:JSON.stringify({slotNumber:n})}),a=await s.json().catch(()=>({}));if(!s.ok||a.ok===!1){if(a.error==="slot-taken"){const l=a.conflict?.deviceName||a.conflict?.hostname||a.conflict?.deviceId||"another computer";throw new Error(`Slot ${String(n).padStart(3,"0")} is already used by ${l}.`)}throw new Error(a.error||`Slot update failed with HTTP ${s.status}.`)}ie.current=!1,E(String(n)),c(a),S({kind:"success",message:`Slot ${String(n).padStart(3,"0")} saved. VuvoDesk is reconnecting this Client.`})}catch(s){S({kind:"error",message:s instanceof Error?s.message:String(s)})}finally{B(!1),await x()}},Ke=async()=>{if(!w){z(!0),d("");try{const n=await fetch(`${m}/api/client/video-acceleration/install`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":await H(m)},body:JSON.stringify({confirm:!0})}),s=await n.json().catch(()=>({}));if(c(s),!n.ok||s.videoAcceleration?.ready!==!0)throw new Error(s.videoAcceleration?.error||s.error||"Linux hardware video setup did not complete.")}catch(n){d(n instanceof Error?n.message:String(n))}finally{z(!1),await x()}}},I=!!(t?.authenticated||o),J=r.useMemo(()=>gt(),[]),Xe=Ee("switch-to-hub",J),Je=Ee("client",J),O=bt(J);return e.jsxs("main",{className:"app-shell client-unified-shell",children:[e.jsxs("aside",{className:"tool-rail","aria-label":"VuvoDesk Client tools",children:[e.jsx("div",{className:"rail-brand",title:"VuvoDesk",children:e.jsx(qe,{size:25})}),e.jsx("nav",{className:"rail-tools","aria-label":"Client navigation",children:e.jsxs("div",{className:"client-main-tool-slot",children:[e.jsxs("button",{className:"rail-tool client-main-tool client-hub-tool client-hub-switch-trigger accent-blue",type:"button",onClick:Ve,disabled:y||!t?.authenticated,"aria-busy":y,"aria-expanded":L,"aria-haspopup":"dialog","aria-controls":L?"client-hub-switch-popover":void 0,"aria-label":`Hub. ${Xe}`,"data-tooltip":L?void 0:Te("Hub","switch-to-hub",J),children:[e.jsx(ne,{size:19}),e.jsx("span",{children:y?"Switching…":"Hub"})]}),e.jsxs("button",{className:`rail-tool client-main-tool accent-blue ${D==="computer"?"active":""}`,type:"button",onClick:()=>de("computer"),"aria-current":D==="computer"?"page":void 0,"aria-label":`Client. ${Je}`,"data-tooltip":Te("Client","client",J),children:[e.jsx(ce,{size:19}),e.jsx("span",{children:"Client"})]})]})}),e.jsxs("div",{className:"rail-footer",children:[Rt.map(n=>{const s=n.icon;return e.jsxs("button",{className:`rail-tool compact ${D===n.id?"active":""}`,type:"button",onClick:()=>de(n.id),title:n.label,children:[e.jsx(s,{size:18}),e.jsx("span",{children:n.label})]},n.id)}),e.jsxs("button",{className:`rail-account ${I?"signed-in":""}`,type:"button",onClick:()=>q(n=>!n),"aria-expanded":he,"aria-haspopup":"dialog","aria-controls":"vuvodesk-account-dialog",title:I?"Account":"Sign in",children:[I&&K?e.jsx("img",{src:K,alt:re,referrerPolicy:"no-referrer",onError:()=>_e(K)},K):I?e.jsx("span",{className:"avatar-fallback",children:ve}):e.jsx(Ie,{size:18}),e.jsx("span",{children:I?"Account":"Sign in"})]})]})]}),L&&e.jsxs("section",{id:"client-hub-switch-popover",className:"client-hub-switch-popover",role:"dialog","aria-modal":"false","aria-labelledby":"client-hub-switch-title","aria-describedby":"client-hub-switch-description client-hub-switch-restart",children:[e.jsxs("header",{className:"client-hub-switch-head",children:[e.jsx("span",{className:"client-hub-switch-mark","aria-hidden":"true",children:e.jsx(ne,{size:19})}),e.jsx("span",{className:"client-hub-switch-eyebrow",children:O.eyebrow}),e.jsx("button",{className:"client-hub-switch-close",type:"button",onClick:()=>X(),"aria-label":O.closeLabel,children:e.jsx(Se,{size:17})})]}),e.jsx("h2",{id:"client-hub-switch-title",children:O.title}),e.jsx("p",{id:"client-hub-switch-description",children:O.description}),e.jsxs("p",{id:"client-hub-switch-restart",className:"client-hub-switch-notice",children:[e.jsx($e,{size:16,"aria-hidden":"true"}),e.jsx("span",{children:O.restartNotice})]}),e.jsxs("div",{className:"client-hub-switch-actions",children:[e.jsx("button",{type:"button",onClick:()=>X(),children:O.cancel}),e.jsxs("button",{ref:me,className:"primary",type:"button",onClick:()=>{Ge()},disabled:y||!t?.authenticated,children:[e.jsx(ne,{size:16}),O.confirm]})]})]}),e.jsx(wt,{open:he,signedIn:I,accountName:I?re:"Account",accountEmail:o?.user.email||t?.userEmail||t?.userId||"",accountInitial:ve,avatarUrl:K,currentPlan:"free",currentPlanKnown:!1,deviceCount:t?1:0,deviceLimit:Number.POSITIVE_INFINITY,licenseLabel:"Plan is managed at the Hub. This Client does not choose or change billing.",networkLabel:t?.connectionState==="connected"?"Connected to Hub":t?"Finding Hub":"Checking local app",accessLabel:t?.auth?.persisted?"Saved sign-in on this computer":I?"Active for this run":"Not signed in",authBusy:!p,checkoutBusy:!1,ltdCheckoutEnabled:!1,monthlyCheckoutEnabled:!1,teamCheckoutEnabled:!1,planChangesEnabled:!1,planManagementLabel:"Plan is managed at the Hub",showWorkspaceSwitcher:!1,workspaces:[],activeWorkspaceId:"",onClose:()=>q(!1),onSignIn:async()=>{q(!1),await F()},onSignOut:Be,onSelectPlan:()=>{}}),e.jsx("section",{className:"desk-stage client-unified-stage",children:D==="support"?e.jsx("section",{className:"client-unified-page",children:e.jsx(ft,{session:o,currentProductKey:"livedesk",appVersion:t?.appVersion||"",onSignIn:()=>{F()}})}):D!=="computer"?e.jsx("section",{className:"client-unified-page",children:e.jsx(Ot,{page:D,status:t})}):e.jsx(Mt,{session:o,status:t,pin:R,roleChangeMessage:$,videoAccelerationBusy:w,slotInput:G,slotBusy:T,onSignIn:()=>{F()},onPinChange:n=>_(n.replace(/\D/g,"").slice(0,6)),onSubmitPin:()=>{ze()},onSlotInputChange:n=>{ie.current=!0,E(n.replace(/\D/g,"").slice(0,3))},onSaveSlot:()=>{We()},onEnableVideoAcceleration:()=>{Ke()}})}),N&&e.jsxs("div",{className:`client-side-toast ${N.kind}`,role:N.kind==="error"?"alert":"status",children:[N.kind==="error"?e.jsx(it,{size:18}):e.jsx(Fe,{size:18}),e.jsx("span",{children:N.message}),e.jsx("button",{type:"button",onClick:()=>S(null),"aria-label":"Dismiss notification",children:e.jsx(Se,{size:16})})]})]})}const Ut=1e3,_t=5e3;function Bt(){return typeof window>"u"?!1:(!!window.navigator.standalone||window.matchMedia("(display-mode: standalone), (display-mode: fullscreen)").matches)&&window.matchMedia("(pointer: coarse)").matches}function Vt(){return typeof window>"u"?[]:[...new Set([window.location.origin,te].filter(Boolean))]}function Qt(){const t=Qe(),c=Bt(),o=t||c,u=t||typeof window>"u"?te:window.location.origin,p=o?{role:"hub",baseUrl:u}:null,[v,R]=r.useState(p),_=r.useRef(null);return r.useEffect(()=>{if(o){R(b=>b?.role==="hub"&&b.baseUrl===u?b:{role:"hub",baseUrl:u});return}let C=!1,d=!1,A=null;const k=new AbortController,j=async()=>{for(const b of Vt()){if(k.signal.aborted)return;try{const P=(await et("/api/runtime/status",{signal:k.signal,timeoutMs:900},b)).role==="hub"?"hub":"client";d=!0,C||R(w=>w?.role===P&&w.baseUrl===b?w:{role:P,baseUrl:b});return}catch{if(k.signal.aborted)return}}},g=()=>{Ze(_,j).finally(()=>{!C&&!k.signal.aborted&&(A=window.setTimeout(g,d?_t:Ut))}).catch(()=>{})};g();const $=window.setTimeout(()=>{!C&&!d&&R(b=>b?.role==="client"&&b.baseUrl===te?b:{role:"client",baseUrl:te})},2500);return()=>{C=!0,k.abort(new Error("VuvoDesk runtime role probe stopped.")),A!==null&&window.clearTimeout(A),window.clearTimeout($)}},[null,o,u]),v?v.role==="client"?e.jsx(Ht,{runtimeBaseUrl:v.baseUrl}):e.jsx(vt,{runtimeBaseUrl:v.baseUrl}):e.jsxs("main",{className:"runtime-role-boot","aria-busy":"true","aria-label":"Starting VuvoDesk",children:[e.jsx("span",{className:"runtime-role-boot-mark","aria-hidden":"true"}),e.jsx("strong",{children:"Starting VuvoDesk"}),e.jsx("p",{children:"Loading this computer's assigned role..."})]})}export{Qt as VuvoDeskApp};
@@ -1 +0,0 @@
1
- import{m as r,c as a,j as t,P as e,D as o,t as s,s as m}from"./styles-Ba1tPFHg.js";import{a as i}from"./icons-CacEbnZu.js";import{H as p}from"./App-DK9GZcvU.js";import"./react-Cfedt3N5.js";import"./supabase-C7qjtLN3.js";import"./frame-lifecycle-esOdP-EY.js";r();a.createRoot(document.getElementById("root")).render(t.jsx(i.StrictMode,{children:t.jsx(e,{automaticRetry:!0,children:t.jsx(p,{runtimeBaseUrl:o})})}));s();m();