@limrun/ui 0.15.0 → 0.16.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.
- package/README.md +27 -0
- package/dist/components/remote-control-framed.d.ts +2 -0
- package/dist/components/remote-control.d.ts +28 -71
- package/dist/core/ax-fetcher.d.ts +5 -0
- package/dist/core/camera.d.ts +58 -0
- package/dist/frame-assets.d.ts +2 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.js +25 -2447
- package/dist/lite.cjs +1 -0
- package/dist/lite.d.ts +6 -0
- package/dist/lite.js +13 -0
- package/dist/remote-control-BRgbD7yo.mjs +2516 -0
- package/dist/remote-control-VISrP1zI.js +1 -0
- package/package.json +11 -4
- package/src/components/remote-control-framed.tsx +14 -0
- package/src/components/remote-control.tsx +369 -435
- package/src/core/ax-fetcher.ts +15 -5
- package/src/core/camera.test.ts +155 -0
- package/src/core/camera.ts +133 -0
- package/src/demo.tsx +2 -1
- package/src/frame-assets.ts +22 -0
- package/src/index.ts +13 -3
- package/src/lite.test.ts +30 -0
- package/src/lite.ts +30 -0
- package/vite.config.ts +5 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";require('./index.css');const A=require("react/jsx-runtime"),f=require("react"),hn=require("react-dom");function Dr(n){var t,c,a="";if(typeof n=="string"||typeof n=="number")a+=n;else if(typeof n=="object")if(Array.isArray(n)){var E=n.length;for(t=0;t<E;t++)n[t]&&(c=Dr(n[t]))&&(a&&(a+=" "),a+=c)}else for(c in n)n[c]&&(a&&(a+=" "),a+=c);return a}function De(){for(var n,t,c=0,a="",E=arguments.length;c<E;c++)(n=arguments[c])&&(t=Dr(n))&&(a&&(a+=" "),a+=t);return a}const wt={INJECT_KEYCODE:0,INJECT_TOUCH_EVENT:2,INJECT_TWO_FINGER_TOUCH_EVENT:18,SET_CLIPBOARD:9},U={ACTION_DOWN:0,ACTION_UP:1,ACTION_MOVE:2,ACTION_CANCEL:3,ACTION_POINTER_DOWN:5,ACTION_POINTER_UP:6,BUTTON_PRIMARY:1,BUTTON_SECONDARY:2,BUTTON_TERTIARY:4},s={ACTION_DOWN:0,ACTION_UP:1,META_NONE:0,META_SHIFT_ON:1,META_ALT_ON:2,META_CTRL_ON:4096,META_META_ON:65536,KEYCODE_0:7,KEYCODE_1:8,KEYCODE_2:9,KEYCODE_3:10,KEYCODE_4:11,KEYCODE_5:12,KEYCODE_6:13,KEYCODE_7:14,KEYCODE_8:15,KEYCODE_9:16,DPAD_UP:19,DPAD_DOWN:20,DPAD_LEFT:21,DPAD_RIGHT:22,KEYCODE_A:29,KEYCODE_B:30,KEYCODE_C:31,KEYCODE_D:32,KEYCODE_E:33,KEYCODE_F:34,KEYCODE_G:35,KEYCODE_H:36,KEYCODE_I:37,KEYCODE_J:38,KEYCODE_K:39,KEYCODE_L:40,KEYCODE_M:41,KEYCODE_N:42,KEYCODE_O:43,KEYCODE_P:44,KEYCODE_Q:45,KEYCODE_R:46,KEYCODE_S:47,KEYCODE_T:48,KEYCODE_U:49,KEYCODE_V:50,KEYCODE_W:51,KEYCODE_X:52,KEYCODE_Y:53,KEYCODE_Z:54,KEYCODE_COMMA:55,KEYCODE_PERIOD:56,KEYCODE_ALT_LEFT:57,KEYCODE_ALT_RIGHT:58,KEYCODE_SHIFT_LEFT:59,KEYCODE_SHIFT_RIGHT:60,KEYCODE_TAB:61,KEYCODE_SPACE:62,ENTER:66,DEL:67,KEYCODE_GRAVE:68,KEYCODE_MINUS:69,KEYCODE_EQUALS:70,KEYCODE_LEFT_BRACKET:71,KEYCODE_RIGHT_BRACKET:72,KEYCODE_BACKSLASH:73,KEYCODE_SEMICOLON:74,KEYCODE_APOSTROPHE:75,KEYCODE_SLASH:76,MENU:82,KEYCODE_PAGE_UP:92,KEYCODE_PAGE_DOWN:93,KEYCODE_ESCAPE:111,FORWARD_DEL:112,KEYCODE_CTRL_LEFT:113,KEYCODE_CTRL_RIGHT:114,KEYCODE_META_LEFT:117,KEYCODE_META_RIGHT:118,KEYCODE_MOVE_HOME:122,KEYCODE_MOVE_END:123,KEYCODE_INSERT:124,KEYCODE_F1:131,KEYCODE_F2:132,KEYCODE_F3:133,KEYCODE_F4:134,KEYCODE_F5:135,KEYCODE_F6:136,KEYCODE_F7:137,KEYCODE_F8:138,KEYCODE_F9:139,KEYCODE_F10:140,KEYCODE_F11:141,KEYCODE_F12:142,KEYCODE_NUMPAD_0:144,KEYCODE_NUMPAD_1:145,KEYCODE_NUMPAD_2:146,KEYCODE_NUMPAD_3:147,KEYCODE_NUMPAD_4:148,KEYCODE_NUMPAD_5:149,KEYCODE_NUMPAD_6:150,KEYCODE_NUMPAD_7:151,KEYCODE_NUMPAD_8:152,KEYCODE_NUMPAD_9:153,KEYCODE_NUMPAD_DIVIDE:154,KEYCODE_NUMPAD_MULTIPLY:155,KEYCODE_NUMPAD_SUBTRACT:156,KEYCODE_NUMPAD_ADD:157,KEYCODE_NUMPAD_DOT:158,KEYCODE_NUMPAD_COMMA:159,KEYCODE_NUMPAD_ENTER:160,KEYCODE_NUMPAD_EQUALS:161},Rr={KeyA:s.KEYCODE_A,KeyB:s.KEYCODE_B,KeyC:s.KEYCODE_C,KeyD:s.KEYCODE_D,KeyE:s.KEYCODE_E,KeyF:s.KEYCODE_F,KeyG:s.KEYCODE_G,KeyH:s.KEYCODE_H,KeyI:s.KEYCODE_I,KeyJ:s.KEYCODE_J,KeyK:s.KEYCODE_K,KeyL:s.KEYCODE_L,KeyM:s.KEYCODE_M,KeyN:s.KEYCODE_N,KeyO:s.KEYCODE_O,KeyP:s.KEYCODE_P,KeyQ:s.KEYCODE_Q,KeyR:s.KEYCODE_R,KeyS:s.KEYCODE_S,KeyT:s.KEYCODE_T,KeyU:s.KEYCODE_U,KeyV:s.KEYCODE_V,KeyW:s.KEYCODE_W,KeyX:s.KEYCODE_X,KeyY:s.KEYCODE_Y,KeyZ:s.KEYCODE_Z,Digit0:s.KEYCODE_0,Digit1:s.KEYCODE_1,Digit2:s.KEYCODE_2,Digit3:s.KEYCODE_3,Digit4:s.KEYCODE_4,Digit5:s.KEYCODE_5,Digit6:s.KEYCODE_6,Digit7:s.KEYCODE_7,Digit8:s.KEYCODE_8,Digit9:s.KEYCODE_9,Backquote:s.KEYCODE_GRAVE,Minus:s.KEYCODE_MINUS,Equal:s.KEYCODE_EQUALS,BracketLeft:s.KEYCODE_LEFT_BRACKET,BracketRight:s.KEYCODE_RIGHT_BRACKET,Backslash:s.KEYCODE_BACKSLASH,Semicolon:s.KEYCODE_SEMICOLON,Quote:s.KEYCODE_APOSTROPHE,Comma:s.KEYCODE_COMMA,Period:s.KEYCODE_PERIOD,Slash:s.KEYCODE_SLASH,Space:s.KEYCODE_SPACE,Tab:s.KEYCODE_TAB,Escape:s.KEYCODE_ESCAPE,ArrowUp:s.DPAD_UP,ArrowDown:s.DPAD_DOWN,ArrowLeft:s.DPAD_LEFT,ArrowRight:s.DPAD_RIGHT,Enter:s.ENTER,Backspace:s.DEL,Delete:s.FORWARD_DEL,Home:s.KEYCODE_MOVE_HOME,End:s.KEYCODE_MOVE_END,PageUp:s.KEYCODE_PAGE_UP,PageDown:s.KEYCODE_PAGE_DOWN,Insert:s.KEYCODE_INSERT,F1:s.KEYCODE_F1,F2:s.KEYCODE_F2,F3:s.KEYCODE_F3,F4:s.KEYCODE_F4,F5:s.KEYCODE_F5,F6:s.KEYCODE_F6,F7:s.KEYCODE_F7,F8:s.KEYCODE_F8,F9:s.KEYCODE_F9,F10:s.KEYCODE_F10,F11:s.KEYCODE_F11,F12:s.KEYCODE_F12,ShiftLeft:s.KEYCODE_SHIFT_LEFT,ShiftRight:s.KEYCODE_SHIFT_RIGHT,ControlLeft:s.KEYCODE_CTRL_LEFT,ControlRight:s.KEYCODE_CTRL_RIGHT,AltLeft:s.KEYCODE_ALT_LEFT,AltRight:s.KEYCODE_ALT_RIGHT,MetaLeft:s.KEYCODE_META_LEFT,MetaRight:s.KEYCODE_META_RIGHT,ContextMenu:s.MENU,Numpad0:s.KEYCODE_NUMPAD_0,Numpad1:s.KEYCODE_NUMPAD_1,Numpad2:s.KEYCODE_NUMPAD_2,Numpad3:s.KEYCODE_NUMPAD_3,Numpad4:s.KEYCODE_NUMPAD_4,Numpad5:s.KEYCODE_NUMPAD_5,Numpad6:s.KEYCODE_NUMPAD_6,Numpad7:s.KEYCODE_NUMPAD_7,Numpad8:s.KEYCODE_NUMPAD_8,Numpad9:s.KEYCODE_NUMPAD_9,NumpadDivide:s.KEYCODE_NUMPAD_DIVIDE,NumpadMultiply:s.KEYCODE_NUMPAD_MULTIPLY,NumpadSubtract:s.KEYCODE_NUMPAD_SUBTRACT,NumpadAdd:s.KEYCODE_NUMPAD_ADD,NumpadDecimal:s.KEYCODE_NUMPAD_DOT,NumpadComma:s.KEYCODE_NUMPAD_COMMA,NumpadEnter:s.KEYCODE_NUMPAD_ENTER,NumpadEqual:s.KEYCODE_NUMPAD_EQUALS};function vt(n,t,c,a,E,p,C=1,O=0,K=0){const T=new ArrayBuffer(32),M=new DataView(T);let N=0;return M.setUint8(N,wt.INJECT_TOUCH_EVENT),N+=1,M.setUint8(N,n),N+=1,M.setBigInt64(N,BigInt(t),!0),N+=8,M.setInt32(N,Math.round(E),!0),N+=4,M.setInt32(N,Math.round(p),!0),N+=4,M.setUint16(N,c,!0),N+=2,M.setUint16(N,a,!0),N+=2,M.setInt16(N,Math.round(C*65535),!0),N+=2,M.setInt32(N,O,!0),N+=4,M.setInt32(N,K,!0),T}function mn(n,t,c,a,E,p,C){const O=new ArrayBuffer(24),K=new DataView(O);let T=0;return K.setUint8(T,wt.INJECT_TWO_FINGER_TOUCH_EVENT),T+=1,K.setUint8(T,n),T+=1,K.setInt32(T,Math.round(a),!0),T+=4,K.setInt32(T,Math.round(E),!0),T+=4,K.setInt32(T,Math.round(p),!0),T+=4,K.setInt32(T,Math.round(C),!0),T+=4,K.setUint16(T,t,!0),T+=2,K.setUint16(T,c,!0),T+=2,K.setUint16(T,0,!0),O}function En(n,t=!0){const a=new TextEncoder().encode(n),E=new ArrayBuffer(14+a.length),p=new DataView(E);let C=0;return p.setUint8(C,wt.SET_CLIPBOARD),C+=1,p.setBigInt64(C,BigInt(0),!1),C+=8,p.setUint8(C,t?1:0),C+=1,p.setUint32(C,a.length,!1),C+=4,new Uint8Array(E,C).set(a),E}function it(n,t,c=0,a=0){const E=new ArrayBuffer(14),p=new DataView(E);let C=0;return p.setUint8(C,wt.INJECT_KEYCODE),C+=1,p.setUint8(C,n),C+=1,p.setInt32(C,t,!0),C+=4,p.setInt32(C,c,!0),C+=4,p.setInt32(C,a,!0),E}const Dt="Accessibility unavailable on this device.",Rt=500,wr=(n,t)=>Math.abs(n.x-t.x)<.5&&Math.abs(n.y-t.y)<.5&&Math.abs(n.width-t.width)<.5&&Math.abs(n.height-t.height)<.5,pn=n=>Math.max(0,n.width)*Math.max(0,n.height),gn=n=>{const t=n.find(c=>c.frame&&c.frame.width>0&&c.frame.height>0);return t?.frame?((Math.abs(t.frame.x)>.5||Math.abs(t.frame.y)>.5)&&console.warn(`[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.`),{x:0,y:0,width:t.frame.width,height:t.frame.height}):{x:0,y:0,width:1,height:1}},Cn=n=>{const t={};return typeof n.AXUniqueId=="string"&&n.AXUniqueId.length>0&&(t.AXUniqueId=n.AXUniqueId),typeof n.AXLabel=="string"&&n.AXLabel.length>0&&(t.AXLabel=n.AXLabel),typeof n.type=="string"&&n.type.length>0&&(t.className=n.type),t},yn=n=>{const t={};for(const[c,a]of Object.entries(n))c!=="children"&&(t[c]=a);return t};function Ar(n){const t=Array.isArray(n)?n:[n],c=gn(t),a=[],E=(p,C)=>{if(a.length>=Rt)return;const O=p.frame;if(O&&O.width>0&&O.height>0&&!wr(O,c)){const T=p.role_description||p.role||"",M=(typeof p.AXLabel=="string"?p.AXLabel:"")||(typeof p.title=="string"?p.title:"")||"";a.push({id:typeof p.AXUniqueId=="string"&&p.AXUniqueId.length>0?p.AXUniqueId:C,path:C,label:M,value:typeof p.AXValue=="string"?p.AXValue:"",role:T,type:typeof p.type=="string"?p.type:"",enabled:p.enabled!==!1,focused:p.focused===!0,frame:{x:O.x,y:O.y,width:O.width,height:O.height},selectors:Cn(p),raw:yn(p)})}const K=Array.isArray(p.children)?p.children:[];for(let T=0;T<K.length&&a.length<Rt;T++)E(K[T],`${C}.${T}`)};for(let p=0;p<t.length&&a.length<Rt;p++)E(t[p],String(p));return{platform:"ios",screen:{width:c.width,height:c.height},elements:a,capturedAt:Date.now()}}const On=n=>{let t={x:0,y:0,width:1,height:1},c=0;for(const a of n){const E=a.parsedBounds;if(!E)continue;const p=E.right-E.left,C=E.bottom-E.top,O=Math.max(0,p)*Math.max(0,C);O>c&&(c=O,t={x:0,y:0,width:p,height:C})}return t},_n=n=>{const t={};return typeof n.resourceId=="string"&&n.resourceId.length>0&&(t.resourceId=n.resourceId),typeof n.contentDesc=="string"&&n.contentDesc.length>0&&(t.contentDesc=n.contentDesc),typeof n.text=="string"&&n.text.length>0&&(t.text=n.text),typeof n.className=="string"&&n.className.length>0&&(t.className=n.className),t};function Sr(n){const t=On(n),c=[];for(let a=0;a<n.length&&c.length<Rt;a++){const E=n[a],p=E.parsedBounds;if(!p)continue;const C=Math.max(0,p.right-p.left),O=Math.max(0,p.bottom-p.top);if(C<=0||O<=0)continue;const K={x:p.left,y:p.top,width:C,height:O};if(wr(K,{x:0,y:0,width:t.width,height:t.height}))continue;const T=E.contentDesc||E.text||"",M=E.className||"";c.push({id:E.resourceId&&E.resourceId.length>0?E.resourceId:E.contentDesc&&E.contentDesc.length>0?`cd:${E.contentDesc}`:String(a),path:String(a),label:T,value:typeof E.text=="string"?E.text:"",role:M,type:M,enabled:E.enabled!==!1,focused:E.focused===!0,frame:K,selectors:_n(E),raw:{...E}})}return{platform:"android",screen:{width:t.width,height:t.height},elements:c,capturedAt:Date.now()}}function Mr(n,t){const c=Math.max(0,n.x),a=Math.max(0,n.y),E=Math.min(t.width,n.x+n.width),p=Math.min(t.height,n.y+n.height),C=Math.max(0,E-c),O=Math.max(0,p-a);return C>0&&O>0?{x:c,y:a,width:C,height:O}:null}function Ht(n,t){if(n===t)return!0;if(n.id!==t.id||n.path!==t.path||n.label!==t.label||n.value!==t.value||n.role!==t.role||n.type!==t.type||n.enabled!==t.enabled||n.focused!==t.focused)return!1;const c=n.frame,a=t.frame;return c.x===a.x&&c.y===a.y&&c.width===a.width&&c.height===a.height}function $t(n,t){if(n===t)return!0;if(!n||!t||n.platform!==t.platform||n.screen.width!==t.screen.width||n.screen.height!==t.screen.height||n.elements.length!==t.elements.length)return!1;for(let c=0;c<n.elements.length;c++)if(!Ht(n.elements[c],t.elements[c]))return!1;return!0}function br(n,t,c){let a=null,E=1/0;for(const p of n.elements){const C=p.frame;if(t<C.x||c<C.y||t>C.x+C.width||c>C.y+C.height)continue;const O=pn(C);O<E&&(E=O,a=p)}return a}function Nr(n,t){if(t==="ios"){if(n.selectors.AXUniqueId)return`client.tapElement({ AXUniqueId: ${JSON.stringify(n.selectors.AXUniqueId)} })`;if(n.selectors.AXLabel){const c=n.selectors.className?`, type: ${JSON.stringify(n.selectors.className)}`:"";return`client.tapElement({ AXLabel: ${JSON.stringify(n.selectors.AXLabel)}${c} })`}return null}return n.selectors.resourceId?`client.tap({ selector: { resourceId: ${JSON.stringify(n.selectors.resourceId)} } })`:n.selectors.contentDesc?`client.tap({ selector: { contentDesc: ${JSON.stringify(n.selectors.contentDesc)} } })`:n.selectors.text?`client.tap({ selector: { text: ${JSON.stringify(n.selectors.text)} } })`:null}function Ir(n){const t=n.role||n.type||"";if(!t)return"element";let c=t.replace(/^AX/,"");return c.includes(".")&&(c=c.split(".").pop()),c==="GenericElement"?"Element":(c=c.replace(/([a-z])([A-Z])/g,"$1 $2"),c)}const yr=80;function Xt(n){const t=Ir(n),c=n.label||n.value||"";if(!c)return t;const a=c.length>yr?c.slice(0,yr).trimEnd()+"…":c;return`${t} · ${a}`}const vn=500,Tn=2e3,Or=5e3,Dn=8e3,Rn=1200,wn=250,An=()=>`ax-rc-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;class Sn{platform;send;onSnapshot;onStatusChange;baseIntervalMs;maxBackoffMs;androidElementTreeOptions;pending=new Map;running=!1;timer;currentInterval;lastSnapshot=null;inflight=!1;lastBumpAtMs=0;boostUntilMs=0;status="idle";constructor(t){this.platform=t.platform,this.send=t.send,this.onSnapshot=t.onSnapshot,this.onStatusChange=t.onStatusChange,this.baseIntervalMs=t.baseIntervalMs??vn,this.maxBackoffMs=t.maxBackoffMs??Tn,this.androidElementTreeOptions=t.androidElementTreeOptions,this.currentInterval=this.baseIntervalMs}start(){this.running||(this.running=!0,this.currentInterval=this.baseIntervalMs,this.boostUntilMs=0,this.setStatus("starting"),this.runOnce())}stop(){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))}getStatus(){return this.status}setStatus(t,c){if(this.status!==t&&(this.status=t,!!this.onStatusChange))try{this.onStatusChange(t,c)}catch(a){console.error("[AxFetcher] onStatusChange threw:",a)}}bumpActivity(){if(!this.running)return;const t=Date.now();this.boostUntilMs=t+Rn;const c=Math.max(150,Math.floor(this.baseIntervalMs/2));if(t-this.lastBumpAtMs<c){this.currentInterval=this.baseIntervalMs;return}this.lastBumpAtMs=t,this.currentInterval=this.baseIntervalMs,this.timer!==void 0&&(window.clearTimeout(this.timer),this.timer=void 0),this.inflight||this.runOnce()}async refresh(){const t=await this.requestOnce();return this.running&&this.deliver(t),t}getLatest(){return this.lastSnapshot}handleMessage(t){if(!t||typeof t.id!="string")return!1;const c=t.id;if(!this.pending.get(c))return!1;if(this.platform==="ios"){if(t.type!=="elementTreeResult")return!1;const O=typeof t.error=="string"?t.error:null;if(O)return this.settleReject(c,new Error(O)),!0;const K=typeof t.json=="string"?t.json:"";try{const T=JSON.parse(K),M=Ar(T);this.settleResolve(c,M)}catch(T){this.settleReject(c,T instanceof Error?T:new Error(String(T)))}return!0}if(t.type!=="getElementTreeResult")return!1;const E=t.error;if(E&&typeof E=="object"){const O=typeof E.message=="string"?E.message:"getElementTree failed";return this.settleReject(c,new Error(O)),!0}const p=t.payload,C=Array.isArray(p?.nodes)?p.nodes:[];try{const O=Sr(C);this.settleResolve(c,O)}catch(O){this.settleReject(c,O instanceof Error?O:new Error(String(O)))}return!0}buildRequest(t){return this.platform==="ios"?{type:"elementTree",id:t}:{type:"getElementTree",id:t,...this.androidElementTreeOptions}}async requestOnce(){const t=An();return new Promise((c,a)=>{const E=window.setTimeout(()=>{this.pending.delete(t),a(new Error("elementTree request timed out"))},Dn+(this.androidElementTreeOptions?.waitForIdleTimeoutMs??0));this.pending.set(t,{resolve:c,reject:a,timer:E}),this.send(this.buildRequest(t))||(window.clearTimeout(E),this.pending.delete(t),a(new Error("elementTree send failed (WebSocket not open)")))})}async runOnce(){if(this.running&&!this.inflight){this.inflight=!0;try{const t=await this.requestOnce();if(!this.running)return;this.deliver(t)}catch(t){if(!this.running)return;const c=t instanceof Error?t.message:String(t),a=/unavailable|not (yet )?running|failed|timeout/i.test(c);this.currentInterval=a?Or:Math.min(this.currentInterval*2,this.maxBackoffMs),this.setStatus(a?"unavailable":"error",c)}finally{this.inflight=!1,this.scheduleNext()}}}deliver(t){const c=this.lastSnapshot;if($t(c,t)){this.currentInterval=Math.min(this.currentInterval*2,this.maxBackoffMs),this.lastSnapshot=t,t.errors?.includes(Dt)||this.setStatus("ready");return}this.lastSnapshot=t,this.currentInterval=this.baseIntervalMs,t.errors?.includes(Dt)?(this.currentInterval=Or,this.setStatus("unavailable",Dt)):this.setStatus("ready"),this.onSnapshot(t)}scheduleNext(){if(!this.running)return;this.timer!==void 0&&window.clearTimeout(this.timer);const t=Date.now()<this.boostUntilMs?Math.min(wn,this.currentInterval):this.currentInterval;this.timer=window.setTimeout(()=>{this.timer=void 0,this.runOnce()},t)}settleResolve(t,c){const a=this.pending.get(t);a&&(window.clearTimeout(a.timer),this.pending.delete(t),a.resolve(c))}settleReject(t,c){const a=this.pending.get(t);a&&(window.clearTimeout(a.timer),this.pending.delete(t),a.reject(c))}failAllPending(t){for(const[c,a]of this.pending.entries())window.clearTimeout(a.timer),a.reject(new Error(t)),this.pending.delete(c)}}class Mn{generation=0;tail=Promise.resolve();get currentGeneration(){return this.generation}enqueue(t){const c=++this.generation;return this.append(c,t)}enqueueCurrent(t){return this.append(this.generation,t)}append(t,c){const a={generation:t,isCurrent:()=>t===this.generation},E=this.tail.then(()=>c(a));return this.tail=E.catch(()=>{}),E}invalidate(){++this.generation}}function bn(n){if(!n||typeof n!="object")return null;const t=n;if(t.type!=="cameraRequest"||typeof t.active!="boolean")return null;const c={active:t.active};return(t.facingMode==="user"||t.facingMode==="environment")&&(c.facingMode=t.facingMode),c}function Nn(n){const t={frameRate:{ideal:30,max:30}};return n?.facingMode&&(t.facingMode={ideal:n.facingMode}),t}function In(n,t){return!n||n.facingMode!==t.facingMode}function Yn(n){const t=n.getSettings();return{width:t.width,height:t.height,frameRate:t.frameRate,deviceId:t.deviceId,label:n.label||void 0,facingMode:t.facingMode}}function Kn(n){return{type:"cameraResult",granted:!0,camera:Yn(n)}}const kn=async n=>{if(!n)return!1;try{if(typeof navigator<"u"&&navigator.clipboard?.writeText)return await navigator.clipboard.writeText(n),!0}catch{}try{const t=document.createElement("textarea");t.value=n,t.style.position="fixed",t.style.opacity="0",document.body.appendChild(t),t.select();const c=document.execCommand("copy");return document.body.removeChild(t),c}catch{return!1}},Pn=f.memo(function({element:t,screen:c,highlighted:a,selected:E,selectable:p,onClick:C}){const O=Mr(t.frame,c);if(!O)return null;const K=Xt(t);return A.jsx("button",{type:"button",className:De("rc-inspect-box",!t.enabled&&"rc-inspect-box-disabled"),"data-ax-id":t.id,"data-ax-path":t.path,"data-ax-label":t.label||void 0,"data-ax-role":t.role||void 0,"data-highlighted":a?"true":"false","data-selected":E?"true":"false","aria-label":K,onClick:T=>{p&&(T.preventDefault(),T.stopPropagation(),C(t,{x:T.clientX,y:T.clientY}))},style:{left:`${O.x/c.width*100}%`,top:`${O.y/c.height*100}%`,width:`${O.width/c.width*100}%`,height:`${O.height/c.height*100}%`}})},(n,t)=>n.highlighted===t.highlighted&&n.selected===t.selected&&n.selectable===t.selectable&&n.screen.width===t.screen.width&&n.screen.height===t.screen.height&&n.onClick===t.onClick&&Ht(n.element,t.element)),Ln=260,Un=220,xn=6,Fn=8,Wn=f.memo(function({element:t,platform:c,anchor:a,cursorAnchored:E,showActions:p,onTap:C}){const[O,K]=f.useState(null);f.useEffect(()=>{if(!O)return;const X=window.setTimeout(()=>K(null),1100);return()=>window.clearTimeout(X)},[O]);const T=f.useMemo(()=>{const X=Ln,ne=Un,J=xn,$=Fn,fe=typeof window<"u"?window.innerWidth:1024,we=typeof window<"u"?window.innerHeight:768,F=a.x+J+X<=fe-$,he=a.y-J-ne>=$;let Xe=F?a.x+J:a.x-J,me=he?a.y-J:a.y+J;const At=`translate(${F?"0":"-100%"}, ${he?"-100%":"0"})`;return Xe=Math.max($+(F?0:X),Math.min(fe-$-(F?X:0),Xe)),me=Math.max($+(he?ne:0),Math.min(we-$-(he?0:ne),me)),{left:`${Xe}px`,top:`${me}px`,transform:At}},[a.x,a.y]),M=f.useMemo(()=>Nr(t,c),[t,c]),N=c==="ios"?t.selectors.AXUniqueId:t.selectors.resourceId,re=c==="ios"?"AXUniqueId":"resourceId",ae=f.useCallback(async(X,ne)=>{if(!X)return;await kn(X)&&K(ne)},[]),de=Ir(t),ct=t.label||t.value||de,Re=Xt(t);return hn.createPortal(A.jsxs("div",{className:"rc-inspect-card","data-cursor-anchored":E?"true":"false",style:T,onClick:X=>X.stopPropagation(),onMouseDown:X=>X.stopPropagation(),onMouseMove:X=>X.stopPropagation(),children:[A.jsxs("div",{className:"rc-inspect-card-header",children:[A.jsx("span",{className:"rc-inspect-card-role",children:de}),!t.enabled&&A.jsx("span",{className:"rc-inspect-card-tag",children:"disabled"}),t.focused&&A.jsx("span",{className:"rc-inspect-card-tag rc-inspect-card-tag-blue",children:"focused"})]}),A.jsx("p",{className:"rc-inspect-card-title",title:Re,children:ct}),N&&A.jsxs("div",{className:"rc-inspect-card-row",children:[A.jsxs("span",{className:"rc-inspect-card-row-label",children:[re,":"]}),A.jsx("span",{className:"rc-inspect-card-row-value",children:N})]}),t.value&&t.value!==t.label&&A.jsxs("div",{className:"rc-inspect-card-row",children:[A.jsx("span",{className:"rc-inspect-card-row-label",children:"value:"}),A.jsx("span",{className:"rc-inspect-card-row-value",children:t.value})]}),A.jsxs("div",{className:"rc-inspect-card-row",children:[A.jsx("span",{className:"rc-inspect-card-row-label",children:"frame:"}),A.jsxs("span",{className:"rc-inspect-card-row-value",children:[Math.round(t.frame.width),"×",Math.round(t.frame.height)," @ ",Math.round(t.frame.x),",",Math.round(t.frame.y)]})]}),p&&A.jsxs("div",{className:"rc-inspect-card-actions",children:[A.jsx("button",{type:"button",className:"rc-inspect-card-btn rc-inspect-card-btn-primary",onClick:()=>C(t,a),children:"Tap"}),A.jsx("button",{type:"button",className:De("rc-inspect-card-btn",O==="selector"&&"rc-inspect-card-btn-copied"),disabled:!M,title:M??"No usable selector for this element",onClick:()=>ae(M??void 0,"selector"),children:O==="selector"?"Copied!":"Copy selector"}),A.jsx("button",{type:"button",className:De("rc-inspect-card-btn",O==="id"&&"rc-inspect-card-btn-copied"),disabled:!N,title:N??`No ${re}`,onClick:()=>ae(N,"id"),children:O==="id"?"Copied!":`Copy ${re}`})]})]}),document.body)}),Hn=f.memo(function({snapshot:t,geometry:c,highlightedId:a,selectedId:E,mode:p,cursorPosition:C,frozenCursorPosition:O,onSelectChange:K,onTapElement:T}){const M=p==="select",N=M?a!==null&&a!==E:a!==null,re=M?a??E:a,ae=f.useMemo(()=>{const $=new Map;if(!t)return $;for(const fe of t.elements)$.set(fe.id,fe);return $},[t]),de=f.useMemo(()=>re?ae.get(re)??null:null,[re,ae]);if(!(!!t&&!!c&&t.screen.width>0&&t.screen.height>0&&t.elements.length>0))return null;const Re=N?C:O??C,X=N,ne=M&&!N&&E!==null,J=$=>{M&&$.target===$.currentTarget&&K(null,null)};return A.jsxs(A.Fragment,{children:[A.jsx("div",{className:De("rc-inspect-overlay",M&&"rc-inspect-overlay-select"),style:{left:`${c.left}px`,top:`${c.top}px`,width:`${c.width}px`,height:`${c.height}px`},onClick:J,children:t.elements.map($=>A.jsx(Pn,{element:$,screen:t.screen,highlighted:$.id===a,selected:$.id===E,selectable:M,onClick:K},$.id))}),de&&Re&&A.jsx(Wn,{element:de,platform:t.platform,anchor:Re,cursorAnchored:X,showActions:ne,onTap:T})]})}),W=(...n)=>{window.debugRemoteControl&&console.log(...n)},R=(...n)=>{window.debugRemoteControl&&console.warn(...n)},x=(n,t,...c)=>{if(t)try{t(...c)}catch(a){console.error(`[RemoteControl] customer callback "${n}" threw:`,a)}},Tt=n=>Object.entries(U).find(([c,a])=>c.startsWith("ACTION_")&&a===n)?.[0]??String(n),$n=n=>n.includes("/android_")?"android":"ios",_r=(n,t)=>{const c=new URL(n);return c.searchParams.set("token",t),c.toString()},vr=1920,Tr=1200,Wt=3,Xn=1e3,Bn=15e3,qn=3e3,Vn=4e3,jn=(n,t)=>n===vr&&t===Tr||n===Tr&&t===vr,Gn={ios:{videoBorderRadiusMultiplier:.15,loadingLogoSize:"20%",videoPosition:{portrait:{heightMultiplier:.9678},landscape:{widthMultiplier:.9678}}},android:{videoBorderRadiusMultiplier:.13,loadingLogoSize:"40%",videoPosition:{portrait:{heightMultiplier:.967},landscape:{widthMultiplier:.962}}}};function Jn(n){const t=n.code,c=Rr[t];if(!c)return R(`Unknown event.code: ${t}, key: ${n.key}`),null;let a=s.META_NONE;const E=t>="KeyA"&&t<="KeyZ",p=n.getModifierState("CapsLock"),C=n.shiftKey;let O=C;return E&&(O=C!==p),O&&(a|=s.META_SHIFT_ON),n.ctrlKey&&(a|=s.META_CTRL_ON),n.altKey&&(a|=s.META_ALT_ON),n.metaKey&&(a|=s.META_META_ON),{keycode:c,metaState:a}}const zn=f.forwardRef(({className:n,url:t,token:c,sessionId:a,openUrl:E,showFrame:p=!0,autoReconnect:C=!1,onTerminated:O,assets:K,onConnectionStateChange:T,inspectMode:M,onAxSnapshotChange:N,onInspectSelectionChange:re,onAxStatusChange:ae,axPollIntervalMs:de,axMaxBackoffMs:ct,androidElementTreeOptions:Re,onCameraDemandChange:X,onCameraStats:ne,microphoneEnabled:J=!1,onMicrophoneStateChange:$},fe)=>{const we=f.useRef(null),F=f.useRef(null),he=f.useRef(null),[Xe,me]=f.useState(!1),[Bt,Be]=f.useState(!1),[At,qt]=f.useState(!1),Ae=f.useRef(!1),St=f.useRef(!1),[Vt,Yr]=f.useState(!1),[Kr,kr]=f.useState(!1),[Pr,jt]=f.useState({}),D=f.useRef(null),H=f.useRef(null),L=f.useRef(null),Se=f.useRef(void 0),qe=f.useRef(void 0),Ve=f.useRef(void 0),st=f.useRef(void 0),Me=f.useRef(void 0),Ee=f.useRef(0),at=f.useRef(0),be=f.useRef(!1),Mt=f.useRef(C);Mt.current=C;const pe=f.useRef(null),z=f.useRef(null),ge=f.useRef(void 0),bt=f.useMemo(()=>new Mn,[]),ce=f.useRef(X);ce.current=X;const ut=f.useRef(ne);ut.current=ne;const je=f.useRef(null),lt=f.useRef(null),Nt=f.useRef(J);Nt.current=J;const It=f.useRef(!1),Ge=f.useRef($);Ge.current=$;const Je=f.useRef(null),oe=f.useRef(null),dt=f.useRef(0),Gt=f.useRef(Promise.resolve()),Ne=f.useRef(null),ze=f.useRef(!1),ue=f.useRef(new Map),se=f.useRef(new Map),Ce=f.useRef(new Map),ye=f.useRef(new Map),V=f.useRef(new Map),Oe=f.useRef(!1),[Lr,Ur]=f.useState(!1),B=f.useRef(null),Ie=f.useRef(null),Qe=f.useRef({handle:()=>{},end:()=>{}}),[_e,ft]=f.useState(null),j=f.useRef(null),[Jt,zt]=f.useState(null),[Yt,Ze]=f.useState(null),[Kt,ht]=f.useState(null),[xr,Qt]=f.useState(null),[Fr,Zt]=f.useState(null),mt=f.useRef(null),Z=f.useRef(void 0),er=e=>{mt.current=e,Z.current===void 0&&(Z.current=window.requestAnimationFrame(()=>{Z.current=void 0,Zt(mt.current)}))},[Wr,Ye]=f.useState(null),Ke=f.useRef(M);Ke.current=M;const ke=f.useRef(null);ke.current=Jt;const kt=f.useRef(N);kt.current=N;const Pe=f.useRef(re);Pe.current=re;const tr=f.useRef(ae);tr.current=ae;const rr=f.useRef(O);rr.current=O;const nr=f.useRef(T);nr.current=T;const Pt=f.useRef(null),Le=e=>{Pt.current!==e&&(Pt.current=e,x("onConnectionStateChange",nr.current,e))},et=M===!0||M==="hover-only",Hr=M==="hover-only"?"hover-only":"select",ee=f.useMemo(()=>a||Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15),[a]),ie=f.useMemo(()=>$n(t),[t]),Ue=Gn[ie],tt=K?.[ie],or=ie==="android"&&Kr?Vt?tt?.tabletFrameLandscape:tt?.tabletFrame:Vt?tt?.frameLandscape:tt?.frame,ir=tt?.loadingLogo,Et=p&&!!or,k=e=>{W(e)},te=e=>{!L.current||L.current.readyState!=="open"||(L.current.send(e),j.current?.bumpActivity())},cr=-10,sr=(e,i)=>{const r=rt();if(!r)return;const o=Fe(r,e,i);if(!o)return;const{videoX:m,videoY:l,videoWidth:h,videoHeight:u}=o,g=vt(U.ACTION_DOWN,cr,h,u,m,l,1,U.BUTTON_PRIMARY,U.BUTTON_PRIMARY);g&&te(g),window.setTimeout(()=>{const _=vt(U.ACTION_UP,cr,h,u,m,l,0,U.BUTTON_PRIMARY,U.BUTTON_PRIMARY);_&&te(_)},60)},$r=(e,i)=>{const r=rt();if(!r||i.screen.width<=0||i.screen.height<=0)return;const o=e.frame.x+e.frame.width/2,m=e.frame.y+e.frame.height/2,l=o/i.screen.width*r.actualWidth,h=m/i.screen.height*r.actualHeight,u=r.videoRect.left+r.offsetX+l,g=r.videoRect.top+r.offsetY+h;sr(u,g)},pt=-1,gt=-2,ve=-3,xe=(e,i,r,o,m,l)=>{const h=vt(e,i,r,o,m,l,1,U.BUTTON_PRIMARY,U.BUTTON_PRIMARY);h&&(W("[rc-touch] sendSingleTouch",{action:e,actionName:Tt(e),pointerId:i,x:m,y:l,video:{width:r,height:o}}),te(h))},Te=(e,i,r)=>{if(!r)return;const{videoX:o,videoY:m,videoWidth:l,videoHeight:h}=r;let u=null,g=null,_=1;const b=U.BUTTON_PRIMARY;switch(i){case"down":e!==ve&&Qe.current.end(),u=V.current.size===0?U.ACTION_DOWN:U.ACTION_POINTER_DOWN,g={x:o,y:m},V.current.set(e,g),e===-1&&F.current?.focus();break;case"move":V.current.has(e)&&(u=U.ACTION_MOVE,g={x:o,y:m},V.current.set(e,g));break;case"up":case"cancel":V.current.has(e)&&(g=V.current.get(e),V.current.delete(e),i==="cancel"?u=U.ACTION_CANCEL:u=V.current.size===0?U.ACTION_UP:U.ACTION_POINTER_UP);break}if(u!==null&&g!==null){W("[rc-touch][mouse->touch] sending",{pointerId:e,eventType:i,action:u,actionName:Tt(u),positionToSend:g,video:{width:l,height:h},altHeld:Oe.current,activePointersAfter:Array.from(V.current.entries()).map(([w,y])=>({id:w,x:y.x,y:y.y}))});const v=vt(u,e,l,h,g.x,g.y,_,b,b);v&&(W("[rc-touch][mouse->touch] buffer",{pointerId:e,actionName:Tt(u),byteLength:v.byteLength}),te(v))}else(i==="up"||i==="cancel")&&V.current.delete(e)},Lt=e=>{if(Oe.current!==e&&(Oe.current=e,Ur(e),e||ft(null),W("[rc-touch][alt] updateAltHeld",{nextHeld:e,activePointerIds:Array.from(V.current.keys())}),ie==="ios"&&L.current&&L.current.readyState==="open")){const i=e?s.ACTION_DOWN:s.ACTION_UP,r=it(i,s.KEYCODE_ALT_LEFT,0,s.META_NONE);W("[rc-touch][alt] sending Indigo modifier keycode",{action:i,keycode:s.KEYCODE_ALT_LEFT}),r&&te(r)}},rt=()=>{const e=F.current,i=we.current;if(!e||!i)return null;const r=e.videoWidth,o=e.videoHeight;if(!r||!o)return null;const m=e.getBoundingClientRect(),l=i.getBoundingClientRect(),h=m.width,u=m.height,g=r/o,_=h/u;let b=h,v=u;g>_?v=h/g:b=u*g;const w=(h-b)/2,y=(u-v)/2;return{videoWidth:r,videoHeight:o,videoRect:m,containerRect:l,actualWidth:b,actualHeight:v,offsetX:w,offsetY:y}},Fe=(e,i,r)=>{const o=i-e.videoRect.left-e.offsetX,m=r-e.videoRect.top-e.offsetY,l=Math.max(0,Math.min(e.actualWidth,o)),h=Math.max(0,Math.min(e.actualHeight,m)),u=Math.max(0,Math.min(e.videoWidth,l/e.actualWidth*e.videoWidth)),g=Math.max(0,Math.min(e.videoHeight,h/e.actualHeight*e.videoHeight));return{videoX:u,videoY:g,videoWidth:e.videoWidth,videoHeight:e.videoHeight}},Xr=(e,i,r)=>{const o=i-e.videoRect.left-e.offsetX,m=r-e.videoRect.top-e.offsetY,l=Math.max(0,Math.min(e.actualWidth,o)),h=Math.max(0,Math.min(e.actualHeight,m)),u=Math.max(0,Math.min(e.videoWidth,l/e.actualWidth*e.videoWidth)),g=Math.max(0,Math.min(e.videoHeight,h/e.actualHeight*e.videoHeight)),_=e.videoWidth-u,b=e.videoHeight-g,v=e.videoRect.left+e.offsetX,w=e.videoRect.top+e.offsetY,y=v-e.containerRect.left+l,d=w-e.containerRect.top+h,I=v-e.containerRect.left+(e.actualWidth-l),P=w-e.containerRect.top+(e.actualHeight-h);return{containerX:y,containerY:d,mirrorContainerX:I,mirrorContainerY:P,videoX:u,videoY:g,mirrorVideoX:_,mirrorVideoY:b,videoWidth:e.videoWidth,videoHeight:e.videoHeight}},Br=(e,i,r,o,m,l,h)=>{const u=mn(e,i,r,o,m,l,h);W("[rc-touch2] sendTwoFingerMessage (iOS)",{actionName:Tt(e),video:{width:i,height:r},p0:{x:o,y:m},p1:{x:l,y:h},byteLength:u.byteLength}),te(u)},We=(e,i,r,o,m,l,h,u,g)=>{if(W("[rc-touch2] applyTwoFingerEvent",{platform:ie,eventType:e,video:{width:i,height:r},p0:{x:o,y:m,id:u},p1:{x:l,y:h,id:g}}),e==="down"&&Qe.current.end(),ie==="ios"){const _=e==="down"?U.ACTION_DOWN:e==="move"?U.ACTION_MOVE:U.ACTION_UP;Br(_,i,r,o,m,l,h)}else e==="down"?(xe(U.ACTION_DOWN,u,i,r,o,m),xe(U.ACTION_POINTER_DOWN,g,i,r,l,h)):e==="move"?(xe(U.ACTION_MOVE,u,i,r,o,m),xe(U.ACTION_MOVE,g,i,r,l,h)):(xe(U.ACTION_POINTER_UP,g,i,r,l,h),xe(U.ACTION_UP,u,i,r,o,m))},qr=(e,i,r)=>{if(!Oe.current){_e!==null&&ft(null);return}const o=Xr(e,i,r);ft(o)},Vr=(e,i,r)=>{const o=ke.current;if(!o||o.screen.width<=0||o.screen.height<=0)return null;const m=i-e.videoRect.left-e.offsetX,l=r-e.videoRect.top-e.offsetY;if(m<0||l<0||m>e.actualWidth||l>e.actualHeight)return null;const h=m/e.actualWidth*o.screen.width,u=l/e.actualHeight*o.screen.height;return br(o,h,u)},le=e=>{e.preventDefault(),e.stopPropagation();const i=rt();if((Ke.current===!0||Ke.current==="hover-only")&&!("touches"in e))if(e.type==="mousemove"){if(er({x:e.clientX,y:e.clientY}),i){const o=Vr(i,e.clientX,e.clientY);Ze(o?.id??null)}}else e.type==="mouseleave"&&(er(null),Ze(null));if(Ke.current!==!0&&(!("touches"in e)&&i&&(e.type==="mousemove"?qr(i,e.clientX,e.clientY):e.type==="mouseleave"&&ft(null)),!(!L.current||L.current.readyState!=="open"||!F.current||!i)))if("touches"in e){const o=e.touches,m=e.changedTouches;let l;switch(e.type){case"touchstart":l="down";break;case"touchmove":l="move";break;case"touchend":l="up";break;case"touchcancel":l="cancel";break;default:return}if(o.length===2){const h=o[0],u=o[1],g=Fe(i,h.clientX,h.clientY),_=Fe(i,u.clientX,u.clientY);if(!g||!_)return;B.current?B.current.source==="real-touch"&&(B.current.finger0={x:g.videoX,y:g.videoY},B.current.finger1={x:_.videoX,y:_.videoY},We("move",g.videoWidth,g.videoHeight,g.videoX,g.videoY,_.videoX,_.videoY,B.current.pointerId0,B.current.pointerId1)):(B.current={finger0:{x:g.videoX,y:g.videoY},finger1:{x:_.videoX,y:_.videoY},videoSize:{width:g.videoWidth,height:g.videoHeight},source:"real-touch",pointerId0:h.identifier,pointerId1:u.identifier},We("down",g.videoWidth,g.videoHeight,g.videoX,g.videoY,_.videoX,_.videoY,h.identifier,u.identifier))}else if(o.length<2&&B.current?.source==="real-touch"){const h=B.current;We("up",h.videoSize.width,h.videoSize.height,h.finger0.x,h.finger0.y,h.finger1.x,h.finger1.y,h.pointerId0,h.pointerId1),B.current=null;return}else{if(o.length>2)return;{const h=m[0];if(h){const u=Fe(i,h.clientX,h.clientY);Te(h.identifier,l,u)}}}}else{let m=null;const l=B.current?.source==="alt-mouse";switch(e.type){case"mousedown":e.button===0&&(m="down");break;case"mousemove":(l||V.current.has(-1))&&(m="move");break;case"mouseup":e.button===0&&(m="up");break;case"mouseleave":(l||V.current.has(-1))&&(m="up");break}if(m){const h=Fe(i,e.clientX,e.clientY);if(!h)return;W("[rc-touch][mouse] event",{domType:e.type,eventType:m,button:e.button,buttons:e.buttons,client:{x:e.clientX,y:e.clientY},altHeldRef:Oe.current,inTwoFingerMode:l,geometry:{videoX:h.videoX,videoY:h.videoY,videoWidth:h.videoWidth,videoHeight:h.videoHeight},activePointerIds:Array.from(V.current.keys())}),Oe.current||l?jr(m,h):Te(-1,m,h)}}},jr=(e,i)=>{const{videoX:r,videoY:o,videoWidth:m,videoHeight:l}=i,h=m-r,u=l-o;if(e==="down"){B.current={finger0:{x:r,y:o},finger1:{x:h,y:u},videoSize:{width:m,height:l},source:"alt-mouse",pointerId0:pt,pointerId1:gt},F.current?.focus(),We("down",m,l,r,o,h,u,pt,gt);return}if(e==="move"){B.current?.source==="alt-mouse"&&(B.current.finger0={x:r,y:o},B.current.finger1={x:h,y:u},We("move",m,l,r,o,h,u,pt,gt));return}if(e==="up"||e==="cancel"){const g=B.current;if(g?.source==="alt-mouse"){const{finger0:_,finger1:b,videoSize:v}=g;We("up",v.width,v.height,_.x,_.y,b.x,b.y,pt,gt),B.current=null}return}},Gr=150,ar=()=>{const e=Ie.current;e&&(window.clearTimeout(e.endTimer),Te(ve,"up",e.pos),Ie.current=null)},Jr=e=>{if(e.ctrlKey||Oe.current||B.current)return;const i=V.current.size;if(i>1||i===1&&!V.current.has(ve))return;const r=rt();if(!r)return;const o=e.clientX-r.videoRect.left-r.offsetX,m=e.clientY-r.videoRect.top-r.offsetY;if(o<0||o>r.actualWidth||m<0||m>r.actualHeight)return;const l=Fe(r,e.clientX,e.clientY);if(!l)return;e.preventDefault();const h=(e.deltaMode===1?16:e.deltaMode===2?r.actualWidth:1)*(r.videoWidth/r.actualWidth),u=(e.deltaMode===1?16:e.deltaMode===2?r.actualHeight:1)*(r.videoHeight/r.actualHeight),g=-e.deltaX*h,_=-e.deltaY*u,b=P=>{window.clearTimeout(P.endTimer),P.endTimer=window.setTimeout(ar,Gr)};if(g===0&&_===0){Ie.current&&b(Ie.current);return}const v=()=>({videoWidth:l.videoWidth,videoHeight:l.videoHeight,videoX:Math.abs(g)>Math.abs(_)?Math.min(Math.max(l.videoX,l.videoWidth*.2),l.videoWidth*.8):l.videoX,videoY:Math.abs(_)>=Math.abs(g)?Math.min(Math.max(l.videoY,l.videoHeight*.2),l.videoHeight*.8):l.videoY}),w=P=>({...P,videoX:Math.min(Math.max(P.videoX+g,0),P.videoWidth),videoY:Math.min(Math.max(P.videoY+_,0),P.videoHeight)});let y=Ie.current;if(y)window.clearTimeout(y.endTimer);else{const P=v();Te(ve,"down",P),y={pos:P,endTimer:0},Ie.current=y}let d=y.pos,I=w(d);I.videoX===d.videoX&&I.videoY===d.videoY&&(Te(ve,"up",d),d=v(),Te(ve,"down",d),I=w(d)),Te(ve,"move",I),y.pos=I,b(y)};f.useEffect(()=>{Qe.current={handle:Jr,end:ar}}),f.useEffect(()=>{const e=we.current;if(!e)return;const i=r=>Qe.current.handle(r);return e.addEventListener("wheel",i,{passive:!1}),()=>{Qe.current.end(),e.removeEventListener("wheel",i)}},[]),f.useEffect(()=>{const e=o=>{o.key==="Alt"&&Lt(!0)},i=o=>{o.key==="Alt"&&Lt(!1)},r=()=>{Lt(!1)};return window.addEventListener("keydown",e,!0),window.addEventListener("keyup",i,!0),window.addEventListener("blur",r),()=>{window.removeEventListener("keydown",e,!0),window.removeEventListener("keyup",i,!0),window.removeEventListener("blur",r)}},[]);const ur=e=>{if(e.preventDefault(),e.stopPropagation(),W("Keyboard event:",{type:e.type,key:e.key,keyCode:e.keyCode,code:e.code,target:e.target.tagName,focused:document.activeElement===F.current}),document.activeElement!==F.current){R("Video element not focused, skipping keyboard event");return}if(!L.current||L.current.readyState!=="open"){R("Data channel not ready for keyboard event:",L.current?.readyState);return}if(e.type==="keydown"){if(e.key.toLowerCase()==="v"&&(e.metaKey||e.ctrlKey)){W("Paste shortcut detected"),navigator.clipboard.readText().then(r=>{if(r){W("Pasting text via SET_CLIPBOARD:",r.substring(0,20)+(r.length>20?"...":""));const o=En(r,!0);te(o)}}).catch(r=>{console.error("Failed to read clipboard contents: ",r)});return}if(e.key.toLowerCase()==="m"&&(e.metaKey||e.ctrlKey)){W("Menu shortcut detected");const r=it(s.ACTION_DOWN,s.MENU,0,s.META_NONE);te(r);const o=it(s.ACTION_UP,s.MENU,0,s.META_NONE);te(o);return}}const i=Jn(e);if(i){const{keycode:r,metaState:o}=i,m=e.type==="keydown"?s.ACTION_DOWN:s.ACTION_UP;W(`Sending Keycode: key=${e.key}, code=${r}, action=${m}, meta=${o}`);const l=it(m,r,0,o);te(l)}else W(`Ignoring unhandled key event: type=${e.type}, key=${e.key}`)},zr=()=>{D.current&&D.current.readyState===WebSocket.OPEN&&D.current.send(JSON.stringify({type:"keepAlive",sessionId:ee}))},lr=()=>{Se.current&&window.clearInterval(Se.current),Se.current=window.setInterval(zr,1e4)},dr=()=>{Se.current&&(window.clearInterval(Se.current),Se.current=void 0)},Ct=()=>{qe.current&&(window.clearTimeout(qe.current),qe.current=void 0)},yt=()=>{Ve.current&&(window.clearTimeout(Ve.current),Ve.current=void 0)},nt=()=>{st.current&&(window.clearInterval(st.current),st.current=void 0)},ot=()=>{Me.current!==void 0&&(window.clearTimeout(Me.current),Me.current=void 0)},Qr=()=>{ze.current||(ze.current=!0,nt(),me(!0),Le("connected"))},G=e=>{for(const i of e.getTracks())try{i.stop()}catch(r){R("track.stop() failed:",r)}},Zr=()=>{const e=z.current;e&&(z.current=null,G(e))},fr=e=>{const i=Gt.current.then(e).catch(r=>{R("microphone operation failed:",r)});return Gt.current=i,i},Ut=()=>Nt.current||It.current,hr=e=>{const i=`ui-mic-${Date.now()}-${Math.random().toString(36).substring(2,9)}`;Ne.current=i,e.send(JSON.stringify({type:"microphoneStart",id:i}))},xt=()=>fr(()=>en()),en=async()=>{const e=dt.current,i=()=>e===dt.current&&Ut(),r=u=>{x("onMicrophoneStateChange",Ge.current,{active:!1,error:u})};if(!i())return;const o=D.current,m=Je.current;if(!o||o.readyState!==WebSocket.OPEN||!m||oe.current)return;if(!navigator.mediaDevices||typeof navigator.mediaDevices.getUserMedia!="function"){console.warn("[RemoteControl] navigator.mediaDevices.getUserMedia unavailable. getUserMedia requires a secure context (https or http://localhost)."),r("Microphone capture requires a secure context (https)");return}let l=null;try{l=await navigator.mediaDevices.getUserMedia({audio:!0,video:!1})}catch(u){console.warn("[RemoteControl] microphone getUserMedia denied/failed:",u)}if(!i()){l&&G(l);return}if(!l){r("Microphone permission denied or no device available");return}const h=l.getAudioTracks()[0]??null;if(!h){G(l),r("Captured stream has no audio track");return}try{await m.replaceTrack(h)}catch(u){R("replaceTrack(audioTrack) failed:",u),G(l),r("Failed to attach the microphone track to the connection");return}if(!i()){try{await m.replaceTrack(null)}catch(u){R("replaceTrack(null) on stale mic attach failed:",u)}G(l);return}oe.current=l,h.onended=()=>{oe.current===l&&Ot("microphone capture ended by the browser")},hr(o),x("onMicrophoneStateChange",Ge.current,{active:!0,label:h.label||void 0})},Ot=e=>(++dt.current,Ne.current=null,fr(async()=>{const i=Je.current,r=oe.current;if(oe.current=null,i&&r)try{await i.replaceTrack(null)}catch(m){R("replaceTrack(null) on mic detach failed:",m)}r&&G(r);const o=D.current;if(r&&o&&o.readyState===WebSocket.OPEN){const m=`ui-mic-${Date.now()}-${Math.random().toString(36).substring(2,9)}`;o.send(JSON.stringify({type:"microphoneStop",id:m}))}(r||e)&&x("onMicrophoneStateChange",Ge.current,{active:!1,...e!==void 0&&{error:e}})})),mr=(e,i)=>{let r;try{r=Kn(i),console.info(`[RemoteControl] camera capture: ${r.camera?.width}x${r.camera?.height} @ ${r.camera?.frameRate??"?"}fps`+(r.camera?.label?` — ${r.camera.label}`:""))}catch(o){R("getSettings() on outbound camera track failed:",o),r={type:"cameraResult",granted:!0,camera:{label:i.label||void 0}}}e.send(JSON.stringify(r)),x("onCameraDemandChange",ce.current,!0,!0,r.camera)},tn=e=>{if(!e)return;const i=e.indexOf("/"),o=(i>=0?e.slice(i+1):e).toUpperCase();return o==="HEVC"?"H265":o},rn=async()=>{const e=pe.current,i=ut.current;if(!e||!i)return;let r;try{r=await e.getStats()}catch{return}let o,m,l;if(r.forEach(w=>{w.type==="outbound-rtp"&&w.kind==="video"?o=w:w.type==="remote-inbound-rtp"&&w.kind==="video"&&(l=w)}),o?.codecId){const w=r.get(o.codecId);w&&(m=w.mimeType)}if(!o)return;const h=o.timestamp??Date.now(),u=lt.current;let g,_,b;if(u&&h>u.timestamp){const w=(h-u.timestamp)/1e3;if(typeof o.framesEncoded=="number"&&typeof u.framesEncoded=="number"&&(g=Math.max(0,(o.framesEncoded-u.framesEncoded)/w)),typeof o.bytesSent=="number"&&typeof u.bytesSent=="number"&&(_=Math.max(0,(o.bytesSent-u.bytesSent)*8/w)),typeof o.packetsSent=="number"&&typeof u.packetsSent=="number"&&l&&typeof l.packetsLost=="number"&&typeof u.packetsLost=="number"){const y=o.packetsSent-u.packetsSent,d=l.packetsLost-u.packetsLost;y>0&&(b=Math.max(0,Math.min(100,d/y*100)))}}lt.current={timestamp:h,framesEncoded:o.framesEncoded,bytesSent:o.bytesSent,packetsSent:o.packetsSent,packetsLost:l?.packetsLost};const v={codec:tn(m),encoderImplementation:o.encoderImplementation,hardwareAccelerated:typeof o.powerEfficientEncoder=="boolean"?o.powerEfficientEncoder:void 0,framesPerSecond:g,framesEncoded:o.framesEncoded,bitrateBps:_,width:o.frameWidth,height:o.frameHeight,qualityLimitationReason:o.qualityLimitationReason,rttMs:typeof l?.roundTripTime=="number"?l.roundTripTime*1e3:void 0,packetsLostPct:b};x("onCameraStats",ut.current,v)},Er=()=>{je.current===null&&(lt.current=null,je.current=setInterval(()=>{rn()},1e3))},_t=()=>{je.current!==null&&(clearInterval(je.current),je.current=null),lt.current=null,x("onCameraStats",ut.current,null)},nn=(e,i,r,o)=>bt.enqueue(async({isCurrent:m})=>{const l=()=>m()&&o()&&D.current===i&&pe.current===r;if(!l())return;if(!e.active){const v=z.current;try{await r.replaceTrack(null)}catch(w){R("replaceTrack(null) on camera detach failed:",w)}if(z.current===v&&(z.current=null,ge.current=void 0,v&&G(v)),_t(),!l())return;x("onCameraDemandChange",ce.current,!1);return}x("onCameraDemandChange",ce.current,!0);const h=z.current,u=h?.getVideoTracks()[0],g=ge.current;if(u?.readyState==="live"&&g&&!In(g,e)){ge.current=e,mr(i,u),Er();return}if(h){try{await r.replaceTrack(null)}catch(v){R("replaceTrack(null) before camera switch failed:",v)}if(z.current===h&&(z.current=null,ge.current=void 0,G(h)),_t(),!l())return}if(!navigator.mediaDevices||typeof navigator.mediaDevices.getUserMedia!="function"){if(console.warn("[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."),!l())return;i.send(JSON.stringify({type:"cameraResult",granted:!1})),x("onCameraDemandChange",ce.current,!0,!1);return}let _=null;try{_=await navigator.mediaDevices.getUserMedia({video:Nn(e),audio:!1})}catch(v){console.warn("[RemoteControl] getUserMedia denied/failed:",v)}if(!l()){_&&G(_);return}if(!_){i.send(JSON.stringify({type:"cameraResult",granted:!1})),x("onCameraDemandChange",ce.current,!0,!1);return}const b=_.getVideoTracks()[0]??null;if(!b){if(G(_),!l())return;i.send(JSON.stringify({type:"cameraResult",granted:!1})),x("onCameraDemandChange",ce.current,!0,!1);return}try{b.contentHint="motion"}catch{}try{await r.replaceTrack(b)}catch(v){if(R("replaceTrack(videoTrack) failed:",v),G(_),!l())return;i.send(JSON.stringify({type:"cameraResult",granted:!1})),x("onCameraDemandChange",ce.current,!0,!1);return}if(!l()){try{await r.replaceTrack(null)}catch(v){R("replaceTrack(null) for stale camera attach failed:",v)}G(_);return}try{const v=r.getParameters();(!v.encodings||v.encodings.length===0)&&(v.encodings=[{}]),v.encodings[0].maxBitrate=8e6,v.encodings[0].maxFramerate=30,v.degradationPreference="maintain-framerate",await r.setParameters(v)}catch(v){R("setParameters on outbound camera failed:",v)}if(!l()){try{await r.replaceTrack(null)}catch(v){R("replaceTrack(null) for stale camera finalize failed:",v)}G(_);return}z.current=_,ge.current=e,b.onended=()=>{z.current===_&&bt.enqueueCurrent(async({isCurrent:v})=>{if(!(!v()||z.current!==_||!o()||D.current!==i||pe.current!==r)){try{await r.replaceTrack(null)}catch(w){R("replaceTrack(null) after camera ended failed:",w)}!v()||z.current!==_||!o()||D.current!==i||pe.current!==r||(z.current=null,ge.current=void 0,G(_),_t(),i.send(JSON.stringify({type:"cameraResult",granted:!1})),x("onCameraDemandChange",ce.current,!0,!1))}}).catch(v=>R("camera ended cleanup failed:",v))},l()&&(mr(i,b),Er())}),He=()=>{yt(),ot(),nt(),j.current&&(j.current.stop(),j.current=null),bt.invalidate(),_t(),Zr(),ge.current=void 0,pe.current=null,++dt.current,It.current=!1,Ne.current=null,oe.current&&(G(oe.current),oe.current=null,x("onMicrophoneStateChange",Ge.current,{active:!1})),Je.current=null,Z.current!==void 0&&(window.cancelAnimationFrame(Z.current),Z.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),H.current&&(H.current.onconnectionstatechange=null,H.current.oniceconnectionstatechange=null,H.current.ontrack=null,H.current.onicecandidate=null,H.current.close(),H.current=null),F.current&&(F.current.srcObject=null),L.current&&(L.current.onopen=null,L.current.onclose=null,L.current.onerror=null,L.current.close(),L.current=null)},pr=()=>{document.hidden?dr():lr()},on=async()=>{if(typeof navigator<"u"&&navigator.onLine===!1)return!1;let e;try{const o=new URL(t);o.protocol=o.protocol==="wss:"?"https:":o.protocol==="ws:"?"http:":o.protocol,e=_r(o.toString(),c)}catch{return!1}const i=new AbortController,r=window.setTimeout(()=>i.abort(),Vn);try{return(await fetch(e,{method:"GET",cache:"no-store",signal:i.signal})).status===404}catch{return!1}finally{window.clearTimeout(r)}},cn=()=>{Ae.current||(Ae.current=!0,qt(!0),Be(!1),Ee.current+=1,Ct(),yt(),ot(),He(),k("Instance terminated"),Le("terminated"),x("onTerminated",rr.current))},sn=()=>{Ae.current||St.current||(St.current=!0,on().then(e=>{St.current=!1,e&&cn()}))},$e=(e,i)=>{if(Ae.current||i!==Ee.current)return;if(sn(),be.current){if(!Mt.current){k(`Connection failed after it was established: ${e}`),Be(!0),Le("failed"),He();return}k(`Reconnecting after established session dropped: ${e}`),be.current=!1,at.current=-1}Ct();const r=at.current+1;if(r>=Wt){k(`Connection failed after ${Wt} attempts: ${e}`),Be(!0),Le("failed"),He();return}k(`Retrying connection (${r+1}/${Wt})`),Le("reconnecting"),He(),qe.current=window.setTimeout(()=>{qe.current=void 0,i===Ee.current&&gr(r)},Xn)},gr=async(e=0)=>{if(Ae.current)return;const i=Ee.current+1;Ee.current=i,at.current=e,be.current=!1,Be(!1),e===0&&Pt.current!=="reconnecting"&&Le("connecting"),Ct(),yt(),nt(),ze.current=!1,me(!1),He();const r=()=>i===Ee.current;Ve.current=window.setTimeout(()=>{Ve.current=void 0,!(!r()||be.current)&&$e("Connection did not succeed within 15 seconds",i)},Bn);try{const o=new WebSocket(_r(t,c));if(D.current=o,await new Promise((y,d)=>{let I=!1;const P=window.setTimeout(()=>d(new Error("WebSocket connection timeout")),3e4),S=Y=>{I||(I=!0,window.clearTimeout(P),Y())};o.onopen=()=>{!r()||D.current!==o||S(y)},o.onerror=Y=>{!r()||D.current!==o||(k("WebSocket error: "+Y),S(()=>d(new Error("WebSocket connection failed"))))},o.onclose=()=>{!r()||D.current!==o||(k("WebSocket closed"),S(()=>d(new Error("WebSocket closed before connection was established"))))}}),!r()||D.current!==o)return;o.onerror=y=>{!r()||D.current!==o||k("WebSocket error: "+y)},o.onclose=()=>{!r()||D.current!==o||k("WebSocket closed")};const m=new Promise((y,d)=>{const I=Y=>{window.clearTimeout(P),o.removeEventListener("message",S),Y()},P=window.setTimeout(()=>I(()=>d(new Error("RTCConfiguration timeout"))),3e4),S=Y=>{if(!(!r()||D.current!==o))try{const q=JSON.parse(Y.data);if(q.type==="signalingError"&&q.requestType==="requestRtcConfiguration"&&q.sessionId===ee){const Q=typeof q.error=="string"?q.error:"Unable to load streaming configuration";I(()=>d(new Error(Q)))}else q.type==="rtcConfiguration"&&I(()=>y({rtcConfiguration:q.rtcConfiguration,cameraSupported:q.cameraSupported===!0}))}catch(q){console.error("Error handling RTC configuration:",q),I(()=>d(q))}};o.addEventListener("message",S),o.send(JSON.stringify({type:"requestRtcConfiguration",sessionId:ee}))}),{rtcConfiguration:l,cameraSupported:h}=await m;if(!r()||D.current!==o)return;const u=new RTCPeerConnection(l);H.current=u,u.addTransceiver("audio",{direction:"recvonly"});const g=u.addTransceiver("video",{direction:"recvonly"}),_=ie==="ios"||h,b=_?u.addTransceiver("video",{direction:"sendonly"}):null;pe.current=b?.sender??null;const v=_?u.addTransceiver("audio",{direction:"sendonly"}):null;if(Je.current=v?.sender??null,RTCRtpReceiver.getCapabilities){const y=RTCRtpReceiver.getCapabilities("video");if(y&&y.codecs){const I=y.codecs.sort((P,S)=>{const Y=q=>{const Q=q.mimeType.toLowerCase();return Q.includes("vp9")?1:Q.includes("h265")||Q.includes("hevc")?2:Q.includes("h264")||Q.includes("avc")?3:4};return Y(P)-Y(S)});g.setCodecPreferences(I),W("Set codec preferences:",I.map(P=>P.mimeType).join(", "))}}if(b&&RTCRtpSender.getCapabilities){const y=RTCRtpSender.getCapabilities("video");if(y&&y.codecs){const d=new Set(["42e01f","42e028","640c1f"]),I=S=>{const Y=S.mimeType.toLowerCase(),Q=(S.sdpFmtpLine||"").toLowerCase().match(/profile-level-id=([0-9a-f]{6})/),fn=Q?Q[1]:"";return Y==="video/h265"||Y==="video/hevc"?1:Y==="video/h264"&&d.has(fn)?2:Y==="video/h264"?3:Y==="video/vp9"?4:Y==="video/vp8"?5:Y==="video/rtx"||Y==="video/red"||Y==="video/ulpfec"?0:6},P=[...y.codecs].sort((S,Y)=>I(S)-I(Y));try{b.setCodecPreferences(P),W("Outbound camera codec preferences:",P.map(S=>`${S.mimeType}${S.sdpFmtpLine?`[${S.sdpFmtpLine}]`:""}`).join(", "))}catch(S){R("Failed to set outbound camera codec preferences:",S)}}}const w=u.createDataChannel("control",{ordered:!0,negotiated:!0,id:1});if(L.current=w,w.onopen=()=>{if(!r()||L.current!==w||D.current!==o)return;be.current=!0,yt(),k("Control channel opened"),j.current||(j.current=new Sn({platform:ie,baseIntervalMs:de,maxBackoffMs:ct,androidElementTreeOptions:Re,send:d=>{if(!D.current||D.current.readyState!==WebSocket.OPEN)return!1;try{return D.current.send(JSON.stringify(d)),!0}catch{return!1}},onSnapshot:d=>{zt(I=>$t(I,d)?I:d),queueMicrotask(()=>{x("onAxSnapshotChange",kt.current,d)})},onStatusChange:(d,I)=>{x("onAxStatusChange",tr.current,d,I)}}),(Ke.current===!0||Ke.current==="hover-only")&&j.current.start());const y=()=>{!r()||ze.current||L.current!==w||D.current!==o||o.readyState!==WebSocket.OPEN||o.send(JSON.stringify({type:"requestFrame",sessionId:ee}))};if(y(),nt(),st.current=window.setInterval(()=>{if(!r()||ze.current||L.current!==w||D.current!==o||o.readyState!==WebSocket.OPEN){nt();return}y()},250),E){try{const d=decodeURIComponent(E);k("Opening URL"),o.send(JSON.stringify({type:"openUrl",url:d,sessionId:ee}))}catch(d){console.error({error:d},"Error decoding URL, falling back to the original URL"),o.send(JSON.stringify({type:"openUrl",url:E,sessionId:ee}))}j.current?.bumpActivity()}},w.onclose=()=>{!r()||L.current!==w||k("Control channel closed")},w.onerror=y=>{!r()||L.current!==w||(console.error("Control channel error:",y),k("Control channel error: "+y))},u.onconnectionstatechange=()=>{!r()||H.current!==u||(k("Connection state: "+u.connectionState),u.connectionState==="failed"&&$e("WebRTC connection entered failed state",i))},u.oniceconnectionstatechange=()=>{if(!r()||H.current!==u)return;const y=u.iceConnectionState;if(k("ICE state: "+y),y==="connected"||y==="completed"){ot(),Ut()&&!oe.current&&xt();return}if(y==="failed"){ot(),$e("ICE connection entered failed state",i);return}y==="disconnected"&&Mt.current&&Me.current===void 0&&(Me.current=window.setTimeout(()=>{Me.current=void 0,!(!r()||H.current!==u)&&u.iceConnectionState==="disconnected"&&$e("ICE stayed disconnected past grace period",i)},qn))},u.ontrack=y=>{!r()||H.current!==u||(k("Received remote track: "+y.track.kind),y.track.kind==="video"&&F.current&&(W(`[${new Date().toISOString()}] Video track received:`,y.track),F.current.srcObject=y.streams[0]))},u.onicecandidate=y=>{if(!(!r()||H.current!==u||D.current!==o))if(y.candidate&&o.readyState===WebSocket.OPEN){const d={type:"candidate",candidate:y.candidate.candidate,sdpMid:y.candidate.sdpMid,sdpMLineIndex:y.candidate.sdpMLineIndex,sessionId:ee};o.send(JSON.stringify(d)),k("Sent ICE candidate")}else k("ICE candidate gathering completed")},o.onmessage=async y=>{if(!r()||D.current!==o)return;let d;try{d=JSON.parse(y.data)}catch(I){R("Error parsing message:",I);return}if(!j.current?.handleMessage(d))switch(k("Received: "+d.type),d.type){case"signalingError":{if(d.requestType!=="offer"||d.sessionId!==ee)break;const S=typeof d.error=="string"?d.error:"Unable to establish the streaming connection";k("Error: "+S),$e(S,i);break}case"answer":if(!H.current||H.current!==u){k("No peer connection, skipping answer");break}if(await u.setRemoteDescription(new RTCSessionDescription({type:"answer",sdp:d.sdp})),!r()||H.current!==u)return;k("Set remote description");break;case"candidate":if(!H.current||H.current!==u){k("No peer connection, skipping candidate");break}if(await u.addIceCandidate(new RTCIceCandidate({candidate:d.candidate,sdpMid:d.sdpMid,sdpMLineIndex:d.sdpMLineIndex})),!r()||H.current!==u)return;k("Added ICE candidate");break;case"screenshot":case"screenshotResult":{if(typeof d.id!="string"){R("Received invalid screenshot success message:",d);break}const S=Qn(d);if(S){const Q=se.current.get(d.id);if(!Q){R(`Received screenshot error for unknown or handled id: ${d.id}`);break}R(`Received screenshot error for id ${d.id}: ${S}`),Q(new Error(S)),ue.current.delete(d.id),se.current.delete(d.id);break}const Y=Zn(d);if(!Y){R("Received screenshot message without image data:",d);break}const q=ue.current.get(d.id);if(!q){R(`Received screenshot data for unknown or handled id: ${d.id}`);break}W(`Received screenshot data for id ${d.id}`),q(Y),ue.current.delete(d.id),se.current.delete(d.id);break}case"screenshotError":if(typeof d.id!="string"||typeof d.message!="string"){R("Received invalid screenshot error message:",d);break}const I=se.current.get(d.id);if(!I){R(`Received screenshot error for unknown or handled id: ${d.id}`);break}R(`Received screenshot error for id ${d.id}: ${d.message}`),I(new Error(d.message)),ue.current.delete(d.id),se.current.delete(d.id);break;case"cameraRequest":{const S=pe.current;if(!S)break;const Y=bn(d);if(!Y){R("Received invalid cameraRequest:",d);break}console.info("[RemoteControl] cameraRequest received:",Y.active,Y.facingMode),await nn(Y,o,S,r);break}case"microphoneRequest":{if(!Je.current)break;const S=d.active===!0;if(It.current=S,console.info("[RemoteControl] microphoneRequest received, active=",S),!S){Nt.current||await Ot();break}if(oe.current){hr(o);break}await xt();break}case"microphoneStartResult":{if(Ne.current===null||d.id!==Ne.current)break;Ne.current=null,typeof d.error=="string"&&(console.warn("[RemoteControl] microphoneStart rejected by host:",d.error),Ot(d.error));break}case"terminateAppResult":if(typeof d.id!="string"){R("Received invalid terminateApp result message:",d);break}if(typeof d.error=="string"){const S=ye.current.get(d.id);if(!S){R(`Received terminateApp error for unknown or handled id: ${d.id}`);break}R(`Received terminateApp error for id ${d.id}: ${d.error}`),S(new Error(d.error)),Ce.current.delete(d.id),ye.current.delete(d.id);break}const P=Ce.current.get(d.id);if(!P){R(`Received terminateApp result for unknown or handled id: ${d.id}`);break}W(`Received terminateApp success for id ${d.id}`),P(),Ce.current.delete(d.id),ye.current.delete(d.id);break;default:R(`Received unhandled message type: ${d.type}`,d);break}},H.current===u){const y=await u.createOffer({offerToReceiveVideo:!0,offerToReceiveAudio:!1});if(!r()||H.current!==u||(await u.setLocalDescription(y),!r()||H.current!==u))return;r()&&D.current===o&&o.readyState===WebSocket.OPEN&&o.send(JSON.stringify({type:"offer",sdp:y.sdp,sessionId:ee})),k("Sent offer")}}catch(o){if(!r())return;const m=o instanceof Error?o.message:String(o);k("Error: "+m),$e(m,i)}},Ft=()=>{Ae.current=!1,qt(!1),gr(0)},an=()=>{Ee.current+=1,at.current=0,be.current=!1,Ct(),ot(),He(),k("Stopped")},un=e=>{e.stopPropagation(),Ft()};f.useEffect(()=>{Ut()?xt():Ot()},[J]),f.useEffect(()=>(me(!1),Ft(),document.hidden||lr(),document.addEventListener("visibilitychange",pr),()=>{dr(),an(),document.removeEventListener("visibilitychange",pr)}),[t,c,a]);const Cr=()=>{const e=rt();if(!e){Qt(null);return}const i={left:e.videoRect.left-e.containerRect.left+e.offsetX,top:e.videoRect.top-e.containerRect.top+e.offsetY,width:e.actualWidth,height:e.actualHeight};Qt(r=>r&&r.left===i.left&&r.top===i.top&&r.width===i.width&&r.height===i.height?r:i)};f.useEffect(()=>{const e=F.current,i=he.current,r=we.current;if(!e)return;const o=()=>{if(!Et||!i){jt({}),Cr();return}const h=i.clientWidth,u=i.clientHeight;if(h===0||u===0)return;const g=e.videoWidth>e.videoHeight;Yr(g),kr(ie==="android"&&jn(e.videoWidth,e.videoHeight));const _=g?Ue.videoPosition.landscape:Ue.videoPosition.portrait;let b={};_.heightMultiplier?(b.height=`${u*_.heightMultiplier}px`,b.width="auto"):_.widthMultiplier&&(b.width=`${h*_.widthMultiplier}px`,b.height="auto"),b.borderRadius=`${g?u*Ue.videoBorderRadiusMultiplier:h*Ue.videoBorderRadiusMultiplier}px`,jt(b),Cr()},m=new ResizeObserver(()=>{o()});i&&m.observe(i),m.observe(e),r&&m.observe(r),i&&i.addEventListener("load",o),e.addEventListener("loadedmetadata",o),e.addEventListener("resize",o);const l=()=>j.current?.bumpActivity();return e.addEventListener("resize",l),o(),()=>{m.disconnect(),e.removeEventListener("loadedmetadata",o),e.removeEventListener("resize",o),e.removeEventListener("resize",l),i&&i.removeEventListener("load",o)}},[Ue,Et]),f.useEffect(()=>{const e=j.current;et?e?.start():(e?.stop(),zt(null),Ze(null),ht(null),Zt(null),Ye(null),mt.current=null,Z.current!==void 0&&(window.cancelAnimationFrame(Z.current),Z.current=void 0),x("onAxSnapshotChange",kt.current,null))},[et]),f.useEffect(()=>()=>{Z.current!==void 0&&(window.cancelAnimationFrame(Z.current),Z.current=void 0)},[]),f.useEffect(()=>{if(!et)return;const e=i=>{i.key==="Escape"&&(Kt||Yt)&&(ht(null),Ze(null),Ye(null),x("onInspectSelectionChange",Pe.current,null))};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)},[et,Kt,Yt]);const ln=()=>{F.current&&F.current.focus()};f.useImperativeHandle(fe,()=>({openUrl:e=>{if(!D.current||D.current.readyState!==WebSocket.OPEN){R("WebSocket not open, cannot send open_url command via ref.");return}try{const i=decodeURIComponent(e);k("Opening URL"),D.current.send(JSON.stringify({type:"openUrl",url:i,sessionId:ee}))}catch(i){R("Error decoding or sending URL via ref:",{error:i,url:e}),D.current.send(JSON.stringify({type:"openUrl",url:e,sessionId:ee}))}j.current?.bumpActivity()},sendKeyEvent:e=>{if(!L.current||L.current.readyState!=="open"){R("Data channel not ready for imperative key command:",L.current?.readyState);return}const i=Rr[e.code];if(!i){R(`Unknown event.code for imperative command: ${e.code}`);return}let r=s.META_NONE;e.shiftKey&&(r|=s.META_SHIFT_ON),e.altKey&&(r|=s.META_ALT_ON),e.ctrlKey&&(r|=s.META_CTRL_ON),e.metaKey&&(r|=s.META_META_ON);const o=e.type==="keydown"?s.ACTION_DOWN:s.ACTION_UP;W(`Sending Imperative Key Command: code=${e.code}, keycode=${i}, action=${o}, meta=${r}`);const m=it(o,i,0,r);m&&te(m)},screenshot:()=>new Promise((e,i)=>{if(!D.current||D.current.readyState!==WebSocket.OPEN)return R("WebSocket not open, cannot send screenshot command."),i(new Error("WebSocket is not connected or connection is not open."));const r=`ui-ss-${Date.now()}-${Math.random().toString(36).substring(2,9)}`,o={type:"screenshot",id:r};ue.current.set(r,e),se.current.set(r,i),W("Sending screenshot request:",o);try{D.current.send(JSON.stringify(o))}catch(m){R("Failed to send screenshot request immediately:",m),ue.current.delete(r),se.current.delete(r),i(m);return}setTimeout(()=>{ue.current.has(r)&&(R(`Screenshot request timed out for id ${r}`),se.current.get(r)?.(new Error("Screenshot request timed out")),ue.current.delete(r),se.current.delete(r))},3e4)}),terminateApp:e=>new Promise((i,r)=>{if(!D.current||D.current.readyState!==WebSocket.OPEN)return R("WebSocket not open, cannot send terminateApp command."),r(new Error("WebSocket is not connected or connection is not open."));const o=`ui-term-${Date.now()}-${Math.random().toString(36).substring(2,9)}`,m={type:"terminateApp",id:o,bundleId:e};Ce.current.set(o,i),ye.current.set(o,r),W("Sending terminateApp request:",m);try{D.current.send(JSON.stringify(m))}catch(l){R("Failed to send terminateApp request immediately:",l),Ce.current.delete(o),ye.current.delete(o),r(l);return}j.current?.bumpActivity(),setTimeout(()=>{Ce.current.has(o)&&(R(`terminateApp request timed out for id ${o}`),ye.current.get(o)?.(new Error("terminateApp request timed out")),Ce.current.delete(o),ye.current.delete(o))},3e4)}),reconnect:()=>Ft(),refreshAxTree:async()=>{const e=j.current;if(!e)throw new Error("Inspect mode is not active");return e.refresh()},getAxSnapshot:()=>ke.current,setInspectHighlight:e=>{Ze(e?.id??null)},setInspectSelection:e=>{ht(e?.id??null),Ye(e?mt.current:null);const i=ke.current;e&&i?x("onInspectSelectionChange",Pe.current,{element:e,snapshot:i}):x("onInspectSelectionChange",Pe.current,null)},getAxStatus:()=>j.current?.getStatus()??"idle"}));const dn=Lr&&_e!==null;return A.jsxs("div",{ref:we,className:De("rc-container",n),style:{touchAction:"none"},onMouseDown:le,onMouseMove:le,onMouseUp:le,onMouseLeave:le,onTouchStart:le,onTouchMove:le,onTouchEnd:le,onTouchCancel:le,children:[dn&&_e&&A.jsxs(A.Fragment,{children:[A.jsx("div",{className:"rc-touch-indicator",style:{left:`${_e.containerX}px`,top:`${_e.containerY}px`}}),A.jsx("div",{className:"rc-touch-indicator",style:{left:`${_e.mirrorContainerX}px`,top:`${_e.mirrorContainerY}px`}})]}),Et&&A.jsx("img",{ref:he,src:or,alt:"",className:ie==="ios"?De("rc-phone-frame","rc-phone-frame-ios"):"rc-phone-frame",draggable:!1}),A.jsx("video",{ref:F,className:De("rc-video",!Et&&"rc-video-frameless",!Xe&&"rc-video-loading"),style:{...Pr,...ir?{backgroundImage:`url("${ir}")`,backgroundRepeat:"no-repeat",backgroundPosition:"center",backgroundSize:Ue.loadingLogoSize}:{}},autoPlay:!0,playsInline:!0,muted:!0,tabIndex:0,onKeyDown:ur,onKeyUp:ur,onClick:ln,onLoadedData:Qr,onFocus:()=>{F.current&&(F.current.style.outline="none")},onBlur:()=>{F.current&&(F.current.style.outline="none")}}),et&&A.jsx(Hn,{snapshot:Jt,geometry:xr,highlightedId:Yt,selectedId:Kt,mode:Hr,cursorPosition:Fr,frozenCursorPosition:Wr,onSelectChange:(e,i)=>{ht(e?.id??null),e&&i?Ye(i):e||Ye(null);const r=ke.current;e&&r?x("onInspectSelectionChange",Pe.current,{element:e,snapshot:r}):x("onInspectSelectionChange",Pe.current,null)},onTapElement:(e,i)=>{if(i){sr(i.x,i.y);return}const r=ke.current;r&&$r(e,r)}}),At?A.jsxs("div",{className:"rc-terminated",role:"status",children:[A.jsx("div",{className:"rc-terminated-title",children:"Instance terminated"}),A.jsx("div",{className:"rc-terminated-message",children:"This instance no longer exists and can't be reconnected."})]}):Bt&&A.jsx("button",{type:"button",className:"rc-retry-button",onClick:un,children:"Retry"})]})}),Qn=n=>typeof n.message=="string"?n.message:typeof n.error=="string"?n.error:null,Zn=n=>typeof n.dataUri=="string"?{dataUri:n.dataUri}:typeof n.base64=="string"?n.base64.startsWith("data:")?{dataUri:n.base64}:{dataUri:`data:${n.base64.startsWith("/9j/")?"image/jpeg":"image/png"};base64,${n.base64}`}:null;exports.AX_UNAVAILABLE_ERROR=Dt;exports.RemoteControl=zn;exports.axElementAtPoint=br;exports.axElementSelectorExpression=Nr;exports.axElementSummary=Xt;exports.axElementsEqual=Ht;exports.axSnapshotsEqual=$t;exports.clampAxFrameForScreen=Mr;exports.normalizeAndroidTree=Sr;exports.normalizeIosTree=Ar;
|
package/package.json
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@limrun/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"publishConfig": {
|
|
5
|
-
"access": "public"
|
|
6
|
-
"tag": "next"
|
|
5
|
+
"access": "public"
|
|
7
6
|
},
|
|
8
7
|
"main": "./dist/index.js",
|
|
9
8
|
"module": "./dist/index.js",
|
|
@@ -14,6 +13,11 @@
|
|
|
14
13
|
"import": "./dist/index.js",
|
|
15
14
|
"require": "./dist/index.cjs"
|
|
16
15
|
},
|
|
16
|
+
"./lite": {
|
|
17
|
+
"types": "./dist/lite.d.ts",
|
|
18
|
+
"import": "./dist/lite.js",
|
|
19
|
+
"require": "./dist/lite.cjs"
|
|
20
|
+
},
|
|
17
21
|
"./package.json": "./package.json"
|
|
18
22
|
},
|
|
19
23
|
"scripts": {
|
|
@@ -49,9 +53,12 @@
|
|
|
49
53
|
"vite": "^7.1.4",
|
|
50
54
|
"vite-plugin-dts": "^4.5.4",
|
|
51
55
|
"vite-plugin-lib-inject-css": "^2.2.2",
|
|
52
|
-
"vitest": "^
|
|
56
|
+
"vitest": "^4.1.11"
|
|
53
57
|
},
|
|
54
58
|
"dependencies": {
|
|
55
59
|
"clsx": "^2.1.1"
|
|
60
|
+
},
|
|
61
|
+
"resolutions": {
|
|
62
|
+
"vite": "^7.1.4"
|
|
56
63
|
}
|
|
57
64
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { forwardRef } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
RemoteControl as RemoteControlBase,
|
|
4
|
+
type RemoteControlHandle,
|
|
5
|
+
type RemoteControlProps,
|
|
6
|
+
} from './remote-control';
|
|
7
|
+
import { defaultRemoteControlAssets } from '../frame-assets';
|
|
8
|
+
|
|
9
|
+
// The default export: RemoteControl with Limrun's device frames unless the
|
|
10
|
+
// caller supplies its own assets.
|
|
11
|
+
export const RemoteControl = forwardRef<RemoteControlHandle, RemoteControlProps>((props, ref) => (
|
|
12
|
+
<RemoteControlBase ref={ref} assets={defaultRemoteControlAssets} {...props} />
|
|
13
|
+
));
|
|
14
|
+
RemoteControl.displayName = 'RemoteControl';
|