@limrun/ui 0.16.0 → 0.17.0-rc.2

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 (73) hide show
  1. package/README.md +64 -0
  2. package/dist/GLTFLoader-Cami_vza.mjs +1679 -0
  3. package/dist/GLTFLoader-DeCLxW_q.js +1 -0
  4. package/dist/components/duo-button-hinge.d.ts +16 -0
  5. package/dist/components/duo-controls.d.ts +21 -0
  6. package/dist/components/duo-flat-frame.d.ts +7 -0
  7. package/dist/components/duo-flat-geometry.d.ts +52 -0
  8. package/dist/components/duo-fold-motion.d.ts +27 -0
  9. package/dist/components/duo-fold-renderer.d.ts +19 -0
  10. package/dist/components/duo-fold-timing.d.ts +1 -0
  11. package/dist/components/duo-frame.d.ts +16 -0
  12. package/dist/components/duo-hardware.d.ts +20 -0
  13. package/dist/components/duo-loading.d.ts +8 -0
  14. package/dist/components/duo-model.d.ts +19 -0
  15. package/dist/components/duo-screen-handoff.d.ts +4 -0
  16. package/dist/components/duo-view.d.ts +9 -0
  17. package/dist/components/remote-control.d.ts +5 -1
  18. package/dist/core/duo.d.ts +63 -0
  19. package/dist/duo-fold-renderer-BXejNHcY.mjs +257 -0
  20. package/dist/duo-fold-renderer-DdltAnF7.js +53 -0
  21. package/dist/duo-frame-Cmw4p2uN.mjs +26767 -0
  22. package/dist/duo-frame-iMtrvx_a.js +4059 -0
  23. package/dist/duo-view-BAh-w2Kz.js +1 -0
  24. package/dist/duo-view-D9Ae00rj.mjs +512 -0
  25. package/dist/index.cjs +1 -1
  26. package/dist/index.css +1 -1
  27. package/dist/index.js +2 -2
  28. package/dist/lite.cjs +1 -1
  29. package/dist/lite.js +1 -1
  30. package/dist/remote-control-B2jZpf3c.js +1 -0
  31. package/dist/remote-control-DiddxS8l.mjs +2883 -0
  32. package/package.json +8 -2
  33. package/dist/demo.d.ts +0 -1
  34. package/dist/remote-control-BRgbD7yo.mjs +0 -2516
  35. package/dist/remote-control-VISrP1zI.js +0 -1
  36. package/index.html +0 -199
  37. package/src/assets/Apple_logo_white.svg +0 -4
  38. package/src/assets/android_boot.gif +0 -0
  39. package/src/assets/android_boot.webp +0 -0
  40. package/src/assets/iphone16pro_black.webp +0 -0
  41. package/src/assets/iphone16pro_black_bg.webp +0 -0
  42. package/src/assets/iphone16pro_black_landscape.webp +0 -0
  43. package/src/assets/iphone16pro_black_landscape_bg.webp +0 -0
  44. package/src/assets/pixel9_black.webp +0 -0
  45. package/src/assets/pixel9_black_landscape.webp +0 -0
  46. package/src/assets/pixel_tablet_landscape.webp +0 -0
  47. package/src/assets/pixel_tablet_portrait.webp +0 -0
  48. package/src/components/device-install/index.ts +0 -1
  49. package/src/components/inspect-overlay.css +0 -223
  50. package/src/components/inspect-overlay.tsx +0 -437
  51. package/src/components/remote-control-framed.tsx +0 -14
  52. package/src/components/remote-control.css +0 -131
  53. package/src/components/remote-control.test.ts +0 -34
  54. package/src/components/remote-control.tsx +0 -3853
  55. package/src/core/ax-fetcher.test.ts +0 -418
  56. package/src/core/ax-fetcher.ts +0 -387
  57. package/src/core/ax-tree.test.ts +0 -491
  58. package/src/core/ax-tree.ts +0 -416
  59. package/src/core/camera.test.ts +0 -155
  60. package/src/core/camera.ts +0 -133
  61. package/src/core/constants.ts +0 -344
  62. package/src/core/webrtc-messages.ts +0 -148
  63. package/src/demo.tsx +0 -269
  64. package/src/frame-assets.ts +0 -22
  65. package/src/hooks/index.ts +0 -1
  66. package/src/index.ts +0 -29
  67. package/src/lite.test.ts +0 -30
  68. package/src/lite.ts +0 -30
  69. package/src/vite-env.d.ts +0 -1
  70. package/tsconfig.json +0 -26
  71. package/tsconfig.node.json +0 -26
  72. package/vite.config.ts +0 -35
  73. package/vitest.config.ts +0 -24
@@ -1,2516 +0,0 @@
1
- import { jsx as W, jsxs as te, Fragment as Ar } from "react/jsx-runtime";
2
- import { memo as qt, useState as z, useEffect as ae, useMemo as Me, useCallback as mn, forwardRef as En, useRef as v, useImperativeHandle as pn } from "react";
3
- import { createPortal as gn } from "react-dom";
4
- import './index.css';function Mr(n) {
5
- var t, c, a = "";
6
- if (typeof n == "string" || typeof n == "number") a += n;
7
- else if (typeof n == "object") if (Array.isArray(n)) {
8
- var m = n.length;
9
- for (t = 0; t < m; t++) n[t] && (c = Mr(n[t])) && (a && (a += " "), a += c);
10
- } else for (c in n) n[c] && (a && (a += " "), a += c);
11
- return a;
12
- }
13
- function Re() {
14
- for (var n, t, c = 0, a = "", m = arguments.length; c < m; c++) (n = arguments[c]) && (t = Mr(n)) && (a && (a += " "), a += t);
15
- return a;
16
- }
17
- const St = {
18
- INJECT_KEYCODE: 0,
19
- INJECT_TOUCH_EVENT: 2,
20
- // iOS-specific: send two touch points in one message (Option/Alt+drag pinch)
21
- INJECT_TWO_FINGER_TOUCH_EVENT: 18,
22
- SET_CLIPBOARD: 9
23
- }, L = {
24
- ACTION_DOWN: 0,
25
- ACTION_UP: 1,
26
- ACTION_MOVE: 2,
27
- ACTION_CANCEL: 3,
28
- ACTION_POINTER_DOWN: 5,
29
- ACTION_POINTER_UP: 6,
30
- BUTTON_PRIMARY: 1,
31
- BUTTON_SECONDARY: 2,
32
- BUTTON_TERTIARY: 4
33
- }, s = {
34
- // Actions
35
- ACTION_DOWN: 0,
36
- ACTION_UP: 1,
37
- // Meta state flags (from android.view.KeyEvent)
38
- META_NONE: 0,
39
- META_SHIFT_ON: 1,
40
- META_ALT_ON: 2,
41
- META_CTRL_ON: 4096,
42
- // META_CTRL_LEFT_ON | META_CTRL_RIGHT_ON
43
- META_META_ON: 65536,
44
- KEYCODE_0: 7,
45
- KEYCODE_1: 8,
46
- KEYCODE_2: 9,
47
- KEYCODE_3: 10,
48
- KEYCODE_4: 11,
49
- KEYCODE_5: 12,
50
- KEYCODE_6: 13,
51
- KEYCODE_7: 14,
52
- KEYCODE_8: 15,
53
- KEYCODE_9: 16,
54
- DPAD_UP: 19,
55
- // KEYCODE_DPAD_UP
56
- DPAD_DOWN: 20,
57
- // KEYCODE_DPAD_DOWN
58
- DPAD_LEFT: 21,
59
- // KEYCODE_DPAD_LEFT
60
- DPAD_RIGHT: 22,
61
- KEYCODE_A: 29,
62
- KEYCODE_B: 30,
63
- KEYCODE_C: 31,
64
- KEYCODE_D: 32,
65
- KEYCODE_E: 33,
66
- KEYCODE_F: 34,
67
- KEYCODE_G: 35,
68
- KEYCODE_H: 36,
69
- KEYCODE_I: 37,
70
- KEYCODE_J: 38,
71
- KEYCODE_K: 39,
72
- KEYCODE_L: 40,
73
- KEYCODE_M: 41,
74
- KEYCODE_N: 42,
75
- KEYCODE_O: 43,
76
- KEYCODE_P: 44,
77
- KEYCODE_Q: 45,
78
- KEYCODE_R: 46,
79
- KEYCODE_S: 47,
80
- KEYCODE_T: 48,
81
- KEYCODE_U: 49,
82
- KEYCODE_V: 50,
83
- KEYCODE_W: 51,
84
- KEYCODE_X: 52,
85
- KEYCODE_Y: 53,
86
- KEYCODE_Z: 54,
87
- KEYCODE_COMMA: 55,
88
- KEYCODE_PERIOD: 56,
89
- KEYCODE_ALT_LEFT: 57,
90
- KEYCODE_ALT_RIGHT: 58,
91
- KEYCODE_SHIFT_LEFT: 59,
92
- KEYCODE_SHIFT_RIGHT: 60,
93
- KEYCODE_TAB: 61,
94
- KEYCODE_SPACE: 62,
95
- ENTER: 66,
96
- // KEYCODE_ENTER
97
- DEL: 67,
98
- // KEYCODE_DEL (Backspace)
99
- KEYCODE_GRAVE: 68,
100
- // `
101
- KEYCODE_MINUS: 69,
102
- // -
103
- KEYCODE_EQUALS: 70,
104
- // =
105
- KEYCODE_LEFT_BRACKET: 71,
106
- // [
107
- KEYCODE_RIGHT_BRACKET: 72,
108
- // ]
109
- KEYCODE_BACKSLASH: 73,
110
- // \
111
- KEYCODE_SEMICOLON: 74,
112
- // ;
113
- KEYCODE_APOSTROPHE: 75,
114
- // '
115
- KEYCODE_SLASH: 76,
116
- MENU: 82,
117
- KEYCODE_PAGE_UP: 92,
118
- KEYCODE_PAGE_DOWN: 93,
119
- KEYCODE_ESCAPE: 111,
120
- FORWARD_DEL: 112,
121
- // KEYCODE_FORWARD_DEL (Delete key)
122
- KEYCODE_CTRL_LEFT: 113,
123
- KEYCODE_CTRL_RIGHT: 114,
124
- KEYCODE_META_LEFT: 117,
125
- KEYCODE_META_RIGHT: 118,
126
- KEYCODE_MOVE_HOME: 122,
127
- KEYCODE_MOVE_END: 123,
128
- KEYCODE_INSERT: 124,
129
- KEYCODE_F1: 131,
130
- KEYCODE_F2: 132,
131
- KEYCODE_F3: 133,
132
- KEYCODE_F4: 134,
133
- KEYCODE_F5: 135,
134
- KEYCODE_F6: 136,
135
- KEYCODE_F7: 137,
136
- KEYCODE_F8: 138,
137
- KEYCODE_F9: 139,
138
- KEYCODE_F10: 140,
139
- KEYCODE_F11: 141,
140
- KEYCODE_F12: 142,
141
- KEYCODE_NUMPAD_0: 144,
142
- KEYCODE_NUMPAD_1: 145,
143
- KEYCODE_NUMPAD_2: 146,
144
- KEYCODE_NUMPAD_3: 147,
145
- KEYCODE_NUMPAD_4: 148,
146
- KEYCODE_NUMPAD_5: 149,
147
- KEYCODE_NUMPAD_6: 150,
148
- KEYCODE_NUMPAD_7: 151,
149
- KEYCODE_NUMPAD_8: 152,
150
- KEYCODE_NUMPAD_9: 153,
151
- KEYCODE_NUMPAD_DIVIDE: 154,
152
- KEYCODE_NUMPAD_MULTIPLY: 155,
153
- KEYCODE_NUMPAD_SUBTRACT: 156,
154
- KEYCODE_NUMPAD_ADD: 157,
155
- KEYCODE_NUMPAD_DOT: 158,
156
- KEYCODE_NUMPAD_COMMA: 159,
157
- KEYCODE_NUMPAD_ENTER: 160,
158
- KEYCODE_NUMPAD_EQUALS: 161
159
- }, Rr = {
160
- KeyA: s.KEYCODE_A,
161
- KeyB: s.KEYCODE_B,
162
- KeyC: s.KEYCODE_C,
163
- KeyD: s.KEYCODE_D,
164
- KeyE: s.KEYCODE_E,
165
- KeyF: s.KEYCODE_F,
166
- KeyG: s.KEYCODE_G,
167
- KeyH: s.KEYCODE_H,
168
- KeyI: s.KEYCODE_I,
169
- KeyJ: s.KEYCODE_J,
170
- KeyK: s.KEYCODE_K,
171
- KeyL: s.KEYCODE_L,
172
- KeyM: s.KEYCODE_M,
173
- KeyN: s.KEYCODE_N,
174
- KeyO: s.KEYCODE_O,
175
- KeyP: s.KEYCODE_P,
176
- KeyQ: s.KEYCODE_Q,
177
- KeyR: s.KEYCODE_R,
178
- KeyS: s.KEYCODE_S,
179
- KeyT: s.KEYCODE_T,
180
- KeyU: s.KEYCODE_U,
181
- KeyV: s.KEYCODE_V,
182
- KeyW: s.KEYCODE_W,
183
- KeyX: s.KEYCODE_X,
184
- KeyY: s.KEYCODE_Y,
185
- KeyZ: s.KEYCODE_Z,
186
- Digit0: s.KEYCODE_0,
187
- Digit1: s.KEYCODE_1,
188
- Digit2: s.KEYCODE_2,
189
- Digit3: s.KEYCODE_3,
190
- Digit4: s.KEYCODE_4,
191
- Digit5: s.KEYCODE_5,
192
- Digit6: s.KEYCODE_6,
193
- Digit7: s.KEYCODE_7,
194
- Digit8: s.KEYCODE_8,
195
- Digit9: s.KEYCODE_9,
196
- Backquote: s.KEYCODE_GRAVE,
197
- Minus: s.KEYCODE_MINUS,
198
- Equal: s.KEYCODE_EQUALS,
199
- BracketLeft: s.KEYCODE_LEFT_BRACKET,
200
- BracketRight: s.KEYCODE_RIGHT_BRACKET,
201
- Backslash: s.KEYCODE_BACKSLASH,
202
- Semicolon: s.KEYCODE_SEMICOLON,
203
- Quote: s.KEYCODE_APOSTROPHE,
204
- Comma: s.KEYCODE_COMMA,
205
- Period: s.KEYCODE_PERIOD,
206
- Slash: s.KEYCODE_SLASH,
207
- Space: s.KEYCODE_SPACE,
208
- Tab: s.KEYCODE_TAB,
209
- Escape: s.KEYCODE_ESCAPE,
210
- ArrowUp: s.DPAD_UP,
211
- ArrowDown: s.DPAD_DOWN,
212
- ArrowLeft: s.DPAD_LEFT,
213
- ArrowRight: s.DPAD_RIGHT,
214
- Enter: s.ENTER,
215
- Backspace: s.DEL,
216
- Delete: s.FORWARD_DEL,
217
- Home: s.KEYCODE_MOVE_HOME,
218
- End: s.KEYCODE_MOVE_END,
219
- PageUp: s.KEYCODE_PAGE_UP,
220
- PageDown: s.KEYCODE_PAGE_DOWN,
221
- Insert: s.KEYCODE_INSERT,
222
- F1: s.KEYCODE_F1,
223
- F2: s.KEYCODE_F2,
224
- F3: s.KEYCODE_F3,
225
- F4: s.KEYCODE_F4,
226
- F5: s.KEYCODE_F5,
227
- F6: s.KEYCODE_F6,
228
- F7: s.KEYCODE_F7,
229
- F8: s.KEYCODE_F8,
230
- F9: s.KEYCODE_F9,
231
- F10: s.KEYCODE_F10,
232
- F11: s.KEYCODE_F11,
233
- F12: s.KEYCODE_F12,
234
- ShiftLeft: s.KEYCODE_SHIFT_LEFT,
235
- ShiftRight: s.KEYCODE_SHIFT_RIGHT,
236
- ControlLeft: s.KEYCODE_CTRL_LEFT,
237
- ControlRight: s.KEYCODE_CTRL_RIGHT,
238
- AltLeft: s.KEYCODE_ALT_LEFT,
239
- AltRight: s.KEYCODE_ALT_RIGHT,
240
- MetaLeft: s.KEYCODE_META_LEFT,
241
- MetaRight: s.KEYCODE_META_RIGHT,
242
- // Windows/Command key
243
- ContextMenu: s.MENU,
244
- // Often the Menu key
245
- // Numpad mappings
246
- Numpad0: s.KEYCODE_NUMPAD_0,
247
- Numpad1: s.KEYCODE_NUMPAD_1,
248
- Numpad2: s.KEYCODE_NUMPAD_2,
249
- Numpad3: s.KEYCODE_NUMPAD_3,
250
- Numpad4: s.KEYCODE_NUMPAD_4,
251
- Numpad5: s.KEYCODE_NUMPAD_5,
252
- Numpad6: s.KEYCODE_NUMPAD_6,
253
- Numpad7: s.KEYCODE_NUMPAD_7,
254
- Numpad8: s.KEYCODE_NUMPAD_8,
255
- Numpad9: s.KEYCODE_NUMPAD_9,
256
- NumpadDivide: s.KEYCODE_NUMPAD_DIVIDE,
257
- NumpadMultiply: s.KEYCODE_NUMPAD_MULTIPLY,
258
- NumpadSubtract: s.KEYCODE_NUMPAD_SUBTRACT,
259
- NumpadAdd: s.KEYCODE_NUMPAD_ADD,
260
- NumpadDecimal: s.KEYCODE_NUMPAD_DOT,
261
- NumpadComma: s.KEYCODE_NUMPAD_COMMA,
262
- // Some numpads have comma
263
- NumpadEnter: s.KEYCODE_NUMPAD_ENTER,
264
- NumpadEqual: s.KEYCODE_NUMPAD_EQUALS
265
- };
266
- function At(n, t, c, a, m, E, g = 1, y = 0, Y = 0) {
267
- const D = new ArrayBuffer(32), R = new DataView(D);
268
- let b = 0;
269
- return R.setUint8(b, St.INJECT_TOUCH_EVENT), b += 1, R.setUint8(b, n), b += 1, R.setBigInt64(b, BigInt(t), !0), b += 8, R.setInt32(b, Math.round(m), !0), b += 4, R.setInt32(b, Math.round(E), !0), b += 4, R.setUint16(b, c, !0), b += 2, R.setUint16(b, a, !0), b += 2, R.setInt16(b, Math.round(g * 65535), !0), b += 2, R.setInt32(b, y, !0), b += 4, R.setInt32(b, Y, !0), D;
270
- }
271
- function Cn(n, t, c, a, m, E, g) {
272
- const y = new ArrayBuffer(24), Y = new DataView(y);
273
- let D = 0;
274
- return Y.setUint8(D, St.INJECT_TWO_FINGER_TOUCH_EVENT), D += 1, Y.setUint8(D, n), D += 1, Y.setInt32(D, Math.round(a), !0), D += 4, Y.setInt32(D, Math.round(m), !0), D += 4, Y.setInt32(D, Math.round(E), !0), D += 4, Y.setInt32(D, Math.round(g), !0), D += 4, Y.setUint16(D, t, !0), D += 2, Y.setUint16(D, c, !0), D += 2, Y.setUint16(D, 0, !0), y;
275
- }
276
- function yn(n, t = !0) {
277
- const a = new TextEncoder().encode(n), m = new ArrayBuffer(14 + a.length), E = new DataView(m);
278
- let g = 0;
279
- return E.setUint8(g, St.SET_CLIPBOARD), g += 1, E.setBigInt64(g, BigInt(0), !1), g += 8, E.setUint8(g, t ? 1 : 0), g += 1, E.setUint32(g, a.length, !1), g += 4, new Uint8Array(m, g).set(a), m;
280
- }
281
- function ut(n, t, c = 0, a = 0) {
282
- const m = new ArrayBuffer(14), E = new DataView(m);
283
- let g = 0;
284
- return E.setUint8(g, St.INJECT_KEYCODE), g += 1, E.setUint8(g, n), g += 1, E.setInt32(g, t, !0), g += 4, E.setInt32(g, c, !0), g += 4, E.setInt32(g, a, !0), m;
285
- }
286
- const Xt = "Accessibility unavailable on this device.", Rt = 500, Sr = (n, t) => Math.abs(n.x - t.x) < 0.5 && Math.abs(n.y - t.y) < 0.5 && Math.abs(n.width - t.width) < 0.5 && Math.abs(n.height - t.height) < 0.5, On = (n) => Math.max(0, n.width) * Math.max(0, n.height), vn = (n) => {
287
- const t = n.find((c) => c.frame && c.frame.width > 0 && c.frame.height > 0);
288
- return t?.frame ? ((Math.abs(t.frame.x) > 0.5 || Math.abs(t.frame.y) > 0.5) && console.warn(
289
- `[ax-tree] iOS root frame is not anchored at (0,0): (${t.frame.x},${t.frame.y}). Element positions may be slightly off from the rendered video.`
290
- ), { x: 0, y: 0, width: t.frame.width, height: t.frame.height }) : { x: 0, y: 0, width: 1, height: 1 };
291
- }, _n = (n) => {
292
- const t = {};
293
- return typeof n.AXUniqueId == "string" && n.AXUniqueId.length > 0 && (t.AXUniqueId = n.AXUniqueId), typeof n.AXLabel == "string" && n.AXLabel.length > 0 && (t.AXLabel = n.AXLabel), typeof n.type == "string" && n.type.length > 0 && (t.className = n.type), t;
294
- }, Dn = (n) => {
295
- const t = {};
296
- for (const [c, a] of Object.entries(n))
297
- c !== "children" && (t[c] = a);
298
- return t;
299
- };
300
- function Tn(n) {
301
- const t = Array.isArray(n) ? n : [n], c = vn(t), a = [], m = (E, g) => {
302
- if (a.length >= Rt) return;
303
- const y = E.frame;
304
- if (y && y.width > 0 && y.height > 0 && !Sr(y, c)) {
305
- const D = E.role_description || E.role || "", R = (typeof E.AXLabel == "string" ? E.AXLabel : "") || (typeof E.title == "string" ? E.title : "") || "";
306
- a.push({
307
- id: typeof E.AXUniqueId == "string" && E.AXUniqueId.length > 0 ? E.AXUniqueId : g,
308
- path: g,
309
- label: R,
310
- value: typeof E.AXValue == "string" ? E.AXValue : "",
311
- role: D,
312
- type: typeof E.type == "string" ? E.type : "",
313
- enabled: E.enabled !== !1,
314
- focused: E.focused === !0,
315
- frame: { x: y.x, y: y.y, width: y.width, height: y.height },
316
- selectors: _n(E),
317
- raw: Dn(E)
318
- });
319
- }
320
- const Y = Array.isArray(E.children) ? E.children : [];
321
- for (let D = 0; D < Y.length && a.length < Rt; D++)
322
- m(Y[D], `${g}.${D}`);
323
- };
324
- for (let E = 0; E < t.length && a.length < Rt; E++)
325
- m(t[E], String(E));
326
- return {
327
- platform: "ios",
328
- screen: { width: c.width, height: c.height },
329
- elements: a,
330
- capturedAt: Date.now()
331
- };
332
- }
333
- const wn = (n) => {
334
- let t = { x: 0, y: 0, width: 1, height: 1 }, c = 0;
335
- for (const a of n) {
336
- const m = a.parsedBounds;
337
- if (!m) continue;
338
- const E = m.right - m.left, g = m.bottom - m.top, y = Math.max(0, E) * Math.max(0, g);
339
- y > c && (c = y, t = { x: 0, y: 0, width: E, height: g });
340
- }
341
- return t;
342
- }, An = (n) => {
343
- const t = {};
344
- return typeof n.resourceId == "string" && n.resourceId.length > 0 && (t.resourceId = n.resourceId), typeof n.contentDesc == "string" && n.contentDesc.length > 0 && (t.contentDesc = n.contentDesc), typeof n.text == "string" && n.text.length > 0 && (t.text = n.text), typeof n.className == "string" && n.className.length > 0 && (t.className = n.className), t;
345
- };
346
- function Mn(n) {
347
- const t = wn(n), c = [];
348
- for (let a = 0; a < n.length && c.length < Rt; a++) {
349
- const m = n[a], E = m.parsedBounds;
350
- if (!E) continue;
351
- const g = Math.max(0, E.right - E.left), y = Math.max(0, E.bottom - E.top);
352
- if (g <= 0 || y <= 0) continue;
353
- const Y = { x: E.left, y: E.top, width: g, height: y };
354
- if (Sr(Y, { x: 0, y: 0, width: t.width, height: t.height })) continue;
355
- const D = m.contentDesc || m.text || "", R = m.className || "";
356
- c.push({
357
- id: m.resourceId && m.resourceId.length > 0 ? m.resourceId : m.contentDesc && m.contentDesc.length > 0 ? `cd:${m.contentDesc}` : String(a),
358
- path: String(a),
359
- label: D,
360
- value: typeof m.text == "string" ? m.text : "",
361
- role: R,
362
- type: R,
363
- enabled: m.enabled !== !1,
364
- focused: m.focused === !0,
365
- frame: Y,
366
- selectors: An(m),
367
- raw: { ...m }
368
- });
369
- }
370
- return {
371
- platform: "android",
372
- screen: { width: t.width, height: t.height },
373
- elements: c,
374
- capturedAt: Date.now()
375
- };
376
- }
377
- function Rn(n, t) {
378
- const c = Math.max(0, n.x), a = Math.max(0, n.y), m = Math.min(t.width, n.x + n.width), E = Math.min(t.height, n.y + n.height), g = Math.max(0, m - c), y = Math.max(0, E - a);
379
- return g > 0 && y > 0 ? { x: c, y: a, width: g, height: y } : null;
380
- }
381
- function br(n, t) {
382
- if (n === t) return !0;
383
- if (n.id !== t.id || n.path !== t.path || n.label !== t.label || n.value !== t.value || n.role !== t.role || n.type !== t.type || n.enabled !== t.enabled || n.focused !== t.focused) return !1;
384
- const c = n.frame, a = t.frame;
385
- return c.x === a.x && c.y === a.y && c.width === a.width && c.height === a.height;
386
- }
387
- function Nr(n, t) {
388
- if (n === t) return !0;
389
- if (!n || !t || n.platform !== t.platform || n.screen.width !== t.screen.width || n.screen.height !== t.screen.height || n.elements.length !== t.elements.length) return !1;
390
- for (let c = 0; c < n.elements.length; c++)
391
- if (!br(n.elements[c], t.elements[c])) return !1;
392
- return !0;
393
- }
394
- function Sn(n, t, c) {
395
- let a = null, m = 1 / 0;
396
- for (const E of n.elements) {
397
- const g = E.frame;
398
- if (t < g.x || c < g.y || t > g.x + g.width || c > g.y + g.height) continue;
399
- const y = On(g);
400
- y < m && (m = y, a = E);
401
- }
402
- return a;
403
- }
404
- function bn(n, t) {
405
- if (t === "ios") {
406
- if (n.selectors.AXUniqueId)
407
- return `client.tapElement({ AXUniqueId: ${JSON.stringify(n.selectors.AXUniqueId)} })`;
408
- if (n.selectors.AXLabel) {
409
- const c = n.selectors.className ? `, type: ${JSON.stringify(n.selectors.className)}` : "";
410
- return `client.tapElement({ AXLabel: ${JSON.stringify(n.selectors.AXLabel)}${c} })`;
411
- }
412
- return null;
413
- }
414
- return n.selectors.resourceId ? `client.tap({ selector: { resourceId: ${JSON.stringify(n.selectors.resourceId)} } })` : n.selectors.contentDesc ? `client.tap({ selector: { contentDesc: ${JSON.stringify(n.selectors.contentDesc)} } })` : n.selectors.text ? `client.tap({ selector: { text: ${JSON.stringify(n.selectors.text)} } })` : null;
415
- }
416
- function Ir(n) {
417
- const t = n.role || n.type || "";
418
- if (!t) return "element";
419
- let c = t.replace(/^AX/, "");
420
- return c.includes(".") && (c = c.split(".").pop()), c === "GenericElement" ? "Element" : (c = c.replace(/([a-z])([A-Z])/g, "$1 $2"), c);
421
- }
422
- const vr = 80;
423
- function Yr(n) {
424
- const t = Ir(n), c = n.label || n.value || "";
425
- if (!c) return t;
426
- const a = c.length > vr ? c.slice(0, vr).trimEnd() + "…" : c;
427
- return `${t} · ${a}`;
428
- }
429
- const Nn = 500, In = 2e3, _r = 5e3, Yn = 8e3, Kn = 1200, kn = 250, Pn = () => `ax-rc-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
430
- class Ln {
431
- platform;
432
- send;
433
- onSnapshot;
434
- onStatusChange;
435
- baseIntervalMs;
436
- maxBackoffMs;
437
- androidElementTreeOptions;
438
- pending = /* @__PURE__ */ new Map();
439
- running = !1;
440
- timer;
441
- currentInterval;
442
- lastSnapshot = null;
443
- // Single-flight: only one outstanding request at a time. Avoids piling
444
- // identical requests on a slow server.
445
- inflight = !1;
446
- // Rate-limit floor for bumpActivity so high-frequency input (drags,
447
- // typing) doesn't trigger a request storm.
448
- lastBumpAtMs = 0;
449
- // Wall-clock timestamp until which we're in "activity boost" mode and
450
- // schedule fetches at ACTIVITY_BOOST_INTERVAL_MS instead of the normal
451
- // backed-off interval. Set by bumpActivity().
452
- boostUntilMs = 0;
453
- // Coarse-grained current status; deduplicated before emission so
454
- // identical-to-current transitions are no-ops.
455
- status = "idle";
456
- constructor(t) {
457
- this.platform = t.platform, this.send = t.send, this.onSnapshot = t.onSnapshot, this.onStatusChange = t.onStatusChange, this.baseIntervalMs = t.baseIntervalMs ?? Nn, this.maxBackoffMs = t.maxBackoffMs ?? In, this.androidElementTreeOptions = t.androidElementTreeOptions, this.currentInterval = this.baseIntervalMs;
458
- }
459
- start() {
460
- this.running || (this.running = !0, this.currentInterval = this.baseIntervalMs, this.boostUntilMs = 0, this.setStatus("starting"), this.runOnce());
461
- }
462
- stop() {
463
- this.running && (this.running = !1, this.timer !== void 0 && (window.clearTimeout(this.timer), this.timer = void 0), this.failAllPending("Inspector stopped"), this.lastSnapshot = null, this.setStatus("idle"), this.onSnapshot(null));
464
- }
465
- getStatus() {
466
- return this.status;
467
- }
468
- setStatus(t, c) {
469
- if (this.status !== t && (this.status = t, !!this.onStatusChange))
470
- try {
471
- this.onStatusChange(t, c);
472
- } catch (a) {
473
- console.error("[AxFetcher] onStatusChange threw:", a);
474
- }
475
- }
476
- // Called after any user-driven action that's likely to change the UI
477
- // (taps, scrolls, key events, openUrl, app termination, orientation
478
- // change, etc.). Has two effects:
479
- //
480
- // 1. Resets the polling interval to base and triggers an immediate
481
- // fetch (rate-limited so drags / rapid typing don't request-storm).
482
- // 2. Enters a brief "boost" window during which scheduleNext() uses a
483
- // shorter interval (ACTIVITY_BOOST_INTERVAL_MS), so we capture the
484
- // mid- and post-animation tree without waiting for the next
485
- // back-off cycle.
486
- bumpActivity() {
487
- if (!this.running) return;
488
- const t = Date.now();
489
- this.boostUntilMs = t + Kn;
490
- const c = Math.max(150, Math.floor(this.baseIntervalMs / 2));
491
- if (t - this.lastBumpAtMs < c) {
492
- this.currentInterval = this.baseIntervalMs;
493
- return;
494
- }
495
- this.lastBumpAtMs = t, this.currentInterval = this.baseIntervalMs, this.timer !== void 0 && (window.clearTimeout(this.timer), this.timer = void 0), this.inflight || this.runOnce();
496
- }
497
- // Fire a one-shot fetch independent of the poll loop. Useful for the
498
- // imperative refresh() ref method customers may call.
499
- //
500
- // Goes through the same change-detect path as the regular poll loop —
501
- // identical-to-last-snapshot responses do NOT re-emit via onSnapshot, so
502
- // a customer calling refresh() in a tight loop doesn't see a stream of
503
- // duplicate snapshots. The returned promise still resolves with the
504
- // (possibly identical) snapshot for the caller's own use.
505
- async refresh() {
506
- const t = await this.requestOnce();
507
- return this.running && this.deliver(t), t;
508
- }
509
- // Returns the latest snapshot delivered to onSnapshot. May be stale.
510
- getLatest() {
511
- return this.lastSnapshot;
512
- }
513
- // Called by RemoteControl's ws.onmessage when it sees a message type we own.
514
- // Returns true when the message was a response we were waiting for.
515
- handleMessage(t) {
516
- if (!t || typeof t.id != "string") return !1;
517
- const c = t.id;
518
- if (!this.pending.get(c)) return !1;
519
- if (this.platform === "ios") {
520
- if (t.type !== "elementTreeResult") return !1;
521
- const y = typeof t.error == "string" ? t.error : null;
522
- if (y)
523
- return this.settleReject(c, new Error(y)), !0;
524
- const Y = typeof t.json == "string" ? t.json : "";
525
- try {
526
- const D = JSON.parse(Y), R = Tn(D);
527
- this.settleResolve(c, R);
528
- } catch (D) {
529
- this.settleReject(c, D instanceof Error ? D : new Error(String(D)));
530
- }
531
- return !0;
532
- }
533
- if (t.type !== "getElementTreeResult") return !1;
534
- const m = t.error;
535
- if (m && typeof m == "object") {
536
- const y = typeof m.message == "string" ? m.message : "getElementTree failed";
537
- return this.settleReject(c, new Error(y)), !0;
538
- }
539
- const E = t.payload, g = Array.isArray(E?.nodes) ? E.nodes : [];
540
- try {
541
- const y = Mn(g);
542
- this.settleResolve(c, y);
543
- } catch (y) {
544
- this.settleReject(c, y instanceof Error ? y : new Error(String(y)));
545
- }
546
- return !0;
547
- }
548
- buildRequest(t) {
549
- return this.platform === "ios" ? { type: "elementTree", id: t } : { type: "getElementTree", id: t, ...this.androidElementTreeOptions };
550
- }
551
- async requestOnce() {
552
- const t = Pn();
553
- return new Promise((c, a) => {
554
- const m = window.setTimeout(
555
- () => {
556
- this.pending.delete(t), a(new Error("elementTree request timed out"));
557
- },
558
- Yn + (this.androidElementTreeOptions?.waitForIdleTimeoutMs ?? 0)
559
- );
560
- this.pending.set(t, { resolve: c, reject: a, timer: m }), this.send(this.buildRequest(t)) || (window.clearTimeout(m), this.pending.delete(t), a(new Error("elementTree send failed (WebSocket not open)")));
561
- });
562
- }
563
- async runOnce() {
564
- if (this.running && !this.inflight) {
565
- this.inflight = !0;
566
- try {
567
- const t = await this.requestOnce();
568
- if (!this.running) return;
569
- this.deliver(t);
570
- } catch (t) {
571
- if (!this.running) return;
572
- const c = t instanceof Error ? t.message : String(t), a = /unavailable|not (yet )?running|failed|timeout/i.test(c);
573
- this.currentInterval = a ? _r : Math.min(this.currentInterval * 2, this.maxBackoffMs), this.setStatus(a ? "unavailable" : "error", c);
574
- } finally {
575
- this.inflight = !1, this.scheduleNext();
576
- }
577
- }
578
- }
579
- deliver(t) {
580
- const c = this.lastSnapshot;
581
- if (Nr(c, t)) {
582
- this.currentInterval = Math.min(this.currentInterval * 2, this.maxBackoffMs), this.lastSnapshot = t, t.errors?.includes(Xt) || this.setStatus("ready");
583
- return;
584
- }
585
- this.lastSnapshot = t, this.currentInterval = this.baseIntervalMs, t.errors?.includes(Xt) ? (this.currentInterval = _r, this.setStatus("unavailable", Xt)) : this.setStatus("ready"), this.onSnapshot(t);
586
- }
587
- scheduleNext() {
588
- if (!this.running) return;
589
- this.timer !== void 0 && window.clearTimeout(this.timer);
590
- const t = Date.now() < this.boostUntilMs ? Math.min(kn, this.currentInterval) : this.currentInterval;
591
- this.timer = window.setTimeout(() => {
592
- this.timer = void 0, this.runOnce();
593
- }, t);
594
- }
595
- settleResolve(t, c) {
596
- const a = this.pending.get(t);
597
- a && (window.clearTimeout(a.timer), this.pending.delete(t), a.resolve(c));
598
- }
599
- settleReject(t, c) {
600
- const a = this.pending.get(t);
601
- a && (window.clearTimeout(a.timer), this.pending.delete(t), a.reject(c));
602
- }
603
- failAllPending(t) {
604
- for (const [c, a] of this.pending.entries())
605
- window.clearTimeout(a.timer), a.reject(new Error(t)), this.pending.delete(c);
606
- }
607
- }
608
- class Un {
609
- generation = 0;
610
- tail = Promise.resolve();
611
- get currentGeneration() {
612
- return this.generation;
613
- }
614
- enqueue(t) {
615
- const c = ++this.generation;
616
- return this.append(c, t);
617
- }
618
- /**
619
- * Queues related work without superseding an already queued request.
620
- *
621
- * The operation retains the generation current at enqueue time and becomes
622
- * stale if a later camera request increments it before this work starts.
623
- */
624
- enqueueCurrent(t) {
625
- return this.append(this.generation, t);
626
- }
627
- append(t, c) {
628
- const a = {
629
- generation: t,
630
- isCurrent: () => t === this.generation
631
- }, m = this.tail.then(() => c(a));
632
- return this.tail = m.catch(() => {
633
- }), m;
634
- }
635
- invalidate() {
636
- ++this.generation;
637
- }
638
- }
639
- function xn(n) {
640
- if (!n || typeof n != "object") return null;
641
- const t = n;
642
- if (t.type !== "cameraRequest" || typeof t.active != "boolean") return null;
643
- const c = { active: t.active };
644
- return (t.facingMode === "user" || t.facingMode === "environment") && (c.facingMode = t.facingMode), c;
645
- }
646
- function Fn(n) {
647
- const t = {
648
- frameRate: { ideal: 30, max: 30 }
649
- };
650
- return n?.facingMode && (t.facingMode = { ideal: n.facingMode }), t;
651
- }
652
- function Wn(n, t) {
653
- return !n || n.facingMode !== t.facingMode;
654
- }
655
- function Hn(n) {
656
- const t = n.getSettings();
657
- return {
658
- width: t.width,
659
- height: t.height,
660
- frameRate: t.frameRate,
661
- deviceId: t.deviceId,
662
- label: n.label || void 0,
663
- facingMode: t.facingMode
664
- };
665
- }
666
- function $n(n) {
667
- return {
668
- type: "cameraResult",
669
- granted: !0,
670
- camera: Hn(n)
671
- };
672
- }
673
- const Xn = async (n) => {
674
- if (!n) return !1;
675
- try {
676
- if (typeof navigator < "u" && navigator.clipboard?.writeText)
677
- return await navigator.clipboard.writeText(n), !0;
678
- } catch {
679
- }
680
- try {
681
- const t = document.createElement("textarea");
682
- t.value = n, t.style.position = "fixed", t.style.opacity = "0", document.body.appendChild(t), t.select();
683
- const c = document.execCommand("copy");
684
- return document.body.removeChild(t), c;
685
- } catch {
686
- return !1;
687
- }
688
- }, Bn = qt(
689
- function({ element: t, screen: c, highlighted: a, selected: m, selectable: E, onClick: g }) {
690
- const y = Rn(t.frame, c);
691
- if (!y) return null;
692
- const Y = Yr(t);
693
- return /* @__PURE__ */ W(
694
- "button",
695
- {
696
- type: "button",
697
- className: Re("rc-inspect-box", !t.enabled && "rc-inspect-box-disabled"),
698
- "data-ax-id": t.id,
699
- "data-ax-path": t.path,
700
- "data-ax-label": t.label || void 0,
701
- "data-ax-role": t.role || void 0,
702
- "data-highlighted": a ? "true" : "false",
703
- "data-selected": m ? "true" : "false",
704
- "aria-label": Y,
705
- onClick: (D) => {
706
- E && (D.preventDefault(), D.stopPropagation(), g(t, { x: D.clientX, y: D.clientY }));
707
- },
708
- style: {
709
- left: `${y.x / c.width * 100}%`,
710
- top: `${y.y / c.height * 100}%`,
711
- width: `${y.width / c.width * 100}%`,
712
- height: `${y.height / c.height * 100}%`
713
- }
714
- }
715
- );
716
- },
717
- (n, t) => n.highlighted === t.highlighted && n.selected === t.selected && n.selectable === t.selectable && n.screen.width === t.screen.width && n.screen.height === t.screen.height && n.onClick === t.onClick && br(n.element, t.element)
718
- ), qn = 260, Vn = 220, Gn = 6, Jn = 8, zn = qt(function({
719
- element: t,
720
- platform: c,
721
- anchor: a,
722
- cursorAnchored: m,
723
- showActions: E,
724
- onTap: g
725
- }) {
726
- const [y, Y] = z(null);
727
- ae(() => {
728
- if (!y) return;
729
- const X = window.setTimeout(() => Y(null), 1100);
730
- return () => window.clearTimeout(X);
731
- }, [y]);
732
- const D = Me(() => {
733
- const X = qn, oe = Vn, j = Gn, $ = Jn, Ee = typeof window < "u" ? window.innerWidth : 1024, be = typeof window < "u" ? window.innerHeight : 768, x = a.x + j + X <= Ee - $, pe = a.y - j - oe >= $;
734
- let Ge = x ? a.x + j : a.x - j, ge = pe ? a.y - j : a.y + j;
735
- const bt = `translate(${x ? "0" : "-100%"}, ${pe ? "-100%" : "0"})`;
736
- return Ge = Math.max($ + (x ? 0 : X), Math.min(Ee - $ - (x ? X : 0), Ge)), ge = Math.max($ + (pe ? oe : 0), Math.min(be - $ - (pe ? 0 : oe), ge)), { left: `${Ge}px`, top: `${ge}px`, transform: bt };
737
- }, [a.x, a.y]), R = Me(() => bn(t, c), [t, c]), b = c === "ios" ? t.selectors.AXUniqueId : t.selectors.resourceId, ie = c === "ios" ? "AXUniqueId" : "resourceId", de = mn(async (X, oe) => {
738
- if (!X) return;
739
- await Xn(X) && Y(oe);
740
- }, []), me = Ir(t), lt = t.label || t.value || me, Se = Yr(t);
741
- return gn(
742
- /* @__PURE__ */ te(
743
- "div",
744
- {
745
- className: "rc-inspect-card",
746
- "data-cursor-anchored": m ? "true" : "false",
747
- style: D,
748
- onClick: (X) => X.stopPropagation(),
749
- onMouseDown: (X) => X.stopPropagation(),
750
- onMouseMove: (X) => X.stopPropagation(),
751
- children: [
752
- /* @__PURE__ */ te("div", { className: "rc-inspect-card-header", children: [
753
- /* @__PURE__ */ W("span", { className: "rc-inspect-card-role", children: me }),
754
- !t.enabled && /* @__PURE__ */ W("span", { className: "rc-inspect-card-tag", children: "disabled" }),
755
- t.focused && /* @__PURE__ */ W("span", { className: "rc-inspect-card-tag rc-inspect-card-tag-blue", children: "focused" })
756
- ] }),
757
- /* @__PURE__ */ W("p", { className: "rc-inspect-card-title", title: Se, children: lt }),
758
- b && /* @__PURE__ */ te("div", { className: "rc-inspect-card-row", children: [
759
- /* @__PURE__ */ te("span", { className: "rc-inspect-card-row-label", children: [
760
- ie,
761
- ":"
762
- ] }),
763
- /* @__PURE__ */ W("span", { className: "rc-inspect-card-row-value", children: b })
764
- ] }),
765
- t.value && t.value !== t.label && /* @__PURE__ */ te("div", { className: "rc-inspect-card-row", children: [
766
- /* @__PURE__ */ W("span", { className: "rc-inspect-card-row-label", children: "value:" }),
767
- /* @__PURE__ */ W("span", { className: "rc-inspect-card-row-value", children: t.value })
768
- ] }),
769
- /* @__PURE__ */ te("div", { className: "rc-inspect-card-row", children: [
770
- /* @__PURE__ */ W("span", { className: "rc-inspect-card-row-label", children: "frame:" }),
771
- /* @__PURE__ */ te("span", { className: "rc-inspect-card-row-value", children: [
772
- Math.round(t.frame.width),
773
- "×",
774
- Math.round(t.frame.height),
775
- " @ ",
776
- Math.round(t.frame.x),
777
- ",",
778
- Math.round(t.frame.y)
779
- ] })
780
- ] }),
781
- E && /* @__PURE__ */ te("div", { className: "rc-inspect-card-actions", children: [
782
- /* @__PURE__ */ W(
783
- "button",
784
- {
785
- type: "button",
786
- className: "rc-inspect-card-btn rc-inspect-card-btn-primary",
787
- onClick: () => g(t, a),
788
- children: "Tap"
789
- }
790
- ),
791
- /* @__PURE__ */ W(
792
- "button",
793
- {
794
- type: "button",
795
- className: Re("rc-inspect-card-btn", y === "selector" && "rc-inspect-card-btn-copied"),
796
- disabled: !R,
797
- title: R ?? "No usable selector for this element",
798
- onClick: () => de(R ?? void 0, "selector"),
799
- children: y === "selector" ? "Copied!" : "Copy selector"
800
- }
801
- ),
802
- /* @__PURE__ */ W(
803
- "button",
804
- {
805
- type: "button",
806
- className: Re("rc-inspect-card-btn", y === "id" && "rc-inspect-card-btn-copied"),
807
- disabled: !b,
808
- title: b ?? `No ${ie}`,
809
- onClick: () => de(b, "id"),
810
- children: y === "id" ? "Copied!" : `Copy ${ie}`
811
- }
812
- )
813
- ] })
814
- ]
815
- }
816
- ),
817
- document.body
818
- );
819
- }), jn = qt(function({
820
- snapshot: t,
821
- geometry: c,
822
- highlightedId: a,
823
- selectedId: m,
824
- mode: E,
825
- cursorPosition: g,
826
- frozenCursorPosition: y,
827
- onSelectChange: Y,
828
- onTapElement: D
829
- }) {
830
- const R = E === "select", b = R ? a !== null && a !== m : a !== null, ie = R ? a ?? m : a, de = Me(() => {
831
- const $ = /* @__PURE__ */ new Map();
832
- if (!t) return $;
833
- for (const Ee of t.elements) $.set(Ee.id, Ee);
834
- return $;
835
- }, [t]), me = Me(() => ie ? de.get(ie) ?? null : null, [ie, de]);
836
- if (!(!!t && !!c && t.screen.width > 0 && t.screen.height > 0 && t.elements.length > 0)) return null;
837
- const Se = b ? g : y ?? g, X = b, oe = R && !b && m !== null, j = ($) => {
838
- R && $.target === $.currentTarget && Y(null, null);
839
- };
840
- return /* @__PURE__ */ te(Ar, { children: [
841
- /* @__PURE__ */ W(
842
- "div",
843
- {
844
- className: Re("rc-inspect-overlay", R && "rc-inspect-overlay-select"),
845
- style: {
846
- left: `${c.left}px`,
847
- top: `${c.top}px`,
848
- width: `${c.width}px`,
849
- height: `${c.height}px`
850
- },
851
- onClick: j,
852
- children: t.elements.map(($) => /* @__PURE__ */ W(
853
- Bn,
854
- {
855
- element: $,
856
- screen: t.screen,
857
- highlighted: $.id === a,
858
- selected: $.id === m,
859
- selectable: R,
860
- onClick: Y
861
- },
862
- $.id
863
- ))
864
- }
865
- ),
866
- me && Se && /* @__PURE__ */ W(
867
- zn,
868
- {
869
- element: me,
870
- platform: t.platform,
871
- anchor: Se,
872
- cursorAnchored: X,
873
- showActions: oe,
874
- onTap: D
875
- }
876
- )
877
- ] });
878
- }), F = (...n) => {
879
- window.debugRemoteControl && console.log(...n);
880
- }, w = (...n) => {
881
- window.debugRemoteControl && console.warn(...n);
882
- }, U = (n, t, ...c) => {
883
- if (t)
884
- try {
885
- t(...c);
886
- } catch (a) {
887
- console.error(`[RemoteControl] customer callback "${n}" threw:`, a);
888
- }
889
- }, Mt = (n) => Object.entries(L).find(
890
- ([c, a]) => c.startsWith("ACTION_") && a === n
891
- )?.[0] ?? String(n), Qn = (n) => n.includes("/android_") ? "android" : "ios", Dr = (n, t) => {
892
- const c = new URL(n);
893
- return c.searchParams.set("token", t), c.toString();
894
- }, Tr = 1920, wr = 1200, Bt = 3, Zn = 1e3, ei = 15e3, ti = 3e3, ri = 4e3, ni = (n, t) => n === Tr && t === wr || n === wr && t === Tr, ii = {
895
- ios: {
896
- videoBorderRadiusMultiplier: 0.15,
897
- loadingLogoSize: "20%",
898
- // Video position as percentage of frame dimensions
899
- videoPosition: {
900
- portrait: { heightMultiplier: 0.9678 },
901
- landscape: { widthMultiplier: 0.9678 }
902
- }
903
- },
904
- android: {
905
- videoBorderRadiusMultiplier: 0.13,
906
- loadingLogoSize: "40%",
907
- // Video position as percentage of frame dimensions
908
- videoPosition: {
909
- portrait: { heightMultiplier: 0.967 },
910
- landscape: { widthMultiplier: 0.962 }
911
- }
912
- }
913
- };
914
- function oi(n) {
915
- const t = n.code, c = Rr[t];
916
- if (!c)
917
- return w(`Unknown event.code: ${t}, key: ${n.key}`), null;
918
- let a = s.META_NONE;
919
- const m = t >= "KeyA" && t <= "KeyZ", E = n.getModifierState("CapsLock"), g = n.shiftKey;
920
- let y = g;
921
- return m && (y = g !== E), y && (a |= s.META_SHIFT_ON), n.ctrlKey && (a |= s.META_CTRL_ON), n.altKey && (a |= s.META_ALT_ON), n.metaKey && (a |= s.META_META_ON), { keycode: c, metaState: a };
922
- }
923
- const di = En(
924
- ({
925
- className: n,
926
- url: t,
927
- token: c,
928
- sessionId: a,
929
- openUrl: m,
930
- showFrame: E = !0,
931
- autoReconnect: g = !1,
932
- onTerminated: y,
933
- assets: Y,
934
- onConnectionStateChange: D,
935
- inspectMode: R,
936
- onAxSnapshotChange: b,
937
- onInspectSelectionChange: ie,
938
- onAxStatusChange: de,
939
- axPollIntervalMs: me,
940
- axMaxBackoffMs: lt,
941
- androidElementTreeOptions: Se,
942
- onCameraDemandChange: X,
943
- onCameraStats: oe,
944
- microphoneEnabled: j = !1,
945
- onMicrophoneStateChange: $
946
- }, Ee) => {
947
- const be = v(null), x = v(null), pe = v(null), [Ge, ge] = z(!1), [Vt, Je] = z(!1), [bt, Gt] = z(!1), Ne = v(!1), Nt = v(!1), [Jt, Kr] = z(!1), [kr, Pr] = z(!1), [Lr, zt] = z({}), T = v(null), H = v(null), P = v(null), Ie = v(void 0), ze = v(void 0), je = v(void 0), dt = v(void 0), Ye = v(void 0), Ce = v(0), ft = v(0), Ke = v(!1), It = v(g);
948
- It.current = g;
949
- const ye = v(null), Q = v(null), Oe = v(void 0), Yt = Me(() => new Un(), []), ue = v(X);
950
- ue.current = X;
951
- const ht = v(oe);
952
- ht.current = oe;
953
- const Qe = v(null), mt = v(null), Kt = v(j);
954
- Kt.current = j;
955
- const kt = v(!1), Ze = v($);
956
- Ze.current = $;
957
- const et = v(null), ce = v(null), Et = v(0), jt = v(Promise.resolve()), ke = v(null), tt = v(!1), fe = v(/* @__PURE__ */ new Map()), le = v(/* @__PURE__ */ new Map()), ve = v(/* @__PURE__ */ new Map()), _e = v(/* @__PURE__ */ new Map()), V = v(/* @__PURE__ */ new Map()), De = v(!1), [Ur, xr] = z(!1), B = v(null), Pe = v(null), rt = v({
958
- handle: () => {
959
- },
960
- end: () => {
961
- }
962
- }), [Te, pt] = z(null), G = v(null), [Qt, Zt] = z(null), [Pt, nt] = z(null), [Lt, gt] = z(null), [Fr, er] = z(null), [Wr, tr] = z(null), Ct = v(null), ee = v(void 0), rr = (e) => {
963
- Ct.current = e, ee.current === void 0 && (ee.current = window.requestAnimationFrame(() => {
964
- ee.current = void 0, tr(Ct.current);
965
- }));
966
- }, [Hr, Le] = z(null), Ue = v(R);
967
- Ue.current = R;
968
- const xe = v(null);
969
- xe.current = Qt;
970
- const Ut = v(b);
971
- Ut.current = b;
972
- const Fe = v(ie);
973
- Fe.current = ie;
974
- const nr = v(de);
975
- nr.current = de;
976
- const ir = v(y);
977
- ir.current = y;
978
- const or = v(D);
979
- or.current = D;
980
- const xt = v(null), We = (e) => {
981
- xt.current !== e && (xt.current = e, U("onConnectionStateChange", or.current, e));
982
- }, it = R === !0 || R === "hover-only", $r = R === "hover-only" ? "hover-only" : "select", re = Me(
983
- () => a || Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15),
984
- [a]
985
- ), se = Me(() => Qn(t), [t]), He = ii[se], ot = Y?.[se], cr = se === "android" && kr ? Jt ? ot?.tabletFrameLandscape : ot?.tabletFrame : Jt ? ot?.frameLandscape : ot?.frame, sr = ot?.loadingLogo, yt = E && !!cr, K = (e) => {
986
- F(e);
987
- }, ne = (e) => {
988
- !P.current || P.current.readyState !== "open" || (P.current.send(e), G.current?.bumpActivity());
989
- }, ar = -10, ur = (e, o) => {
990
- const r = ct();
991
- if (!r) return;
992
- const i = Xe(r, e, o);
993
- if (!i) return;
994
- const { videoX: h, videoY: l, videoWidth: f, videoHeight: u } = i, p = At(
995
- L.ACTION_DOWN,
996
- ar,
997
- f,
998
- u,
999
- h,
1000
- l,
1001
- 1,
1002
- L.BUTTON_PRIMARY,
1003
- L.BUTTON_PRIMARY
1004
- );
1005
- p && ne(p), window.setTimeout(() => {
1006
- const O = At(
1007
- L.ACTION_UP,
1008
- ar,
1009
- f,
1010
- u,
1011
- h,
1012
- l,
1013
- 0,
1014
- L.BUTTON_PRIMARY,
1015
- L.BUTTON_PRIMARY
1016
- );
1017
- O && ne(O);
1018
- }, 60);
1019
- }, Xr = (e, o) => {
1020
- const r = ct();
1021
- if (!r || o.screen.width <= 0 || o.screen.height <= 0) return;
1022
- const i = e.frame.x + e.frame.width / 2, h = e.frame.y + e.frame.height / 2, l = i / o.screen.width * r.actualWidth, f = h / o.screen.height * r.actualHeight, u = r.videoRect.left + r.offsetX + l, p = r.videoRect.top + r.offsetY + f;
1023
- ur(u, p);
1024
- }, Ot = -1, vt = -2, we = -3, $e = (e, o, r, i, h, l) => {
1025
- const f = At(
1026
- e,
1027
- o,
1028
- r,
1029
- i,
1030
- h,
1031
- l,
1032
- 1,
1033
- // pressure
1034
- L.BUTTON_PRIMARY,
1035
- L.BUTTON_PRIMARY
1036
- );
1037
- f && (F("[rc-touch] sendSingleTouch", {
1038
- action: e,
1039
- actionName: Mt(e),
1040
- pointerId: o,
1041
- x: h,
1042
- y: l,
1043
- video: { width: r, height: i }
1044
- }), ne(f));
1045
- }, Ae = (e, o, r) => {
1046
- if (!r) return;
1047
- const { videoX: i, videoY: h, videoWidth: l, videoHeight: f } = r;
1048
- let u = null, p = null, O = 1;
1049
- const S = L.BUTTON_PRIMARY;
1050
- switch (o) {
1051
- case "down":
1052
- e !== we && rt.current.end(), u = V.current.size === 0 ? L.ACTION_DOWN : L.ACTION_POINTER_DOWN, p = { x: i, y: h }, V.current.set(e, p), e === -1 && x.current?.focus();
1053
- break;
1054
- case "move":
1055
- V.current.has(e) && (u = L.ACTION_MOVE, p = { x: i, y: h }, V.current.set(e, p));
1056
- break;
1057
- case "up":
1058
- case "cancel":
1059
- V.current.has(e) && (p = V.current.get(e), V.current.delete(e), o === "cancel" ? u = L.ACTION_CANCEL : u = V.current.size === 0 ? L.ACTION_UP : L.ACTION_POINTER_UP);
1060
- break;
1061
- }
1062
- if (u !== null && p !== null) {
1063
- F("[rc-touch][mouse->touch] sending", {
1064
- pointerId: e,
1065
- eventType: o,
1066
- action: u,
1067
- actionName: Mt(u),
1068
- positionToSend: p,
1069
- video: { width: l, height: f },
1070
- altHeld: De.current,
1071
- activePointersAfter: Array.from(V.current.entries()).map(([A, C]) => ({
1072
- id: A,
1073
- x: C.x,
1074
- y: C.y
1075
- }))
1076
- });
1077
- const _ = At(
1078
- u,
1079
- e,
1080
- l,
1081
- f,
1082
- p.x,
1083
- p.y,
1084
- O,
1085
- S,
1086
- S
1087
- );
1088
- _ && (F("[rc-touch][mouse->touch] buffer", {
1089
- pointerId: e,
1090
- actionName: Mt(u),
1091
- byteLength: _.byteLength
1092
- }), ne(_));
1093
- } else (o === "up" || o === "cancel") && V.current.delete(e);
1094
- }, Ft = (e) => {
1095
- if (De.current !== e && (De.current = e, xr(e), e || pt(null), F("[rc-touch][alt] updateAltHeld", {
1096
- nextHeld: e,
1097
- activePointerIds: Array.from(V.current.keys())
1098
- }), se === "ios" && P.current && P.current.readyState === "open")) {
1099
- const o = e ? s.ACTION_DOWN : s.ACTION_UP, r = ut(
1100
- o,
1101
- s.KEYCODE_ALT_LEFT,
1102
- 0,
1103
- s.META_NONE
1104
- );
1105
- F("[rc-touch][alt] sending Indigo modifier keycode", {
1106
- action: o,
1107
- keycode: s.KEYCODE_ALT_LEFT
1108
- }), r && ne(r);
1109
- }
1110
- }, ct = () => {
1111
- const e = x.current, o = be.current;
1112
- if (!e || !o) return null;
1113
- const r = e.videoWidth, i = e.videoHeight;
1114
- if (!r || !i) return null;
1115
- const h = e.getBoundingClientRect(), l = o.getBoundingClientRect(), f = h.width, u = h.height, p = r / i, O = f / u;
1116
- let S = f, _ = u;
1117
- p > O ? _ = f / p : S = u * p;
1118
- const A = (f - S) / 2, C = (u - _) / 2;
1119
- return {
1120
- videoWidth: r,
1121
- videoHeight: i,
1122
- videoRect: h,
1123
- containerRect: l,
1124
- actualWidth: S,
1125
- actualHeight: _,
1126
- offsetX: A,
1127
- offsetY: C
1128
- };
1129
- }, Xe = (e, o, r) => {
1130
- const i = o - e.videoRect.left - e.offsetX, h = r - e.videoRect.top - e.offsetY, l = Math.max(0, Math.min(e.actualWidth, i)), f = Math.max(0, Math.min(e.actualHeight, h)), u = Math.max(
1131
- 0,
1132
- Math.min(e.videoWidth, l / e.actualWidth * e.videoWidth)
1133
- ), p = Math.max(
1134
- 0,
1135
- Math.min(e.videoHeight, f / e.actualHeight * e.videoHeight)
1136
- );
1137
- return {
1138
- videoX: u,
1139
- videoY: p,
1140
- videoWidth: e.videoWidth,
1141
- videoHeight: e.videoHeight
1142
- };
1143
- }, Br = (e, o, r) => {
1144
- const i = o - e.videoRect.left - e.offsetX, h = r - e.videoRect.top - e.offsetY, l = Math.max(0, Math.min(e.actualWidth, i)), f = Math.max(0, Math.min(e.actualHeight, h)), u = Math.max(
1145
- 0,
1146
- Math.min(e.videoWidth, l / e.actualWidth * e.videoWidth)
1147
- ), p = Math.max(
1148
- 0,
1149
- Math.min(e.videoHeight, f / e.actualHeight * e.videoHeight)
1150
- ), O = e.videoWidth - u, S = e.videoHeight - p, _ = e.videoRect.left + e.offsetX, A = e.videoRect.top + e.offsetY, C = _ - e.containerRect.left + l, d = A - e.containerRect.top + f, N = _ - e.containerRect.left + (e.actualWidth - l), k = A - e.containerRect.top + (e.actualHeight - f);
1151
- return {
1152
- containerX: C,
1153
- containerY: d,
1154
- mirrorContainerX: N,
1155
- mirrorContainerY: k,
1156
- videoX: u,
1157
- videoY: p,
1158
- mirrorVideoX: O,
1159
- mirrorVideoY: S,
1160
- videoWidth: e.videoWidth,
1161
- videoHeight: e.videoHeight
1162
- };
1163
- }, qr = (e, o, r, i, h, l, f) => {
1164
- const u = Cn(e, o, r, i, h, l, f);
1165
- F("[rc-touch2] sendTwoFingerMessage (iOS)", {
1166
- actionName: Mt(e),
1167
- video: { width: o, height: r },
1168
- p0: { x: i, y: h },
1169
- p1: { x: l, y: f },
1170
- byteLength: u.byteLength
1171
- }), ne(u);
1172
- }, Be = (e, o, r, i, h, l, f, u, p) => {
1173
- if (F("[rc-touch2] applyTwoFingerEvent", {
1174
- platform: se,
1175
- eventType: e,
1176
- video: { width: o, height: r },
1177
- p0: { x: i, y: h, id: u },
1178
- p1: { x: l, y: f, id: p }
1179
- }), e === "down" && rt.current.end(), se === "ios") {
1180
- const O = e === "down" ? L.ACTION_DOWN : e === "move" ? L.ACTION_MOVE : L.ACTION_UP;
1181
- qr(O, o, r, i, h, l, f);
1182
- } else
1183
- e === "down" ? ($e(L.ACTION_DOWN, u, o, r, i, h), $e(L.ACTION_POINTER_DOWN, p, o, r, l, f)) : e === "move" ? ($e(L.ACTION_MOVE, u, o, r, i, h), $e(L.ACTION_MOVE, p, o, r, l, f)) : ($e(L.ACTION_POINTER_UP, p, o, r, l, f), $e(L.ACTION_UP, u, o, r, i, h));
1184
- }, Vr = (e, o, r) => {
1185
- if (!De.current) {
1186
- Te !== null && pt(null);
1187
- return;
1188
- }
1189
- const i = Br(e, o, r);
1190
- pt(i);
1191
- }, Gr = (e, o, r) => {
1192
- const i = xe.current;
1193
- if (!i || i.screen.width <= 0 || i.screen.height <= 0) return null;
1194
- const h = o - e.videoRect.left - e.offsetX, l = r - e.videoRect.top - e.offsetY;
1195
- if (h < 0 || l < 0 || h > e.actualWidth || l > e.actualHeight) return null;
1196
- const f = h / e.actualWidth * i.screen.width, u = l / e.actualHeight * i.screen.height;
1197
- return Sn(i, f, u);
1198
- }, he = (e) => {
1199
- e.preventDefault(), e.stopPropagation();
1200
- const o = ct();
1201
- if ((Ue.current === !0 || Ue.current === "hover-only") && !("touches" in e))
1202
- if (e.type === "mousemove") {
1203
- if (rr({ x: e.clientX, y: e.clientY }), o) {
1204
- const i = Gr(o, e.clientX, e.clientY);
1205
- nt(i?.id ?? null);
1206
- }
1207
- } else e.type === "mouseleave" && (rr(null), nt(null));
1208
- if (Ue.current !== !0 && (!("touches" in e) && o && (e.type === "mousemove" ? Vr(o, e.clientX, e.clientY) : e.type === "mouseleave" && pt(null)), !(!P.current || P.current.readyState !== "open" || !x.current || !o)))
1209
- if ("touches" in e) {
1210
- const i = e.touches, h = e.changedTouches;
1211
- let l;
1212
- switch (e.type) {
1213
- case "touchstart":
1214
- l = "down";
1215
- break;
1216
- case "touchmove":
1217
- l = "move";
1218
- break;
1219
- case "touchend":
1220
- l = "up";
1221
- break;
1222
- case "touchcancel":
1223
- l = "cancel";
1224
- break;
1225
- default:
1226
- return;
1227
- }
1228
- if (i.length === 2) {
1229
- const f = i[0], u = i[1], p = Xe(o, f.clientX, f.clientY), O = Xe(o, u.clientX, u.clientY);
1230
- if (!p || !O) return;
1231
- B.current ? B.current.source === "real-touch" && (B.current.finger0 = { x: p.videoX, y: p.videoY }, B.current.finger1 = { x: O.videoX, y: O.videoY }, Be(
1232
- "move",
1233
- p.videoWidth,
1234
- p.videoHeight,
1235
- p.videoX,
1236
- p.videoY,
1237
- O.videoX,
1238
- O.videoY,
1239
- B.current.pointerId0,
1240
- B.current.pointerId1
1241
- )) : (B.current = {
1242
- finger0: { x: p.videoX, y: p.videoY },
1243
- finger1: { x: O.videoX, y: O.videoY },
1244
- videoSize: { width: p.videoWidth, height: p.videoHeight },
1245
- source: "real-touch",
1246
- pointerId0: f.identifier,
1247
- pointerId1: u.identifier
1248
- }, Be(
1249
- "down",
1250
- p.videoWidth,
1251
- p.videoHeight,
1252
- p.videoX,
1253
- p.videoY,
1254
- O.videoX,
1255
- O.videoY,
1256
- f.identifier,
1257
- u.identifier
1258
- ));
1259
- } else if (i.length < 2 && B.current?.source === "real-touch") {
1260
- const f = B.current;
1261
- Be(
1262
- "up",
1263
- f.videoSize.width,
1264
- f.videoSize.height,
1265
- f.finger0.x,
1266
- f.finger0.y,
1267
- f.finger1.x,
1268
- f.finger1.y,
1269
- f.pointerId0,
1270
- f.pointerId1
1271
- ), B.current = null;
1272
- return;
1273
- } else {
1274
- if (i.length > 2)
1275
- return;
1276
- {
1277
- const f = h[0];
1278
- if (f) {
1279
- const u = Xe(o, f.clientX, f.clientY);
1280
- Ae(f.identifier, l, u);
1281
- }
1282
- }
1283
- }
1284
- } else {
1285
- let h = null;
1286
- const l = B.current?.source === "alt-mouse";
1287
- switch (e.type) {
1288
- case "mousedown":
1289
- e.button === 0 && (h = "down");
1290
- break;
1291
- case "mousemove":
1292
- (l || V.current.has(-1)) && (h = "move");
1293
- break;
1294
- case "mouseup":
1295
- e.button === 0 && (h = "up");
1296
- break;
1297
- case "mouseleave":
1298
- (l || V.current.has(-1)) && (h = "up");
1299
- break;
1300
- }
1301
- if (h) {
1302
- const f = Xe(o, e.clientX, e.clientY);
1303
- if (!f)
1304
- return;
1305
- F("[rc-touch][mouse] event", {
1306
- domType: e.type,
1307
- eventType: h,
1308
- button: e.button,
1309
- buttons: e.buttons,
1310
- client: { x: e.clientX, y: e.clientY },
1311
- altHeldRef: De.current,
1312
- inTwoFingerMode: l,
1313
- geometry: {
1314
- videoX: f.videoX,
1315
- videoY: f.videoY,
1316
- videoWidth: f.videoWidth,
1317
- videoHeight: f.videoHeight
1318
- },
1319
- activePointerIds: Array.from(V.current.keys())
1320
- }), De.current || l ? Jr(h, f) : Ae(-1, h, f);
1321
- }
1322
- }
1323
- }, Jr = (e, o) => {
1324
- const { videoX: r, videoY: i, videoWidth: h, videoHeight: l } = o, f = h - r, u = l - i;
1325
- if (e === "down") {
1326
- B.current = {
1327
- finger0: { x: r, y: i },
1328
- finger1: { x: f, y: u },
1329
- videoSize: { width: h, height: l },
1330
- source: "alt-mouse",
1331
- pointerId0: Ot,
1332
- pointerId1: vt
1333
- }, x.current?.focus(), Be(
1334
- "down",
1335
- h,
1336
- l,
1337
- r,
1338
- i,
1339
- f,
1340
- u,
1341
- Ot,
1342
- vt
1343
- );
1344
- return;
1345
- }
1346
- if (e === "move") {
1347
- B.current?.source === "alt-mouse" && (B.current.finger0 = { x: r, y: i }, B.current.finger1 = { x: f, y: u }, Be(
1348
- "move",
1349
- h,
1350
- l,
1351
- r,
1352
- i,
1353
- f,
1354
- u,
1355
- Ot,
1356
- vt
1357
- ));
1358
- return;
1359
- }
1360
- if (e === "up" || e === "cancel") {
1361
- const p = B.current;
1362
- if (p?.source === "alt-mouse") {
1363
- const { finger0: O, finger1: S, videoSize: _ } = p;
1364
- Be(
1365
- "up",
1366
- _.width,
1367
- _.height,
1368
- O.x,
1369
- O.y,
1370
- S.x,
1371
- S.y,
1372
- Ot,
1373
- vt
1374
- ), B.current = null;
1375
- }
1376
- return;
1377
- }
1378
- }, zr = 150, lr = () => {
1379
- const e = Pe.current;
1380
- e && (window.clearTimeout(e.endTimer), Ae(we, "up", e.pos), Pe.current = null);
1381
- }, jr = (e) => {
1382
- if (e.ctrlKey || De.current || B.current) return;
1383
- const o = V.current.size;
1384
- if (o > 1 || o === 1 && !V.current.has(we)) return;
1385
- const r = ct();
1386
- if (!r) return;
1387
- const i = e.clientX - r.videoRect.left - r.offsetX, h = e.clientY - r.videoRect.top - r.offsetY;
1388
- if (i < 0 || i > r.actualWidth || h < 0 || h > r.actualHeight)
1389
- return;
1390
- const l = Xe(r, e.clientX, e.clientY);
1391
- if (!l) return;
1392
- e.preventDefault();
1393
- const f = (e.deltaMode === 1 ? 16 : e.deltaMode === 2 ? r.actualWidth : 1) * (r.videoWidth / r.actualWidth), u = (e.deltaMode === 1 ? 16 : e.deltaMode === 2 ? r.actualHeight : 1) * (r.videoHeight / r.actualHeight), p = -e.deltaX * f, O = -e.deltaY * u, S = (k) => {
1394
- window.clearTimeout(k.endTimer), k.endTimer = window.setTimeout(lr, zr);
1395
- };
1396
- if (p === 0 && O === 0) {
1397
- Pe.current && S(Pe.current);
1398
- return;
1399
- }
1400
- const _ = () => ({
1401
- videoWidth: l.videoWidth,
1402
- videoHeight: l.videoHeight,
1403
- videoX: Math.abs(p) > Math.abs(O) ? Math.min(Math.max(l.videoX, l.videoWidth * 0.2), l.videoWidth * 0.8) : l.videoX,
1404
- videoY: Math.abs(O) >= Math.abs(p) ? Math.min(Math.max(l.videoY, l.videoHeight * 0.2), l.videoHeight * 0.8) : l.videoY
1405
- }), A = (k) => ({
1406
- ...k,
1407
- videoX: Math.min(Math.max(k.videoX + p, 0), k.videoWidth),
1408
- videoY: Math.min(Math.max(k.videoY + O, 0), k.videoHeight)
1409
- });
1410
- let C = Pe.current;
1411
- if (C)
1412
- window.clearTimeout(C.endTimer);
1413
- else {
1414
- const k = _();
1415
- Ae(we, "down", k), C = { pos: k, endTimer: 0 }, Pe.current = C;
1416
- }
1417
- let d = C.pos, N = A(d);
1418
- N.videoX === d.videoX && N.videoY === d.videoY && (Ae(we, "up", d), d = _(), Ae(we, "down", d), N = A(d)), Ae(we, "move", N), C.pos = N, S(C);
1419
- };
1420
- ae(() => {
1421
- rt.current = { handle: jr, end: lr };
1422
- }), ae(() => {
1423
- const e = be.current;
1424
- if (!e) return;
1425
- const o = (r) => rt.current.handle(r);
1426
- return e.addEventListener("wheel", o, { passive: !1 }), () => {
1427
- rt.current.end(), e.removeEventListener("wheel", o);
1428
- };
1429
- }, []), ae(() => {
1430
- const e = (i) => {
1431
- i.key === "Alt" && Ft(!0);
1432
- }, o = (i) => {
1433
- i.key === "Alt" && Ft(!1);
1434
- }, r = () => {
1435
- Ft(!1);
1436
- };
1437
- return window.addEventListener("keydown", e, !0), window.addEventListener("keyup", o, !0), window.addEventListener("blur", r), () => {
1438
- window.removeEventListener("keydown", e, !0), window.removeEventListener("keyup", o, !0), window.removeEventListener("blur", r);
1439
- };
1440
- }, []);
1441
- const dr = (e) => {
1442
- if (e.preventDefault(), e.stopPropagation(), F("Keyboard event:", {
1443
- type: e.type,
1444
- key: e.key,
1445
- keyCode: e.keyCode,
1446
- code: e.code,
1447
- target: e.target.tagName,
1448
- focused: document.activeElement === x.current
1449
- }), document.activeElement !== x.current) {
1450
- w("Video element not focused, skipping keyboard event");
1451
- return;
1452
- }
1453
- if (!P.current || P.current.readyState !== "open") {
1454
- w("Data channel not ready for keyboard event:", P.current?.readyState);
1455
- return;
1456
- }
1457
- if (e.type === "keydown") {
1458
- if (e.key.toLowerCase() === "v" && (e.metaKey || e.ctrlKey)) {
1459
- F("Paste shortcut detected"), navigator.clipboard.readText().then((r) => {
1460
- if (r) {
1461
- F(
1462
- "Pasting text via SET_CLIPBOARD:",
1463
- r.substring(0, 20) + (r.length > 20 ? "..." : "")
1464
- );
1465
- const i = yn(r, !0);
1466
- ne(i);
1467
- }
1468
- }).catch((r) => {
1469
- console.error("Failed to read clipboard contents: ", r);
1470
- });
1471
- return;
1472
- }
1473
- if (e.key.toLowerCase() === "m" && (e.metaKey || e.ctrlKey)) {
1474
- F("Menu shortcut detected");
1475
- const r = ut(
1476
- s.ACTION_DOWN,
1477
- s.MENU,
1478
- 0,
1479
- s.META_NONE
1480
- // Modifiers are handled by the shortcut check, not passed down
1481
- );
1482
- ne(r);
1483
- const i = ut(
1484
- s.ACTION_UP,
1485
- s.MENU,
1486
- 0,
1487
- s.META_NONE
1488
- );
1489
- ne(i);
1490
- return;
1491
- }
1492
- }
1493
- const o = oi(e);
1494
- if (o) {
1495
- const { keycode: r, metaState: i } = o, h = e.type === "keydown" ? s.ACTION_DOWN : s.ACTION_UP;
1496
- F(`Sending Keycode: key=${e.key}, code=${r}, action=${h}, meta=${i}`);
1497
- const l = ut(
1498
- h,
1499
- r,
1500
- 0,
1501
- // repeat count, typically 0 for single presses
1502
- i
1503
- );
1504
- ne(l);
1505
- } else
1506
- F(`Ignoring unhandled key event: type=${e.type}, key=${e.key}`);
1507
- }, Qr = () => {
1508
- T.current && T.current.readyState === WebSocket.OPEN && T.current.send(
1509
- JSON.stringify({
1510
- type: "keepAlive",
1511
- sessionId: re
1512
- })
1513
- );
1514
- }, fr = () => {
1515
- Ie.current && window.clearInterval(Ie.current), Ie.current = window.setInterval(Qr, 1e4);
1516
- }, hr = () => {
1517
- Ie.current && (window.clearInterval(Ie.current), Ie.current = void 0);
1518
- }, _t = () => {
1519
- ze.current && (window.clearTimeout(ze.current), ze.current = void 0);
1520
- }, Dt = () => {
1521
- je.current && (window.clearTimeout(je.current), je.current = void 0);
1522
- }, st = () => {
1523
- dt.current && (window.clearInterval(dt.current), dt.current = void 0);
1524
- }, at = () => {
1525
- Ye.current !== void 0 && (window.clearTimeout(Ye.current), Ye.current = void 0);
1526
- }, Zr = () => {
1527
- tt.current || (tt.current = !0, st(), ge(!0), We("connected"));
1528
- }, J = (e) => {
1529
- for (const o of e.getTracks())
1530
- try {
1531
- o.stop();
1532
- } catch (r) {
1533
- w("track.stop() failed:", r);
1534
- }
1535
- }, en = () => {
1536
- const e = Q.current;
1537
- e && (Q.current = null, J(e));
1538
- }, mr = (e) => {
1539
- const o = jt.current.then(e).catch((r) => {
1540
- w("microphone operation failed:", r);
1541
- });
1542
- return jt.current = o, o;
1543
- }, Wt = () => Kt.current || kt.current, Er = (e) => {
1544
- const o = `ui-mic-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
1545
- ke.current = o, e.send(JSON.stringify({ type: "microphoneStart", id: o }));
1546
- }, Ht = () => mr(() => tn()), tn = async () => {
1547
- const e = Et.current, o = () => e === Et.current && Wt(), r = (u) => {
1548
- U("onMicrophoneStateChange", Ze.current, {
1549
- active: !1,
1550
- error: u
1551
- });
1552
- };
1553
- if (!o()) return;
1554
- const i = T.current, h = et.current;
1555
- if (!i || i.readyState !== WebSocket.OPEN || !h || ce.current) return;
1556
- if (!navigator.mediaDevices || typeof navigator.mediaDevices.getUserMedia != "function") {
1557
- console.warn(
1558
- "[RemoteControl] navigator.mediaDevices.getUserMedia unavailable. getUserMedia requires a secure context (https or http://localhost)."
1559
- ), r("Microphone capture requires a secure context (https)");
1560
- return;
1561
- }
1562
- let l = null;
1563
- try {
1564
- l = await navigator.mediaDevices.getUserMedia({ audio: !0, video: !1 });
1565
- } catch (u) {
1566
- console.warn("[RemoteControl] microphone getUserMedia denied/failed:", u);
1567
- }
1568
- if (!o()) {
1569
- l && J(l);
1570
- return;
1571
- }
1572
- if (!l) {
1573
- r("Microphone permission denied or no device available");
1574
- return;
1575
- }
1576
- const f = l.getAudioTracks()[0] ?? null;
1577
- if (!f) {
1578
- J(l), r("Captured stream has no audio track");
1579
- return;
1580
- }
1581
- try {
1582
- await h.replaceTrack(f);
1583
- } catch (u) {
1584
- w("replaceTrack(audioTrack) failed:", u), J(l), r("Failed to attach the microphone track to the connection");
1585
- return;
1586
- }
1587
- if (!o()) {
1588
- try {
1589
- await h.replaceTrack(null);
1590
- } catch (u) {
1591
- w("replaceTrack(null) on stale mic attach failed:", u);
1592
- }
1593
- J(l);
1594
- return;
1595
- }
1596
- ce.current = l, f.onended = () => {
1597
- ce.current === l && Tt("microphone capture ended by the browser");
1598
- }, Er(i), U("onMicrophoneStateChange", Ze.current, {
1599
- active: !0,
1600
- label: f.label || void 0
1601
- });
1602
- }, Tt = (e) => (++Et.current, ke.current = null, mr(async () => {
1603
- const o = et.current, r = ce.current;
1604
- if (ce.current = null, o && r)
1605
- try {
1606
- await o.replaceTrack(null);
1607
- } catch (h) {
1608
- w("replaceTrack(null) on mic detach failed:", h);
1609
- }
1610
- r && J(r);
1611
- const i = T.current;
1612
- if (r && i && i.readyState === WebSocket.OPEN) {
1613
- const h = `ui-mic-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
1614
- i.send(JSON.stringify({ type: "microphoneStop", id: h }));
1615
- }
1616
- (r || e) && U("onMicrophoneStateChange", Ze.current, {
1617
- active: !1,
1618
- ...e !== void 0 && { error: e }
1619
- });
1620
- })), pr = (e, o) => {
1621
- let r;
1622
- try {
1623
- r = $n(o), console.info(
1624
- `[RemoteControl] camera capture: ${r.camera?.width}x${r.camera?.height} @ ${r.camera?.frameRate ?? "?"}fps` + (r.camera?.label ? ` — ${r.camera.label}` : "")
1625
- );
1626
- } catch (i) {
1627
- w("getSettings() on outbound camera track failed:", i), r = {
1628
- type: "cameraResult",
1629
- granted: !0,
1630
- camera: {
1631
- label: o.label || void 0
1632
- }
1633
- };
1634
- }
1635
- e.send(JSON.stringify(r)), U("onCameraDemandChange", ue.current, !0, !0, r.camera);
1636
- }, rn = (e) => {
1637
- if (!e) return;
1638
- const o = e.indexOf("/"), i = (o >= 0 ? e.slice(o + 1) : e).toUpperCase();
1639
- return i === "HEVC" ? "H265" : i;
1640
- }, nn = async () => {
1641
- const e = ye.current, o = ht.current;
1642
- if (!e || !o) return;
1643
- let r;
1644
- try {
1645
- r = await e.getStats();
1646
- } catch {
1647
- return;
1648
- }
1649
- let i, h, l;
1650
- if (r.forEach((A) => {
1651
- A.type === "outbound-rtp" && A.kind === "video" ? i = A : A.type === "remote-inbound-rtp" && A.kind === "video" && (l = A);
1652
- }), i?.codecId) {
1653
- const A = r.get(i.codecId);
1654
- A && (h = A.mimeType);
1655
- }
1656
- if (!i) return;
1657
- const f = i.timestamp ?? Date.now(), u = mt.current;
1658
- let p, O, S;
1659
- if (u && f > u.timestamp) {
1660
- const A = (f - u.timestamp) / 1e3;
1661
- if (typeof i.framesEncoded == "number" && typeof u.framesEncoded == "number" && (p = Math.max(0, (i.framesEncoded - u.framesEncoded) / A)), typeof i.bytesSent == "number" && typeof u.bytesSent == "number" && (O = Math.max(0, (i.bytesSent - u.bytesSent) * 8 / A)), typeof i.packetsSent == "number" && typeof u.packetsSent == "number" && l && typeof l.packetsLost == "number" && typeof u.packetsLost == "number") {
1662
- const C = i.packetsSent - u.packetsSent, d = l.packetsLost - u.packetsLost;
1663
- C > 0 && (S = Math.max(0, Math.min(100, d / C * 100)));
1664
- }
1665
- }
1666
- mt.current = {
1667
- timestamp: f,
1668
- framesEncoded: i.framesEncoded,
1669
- bytesSent: i.bytesSent,
1670
- packetsSent: i.packetsSent,
1671
- packetsLost: l?.packetsLost
1672
- };
1673
- const _ = {
1674
- codec: rn(h),
1675
- encoderImplementation: i.encoderImplementation,
1676
- hardwareAccelerated: typeof i.powerEfficientEncoder == "boolean" ? i.powerEfficientEncoder : void 0,
1677
- framesPerSecond: p,
1678
- framesEncoded: i.framesEncoded,
1679
- bitrateBps: O,
1680
- width: i.frameWidth,
1681
- height: i.frameHeight,
1682
- qualityLimitationReason: i.qualityLimitationReason,
1683
- rttMs: typeof l?.roundTripTime == "number" ? l.roundTripTime * 1e3 : void 0,
1684
- packetsLostPct: S
1685
- };
1686
- U("onCameraStats", ht.current, _);
1687
- }, gr = () => {
1688
- Qe.current === null && (mt.current = null, Qe.current = setInterval(() => {
1689
- nn();
1690
- }, 1e3));
1691
- }, wt = () => {
1692
- Qe.current !== null && (clearInterval(Qe.current), Qe.current = null), mt.current = null, U("onCameraStats", ht.current, null);
1693
- }, on = (e, o, r, i) => Yt.enqueue(async ({ isCurrent: h }) => {
1694
- const l = () => h() && i() && T.current === o && ye.current === r;
1695
- if (!l()) return;
1696
- if (!e.active) {
1697
- const _ = Q.current;
1698
- try {
1699
- await r.replaceTrack(null);
1700
- } catch (A) {
1701
- w("replaceTrack(null) on camera detach failed:", A);
1702
- }
1703
- if (Q.current === _ && (Q.current = null, Oe.current = void 0, _ && J(_)), wt(), !l()) return;
1704
- U("onCameraDemandChange", ue.current, !1);
1705
- return;
1706
- }
1707
- U("onCameraDemandChange", ue.current, !0);
1708
- const f = Q.current, u = f?.getVideoTracks()[0], p = Oe.current;
1709
- if (u?.readyState === "live" && p && !Wn(p, e)) {
1710
- Oe.current = e, pr(o, u), gr();
1711
- return;
1712
- }
1713
- if (f) {
1714
- try {
1715
- await r.replaceTrack(null);
1716
- } catch (_) {
1717
- w("replaceTrack(null) before camera switch failed:", _);
1718
- }
1719
- if (Q.current === f && (Q.current = null, Oe.current = void 0, J(f)), wt(), !l()) return;
1720
- }
1721
- if (!navigator.mediaDevices || typeof navigator.mediaDevices.getUserMedia != "function") {
1722
- if (console.warn(
1723
- "[RemoteControl] navigator.mediaDevices.getUserMedia unavailable. getUserMedia requires a secure context (https or http://localhost). Replying cameraResult granted=false so limulator falls back to black frames."
1724
- ), !l()) return;
1725
- o.send(JSON.stringify({ type: "cameraResult", granted: !1 })), U("onCameraDemandChange", ue.current, !0, !1);
1726
- return;
1727
- }
1728
- let O = null;
1729
- try {
1730
- O = await navigator.mediaDevices.getUserMedia({
1731
- video: Fn(e),
1732
- audio: !1
1733
- });
1734
- } catch (_) {
1735
- console.warn("[RemoteControl] getUserMedia denied/failed:", _);
1736
- }
1737
- if (!l()) {
1738
- O && J(O);
1739
- return;
1740
- }
1741
- if (!O) {
1742
- o.send(JSON.stringify({ type: "cameraResult", granted: !1 })), U("onCameraDemandChange", ue.current, !0, !1);
1743
- return;
1744
- }
1745
- const S = O.getVideoTracks()[0] ?? null;
1746
- if (!S) {
1747
- if (J(O), !l()) return;
1748
- o.send(JSON.stringify({ type: "cameraResult", granted: !1 })), U("onCameraDemandChange", ue.current, !0, !1);
1749
- return;
1750
- }
1751
- try {
1752
- S.contentHint = "motion";
1753
- } catch {
1754
- }
1755
- try {
1756
- await r.replaceTrack(S);
1757
- } catch (_) {
1758
- if (w("replaceTrack(videoTrack) failed:", _), J(O), !l()) return;
1759
- o.send(JSON.stringify({ type: "cameraResult", granted: !1 })), U("onCameraDemandChange", ue.current, !0, !1);
1760
- return;
1761
- }
1762
- if (!l()) {
1763
- try {
1764
- await r.replaceTrack(null);
1765
- } catch (_) {
1766
- w("replaceTrack(null) for stale camera attach failed:", _);
1767
- }
1768
- J(O);
1769
- return;
1770
- }
1771
- try {
1772
- const _ = r.getParameters();
1773
- (!_.encodings || _.encodings.length === 0) && (_.encodings = [{}]), _.encodings[0].maxBitrate = 8e6, _.encodings[0].maxFramerate = 30, _.degradationPreference = "maintain-framerate", await r.setParameters(_);
1774
- } catch (_) {
1775
- w("setParameters on outbound camera failed:", _);
1776
- }
1777
- if (!l()) {
1778
- try {
1779
- await r.replaceTrack(null);
1780
- } catch (_) {
1781
- w("replaceTrack(null) for stale camera finalize failed:", _);
1782
- }
1783
- J(O);
1784
- return;
1785
- }
1786
- Q.current = O, Oe.current = e, S.onended = () => {
1787
- Q.current === O && Yt.enqueueCurrent(async ({ isCurrent: _ }) => {
1788
- if (!(!_() || Q.current !== O || !i() || T.current !== o || ye.current !== r)) {
1789
- try {
1790
- await r.replaceTrack(null);
1791
- } catch (A) {
1792
- w("replaceTrack(null) after camera ended failed:", A);
1793
- }
1794
- !_() || Q.current !== O || !i() || T.current !== o || ye.current !== r || (Q.current = null, Oe.current = void 0, J(O), wt(), o.send(JSON.stringify({ type: "cameraResult", granted: !1 })), U("onCameraDemandChange", ue.current, !0, !1));
1795
- }
1796
- }).catch((_) => w("camera ended cleanup failed:", _));
1797
- }, l() && (pr(o, S), gr());
1798
- }), qe = () => {
1799
- Dt(), at(), st(), G.current && (G.current.stop(), G.current = null), Yt.invalidate(), wt(), en(), Oe.current = void 0, ye.current = null, ++Et.current, kt.current = !1, ke.current = null, ce.current && (J(ce.current), ce.current = null, U("onMicrophoneStateChange", Ze.current, {
1800
- active: !1
1801
- })), et.current = null, ee.current !== void 0 && (window.cancelAnimationFrame(ee.current), ee.current = void 0), T.current && (T.current.onopen = null, T.current.onmessage = null, T.current.onerror = null, T.current.onclose = null, T.current.close(), T.current = null), H.current && (H.current.onconnectionstatechange = null, H.current.oniceconnectionstatechange = null, H.current.ontrack = null, H.current.onicecandidate = null, H.current.close(), H.current = null), x.current && (x.current.srcObject = null), P.current && (P.current.onopen = null, P.current.onclose = null, P.current.onerror = null, P.current.close(), P.current = null);
1802
- }, Cr = () => {
1803
- document.hidden ? hr() : fr();
1804
- }, cn = async () => {
1805
- if (typeof navigator < "u" && navigator.onLine === !1)
1806
- return !1;
1807
- let e;
1808
- try {
1809
- const i = new URL(t);
1810
- i.protocol = i.protocol === "wss:" ? "https:" : i.protocol === "ws:" ? "http:" : i.protocol, e = Dr(i.toString(), c);
1811
- } catch {
1812
- return !1;
1813
- }
1814
- const o = new AbortController(), r = window.setTimeout(() => o.abort(), ri);
1815
- try {
1816
- return (await fetch(e, { method: "GET", cache: "no-store", signal: o.signal })).status === 404;
1817
- } catch {
1818
- return !1;
1819
- } finally {
1820
- window.clearTimeout(r);
1821
- }
1822
- }, sn = () => {
1823
- Ne.current || (Ne.current = !0, Gt(!0), Je(!1), Ce.current += 1, _t(), Dt(), at(), qe(), K("Instance terminated"), We("terminated"), U("onTerminated", ir.current));
1824
- }, an = () => {
1825
- Ne.current || Nt.current || (Nt.current = !0, cn().then((e) => {
1826
- Nt.current = !1, e && sn();
1827
- }));
1828
- }, Ve = (e, o) => {
1829
- if (Ne.current || o !== Ce.current)
1830
- return;
1831
- if (an(), Ke.current) {
1832
- if (!It.current) {
1833
- K(`Connection failed after it was established: ${e}`), Je(!0), We("failed"), qe();
1834
- return;
1835
- }
1836
- K(`Reconnecting after established session dropped: ${e}`), Ke.current = !1, ft.current = -1;
1837
- }
1838
- _t();
1839
- const r = ft.current + 1;
1840
- if (r >= Bt) {
1841
- K(`Connection failed after ${Bt} attempts: ${e}`), Je(!0), We("failed"), qe();
1842
- return;
1843
- }
1844
- K(`Retrying connection (${r + 1}/${Bt})`), We("reconnecting"), qe(), ze.current = window.setTimeout(() => {
1845
- ze.current = void 0, o === Ce.current && yr(r);
1846
- }, Zn);
1847
- }, yr = async (e = 0) => {
1848
- if (Ne.current) return;
1849
- const o = Ce.current + 1;
1850
- Ce.current = o, ft.current = e, Ke.current = !1, Je(!1), e === 0 && xt.current !== "reconnecting" && We("connecting"), _t(), Dt(), st(), tt.current = !1, ge(!1), qe();
1851
- const r = () => o === Ce.current;
1852
- je.current = window.setTimeout(() => {
1853
- je.current = void 0, !(!r() || Ke.current) && Ve("Connection did not succeed within 15 seconds", o);
1854
- }, ei);
1855
- try {
1856
- const i = new WebSocket(Dr(t, c));
1857
- if (T.current = i, await new Promise((C, d) => {
1858
- let N = !1;
1859
- const k = window.setTimeout(() => d(new Error("WebSocket connection timeout")), 3e4), M = (I) => {
1860
- N || (N = !0, window.clearTimeout(k), I());
1861
- };
1862
- i.onopen = () => {
1863
- !r() || T.current !== i || M(C);
1864
- }, i.onerror = (I) => {
1865
- !r() || T.current !== i || (K("WebSocket error: " + I), M(() => d(new Error("WebSocket connection failed"))));
1866
- }, i.onclose = () => {
1867
- !r() || T.current !== i || (K("WebSocket closed"), M(() => d(new Error("WebSocket closed before connection was established"))));
1868
- };
1869
- }), !r() || T.current !== i)
1870
- return;
1871
- i.onerror = (C) => {
1872
- !r() || T.current !== i || K("WebSocket error: " + C);
1873
- }, i.onclose = () => {
1874
- !r() || T.current !== i || K("WebSocket closed");
1875
- };
1876
- const h = new Promise((C, d) => {
1877
- const N = (I) => {
1878
- window.clearTimeout(k), i.removeEventListener("message", M), I();
1879
- }, k = window.setTimeout(
1880
- () => N(() => d(new Error("RTCConfiguration timeout"))),
1881
- 3e4
1882
- ), M = (I) => {
1883
- if (!(!r() || T.current !== i))
1884
- try {
1885
- const q = JSON.parse(I.data);
1886
- if (q.type === "signalingError" && q.requestType === "requestRtcConfiguration" && q.sessionId === re) {
1887
- const Z = typeof q.error == "string" ? q.error : "Unable to load streaming configuration";
1888
- N(() => d(new Error(Z)));
1889
- } else q.type === "rtcConfiguration" && N(
1890
- () => C({
1891
- rtcConfiguration: q.rtcConfiguration,
1892
- cameraSupported: q.cameraSupported === !0
1893
- })
1894
- );
1895
- } catch (q) {
1896
- console.error("Error handling RTC configuration:", q), N(() => d(q));
1897
- }
1898
- };
1899
- i.addEventListener("message", M), i.send(
1900
- JSON.stringify({
1901
- type: "requestRtcConfiguration",
1902
- sessionId: re
1903
- })
1904
- );
1905
- }), { rtcConfiguration: l, cameraSupported: f } = await h;
1906
- if (!r() || T.current !== i)
1907
- return;
1908
- const u = new RTCPeerConnection(l);
1909
- H.current = u, u.addTransceiver("audio", { direction: "recvonly" });
1910
- const p = u.addTransceiver("video", { direction: "recvonly" }), O = se === "ios" || f, S = O ? u.addTransceiver("video", {
1911
- direction: "sendonly"
1912
- }) : null;
1913
- ye.current = S?.sender ?? null;
1914
- const _ = O ? u.addTransceiver("audio", {
1915
- direction: "sendonly"
1916
- }) : null;
1917
- if (et.current = _?.sender ?? null, RTCRtpReceiver.getCapabilities) {
1918
- const C = RTCRtpReceiver.getCapabilities("video");
1919
- if (C && C.codecs) {
1920
- const N = C.codecs.sort((k, M) => {
1921
- const I = (q) => {
1922
- const Z = q.mimeType.toLowerCase();
1923
- return Z.includes("vp9") ? 1 : Z.includes("h265") || Z.includes("hevc") ? 2 : Z.includes("h264") || Z.includes("avc") ? 3 : 4;
1924
- };
1925
- return I(k) - I(M);
1926
- });
1927
- p.setCodecPreferences(N), F("Set codec preferences:", N.map((k) => k.mimeType).join(", "));
1928
- }
1929
- }
1930
- if (S && RTCRtpSender.getCapabilities) {
1931
- const C = RTCRtpSender.getCapabilities("video");
1932
- if (C && C.codecs) {
1933
- const d = /* @__PURE__ */ new Set(["42e01f", "42e028", "640c1f"]), N = (M) => {
1934
- const I = M.mimeType.toLowerCase(), Z = (M.sdpFmtpLine || "").toLowerCase().match(/profile-level-id=([0-9a-f]{6})/), hn = Z ? Z[1] : "";
1935
- return I === "video/h265" || I === "video/hevc" ? 1 : I === "video/h264" && d.has(hn) ? 2 : I === "video/h264" ? 3 : I === "video/vp9" ? 4 : I === "video/vp8" ? 5 : I === "video/rtx" || I === "video/red" || I === "video/ulpfec" ? 0 : 6;
1936
- }, k = [...C.codecs].sort((M, I) => N(M) - N(I));
1937
- try {
1938
- S.setCodecPreferences(k), F(
1939
- "Outbound camera codec preferences:",
1940
- k.map((M) => `${M.mimeType}${M.sdpFmtpLine ? `[${M.sdpFmtpLine}]` : ""}`).join(", ")
1941
- );
1942
- } catch (M) {
1943
- w("Failed to set outbound camera codec preferences:", M);
1944
- }
1945
- }
1946
- }
1947
- const A = u.createDataChannel("control", {
1948
- ordered: !0,
1949
- negotiated: !0,
1950
- id: 1
1951
- });
1952
- if (P.current = A, A.onopen = () => {
1953
- if (!r() || P.current !== A || T.current !== i)
1954
- return;
1955
- Ke.current = !0, Dt(), K("Control channel opened"), G.current || (G.current = new Ln({
1956
- platform: se,
1957
- baseIntervalMs: me,
1958
- maxBackoffMs: lt,
1959
- androidElementTreeOptions: Se,
1960
- send: (d) => {
1961
- if (!T.current || T.current.readyState !== WebSocket.OPEN) return !1;
1962
- try {
1963
- return T.current.send(JSON.stringify(d)), !0;
1964
- } catch {
1965
- return !1;
1966
- }
1967
- },
1968
- onSnapshot: (d) => {
1969
- Zt((N) => Nr(N, d) ? N : d), queueMicrotask(() => {
1970
- U("onAxSnapshotChange", Ut.current, d);
1971
- });
1972
- },
1973
- onStatusChange: (d, N) => {
1974
- U("onAxStatusChange", nr.current, d, N);
1975
- }
1976
- }), (Ue.current === !0 || Ue.current === "hover-only") && G.current.start());
1977
- const C = () => {
1978
- !r() || tt.current || P.current !== A || T.current !== i || i.readyState !== WebSocket.OPEN || i.send(JSON.stringify({ type: "requestFrame", sessionId: re }));
1979
- };
1980
- if (C(), st(), dt.current = window.setInterval(() => {
1981
- if (!r() || tt.current || P.current !== A || T.current !== i || i.readyState !== WebSocket.OPEN) {
1982
- st();
1983
- return;
1984
- }
1985
- C();
1986
- }, 250), m) {
1987
- try {
1988
- const d = decodeURIComponent(m);
1989
- K("Opening URL"), i.send(
1990
- JSON.stringify({
1991
- type: "openUrl",
1992
- url: d,
1993
- sessionId: re
1994
- })
1995
- );
1996
- } catch (d) {
1997
- console.error({ error: d }, "Error decoding URL, falling back to the original URL"), i.send(
1998
- JSON.stringify({
1999
- type: "openUrl",
2000
- url: m,
2001
- sessionId: re
2002
- })
2003
- );
2004
- }
2005
- G.current?.bumpActivity();
2006
- }
2007
- }, A.onclose = () => {
2008
- !r() || P.current !== A || K("Control channel closed");
2009
- }, A.onerror = (C) => {
2010
- !r() || P.current !== A || (console.error("Control channel error:", C), K("Control channel error: " + C));
2011
- }, u.onconnectionstatechange = () => {
2012
- !r() || H.current !== u || (K("Connection state: " + u.connectionState), u.connectionState === "failed" && Ve("WebRTC connection entered failed state", o));
2013
- }, u.oniceconnectionstatechange = () => {
2014
- if (!r() || H.current !== u)
2015
- return;
2016
- const C = u.iceConnectionState;
2017
- if (K("ICE state: " + C), C === "connected" || C === "completed") {
2018
- at(), Wt() && !ce.current && Ht();
2019
- return;
2020
- }
2021
- if (C === "failed") {
2022
- at(), Ve("ICE connection entered failed state", o);
2023
- return;
2024
- }
2025
- C === "disconnected" && It.current && Ye.current === void 0 && (Ye.current = window.setTimeout(() => {
2026
- Ye.current = void 0, !(!r() || H.current !== u) && u.iceConnectionState === "disconnected" && Ve("ICE stayed disconnected past grace period", o);
2027
- }, ti));
2028
- }, u.ontrack = (C) => {
2029
- !r() || H.current !== u || (K("Received remote track: " + C.track.kind), C.track.kind === "video" && x.current && (F(`[${(/* @__PURE__ */ new Date()).toISOString()}] Video track received:`, C.track), x.current.srcObject = C.streams[0]));
2030
- }, u.onicecandidate = (C) => {
2031
- if (!(!r() || H.current !== u || T.current !== i))
2032
- if (C.candidate && i.readyState === WebSocket.OPEN) {
2033
- const d = {
2034
- type: "candidate",
2035
- candidate: C.candidate.candidate,
2036
- sdpMid: C.candidate.sdpMid,
2037
- sdpMLineIndex: C.candidate.sdpMLineIndex,
2038
- sessionId: re
2039
- };
2040
- i.send(JSON.stringify(d)), K("Sent ICE candidate");
2041
- } else
2042
- K("ICE candidate gathering completed");
2043
- }, i.onmessage = async (C) => {
2044
- if (!r() || T.current !== i)
2045
- return;
2046
- let d;
2047
- try {
2048
- d = JSON.parse(C.data);
2049
- } catch (N) {
2050
- w("Error parsing message:", N);
2051
- return;
2052
- }
2053
- if (!G.current?.handleMessage(d))
2054
- switch (K("Received: " + d.type), d.type) {
2055
- case "signalingError": {
2056
- if (d.requestType !== "offer" || d.sessionId !== re)
2057
- break;
2058
- const M = typeof d.error == "string" ? d.error : "Unable to establish the streaming connection";
2059
- K("Error: " + M), Ve(M, o);
2060
- break;
2061
- }
2062
- case "answer":
2063
- if (!H.current || H.current !== u) {
2064
- K("No peer connection, skipping answer");
2065
- break;
2066
- }
2067
- if (await u.setRemoteDescription(
2068
- new RTCSessionDescription({
2069
- type: "answer",
2070
- sdp: d.sdp
2071
- })
2072
- ), !r() || H.current !== u)
2073
- return;
2074
- K("Set remote description");
2075
- break;
2076
- case "candidate":
2077
- if (!H.current || H.current !== u) {
2078
- K("No peer connection, skipping candidate");
2079
- break;
2080
- }
2081
- if (await u.addIceCandidate(
2082
- new RTCIceCandidate({
2083
- candidate: d.candidate,
2084
- sdpMid: d.sdpMid,
2085
- sdpMLineIndex: d.sdpMLineIndex
2086
- })
2087
- ), !r() || H.current !== u)
2088
- return;
2089
- K("Added ICE candidate");
2090
- break;
2091
- case "screenshot":
2092
- case "screenshotResult": {
2093
- if (typeof d.id != "string") {
2094
- w("Received invalid screenshot success message:", d);
2095
- break;
2096
- }
2097
- const M = ci(d);
2098
- if (M) {
2099
- const Z = le.current.get(d.id);
2100
- if (!Z) {
2101
- w(`Received screenshot error for unknown or handled id: ${d.id}`);
2102
- break;
2103
- }
2104
- w(`Received screenshot error for id ${d.id}: ${M}`), Z(new Error(M)), fe.current.delete(d.id), le.current.delete(d.id);
2105
- break;
2106
- }
2107
- const I = si(d);
2108
- if (!I) {
2109
- w("Received screenshot message without image data:", d);
2110
- break;
2111
- }
2112
- const q = fe.current.get(d.id);
2113
- if (!q) {
2114
- w(`Received screenshot data for unknown or handled id: ${d.id}`);
2115
- break;
2116
- }
2117
- F(`Received screenshot data for id ${d.id}`), q(I), fe.current.delete(d.id), le.current.delete(d.id);
2118
- break;
2119
- }
2120
- case "screenshotError":
2121
- if (typeof d.id != "string" || typeof d.message != "string") {
2122
- w("Received invalid screenshot error message:", d);
2123
- break;
2124
- }
2125
- const N = le.current.get(d.id);
2126
- if (!N) {
2127
- w(`Received screenshot error for unknown or handled id: ${d.id}`);
2128
- break;
2129
- }
2130
- w(`Received screenshot error for id ${d.id}: ${d.message}`), N(new Error(d.message)), fe.current.delete(d.id), le.current.delete(d.id);
2131
- break;
2132
- case "cameraRequest": {
2133
- const M = ye.current;
2134
- if (!M)
2135
- break;
2136
- const I = xn(d);
2137
- if (!I) {
2138
- w("Received invalid cameraRequest:", d);
2139
- break;
2140
- }
2141
- console.info("[RemoteControl] cameraRequest received:", I.active, I.facingMode), await on(I, i, M, r);
2142
- break;
2143
- }
2144
- case "microphoneRequest": {
2145
- if (!et.current)
2146
- break;
2147
- const M = d.active === !0;
2148
- if (kt.current = M, console.info("[RemoteControl] microphoneRequest received, active=", M), !M) {
2149
- Kt.current || await Tt();
2150
- break;
2151
- }
2152
- if (ce.current) {
2153
- Er(i);
2154
- break;
2155
- }
2156
- await Ht();
2157
- break;
2158
- }
2159
- case "microphoneStartResult": {
2160
- if (ke.current === null || d.id !== ke.current)
2161
- break;
2162
- ke.current = null, typeof d.error == "string" && (console.warn("[RemoteControl] microphoneStart rejected by host:", d.error), Tt(d.error));
2163
- break;
2164
- }
2165
- case "terminateAppResult":
2166
- if (typeof d.id != "string") {
2167
- w("Received invalid terminateApp result message:", d);
2168
- break;
2169
- }
2170
- if (typeof d.error == "string") {
2171
- const M = _e.current.get(d.id);
2172
- if (!M) {
2173
- w(`Received terminateApp error for unknown or handled id: ${d.id}`);
2174
- break;
2175
- }
2176
- w(`Received terminateApp error for id ${d.id}: ${d.error}`), M(new Error(d.error)), ve.current.delete(d.id), _e.current.delete(d.id);
2177
- break;
2178
- }
2179
- const k = ve.current.get(d.id);
2180
- if (!k) {
2181
- w(`Received terminateApp result for unknown or handled id: ${d.id}`);
2182
- break;
2183
- }
2184
- F(`Received terminateApp success for id ${d.id}`), k(), ve.current.delete(d.id), _e.current.delete(d.id);
2185
- break;
2186
- default:
2187
- w(`Received unhandled message type: ${d.type}`, d);
2188
- break;
2189
- }
2190
- }, H.current === u) {
2191
- const C = await u.createOffer({
2192
- offerToReceiveVideo: !0,
2193
- offerToReceiveAudio: !1
2194
- });
2195
- if (!r() || H.current !== u || (await u.setLocalDescription(C), !r() || H.current !== u))
2196
- return;
2197
- r() && T.current === i && i.readyState === WebSocket.OPEN && i.send(
2198
- JSON.stringify({
2199
- type: "offer",
2200
- sdp: C.sdp,
2201
- sessionId: re
2202
- })
2203
- ), K("Sent offer");
2204
- }
2205
- } catch (i) {
2206
- if (!r())
2207
- return;
2208
- const h = i instanceof Error ? i.message : String(i);
2209
- K("Error: " + h), Ve(h, o);
2210
- }
2211
- }, $t = () => {
2212
- Ne.current = !1, Gt(!1), yr(0);
2213
- }, un = () => {
2214
- Ce.current += 1, ft.current = 0, Ke.current = !1, _t(), at(), qe(), K("Stopped");
2215
- }, ln = (e) => {
2216
- e.stopPropagation(), $t();
2217
- };
2218
- ae(() => {
2219
- Wt() ? Ht() : Tt();
2220
- }, [j]), ae(() => (ge(!1), $t(), document.hidden || fr(), document.addEventListener("visibilitychange", Cr), () => {
2221
- hr(), un(), document.removeEventListener("visibilitychange", Cr);
2222
- }), [t, c, a]);
2223
- const Or = () => {
2224
- const e = ct();
2225
- if (!e) {
2226
- er(null);
2227
- return;
2228
- }
2229
- const o = {
2230
- left: e.videoRect.left - e.containerRect.left + e.offsetX,
2231
- top: e.videoRect.top - e.containerRect.top + e.offsetY,
2232
- width: e.actualWidth,
2233
- height: e.actualHeight
2234
- };
2235
- er(
2236
- (r) => r && r.left === o.left && r.top === o.top && r.width === o.width && r.height === o.height ? r : o
2237
- );
2238
- };
2239
- ae(() => {
2240
- const e = x.current, o = pe.current, r = be.current;
2241
- if (!e) return;
2242
- const i = () => {
2243
- if (!yt || !o) {
2244
- zt({}), Or();
2245
- return;
2246
- }
2247
- const f = o.clientWidth, u = o.clientHeight;
2248
- if (f === 0 || u === 0) return;
2249
- const p = e.videoWidth > e.videoHeight;
2250
- Kr(p), Pr(
2251
- se === "android" && ni(e.videoWidth, e.videoHeight)
2252
- );
2253
- const O = p ? He.videoPosition.landscape : He.videoPosition.portrait;
2254
- let S = {};
2255
- O.heightMultiplier ? (S.height = `${u * O.heightMultiplier}px`, S.width = "auto") : O.widthMultiplier && (S.width = `${f * O.widthMultiplier}px`, S.height = "auto"), S.borderRadius = `${p ? u * He.videoBorderRadiusMultiplier : f * He.videoBorderRadiusMultiplier}px`, zt(S), Or();
2256
- }, h = new ResizeObserver(() => {
2257
- i();
2258
- });
2259
- o && h.observe(o), h.observe(e), r && h.observe(r), o && o.addEventListener("load", i), e.addEventListener("loadedmetadata", i), e.addEventListener("resize", i);
2260
- const l = () => G.current?.bumpActivity();
2261
- return e.addEventListener("resize", l), i(), () => {
2262
- h.disconnect(), e.removeEventListener("loadedmetadata", i), e.removeEventListener("resize", i), e.removeEventListener("resize", l), o && o.removeEventListener("load", i);
2263
- };
2264
- }, [He, yt]), ae(() => {
2265
- const e = G.current;
2266
- it ? e?.start() : (e?.stop(), Zt(null), nt(null), gt(null), tr(null), Le(null), Ct.current = null, ee.current !== void 0 && (window.cancelAnimationFrame(ee.current), ee.current = void 0), U("onAxSnapshotChange", Ut.current, null));
2267
- }, [it]), ae(() => () => {
2268
- ee.current !== void 0 && (window.cancelAnimationFrame(ee.current), ee.current = void 0);
2269
- }, []), ae(() => {
2270
- if (!it) return;
2271
- const e = (o) => {
2272
- o.key === "Escape" && (Lt || Pt) && (gt(null), nt(null), Le(null), U("onInspectSelectionChange", Fe.current, null));
2273
- };
2274
- return window.addEventListener("keydown", e), () => window.removeEventListener("keydown", e);
2275
- }, [it, Lt, Pt]);
2276
- const dn = () => {
2277
- x.current && x.current.focus();
2278
- };
2279
- pn(Ee, () => ({
2280
- openUrl: (e) => {
2281
- if (!T.current || T.current.readyState !== WebSocket.OPEN) {
2282
- w("WebSocket not open, cannot send open_url command via ref.");
2283
- return;
2284
- }
2285
- try {
2286
- const o = decodeURIComponent(e);
2287
- K("Opening URL"), T.current.send(
2288
- JSON.stringify({
2289
- type: "openUrl",
2290
- url: o,
2291
- sessionId: re
2292
- })
2293
- );
2294
- } catch (o) {
2295
- w("Error decoding or sending URL via ref:", { error: o, url: e }), T.current.send(
2296
- JSON.stringify({
2297
- type: "openUrl",
2298
- url: e,
2299
- sessionId: re
2300
- })
2301
- );
2302
- }
2303
- G.current?.bumpActivity();
2304
- },
2305
- sendKeyEvent: (e) => {
2306
- if (!P.current || P.current.readyState !== "open") {
2307
- w("Data channel not ready for imperative key command:", P.current?.readyState);
2308
- return;
2309
- }
2310
- const o = Rr[e.code];
2311
- if (!o) {
2312
- w(`Unknown event.code for imperative command: ${e.code}`);
2313
- return;
2314
- }
2315
- let r = s.META_NONE;
2316
- e.shiftKey && (r |= s.META_SHIFT_ON), e.altKey && (r |= s.META_ALT_ON), e.ctrlKey && (r |= s.META_CTRL_ON), e.metaKey && (r |= s.META_META_ON);
2317
- const i = e.type === "keydown" ? s.ACTION_DOWN : s.ACTION_UP;
2318
- F(
2319
- `Sending Imperative Key Command: code=${e.code}, keycode=${o}, action=${i}, meta=${r}`
2320
- );
2321
- const h = ut(
2322
- i,
2323
- o,
2324
- 0,
2325
- // repeat count, typically 0 for single presses
2326
- r
2327
- );
2328
- h && ne(h);
2329
- },
2330
- screenshot: () => new Promise((e, o) => {
2331
- if (!T.current || T.current.readyState !== WebSocket.OPEN)
2332
- return w("WebSocket not open, cannot send screenshot command."), o(new Error("WebSocket is not connected or connection is not open."));
2333
- const r = `ui-ss-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`, i = {
2334
- type: "screenshot",
2335
- // Matches the type expected by instance API
2336
- id: r
2337
- };
2338
- fe.current.set(r, e), le.current.set(r, o), F("Sending screenshot request:", i);
2339
- try {
2340
- T.current.send(JSON.stringify(i));
2341
- } catch (h) {
2342
- w("Failed to send screenshot request immediately:", h), fe.current.delete(r), le.current.delete(r), o(h);
2343
- return;
2344
- }
2345
- setTimeout(() => {
2346
- fe.current.has(r) && (w(`Screenshot request timed out for id ${r}`), le.current.get(r)?.(new Error("Screenshot request timed out")), fe.current.delete(r), le.current.delete(r));
2347
- }, 3e4);
2348
- }),
2349
- terminateApp: (e) => new Promise((o, r) => {
2350
- if (!T.current || T.current.readyState !== WebSocket.OPEN)
2351
- return w("WebSocket not open, cannot send terminateApp command."), r(new Error("WebSocket is not connected or connection is not open."));
2352
- const i = `ui-term-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`, h = {
2353
- type: "terminateApp",
2354
- id: i,
2355
- bundleId: e
2356
- };
2357
- ve.current.set(i, o), _e.current.set(i, r), F("Sending terminateApp request:", h);
2358
- try {
2359
- T.current.send(JSON.stringify(h));
2360
- } catch (l) {
2361
- w("Failed to send terminateApp request immediately:", l), ve.current.delete(i), _e.current.delete(i), r(l);
2362
- return;
2363
- }
2364
- G.current?.bumpActivity(), setTimeout(() => {
2365
- ve.current.has(i) && (w(`terminateApp request timed out for id ${i}`), _e.current.get(i)?.(new Error("terminateApp request timed out")), ve.current.delete(i), _e.current.delete(i));
2366
- }, 3e4);
2367
- }),
2368
- reconnect: () => $t(),
2369
- refreshAxTree: async () => {
2370
- const e = G.current;
2371
- if (!e)
2372
- throw new Error("Inspect mode is not active");
2373
- return e.refresh();
2374
- },
2375
- getAxSnapshot: () => xe.current,
2376
- setInspectHighlight: (e) => {
2377
- nt(e?.id ?? null);
2378
- },
2379
- setInspectSelection: (e) => {
2380
- gt(e?.id ?? null), Le(e ? Ct.current : null);
2381
- const o = xe.current;
2382
- e && o ? U("onInspectSelectionChange", Fe.current, { element: e, snapshot: o }) : U("onInspectSelectionChange", Fe.current, null);
2383
- },
2384
- getAxStatus: () => G.current?.getStatus() ?? "idle"
2385
- }));
2386
- const fn = Ur && Te !== null;
2387
- return /* @__PURE__ */ te(
2388
- "div",
2389
- {
2390
- ref: be,
2391
- className: Re("rc-container", n),
2392
- style: { touchAction: "none" },
2393
- onMouseDown: he,
2394
- onMouseMove: he,
2395
- onMouseUp: he,
2396
- onMouseLeave: he,
2397
- onTouchStart: he,
2398
- onTouchMove: he,
2399
- onTouchEnd: he,
2400
- onTouchCancel: he,
2401
- children: [
2402
- fn && Te && /* @__PURE__ */ te(Ar, { children: [
2403
- /* @__PURE__ */ W(
2404
- "div",
2405
- {
2406
- className: "rc-touch-indicator",
2407
- style: {
2408
- left: `${Te.containerX}px`,
2409
- top: `${Te.containerY}px`
2410
- }
2411
- }
2412
- ),
2413
- /* @__PURE__ */ W(
2414
- "div",
2415
- {
2416
- className: "rc-touch-indicator",
2417
- style: {
2418
- left: `${Te.mirrorContainerX}px`,
2419
- top: `${Te.mirrorContainerY}px`
2420
- }
2421
- }
2422
- )
2423
- ] }),
2424
- yt && /* @__PURE__ */ W(
2425
- "img",
2426
- {
2427
- ref: pe,
2428
- src: cr,
2429
- alt: "",
2430
- className: se === "ios" ? Re("rc-phone-frame", "rc-phone-frame-ios") : "rc-phone-frame",
2431
- draggable: !1
2432
- }
2433
- ),
2434
- /* @__PURE__ */ W(
2435
- "video",
2436
- {
2437
- ref: x,
2438
- className: Re(
2439
- "rc-video",
2440
- !yt && "rc-video-frameless",
2441
- !Ge && "rc-video-loading"
2442
- ),
2443
- style: {
2444
- ...Lr,
2445
- ...sr ? {
2446
- backgroundImage: `url("${sr}")`,
2447
- backgroundRepeat: "no-repeat",
2448
- backgroundPosition: "center",
2449
- backgroundSize: He.loadingLogoSize
2450
- } : {}
2451
- },
2452
- autoPlay: !0,
2453
- playsInline: !0,
2454
- muted: !0,
2455
- tabIndex: 0,
2456
- onKeyDown: dr,
2457
- onKeyUp: dr,
2458
- onClick: dn,
2459
- onLoadedData: Zr,
2460
- onFocus: () => {
2461
- x.current && (x.current.style.outline = "none");
2462
- },
2463
- onBlur: () => {
2464
- x.current && (x.current.style.outline = "none");
2465
- }
2466
- }
2467
- ),
2468
- it && /* @__PURE__ */ W(
2469
- jn,
2470
- {
2471
- snapshot: Qt,
2472
- geometry: Fr,
2473
- highlightedId: Pt,
2474
- selectedId: Lt,
2475
- mode: $r,
2476
- cursorPosition: Wr,
2477
- frozenCursorPosition: Hr,
2478
- onSelectChange: (e, o) => {
2479
- gt(e?.id ?? null), e && o ? Le(o) : e || Le(null);
2480
- const r = xe.current;
2481
- e && r ? U("onInspectSelectionChange", Fe.current, {
2482
- element: e,
2483
- snapshot: r
2484
- }) : U("onInspectSelectionChange", Fe.current, null);
2485
- },
2486
- onTapElement: (e, o) => {
2487
- if (o) {
2488
- ur(o.x, o.y);
2489
- return;
2490
- }
2491
- const r = xe.current;
2492
- r && Xr(e, r);
2493
- }
2494
- }
2495
- ),
2496
- bt ? /* @__PURE__ */ te("div", { className: "rc-terminated", role: "status", children: [
2497
- /* @__PURE__ */ W("div", { className: "rc-terminated-title", children: "Instance terminated" }),
2498
- /* @__PURE__ */ W("div", { className: "rc-terminated-message", children: "This instance no longer exists and can't be reconnected." })
2499
- ] }) : Vt && /* @__PURE__ */ W("button", { type: "button", className: "rc-retry-button", onClick: ln, children: "Retry" })
2500
- ]
2501
- }
2502
- );
2503
- }
2504
- ), ci = (n) => typeof n.message == "string" ? n.message : typeof n.error == "string" ? n.error : null, si = (n) => typeof n.dataUri == "string" ? { dataUri: n.dataUri } : typeof n.base64 == "string" ? n.base64.startsWith("data:") ? { dataUri: n.base64 } : { dataUri: `data:${n.base64.startsWith("/9j/") ? "image/jpeg" : "image/png"};base64,${n.base64}` } : null;
2505
- export {
2506
- Xt as A,
2507
- di as R,
2508
- Sn as a,
2509
- bn as b,
2510
- Yr as c,
2511
- br as d,
2512
- Nr as e,
2513
- Rn as f,
2514
- Tn as g,
2515
- Mn as n
2516
- };