@limrun/ui 0.20.1 → 0.20.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2113 @@
1
+ const Je = {
2
+ INJECT_KEYCODE: 0,
3
+ INJECT_TEXT: 1,
4
+ INJECT_TOUCH_EVENT: 2,
5
+ // iOS-specific: send two touch points in one message (Option/Alt+drag pinch)
6
+ INJECT_TWO_FINGER_TOUCH_EVENT: 18,
7
+ INJECT_SCROLL_EVENT: 3,
8
+ BACK_OR_SCREEN_ON: 4,
9
+ EXPAND_NOTIFICATION_PANEL: 5,
10
+ EXPAND_SETTINGS_PANEL: 6,
11
+ COLLAPSE_PANELS: 7,
12
+ GET_CLIPBOARD: 8,
13
+ SET_CLIPBOARD: 9,
14
+ SET_DISPLAY_POWER: 10,
15
+ ROTATE_DEVICE: 11
16
+ }, He = {
17
+ ACTION_DOWN: 0,
18
+ ACTION_UP: 1,
19
+ ACTION_MOVE: 2,
20
+ ACTION_CANCEL: 3,
21
+ ACTION_POINTER_DOWN: 5,
22
+ ACTION_POINTER_UP: 6,
23
+ BUTTON_PRIMARY: 1,
24
+ BUTTON_SECONDARY: 2,
25
+ BUTTON_TERTIARY: 4
26
+ }, i = {
27
+ // Actions
28
+ ACTION_DOWN: 0,
29
+ ACTION_UP: 1,
30
+ // Meta state flags (from android.view.KeyEvent)
31
+ META_NONE: 0,
32
+ META_SHIFT_ON: 1,
33
+ META_ALT_ON: 2,
34
+ META_CTRL_ON: 4096,
35
+ // META_CTRL_LEFT_ON | META_CTRL_RIGHT_ON
36
+ META_META_ON: 65536,
37
+ // META_META_LEFT_ON | META_META_RIGHT_ON
38
+ // Keycodes (from android.view.KeyEvent)
39
+ KEYCODE_UNKNOWN: 0,
40
+ KEYCODE_SOFT_LEFT: 1,
41
+ KEYCODE_SOFT_RIGHT: 2,
42
+ KEYCODE_HOME: 3,
43
+ KEYCODE_BACK: 4,
44
+ KEYCODE_CALL: 5,
45
+ KEYCODE_ENDCALL: 6,
46
+ KEYCODE_0: 7,
47
+ KEYCODE_1: 8,
48
+ KEYCODE_2: 9,
49
+ KEYCODE_3: 10,
50
+ KEYCODE_4: 11,
51
+ KEYCODE_5: 12,
52
+ KEYCODE_6: 13,
53
+ KEYCODE_7: 14,
54
+ KEYCODE_8: 15,
55
+ KEYCODE_9: 16,
56
+ KEYCODE_STAR: 17,
57
+ KEYCODE_POUND: 18,
58
+ DPAD_UP: 19,
59
+ // KEYCODE_DPAD_UP
60
+ DPAD_DOWN: 20,
61
+ // KEYCODE_DPAD_DOWN
62
+ DPAD_LEFT: 21,
63
+ // KEYCODE_DPAD_LEFT
64
+ DPAD_RIGHT: 22,
65
+ // KEYCODE_DPAD_RIGHT
66
+ KEYCODE_DPAD_CENTER: 23,
67
+ KEYCODE_VOLUME_UP: 24,
68
+ KEYCODE_VOLUME_DOWN: 25,
69
+ KEYCODE_POWER: 26,
70
+ KEYCODE_CAMERA: 27,
71
+ KEYCODE_CLEAR: 28,
72
+ KEYCODE_A: 29,
73
+ KEYCODE_B: 30,
74
+ KEYCODE_C: 31,
75
+ KEYCODE_D: 32,
76
+ KEYCODE_E: 33,
77
+ KEYCODE_F: 34,
78
+ KEYCODE_G: 35,
79
+ KEYCODE_H: 36,
80
+ KEYCODE_I: 37,
81
+ KEYCODE_J: 38,
82
+ KEYCODE_K: 39,
83
+ KEYCODE_L: 40,
84
+ KEYCODE_M: 41,
85
+ KEYCODE_N: 42,
86
+ KEYCODE_O: 43,
87
+ KEYCODE_P: 44,
88
+ KEYCODE_Q: 45,
89
+ KEYCODE_R: 46,
90
+ KEYCODE_S: 47,
91
+ KEYCODE_T: 48,
92
+ KEYCODE_U: 49,
93
+ KEYCODE_V: 50,
94
+ KEYCODE_W: 51,
95
+ KEYCODE_X: 52,
96
+ KEYCODE_Y: 53,
97
+ KEYCODE_Z: 54,
98
+ KEYCODE_COMMA: 55,
99
+ KEYCODE_PERIOD: 56,
100
+ KEYCODE_ALT_LEFT: 57,
101
+ KEYCODE_ALT_RIGHT: 58,
102
+ KEYCODE_SHIFT_LEFT: 59,
103
+ KEYCODE_SHIFT_RIGHT: 60,
104
+ KEYCODE_TAB: 61,
105
+ KEYCODE_SPACE: 62,
106
+ KEYCODE_SYM: 63,
107
+ KEYCODE_EXPLORER: 64,
108
+ KEYCODE_ENVELOPE: 65,
109
+ ENTER: 66,
110
+ // KEYCODE_ENTER
111
+ DEL: 67,
112
+ // KEYCODE_DEL (Backspace)
113
+ KEYCODE_GRAVE: 68,
114
+ // `
115
+ KEYCODE_MINUS: 69,
116
+ // -
117
+ KEYCODE_EQUALS: 70,
118
+ // =
119
+ KEYCODE_LEFT_BRACKET: 71,
120
+ // [
121
+ KEYCODE_RIGHT_BRACKET: 72,
122
+ // ]
123
+ KEYCODE_BACKSLASH: 73,
124
+ // \
125
+ KEYCODE_SEMICOLON: 74,
126
+ // ;
127
+ KEYCODE_APOSTROPHE: 75,
128
+ // '
129
+ KEYCODE_SLASH: 76,
130
+ // /
131
+ KEYCODE_AT: 77,
132
+ // @
133
+ KEYCODE_NUM: 78,
134
+ KEYCODE_HEADSETHOOK: 79,
135
+ KEYCODE_FOCUS: 80,
136
+ KEYCODE_PLUS: 81,
137
+ MENU: 82,
138
+ // KEYCODE_MENU
139
+ KEYCODE_NOTIFICATION: 83,
140
+ KEYCODE_SEARCH: 84,
141
+ KEYCODE_MEDIA_PLAY_PAUSE: 85,
142
+ KEYCODE_MEDIA_STOP: 86,
143
+ KEYCODE_MEDIA_NEXT: 87,
144
+ KEYCODE_MEDIA_PREVIOUS: 88,
145
+ KEYCODE_MEDIA_REWIND: 89,
146
+ KEYCODE_MEDIA_FAST_FORWARD: 90,
147
+ KEYCODE_MUTE: 91,
148
+ KEYCODE_PAGE_UP: 92,
149
+ KEYCODE_PAGE_DOWN: 93,
150
+ KEYCODE_PICTSYMBOLS: 94,
151
+ KEYCODE_SWITCH_CHARSET: 95,
152
+ KEYCODE_BUTTON_A: 96,
153
+ KEYCODE_BUTTON_B: 97,
154
+ KEYCODE_BUTTON_C: 98,
155
+ KEYCODE_BUTTON_X: 99,
156
+ KEYCODE_BUTTON_Y: 100,
157
+ KEYCODE_BUTTON_Z: 101,
158
+ KEYCODE_BUTTON_L1: 102,
159
+ KEYCODE_BUTTON_R1: 103,
160
+ KEYCODE_BUTTON_L2: 104,
161
+ KEYCODE_BUTTON_R2: 105,
162
+ KEYCODE_BUTTON_THUMBL: 106,
163
+ KEYCODE_BUTTON_THUMBR: 107,
164
+ KEYCODE_BUTTON_START: 108,
165
+ KEYCODE_BUTTON_SELECT: 109,
166
+ KEYCODE_BUTTON_MODE: 110,
167
+ KEYCODE_ESCAPE: 111,
168
+ FORWARD_DEL: 112,
169
+ // KEYCODE_FORWARD_DEL (Delete key)
170
+ KEYCODE_CTRL_LEFT: 113,
171
+ KEYCODE_CTRL_RIGHT: 114,
172
+ KEYCODE_CAPS_LOCK: 115,
173
+ KEYCODE_SCROLL_LOCK: 116,
174
+ KEYCODE_META_LEFT: 117,
175
+ KEYCODE_META_RIGHT: 118,
176
+ KEYCODE_FUNCTION: 119,
177
+ KEYCODE_SYSRQ: 120,
178
+ KEYCODE_BREAK: 121,
179
+ KEYCODE_MOVE_HOME: 122,
180
+ KEYCODE_MOVE_END: 123,
181
+ KEYCODE_INSERT: 124,
182
+ KEYCODE_FORWARD: 125,
183
+ KEYCODE_MEDIA_PLAY: 126,
184
+ KEYCODE_MEDIA_PAUSE: 127,
185
+ KEYCODE_MEDIA_CLOSE: 128,
186
+ KEYCODE_MEDIA_EJECT: 129,
187
+ KEYCODE_MEDIA_RECORD: 130,
188
+ KEYCODE_F1: 131,
189
+ KEYCODE_F2: 132,
190
+ KEYCODE_F3: 133,
191
+ KEYCODE_F4: 134,
192
+ KEYCODE_F5: 135,
193
+ KEYCODE_F6: 136,
194
+ KEYCODE_F7: 137,
195
+ KEYCODE_F8: 138,
196
+ KEYCODE_F9: 139,
197
+ KEYCODE_F10: 140,
198
+ KEYCODE_F11: 141,
199
+ KEYCODE_F12: 142,
200
+ KEYCODE_NUM_LOCK: 143,
201
+ KEYCODE_NUMPAD_0: 144,
202
+ KEYCODE_NUMPAD_1: 145,
203
+ KEYCODE_NUMPAD_2: 146,
204
+ KEYCODE_NUMPAD_3: 147,
205
+ KEYCODE_NUMPAD_4: 148,
206
+ KEYCODE_NUMPAD_5: 149,
207
+ KEYCODE_NUMPAD_6: 150,
208
+ KEYCODE_NUMPAD_7: 151,
209
+ KEYCODE_NUMPAD_8: 152,
210
+ KEYCODE_NUMPAD_9: 153,
211
+ KEYCODE_NUMPAD_DIVIDE: 154,
212
+ KEYCODE_NUMPAD_MULTIPLY: 155,
213
+ KEYCODE_NUMPAD_SUBTRACT: 156,
214
+ KEYCODE_NUMPAD_ADD: 157,
215
+ KEYCODE_NUMPAD_DOT: 158,
216
+ KEYCODE_NUMPAD_COMMA: 159,
217
+ KEYCODE_NUMPAD_ENTER: 160,
218
+ KEYCODE_NUMPAD_EQUALS: 161,
219
+ KEYCODE_NUMPAD_LEFT_PAREN: 162,
220
+ KEYCODE_NUMPAD_RIGHT_PAREN: 163,
221
+ KEYCODE_VOLUME_MUTE: 164,
222
+ KEYCODE_INFO: 165,
223
+ KEYCODE_CHANNEL_UP: 166,
224
+ KEYCODE_CHANNEL_DOWN: 167,
225
+ KEYCODE_ZOOM_IN: 168,
226
+ KEYCODE_ZOOM_OUT: 169,
227
+ KEYCODE_TV: 170,
228
+ KEYCODE_WINDOW: 171,
229
+ KEYCODE_GUIDE: 172,
230
+ KEYCODE_DVR: 173,
231
+ KEYCODE_BOOKMARK: 174,
232
+ KEYCODE_CAPTIONS: 175,
233
+ KEYCODE_SETTINGS: 176,
234
+ KEYCODE_TV_POWER: 177,
235
+ KEYCODE_TV_INPUT: 178,
236
+ KEYCODE_STB_POWER: 179,
237
+ KEYCODE_STB_INPUT: 180,
238
+ KEYCODE_AVR_POWER: 181,
239
+ KEYCODE_AVR_INPUT: 182,
240
+ KEYCODE_PROG_RED: 183,
241
+ KEYCODE_PROG_GREEN: 184,
242
+ KEYCODE_PROG_YELLOW: 185,
243
+ KEYCODE_PROG_BLUE: 186,
244
+ KEYCODE_APP_SWITCH: 187,
245
+ KEYCODE_LANGUAGE_SWITCH: 204,
246
+ KEYCODE_ASSIST: 219,
247
+ KEYCODE_BRIGHTNESS_DOWN: 220,
248
+ KEYCODE_BRIGHTNESS_UP: 221,
249
+ KEYCODE_SLEEP: 223,
250
+ KEYCODE_WAKEUP: 224,
251
+ KEYCODE_SOFT_SLEEP: 276
252
+ }, qt = {
253
+ KeyA: i.KEYCODE_A,
254
+ KeyB: i.KEYCODE_B,
255
+ KeyC: i.KEYCODE_C,
256
+ KeyD: i.KEYCODE_D,
257
+ KeyE: i.KEYCODE_E,
258
+ KeyF: i.KEYCODE_F,
259
+ KeyG: i.KEYCODE_G,
260
+ KeyH: i.KEYCODE_H,
261
+ KeyI: i.KEYCODE_I,
262
+ KeyJ: i.KEYCODE_J,
263
+ KeyK: i.KEYCODE_K,
264
+ KeyL: i.KEYCODE_L,
265
+ KeyM: i.KEYCODE_M,
266
+ KeyN: i.KEYCODE_N,
267
+ KeyO: i.KEYCODE_O,
268
+ KeyP: i.KEYCODE_P,
269
+ KeyQ: i.KEYCODE_Q,
270
+ KeyR: i.KEYCODE_R,
271
+ KeyS: i.KEYCODE_S,
272
+ KeyT: i.KEYCODE_T,
273
+ KeyU: i.KEYCODE_U,
274
+ KeyV: i.KEYCODE_V,
275
+ KeyW: i.KEYCODE_W,
276
+ KeyX: i.KEYCODE_X,
277
+ KeyY: i.KEYCODE_Y,
278
+ KeyZ: i.KEYCODE_Z,
279
+ Digit0: i.KEYCODE_0,
280
+ Digit1: i.KEYCODE_1,
281
+ Digit2: i.KEYCODE_2,
282
+ Digit3: i.KEYCODE_3,
283
+ Digit4: i.KEYCODE_4,
284
+ Digit5: i.KEYCODE_5,
285
+ Digit6: i.KEYCODE_6,
286
+ Digit7: i.KEYCODE_7,
287
+ Digit8: i.KEYCODE_8,
288
+ Digit9: i.KEYCODE_9,
289
+ Backquote: i.KEYCODE_GRAVE,
290
+ Minus: i.KEYCODE_MINUS,
291
+ Equal: i.KEYCODE_EQUALS,
292
+ BracketLeft: i.KEYCODE_LEFT_BRACKET,
293
+ BracketRight: i.KEYCODE_RIGHT_BRACKET,
294
+ Backslash: i.KEYCODE_BACKSLASH,
295
+ Semicolon: i.KEYCODE_SEMICOLON,
296
+ Quote: i.KEYCODE_APOSTROPHE,
297
+ Comma: i.KEYCODE_COMMA,
298
+ Period: i.KEYCODE_PERIOD,
299
+ Slash: i.KEYCODE_SLASH,
300
+ Space: i.KEYCODE_SPACE,
301
+ Tab: i.KEYCODE_TAB,
302
+ Escape: i.KEYCODE_ESCAPE,
303
+ ArrowUp: i.DPAD_UP,
304
+ ArrowDown: i.DPAD_DOWN,
305
+ ArrowLeft: i.DPAD_LEFT,
306
+ ArrowRight: i.DPAD_RIGHT,
307
+ Enter: i.ENTER,
308
+ Backspace: i.DEL,
309
+ Delete: i.FORWARD_DEL,
310
+ Home: i.KEYCODE_MOVE_HOME,
311
+ End: i.KEYCODE_MOVE_END,
312
+ PageUp: i.KEYCODE_PAGE_UP,
313
+ PageDown: i.KEYCODE_PAGE_DOWN,
314
+ Insert: i.KEYCODE_INSERT,
315
+ F1: i.KEYCODE_F1,
316
+ F2: i.KEYCODE_F2,
317
+ F3: i.KEYCODE_F3,
318
+ F4: i.KEYCODE_F4,
319
+ F5: i.KEYCODE_F5,
320
+ F6: i.KEYCODE_F6,
321
+ F7: i.KEYCODE_F7,
322
+ F8: i.KEYCODE_F8,
323
+ F9: i.KEYCODE_F9,
324
+ F10: i.KEYCODE_F10,
325
+ F11: i.KEYCODE_F11,
326
+ F12: i.KEYCODE_F12,
327
+ ShiftLeft: i.KEYCODE_SHIFT_LEFT,
328
+ ShiftRight: i.KEYCODE_SHIFT_RIGHT,
329
+ ControlLeft: i.KEYCODE_CTRL_LEFT,
330
+ ControlRight: i.KEYCODE_CTRL_RIGHT,
331
+ AltLeft: i.KEYCODE_ALT_LEFT,
332
+ AltRight: i.KEYCODE_ALT_RIGHT,
333
+ MetaLeft: i.KEYCODE_META_LEFT,
334
+ MetaRight: i.KEYCODE_META_RIGHT,
335
+ // Windows/Command key
336
+ ContextMenu: i.MENU,
337
+ // Often the Menu key
338
+ // Numpad mappings
339
+ Numpad0: i.KEYCODE_NUMPAD_0,
340
+ Numpad1: i.KEYCODE_NUMPAD_1,
341
+ Numpad2: i.KEYCODE_NUMPAD_2,
342
+ Numpad3: i.KEYCODE_NUMPAD_3,
343
+ Numpad4: i.KEYCODE_NUMPAD_4,
344
+ Numpad5: i.KEYCODE_NUMPAD_5,
345
+ Numpad6: i.KEYCODE_NUMPAD_6,
346
+ Numpad7: i.KEYCODE_NUMPAD_7,
347
+ Numpad8: i.KEYCODE_NUMPAD_8,
348
+ Numpad9: i.KEYCODE_NUMPAD_9,
349
+ NumpadDivide: i.KEYCODE_NUMPAD_DIVIDE,
350
+ NumpadMultiply: i.KEYCODE_NUMPAD_MULTIPLY,
351
+ NumpadSubtract: i.KEYCODE_NUMPAD_SUBTRACT,
352
+ NumpadAdd: i.KEYCODE_NUMPAD_ADD,
353
+ NumpadDecimal: i.KEYCODE_NUMPAD_DOT,
354
+ NumpadComma: i.KEYCODE_NUMPAD_COMMA,
355
+ // Some numpads have comma
356
+ NumpadEnter: i.KEYCODE_NUMPAD_ENTER,
357
+ NumpadEqual: i.KEYCODE_NUMPAD_EQUALS
358
+ };
359
+ function $t(t, e, n, s, E, d, c = 1, h = 0, C = 0) {
360
+ const p = new ArrayBuffer(32), K = new DataView(p);
361
+ let w = 0;
362
+ K.setUint8(w, Je.INJECT_TOUCH_EVENT), w += 1;
363
+ const U = t === He.ACTION_POINTER_DOWN ? He.ACTION_DOWN : t === He.ACTION_POINTER_UP ? He.ACTION_UP : t;
364
+ return K.setUint8(w, U), w += 1, K.setBigInt64(w, BigInt(e), !0), w += 8, K.setInt32(w, Math.round(E), !0), w += 4, K.setInt32(w, Math.round(d), !0), w += 4, K.setUint16(w, n, !0), w += 2, K.setUint16(w, s, !0), w += 2, K.setInt16(w, Math.round(c * 65535), !0), w += 2, K.setInt32(w, h, !0), w += 4, K.setInt32(w, C, !0), p;
365
+ }
366
+ function Rn(t, e, n, s, E, d, c) {
367
+ const h = new ArrayBuffer(24), C = new DataView(h);
368
+ let p = 0;
369
+ return C.setUint8(p, Je.INJECT_TWO_FINGER_TOUCH_EVENT), p += 1, C.setUint8(p, t), p += 1, C.setInt32(p, Math.round(s), !0), p += 4, C.setInt32(p, Math.round(E), !0), p += 4, C.setInt32(p, Math.round(d), !0), p += 4, C.setInt32(p, Math.round(c), !0), p += 4, C.setUint16(p, e, !0), p += 2, C.setUint16(p, n, !0), p += 2, C.setUint16(p, 0, !0), h;
370
+ }
371
+ function Vt(t, e = !0) {
372
+ const s = new TextEncoder().encode(t), E = new ArrayBuffer(14 + s.length), d = new DataView(E);
373
+ let c = 0;
374
+ return d.setUint8(c, Je.SET_CLIPBOARD), c += 1, d.setBigInt64(c, BigInt(0), !1), c += 8, d.setUint8(c, e ? 1 : 0), c += 1, d.setUint32(c, s.length, !1), c += 4, new Uint8Array(E, c).set(s), E;
375
+ }
376
+ function nt(t, e, n = 0, s = 0) {
377
+ const E = new ArrayBuffer(14), d = new DataView(E);
378
+ let c = 0;
379
+ return d.setUint8(c, Je.INJECT_KEYCODE), c += 1, d.setUint8(c, t), c += 1, d.setInt32(c, e, !0), c += 4, d.setInt32(c, n, !0), c += 4, d.setInt32(c, s, !0), E;
380
+ }
381
+ const In = { width: 164.6, height: 117.8, depth: 5.2 };
382
+ function kn(t, e, n) {
383
+ return t = Math.max(0, Math.min(1, t)), e = Math.max(0, Math.min(1, e)), n === 1 ? { x: e, y: 1 - t } : n === 2 ? { x: 1 - t, y: 1 - e } : n === 3 ? { x: 1 - e, y: t } : { x: t, y: e };
384
+ }
385
+ function Ht(t) {
386
+ return Number.isFinite(t) && t >= 0 && t <= 180;
387
+ }
388
+ function Un(t, e) {
389
+ return { x: Math.max(0, Math.min(1, t)), y: Math.max(0, Math.min(1, 1 - e)) };
390
+ }
391
+ function Pn(t, e, n) {
392
+ return e && (t || !n) ? "touch" : t ? "ignore" : "orbit";
393
+ }
394
+ function Gt(t, e, n, s) {
395
+ if (!Number.isInteger(t) || t < 0 || t > 3 || !Number.isInteger(e) || e < 1 || e > 255 || !Number.isFinite(n) || !Number.isFinite(s) || n < 0 || n > 1 || s < 0 || s > 1)
396
+ throw new RangeError("Invalid display touch coordinates");
397
+ const E = new ArrayBuffer(12), d = new DataView(E);
398
+ return d.setUint8(0, 19), d.setUint8(1, t), d.setUint8(2, e), d.setFloat32(4, n, !0), d.setFloat32(8, s, !0), E;
399
+ }
400
+ class Ln {
401
+ constructor(e, n) {
402
+ this.send = e, this.failed = n;
403
+ }
404
+ send;
405
+ failed;
406
+ latest;
407
+ running = !1;
408
+ stopped = !1;
409
+ set(e) {
410
+ this.stopped || !Ht(e) || (this.latest = e, this.flush());
411
+ }
412
+ stop() {
413
+ this.stopped = !0, this.latest = void 0;
414
+ }
415
+ async flush() {
416
+ if (!(this.running || this.stopped)) {
417
+ this.running = !0;
418
+ try {
419
+ for (; this.latest !== void 0 && !this.stopped; ) {
420
+ const e = this.latest;
421
+ this.latest = void 0, await this.send(e);
422
+ }
423
+ } catch (e) {
424
+ this.latest = void 0, this.stopped || this.failed(e);
425
+ } finally {
426
+ this.running = !1;
427
+ }
428
+ }
429
+ }
430
+ }
431
+ const Fn = {
432
+ side: "Sleep/Wake",
433
+ volumeUp: "Volume Up",
434
+ volumeDown: "Volume Down"
435
+ };
436
+ class Bn {
437
+ constructor(e, n) {
438
+ this.send = e, this.failed = n;
439
+ }
440
+ send;
441
+ failed;
442
+ held;
443
+ tail = Promise.resolve();
444
+ timeout;
445
+ press(e) {
446
+ this.held || (this.held = e, this.enqueue(e, !0), this.timeout = setTimeout(() => this.release(), 1e4));
447
+ }
448
+ release() {
449
+ if (!this.held) return;
450
+ clearTimeout(this.timeout);
451
+ const e = this.held;
452
+ this.held = void 0, this.enqueue(e, !1);
453
+ }
454
+ enqueue(e, n) {
455
+ this.tail = this.tail.then(() => this.send(e, n)).catch(this.failed);
456
+ }
457
+ }
458
+ const rt = "Accessibility unavailable on this device.", Ge = 500, Kt = (t, e) => Math.abs(t.x - e.x) < 0.5 && Math.abs(t.y - e.y) < 0.5 && Math.abs(t.width - e.width) < 0.5 && Math.abs(t.height - e.height) < 0.5, Jt = (t) => Math.max(0, t.width) * Math.max(0, t.height), jt = (t) => {
459
+ const e = t.find((n) => n.frame && n.frame.width > 0 && n.frame.height > 0);
460
+ return e?.frame ? ((Math.abs(e.frame.x) > 0.5 || Math.abs(e.frame.y) > 0.5) && console.warn(
461
+ `[ax-tree] iOS root frame is not anchored at (0,0): (${e.frame.x},${e.frame.y}). Element positions may be slightly off from the rendered video.`
462
+ ), { x: 0, y: 0, width: e.frame.width, height: e.frame.height }) : { x: 0, y: 0, width: 1, height: 1 };
463
+ }, Xt = (t) => {
464
+ const e = {};
465
+ return typeof t.AXUniqueId == "string" && t.AXUniqueId.length > 0 && (e.AXUniqueId = t.AXUniqueId), typeof t.AXLabel == "string" && t.AXLabel.length > 0 && (e.AXLabel = t.AXLabel), typeof t.type == "string" && t.type.length > 0 && (e.className = t.type), e;
466
+ }, Qt = (t) => {
467
+ const e = {};
468
+ for (const [n, s] of Object.entries(t))
469
+ n !== "children" && (e[n] = s);
470
+ return e;
471
+ };
472
+ function zt(t) {
473
+ const e = Array.isArray(t) ? t : [t], n = jt(e), s = [], E = (d, c) => {
474
+ if (s.length >= Ge) return;
475
+ const h = d.frame;
476
+ if (h && h.width > 0 && h.height > 0 && !Kt(h, n)) {
477
+ const p = d.role_description || d.role || "", K = (typeof d.AXLabel == "string" ? d.AXLabel : "") || (typeof d.title == "string" ? d.title : "") || "";
478
+ s.push({
479
+ id: typeof d.AXUniqueId == "string" && d.AXUniqueId.length > 0 ? d.AXUniqueId : c,
480
+ path: c,
481
+ label: K,
482
+ value: typeof d.AXValue == "string" ? d.AXValue : "",
483
+ role: p,
484
+ type: typeof d.type == "string" ? d.type : "",
485
+ enabled: d.enabled !== !1,
486
+ focused: d.focused === !0,
487
+ frame: { x: h.x, y: h.y, width: h.width, height: h.height },
488
+ selectors: Xt(d),
489
+ raw: Qt(d)
490
+ });
491
+ }
492
+ const C = Array.isArray(d.children) ? d.children : [];
493
+ for (let p = 0; p < C.length && s.length < Ge; p++)
494
+ E(C[p], `${c}.${p}`);
495
+ };
496
+ for (let d = 0; d < e.length && s.length < Ge; d++)
497
+ E(e[d], String(d));
498
+ return {
499
+ platform: "ios",
500
+ screen: { width: n.width, height: n.height },
501
+ elements: s,
502
+ capturedAt: Date.now()
503
+ };
504
+ }
505
+ const Zt = (t) => {
506
+ let e = { x: 0, y: 0, width: 1, height: 1 }, n = 0;
507
+ for (const s of t) {
508
+ const E = s.parsedBounds;
509
+ if (!E) continue;
510
+ const d = E.right - E.left, c = E.bottom - E.top, h = Math.max(0, d) * Math.max(0, c);
511
+ h > n && (n = h, e = { x: 0, y: 0, width: d, height: c });
512
+ }
513
+ return e;
514
+ }, en = (t) => {
515
+ const e = {};
516
+ return typeof t.resourceId == "string" && t.resourceId.length > 0 && (e.resourceId = t.resourceId), typeof t.contentDesc == "string" && t.contentDesc.length > 0 && (e.contentDesc = t.contentDesc), typeof t.text == "string" && t.text.length > 0 && (e.text = t.text), typeof t.className == "string" && t.className.length > 0 && (e.className = t.className), e;
517
+ };
518
+ function tn(t) {
519
+ const e = Zt(t), n = [];
520
+ for (let s = 0; s < t.length && n.length < Ge; s++) {
521
+ const E = t[s], d = E.parsedBounds;
522
+ if (!d) continue;
523
+ const c = Math.max(0, d.right - d.left), h = Math.max(0, d.bottom - d.top);
524
+ if (c <= 0 || h <= 0) continue;
525
+ const C = { x: d.left, y: d.top, width: c, height: h };
526
+ if (Kt(C, { x: 0, y: 0, width: e.width, height: e.height })) continue;
527
+ const p = E.contentDesc || E.text || "", K = E.className || "";
528
+ n.push({
529
+ id: E.resourceId && E.resourceId.length > 0 ? E.resourceId : E.contentDesc && E.contentDesc.length > 0 ? `cd:${E.contentDesc}` : String(s),
530
+ path: String(s),
531
+ label: p,
532
+ value: typeof E.text == "string" ? E.text : "",
533
+ role: K,
534
+ type: K,
535
+ enabled: E.enabled !== !1,
536
+ focused: E.focused === !0,
537
+ frame: C,
538
+ selectors: en(E),
539
+ raw: { ...E }
540
+ });
541
+ }
542
+ return {
543
+ platform: "android",
544
+ screen: { width: e.width, height: e.height },
545
+ elements: n,
546
+ capturedAt: Date.now()
547
+ };
548
+ }
549
+ function xn(t, e) {
550
+ const n = Math.max(0, t.x), s = Math.max(0, t.y), E = Math.min(e.width, t.x + t.width), d = Math.min(e.height, t.y + t.height), c = Math.max(0, E - n), h = Math.max(0, d - s);
551
+ return c > 0 && h > 0 ? { x: n, y: s, width: c, height: h } : null;
552
+ }
553
+ function nn(t, e) {
554
+ if (t === e) return !0;
555
+ if (t.id !== e.id || t.path !== e.path || t.label !== e.label || t.value !== e.value || t.role !== e.role || t.type !== e.type || t.enabled !== e.enabled || t.focused !== e.focused) return !1;
556
+ const n = t.frame, s = e.frame;
557
+ return n.x === s.x && n.y === s.y && n.width === s.width && n.height === s.height;
558
+ }
559
+ function rn(t, e) {
560
+ if (t === e) return !0;
561
+ if (!t || !e || t.platform !== e.platform || t.screen.width !== e.screen.width || t.screen.height !== e.screen.height || t.elements.length !== e.elements.length) return !1;
562
+ for (let n = 0; n < t.elements.length; n++)
563
+ if (!nn(t.elements[n], e.elements[n])) return !1;
564
+ return !0;
565
+ }
566
+ function Wn(t, e, n) {
567
+ let s = null, E = 1 / 0;
568
+ for (const d of t.elements) {
569
+ const c = d.frame;
570
+ if (e < c.x || n < c.y || e > c.x + c.width || n > c.y + c.height) continue;
571
+ const h = Jt(c);
572
+ h < E && (E = h, s = d);
573
+ }
574
+ return s;
575
+ }
576
+ function qn(t, e) {
577
+ if (e === "ios") {
578
+ if (t.selectors.AXUniqueId)
579
+ return `client.tapElement({ AXUniqueId: ${JSON.stringify(t.selectors.AXUniqueId)} })`;
580
+ if (t.selectors.AXLabel) {
581
+ const n = t.selectors.className ? `, type: ${JSON.stringify(t.selectors.className)}` : "";
582
+ return `client.tapElement({ AXLabel: ${JSON.stringify(t.selectors.AXLabel)}${n} })`;
583
+ }
584
+ return null;
585
+ }
586
+ return t.selectors.resourceId ? `client.tap({ selector: { resourceId: ${JSON.stringify(t.selectors.resourceId)} } })` : t.selectors.contentDesc ? `client.tap({ selector: { contentDesc: ${JSON.stringify(t.selectors.contentDesc)} } })` : t.selectors.text ? `client.tap({ selector: { text: ${JSON.stringify(t.selectors.text)} } })` : null;
587
+ }
588
+ function on(t) {
589
+ const e = t.role || t.type || "";
590
+ if (!e) return "element";
591
+ let n = e.replace(/^AX/, "");
592
+ return n.includes(".") && (n = n.split(".").pop()), n === "GenericElement" ? "Element" : (n = n.replace(/([a-z])([A-Z])/g, "$1 $2"), n);
593
+ }
594
+ const Dt = 80;
595
+ function $n(t) {
596
+ const e = on(t), n = t.label || t.value || "";
597
+ if (!n) return e;
598
+ const s = n.length > Dt ? n.slice(0, Dt).trimEnd() + "…" : n;
599
+ return `${e} · ${s}`;
600
+ }
601
+ const an = 500, sn = 2e3, gt = 5e3, cn = 8e3, ln = 1200, dn = 250, un = () => `ax-rc-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
602
+ class En {
603
+ platform;
604
+ send;
605
+ onSnapshot;
606
+ onStatusChange;
607
+ baseIntervalMs;
608
+ maxBackoffMs;
609
+ androidElementTreeOptions;
610
+ pending = /* @__PURE__ */ new Map();
611
+ running = !1;
612
+ timer;
613
+ currentInterval;
614
+ lastSnapshot = null;
615
+ // Single-flight: only one outstanding request at a time. Avoids piling
616
+ // identical requests on a slow server.
617
+ inflight = !1;
618
+ // Rate-limit floor for bumpActivity so high-frequency input (drags,
619
+ // typing) doesn't trigger a request storm.
620
+ lastBumpAtMs = 0;
621
+ // Wall-clock timestamp until which we're in "activity boost" mode and
622
+ // schedule fetches at ACTIVITY_BOOST_INTERVAL_MS instead of the normal
623
+ // backed-off interval. Set by bumpActivity().
624
+ boostUntilMs = 0;
625
+ // Coarse-grained current status; deduplicated before emission so
626
+ // identical-to-current transitions are no-ops.
627
+ status = "idle";
628
+ constructor(e) {
629
+ this.platform = e.platform, this.send = e.send, this.onSnapshot = e.onSnapshot, this.onStatusChange = e.onStatusChange, this.baseIntervalMs = e.baseIntervalMs ?? an, this.maxBackoffMs = e.maxBackoffMs ?? sn, this.androidElementTreeOptions = e.androidElementTreeOptions, this.currentInterval = this.baseIntervalMs;
630
+ }
631
+ start() {
632
+ this.running || (this.running = !0, this.currentInterval = this.baseIntervalMs, this.boostUntilMs = 0, this.setStatus("starting"), this.runOnce());
633
+ }
634
+ stop() {
635
+ 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));
636
+ }
637
+ getStatus() {
638
+ return this.status;
639
+ }
640
+ setStatus(e, n) {
641
+ if (this.status !== e && (this.status = e, !!this.onStatusChange))
642
+ try {
643
+ this.onStatusChange(e, n);
644
+ } catch (s) {
645
+ console.error("[AxFetcher] onStatusChange threw:", s);
646
+ }
647
+ }
648
+ // Called after any user-driven action that's likely to change the UI
649
+ // (taps, scrolls, key events, openUrl, app termination, orientation
650
+ // change, etc.). Has two effects:
651
+ //
652
+ // 1. Resets the polling interval to base and triggers an immediate
653
+ // fetch (rate-limited so drags / rapid typing don't request-storm).
654
+ // 2. Enters a brief "boost" window during which scheduleNext() uses a
655
+ // shorter interval (ACTIVITY_BOOST_INTERVAL_MS), so we capture the
656
+ // mid- and post-animation tree without waiting for the next
657
+ // back-off cycle.
658
+ bumpActivity() {
659
+ if (!this.running) return;
660
+ const e = Date.now();
661
+ this.boostUntilMs = e + ln;
662
+ const n = Math.max(150, Math.floor(this.baseIntervalMs / 2));
663
+ if (e - this.lastBumpAtMs < n) {
664
+ this.currentInterval = this.baseIntervalMs;
665
+ return;
666
+ }
667
+ this.lastBumpAtMs = e, this.currentInterval = this.baseIntervalMs, this.timer !== void 0 && (window.clearTimeout(this.timer), this.timer = void 0), this.inflight || this.runOnce();
668
+ }
669
+ // Fire a one-shot fetch independent of the poll loop. Useful for the
670
+ // imperative refresh() ref method customers may call.
671
+ //
672
+ // Goes through the same change-detect path as the regular poll loop —
673
+ // identical-to-last-snapshot responses do NOT re-emit via onSnapshot, so
674
+ // a customer calling refresh() in a tight loop doesn't see a stream of
675
+ // duplicate snapshots. The returned promise still resolves with the
676
+ // (possibly identical) snapshot for the caller's own use.
677
+ async refresh() {
678
+ const e = await this.requestOnce();
679
+ return this.running && this.deliver(e), e;
680
+ }
681
+ // Returns the latest snapshot delivered to onSnapshot. May be stale.
682
+ getLatest() {
683
+ return this.lastSnapshot;
684
+ }
685
+ // Called by RemoteControl's ws.onmessage when it sees a message type we own.
686
+ // Returns true when the message was a response we were waiting for.
687
+ handleMessage(e) {
688
+ if (!e || typeof e.id != "string") return !1;
689
+ const n = e.id;
690
+ if (!this.pending.get(n)) return !1;
691
+ if (this.platform === "ios") {
692
+ if (e.type !== "elementTreeResult") return !1;
693
+ const h = typeof e.error == "string" ? e.error : null;
694
+ if (h)
695
+ return this.settleReject(n, new Error(h)), !0;
696
+ const C = typeof e.json == "string" ? e.json : "";
697
+ try {
698
+ const p = JSON.parse(C), K = zt(p);
699
+ this.settleResolve(n, K);
700
+ } catch (p) {
701
+ this.settleReject(n, p instanceof Error ? p : new Error(String(p)));
702
+ }
703
+ return !0;
704
+ }
705
+ if (e.type !== "getElementTreeResult") return !1;
706
+ const E = e.error;
707
+ if (E && typeof E == "object") {
708
+ const h = typeof E.message == "string" ? E.message : "getElementTree failed";
709
+ return this.settleReject(n, new Error(h)), !0;
710
+ }
711
+ const d = e.payload, c = Array.isArray(d?.nodes) ? d.nodes : [];
712
+ try {
713
+ const h = tn(c);
714
+ this.settleResolve(n, h);
715
+ } catch (h) {
716
+ this.settleReject(n, h instanceof Error ? h : new Error(String(h)));
717
+ }
718
+ return !0;
719
+ }
720
+ buildRequest(e) {
721
+ return this.platform === "ios" ? { type: "elementTree", id: e } : { type: "getElementTree", id: e, ...this.androidElementTreeOptions };
722
+ }
723
+ async requestOnce() {
724
+ const e = un();
725
+ return new Promise((n, s) => {
726
+ const E = window.setTimeout(
727
+ () => {
728
+ this.pending.delete(e), s(new Error("elementTree request timed out"));
729
+ },
730
+ cn + (this.androidElementTreeOptions?.waitForIdleTimeoutMs ?? 0)
731
+ );
732
+ this.pending.set(e, { resolve: n, reject: s, timer: E }), this.send(this.buildRequest(e)) || (window.clearTimeout(E), this.pending.delete(e), s(new Error("elementTree send failed (WebSocket not open)")));
733
+ });
734
+ }
735
+ async runOnce() {
736
+ if (this.running && !this.inflight) {
737
+ this.inflight = !0;
738
+ try {
739
+ const e = await this.requestOnce();
740
+ if (!this.running) return;
741
+ this.deliver(e);
742
+ } catch (e) {
743
+ if (!this.running) return;
744
+ const n = e instanceof Error ? e.message : String(e), s = /unavailable|not (yet )?running|failed|timeout/i.test(n);
745
+ this.currentInterval = s ? gt : Math.min(this.currentInterval * 2, this.maxBackoffMs), this.setStatus(s ? "unavailable" : "error", n);
746
+ } finally {
747
+ this.inflight = !1, this.scheduleNext();
748
+ }
749
+ }
750
+ }
751
+ deliver(e) {
752
+ const n = this.lastSnapshot;
753
+ if (rn(n, e)) {
754
+ this.currentInterval = Math.min(this.currentInterval * 2, this.maxBackoffMs), this.lastSnapshot = e, e.errors?.includes(rt) || this.setStatus("ready");
755
+ return;
756
+ }
757
+ this.lastSnapshot = e, this.currentInterval = this.baseIntervalMs, e.errors?.includes(rt) ? (this.currentInterval = gt, this.setStatus("unavailable", rt)) : this.setStatus("ready"), this.onSnapshot(e);
758
+ }
759
+ scheduleNext() {
760
+ if (!this.running) return;
761
+ this.timer !== void 0 && window.clearTimeout(this.timer);
762
+ const e = Date.now() < this.boostUntilMs ? Math.min(dn, this.currentInterval) : this.currentInterval;
763
+ this.timer = window.setTimeout(() => {
764
+ this.timer = void 0, this.runOnce();
765
+ }, e);
766
+ }
767
+ settleResolve(e, n) {
768
+ const s = this.pending.get(e);
769
+ s && (window.clearTimeout(s.timer), this.pending.delete(e), s.resolve(n));
770
+ }
771
+ settleReject(e, n) {
772
+ const s = this.pending.get(e);
773
+ s && (window.clearTimeout(s.timer), this.pending.delete(e), s.reject(n));
774
+ }
775
+ failAllPending(e) {
776
+ for (const [n, s] of this.pending.entries())
777
+ window.clearTimeout(s.timer), s.reject(new Error(e)), this.pending.delete(n);
778
+ }
779
+ }
780
+ function Tt(t, e) {
781
+ if (e != null && (!Number.isFinite(e) || e < 0 || e > 4e3)) {
782
+ console.warn("RemoteControl: jitterBufferTargetMs must be a finite number between 0 and 4000.");
783
+ return;
784
+ }
785
+ if (!("jitterBufferTarget" in t)) return;
786
+ const n = e ?? null;
787
+ try {
788
+ t.jitterBufferTarget !== n && (t.jitterBufferTarget = n);
789
+ } catch (s) {
790
+ console.warn("RemoteControl: could not set the jitter buffer target.", s);
791
+ }
792
+ }
793
+ const At = `(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())}})();
794
+ `, St = typeof self < "u" && self.Blob && new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);", At], { type: "text/javascript;charset=utf-8" });
795
+ function fn(t) {
796
+ let e;
797
+ try {
798
+ if (e = St && (self.URL || self.webkitURL).createObjectURL(St), !e) throw "";
799
+ const n = new Worker(e, {
800
+ name: t?.name
801
+ });
802
+ return n.addEventListener("error", () => {
803
+ (self.URL || self.webkitURL).revokeObjectURL(e);
804
+ }), n;
805
+ } catch {
806
+ return new Worker(
807
+ "data:text/javascript;charset=utf-8," + encodeURIComponent(At),
808
+ {
809
+ name: t?.name
810
+ }
811
+ );
812
+ }
813
+ }
814
+ function hn(t, e, n) {
815
+ const { MediaStreamTrackProcessor: s, MediaStreamTrackGenerator: E } = globalThis, d = e.getVideoTracks()[0];
816
+ let c, h, C, p, K = !1;
817
+ const w = () => {
818
+ K || (K = !0, c?.stop(), h?.stop(), C && (C.postMessage({ type: "stop" }), p = setTimeout(() => C?.terminate(), 1e3)));
819
+ }, U = (b) => {
820
+ t.srcObject = b, t.play().catch(() => {
821
+ });
822
+ }, T = (b) => {
823
+ K || (w(), n(b), U(e));
824
+ };
825
+ try {
826
+ if (d && s && E) {
827
+ c = d.clone();
828
+ const b = new s({ track: c, maxBufferSize: 1 }), $ = new E({ kind: "video" });
829
+ h = $, C = new fn(), C.onmessage = ({ data: F }) => {
830
+ F.type === "error" ? T(new Error(F.message)) : F.type === "stopped" && (clearTimeout(p), C?.terminate());
831
+ }, C.onerror = (F) => T(new Error(F.message)), C.postMessage({ type: "start", readable: b.readable, writable: $.writable }, [
832
+ b.readable,
833
+ $.writable
834
+ ]), U(new MediaStream(e.getTracks().map((F) => F === d ? $ : F)));
835
+ } else
836
+ U(e);
837
+ } catch (b) {
838
+ T(b);
839
+ }
840
+ return w;
841
+ }
842
+ function Ne(t) {
843
+ return typeof t == "number" && Number.isFinite(t);
844
+ }
845
+ function ge(t, e) {
846
+ if (!(!Ne(t) || !Ne(e) || t < e || e < 0))
847
+ return t - e;
848
+ }
849
+ class mn {
850
+ previous = /* @__PURE__ */ new Map();
851
+ reset() {
852
+ this.previous.clear();
853
+ }
854
+ read(e, n, s) {
855
+ const E = { timestamp: 0, video: [], audio: [] };
856
+ s == null ? E.requestedTargetMs = null : Ne(s) && s >= 0 && s <= 4e3 && (E.requestedTargetMs = s);
857
+ const d = /* @__PURE__ */ new Map();
858
+ return e.forEach((c) => {
859
+ if (c.type !== "inbound-rtp" || !Ne(c.timestamp)) return;
860
+ const h = c.kind ?? c.mediaType;
861
+ if (h !== "video" && h !== "audio") return;
862
+ const C = n.filter((Y) => Y.kind === h), p = c.trackIdentifier ? C.find((Y) => Y.trackId === c.trackIdentifier) : c.mid != null ? C.find((Y) => Y.mid === c.mid) : C.length === 1 ? C[0] : void 0;
863
+ if (!p) return;
864
+ const K = this.previous.get(c.id), U = K?.trackId === p.trackId && K.stats.ssrc === c.ssrc ? K.stats : void 0, T = U ? c.timestamp - U.timestamp : void 0, b = {
865
+ id: c.id,
866
+ trackId: p.trackId,
867
+ timestamp: c.timestamp
868
+ };
869
+ if (T !== void 0 && T > 0) {
870
+ b.intervalMs = T;
871
+ const Y = ge(c.jitterBufferEmittedCount, U?.jitterBufferEmittedCount), P = ge(c.jitterBufferDelay, U?.jitterBufferDelay);
872
+ Y !== void 0 && Y > 0 && P !== void 0 && (b.bufferDelayMs = P / Y * 1e3);
873
+ const V = ge(c.bytesReceived, U?.bytesReceived);
874
+ V !== void 0 && (b.bitrateBps = V * 8e3 / T);
875
+ }
876
+ if (h === "video") {
877
+ const Y = { ...b, display: p.display ?? "primary" };
878
+ if (b.intervalMs !== void 0) {
879
+ const P = ge(c.framesDecoded, U?.framesDecoded);
880
+ P !== void 0 && (Y.fps = P * 1e3 / b.intervalMs), Y.droppedFrames = ge(c.framesDropped, U?.framesDropped), Y.freezes = ge(c.freezeCount, U?.freezeCount);
881
+ }
882
+ E.video.push(Y);
883
+ } else E.audio.push(b);
884
+ E.timestamp = Math.max(E.timestamp, c.timestamp), d.set(
885
+ c.id,
886
+ U && c.timestamp <= U.timestamp ? K : { stats: c, trackId: p.trackId }
887
+ );
888
+ const $ = c.transportId ? e.get(c.transportId) : void 0, F = $?.selectedCandidatePairId ? e.get($.selectedCandidatePairId) : void 0;
889
+ F?.state === "succeeded" && Ne(F.currentRoundTripTime) && F.currentRoundTripTime >= 0 && (E.rttMs = F.currentRoundTripTime * 1e3);
890
+ }), this.previous = d, E.video.length || E.audio.length ? E : null;
891
+ }
892
+ }
893
+ const it = /* @__PURE__ */ new WeakSet();
894
+ function pn(t, e, n) {
895
+ const { peer: s, displays: E } = t, d = new mn();
896
+ let c, h = !1, C = !1, p = !1, K = 0, w = !1, U = !1;
897
+ const T = () => !h && !document.hidden && s.connectionState === "connected", b = (P) => {
898
+ if (!(!P && !w)) {
899
+ w = P !== null;
900
+ try {
901
+ e()?.(P);
902
+ } catch (V) {
903
+ console.error('[RemoteControl] customer callback "onPlaybackStats" threw:', V);
904
+ }
905
+ }
906
+ }, $ = () => {
907
+ C = !1, K++, clearTimeout(c), d.reset(), b(null);
908
+ }, F = async () => {
909
+ if (p || !T()) return;
910
+ if (it.has(s)) {
911
+ c = setTimeout(() => {
912
+ F();
913
+ }, 2e3);
914
+ return;
915
+ }
916
+ p = !0, it.add(s);
917
+ const P = K;
918
+ try {
919
+ const V = await s.getStats();
920
+ if (P !== K || !T()) return;
921
+ const B = s.getTransceivers().filter(
922
+ (J) => (J.currentDirection === "recvonly" || J.currentDirection === "sendrecv") && J.receiver.track.readyState !== "ended"
923
+ ).map((J) => ({
924
+ trackId: J.receiver.track.id,
925
+ kind: J.receiver.track.kind,
926
+ mid: J.mid,
927
+ display: E.get(J.receiver)
928
+ }));
929
+ b(d.read(V, B, n())), U = !1;
930
+ } catch (V) {
931
+ if (P !== K || !T()) return;
932
+ U || console.warn("[RemoteControl] could not read playback stats:", V), U = !0, d.reset(), b(null);
933
+ } finally {
934
+ p = !1, it.delete(s), C && T() && (c = setTimeout(
935
+ () => {
936
+ F();
937
+ },
938
+ P === K ? 2e3 : 0
939
+ ));
940
+ }
941
+ }, Y = () => {
942
+ if (!T()) {
943
+ $();
944
+ return;
945
+ }
946
+ C || (C = !0, F());
947
+ };
948
+ return document.addEventListener("visibilitychange", Y), s.addEventListener("connectionstatechange", Y), Y(), () => {
949
+ h = !0, document.removeEventListener("visibilitychange", Y), s.removeEventListener("connectionstatechange", Y), $();
950
+ };
951
+ }
952
+ function Cn(t, e) {
953
+ const n = t.createDataChannel("latency-trace-v1", {
954
+ ordered: !0,
955
+ negotiated: !0,
956
+ id: 2
957
+ });
958
+ let s = !1, E = !1, d = 0;
959
+ return n.onmessage = (c) => {
960
+ if (E) return;
961
+ let h;
962
+ try {
963
+ h = JSON.parse(c.data);
964
+ } catch (C) {
965
+ console.warn("Invalid latency trace message", C);
966
+ return;
967
+ }
968
+ h && typeof h == "object" && !Array.isArray(h) && e(h);
969
+ }, n.onclose = () => {
970
+ E = !0, s = !1;
971
+ }, {
972
+ accept(c) {
973
+ s = !E && c === 1;
974
+ },
975
+ wrap(c) {
976
+ if (!s || c.byteLength !== 32) return c;
977
+ const h = new DataView(c);
978
+ if (h.getUint8(0) !== 2 || h.getUint8(1) > 2) return c;
979
+ const C = new ArrayBuffer(38), p = new DataView(C);
980
+ return p.setUint8(0, 240), p.setUint8(1, 1), p.setUint32(2, ++d, !0), new Uint8Array(C, 6).set(new Uint8Array(c)), C;
981
+ },
982
+ close() {
983
+ E = !0, s = !1, n.onmessage = null, n.onclose = null, n.close();
984
+ }
985
+ };
986
+ }
987
+ class On {
988
+ generation = 0;
989
+ tail = Promise.resolve();
990
+ get currentGeneration() {
991
+ return this.generation;
992
+ }
993
+ enqueue(e) {
994
+ const n = ++this.generation;
995
+ return this.append(n, e);
996
+ }
997
+ /**
998
+ * Queues related work without superseding an already queued request.
999
+ *
1000
+ * The operation retains the generation current at enqueue time and becomes
1001
+ * stale if a later camera request increments it before this work starts.
1002
+ */
1003
+ enqueueCurrent(e) {
1004
+ return this.append(this.generation, e);
1005
+ }
1006
+ append(e, n) {
1007
+ const s = {
1008
+ generation: e,
1009
+ isCurrent: () => e === this.generation
1010
+ }, E = this.tail.then(() => n(s));
1011
+ return this.tail = E.catch(() => {
1012
+ }), E;
1013
+ }
1014
+ invalidate() {
1015
+ ++this.generation;
1016
+ }
1017
+ }
1018
+ function _n(t) {
1019
+ if (!t || typeof t != "object") return null;
1020
+ const e = t;
1021
+ if (e.type !== "cameraRequest" || typeof e.active != "boolean") return null;
1022
+ const n = { active: e.active };
1023
+ return (e.facingMode === "user" || e.facingMode === "environment") && (n.facingMode = e.facingMode), n;
1024
+ }
1025
+ function Dn(t) {
1026
+ const e = {
1027
+ frameRate: { ideal: 30, max: 30 }
1028
+ };
1029
+ return t?.facingMode && (e.facingMode = { ideal: t.facingMode }), e;
1030
+ }
1031
+ function gn(t, e) {
1032
+ return !t || t.facingMode !== e.facingMode;
1033
+ }
1034
+ function Tn(t) {
1035
+ const e = t.getSettings();
1036
+ return {
1037
+ width: e.width,
1038
+ height: e.height,
1039
+ frameRate: e.frameRate,
1040
+ deviceId: e.deviceId,
1041
+ label: t.label || void 0,
1042
+ facingMode: e.facingMode
1043
+ };
1044
+ }
1045
+ function Sn(t) {
1046
+ return {
1047
+ type: "cameraResult",
1048
+ granted: !0,
1049
+ camera: Tn(t)
1050
+ };
1051
+ }
1052
+ const ce = (...t) => {
1053
+ window.debugRemoteControl && console.log(...t);
1054
+ }, S = (...t) => {
1055
+ window.debugRemoteControl && console.warn(...t);
1056
+ }, L = (t, e, ...n) => {
1057
+ if (e)
1058
+ try {
1059
+ e(...n);
1060
+ } catch (s) {
1061
+ console.error(`[RemoteControl] customer callback "${t}" threw:`, s);
1062
+ }
1063
+ }, yn = (t) => t.includes("/android_") ? "android" : "ios", yt = (t, e) => {
1064
+ const n = new URL(t);
1065
+ return n.searchParams.set("token", e), n.toString();
1066
+ }, ot = 3, vn = 1e3, Kn = 15e3, An = 3e3, Mn = 4e3;
1067
+ function vt() {
1068
+ const t = crypto.getRandomValues(new Uint8Array(16));
1069
+ t[6] = t[6] & 15 | 64, t[8] = t[8] & 63 | 128;
1070
+ const e = Array.from(t, (n) => n.toString(16).padStart(2, "0")).join("");
1071
+ return `${e.slice(0, 8)}-${e.slice(8, 12)}-${e.slice(12, 16)}-${e.slice(16, 20)}-${e.slice(20)}`;
1072
+ }
1073
+ function Vn(t) {
1074
+ let e = { ...t };
1075
+ const { url: n, token: s, deviceModel: E } = e, d = e.sessionId ?? vt(), c = e.platform ?? yn(n ?? "");
1076
+ let h = {
1077
+ connection: "idle",
1078
+ videoReady: !1,
1079
+ controlReady: !1,
1080
+ duo: !1,
1081
+ duoState: null
1082
+ };
1083
+ const C = (r) => {
1084
+ h = { ...h, ...r }, L("onStateChange", e.onStateChange, h);
1085
+ }, p = (r) => C({ videoReady: r }), K = (r) => C({ duoState: r }), w = (r) => C({ duoError: r }), U = (r) => C({ duo: r }), T = (r) => ce(r);
1086
+ let b = null, $;
1087
+ const F = () => {
1088
+ $?.(), $ = b && e.onPlaybackStats ? pn(
1089
+ b,
1090
+ () => e.onPlaybackStats,
1091
+ () => e.jitterBufferTargetMs
1092
+ ) : void 0;
1093
+ }, Y = /* @__PURE__ */ new Map(), P = /* @__PURE__ */ new Set(), V = /* @__PURE__ */ new Set(), B = /* @__PURE__ */ new Map();
1094
+ let J = !1;
1095
+ const Re = /* @__PURE__ */ new Map(), at = (r, u, a) => {
1096
+ u.stop?.(), u.stop = hn(r, a, (l) => S("Video playback fallback:", l));
1097
+ }, Mt = () => {
1098
+ Re.clear();
1099
+ for (const [r, u] of Y)
1100
+ u.clear?.(), u.stop?.(), u.stop = void 0, r.srcObject = null;
1101
+ };
1102
+ let Ee = !1, Te = !1, Ie = 0, D = null, N = null, x = null, ke = null, fe, Se, ye, Ue, he, le = 0, Pe = 0, ne = !1, de = null, z = null, ue;
1103
+ const je = new On();
1104
+ let ve = null, Le = null, Xe = e.microphoneEnabled ?? !1, Qe = !1, Ke = null, te = null, Fe = 0, st = Promise.resolve(), me = null, Ae = !1, re = /* @__PURE__ */ new Map(), ee = /* @__PURE__ */ new Map(), ae = /* @__PURE__ */ new Map(), ie = /* @__PURE__ */ new Map(), q = null, Me = null, ct = 0;
1105
+ const Be = (r) => {
1106
+ if (r === null && Me === null) return;
1107
+ Me = r;
1108
+ const u = ++ct;
1109
+ queueMicrotask(() => {
1110
+ u === ct && L("onAxSnapshotChange", e.onAxSnapshotChange, r);
1111
+ });
1112
+ };
1113
+ let pe = null, Ce = /* @__PURE__ */ new Map();
1114
+ const wt = (r, u) => new Promise((a, l) => {
1115
+ const y = D;
1116
+ if (!y || y.readyState !== WebSocket.OPEN) {
1117
+ l(new Error("Simulator disconnected"));
1118
+ return;
1119
+ }
1120
+ const m = vt(), O = setTimeout(() => {
1121
+ Ce.delete(m), l(new Error("Device control timed out"));
1122
+ }, 5e3);
1123
+ Ce.set(m, { resolve: a, reject: l, timer: O }), y.send(JSON.stringify({ type: r, id: m, ...u }));
1124
+ }), Oe = (r) => {
1125
+ pe !== r && (pe = r, C({ connection: r }), L("onConnectionStateChange", e.onConnectionStateChange, r));
1126
+ }, se = (r) => {
1127
+ !x || x.readyState !== "open" || (x.send(ke?.wrap(r) ?? r), q?.bumpActivity());
1128
+ }, Yt = () => {
1129
+ D && D.readyState === WebSocket.OPEN && D.send(
1130
+ JSON.stringify({
1131
+ type: "keepAlive",
1132
+ sessionId: d
1133
+ })
1134
+ );
1135
+ }, lt = () => {
1136
+ fe && window.clearInterval(fe), fe = window.setInterval(Yt, 1e4);
1137
+ }, we = () => {
1138
+ fe && (window.clearInterval(fe), fe = void 0);
1139
+ }, xe = () => {
1140
+ Se && (window.clearTimeout(Se), Se = void 0);
1141
+ }, We = () => {
1142
+ ye && (window.clearTimeout(ye), ye = void 0);
1143
+ }, Ye = () => {
1144
+ Ue && (window.clearInterval(Ue), Ue = void 0);
1145
+ }, be = () => {
1146
+ he !== void 0 && (window.clearTimeout(he), he = void 0);
1147
+ }, bt = () => {
1148
+ Ae || (Ae = !0, Ye(), p(!0), Oe("connected"));
1149
+ }, H = (r) => {
1150
+ for (const u of r.getTracks())
1151
+ try {
1152
+ u.stop();
1153
+ } catch (a) {
1154
+ S("track.stop() failed:", a);
1155
+ }
1156
+ }, Nt = () => {
1157
+ const r = z;
1158
+ r && (z = null, H(r));
1159
+ }, dt = (r) => {
1160
+ const u = st.then(r).catch((a) => {
1161
+ S("microphone operation failed:", a);
1162
+ });
1163
+ return st = u, u;
1164
+ }, ze = () => Xe || Qe, ut = (r) => {
1165
+ const u = `ui-mic-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
1166
+ me = u, r.send(JSON.stringify({ type: "microphoneStart", id: u }));
1167
+ }, Ze = () => dt(() => Rt()), Rt = async () => {
1168
+ const r = Fe, u = () => r === Fe && ze(), a = (f) => {
1169
+ L("onMicrophoneStateChange", e.onMicrophoneStateChange, {
1170
+ active: !1,
1171
+ error: f
1172
+ });
1173
+ };
1174
+ if (!u()) return;
1175
+ const l = D, y = Ke;
1176
+ if (!l || l.readyState !== WebSocket.OPEN || !y || te) return;
1177
+ if (!navigator.mediaDevices || typeof navigator.mediaDevices.getUserMedia != "function") {
1178
+ console.warn(
1179
+ "[RemoteControl] navigator.mediaDevices.getUserMedia unavailable. getUserMedia requires a secure context (https or http://localhost)."
1180
+ ), a("Microphone capture requires a secure context (https)");
1181
+ return;
1182
+ }
1183
+ let m = null;
1184
+ try {
1185
+ m = await navigator.mediaDevices.getUserMedia({ audio: !0, video: !1 });
1186
+ } catch (f) {
1187
+ console.warn("[RemoteControl] microphone getUserMedia denied/failed:", f);
1188
+ }
1189
+ if (!u()) {
1190
+ m && H(m);
1191
+ return;
1192
+ }
1193
+ if (!m) {
1194
+ a("Microphone permission denied or no device available");
1195
+ return;
1196
+ }
1197
+ const O = m.getAudioTracks()[0] ?? null;
1198
+ if (!O) {
1199
+ H(m), a("Captured stream has no audio track");
1200
+ return;
1201
+ }
1202
+ try {
1203
+ await y.replaceTrack(O);
1204
+ } catch (f) {
1205
+ S("replaceTrack(audioTrack) failed:", f), H(m), a("Failed to attach the microphone track to the connection");
1206
+ return;
1207
+ }
1208
+ if (!u()) {
1209
+ try {
1210
+ await y.replaceTrack(null);
1211
+ } catch (f) {
1212
+ S("replaceTrack(null) on stale mic attach failed:", f);
1213
+ }
1214
+ H(m);
1215
+ return;
1216
+ }
1217
+ te = m, O.onended = () => {
1218
+ te === m && qe("microphone capture ended by the browser");
1219
+ }, ut(l), L("onMicrophoneStateChange", e.onMicrophoneStateChange, {
1220
+ active: !0,
1221
+ label: O.label || void 0
1222
+ });
1223
+ }, qe = (r) => (++Fe, me = null, dt(async () => {
1224
+ const u = Ke, a = te;
1225
+ if (te = null, u && a)
1226
+ try {
1227
+ await u.replaceTrack(null);
1228
+ } catch (y) {
1229
+ S("replaceTrack(null) on mic detach failed:", y);
1230
+ }
1231
+ a && H(a);
1232
+ const l = D;
1233
+ if (a && l && l.readyState === WebSocket.OPEN) {
1234
+ const y = `ui-mic-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
1235
+ l.send(JSON.stringify({ type: "microphoneStop", id: y }));
1236
+ }
1237
+ (a || r) && L("onMicrophoneStateChange", e.onMicrophoneStateChange, {
1238
+ active: !1,
1239
+ ...r !== void 0 && { error: r }
1240
+ });
1241
+ })), Et = (r, u) => {
1242
+ let a;
1243
+ try {
1244
+ a = Sn(u), console.info(
1245
+ `[RemoteControl] camera capture: ${a.camera?.width}x${a.camera?.height} @ ${a.camera?.frameRate ?? "?"}fps` + (a.camera?.label ? ` — ${a.camera.label}` : "")
1246
+ );
1247
+ } catch (l) {
1248
+ S("getSettings() on outbound camera track failed:", l), a = {
1249
+ type: "cameraResult",
1250
+ granted: !0,
1251
+ camera: {
1252
+ label: u.label || void 0
1253
+ }
1254
+ };
1255
+ }
1256
+ r.send(JSON.stringify(a)), L("onCameraDemandChange", e.onCameraDemandChange, !0, !0, a.camera);
1257
+ }, It = (r) => {
1258
+ if (!r) return;
1259
+ const u = r.indexOf("/"), l = (u >= 0 ? r.slice(u + 1) : r).toUpperCase();
1260
+ return l === "HEVC" ? "H265" : l;
1261
+ }, kt = async () => {
1262
+ const r = de, u = e.onCameraStats;
1263
+ if (!r || !u) return;
1264
+ let a;
1265
+ try {
1266
+ a = await r.getStats();
1267
+ } catch {
1268
+ return;
1269
+ }
1270
+ let l, y, m;
1271
+ if (a.forEach((R) => {
1272
+ R.type === "outbound-rtp" && R.kind === "video" ? l = R : R.type === "remote-inbound-rtp" && R.kind === "video" && (m = R);
1273
+ }), l?.codecId) {
1274
+ const R = a.get(l.codecId);
1275
+ R && (y = R.mimeType);
1276
+ }
1277
+ if (!l) return;
1278
+ const O = l.timestamp ?? Date.now(), f = Le;
1279
+ let j, k, X;
1280
+ if (f && O > f.timestamp) {
1281
+ const R = (O - f.timestamp) / 1e3;
1282
+ if (typeof l.framesEncoded == "number" && typeof f.framesEncoded == "number" && (j = Math.max(0, (l.framesEncoded - f.framesEncoded) / R)), typeof l.bytesSent == "number" && typeof f.bytesSent == "number" && (k = Math.max(0, (l.bytesSent - f.bytesSent) * 8 / R)), typeof l.packetsSent == "number" && typeof f.packetsSent == "number" && m && typeof m.packetsLost == "number" && typeof f.packetsLost == "number") {
1283
+ const v = l.packetsSent - f.packetsSent, Ve = m.packetsLost - f.packetsLost;
1284
+ v > 0 && (X = Math.max(0, Math.min(100, Ve / v * 100)));
1285
+ }
1286
+ }
1287
+ Le = {
1288
+ timestamp: O,
1289
+ framesEncoded: l.framesEncoded,
1290
+ bytesSent: l.bytesSent,
1291
+ packetsSent: l.packetsSent,
1292
+ packetsLost: m?.packetsLost
1293
+ };
1294
+ const M = {
1295
+ codec: It(y),
1296
+ encoderImplementation: l.encoderImplementation,
1297
+ hardwareAccelerated: typeof l.powerEfficientEncoder == "boolean" ? l.powerEfficientEncoder : void 0,
1298
+ framesPerSecond: j,
1299
+ framesEncoded: l.framesEncoded,
1300
+ bitrateBps: k,
1301
+ width: l.frameWidth,
1302
+ height: l.frameHeight,
1303
+ qualityLimitationReason: l.qualityLimitationReason,
1304
+ rttMs: typeof m?.roundTripTime == "number" ? m.roundTripTime * 1e3 : void 0,
1305
+ packetsLostPct: X
1306
+ };
1307
+ L("onCameraStats", e.onCameraStats, M);
1308
+ }, ft = () => {
1309
+ ve === null && (Le = null, ve = setInterval(() => {
1310
+ kt();
1311
+ }, 1e3));
1312
+ }, $e = () => {
1313
+ ve !== null && (clearInterval(ve), ve = null), Le = null, L("onCameraStats", e.onCameraStats, null);
1314
+ }, Ut = (r, u, a, l) => je.enqueue(async ({ isCurrent: y }) => {
1315
+ const m = () => y() && l() && D === u && de === a;
1316
+ if (!m()) return;
1317
+ if (!r.active) {
1318
+ const M = z;
1319
+ try {
1320
+ await a.replaceTrack(null);
1321
+ } catch (R) {
1322
+ S("replaceTrack(null) on camera detach failed:", R);
1323
+ }
1324
+ if (z === M && (z = null, ue = void 0, M && H(M)), $e(), !m()) return;
1325
+ L("onCameraDemandChange", e.onCameraDemandChange, !1);
1326
+ return;
1327
+ }
1328
+ L("onCameraDemandChange", e.onCameraDemandChange, !0);
1329
+ const O = z, f = O?.getVideoTracks()[0], j = ue;
1330
+ if (f?.readyState === "live" && j && !gn(j, r)) {
1331
+ ue = r, Et(u, f), ft();
1332
+ return;
1333
+ }
1334
+ if (O) {
1335
+ try {
1336
+ await a.replaceTrack(null);
1337
+ } catch (M) {
1338
+ S("replaceTrack(null) before camera switch failed:", M);
1339
+ }
1340
+ if (z === O && (z = null, ue = void 0, H(O)), $e(), !m()) return;
1341
+ }
1342
+ if (!navigator.mediaDevices || typeof navigator.mediaDevices.getUserMedia != "function") {
1343
+ if (console.warn(
1344
+ "[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."
1345
+ ), !m()) return;
1346
+ u.send(JSON.stringify({ type: "cameraResult", granted: !1 })), L("onCameraDemandChange", e.onCameraDemandChange, !0, !1);
1347
+ return;
1348
+ }
1349
+ let k = null;
1350
+ try {
1351
+ k = await navigator.mediaDevices.getUserMedia({
1352
+ video: Dn(r),
1353
+ audio: !1
1354
+ });
1355
+ } catch (M) {
1356
+ console.warn("[RemoteControl] getUserMedia denied/failed:", M);
1357
+ }
1358
+ if (!m()) {
1359
+ k && H(k);
1360
+ return;
1361
+ }
1362
+ if (!k) {
1363
+ u.send(JSON.stringify({ type: "cameraResult", granted: !1 })), L("onCameraDemandChange", e.onCameraDemandChange, !0, !1);
1364
+ return;
1365
+ }
1366
+ const X = k.getVideoTracks()[0] ?? null;
1367
+ if (!X) {
1368
+ if (H(k), !m()) return;
1369
+ u.send(JSON.stringify({ type: "cameraResult", granted: !1 })), L("onCameraDemandChange", e.onCameraDemandChange, !0, !1);
1370
+ return;
1371
+ }
1372
+ try {
1373
+ X.contentHint = "motion";
1374
+ } catch {
1375
+ }
1376
+ try {
1377
+ await a.replaceTrack(X);
1378
+ } catch (M) {
1379
+ if (S("replaceTrack(videoTrack) failed:", M), H(k), !m()) return;
1380
+ u.send(JSON.stringify({ type: "cameraResult", granted: !1 })), L("onCameraDemandChange", e.onCameraDemandChange, !0, !1);
1381
+ return;
1382
+ }
1383
+ if (!m()) {
1384
+ try {
1385
+ await a.replaceTrack(null);
1386
+ } catch (M) {
1387
+ S("replaceTrack(null) for stale camera attach failed:", M);
1388
+ }
1389
+ H(k);
1390
+ return;
1391
+ }
1392
+ try {
1393
+ const M = a.getParameters();
1394
+ (!M.encodings || M.encodings.length === 0) && (M.encodings = [{}]), M.encodings[0].maxBitrate = 8e6, M.encodings[0].maxFramerate = 30, M.degradationPreference = "maintain-framerate", await a.setParameters(M);
1395
+ } catch (M) {
1396
+ S("setParameters on outbound camera failed:", M);
1397
+ }
1398
+ if (!m()) {
1399
+ try {
1400
+ await a.replaceTrack(null);
1401
+ } catch (M) {
1402
+ S("replaceTrack(null) for stale camera finalize failed:", M);
1403
+ }
1404
+ H(k);
1405
+ return;
1406
+ }
1407
+ z = k, ue = r, X.onended = () => {
1408
+ z === k && je.enqueueCurrent(async ({ isCurrent: M }) => {
1409
+ if (!(!M() || z !== k || !l() || D !== u || de !== a)) {
1410
+ try {
1411
+ await a.replaceTrack(null);
1412
+ } catch (R) {
1413
+ S("replaceTrack(null) after camera ended failed:", R);
1414
+ }
1415
+ !M() || z !== k || !l() || D !== u || de !== a || (z = null, ue = void 0, H(k), $e(), u.send(JSON.stringify({ type: "cameraResult", granted: !1 })), L("onCameraDemandChange", e.onCameraDemandChange, !0, !1));
1416
+ }
1417
+ }).catch((M) => S("camera ended cleanup failed:", M));
1418
+ }, m() && (Et(u, X), ft());
1419
+ }), _e = () => {
1420
+ for (const r of V) r();
1421
+ V.clear();
1422
+ for (const r of B.values()) clearTimeout(r);
1423
+ B.clear();
1424
+ for (const r of ee.values())
1425
+ r(new Error("Simulator disconnected"));
1426
+ for (const r of ie.values())
1427
+ r(new Error("Simulator disconnected"));
1428
+ ee.clear(), re.clear(), ie.clear(), ae.clear(), $?.(), $ = void 0, Mt(), b = null;
1429
+ for (const r of Ce.values())
1430
+ clearTimeout(r.timer), r.reject(new Error("Simulator disconnected"));
1431
+ Ce.clear(), K(null), C({ controlReady: !1, videoReady: !1 }), We(), be(), Ye(), q && (q.stop(), q = null), Me !== null && Be(null), je.invalidate(), $e(), Nt(), ue = void 0, de = null, ++Fe, Qe = !1, me = null, te && (H(te), te = null, L("onMicrophoneStateChange", e.onMicrophoneStateChange, {
1432
+ active: !1
1433
+ })), Ke = null, D && (D.onopen = null, D.onmessage = null, D.onerror = null, D.onclose = null, D.close(), D = null), ke?.close(), ke = null, N && (N.onconnectionstatechange = null, N.oniceconnectionstatechange = null, N.ontrack = null, N.onicecandidate = null, N.close(), N = null), x && (x.onopen = null, x.onclose = null, x.onerror = null, x.close(), x = null);
1434
+ }, ht = () => {
1435
+ document.hidden ? we() : lt();
1436
+ }, Pt = async () => {
1437
+ if (e.transport) return e.transport.isTerminated?.() ?? !1;
1438
+ if (typeof navigator < "u" && navigator.onLine === !1)
1439
+ return !1;
1440
+ let r;
1441
+ try {
1442
+ const l = new URL(n);
1443
+ l.protocol = l.protocol === "wss:" ? "https:" : l.protocol === "ws:" ? "http:" : l.protocol, r = yt(l.toString(), s);
1444
+ } catch {
1445
+ return !1;
1446
+ }
1447
+ const u = new AbortController(), a = window.setTimeout(() => u.abort(), Mn);
1448
+ try {
1449
+ return (await fetch(r, { method: "GET", cache: "no-store", signal: u.signal })).status === 404;
1450
+ } catch {
1451
+ return !1;
1452
+ } finally {
1453
+ window.clearTimeout(a);
1454
+ }
1455
+ }, Lt = () => {
1456
+ Ee || (Ee = !0, le += 1, xe(), We(), be(), _e(), T("Instance terminated"), we(), Oe("terminated"), L("onTerminated", e.onTerminated));
1457
+ }, Ft = () => {
1458
+ if (Ee || Te) return;
1459
+ Te = !0;
1460
+ const r = Ie;
1461
+ Pt().catch(() => !1).then((u) => {
1462
+ r === Ie && (Te = !1, u && Lt());
1463
+ });
1464
+ }, De = (r, u) => {
1465
+ if (Ee || u !== le)
1466
+ return;
1467
+ if (Ft(), ne) {
1468
+ if (!e.autoReconnect) {
1469
+ T(`Connection failed after it was established: ${r}`), we(), Oe("failed"), _e();
1470
+ return;
1471
+ }
1472
+ T(`Reconnecting after established session dropped: ${r}`), ne = !1, Pe = -1;
1473
+ }
1474
+ xe();
1475
+ const a = Pe + 1;
1476
+ if (a >= ot) {
1477
+ T(`Connection failed after ${ot} attempts: ${r}`), we(), Oe("failed"), _e();
1478
+ return;
1479
+ }
1480
+ T(`Retrying connection (${a + 1}/${ot})`), Oe("reconnecting"), _e(), Se = window.setTimeout(() => {
1481
+ Se = void 0, u === le && mt(a);
1482
+ }, vn);
1483
+ }, mt = async (r = 0) => {
1484
+ const { openUrl: u, axPollIntervalMs: a, axMaxBackoffMs: l, androidElementTreeOptions: y } = e;
1485
+ if (Ee) return;
1486
+ const m = le + 1;
1487
+ le = m, Pe = r, ne = !1, r === 0 && pe !== "reconnecting" && Oe("connecting"), xe(), We(), Ye(), Ae = !1, p(!1), _e();
1488
+ const O = () => m === le;
1489
+ ye = window.setTimeout(() => {
1490
+ ye = void 0, !(!O() || ne) && De("Connection did not succeed within 15 seconds", m);
1491
+ }, Kn);
1492
+ try {
1493
+ const f = e.transport ? await e.transport.connect() : new WebSocket(yt(n, s));
1494
+ if (!O()) {
1495
+ f.close();
1496
+ return;
1497
+ }
1498
+ if (D = f, await new Promise((_, o) => {
1499
+ let I = !1;
1500
+ const W = () => A(() => o(new Error("Connection stopped")));
1501
+ V.add(W);
1502
+ const g = window.setTimeout(
1503
+ () => A(() => o(new Error("WebSocket connection timeout"))),
1504
+ 3e4
1505
+ ), A = (Z) => {
1506
+ I || (I = !0, V.delete(W), window.clearTimeout(g), Z());
1507
+ };
1508
+ f.onopen = () => {
1509
+ !O() || D !== f || A(_);
1510
+ }, f.onerror = (Z) => {
1511
+ !O() || D !== f || (T("WebSocket error: " + Z), A(() => o(new Error("WebSocket connection failed"))));
1512
+ }, f.onclose = () => {
1513
+ !O() || D !== f || (T("WebSocket closed"), A(() => o(new Error("WebSocket closed before connection was established"))));
1514
+ }, f.readyState === WebSocket.OPEN ? A(_) : f.readyState !== WebSocket.CONNECTING && A(() => o(new Error("WebSocket is closed")));
1515
+ }), !O() || D !== f)
1516
+ return;
1517
+ f.onerror = (_) => {
1518
+ !O() || D !== f || T("WebSocket error: " + _);
1519
+ }, f.onclose = () => {
1520
+ !O() || D !== f || T("WebSocket closed");
1521
+ };
1522
+ const j = new Promise((_, o) => {
1523
+ let I = !1;
1524
+ const W = () => g(() => o(new Error("Connection stopped")));
1525
+ V.add(W);
1526
+ const g = (G) => {
1527
+ I || (I = !0, V.delete(W), window.clearTimeout(A), f.removeEventListener("message", Z), G());
1528
+ }, A = window.setTimeout(
1529
+ () => g(() => o(new Error("RTCConfiguration timeout"))),
1530
+ 3e4
1531
+ ), Z = (G) => {
1532
+ if (!(!O() || D !== f))
1533
+ try {
1534
+ const Q = JSON.parse(G.data);
1535
+ if (Q.type === "signalingError" && Q.requestType === "requestRtcConfiguration" && Q.sessionId === d) {
1536
+ const Wt = typeof Q.error == "string" ? Q.error : "Unable to load streaming configuration";
1537
+ g(() => o(new Error(Wt)));
1538
+ } else Q.type === "rtcConfiguration" && g(
1539
+ () => _({
1540
+ rtcConfiguration: Q.rtcConfiguration,
1541
+ cameraSupported: Q.cameraSupported === !0,
1542
+ foldSupported: Q.foldSupported === !0
1543
+ })
1544
+ );
1545
+ } catch (Q) {
1546
+ console.error("Error handling RTC configuration:", Q), g(() => o(Q));
1547
+ }
1548
+ };
1549
+ f.addEventListener("message", Z), f.send(
1550
+ JSON.stringify({
1551
+ type: "requestRtcConfiguration",
1552
+ sessionId: d
1553
+ })
1554
+ );
1555
+ }), {
1556
+ rtcConfiguration: k,
1557
+ cameraSupported: X,
1558
+ foldSupported: M
1559
+ } = await j;
1560
+ if (!O() || D !== f)
1561
+ return;
1562
+ const R = E === "iphone-duo" || M;
1563
+ U(R);
1564
+ const v = new RTCPeerConnection({ ...k, iceTransportPolicy: "relay" });
1565
+ N = v;
1566
+ const Ve = { peer: v, displays: /* @__PURE__ */ new Map() };
1567
+ b = Ve, F(), v.addTransceiver("audio", { direction: "recvonly" });
1568
+ const Bt = v.addTransceiver("video", { direction: "recvonly" }), xt = R ? v.addTransceiver("video", { direction: "recvonly" }) : null, _t = c === "ios" || X, et = _t ? v.addTransceiver("video", {
1569
+ direction: "sendonly"
1570
+ }) : null;
1571
+ if (de = et?.sender ?? null, Ke = (_t ? v.addTransceiver("audio", {
1572
+ direction: "sendonly"
1573
+ }) : null)?.sender ?? null, RTCRtpReceiver.getCapabilities) {
1574
+ const _ = RTCRtpReceiver.getCapabilities("video");
1575
+ if (_ && _.codecs) {
1576
+ const I = _.codecs.sort((W, g) => {
1577
+ const A = (Z) => {
1578
+ const G = Z.mimeType.toLowerCase();
1579
+ return G.includes("vp9") ? 1 : G.includes("h265") || G.includes("hevc") ? 2 : G.includes("h264") || G.includes("avc") ? 3 : 4;
1580
+ };
1581
+ return A(W) - A(g);
1582
+ });
1583
+ Bt.setCodecPreferences(I), xt?.setCodecPreferences(I), ce("Set codec preferences:", I.map((W) => W.mimeType).join(", "));
1584
+ }
1585
+ }
1586
+ if (et && RTCRtpSender.getCapabilities) {
1587
+ const _ = RTCRtpSender.getCapabilities("video");
1588
+ if (_ && _.codecs) {
1589
+ const o = /* @__PURE__ */ new Set(["42e01f", "42e028", "640c1f"]), I = (g) => {
1590
+ const A = g.mimeType.toLowerCase(), G = (g.sdpFmtpLine || "").toLowerCase().match(/profile-level-id=([0-9a-f]{6})/), Q = G ? G[1] : "";
1591
+ return A === "video/h265" || A === "video/hevc" ? 1 : A === "video/h264" && o.has(Q) ? 2 : A === "video/h264" ? 3 : A === "video/vp9" ? 4 : A === "video/vp8" ? 5 : A === "video/rtx" || A === "video/red" || A === "video/ulpfec" ? 0 : 6;
1592
+ }, W = [..._.codecs].sort((g, A) => I(g) - I(A));
1593
+ try {
1594
+ et.setCodecPreferences(W), ce(
1595
+ "Outbound camera codec preferences:",
1596
+ W.map((g) => `${g.mimeType}${g.sdpFmtpLine ? `[${g.sdpFmtpLine}]` : ""}`).join(", ")
1597
+ );
1598
+ } catch (g) {
1599
+ S("Failed to set outbound camera codec preferences:", g);
1600
+ }
1601
+ }
1602
+ }
1603
+ const oe = v.createDataChannel("control", {
1604
+ ordered: !0,
1605
+ negotiated: !0,
1606
+ id: 1
1607
+ });
1608
+ x = oe;
1609
+ const tt = !R && e.onTrace ? Cn(v, (_) => {
1610
+ O() && N === v && L("onTrace", e.onTrace, _);
1611
+ }) : null;
1612
+ if (ke = tt, oe.onopen = () => {
1613
+ if (!O() || x !== oe || D !== f)
1614
+ return;
1615
+ ne = !0, C({ controlReady: !0 }), We(), T("Control channel opened"), R && f.send(JSON.stringify({ type: "getFoldState", id: "duo-capabilities" })), q || (q = new En({
1616
+ platform: c,
1617
+ baseIntervalMs: a,
1618
+ maxBackoffMs: l,
1619
+ androidElementTreeOptions: y,
1620
+ send: (o) => {
1621
+ if (!D || D.readyState !== WebSocket.OPEN) return !1;
1622
+ try {
1623
+ return D.send(JSON.stringify(o)), !0;
1624
+ } catch {
1625
+ return !1;
1626
+ }
1627
+ },
1628
+ onSnapshot: Be,
1629
+ onStatusChange: (o, I) => {
1630
+ L("onAxStatusChange", e.onAxStatusChange, o, I);
1631
+ }
1632
+ }), (e.inspectMode === !0 || e.inspectMode === "hover-only") && q.start());
1633
+ const _ = () => {
1634
+ !O() || Ae || x !== oe || D !== f || f.readyState !== WebSocket.OPEN || f.send(JSON.stringify({ type: "requestFrame", sessionId: d }));
1635
+ };
1636
+ if (_(), Ye(), Ue = window.setInterval(() => {
1637
+ if (!O() || Ae || x !== oe || D !== f || f.readyState !== WebSocket.OPEN) {
1638
+ Ye();
1639
+ return;
1640
+ }
1641
+ _();
1642
+ }, 250), u) {
1643
+ try {
1644
+ const o = decodeURIComponent(u);
1645
+ T("Opening URL"), f.send(
1646
+ JSON.stringify({
1647
+ type: "openUrl",
1648
+ url: o,
1649
+ sessionId: d
1650
+ })
1651
+ );
1652
+ } catch (o) {
1653
+ console.error({ error: o }, "Error decoding URL, falling back to the original URL"), f.send(
1654
+ JSON.stringify({
1655
+ type: "openUrl",
1656
+ url: u,
1657
+ sessionId: d
1658
+ })
1659
+ );
1660
+ }
1661
+ q?.bumpActivity();
1662
+ }
1663
+ }, oe.onclose = () => {
1664
+ !O() || x !== oe || (C({ controlReady: !1 }), T("Control channel closed"));
1665
+ }, oe.onerror = (_) => {
1666
+ !O() || x !== oe || (console.error("Control channel error:", _), T("Control channel error: " + _));
1667
+ }, v.onconnectionstatechange = () => {
1668
+ !O() || N !== v || (T("Connection state: " + v.connectionState), v.connectionState === "failed" && ne && De("WebRTC connection entered failed state", m));
1669
+ }, v.oniceconnectionstatechange = () => {
1670
+ if (!O() || N !== v)
1671
+ return;
1672
+ const _ = v.iceConnectionState;
1673
+ if (T("ICE state: " + _), _ === "connected" || _ === "completed") {
1674
+ be(), ze() && !te && Ze();
1675
+ return;
1676
+ }
1677
+ if (_ === "failed") {
1678
+ be(), ne && De("ICE connection entered failed state", m);
1679
+ return;
1680
+ }
1681
+ _ === "disconnected" && ne && e.autoReconnect && he === void 0 && (he = window.setTimeout(() => {
1682
+ he = void 0, !(!O() || N !== v) && v.iceConnectionState === "disconnected" && De("ICE stayed disconnected past grace period", m);
1683
+ }, An));
1684
+ }, v.ontrack = (_) => {
1685
+ if (!O() || N !== v)
1686
+ return;
1687
+ Tt(_.receiver, e.jitterBufferTargetMs);
1688
+ const o = _.track.id === "duo-inner" || _.streams.some((I) => I.id === "duo-inner");
1689
+ if (_.track.kind === "video" && Ve.displays.set(_.receiver, o ? "inner" : "primary"), T("Received remote track: " + _.track.kind), _.track.kind === "video") {
1690
+ const I = o ? "inner" : "primary", W = R ? new MediaStream([_.track]) : _.streams[0] ?? new MediaStream([_.track]);
1691
+ Re.set(I, W);
1692
+ for (const [g, A] of Y)
1693
+ A.display === I && at(g, A, W);
1694
+ }
1695
+ }, v.onicecandidate = (_) => {
1696
+ if (!(!O() || N !== v || D !== f))
1697
+ if (_.candidate && f.readyState === WebSocket.OPEN) {
1698
+ const o = {
1699
+ type: "candidate",
1700
+ candidate: _.candidate.candidate,
1701
+ sdpMid: _.candidate.sdpMid,
1702
+ sdpMLineIndex: _.candidate.sdpMLineIndex,
1703
+ sessionId: d
1704
+ };
1705
+ f.send(JSON.stringify(o)), T("Sent ICE candidate");
1706
+ } else
1707
+ T("ICE candidate gathering completed");
1708
+ }, f.onmessage = async (_) => {
1709
+ if (!O() || D !== f)
1710
+ return;
1711
+ let o;
1712
+ try {
1713
+ o = JSON.parse(_.data);
1714
+ } catch (I) {
1715
+ S("Error parsing message:", I);
1716
+ return;
1717
+ }
1718
+ if (!q?.handleMessage(o))
1719
+ switch (T("Received: " + o.type), o.type) {
1720
+ case "performActionsResult":
1721
+ case "foldStateResult":
1722
+ case "foldStateChanged": {
1723
+ if (!R) break;
1724
+ o.state ? (K(o.state), w(void 0)) : o.id === "duo-capabilities" && w(o.error || "This instance does not support native iPhone Duo displays.");
1725
+ const g = Ce.get(o.id);
1726
+ g && (clearTimeout(g.timer), Ce.delete(o.id), o.error ? g.reject(new Error(o.error)) : g.resolve());
1727
+ break;
1728
+ }
1729
+ case "signalingError": {
1730
+ if (o.requestType !== "offer" || o.sessionId !== d)
1731
+ break;
1732
+ const g = typeof o.error == "string" ? o.error : "Unable to establish the streaming connection";
1733
+ T("Error: " + g), De(g, m);
1734
+ break;
1735
+ }
1736
+ case "answer":
1737
+ if (!N || N !== v) {
1738
+ T("No peer connection, skipping answer");
1739
+ break;
1740
+ }
1741
+ if (tt?.accept(o.latencyTraceVersion), await v.setRemoteDescription(
1742
+ new RTCSessionDescription({
1743
+ type: "answer",
1744
+ sdp: o.sdp
1745
+ })
1746
+ ), !O() || N !== v)
1747
+ return;
1748
+ T("Set remote description");
1749
+ break;
1750
+ case "candidate":
1751
+ if (!N || N !== v) {
1752
+ T("No peer connection, skipping candidate");
1753
+ break;
1754
+ }
1755
+ if (await v.addIceCandidate(
1756
+ new RTCIceCandidate({
1757
+ candidate: o.candidate,
1758
+ sdpMid: o.sdpMid,
1759
+ sdpMLineIndex: o.sdpMLineIndex
1760
+ })
1761
+ ), !O() || N !== v)
1762
+ return;
1763
+ T("Added ICE candidate");
1764
+ break;
1765
+ case "screenshot":
1766
+ case "screenshotResult": {
1767
+ if (typeof o.id != "string") {
1768
+ S("Received invalid screenshot success message:", o);
1769
+ break;
1770
+ }
1771
+ const g = wn(o);
1772
+ if (g) {
1773
+ const G = ee.get(o.id);
1774
+ if (typeof G != "function") {
1775
+ S(`Received screenshot error for unknown or handled id: ${o.id}`);
1776
+ break;
1777
+ }
1778
+ S(`Received screenshot error for id ${o.id}: ${g}`), G(new Error(g)), re.delete(o.id), ee.delete(o.id), clearTimeout(B.get(o.id)), B.delete(o.id);
1779
+ break;
1780
+ }
1781
+ const A = Yn(o);
1782
+ if (!A) {
1783
+ S("Received screenshot message without image data:", o);
1784
+ break;
1785
+ }
1786
+ const Z = re.get(o.id);
1787
+ if (typeof Z != "function") {
1788
+ S(`Received screenshot data for unknown or handled id: ${o.id}`);
1789
+ break;
1790
+ }
1791
+ ce(`Received screenshot data for id ${o.id}`), Z(A), re.delete(o.id), ee.delete(o.id), clearTimeout(B.get(o.id)), B.delete(o.id);
1792
+ break;
1793
+ }
1794
+ case "screenshotError":
1795
+ if (typeof o.id != "string" || typeof o.message != "string") {
1796
+ S("Received invalid screenshot error message:", o);
1797
+ break;
1798
+ }
1799
+ const I = ee.get(o.id);
1800
+ if (typeof I != "function") {
1801
+ S(`Received screenshot error for unknown or handled id: ${o.id}`);
1802
+ break;
1803
+ }
1804
+ S(`Received screenshot error for id ${o.id}: ${o.message}`), I(new Error(o.message)), re.delete(o.id), ee.delete(o.id), clearTimeout(B.get(o.id)), B.delete(o.id);
1805
+ break;
1806
+ case "cameraRequest": {
1807
+ const g = de;
1808
+ if (!g)
1809
+ break;
1810
+ const A = _n(o);
1811
+ if (!A) {
1812
+ S("Received invalid cameraRequest:", o);
1813
+ break;
1814
+ }
1815
+ console.info("[RemoteControl] cameraRequest received:", A.active, A.facingMode), await Ut(A, f, g, O);
1816
+ break;
1817
+ }
1818
+ case "microphoneRequest": {
1819
+ if (!Ke)
1820
+ break;
1821
+ const g = o.active === !0;
1822
+ if (Qe = g, console.info("[RemoteControl] microphoneRequest received, active=", g), !g) {
1823
+ Xe || await qe();
1824
+ break;
1825
+ }
1826
+ if (te) {
1827
+ ut(f);
1828
+ break;
1829
+ }
1830
+ await Ze();
1831
+ break;
1832
+ }
1833
+ case "microphoneStartResult": {
1834
+ if (me === null || o.id !== me)
1835
+ break;
1836
+ me = null, typeof o.error == "string" && (console.warn("[RemoteControl] microphoneStart rejected by host:", o.error), qe(o.error));
1837
+ break;
1838
+ }
1839
+ case "terminateAppResult":
1840
+ if (typeof o.id != "string") {
1841
+ S("Received invalid terminateApp result message:", o);
1842
+ break;
1843
+ }
1844
+ if (typeof o.error == "string") {
1845
+ const g = ie.get(o.id);
1846
+ if (typeof g != "function") {
1847
+ S(`Received terminateApp error for unknown or handled id: ${o.id}`);
1848
+ break;
1849
+ }
1850
+ S(`Received terminateApp error for id ${o.id}: ${o.error}`), g(new Error(o.error)), ae.delete(o.id), ie.delete(o.id), clearTimeout(B.get(o.id)), B.delete(o.id);
1851
+ break;
1852
+ }
1853
+ const W = ae.get(o.id);
1854
+ if (typeof W != "function") {
1855
+ S(`Received terminateApp result for unknown or handled id: ${o.id}`);
1856
+ break;
1857
+ }
1858
+ ce(`Received terminateApp success for id ${o.id}`), W(), ae.delete(o.id), ie.delete(o.id), clearTimeout(B.get(o.id)), B.delete(o.id);
1859
+ break;
1860
+ default:
1861
+ S(`Received unhandled message type: ${o.type}`, o);
1862
+ break;
1863
+ }
1864
+ }, N === v) {
1865
+ const _ = await v.createOffer({
1866
+ offerToReceiveVideo: !0,
1867
+ offerToReceiveAudio: !1
1868
+ });
1869
+ if (!O() || N !== v || (await v.setLocalDescription(_), !O() || N !== v))
1870
+ return;
1871
+ O() && D === f && f.readyState === WebSocket.OPEN && f.send(
1872
+ JSON.stringify({
1873
+ type: "offer",
1874
+ ...R ? { displayStreams: !0 } : {},
1875
+ ...tt ? { latencyTraceVersion: 1 } : {},
1876
+ sdp: _.sdp,
1877
+ sessionId: d
1878
+ })
1879
+ ), T("Sent offer");
1880
+ }
1881
+ } catch (f) {
1882
+ if (!O() || f instanceof Error && f.message === "Connection stopped")
1883
+ return;
1884
+ const j = f instanceof Error ? f.message : String(f);
1885
+ T("Error: " + j), De(j, m);
1886
+ }
1887
+ }, pt = () => {
1888
+ if (J) throw new Error("Device stream is disposed");
1889
+ Ie++, Te = !1, Be(null), pe !== "reconnecting" && (pe = null), document.addEventListener("visibilitychange", ht), document.hidden || lt(), Ee = !1, mt(0);
1890
+ }, Ct = () => {
1891
+ Ie++, Te = !1, we(), document.removeEventListener("visibilitychange", ht), le += 1, Pe = 0, ne = !1, xe(), be(), _e(), pe = null, C({ connection: "idle", videoReady: !1, controlReady: !1 }), T("Stopped");
1892
+ }, Ot = (r, u = "primary") => {
1893
+ if (J) throw new Error("Device stream is disposed");
1894
+ if (Y.has(r)) throw new Error("Video element is already attached");
1895
+ const a = { display: u };
1896
+ Y.set(r, a);
1897
+ const l = () => {
1898
+ u === "primary" && Re.has(u) && bt();
1899
+ };
1900
+ r.addEventListener("loadeddata", l);
1901
+ const y = Re.get(u);
1902
+ y && at(r, a, y);
1903
+ let m = !1;
1904
+ const O = () => {
1905
+ m || (m = !0, P.delete(O), r.removeEventListener("loadeddata", l), a.stop?.(), Y.delete(r), r.srcObject = null);
1906
+ };
1907
+ return P.add(O), O;
1908
+ };
1909
+ return {
1910
+ start: pt,
1911
+ stop: Ct,
1912
+ attachVideo: Ot,
1913
+ attachFrameSink: (r, u = "primary") => {
1914
+ const a = document.createElement("video");
1915
+ a.muted = !0, a.playsInline = !0, a.autoplay = !0;
1916
+ const l = Ot(a, u);
1917
+ let y = !1, m = 0, O = 0;
1918
+ const f = () => {
1919
+ a.cancelVideoFrameCallback?.(m), cancelAnimationFrame(O);
1920
+ }, j = () => {
1921
+ y || !a.srcObject || (a.readyState >= 2 && a.videoWidth > 0 && L(
1922
+ "present",
1923
+ (...M) => r.present(...M),
1924
+ a,
1925
+ a.videoWidth,
1926
+ a.videoHeight,
1927
+ u
1928
+ ), !(y || !a.srcObject) && (a.requestVideoFrameCallback ? m = a.requestVideoFrameCallback(j) : O = requestAnimationFrame(j)));
1929
+ }, k = () => {
1930
+ f(), j();
1931
+ };
1932
+ Y.get(a).clear = f, a.addEventListener("loadeddata", k);
1933
+ const X = () => {
1934
+ y || (y = !0, P.delete(X), f(), a.removeEventListener("loadeddata", k), l(), a.remove());
1935
+ };
1936
+ return P.delete(l), P.add(X), a.readyState >= 2 && k(), X;
1937
+ },
1938
+ dispose: () => {
1939
+ if (!J) {
1940
+ J = !0, Ct();
1941
+ for (const r of P) r();
1942
+ P.clear();
1943
+ }
1944
+ },
1945
+ getState: () => h,
1946
+ updateOptions: (r) => {
1947
+ if (J) throw new Error("Device stream is disposed");
1948
+ const u = e;
1949
+ if (e = { ...e, ...r }, u.jitterBufferTargetMs !== e.jitterBufferTargetMs)
1950
+ for (const a of N?.getTransceivers() ?? [])
1951
+ (a.currentDirection === "recvonly" || a.currentDirection === "sendrecv") && Tt(a.receiver, e.jitterBufferTargetMs);
1952
+ !!u.onPlaybackStats != !!e.onPlaybackStats && F(), !!u.microphoneEnabled != !!e.microphoneEnabled && (Xe = e.microphoneEnabled ?? !1, ze() ? Ze() : qe()), !!u.inspectMode != !!e.inspectMode && (e.inspectMode ? q?.start() : (q?.stop(), Me !== null && Be(null)));
1953
+ },
1954
+ sendControl: se,
1955
+ sendTouch: (r, u, a, l, y, m = 0) => se(
1956
+ $t(
1957
+ r === "begin" ? 0 : r === "end" ? 1 : 2,
1958
+ m,
1959
+ l,
1960
+ y,
1961
+ u,
1962
+ a,
1963
+ r === "end" ? 0 : 1
1964
+ )
1965
+ ),
1966
+ sendText: (r) => se(Vt(r)),
1967
+ sendDisplayTouch: (r, u, a, l) => se(Gt(r, u, a, l)),
1968
+ sendDuoControl: wt,
1969
+ pressButton: (r) => {
1970
+ const u = { home: 3, back: 4, recents: 187, power: 26 }[r];
1971
+ se(nt(0, u, 0, 0)), se(nt(1, u, 0, 0));
1972
+ },
1973
+ rotate: () => se(new Uint8Array([11]).buffer),
1974
+ bumpActivity: () => q?.bumpActivity(),
1975
+ getAxStatus: () => q?.getStatus() ?? "idle",
1976
+ openUrl: (r) => {
1977
+ if (!D || D.readyState !== WebSocket.OPEN) {
1978
+ S("WebSocket not open, cannot send open_url command.");
1979
+ return;
1980
+ }
1981
+ try {
1982
+ const u = decodeURIComponent(r);
1983
+ T("Opening URL"), D.send(
1984
+ JSON.stringify({
1985
+ type: "openUrl",
1986
+ url: u,
1987
+ sessionId: d
1988
+ })
1989
+ );
1990
+ } catch (u) {
1991
+ S("Error decoding or sending URL :", { error: u, url: r }), D.send(
1992
+ JSON.stringify({
1993
+ type: "openUrl",
1994
+ url: r,
1995
+ sessionId: d
1996
+ })
1997
+ );
1998
+ }
1999
+ q?.bumpActivity();
2000
+ },
2001
+ sendKeyEvent: (r) => {
2002
+ if (!x || x.readyState !== "open") {
2003
+ S("Data channel not ready for imperative key command:", x?.readyState);
2004
+ return;
2005
+ }
2006
+ const u = qt[r.code];
2007
+ if (!u) {
2008
+ S(`Unknown event.code for imperative command: ${r.code}`);
2009
+ return;
2010
+ }
2011
+ let a = i.META_NONE;
2012
+ r.shiftKey && (a |= i.META_SHIFT_ON), r.altKey && (a |= i.META_ALT_ON), r.ctrlKey && (a |= i.META_CTRL_ON), r.metaKey && (a |= i.META_META_ON);
2013
+ const l = r.type === "keydown" ? i.ACTION_DOWN : i.ACTION_UP;
2014
+ ce(
2015
+ `Sending Imperative Key Command: code=${r.code}, keycode=${u}, action=${l}, meta=${a}`
2016
+ );
2017
+ const y = nt(
2018
+ l,
2019
+ u,
2020
+ 0,
2021
+ // repeat count, typically 0 for single presses
2022
+ a
2023
+ );
2024
+ y && se(y);
2025
+ },
2026
+ screenshot: (r) => new Promise((u, a) => {
2027
+ if (!D || D.readyState !== WebSocket.OPEN)
2028
+ return S("WebSocket not open, cannot send screenshot command."), a(new Error("WebSocket is not connected or connection is not open."));
2029
+ const l = `ui-ss-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`, y = {
2030
+ type: r ? "screenshotDisplay" : "screenshot",
2031
+ ...r ? { display: r } : {},
2032
+ id: l
2033
+ };
2034
+ re.set(l, u), ee.set(l, a), ce("Sending screenshot request:", y);
2035
+ try {
2036
+ D.send(JSON.stringify(y));
2037
+ } catch (m) {
2038
+ S("Failed to send screenshot request immediately:", m), re.delete(l), ee.delete(l), a(m);
2039
+ return;
2040
+ }
2041
+ B.set(
2042
+ l,
2043
+ setTimeout(() => {
2044
+ B.delete(l), re.has(l) && (S(`Screenshot request timed out for id ${l}`), ee.get(l)?.(new Error("Screenshot request timed out")), re.delete(l), ee.delete(l));
2045
+ }, 3e4)
2046
+ );
2047
+ }),
2048
+ terminateApp: (r) => new Promise((u, a) => {
2049
+ if (!D || D.readyState !== WebSocket.OPEN)
2050
+ return S("WebSocket not open, cannot send terminateApp command."), a(new Error("WebSocket is not connected or connection is not open."));
2051
+ const l = `ui-term-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`, y = {
2052
+ type: "terminateApp",
2053
+ id: l,
2054
+ bundleId: r
2055
+ };
2056
+ ae.set(l, u), ie.set(l, a), ce("Sending terminateApp request:", y);
2057
+ try {
2058
+ D.send(JSON.stringify(y));
2059
+ } catch (m) {
2060
+ S("Failed to send terminateApp request immediately:", m), ae.delete(l), ie.delete(l), a(m);
2061
+ return;
2062
+ }
2063
+ q?.bumpActivity(), B.set(
2064
+ l,
2065
+ setTimeout(() => {
2066
+ B.delete(l), ae.has(l) && (S(`terminateApp request timed out for id ${l}`), ie.get(l)?.(new Error("terminateApp request timed out")), ae.delete(l), ie.delete(l));
2067
+ }, 3e4)
2068
+ );
2069
+ }),
2070
+ reconnect: () => pt(),
2071
+ refreshAxTree: async () => {
2072
+ const r = q;
2073
+ if (!r)
2074
+ throw new Error("Inspect mode is not active");
2075
+ return r.refresh();
2076
+ },
2077
+ getAxSnapshot: () => Me
2078
+ };
2079
+ }
2080
+ const wn = (t) => typeof t.message == "string" ? t.message : typeof t.error == "string" ? t.error : null, Yn = (t) => typeof t.dataUri == "string" ? { dataUri: t.dataUri } : typeof t.base64 == "string" ? t.base64.startsWith("data:") ? { dataUri: t.base64 } : { dataUri: `data:${t.base64.startsWith("/9j/") ? "image/jpeg" : "image/png"};base64,${t.base64}` } : null;
2081
+ export {
2082
+ rt as A,
2083
+ Gt as B,
2084
+ Je as C,
2085
+ In as D,
2086
+ Ln as H,
2087
+ Wn as a,
2088
+ qn as b,
2089
+ $n as c,
2090
+ nn as d,
2091
+ rn as e,
2092
+ xn as f,
2093
+ zt as g,
2094
+ on as h,
2095
+ yn as i,
2096
+ Vn as j,
2097
+ ce as k,
2098
+ S as l,
2099
+ Vt as m,
2100
+ tn as n,
2101
+ nt as o,
2102
+ i as p,
2103
+ $t as q,
2104
+ qt as r,
2105
+ L as s,
2106
+ He as t,
2107
+ Rn as u,
2108
+ Bn as v,
2109
+ Fn as w,
2110
+ kn as x,
2111
+ Pn as y,
2112
+ Un as z
2113
+ };