@limrun/ui 0.17.0-rc.2 → 0.17.0-rc.4

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