@limrun/ui 0.18.1 → 0.19.0

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