@mearl/native-host 2.15.1 → 2.15.3
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 +1 -7
- package/dist/index.js +19 -19
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -56,7 +56,7 @@ ${truncated}...`}function extractFields(data,fields){if(fields.length>100)throw
|
|
|
56
56
|
if (!el) return { error: 'Element not found: ' + sel };
|
|
57
57
|
return scroll.call(el, dir, dist, sel, policy);
|
|
58
58
|
})()`}function unwrapPageScrollResult(result,missingResultMessage){if(!result)throw new Error(missingResultMessage);if("error"in result)throw new Error(result.error);return result}var IPHONE_SAFARI_26_USER_AGENT="Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Mobile/15E148 Safari/604.1",ANDROID_CHROME_152_USER_AGENT="Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Mobile Safari/537.36",DEVICE_PRESETS={"iphone-17-pro":{width:402,height:874,deviceScaleFactor:3,mobile:!0,userAgent:IPHONE_SAFARI_26_USER_AGENT,platform:"iPhone",platformVersion:"26.0",architecture:"",model:"iPhone",safeAreaInsets:{top:62,right:0,bottom:34,left:0},landscapeSafeAreaInsets:{top:0,right:62,bottom:21,left:62},appProfileModel:"iPhone 17 Pro",appProfileOs:"ios",appearance:{cutout:"dynamic-island"}},"iphone-17e":{width:390,height:844,deviceScaleFactor:3,mobile:!0,userAgent:IPHONE_SAFARI_26_USER_AGENT,platform:"iPhone",platformVersion:"26.0",architecture:"",model:"iPhone",safeAreaInsets:{top:47,right:0,bottom:34,left:0},landscapeSafeAreaInsets:{top:0,right:47,bottom:21,left:47},appProfileModel:"iPhone 17e",appProfileOs:"ios",appearance:{cutout:"notch"}},"pixel-11":{width:412,height:923,deviceScaleFactor:2.625,mobile:!0,userAgent:ANDROID_CHROME_152_USER_AGENT,platform:"Android",platformVersion:"17",architecture:"arm",model:"Pixel 11",safeAreaInsets:{top:30,right:0,bottom:24,left:0},landscapeSafeAreaInsets:{top:0,right:24,bottom:0,left:24},appProfileModel:"Pixel 11",appProfileOs:"android",appearance:{cutout:"none"}},"ipad-mini-a17-pro":{width:744,height:1133,deviceScaleFactor:2,mobile:!1,touch:!0,userAgent:"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Safari/605.1.15",platform:"macOS",platformVersion:"10.15.7",architecture:"x86",model:"",safeAreaInsets:{top:24,right:0,bottom:20,left:0},landscapeSafeAreaInsets:{top:0,right:24,bottom:20,left:24},appProfileModel:"iPad mini (A17 Pro)",appProfileOs:"ios",appearance:{cutout:"none"}},"galaxy-s26":{width:360,height:780,deviceScaleFactor:3,mobile:!0,userAgent:ANDROID_CHROME_152_USER_AGENT,platform:"Android",platformVersion:"16",architecture:"arm",model:"SM-S942B",safeAreaInsets:{top:30,right:0,bottom:24,left:0},landscapeSafeAreaInsets:{top:0,right:24,bottom:0,left:24},appProfileModel:"SM-S942B",appProfileOs:"android",appearance:{cutout:"none"}},"pura-x-max":{width:664,height:939,deviceScaleFactor:2.75,mobile:!0,userAgent:"Mozilla/5.0 (Phone;OpenHarmony 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 ArkWeb/6.0.0.42 Mobile",platform:"OpenHarmony",platformVersion:"6.0",architecture:"",model:"HUAWEI Pura X Max",safeAreaInsets:{top:30,right:0,bottom:24,left:0},landscapeSafeAreaInsets:{top:0,right:24,bottom:0,left:24},appProfileModel:"HUAWEI Pura X Max",appProfileOs:"android",appearance:{cutout:"none"}},"iphone-15-pro":{width:393,height:852,deviceScaleFactor:3,mobile:!0,userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",platform:"iPhone",platformVersion:"17.0",architecture:"",model:"iPhone",safeAreaInsets:{top:59,right:0,bottom:34,left:0},landscapeSafeAreaInsets:{top:0,right:59,bottom:21,left:59},appProfileModel:"iPhone 15 Pro",appProfileOs:"ios",appearance:{cutout:"dynamic-island"}},"iphone-se":{width:375,height:667,deviceScaleFactor:2,mobile:!0,userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1",platform:"iPhone",platformVersion:"16.0",architecture:"",model:"iPhone",safeAreaInsets:{top:20,right:0,bottom:0,left:0},landscapeSafeAreaInsets:{top:0,right:0,bottom:0,left:0},appProfileModel:"iPhone SE",appProfileOs:"ios",appearance:{cutout:"none"}},"pixel-8":{width:412,height:915,deviceScaleFactor:2.625,mobile:!0,userAgent:"Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36",platform:"Android",platformVersion:"14",architecture:"",model:"Pixel 8",safeAreaInsets:{top:30,right:0,bottom:24,left:0},landscapeSafeAreaInsets:{top:0,right:24,bottom:0,left:24},appProfileModel:"Pixel 8",appProfileOs:"android",appearance:{cutout:"none"}},"ipad-mini":{width:768,height:1024,deviceScaleFactor:2,mobile:!1,touch:!0,userAgent:"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15",platform:"macOS",platformVersion:"10.15.7",architecture:"x86",model:"",safeAreaInsets:{top:24,right:0,bottom:20,left:0},landscapeSafeAreaInsets:{top:0,right:24,bottom:20,left:24},appProfileModel:"iPad mini",appProfileOs:"ios",appearance:{cutout:"none"}},"galaxy-s23":{width:360,height:780,deviceScaleFactor:3,mobile:!0,userAgent:"Mozilla/5.0 (Linux; Android 14; SM-S911B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36",platform:"Android",platformVersion:"14",architecture:"",model:"SM-S911B",safeAreaInsets:{top:30,right:0,bottom:24,left:0},landscapeSafeAreaInsets:{top:0,right:24,bottom:0,left:24},appProfileModel:"SM-S911B",appProfileOs:"android",appearance:{cutout:"none"}}};function resolveEmulationConfig(input){if(input.preset&&!(input.preset in DEVICE_PRESETS))throw new Error(`set_device_emulation: unknown preset "${input.preset}". Available: ${Object.keys(DEVICE_PRESETS).join(", ")}`);let preset=input.preset?DEVICE_PRESETS[input.preset]:void 0,width=input.width??preset?.width,height=input.height??preset?.height;if(!width||!height)throw new Error('set_device_emulation: must provide either "preset" or both "width" and "height"');let mobile=input.mobile??preset?.mobile??!0,orientation=input.orientation??"portrait",scale=input.scale??1;if(!Number.isFinite(scale)||scale<=0)throw new Error('set_device_emulation: "scale" must be a finite positive number');let[finalWidth,finalHeight]=orientation==="landscape"?[height,width]:[width,height],userAgent=input.userAgent??preset?.userAgent??"";if(!userAgent)throw new Error('set_device_emulation: "userAgent" is required when no preset is used (preset supplies a default)');let safeAreaInsets=orientation==="landscape"?preset?.landscapeSafeAreaInsets??{top:preset?.safeAreaInsets.left??0,right:preset?.safeAreaInsets.top??0,bottom:preset?.safeAreaInsets.right??0,left:preset?.safeAreaInsets.bottom??0}:preset?.safeAreaInsets??{top:0,right:0,bottom:0,left:0},appearance={cutout:orientation==="landscape"?"none":preset?.appearance.cutout??"none"};return{width:finalWidth,height:finalHeight,deviceScaleFactor:input.deviceScaleFactor??preset?.deviceScaleFactor??(mobile?2:1),scale,mobile,userAgent,platform:preset?.platform??(mobile?"iPhone":"macOS"),platformVersion:preset?.platformVersion??"",architecture:preset?.architecture??"",model:preset?.model??"",touch:input.touch??preset?.touch??mobile,orientation,safeAreaInsets,appearance,presetName:input.preset}}function buildEnableEmulationCommands(config2){let safeAreaInsets=config2.safeAreaInsets??{top:0,right:0,bottom:0,left:0};return[{method:"Emulation.setDeviceMetricsOverride",params:{width:config2.width,height:config2.height,screenWidth:config2.width,screenHeight:config2.height,deviceScaleFactor:config2.deviceScaleFactor,scale:config2.scale??1,...(config2.scale??1)!==1?{dontSetVisibleSize:!0}:{},mobile:config2.mobile,screenOrientation:{type:config2.orientation==="landscape"?"landscapePrimary":"portraitPrimary",angle:config2.orientation==="landscape"?90:0}}},...(config2.scale??1)!==1?[{method:"Emulation.setVisibleSize",params:{width:Math.max(1,Math.round(config2.width*(config2.scale??1))),height:Math.max(1,Math.round(config2.height*(config2.scale??1)))}}]:[],{method:"Emulation.setUserAgentOverride",params:{userAgent:config2.userAgent,platform:config2.platform,userAgentMetadata:{mobile:config2.mobile,platform:config2.platform,platformVersion:config2.platformVersion,architecture:config2.architecture,model:config2.model}}},{method:"Emulation.setTouchEmulationEnabled",params:config2.touch?{enabled:!0,maxTouchPoints:5}:{enabled:!1}},{method:"Emulation.setEmitTouchEventsForMouse",params:{enabled:config2.touch,configuration:"mobile"}},{method:"Emulation.setSafeAreaInsetsOverride",params:{insets:{top:safeAreaInsets.top,topMax:safeAreaInsets.top,right:safeAreaInsets.right,rightMax:safeAreaInsets.right,bottom:safeAreaInsets.bottom,bottomMax:safeAreaInsets.bottom,left:safeAreaInsets.left,leftMax:safeAreaInsets.left}},optional:!0}]}function buildDisableEmulationCommands(){return[{method:"Emulation.clearDeviceMetricsOverride",params:{}},{method:"Emulation.setUserAgentOverride",params:{userAgent:""}},{method:"Emulation.setTouchEmulationEnabled",params:{enabled:!1}},{method:"Emulation.setEmitTouchEventsForMouse",params:{enabled:!1}},{method:"Emulation.setSafeAreaInsetsOverride",params:{insets:{}},optional:!0}]}function matchAXNodesByText(nodes,options){let{text,role,exact=!0}=options;if(typeof text!="string"||text.length===0)return{hits:[]};let hits=[];for(let node of nodes){if(node.ignored||node.backendDOMNodeId===void 0)continue;let name=node.name?.value;if(typeof name!="string"||name.length===0||!(exact?name===text:name.includes(text)))continue;let nodeRole=node.role?.value??"";role&&nodeRole!==role||hits.push({backendNodeId:node.backendDOMNodeId,role:nodeRole,name})}return{hits}}function formatAXTextMatchCandidates(hits,limit=5){return hits.slice(0,limit).map((hit,idx)=>{let name=hit.name.length>60?`${hit.name.slice(0,60)}…`:hit.name,role=hit.role||"(no-role)";return` ${idx+1}. ${role} "${name}"`}).join(`
|
|
59
|
-
`)}function resolvePageClickDispatchPolicy(clickMode,visibilityState,touchEmulationEnabled){return clickMode!==void 0&&clickMode!=="auto"?{clickMode,stateAwareControls:clickMode==="dom"}:visibilityState==="hidden"?{clickMode:"dom",stateAwareControls:!0,fallbackReason:"page-hidden"}:{clickMode:touchEmulationEnabled?"touch":"mouse",stateAwareControls:!0}}function createPageClickResult(requestedTarget,dispatchTarget){let normalizedDispatchTarget={tag:dispatchTarget.tag,text:dispatchTarget.text},resolvedTarget={tag:dispatchTarget.sourceTarget?.tag??normalizedDispatchTarget.tag,text:dispatchTarget.sourceTarget?.text??normalizedDispatchTarget.text,strategy:dispatchTarget.strategy??"self",distance:dispatchTarget.distance??0};return{clicked:!0,tag:normalizedDispatchTarget.tag,text:requestedTarget.name||normalizedDispatchTarget.text,requestedTarget,resolvedTarget,dispatchTarget:normalizedDispatchTarget,...dispatchTarget.hitTarget?{hitTarget:dispatchTarget.hitTarget}:{},...dispatchTarget.frame?{frame:dispatchTarget.frame}:{},...dispatchTarget.coordinates?{coordinates:dispatchTarget.coordinates}:{},...dispatchTarget.actionableAncestorCandidates?.length?{actionableAncestorCandidates:dispatchTarget.actionableAncestorCandidates}:{},...dispatchTarget.controlState?{controlState:dispatchTarget.controlState}:{},...dispatchTarget.dispatchMode?{dispatchMode:dispatchTarget.dispatchMode}:{},...dispatchTarget.pointerType?{pointerType:dispatchTarget.pointerType}:{}}}function clickElementViaJS(){let el=this.nodeType===3?this.parentElement:this;if(!el||!el.isConnected)return null;let sourceTarget={tag:el.tagName?el.tagName.toLowerCase():"",text:(el.textContent||"").trim().slice(0,100)};if(el.tagName==="OPTION"){let select=el.closest("select");if(select){let desc=Object.getOwnPropertyDescriptor(window.HTMLSelectElement.prototype,"value");desc&&desc.set?desc.set.call(select,el.value):select.value=el.value,select.dispatchEvent(new Event("input",{bubbles:!0})),select.dispatchEvent(new Event("change",{bubbles:!0}));let rect2=select.getBoundingClientRect();return{tag:"option",text:(el.textContent||"").trim().slice(0,100),cx:rect2.x+rect2.width/2,cy:rect2.y+rect2.height/2,strategy:"self",distance:0,sourceTarget}}}function isActionable(node){if(!node||node.nodeType!==1)return!1;if(/^(A|BUTTON|INPUT|SELECT|TEXTAREA|SUMMARY|DETAILS|LABEL)$/i.test(node.tagName)||/button|link|tab|menuitem|checkbox|radio|option|switch/i.test(node.getAttribute("role")||"")||node.isContentEditable||typeof node.onclick=="function")return!0;let tabIndexAttribute=node.getAttribute("tabindex");if(tabIndexAttribute===null)return!1;let tabIndex=Number(tabIndexAttribute);return Number.isFinite(tabIndex)&&tabIndex>=0}let target=el,strategy="self",distance=0;if(!isActionable(target)){let ancestor=target.parentElement;for(;ancestor&&ancestor!==document.body&&distance<6;){if(distance+=1,isActionable(ancestor)){target=ancestor,strategy="actionable-ancestor";break}ancestor=ancestor.parentElement}}if(strategy==="self"&&!isActionable(target)){let cursor=target,descendantDistance=0;for(;cursor.children.length===1;){let child=cursor.children[0];if(!child||child.nodeType!==1||!(child.textContent||"").trim())break;cursor=child,descendantDistance+=1}cursor!==target?(target=cursor,strategy="single-child-descendant",distance=descendantDistance):distance=0}let rect=target.getBoundingClientRect();(rect.top<0||rect.left<0||rect.bottom>window.innerHeight||rect.right>window.innerWidth)&&(target.scrollIntoView({block:"center",inline:"center",behavior:"instant"}),rect=target.getBoundingClientRect());let cx=rect.x+rect.width/2,cy=rect.y+rect.height/2;try{let touch=new Touch({identifier:Date.now(),target,clientX:cx,clientY:cy});target.dispatchEvent(new TouchEvent("touchstart",{touches:[touch],targetTouches:[touch],changedTouches:[touch],bubbles:!0,cancelable:!0})),target.dispatchEvent(new TouchEvent("touchend",{touches:[],targetTouches:[],changedTouches:[touch],bubbles:!0,cancelable:!0}))}catch{}let controlState,controlType=target.tagName==="INPUT"&&/^(checkbox|radio)$/i.test(target.type||"")?String(target.type).toLowerCase():"";if(controlType==="checkbox"||controlType==="radio"){let checkedBefore=!!target.checked;target.click(),controlState={type:controlType,checkedBefore,checkedAfter:!!target.checked}}else target.click();return{tag:target.tagName?target.tagName.toLowerCase():"",text:(target.textContent||"").trim().slice(0,100),cx,cy,strategy,distance,sourceTarget,...controlState?{controlState}:{}}}function getClickCoordsFromNode(){let el=this.nodeType===3?this.parentElement:this;if(!el||!el.isConnected||!el.getBoundingClientRect)return null;let sourceTarget={tag:el.tagName?el.tagName.toLowerCase():"",text:(el.textContent||"").trim().slice(0,100)};function isActionable(node){if(!node||node.nodeType!==1)return!1;if(/^(A|BUTTON|INPUT|SELECT|TEXTAREA|SUMMARY|DETAILS|LABEL)$/i.test(node.tagName)||/button|link|tab|menuitem|checkbox|radio|option|switch/i.test(node.getAttribute("role")||"")||node.isContentEditable||typeof node.onclick=="function")return!0;let tabIndexAttribute=node.getAttribute("tabindex");if(tabIndexAttribute===null)return!1;let tabIndex=Number(tabIndexAttribute);return Number.isFinite(tabIndex)&&tabIndex>=0}let target=el,strategy="self",distance=0;if(!isActionable(target)){let ancestor=target.parentElement;for(;ancestor&&ancestor!==document.body&&distance<6;){if(distance+=1,isActionable(ancestor)){target=ancestor,strategy="actionable-ancestor";break}ancestor=ancestor.parentElement}}if(strategy==="self"&&!isActionable(target)){let cursor=target,descendantDistance=0;for(;cursor.children.length===1;){let child=cursor.children[0];if(!child||child.nodeType!==1||!(child.textContent||"").trim())break;cursor=child,descendantDistance+=1}cursor!==target?(target=cursor,strategy="single-child-descendant",distance=descendantDistance):distance=0}let actionableAncestorCandidates=[];if(strategy==="self"&&!isActionable(target)){let sourceRect=el.getBoundingClientRect(),ancestor=el.parentElement,candidateDistance=0;for(;ancestor&&ancestor!==document.body&&candidateDistance<6;){candidateDistance+=1;let rect2=ancestor.getBoundingClientRect(),reason=getComputedStyle(ancestor).cursor==="pointer"?"cursor-pointer":rect2.width*rect2.height>sourceRect.width*sourceRect.height*1.5?"containing-block":null;if(reason){let escapeCss=value=>globalThis.CSS&&typeof globalThis.CSS.escape=="function"?globalThis.CSS.escape(value):value.replace(/[^a-zA-Z0-9_-]/g,character=>`\\${character}`),candidateSelector=ancestor.id?`#${escapeCss(ancestor.id)}`:"";if(!candidateSelector){let path19=[],cursor=ancestor;for(;cursor&&cursor!==document.documentElement&&path19.length<5;){let parent=cursor.parentElement,tag=cursor.tagName.toLowerCase();if(!parent){path19.unshift(tag);break}let siblings=Array.from(parent.children).filter(item=>item.tagName===cursor.tagName),index=siblings.indexOf(cursor)+1;path19.unshift(siblings.length>1?`${tag}:nth-of-type(${index})`:tag),cursor=parent}candidateSelector=path19.join(" > ")}candidateSelector&&actionableAncestorCandidates.push({selector:candidateSelector,tag:ancestor.tagName.toLowerCase(),text:(ancestor.textContent||"").trim().slice(0,100),distance:candidateDistance,reason})}if(actionableAncestorCandidates.length>=3)break;ancestor=ancestor.parentElement}}let rect=target.getBoundingClientRect();return(rect.top<0||rect.left<0||rect.bottom>window.innerHeight||rect.right>window.innerWidth)&&(target.scrollIntoView({block:"center",inline:"center",behavior:"instant"}),rect=target.getBoundingClientRect()),{x:rect.x+rect.width/2,y:rect.y+rect.height/2,tag:target.tagName?target.tagName.toLowerCase():"",text:(target.textContent||"").trim().slice(0,100),...target.tagName==="INPUT"?{inputType:String(target.type||"").toLowerCase()}:{},strategy,distance,sourceTarget,...actionableAncestorCandidates.length>0?{actionableAncestorCandidates}:{}}}function isPageDragPoint(value){if(!value||typeof value!="object")return!1;let point=value;return Number.isFinite(point.x)&&Number.isFinite(point.y)&&point.x>=0&&point.y>=0}function resolveEndpoint(value,name){if(typeof value=="string"&&value.trim().length>0)return value.trim();if(isPageDragPoint(value))return{x:value.x,y:value.y};throw new Error(`page_drag: "${name}" must be a non-empty CSS/@ref selector or { x, y } viewport point.`)}function resolvePageDragInput(data){if(!data||typeof data!="object")throw new Error("page_drag: payload is required");if(data.dragMode!==void 0&&!["auto","dom","mouse","touch"].includes(data.dragMode))throw new Error('page_drag: "dragMode" must be one of auto, dom, mouse, touch');let durationMs=data.durationMs??400;if(!Number.isFinite(durationMs)||durationMs<0||durationMs>5e3)throw new Error('page_drag: "durationMs" must be between 0 and 5000.');return{from:resolveEndpoint(data.from,"from"),to:resolveEndpoint(data.to,"to"),dragMode:data.dragMode??"auto",durationMs:Math.round(durationMs)}}function resolvePageDragDispatchPolicy(dragMode,visibilityState,touchEmulationEnabled){let requestedMode=dragMode??"auto",pointerType=requestedMode==="mouse"||requestedMode==="touch"?requestedMode:touchEmulationEnabled?"touch":"mouse";return requestedMode==="dom"?{dispatchMode:"dom",pointerType}:requestedMode==="auto"&&visibilityState==="hidden"?{dispatchMode:"dom",pointerType,fallbackReason:"page-hidden"}:{dispatchMode:"trusted-input",pointerType}}function buildPageDragPath(from,to,durationMs){let steps=Math.max(2,Math.min(60,Math.ceil(durationMs/25)));return{points:Array.from({length:steps},(_,index)=>{let ratio=(index+1)/steps;return{x:from.x+(to.x-from.x)*ratio,y:from.y+(to.y-from.y)*ratio}}),intervalMs:durationMs/steps}}function dragBetweenPointsInPage(from,points,pointerType){let target=document.elementFromPoint(from.x,from.y);if(!target)return{dragged:!1,steps:0,error:`No element found at drag start point (${from.x}, ${from.y})`};if(points.length===0)return{dragged:!1,steps:0,error:"Drag path must contain at least one point"};let view=target.ownerDocument.defaultView??window,realm=view,pointerId=1,pointerInit=(point,buttons,pressure)=>({bubbles:!0,cancelable:!0,composed:!0,view,clientX:point.x,clientY:point.y,screenX:point.x,screenY:point.y,button:0,buttons,pointerId,pointerType,isPrimary:!0,pressure,width:1,height:1}),dispatchPointer=(type,point,buttons,pressure)=>typeof realm.PointerEvent!="function"?!1:(target.dispatchEvent(new realm.PointerEvent(type,pointerInit(point,buttons,pressure))),!0),dispatchMouse=(type,point,buttons)=>typeof realm.MouseEvent!="function"?!1:(target.dispatchEvent(new realm.MouseEvent(type,{bubbles:!0,cancelable:!0,composed:!0,view,clientX:point.x,clientY:point.y,screenX:point.x,screenY:point.y,button:0,buttons})),!0),createTouch=point=>{let init={identifier:pointerId,target,clientX:point.x,clientY:point.y,screenX:point.x,screenY:point.y,pageX:point.x+view.scrollX,pageY:point.y+view.scrollY,radiusX:1,radiusY:1,rotationAngle:0,force:.5};return typeof realm.Touch=="function"?new realm.Touch(init):init},dispatchTouch=(type,point)=>{if(typeof realm.TouchEvent!="function")return!1;let touch=createTouch(point),activeTouches=type==="touchend"?[]:[touch];return target.dispatchEvent(new realm.TouchEvent(type,{bubbles:!0,cancelable:!0,composed:!0,touches:activeTouches,targetTouches:activeTouches,changedTouches:[touch]})),!0},dispatched=dispatchPointer("pointerdown",from,1,.5);dispatched=pointerType==="touch"?dispatchTouch("touchstart",from)||dispatched:dispatchMouse("mousedown",from,1)||dispatched;for(let point of points)dispatched=dispatchPointer("pointermove",point,1,.5)||dispatched,dispatched=pointerType==="touch"?dispatchTouch("touchmove",point)||dispatched:dispatchMouse("mousemove",point,1)||dispatched;let end=points[points.length-1];return dispatched=pointerType==="touch"?dispatchTouch("touchend",end)||dispatched:dispatchMouse("mouseup",end,0)||dispatched,dispatched=dispatchPointer("pointerup",end,0,0)||dispatched,dispatched?{dragged:!0,steps:points.length}:{dragged:!1,steps:0,error:"This page does not support synthetic drag events"}}var DRAG_BETWEEN_POINTS_IN_PAGE_SOURCE=dragBetweenPointsInPage.toString();function buildPageDragDomExpression(from,points,pointerType){return`(${DRAG_BETWEEN_POINTS_IN_PAGE_SOURCE})(${JSON.stringify(from)}, ${JSON.stringify(points)}, ${JSON.stringify(pointerType)})`}function unwrapPageDragDomResult(result){if(!result)throw new Error("page_drag: DOM simulation returned no result");if(!result.dragged)throw new Error(`page_drag: ${result.error}`);return result}function getDragCoordsFromNode(){let el=this.nodeType===Node.TEXT_NODE?this.parentElement:this;if(!el||typeof el.getBoundingClientRect!="function")return null;let rect=el.getBoundingClientRect(),viewportWidth=window.visualViewport?.width??window.innerWidth,viewportHeight=window.visualViewport?.height??window.innerHeight;if(rect.width<=0||rect.height<=0)return{x:0,y:0,tag:"",text:"",error:"Element has no visible bounds"};if(rect.right<=0||rect.bottom<=0||rect.left>=viewportWidth||rect.top>=viewportHeight)return{x:0,y:0,tag:"",text:"",error:"Element is outside the current viewport; scroll it into view before dragging"};let x=Math.min(Math.max(rect.left+rect.width/2,0),Math.max(viewportWidth-1,0)),y=Math.min(Math.max(rect.top+rect.height/2,0),Math.max(viewportHeight-1,0));return{x,y,tag:el.tagName?.toLowerCase()??"",text:(el.textContent??"").trim().slice(0,100)}}var SKIP_ROLES=new Set(["none","generic","InlineTextBox","LineBreak","paragraph","Section","LabelText"]),ALWAYS_SKIP_ROLES=new Set(["InlineTextBox","LineBreak","graphics-symbol","graphics-document"]),INTERACTIVE_ROLES=new Set(["button","checkbox","combobox","gridcell","link","listbox","menuitem","menuitemcheckbox","menuitemradio","option","radio","scrollbar","searchbox","slider","spinbutton","switch","tab","textbox","treeitem"]);function isInteractiveSnapshotNode(node){let focusedControl=!!node.focused&&node.role!=="RootWebArea"&&node.role!=="WebArea";return INTERACTIVE_ROLES.has(node.role)||focusedControl||node.checked!==void 0||node.expanded!==void 0||!!node.selected}function hasInteractiveSnapshotNode(node){return node?isInteractiveSnapshotNode(node)?!0:(node.children??[]).some(hasInteractiveSnapshotNode):!1}var CHECKABLE_AX_ROLES=new Set(["checkbox","menuitemcheckbox","menuitemradio","radio","switch"]);function resolveDOMSnapshotViewportBounds(metrics){let viewport=metrics.visualViewport??metrics.cssVisualViewport;return normalizePageViewportBounds({left:viewport?.pageX??0,top:viewport?.pageY??0,width:viewport?.clientWidth,height:viewport?.clientHeight})}function normalizePageViewportBounds(value){if(!value||typeof value!="object")return null;let{left,top,width,height}=value;return typeof left!="number"||typeof top!="number"||typeof width!="number"||typeof height!="number"||!Number.isFinite(left)||!Number.isFinite(top)||!Number.isFinite(width)||!Number.isFinite(height)||width<=0||height<=0?null:{left,top,width,height}}function readDOMCheckedState(){let tag=String(this&&this.tagName||"").toLowerCase(),type=String(this&&this.type||"").toLowerCase();if(tag==="input"&&(type==="checkbox"||type==="radio"))return!!this.checked;let ariaChecked=this&&this.getAttribute&&this.getAttribute("aria-checked");if(ariaChecked==="mixed")return"mixed";if(ariaChecked==="true")return!0;if(ariaChecked==="false")return!1}async function reconcileAXCheckedStates(nodes,readCheckedState){let candidates=nodes.filter(node=>node.backendDOMNodeId!==void 0&&CHECKABLE_AX_ROLES.has(node.role?.value??"")),nextIndex=0,workers=Array.from({length:Math.min(8,candidates.length)},async()=>{for(;nextIndex<candidates.length;){let node=candidates[nextIndex++];if(!(!node||node.backendDOMNodeId===void 0))try{let checked=await readCheckedState(node.backendDOMNodeId);if(checked===void 0)continue;let properties=node.properties??=[],existing=properties.find(property=>property.name==="checked");existing?existing.value.value=checked:properties.push({name:"checked",value:{value:checked}})}catch{}}});await Promise.all(workers)}function extractAXProperties(node){let result={};if(!node.properties)return result;for(let prop of node.properties)switch(prop.name){case"focused":prop.value.value===!0&&(result.focused=!0);break;case"checked":result.checked=prop.value.value==="mixed"?"mixed":prop.value.value===!0;break;case"disabled":prop.value.value===!0&&(result.disabled=!0);break;case"required":prop.value.value===!0&&(result.required=!0);break;case"expanded":result.expanded=prop.value.value===!0;break;case"selected":prop.value.value===!0&&(result.selected=!0);break;case"level":result.level=prop.value.value;break}return result}function formatSnapshotNode(node,indent,lines){let line=" ".repeat(indent);node.ref&&(line+=`${node.ref} `),line+=`[${node.role}`,node.name&&(line+=` "${node.name}"`),line+="]";let annotations=[];if(node.value!==void 0&&annotations.push(`value="${node.value}"`),node.focused&&annotations.push("focused"),node.checked===!0&&annotations.push("checked"),node.checked==="mixed"&&annotations.push("mixed"),node.disabled&&annotations.push("disabled"),node.required&&annotations.push("required"),node.expanded===!0&&annotations.push("expanded"),node.expanded===!1&&annotations.push("collapsed"),node.selected&&annotations.push("selected"),node.level!==void 0&&annotations.push(`level=${node.level}`),node.description&&annotations.push(`desc="${node.description}"`),annotations.length>0&&(line+=` (${annotations.join(", ")})`),lines.push(line),node.children)for(let child of node.children)formatSnapshotNode(child,indent+1,lines)}function filterSnapshotTree(node,mode,visibleBackendNodeIds){if(!node)return null;if(mode==="full")return node;let keepSelf=mode==="interactive"?isInteractiveSnapshotNode(node):node.backendDOMNodeId!==void 0&&!!visibleBackendNodeIds?.has(node.backendDOMNodeId);if(mode==="interactive"&&keepSelf)return node;let children=(node.children??[]).map(child=>filterSnapshotTree(child,mode,visibleBackendNodeIds)).filter(child=>child!==null);return!keepSelf&&children.length===0?null:{...node,...children.length>0?{children}:{children:void 0}}}function snapshotNodeMatchesQuery(node,query){return query.role&&node.role!==query.role?!1:query.text===void 0?!0:query.exact??!0?node.name===query.text:node.name.includes(query.text)}function resolvePageSnapshotQuery(query){if(query===void 0)return;if(!query||typeof query!="object"||Array.isArray(query))throw new Error("page_snapshot: query must be an object");let{text,role,exact}=query;if(text!==void 0&&(typeof text!="string"||!text.trim()))throw new Error("page_snapshot: query.text must be a non-empty string");if(role!==void 0&&(typeof role!="string"||!role.trim()))throw new Error("page_snapshot: query.role must be a non-empty string");if(text===void 0&&role===void 0)throw new Error("page_snapshot: query must include text or role");if(exact!==void 0&&typeof exact!="boolean")throw new Error("page_snapshot: query.exact must be a boolean");return{...text!==void 0?{text}:{},...role!==void 0?{role}:{},...exact!==void 0?{exact}:{}}}function snapshotQueryMatch(node){return{...node.ref?{ref:node.ref}:{},role:node.role,name:node.name,...node.value!==void 0?{value:node.value}:{},...node.disabled?{disabled:!0}:{},...node.checked!==void 0?{checked:node.checked}:{},...node.selected?{selected:!0}:{},...node.expanded!==void 0?{expanded:node.expanded}:{}}}function compactSnapshotQueryField(value){if(value.length<=2048)return{value,truncated:!1};let marker="… [truncated] …",remaining=2048-marker.length,head=Math.ceil(remaining/2),tail=Math.floor(remaining/2);return{value:value.slice(0,head)+marker+value.slice(-tail),truncated:!0}}function compactSnapshotQueryMatch(match){let role=compactSnapshotQueryField(match.role),name=compactSnapshotQueryField(match.name),value=match.value===void 0?void 0:compactSnapshotQueryField(match.value);return{match:{...match,role:role.value,name:name.value,...value?{value:value.value}:{}},truncated:role.truncated||name.truncated||!!value?.truncated}}function limitPageSnapshotQueryMatches(matches){let limited=[],encoder=new TextEncoder,bytes=2,truncated=!1;for(let candidate of matches){if(limited.length>=100){truncated=!0;break}let compacted=compactSnapshotQueryMatch(candidate),candidateBytes=encoder.encode(JSON.stringify(compacted.match)).byteLength+(limited.length>0?1:0);if(bytes+candidateBytes>262144){truncated=!0;break}limited.push(compacted.match),bytes+=candidateBytes,truncated=truncated||compacted.truncated}return limited.length<matches.length&&(truncated=!0),{matches:limited,truncated}}function filterSnapshotTreeByQuery(node,query){if(!node)return{tree:null,matches:[]};let matches=[],children=[];for(let child of node.children??[]){let childResult=filterSnapshotTreeByQuery(child,query);matches.push(...childResult.matches),childResult.tree&&children.push(childResult.tree)}let matchesSelf=snapshotNodeMatchesQuery(node,query);return matchesSelf&&matches.unshift(snapshotQueryMatch(node)),!matchesSelf&&children.length===0?{tree:null,matches}:{tree:{...node,...children.length>0?{children}:{children:void 0}},matches}}function countSnapshotNodes(node){return node?1+(node.children??[]).reduce((total,child)=>total+countSnapshotNodes(child),0):0}function takeHeadTail(items,limit){let available=Math.max(0,Math.floor(limit)-1),tailCount=available>1?Math.max(1,Math.floor(available*.3)):0,headCount=Math.max(0,available-tailCount);return{items:[...items.slice(0,headCount),...items.slice(Math.max(headCount,items.length-tailCount))],headCount}}function formatSnapshotWithLimits(lines,limits={}){let maxNodes=limits.maxNodes===void 0||limits.maxNodes===0?1/0:Math.max(3,Math.floor(limits.maxNodes)),maxChars=limits.maxChars===void 0?6e4:limits.maxChars===0?1/0:Math.max(200,Math.floor(limits.maxChars)),outputLines=lines,truncated=!1;if(outputLines.length>maxNodes){let originalCount=outputLines.length,selected=takeHeadTail(outputLines,maxNodes);outputLines=[...selected.items.slice(0,selected.headCount),`... [snapshot nodes omitted: showing ${selected.items.length} of ${originalCount}; use rootSelector or mode:"viewport"]`,...selected.items.slice(selected.headCount)],truncated=!0}let snapshot=outputLines.join(`
|
|
59
|
+
`)}var PAGE_CLICK_HIDDEN_TOUCH_ERROR='page_click: clickMode "touch" requires a visible page, but the target is hidden or in a background tab. Use clickMode "auto" for DOM fallback, activate the tab, or use "mouse" when trusted touch is not required.';function resolvePageClickDispatchPolicy(clickMode,visibilityState,touchEmulationEnabled){return clickMode!==void 0&&clickMode!=="auto"?{clickMode,stateAwareControls:clickMode==="dom"}:visibilityState==="hidden"?{clickMode:"dom",stateAwareControls:!0,fallbackReason:"page-hidden"}:{clickMode:touchEmulationEnabled?"touch":"mouse",stateAwareControls:!0}}function createPageClickResult(requestedTarget,dispatchTarget){let normalizedDispatchTarget={tag:dispatchTarget.tag,text:dispatchTarget.text},resolvedTarget={tag:dispatchTarget.sourceTarget?.tag??normalizedDispatchTarget.tag,text:dispatchTarget.sourceTarget?.text??normalizedDispatchTarget.text,strategy:dispatchTarget.strategy??"self",distance:dispatchTarget.distance??0};return{clicked:!0,tag:normalizedDispatchTarget.tag,text:requestedTarget.name||normalizedDispatchTarget.text,requestedTarget,resolvedTarget,dispatchTarget:normalizedDispatchTarget,...dispatchTarget.hitTarget?{hitTarget:dispatchTarget.hitTarget}:{},...dispatchTarget.frame?{frame:dispatchTarget.frame}:{},...dispatchTarget.coordinates?{coordinates:dispatchTarget.coordinates}:{},...dispatchTarget.actionableAncestorCandidates?.length?{actionableAncestorCandidates:dispatchTarget.actionableAncestorCandidates}:{},...dispatchTarget.controlState?{controlState:dispatchTarget.controlState}:{},...dispatchTarget.dispatchMode?{dispatchMode:dispatchTarget.dispatchMode}:{},...dispatchTarget.pointerType?{pointerType:dispatchTarget.pointerType}:{}}}function clickElementViaJS(){let el=this.nodeType===3?this.parentElement:this;if(!el||!el.isConnected)return null;let sourceTarget={tag:el.tagName?el.tagName.toLowerCase():"",text:(el.textContent||"").trim().slice(0,100)};if(el.tagName==="OPTION"){let select=el.closest("select");if(select){let desc=Object.getOwnPropertyDescriptor(window.HTMLSelectElement.prototype,"value");desc&&desc.set?desc.set.call(select,el.value):select.value=el.value,select.dispatchEvent(new Event("input",{bubbles:!0})),select.dispatchEvent(new Event("change",{bubbles:!0}));let rect2=select.getBoundingClientRect();return{tag:"option",text:(el.textContent||"").trim().slice(0,100),cx:rect2.x+rect2.width/2,cy:rect2.y+rect2.height/2,strategy:"self",distance:0,sourceTarget}}}function isActionable(node){if(!node||node.nodeType!==1)return!1;if(/^(A|BUTTON|INPUT|SELECT|TEXTAREA|SUMMARY|DETAILS|LABEL)$/i.test(node.tagName)||/button|link|tab|menuitem|checkbox|radio|option|switch/i.test(node.getAttribute("role")||"")||node.isContentEditable||typeof node.onclick=="function")return!0;let tabIndexAttribute=node.getAttribute("tabindex");if(tabIndexAttribute===null)return!1;let tabIndex=Number(tabIndexAttribute);return Number.isFinite(tabIndex)&&tabIndex>=0}let target=el,strategy="self",distance=0;if(!isActionable(target)){let ancestor=target.parentElement;for(;ancestor&&ancestor!==document.body&&distance<6;){if(distance+=1,isActionable(ancestor)){target=ancestor,strategy="actionable-ancestor";break}ancestor=ancestor.parentElement}}if(strategy==="self"&&!isActionable(target)){let cursor=target,descendantDistance=0;for(;cursor.children.length===1;){let child=cursor.children[0];if(!child||child.nodeType!==1||!(child.textContent||"").trim())break;cursor=child,descendantDistance+=1}cursor!==target?(target=cursor,strategy="single-child-descendant",distance=descendantDistance):distance=0}let rect=target.getBoundingClientRect();(rect.top<0||rect.left<0||rect.bottom>window.innerHeight||rect.right>window.innerWidth)&&(target.scrollIntoView({block:"center",inline:"center",behavior:"instant"}),rect=target.getBoundingClientRect());let cx=rect.x+rect.width/2,cy=rect.y+rect.height/2;try{let touch=new Touch({identifier:Date.now(),target,clientX:cx,clientY:cy});target.dispatchEvent(new TouchEvent("touchstart",{touches:[touch],targetTouches:[touch],changedTouches:[touch],bubbles:!0,cancelable:!0})),target.dispatchEvent(new TouchEvent("touchend",{touches:[],targetTouches:[],changedTouches:[touch],bubbles:!0,cancelable:!0}))}catch{}let controlState,controlType=target.tagName==="INPUT"&&/^(checkbox|radio)$/i.test(target.type||"")?String(target.type).toLowerCase():"";if(controlType==="checkbox"||controlType==="radio"){let checkedBefore=!!target.checked;target.click(),controlState={type:controlType,checkedBefore,checkedAfter:!!target.checked}}else target.click();return{tag:target.tagName?target.tagName.toLowerCase():"",text:(target.textContent||"").trim().slice(0,100),cx,cy,strategy,distance,sourceTarget,...controlState?{controlState}:{}}}function getClickCoordsFromNode(){let el=this.nodeType===3?this.parentElement:this;if(!el||!el.isConnected||!el.getBoundingClientRect)return null;let sourceTarget={tag:el.tagName?el.tagName.toLowerCase():"",text:(el.textContent||"").trim().slice(0,100)};function isActionable(node){if(!node||node.nodeType!==1)return!1;if(/^(A|BUTTON|INPUT|SELECT|TEXTAREA|SUMMARY|DETAILS|LABEL)$/i.test(node.tagName)||/button|link|tab|menuitem|checkbox|radio|option|switch/i.test(node.getAttribute("role")||"")||node.isContentEditable||typeof node.onclick=="function")return!0;let tabIndexAttribute=node.getAttribute("tabindex");if(tabIndexAttribute===null)return!1;let tabIndex=Number(tabIndexAttribute);return Number.isFinite(tabIndex)&&tabIndex>=0}let target=el,strategy="self",distance=0;if(!isActionable(target)){let ancestor=target.parentElement;for(;ancestor&&ancestor!==document.body&&distance<6;){if(distance+=1,isActionable(ancestor)){target=ancestor,strategy="actionable-ancestor";break}ancestor=ancestor.parentElement}}if(strategy==="self"&&!isActionable(target)){let cursor=target,descendantDistance=0;for(;cursor.children.length===1;){let child=cursor.children[0];if(!child||child.nodeType!==1||!(child.textContent||"").trim())break;cursor=child,descendantDistance+=1}cursor!==target?(target=cursor,strategy="single-child-descendant",distance=descendantDistance):distance=0}let actionableAncestorCandidates=[];if(strategy==="self"&&!isActionable(target)){let sourceRect=el.getBoundingClientRect(),ancestor=el.parentElement,candidateDistance=0;for(;ancestor&&ancestor!==document.body&&candidateDistance<6;){candidateDistance+=1;let rect2=ancestor.getBoundingClientRect(),reason=getComputedStyle(ancestor).cursor==="pointer"?"cursor-pointer":rect2.width*rect2.height>sourceRect.width*sourceRect.height*1.5?"containing-block":null;if(reason){let escapeCss=value=>globalThis.CSS&&typeof globalThis.CSS.escape=="function"?globalThis.CSS.escape(value):value.replace(/[^a-zA-Z0-9_-]/g,character=>`\\${character}`),candidateSelector=ancestor.id?`#${escapeCss(ancestor.id)}`:"";if(!candidateSelector){let path19=[],cursor=ancestor;for(;cursor&&cursor!==document.documentElement&&path19.length<5;){let parent=cursor.parentElement,tag=cursor.tagName.toLowerCase();if(!parent){path19.unshift(tag);break}let siblings=Array.from(parent.children).filter(item=>item.tagName===cursor.tagName),index=siblings.indexOf(cursor)+1;path19.unshift(siblings.length>1?`${tag}:nth-of-type(${index})`:tag),cursor=parent}candidateSelector=path19.join(" > ")}candidateSelector&&actionableAncestorCandidates.push({selector:candidateSelector,tag:ancestor.tagName.toLowerCase(),text:(ancestor.textContent||"").trim().slice(0,100),distance:candidateDistance,reason})}if(actionableAncestorCandidates.length>=3)break;ancestor=ancestor.parentElement}}let rect=target.getBoundingClientRect();return(rect.top<0||rect.left<0||rect.bottom>window.innerHeight||rect.right>window.innerWidth)&&(target.scrollIntoView({block:"center",inline:"center",behavior:"instant"}),rect=target.getBoundingClientRect()),{x:rect.x+rect.width/2,y:rect.y+rect.height/2,tag:target.tagName?target.tagName.toLowerCase():"",text:(target.textContent||"").trim().slice(0,100),...target.tagName==="INPUT"?{inputType:String(target.type||"").toLowerCase()}:{},strategy,distance,sourceTarget,...actionableAncestorCandidates.length>0?{actionableAncestorCandidates}:{}}}function isPageDragPoint(value){if(!value||typeof value!="object")return!1;let point=value;return Number.isFinite(point.x)&&Number.isFinite(point.y)&&point.x>=0&&point.y>=0}function resolveEndpoint(value,name){if(typeof value=="string"&&value.trim().length>0)return value.trim();if(isPageDragPoint(value))return{x:value.x,y:value.y};throw new Error(`page_drag: "${name}" must be a non-empty CSS/@ref selector or { x, y } viewport point.`)}function resolvePageDragInput(data){if(!data||typeof data!="object")throw new Error("page_drag: payload is required");if(data.dragMode!==void 0&&!["auto","dom","mouse","touch"].includes(data.dragMode))throw new Error('page_drag: "dragMode" must be one of auto, dom, mouse, touch');let durationMs=data.durationMs??400;if(!Number.isFinite(durationMs)||durationMs<0||durationMs>5e3)throw new Error('page_drag: "durationMs" must be between 0 and 5000.');return{from:resolveEndpoint(data.from,"from"),to:resolveEndpoint(data.to,"to"),dragMode:data.dragMode??"auto",durationMs:Math.round(durationMs)}}function resolvePageDragDispatchPolicy(dragMode,visibilityState,touchEmulationEnabled){let requestedMode=dragMode??"auto",pointerType=requestedMode==="mouse"||requestedMode==="touch"?requestedMode:touchEmulationEnabled?"touch":"mouse";return requestedMode==="dom"?{dispatchMode:"dom",pointerType}:requestedMode==="auto"&&visibilityState==="hidden"?{dispatchMode:"dom",pointerType,fallbackReason:"page-hidden"}:{dispatchMode:"trusted-input",pointerType}}function buildPageDragPath(from,to,durationMs){let steps=Math.max(2,Math.min(60,Math.ceil(durationMs/25)));return{points:Array.from({length:steps},(_,index)=>{let ratio=(index+1)/steps;return{x:from.x+(to.x-from.x)*ratio,y:from.y+(to.y-from.y)*ratio}}),intervalMs:durationMs/steps}}function dragBetweenPointsInPage(from,points,pointerType){let target=document.elementFromPoint(from.x,from.y);if(!target)return{dragged:!1,steps:0,error:`No element found at drag start point (${from.x}, ${from.y})`};if(points.length===0)return{dragged:!1,steps:0,error:"Drag path must contain at least one point"};let view=target.ownerDocument.defaultView??window,realm=view,pointerId=1,pointerInit=(point,buttons,pressure)=>({bubbles:!0,cancelable:!0,composed:!0,view,clientX:point.x,clientY:point.y,screenX:point.x,screenY:point.y,button:0,buttons,pointerId,pointerType,isPrimary:!0,pressure,width:1,height:1}),dispatchPointer=(type,point,buttons,pressure)=>typeof realm.PointerEvent!="function"?!1:(target.dispatchEvent(new realm.PointerEvent(type,pointerInit(point,buttons,pressure))),!0),dispatchMouse=(type,point,buttons)=>typeof realm.MouseEvent!="function"?!1:(target.dispatchEvent(new realm.MouseEvent(type,{bubbles:!0,cancelable:!0,composed:!0,view,clientX:point.x,clientY:point.y,screenX:point.x,screenY:point.y,button:0,buttons})),!0),createTouch=point=>{let init={identifier:pointerId,target,clientX:point.x,clientY:point.y,screenX:point.x,screenY:point.y,pageX:point.x+view.scrollX,pageY:point.y+view.scrollY,radiusX:1,radiusY:1,rotationAngle:0,force:.5};return typeof realm.Touch=="function"?new realm.Touch(init):init},dispatchTouch=(type,point)=>{if(typeof realm.TouchEvent!="function")return!1;let touch=createTouch(point),activeTouches=type==="touchend"?[]:[touch];return target.dispatchEvent(new realm.TouchEvent(type,{bubbles:!0,cancelable:!0,composed:!0,touches:activeTouches,targetTouches:activeTouches,changedTouches:[touch]})),!0},dispatched=dispatchPointer("pointerdown",from,1,.5);dispatched=pointerType==="touch"?dispatchTouch("touchstart",from)||dispatched:dispatchMouse("mousedown",from,1)||dispatched;for(let point of points)dispatched=dispatchPointer("pointermove",point,1,.5)||dispatched,dispatched=pointerType==="touch"?dispatchTouch("touchmove",point)||dispatched:dispatchMouse("mousemove",point,1)||dispatched;let end=points[points.length-1];return dispatched=pointerType==="touch"?dispatchTouch("touchend",end)||dispatched:dispatchMouse("mouseup",end,0)||dispatched,dispatched=dispatchPointer("pointerup",end,0,0)||dispatched,dispatched?{dragged:!0,steps:points.length}:{dragged:!1,steps:0,error:"This page does not support synthetic drag events"}}var DRAG_BETWEEN_POINTS_IN_PAGE_SOURCE=dragBetweenPointsInPage.toString();function buildPageDragDomExpression(from,points,pointerType){return`(${DRAG_BETWEEN_POINTS_IN_PAGE_SOURCE})(${JSON.stringify(from)}, ${JSON.stringify(points)}, ${JSON.stringify(pointerType)})`}function unwrapPageDragDomResult(result){if(!result)throw new Error("page_drag: DOM simulation returned no result");if(!result.dragged)throw new Error(`page_drag: ${result.error}`);return result}function getDragCoordsFromNode(){let el=this.nodeType===Node.TEXT_NODE?this.parentElement:this;if(!el||typeof el.getBoundingClientRect!="function")return null;let rect=el.getBoundingClientRect(),viewportWidth=window.visualViewport?.width??window.innerWidth,viewportHeight=window.visualViewport?.height??window.innerHeight;if(rect.width<=0||rect.height<=0)return{x:0,y:0,tag:"",text:"",error:"Element has no visible bounds"};if(rect.right<=0||rect.bottom<=0||rect.left>=viewportWidth||rect.top>=viewportHeight)return{x:0,y:0,tag:"",text:"",error:"Element is outside the current viewport; scroll it into view before dragging"};let x=Math.min(Math.max(rect.left+rect.width/2,0),Math.max(viewportWidth-1,0)),y=Math.min(Math.max(rect.top+rect.height/2,0),Math.max(viewportHeight-1,0));return{x,y,tag:el.tagName?.toLowerCase()??"",text:(el.textContent??"").trim().slice(0,100)}}var SKIP_ROLES=new Set(["none","generic","InlineTextBox","LineBreak","paragraph","Section","LabelText"]),ALWAYS_SKIP_ROLES=new Set(["InlineTextBox","LineBreak","graphics-symbol","graphics-document"]),INTERACTIVE_ROLES=new Set(["button","checkbox","combobox","gridcell","link","listbox","menuitem","menuitemcheckbox","menuitemradio","option","radio","scrollbar","searchbox","slider","spinbutton","switch","tab","textbox","treeitem"]);function isInteractiveSnapshotNode(node){let focusedControl=!!node.focused&&node.role!=="RootWebArea"&&node.role!=="WebArea";return INTERACTIVE_ROLES.has(node.role)||focusedControl||node.checked!==void 0||node.expanded!==void 0||!!node.selected}function hasInteractiveSnapshotNode(node){return node?isInteractiveSnapshotNode(node)?!0:(node.children??[]).some(hasInteractiveSnapshotNode):!1}var CHECKABLE_AX_ROLES=new Set(["checkbox","menuitemcheckbox","menuitemradio","radio","switch"]);function resolveDOMSnapshotViewportBounds(metrics){let viewport=metrics.visualViewport??metrics.cssVisualViewport;return normalizePageViewportBounds({left:viewport?.pageX??0,top:viewport?.pageY??0,width:viewport?.clientWidth,height:viewport?.clientHeight})}function normalizePageViewportBounds(value){if(!value||typeof value!="object")return null;let{left,top,width,height}=value;return typeof left!="number"||typeof top!="number"||typeof width!="number"||typeof height!="number"||!Number.isFinite(left)||!Number.isFinite(top)||!Number.isFinite(width)||!Number.isFinite(height)||width<=0||height<=0?null:{left,top,width,height}}function readDOMCheckedState(){let tag=String(this&&this.tagName||"").toLowerCase(),type=String(this&&this.type||"").toLowerCase();if(tag==="input"&&(type==="checkbox"||type==="radio"))return!!this.checked;let ariaChecked=this&&this.getAttribute&&this.getAttribute("aria-checked");if(ariaChecked==="mixed")return"mixed";if(ariaChecked==="true")return!0;if(ariaChecked==="false")return!1}async function reconcileAXCheckedStates(nodes,readCheckedState){let candidates=nodes.filter(node=>node.backendDOMNodeId!==void 0&&CHECKABLE_AX_ROLES.has(node.role?.value??"")),nextIndex=0,workers=Array.from({length:Math.min(8,candidates.length)},async()=>{for(;nextIndex<candidates.length;){let node=candidates[nextIndex++];if(!(!node||node.backendDOMNodeId===void 0))try{let checked=await readCheckedState(node.backendDOMNodeId);if(checked===void 0)continue;let properties=node.properties??=[],existing=properties.find(property=>property.name==="checked");existing?existing.value.value=checked:properties.push({name:"checked",value:{value:checked}})}catch{}}});await Promise.all(workers)}function extractAXProperties(node){let result={};if(!node.properties)return result;for(let prop of node.properties)switch(prop.name){case"focused":prop.value.value===!0&&(result.focused=!0);break;case"checked":result.checked=prop.value.value==="mixed"?"mixed":prop.value.value===!0;break;case"disabled":prop.value.value===!0&&(result.disabled=!0);break;case"required":prop.value.value===!0&&(result.required=!0);break;case"expanded":result.expanded=prop.value.value===!0;break;case"selected":prop.value.value===!0&&(result.selected=!0);break;case"level":result.level=prop.value.value;break}return result}function formatSnapshotNode(node,indent,lines){let line=" ".repeat(indent);node.ref&&(line+=`${node.ref} `),line+=`[${node.role}`,node.name&&(line+=` "${node.name}"`),line+="]";let annotations=[];if(node.value!==void 0&&annotations.push(`value="${node.value}"`),node.focused&&annotations.push("focused"),node.checked===!0&&annotations.push("checked"),node.checked==="mixed"&&annotations.push("mixed"),node.disabled&&annotations.push("disabled"),node.required&&annotations.push("required"),node.expanded===!0&&annotations.push("expanded"),node.expanded===!1&&annotations.push("collapsed"),node.selected&&annotations.push("selected"),node.level!==void 0&&annotations.push(`level=${node.level}`),node.description&&annotations.push(`desc="${node.description}"`),annotations.length>0&&(line+=` (${annotations.join(", ")})`),lines.push(line),node.children)for(let child of node.children)formatSnapshotNode(child,indent+1,lines)}function filterSnapshotTree(node,mode,visibleBackendNodeIds){if(!node)return null;if(mode==="full")return node;let keepSelf=mode==="interactive"?isInteractiveSnapshotNode(node):node.backendDOMNodeId!==void 0&&!!visibleBackendNodeIds?.has(node.backendDOMNodeId);if(mode==="interactive"&&keepSelf)return node;let children=(node.children??[]).map(child=>filterSnapshotTree(child,mode,visibleBackendNodeIds)).filter(child=>child!==null);return!keepSelf&&children.length===0?null:{...node,...children.length>0?{children}:{children:void 0}}}function snapshotNodeMatchesQuery(node,query){return query.role&&node.role!==query.role?!1:query.text===void 0?!0:query.exact??!0?node.name===query.text:node.name.includes(query.text)}function resolvePageSnapshotQuery(query){if(query===void 0)return;if(!query||typeof query!="object"||Array.isArray(query))throw new Error("page_snapshot: query must be an object");let{text,role,exact}=query;if(text!==void 0&&(typeof text!="string"||!text.trim()))throw new Error("page_snapshot: query.text must be a non-empty string");if(role!==void 0&&(typeof role!="string"||!role.trim()))throw new Error("page_snapshot: query.role must be a non-empty string");if(text===void 0&&role===void 0)throw new Error("page_snapshot: query must include text or role");if(exact!==void 0&&typeof exact!="boolean")throw new Error("page_snapshot: query.exact must be a boolean");return{...text!==void 0?{text}:{},...role!==void 0?{role}:{},...exact!==void 0?{exact}:{}}}function snapshotQueryMatch(node){return{...node.ref?{ref:node.ref}:{},role:node.role,name:node.name,...node.value!==void 0?{value:node.value}:{},...node.disabled?{disabled:!0}:{},...node.checked!==void 0?{checked:node.checked}:{},...node.selected?{selected:!0}:{},...node.expanded!==void 0?{expanded:node.expanded}:{}}}function compactSnapshotQueryField(value){if(value.length<=2048)return{value,truncated:!1};let marker="… [truncated] …",remaining=2048-marker.length,head=Math.ceil(remaining/2),tail=Math.floor(remaining/2);return{value:value.slice(0,head)+marker+value.slice(-tail),truncated:!0}}function compactSnapshotQueryMatch(match){let role=compactSnapshotQueryField(match.role),name=compactSnapshotQueryField(match.name),value=match.value===void 0?void 0:compactSnapshotQueryField(match.value);return{match:{...match,role:role.value,name:name.value,...value?{value:value.value}:{}},truncated:role.truncated||name.truncated||!!value?.truncated}}function limitPageSnapshotQueryMatches(matches){let limited=[],encoder=new TextEncoder,bytes=2,truncated=!1;for(let candidate of matches){if(limited.length>=100){truncated=!0;break}let compacted=compactSnapshotQueryMatch(candidate),candidateBytes=encoder.encode(JSON.stringify(compacted.match)).byteLength+(limited.length>0?1:0);if(bytes+candidateBytes>262144){truncated=!0;break}limited.push(compacted.match),bytes+=candidateBytes,truncated=truncated||compacted.truncated}return limited.length<matches.length&&(truncated=!0),{matches:limited,truncated}}function filterSnapshotTreeByQuery(node,query){if(!node)return{tree:null,matches:[]};let matches=[],children=[];for(let child of node.children??[]){let childResult=filterSnapshotTreeByQuery(child,query);matches.push(...childResult.matches),childResult.tree&&children.push(childResult.tree)}let matchesSelf=snapshotNodeMatchesQuery(node,query);return matchesSelf&&matches.unshift(snapshotQueryMatch(node)),!matchesSelf&&children.length===0?{tree:null,matches}:{tree:{...node,...children.length>0?{children}:{children:void 0}},matches}}function countSnapshotNodes(node){return node?1+(node.children??[]).reduce((total,child)=>total+countSnapshotNodes(child),0):0}function takeHeadTail(items,limit){let available=Math.max(0,Math.floor(limit)-1),tailCount=available>1?Math.max(1,Math.floor(available*.3)):0,headCount=Math.max(0,available-tailCount);return{items:[...items.slice(0,headCount),...items.slice(Math.max(headCount,items.length-tailCount))],headCount}}function formatSnapshotWithLimits(lines,limits={}){let maxNodes=limits.maxNodes===void 0||limits.maxNodes===0?1/0:Math.max(3,Math.floor(limits.maxNodes)),maxChars=limits.maxChars===void 0?6e4:limits.maxChars===0?1/0:Math.max(200,Math.floor(limits.maxChars)),outputLines=lines,truncated=!1;if(outputLines.length>maxNodes){let originalCount=outputLines.length,selected=takeHeadTail(outputLines,maxNodes);outputLines=[...selected.items.slice(0,selected.headCount),`... [snapshot nodes omitted: showing ${selected.items.length} of ${originalCount}; use rootSelector or mode:"viewport"]`,...selected.items.slice(selected.headCount)],truncated=!0}let snapshot=outputLines.join(`
|
|
60
60
|
`);if(snapshot.length>maxChars){let originalLength=snapshot.length,marker=`
|
|
61
61
|
... [snapshot content omitted: showing at most ${maxChars} of ${originalLength} chars; use rootSelector, mode:"viewport", or maxChars:0]
|
|
62
62
|
`,usable=Math.max(0,maxChars-marker.length),headBudget=Math.ceil(usable*.7),tailBudget=Math.max(0,usable-headBudget),headCut=snapshot.lastIndexOf(`
|
|
@@ -76,7 +76,7 @@ ${truncated}...`}function extractFields(data,fields){if(fields.length>100)throw
|
|
|
76
76
|
${BASE_ICON}
|
|
77
77
|
${SOURCE_BADGES[source]}
|
|
78
78
|
</svg>`;return`data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`}var enabledDomains=new WeakMap;function ensureCdpDomain(client2,domain2,params={}){let domains=enabledDomains.get(client2);domains||(domains=new Map,enabledDomains.set(client2,domains));let existing=domains.get(domain2);if(existing)return existing;let enabling=client2.sendCommand(`${domain2}.enable`,params).then(()=>{}).catch(error48=>{throw domains?.get(domain2)===enabling&&domains.delete(domain2),error48});return domains.set(domain2,enabling),enabling}var MAX_LOGS=500,MAX_EVENTS=500,COLLECTED_RESOURCE_TYPES=new Set(["xhr","fetch","document","eventsource"]);function createBuffers(tabId=0){return{requests:[],logs:[],events:[],pending:new Map,sseStreams:new Map,requestCounter:0,requestBufferAccounting:createRequestBufferAccounting(),capture:{tabId,generation:createCaptureGeneration(),currentSequence:0,droppedRequestsThroughSequence:0,droppedLogsThroughSequence:0,droppedEventsThroughSequence:0}}}function parseQueryString2(url2){try{let u=new URL(url2),result=[];return u.searchParams.forEach((value,name)=>result.push({name,value})),result}catch{return[]}}function headersObjToArray(obj){return Object.entries(obj).map(([name,value])=>({name,value:String(value)}))}function getHeaderValue(headers,targetName){let target=targetName.toLowerCase(),entry=Object.entries(headers).find(([name])=>name.toLowerCase()===target);return entry?String(entry[1]):""}function extractMtopApiName(url2,postData){try{let u=new URL(url2),pathMatch=u.pathname.match(/\/h5\/([\w.]+)\//);if(pathMatch)return pathMatch[1];let proxyMatch=u.searchParams.get("requestUrl")?.match(/\b(?:mtop|mopen)\.[\w.]+/);if(proxyMatch)return proxyMatch[0]}catch{}let urlMatch=url2.match(/\b(?:mtop|mopen)\.[\w.]+/);if(urlMatch)return urlMatch[0];if(!postData)return null;try{let parsed=JSON.parse(postData),proxyMatch=(typeof parsed?.requestUrl=="string"?parsed.requestUrl:void 0)?.match(/\b(?:mtop|mopen)\.[\w.]+/);if(proxyMatch)return proxyMatch[0]}catch{let proxyMatch=new URLSearchParams(postData).get("requestUrl")?.match(/\b(?:mtop|mopen)\.[\w.]+/);if(proxyMatch)return proxyMatch[0]}return null}function requestDisplayName(url2){try{return new URL(url2).pathname}catch{return url2}}function parsePostData(postData){if(!postData)return null;try{return JSON.parse(postData)}catch{try{let params={};return new URLSearchParams(postData).forEach((v,k)=>params[k]=v),params}catch{return postData}}}function appendTrackingEvents(buffers,url2,postData,batchSequence,captureSequence){let events=parseTrackingRequest(url2,postData,{sequence:batchSequence,now:Date.now()}).map(event=>({...event,captureSequence}));if(events.length===0)return!1;let removed=appendCapturedTrackingBatch(buffers.events,events,MAX_EVENTS);for(let event of removed)event.captureSequence!==void 0&&(buffers.capture.droppedEventsThroughSequence=Math.max(buffers.capture.droppedEventsThroughSequence,event.captureSequence));return!0}function recordDroppedRequests(buffers,removed){for(let request of removed)request.captureSequence!==void 0&&(buffers.capture.droppedRequestsThroughSequence=Math.max(buffers.capture.droppedRequestsThroughSequence,request.captureSequence))}function appendCapturedRequest(buffers,request){recordDroppedRequests(buffers,appendRequestToBuffer(buffers.requests,buffers.requestBufferAccounting,request))}function refreshCapturedRequest(buffers,request){recordDroppedRequests(buffers,refreshRequestInBuffer(buffers.requests,buffers.requestBufferAccounting,request))}function recordCdpMtopStreamStart(buffers,data){let capture=createMtopStreamCapture({...data,id:++buffers.requestCounter,tabId:buffers.capture.tabId,captureSequence:nextCaptureSequence(buffers.capture)});return appendCapturedRequest(buffers,capture.request),capture}function recordCdpMtopStreamResponse(buffers,capture,response){updateMtopStreamCaptureResponse(capture,response),refreshCapturedRequest(buffers,capture.request)}function recordCdpMtopStreamChunk(buffers,capture,data,timestampMs2=Date.now()){appendMtopStreamCaptureChunk(capture,data,timestampMs2)&&refreshCapturedRequest(buffers,capture.request)}function recordCdpMtopStreamEnd(buffers,capture,options={}){finishMtopStreamCapture(capture,options),refreshCapturedRequest(buffers,capture.request)}function requestEventTimestamp(partial2,monotonicTimestamp){return monotonicTimestamp!==void 0&&partial2.startTs!==void 0?Math.round(partial2.timestampMs+(monotonicTimestamp-partial2.startTs)*1e3):Date.now()}function ensurePageSseStream(buffers,partial2,mode){partial2.isSSE=!0,Array.isArray(partial2.responseBody)||(partial2.responseBody=[]);let existing=buffers.sseStreams.get(partial2.requestId);if(existing)return existing;let stream={parser:createSseEventParser(),decoder:new TextDecoder2,mode};return buffers.sseStreams.set(partial2.requestId,stream),stream}function appendPageSseEvents(buffers,partial2,stream,events,timestampMs2){if(Array.isArray(partial2.responseBody)){for(let event of events)partial2.responseBody.push({event:event.event,data:event.data,...event.eventId!==void 0?{eventId:event.eventId}:{},timestamp:timestampMs2,duration:stream.lastMessageTimeMs===void 0?0:timestampMs2-stream.lastMessageTimeMs}),stream.lastMessageTimeMs=timestampMs2;events.length>0&&refreshCapturedRequest(buffers,partial2)}}function consumePageSseBytes(buffers,partial2,stream,bytes,timestampMs2){let text=stream.decoder.decode(bytes,{stream:!0});appendPageSseEvents(buffers,partial2,stream,stream.parser.push(text),timestampMs2)}function finishPageSseStream(buffers,partial2,stream,timestampMs2){let tail=stream.decoder.decode(),events=[...stream.parser.push(tail),...stream.parser.finish()];appendPageSseEvents(buffers,partial2,stream,events,timestampMs2)}function replaceWithParsedSseBody(partial2,body,timestampMs2){let parser=createSseEventParser();partial2.responseBody=[...parser.push(body),...parser.finish()].map(event=>({event:event.event,data:event.data,...event.eventId!==void 0?{eventId:event.eventId}:{},timestamp:timestampMs2,duration:0}))}function appendCapturedLog(buffers,log2){if(buffers.logs.push({...log2,captureSequence:nextCaptureSequence(buffers.capture)}),buffers.logs.length>MAX_LOGS){let removed=buffers.logs.shift();removed&&(buffers.capture.droppedLogsThroughSequence=removed.captureSequence)}}async function setupBufferListeners(client2,buffers){client2.on("Network.requestWillBeSent",params=>{let url2=params.request?.url??"";if(!url2.startsWith("http"))return;if(isTrackingUrl(url2)){let batchSequence=++buffers.requestCounter,captureSequence2=nextCaptureSequence(buffers.capture);!appendTrackingEvents(buffers,url2,params.request?.postData,batchSequence,captureSequence2)&¶ms.request?.hasPostData&&!params.request?.postData&&client2.sendCommand("Network.getRequestPostData",{requestId:params.requestId},1e4).then(result=>appendTrackingEvents(buffers,url2,result?.postData,batchSequence,captureSequence2)).catch(()=>{});return}let resourceType=String(params.type??"").toLowerCase(),mtopApiName=extractMtopApiName(url2,params.request?.postData),isMtop=mtopApiName!==null;if(!isMtop&&!COLLECTED_RESOURCE_TYPES.has(resourceType))return;let ts=params.timestamp,timestampMs2=params.wallTime!==void 0?Math.floor(params.wallTime*1e3):Date.now(),redirected=buffers.pending.get(params.requestId);redirected&¶ms.redirectResponse&&(redirected.status=params.redirectResponse.status??0,redirected.statusText=params.redirectResponse.statusText??"",redirected.duration=ts!==void 0&&redirected.startTs!==void 0?Math.round((ts-redirected.startTs)*1e3):void 0,redirected.isPending=!1,refreshCapturedRequest(buffers,redirected),buffers.pending.delete(params.requestId),buffers.sseStreams.delete(params.requestId));let id=++buffers.requestCounter,captureSequence=nextCaptureSequence(buffers.capture),partial2={id,requestId:params.requestId,timestamp:new Date(timestampMs2).toISOString(),timestampMs:timestampMs2,method:params.request?.method??"GET",url:url2,apiName:mtopApiName??requestDisplayName(url2),headers:headersObjToArray(params.request?.headers??{}),postData:parsePostData(params.request?.postData),queryString:parseQueryString2(url2),status:0,statusText:"",responseHeaders:[],responseBody:resourceType==="eventsource"?[]:null,isProxy:!1,proxyRequestUrl:null,proxyData:null,startTs:ts,captureSequence,isPending:!0,isSSE:resourceType==="eventsource",source:isMtop?"mtop":"requests",resourceType};buffers.pending.set(params.requestId,partial2),appendCapturedRequest(buffers,partial2)}),client2.on("Network.responseReceived",params=>{let partial2=buffers.pending.get(params.requestId);if(!partial2)return;partial2.status=params.response?.status??0,partial2.statusText=params.response?.statusText??"",partial2.responseHeaders=headersObjToArray(params.response?.headers??{});let contentType=getHeaderValue(params.response?.headers??{},"content-type");if(partial2.resourceType==="eventsource"||contentType.toLowerCase().includes("text/event-stream")){let mode=partial2.resourceType==="eventsource"?"eventsource":"resource",stream=ensurePageSseStream(buffers,partial2,mode);mode==="resource"&&client2.sendCommand("Network.streamResourceContent",{requestId:params.requestId},1e4).then(result=>{buffers.sseStreams.get(params.requestId)===stream&&typeof result?.bufferedData=="string"&&result.bufferedData&&consumePageSseBytes(buffers,partial2,stream,Buffer.from(result.bufferedData,"base64"),requestEventTimestamp(partial2,params.timestamp))}).catch(()=>{buffers.sseStreams.get(params.requestId)===stream&&(stream.mode="fallback")})}refreshCapturedRequest(buffers,partial2)}),client2.on("Network.dataReceived",params=>{let partial2=buffers.pending.get(params.requestId),stream=buffers.sseStreams.get(params.requestId);!partial2||stream?.mode!=="resource"||typeof params.data!="string"||consumePageSseBytes(buffers,partial2,stream,Buffer.from(params.data,"base64"),requestEventTimestamp(partial2,params.timestamp))}),client2.on("Network.eventSourceMessageReceived",params=>{let partial2=buffers.pending.get(params.requestId);if(!partial2)return;let stream=ensurePageSseStream(buffers,partial2,"eventsource");appendPageSseEvents(buffers,partial2,stream,[{event:typeof params.eventName=="string"&¶ms.eventName?params.eventName:"message",data:parseSseDataValue(String(params.data??"")),...typeof params.eventId=="string"&¶ms.eventId?{eventId:params.eventId}:{}}],requestEventTimestamp(partial2,params.timestamp))}),client2.on("Network.loadingFinished",params=>{let partial2=buffers.pending.get(params.requestId);if(!partial2)return;buffers.pending.delete(params.requestId);let endTs=params.timestamp,duration3=endTs!==void 0&&partial2.startTs!==void 0?Math.round((endTs-partial2.startTs)*1e3):void 0,stream=buffers.sseStreams.get(params.requestId);stream?.mode==="resource"&&finishPageSseStream(buffers,partial2,stream,requestEventTimestamp(partial2,params.timestamp)),buffers.sseStreams.delete(params.requestId),partial2.duration=duration3,partial2.isPending=!1,refreshCapturedRequest(buffers,partial2),!(partial2.isSSE&&Array.isArray(partial2.responseBody)&&partial2.responseBody.length>0)&&client2.sendCommand("Network.getResponseBody",{requestId:params.requestId},1e4).then(result=>{let responseBody=result.base64Encoded?Buffer.from(result.body,"base64").toString("utf-8"):result.body;if(partial2.isSSE&&typeof responseBody=="string"){replaceWithParsedSseBody(partial2,responseBody,requestEventTimestamp(partial2,params.timestamp)),refreshCapturedRequest(buffers,partial2);return}if(partial2.responseBody=responseBody,typeof partial2.responseBody=="string")try{partial2.responseBody=JSON.parse(partial2.responseBody)}catch{}refreshCapturedRequest(buffers,partial2)}).catch(()=>{})}),client2.on("Network.loadingFailed",params=>{let partial2=buffers.pending.get(params.requestId);partial2&&(buffers.pending.delete(params.requestId),buffers.sseStreams.delete(params.requestId),partial2.status=0,partial2.statusText=params.errorText??"Failed",partial2.duration=params.timestamp!==void 0&&partial2.startTs!==void 0?Math.round((params.timestamp-partial2.startTs)*1e3):void 0,partial2.isPending=!1,partial2.isSSE&&Array.isArray(partial2.responseBody)&&partial2.responseBody.length===0&&(partial2.responseBody={error:partial2.statusText}),refreshCapturedRequest(buffers,partial2))}),client2.on("Runtime.consoleAPICalled",params=>{let level={warning:"warn",debug:"debug",info:"info",error:"error",assert:"error"}[params.type]??"log",args=(params.args??[]).map(arg=>arg.type==="string"?arg.value:arg.value!==void 0?String(arg.value):arg.description!==void 0?arg.description:JSON.stringify(arg));appendCapturedLog(buffers,{level,message:args.join(" "),timestampMs:params.timestamp??Date.now(),source:params.stackTrace?.callFrames?.[0]?.url?`${params.stackTrace.callFrames[0].url.split("/").pop()||params.stackTrace.callFrames[0].url}:${params.stackTrace.callFrames[0].lineNumber+1}`:"console",args,origin:"console"})}),client2.on("Runtime.exceptionThrown",params=>{let details=params.exceptionDetails??{},exception=details.exception,message=exception?.description??(exception?.value!==void 0?String(exception.value):void 0)??details.text??"Uncaught exception",topFrame=details.stackTrace?.callFrames?.[0],url2=topFrame?.url||details.url,lineNumber=topFrame?.lineNumber??details.lineNumber,source=url2?`${url2.split("/").pop()||url2}${lineNumber!==void 0?`:${lineNumber+1}`:""}`:void 0;appendCapturedLog(buffers,{level:"error",message,timestampMs:params.timestamp??Date.now(),...source?{source}:{},args:[message],origin:"exception"})}),client2.on("Log.entryAdded",params=>{let entry=params.entry??{},levelMap={verbose:"log",info:"info",warning:"warn",error:"error"},args=(entry.args??[]).map(arg=>arg.value!==void 0?String(arg.value):arg.description??`[${arg.type||"Object"}]`),message=entry.text||args.join(" ");appendCapturedLog(buffers,{level:levelMap[entry.level]??entry.level??"log",message,timestampMs:entry.timestamp??Date.now(),source:entry.url?`${entry.url.split("/").pop()||entry.url}${entry.lineNumber!==void 0?`:${entry.lineNumber+1}`:""}`:entry.source??"other",args:args.length>0?args:[message],origin:"browser"})}),await Promise.all([ensureCdpDomain(client2,"Network",{maxTotalBufferSize:10*1024*1024,maxPostDataSize:5*1024*1024}),ensureCdpDomain(client2,"Runtime"),ensureCdpDomain(client2,"Log")])}import fs from"node:fs";import http from"node:http";import os from"node:os";import path from"node:path";function chromeUserDataDir(){let platform=process.platform,home=os.homedir();return platform==="darwin"?path.join(home,"Library","Application Support","Google","Chrome"):platform==="win32"?path.join(process.env.LOCALAPPDATA??home,"Google","Chrome","User Data"):path.join(home,".config","google-chrome")}function readDevToolsActivePort(userDataDir=chromeUserDataDir()){try{let filePath=path.join(userDataDir,"DevToolsActivePort"),lines=fs.readFileSync(filePath,"utf8").trim().split(`
|
|
79
|
-
`).map(l=>l.trim()),port=parseInt(lines[0],10),browserWsPath=lines[1]??"/devtools/browser";return isNaN(port)?null:{port,browserWsPath}}catch{return null}}async function discoverTargets(port=9222){return new Promise((resolve2,reject)=>{let req=http.get(`http://localhost:${port}/json`,res=>{let data="";res.on("data",chunk=>data+=chunk),res.on("end",()=>{try{resolve2(JSON.parse(data))}catch(e){reject(new Error(`Failed to parse CDP targets: ${e}`))}})});req.on("error",reject),req.setTimeout(3e3,()=>{req.destroy(),reject(new Error("CDP discover timeout"))})})}var CdpSession=class{port;userDataDir;endpointUrl;endpointResolver;browserClient=null;browserClientPromise=null;pageSessions=new Map;tabIdMap=new Map;nextTabId=1e3;constructor(options=9222){if(typeof options=="number"){this.port=options;return}this.port=options.port??9222,this.userDataDir=options.userDataDir,this.endpointUrl=options.endpointUrl,this.endpointResolver=options.endpointResolver}async getBrowserClient(){if(this.browserClient&&!this.browserClient.closed)return this.browserClient;this.browserClientPromise||(this.browserClientPromise=this.connectBrowserClient());let pending=this.browserClientPromise;try{return await pending}finally{this.browserClientPromise===pending&&(this.browserClientPromise=null)}}async getPageSession(virtualTabId){let targetId;if(virtualTabId!==void 0&&(targetId=this.tabIdMap.get(virtualTabId),!targetId))throw new Error(`Tab ${virtualTabId} not found. Open a tab first with tab_open.`);if(targetId){let existing2=this.pageSessions.get(targetId);if(existing2&&!existing2.client.closed)return existing2}let target=targetId?await this.findTargetById(targetId):await this.findDefaultPageTarget();if(!target)throw new Error(virtualTabId?`CDP target for tab ${virtualTabId} is no longer available`:"No
|
|
79
|
+
`).map(l=>l.trim()),port=parseInt(lines[0],10),browserWsPath=lines[1]??"/devtools/browser";return isNaN(port)?null:{port,browserWsPath}}catch{return null}}async function discoverTargets(port=9222){return new Promise((resolve2,reject)=>{let req=http.get(`http://localhost:${port}/json`,res=>{let data="";res.on("data",chunk=>data+=chunk),res.on("end",()=>{try{resolve2(JSON.parse(data))}catch(e){reject(new Error(`Failed to parse CDP targets: ${e}`))}})});req.on("error",reject),req.setTimeout(3e3,()=>{req.destroy(),reject(new Error("CDP discover timeout"))})})}var initializers=[];function registerPageSessionInitializer(initializer3){initializers.push(initializer3)}async function initializePageSession(session){for(let initializer3 of initializers)await initializer3(session)}function isImplicitlySelectablePageUrl(url2){return!url2.startsWith("chrome-extension://")&&!url2.startsWith("about:")&&!url2.startsWith("chrome://")}var CdpSession=class{port;userDataDir;endpointUrl;endpointResolver;browserClient=null;browserClientPromise=null;pageSessions=new Map;tabIdMap=new Map;nextTabId=1e3;constructor(options=9222){if(typeof options=="number"){this.port=options;return}this.port=options.port??9222,this.userDataDir=options.userDataDir,this.endpointUrl=options.endpointUrl,this.endpointResolver=options.endpointResolver}async getBrowserClient(){if(this.browserClient&&!this.browserClient.closed)return this.browserClient;this.browserClientPromise||(this.browserClientPromise=this.connectBrowserClient());let pending=this.browserClientPromise;try{return await pending}finally{this.browserClientPromise===pending&&(this.browserClientPromise=null)}}async getPageSession(virtualTabId){let targetId;if(virtualTabId!==void 0&&(targetId=this.tabIdMap.get(virtualTabId),!targetId))throw new Error(`Tab ${virtualTabId} not found. Open a tab first with tab_open.`);if(targetId){let existing2=this.pageSessions.get(targetId);if(existing2&&!existing2.client.closed)return existing2}let target=targetId?await this.findTargetById(targetId):await this.findDefaultPageTarget();if(!target)throw new Error(virtualTabId?`CDP target for tab ${virtualTabId} is no longer available`:"No implicitly selectable page target found. about:, chrome:, and extension pages are excluded; pass a tabId returned by tab_open or open a web page.");let existing=this.pageSessions.get(target.id);return existing&&!existing.client.closed?existing:this.createPageSession(target)}async registerTarget(targetId){let virtualId=this.nextTabId++;this.tabIdMap.set(virtualId,targetId);let target=await this.findTargetById(targetId);return target&&await this.createPageSession(target),virtualId}async ensureTargetRegistered(targetId){for(let[virtualId2,registeredTargetId]of this.tabIdMap)if(registeredTargetId===targetId)return virtualId2;let virtualId=this.nextTabId++;return this.tabIdMap.set(virtualId,targetId),virtualId}async connectBrowserClient(){let wsUrl=await this.resolveBrowserWsUrl();if(!wsUrl)throw new Error("No browser-level WebSocket URL available from CDP");let client2=await CdpClient.connect(wsUrl);return this.browserClient=client2,client2.on("Target.targetDestroyed",params=>{for(let[virtualId,targetId]of this.tabIdMap)if(targetId===params.targetId){this.tabIdMap.delete(virtualId);break}this.pageSessions.delete(params.targetId)}),client2}async createPageSession(target){let client2;try{let browser=await this.getBrowserClient(),{sessionId}=await browser.sendCommand("Target.attachToTarget",{targetId:target.id,flatten:!0},5e3);client2=browser.createChildSession(sessionId)}catch(error48){if(this.isRemote())throw new Error(`Failed to attach to remote CDP target ${target.id}: ${error48 instanceof Error?error48.message:String(error48)}`,{cause:error48});client2=await CdpClient.connect(target.webSocketDebuggerUrl)}let tabId;for(let[virtualId,registeredTargetId]of this.tabIdMap)if(registeredTargetId===target.id){tabId=virtualId;break}tabId===void 0&&(tabId=this.nextTabId++,this.tabIdMap.set(tabId,target.id));let buffers=createBuffers(tabId);await setupBufferListeners(client2,buffers);let session={tabId,client:client2,buffers,targetId:target.id,url:target.url};this.pageSessions.set(target.id,session),client2.on("Inspector.detached",()=>{this.pageSessions.delete(target.id)});try{await initializePageSession(session)}catch(error48){throw this.pageSessions.delete(target.id),client2.close(),error48}return session}async findTargetById(targetId){if(this.isRemote())return this.findTargetByIdViaCdp(targetId);try{return(await discoverTargets(this.effectivePort())).find(t=>t.id===targetId&&t.webSocketDebuggerUrl)??null}catch{return this.findTargetByIdViaCdp(targetId)}}async findDefaultPageTarget(){if(this.isRemote())return this.findDefaultPageTargetViaCdp();try{return(await discoverTargets(this.effectivePort())).find(t=>t.type==="page"&&t.webSocketDebuggerUrl&&isImplicitlySelectablePageUrl(t.url))??null}catch{return this.findDefaultPageTargetViaCdp()}}effectivePort(){return readDevToolsActivePort(this.userDataDir)?.port??this.port}async resolveBrowserWsUrl(){let configuredEndpoint=this.endpointResolver?await this.endpointResolver():this.endpointUrl;if(configuredEndpoint){let url2=new URL(configuredEndpoint);if(url2.protocol!=="ws:"&&url2.protocol!=="wss:")throw new Error(`Unsupported CDP endpoint protocol: ${url2.protocol}`);return url2.toString()}let fileInfo=readDevToolsActivePort(this.userDataDir);if(fileInfo)return`ws://localhost:${fileInfo.port}${fileInfo.browserWsPath}`;try{return(await this.fetchVersionInfo()).webSocketDebuggerUrl??null}catch{return null}}pageWsUrl(targetId){return`ws://localhost:${this.effectivePort()}/devtools/page/${targetId}`}isRemote(){return!!(this.endpointUrl||this.endpointResolver)}async findTargetByIdViaCdp(targetId){try{let info=(await(await this.getBrowserClient()).sendCommand("Target.getTargets",{})).targetInfos.find(t=>t.targetId===targetId);return info?{id:info.targetId,title:info.title??"",type:info.type??"page",url:info.url??"",webSocketDebuggerUrl:this.pageWsUrl(info.targetId)}:null}catch{return null}}async findDefaultPageTargetViaCdp(){try{let info=(await(await this.getBrowserClient()).sendCommand("Target.getTargets",{})).targetInfos.find(t=>t.type==="page"&&isImplicitlySelectablePageUrl(t.url));return info?{id:info.targetId,title:info.title??"",type:info.type??"page",url:info.url??"",webSocketDebuggerUrl:this.pageWsUrl(info.targetId)}:null}catch{return null}}fetchVersionInfo(){return new Promise((resolve2,reject)=>{let req=http2.get(`http://localhost:${this.port}/json/version`,res=>{let data="";res.on("data",chunk=>data+=chunk),res.on("end",()=>{try{resolve2(JSON.parse(data))}catch(e){reject(new Error(`Failed to parse CDP version info: ${e}`))}})});req.on("error",reject),req.setTimeout(3e3,()=>{req.destroy(),reject(new Error("CDP version info timeout"))})})}async probeAvailability(){try{return await(await this.getBrowserClient()).sendCommand("Target.getTargets",{},3e3),{available:!0}}catch(error48){return this.browserClient?.close(),this.browserClient=null,{available:!1,error:(error48 instanceof Error?error48.message:String(error48)).trim()||"CDP connection failed"}}}async isAvailable(){return(await this.probeAvailability()).available}hasActiveConnections(){return this.browserClient!==null&&!this.browserClient.closed||Array.from(this.pageSessions.values()).some(session=>!session.client.closed)}listOpenPageSessions(){return Array.from(this.pageSessions.values()).filter(session=>!session.client.closed)}listRegisteredTabIds(targetIds){return Array.from(this.tabIdMap.entries()).filter(([,targetId])=>!targetIds||targetIds.has(targetId)).map(([tabId])=>tabId)}close(){this.browserClient?.close(),this.browserClient=null;for(let session of this.pageSessions.values())session.client.close();this.pageSessions.clear(),this.tabIdMap.clear()}};var injectedSessions=new WeakMap,indicatorQueues=new WeakMap;function enqueueIndicatorOperation(session,operation){let queued=(indicatorQueues.get(session)??Promise.resolve()).catch(()=>{}).then(operation);return indicatorQueues.set(session,queued),queued.finally(()=>{indicatorQueues.get(session)===queued&&indicatorQueues.delete(session)})}function createFaviconScript(controlSource){let iconDataUrl=createControlledFaviconDataUrl(controlSource);return`(() => {
|
|
80
80
|
if (window !== window.top) return;
|
|
81
81
|
const ICON = ${JSON.stringify(iconDataUrl)};
|
|
82
82
|
const existing = window.__mearlControlledFavicon__;
|
|
@@ -396,14 +396,14 @@ ${SOURCE_BADGES[source]}
|
|
|
396
396
|
<div id="bottom-bar" class="system-bar" data-mearl-device-bottom-bar>
|
|
397
397
|
<button id="gesture-surface" type="button" data-interactive="false" disabled aria-hidden="true"><span id="gesture-indicator" aria-hidden="true"></span></button>
|
|
398
398
|
</div>
|
|
399
|
-
</div>`;let deviceChrome=root.querySelector("#device-chrome"),statusBar=root.querySelector("#status-bar"),time3=root.querySelector("#time"),cutoutButton=root.querySelector("#device-cutout"),cutoutStatusPath=root.querySelector("#cutout-check path"),gestureSurface=root.querySelector("#gesture-surface"),screenshotPending=!1,resetTimer=null,destroyed=!1,updateTime=()=>{if(!time3)return;let now=new NativeDate(nativeNow()+(state.timeOffsetMs??0));time3.textContent=`${String(now.getHours()).padStart(2,"0")}:${String(now.getMinutes()).padStart(2,"0")}`};updateTime();let timeTimer=browser.setInterval(updateTime,3e4),setCutoutState=nextState=>{if(!cutoutButton||cutoutButton.tagName!=="BUTTON")return;cutoutButton.dataset.state=nextState;let label=nextState==="copied"?labels.copied:nextState==="downloaded"?labels.downloaded:nextState==="failed"?labels.captureFailed:labels.screenshot;cutoutButton.setAttribute("aria-label",label),cutoutButton.title=label,cutoutStatusPath?.setAttribute("d",nextState==="failed"?"M5.5 5.5l9 9m0-9-9 9":"m4.5 10.5 3.2 3.2 7.8-7.8")},screenshotBlob=data=>{let binary=browser.atob(data),bytes=new Uint8Array(binary.length);for(let index=0;index<binary.length;index+=1)bytes[index]=binary.charCodeAt(index);return new browser.Blob([bytes],{type:"image/png"})},downloadScreenshot=blob=>{let link=ownerDocument.createElement("a"),objectUrl=browser.URL.createObjectURL(blob);link.href=objectUrl,link.download=`mearl-screenshot-${new Date().toISOString().replace(/[:.]/g,"-")}.png`,link.style.display="none",ownerDocument.body.appendChild(link),link.click(),link.remove(),browser.setTimeout(()=>browser.URL.revokeObjectURL(objectUrl),1e3)},applyState=()=>{if(statusBar&&(statusBar.style.display=state.statusBarVisible?"":"none",statusBar.style.background=state.statusBarBackground),deviceChrome&&(deviceChrome.style.color=state.textColor),gestureSurface){let interactive=!!(state.bottomActionEnabled&&options.onBottomAction);gestureSurface.dataset.interactive=String(interactive),gestureSurface.disabled=!interactive,gestureSurface.setAttribute("aria-hidden",String(!interactive)),interactive?(gestureSurface.setAttribute("aria-label",labels.bottomAction),gestureSurface.title=labels.bottomAction):(gestureSurface.removeAttribute("aria-label"),gestureSurface.removeAttribute("title"))}};return cutoutButton?.tagName==="BUTTON"&&(setCutoutState("idle"),cutoutButton.disabled=!options.captureScreenshot,cutoutButton.addEventListener("click",()=>{destroyed||!options.captureScreenshot||screenshotPending||cutoutButton.dataset.state!=="idle"||(screenshotPending=!0,cutoutButton.setAttribute("aria-busy","true"),options.captureScreenshot().then(({data})=>screenshotBlob(data)).then(async blob=>{let ClipboardItemConstructor=browser.ClipboardItem;if(browser.navigator.clipboard?.write&&ClipboardItemConstructor)try{await browser.navigator.clipboard.write([new ClipboardItemConstructor({"image/png":blob})]),setCutoutState("copied");return}catch{}downloadScreenshot(blob),setCutoutState("downloaded")}).catch(()=>setCutoutState("failed")).finally(()=>{screenshotPending=!1,!destroyed&&(cutoutButton.setAttribute("aria-busy","false"),resetTimer=browser.setTimeout(()=>{resetTimer=null,screenshotPending||setCutoutState("idle")},1600))}))})),gestureSurface?.addEventListener("click",()=>{!destroyed&&state.bottomActionEnabled&&options.onBottomAction?.()}),applyState(),{updateState(nextState){destroyed||(Object.assign(state,nextState),applyState(),updateTime())},destroy(){destroyed||(destroyed=!0,browser.clearInterval(timeTimer),resetTimer!==null&&browser.clearTimeout(resetTimer),root.replaceChildren())}}}var deviceShellStates=new WeakMap,DEVICE_SHELL_BINDING="__mearlCdpDeviceShellRelay",DEVICE_SHELL_RESPONSE="__mearlCdpDeviceShellResponse",FRAME_INTERACTIVITY_SETTLE_TIMEOUT_MS=420,FRAME_INTERACTIVITY_POLL_MS=20;function findActiveWebView(frameTree){if(!frameTree)return;let root=frameTree.frame?.name==="__mearl_root__"?frameTree.frame:void 0,layer=frameTree.frame?.name==="__mearl_layer__"?frameTree.frame:void 0;for(let child of frameTree.childFrames??[]){let match=findActiveWebView(child);match&&(match.name==="__mearl_layer__"?layer=match:root??=match)}return layer??root}function collectDeviceShellFrames(frameTree,frames=[]){if(!frameTree)return frames;(frameTree.frame?.name==="__mearl_root__"||frameTree.frame?.name==="__mearl_layer__")&&frames.push(frameTree.frame);for(let child of frameTree.childFrames??[])collectDeviceShellFrames(child,frames);return frames}async function readFrameOwnerInteractivity(client2,frameId){try{let owner=await client2.sendCommand("DOM.getFrameOwner",{frameId});if(owner.backendNodeId===void 0)return;let attributes=(await client2.sendCommand("DOM.describeNode",{backendNodeId:owner.backendNodeId,depth:0})).node?.attributes;if(!attributes)return;let names=new Set(attributes.filter((_,index)=>index%2===0)),ariaHiddenIndex=attributes.indexOf("aria-hidden");return!names.has("inert")&&(ariaHiddenIndex<0||attributes[ariaHiddenIndex+1]!=="true")}catch{return}}async function resolveInteractiveWebViewFrame(client2){let deadline=Date.now()+FRAME_INTERACTIVITY_SETTLE_TIMEOUT_MS,fallback;do{let frameTree=(await client2.sendCommand("Page.getFrameTree").catch(()=>null))?.frameTree;fallback=findActiveWebView(frameTree)??fallback;let candidates=collectDeviceShellFrames(frameTree),inspected=!1;for(let index=candidates.length-1;index>=0;index-=1){let candidate=candidates[index];if(candidate.id===frameTree?.frame?.id)continue;let interactive=await readFrameOwnerInteractivity(client2,candidate.id);if(interactive!==void 0&&(inspected=!0,interactive))return candidate}if(!inspected||Date.now()>=deadline)return fallback;await new Promise(resolve2=>setTimeout(resolve2,FRAME_INTERACTIVITY_POLL_MS))}while(Date.now()<deadline);return fallback}function trackExecutionContexts(state,client2){let contexts=new Map;return state.executionContexts.set(client2,contexts),[client2.on("Runtime.executionContextsCleared",()=>contexts.clear()),client2.on("Runtime.executionContextCreated",params=>{let context=params?.context,frameId=context?.auxData?.frameId;typeof frameId=="string"&&context?.auxData?.isDefault===!0&&typeof context.id=="number"&&contexts.set(frameId,context.id)}),client2.on("Runtime.executionContextDestroyed",params=>{let executionContextId=params?.executionContextId;for(let[frameId,contextId]of contexts)contextId===executionContextId&&contexts.delete(frameId)})]}async function installChildTarget(session,state,params){let sessionId=params.sessionId;if(typeof sessionId!="string")return;let child=session.client.createChildSession(sessionId),disposeListeners=trackExecutionContexts(state,child);try{if(params.targetInfo?.type!=="iframe"||deviceShellStates.get(session)!==state)return;await child.sendCommand("Runtime.enable");let frameName=await child.sendCommand("Runtime.evaluate",{expression:"window.name",returnByValue:!0}).then(result=>result.result?.value);if(frameName!=="__mearl_root__"&&frameName!=="__mearl_layer__")return;let frameTree=await child.sendCommand("Page.getFrameTree").catch(()=>null);if(state.attachedWebViews.set(sessionId,{client:child,name:frameName,frameId:frameTree?.frameTree?.frame?.id??params.targetInfo?.targetId,order:state.nextAttachedOrder++,disposeListeners}),!state.childEnvironmentManagedByApp)for(let{method,params:commandParams,optional:optional2}of buildEnableEmulationCommands(state.emulation))await child.sendCommand(method,commandParams).catch(error48=>{if(!optional2)throw error48})}finally{if(!state.attachedWebViews.has(sessionId)){for(let dispose of disposeListeners)dispose();state.executionContexts.delete(child)}await child.sendCommand("Runtime.runIfWaitingForDebugger").catch(()=>{})}}async function enableDeviceShellFrameRouting(session,state){state.disposeListeners.push(...trackExecutionContexts(state,session.client)),state.disposeListeners.push(session.client.on("Target.attachedToTarget",params=>{installChildTarget(session,state,params).catch(()=>{})})),state.disposeListeners.push(session.client.on("Target.detachedFromTarget",params=>{if(deviceShellStates.get(session)!==state)return;let attached=state.attachedWebViews.get(params?.sessionId);if(attached){for(let dispose of attached.disposeListeners)dispose();state.executionContexts.delete(attached.client),state.attachedWebViews.delete(params.sessionId)}})),await session.client.sendCommand("Runtime.enable"),await session.client.sendCommand("Target.setAutoAttach",{autoAttach:!0,waitForDebuggerOnStart:!0,flatten:!0,filter:[{type:"iframe"},{exclude:!0}]})}function serializeForSource(value){return JSON.stringify(value).replace(/[\u2028\u2029]/g,character=>character==="\u2028"?"\\u2028":"\\u2029")}function installDeviceShell(config2,installChromeView,bindingName,responseName){let browser=globalThis,target=globalThis,document2=browser.document;if(browser.top!==globalThis||!/^https?:$/i.test(browser.location.protocol))return;let businessUrl=browser.location.href;try{let shellRoot=document2.createElement("html"),shellHead=document2.createElement("head"),charset=document2.createElement("meta"),viewport=document2.createElement("meta"),title=document2.createElement("title"),style=document2.createElement("style"),shellBody=document2.createElement("body"),frame=document2.createElement("iframe"),chromeHost=document2.createElement("div");shellRoot.setAttribute("data-mearl-device-shell",""),shellBody.setAttribute("data-mearl-device-shell",""),charset.setAttribute("charset","utf-8"),viewport.name="viewport",viewport.content="width=device-width,initial-scale=1,viewport-fit=cover",style.textContent=`
|
|
399
|
+
</div>`;let deviceChrome=root.querySelector("#device-chrome"),statusBar=root.querySelector("#status-bar"),time3=root.querySelector("#time"),cutoutButton=root.querySelector("#device-cutout"),cutoutStatusPath=root.querySelector("#cutout-check path"),gestureSurface=root.querySelector("#gesture-surface"),screenshotPending=!1,resetTimer=null,destroyed=!1,updateTime=()=>{if(!time3)return;let now=new NativeDate(nativeNow()+(state.timeOffsetMs??0));time3.textContent=`${String(now.getHours()).padStart(2,"0")}:${String(now.getMinutes()).padStart(2,"0")}`};updateTime();let timeTimer=browser.setInterval(updateTime,3e4),setCutoutState=nextState=>{if(!cutoutButton||cutoutButton.tagName!=="BUTTON")return;cutoutButton.dataset.state=nextState;let label=nextState==="copied"?labels.copied:nextState==="downloaded"?labels.downloaded:nextState==="failed"?labels.captureFailed:labels.screenshot;cutoutButton.setAttribute("aria-label",label),cutoutButton.title=label,cutoutStatusPath?.setAttribute("d",nextState==="failed"?"M5.5 5.5l9 9m0-9-9 9":"m4.5 10.5 3.2 3.2 7.8-7.8")},screenshotBlob=data=>{let binary=browser.atob(data),bytes=new Uint8Array(binary.length);for(let index=0;index<binary.length;index+=1)bytes[index]=binary.charCodeAt(index);return new browser.Blob([bytes],{type:"image/png"})},downloadScreenshot=blob=>{let link=ownerDocument.createElement("a"),objectUrl=browser.URL.createObjectURL(blob);link.href=objectUrl,link.download=`mearl-screenshot-${new Date().toISOString().replace(/[:.]/g,"-")}.png`,link.style.display="none",ownerDocument.body.appendChild(link),link.click(),link.remove(),browser.setTimeout(()=>browser.URL.revokeObjectURL(objectUrl),1e3)},applyState=()=>{if(statusBar&&(statusBar.style.display=state.statusBarVisible?"":"none",statusBar.style.background=state.statusBarBackground),deviceChrome&&(deviceChrome.style.color=state.textColor),gestureSurface){let interactive=!!(state.bottomActionEnabled&&options.onBottomAction);gestureSurface.dataset.interactive=String(interactive),gestureSurface.disabled=!interactive,gestureSurface.setAttribute("aria-hidden",String(!interactive)),interactive?(gestureSurface.setAttribute("aria-label",labels.bottomAction),gestureSurface.title=labels.bottomAction):(gestureSurface.removeAttribute("aria-label"),gestureSurface.removeAttribute("title"))}};return cutoutButton?.tagName==="BUTTON"&&(setCutoutState("idle"),cutoutButton.disabled=!options.captureScreenshot,cutoutButton.addEventListener("click",()=>{destroyed||!options.captureScreenshot||screenshotPending||cutoutButton.dataset.state!=="idle"||(screenshotPending=!0,cutoutButton.setAttribute("aria-busy","true"),options.captureScreenshot().then(({data})=>screenshotBlob(data)).then(async blob=>{let ClipboardItemConstructor=browser.ClipboardItem;if(browser.navigator.clipboard?.write&&ClipboardItemConstructor)try{await browser.navigator.clipboard.write([new ClipboardItemConstructor({"image/png":blob})]),setCutoutState("copied");return}catch{}downloadScreenshot(blob),setCutoutState("downloaded")}).catch(()=>setCutoutState("failed")).finally(()=>{screenshotPending=!1,!destroyed&&(cutoutButton.setAttribute("aria-busy","false"),resetTimer=browser.setTimeout(()=>{resetTimer=null,screenshotPending||setCutoutState("idle")},1600))}))})),gestureSurface?.addEventListener("click",()=>{!destroyed&&state.bottomActionEnabled&&options.onBottomAction?.()}),applyState(),{updateState(nextState){destroyed||(Object.assign(state,nextState),applyState(),updateTime())},destroy(){destroyed||(destroyed=!0,browser.clearInterval(timeTimer),resetTimer!==null&&browser.clearTimeout(resetTimer),root.replaceChildren())}}}var deviceShellStates=new WeakMap,DEVICE_SHELL_BINDING="__mearlCdpDeviceShellRelay",DEVICE_SHELL_RESPONSE="__mearlCdpDeviceShellResponse",FRAME_INTERACTIVITY_SETTLE_TIMEOUT_MS=420,FRAME_INTERACTIVITY_POLL_MS=20;function findActiveWebView(frameTree){if(!frameTree)return;let root=frameTree.frame?.name==="__mearl_root__"?frameTree.frame:void 0,layer=frameTree.frame?.name==="__mearl_layer__"?frameTree.frame:void 0;for(let child of frameTree.childFrames??[]){let match=findActiveWebView(child);match&&(match.name==="__mearl_layer__"?layer=match:root??=match)}return layer??root}function collectDeviceShellFrames(frameTree,frames=[]){if(!frameTree)return frames;(frameTree.frame?.name==="__mearl_root__"||frameTree.frame?.name==="__mearl_layer__")&&frames.push(frameTree.frame);for(let child of frameTree.childFrames??[])collectDeviceShellFrames(child,frames);return frames}async function readFrameOwnerInteractivity(client2,frameId){try{let owner=await client2.sendCommand("DOM.getFrameOwner",{frameId});if(owner.backendNodeId===void 0)return;let attributes=(await client2.sendCommand("DOM.describeNode",{backendNodeId:owner.backendNodeId,depth:0})).node?.attributes;if(!attributes)return;let names=new Set(attributes.filter((_,index)=>index%2===0)),ariaHiddenIndex=attributes.indexOf("aria-hidden");return!names.has("inert")&&(ariaHiddenIndex<0||attributes[ariaHiddenIndex+1]!=="true")}catch{return}}async function resolveInteractiveWebViewFrame(client2){let deadline=Date.now()+FRAME_INTERACTIVITY_SETTLE_TIMEOUT_MS,fallback;do{let frameTree=(await client2.sendCommand("Page.getFrameTree").catch(()=>null))?.frameTree;fallback=findActiveWebView(frameTree)??fallback;let candidates=collectDeviceShellFrames(frameTree),inspected=!1;for(let index=candidates.length-1;index>=0;index-=1){let candidate=candidates[index];if(candidate.id===frameTree?.frame?.id)continue;let interactive=await readFrameOwnerInteractivity(client2,candidate.id);if(interactive!==void 0&&(inspected=!0,interactive))return candidate}if(!inspected||Date.now()>=deadline)return fallback;await new Promise(resolve2=>setTimeout(resolve2,FRAME_INTERACTIVITY_POLL_MS))}while(Date.now()<deadline);return fallback}function trackExecutionContexts(state,client2){let contexts=new Map;return state.executionContexts.set(client2,contexts),[client2.on("Runtime.executionContextsCleared",()=>contexts.clear()),client2.on("Runtime.executionContextCreated",params=>{let context=params?.context,frameId=context?.auxData?.frameId;typeof frameId=="string"&&context?.auxData?.isDefault===!0&&typeof context.id=="number"&&contexts.set(frameId,context.id)}),client2.on("Runtime.executionContextDestroyed",params=>{let executionContextId=params?.executionContextId;for(let[frameId,contextId]of contexts)contextId===executionContextId&&contexts.delete(frameId)})]}async function installChildTarget(session,state,params){let sessionId=params.sessionId;if(typeof sessionId!="string")return;let child=session.client.createChildSession(sessionId),disposeListeners=trackExecutionContexts(state,child);try{if(params.targetInfo?.type!=="iframe"||deviceShellStates.get(session)!==state)return;await child.sendCommand("Runtime.enable");let frameName=await child.sendCommand("Runtime.evaluate",{expression:"window.name",returnByValue:!0}).then(result=>result.result?.value);if(frameName!=="__mearl_root__"&&frameName!=="__mearl_layer__")return;let frameTree=await child.sendCommand("Page.getFrameTree").catch(()=>null);if(state.attachedWebViews.set(sessionId,{client:child,name:frameName,frameId:frameTree?.frameTree?.frame?.id??params.targetInfo?.targetId,order:state.nextAttachedOrder++,disposeListeners}),!state.childEnvironmentManagedByApp)for(let{method,params:commandParams,optional:optional2}of buildEnableEmulationCommands(state.emulation))await child.sendCommand(method,commandParams).catch(error48=>{if(!optional2)throw error48})}finally{if(!state.attachedWebViews.has(sessionId)){for(let dispose of disposeListeners)dispose();state.executionContexts.delete(child)}await child.sendCommand("Runtime.runIfWaitingForDebugger").catch(()=>{})}}async function enableDeviceShellFrameRouting(session,state){state.disposeListeners.push(...trackExecutionContexts(state,session.client)),state.disposeListeners.push(session.client.on("Target.attachedToTarget",params=>{installChildTarget(session,state,params).catch(()=>{})})),state.disposeListeners.push(session.client.on("Target.detachedFromTarget",params=>{if(deviceShellStates.get(session)!==state)return;let attached=state.attachedWebViews.get(params?.sessionId);if(attached){for(let dispose of attached.disposeListeners)dispose();state.executionContexts.delete(attached.client),state.attachedWebViews.delete(params.sessionId)}})),await session.client.sendCommand("Runtime.enable"),await session.client.sendCommand("Target.setAutoAttach",{autoAttach:!0,waitForDebuggerOnStart:!0,flatten:!0,filter:[{type:"iframe"},{exclude:!0}]})}function serializeForSource(value){return JSON.stringify(value).replace(/[\u2028\u2029]/g,character=>character==="\u2028"?"\\u2028":"\\u2029")}function installDeviceShell(config2,installChromeView,bindingName,responseName){if(config2.rootContainerManagedByApp)return;let browser=globalThis,target=globalThis,document2=browser.document;if(browser.top!==globalThis||!/^https?:$/i.test(browser.location.protocol))return;if(!document2.documentElement){let observer=new browser.MutationObserver(()=>{document2.documentElement&&(observer.disconnect(),installDeviceShell(config2,installChromeView,bindingName,responseName))});observer.observe(document2,{childList:!0});return}let businessUrl=browser.location.href;try{let shellRoot=document2.createElement("html"),shellHead=document2.createElement("head"),charset=document2.createElement("meta"),viewport=document2.createElement("meta"),title=document2.createElement("title"),style=document2.createElement("style"),shellBody=document2.createElement("body"),frame=document2.createElement("iframe"),chromeHost=document2.createElement("div");shellRoot.setAttribute("data-mearl-device-shell",""),shellBody.setAttribute("data-mearl-device-shell",""),charset.setAttribute("charset","utf-8"),viewport.name="viewport",viewport.content="width=device-width,initial-scale=1,viewport-fit=cover",style.textContent=`
|
|
400
400
|
:root, body { width: 100%; height: 100%; margin: 0; overflow: hidden; background: #fff; }
|
|
401
401
|
[data-mearl-root-webview] {
|
|
402
402
|
position: fixed; left: 0; right: 0; top: ${config2.statusBarHeight}px;
|
|
403
403
|
width: 100%; height: calc(100% - ${config2.statusBarHeight}px);
|
|
404
404
|
border: 0; display: block; background: #fff; z-index: 0;
|
|
405
405
|
}
|
|
406
|
-
`,shellHead.append(charset,viewport,title,style),shellRoot.append(shellHead,shellBody),frame.name="__mearl_root__",frame.setAttribute("data-mearl-root-webview","device-shell"),frame.addEventListener("load",()=>{frame.getAttribute("src")&&frame.getAttribute("src")!=="about:blank"&&frame.setAttribute("data-mearl-webview-ready","")}),chromeHost.setAttribute("data-mearl-device-chrome-host","");let pendingScreenshots=new Map,nextScreenshotId=1;target[responseName]=(requestId,result)=>{let pending=pendingScreenshots.get(requestId);pending&&(pendingScreenshots.delete(requestId),browser.clearTimeout(pending.timer),typeof result?.data=="string"?pending.resolve({data:result.data}):pending.reject(new Error(String(result?.error??"Screenshot failed"))))};let binding=target[bindingName],captureScreenshot=typeof binding=="function"?()=>new Promise((resolve2,reject)=>{let requestId=nextScreenshotId++,timer=browser.setTimeout(()=>{pendingScreenshots.delete(requestId),reject(new Error("Screenshot timed out"))},15e3);pendingScreenshots.set(requestId,{resolve:resolve2,reject,timer});try{binding(JSON.stringify({type:"screenshot",requestId}))}catch(error48){pendingScreenshots.delete(requestId),browser.clearTimeout(timer),reject(error48 instanceof Error?error48:new Error(String(error48)))}}):void 0
|
|
406
|
+
`,shellHead.append(charset,viewport,title,style),shellRoot.append(shellHead,shellBody),frame.name="__mearl_root__",frame.setAttribute("data-mearl-root-webview","device-shell"),frame.addEventListener("load",()=>{frame.getAttribute("src")&&frame.getAttribute("src")!=="about:blank"&&(frame.setAttribute("data-mearl-webview-ready",""),frame.contentWindow?.postMessage({source:"mearl-app-bridge",type:"requestTitleBarState"},"*"))}),chromeHost.setAttribute("data-mearl-device-chrome-host","");let pendingScreenshots=new Map,nextScreenshotId=1;target[responseName]=(requestId,result)=>{let pending=pendingScreenshots.get(requestId);pending&&(pendingScreenshots.delete(requestId),browser.clearTimeout(pending.timer),typeof result?.data=="string"?pending.resolve({data:result.data}):pending.reject(new Error(String(result?.error??"Screenshot failed"))))};let binding=target[bindingName],captureScreenshot=typeof binding=="function"?()=>new Promise((resolve2,reject)=>{let requestId=nextScreenshotId++,timer=browser.setTimeout(()=>{pendingScreenshots.delete(requestId),reject(new Error("Screenshot timed out"))},15e3);pendingScreenshots.set(requestId,{resolve:resolve2,reject,timer});try{binding(JSON.stringify({type:"screenshot",requestId}))}catch(error48){pendingScreenshots.delete(requestId),browser.clearTimeout(timer),reject(error48 instanceof Error?error48:new Error(String(error48)))}}):void 0,chromeView=installChromeView(chromeHost.attachShadow({mode:"open"}),config2,{captureScreenshot});browser.addEventListener("message",event=>{if(event.source!==frame.contentWindow)return;let message=event.data,state=message?.state;message?.source!=="mearl-app-bridge"||message.type!=="titleBarState"||typeof state?.statusBarBackground!="string"||typeof state.textColor!="string"||chromeView.updateState({statusBarVisible:state.mode!=="hidden",statusBarBackground:state.statusBarBackground,textColor:state.textColor})}),shellBody.append(frame,chromeHost);let currentRoot=document2.documentElement;currentRoot?document2.replaceChild(shellRoot,currentRoot):document2.appendChild(shellRoot),typeof browser.stop=="function"&&browser.stop(),frame.src=businessUrl}catch(error48){console.warn("[Mearl Device Shell] failed to create root WebView",error48)}}function resolveDeviceShellConfig(emulation,options){let platform=/iPhone|iPad|iPod|Mac/i.test(emulation.platform)?"ios":"android";return{platform,statusBarHeight:emulation.orientation==="landscape"?24:Math.max(0,Math.round(emulation.safeAreaInsets.top)),bottomBarHeight:Math.max(0,Math.round(emulation.safeAreaInsets.bottom)),cutout:platform==="ios"?emulation.appearance.cutout:"none",...options.rootContainerManagedByApp?{rootContainerManagedByApp:!0}:{}}}function buildDeviceShellSource(config2){return`;(${installDeviceShell.toString()})(${serializeForSource(config2)},(${installDeviceChromeView.toString()}),${JSON.stringify(DEVICE_SHELL_BINDING)},${JSON.stringify(DEVICE_SHELL_RESPONSE)});`}async function evaluateDeviceShellContext(session,contextId,expression,options={}){return session.client.sendCommand("Runtime.evaluate",{expression,...contextId===void 0?{}:{contextId},...options})}function listenForDeviceShellRequests(session,state){return session.client.on("Runtime.bindingCalled",params=>{if(params?.name!==DEVICE_SHELL_BINDING||deviceShellStates.get(session)!==state)return;let request;try{request=JSON.parse(params.payload)}catch{return}if(request.type!=="screenshot"||typeof request.requestId!="number")return;let requestId=request.requestId,contextId=typeof params.executionContextId=="number"?params.executionContextId:void 0,reply=result=>evaluateDeviceShellContext(session,contextId,`globalThis[${JSON.stringify(DEVICE_SHELL_RESPONSE)}]?.(${requestId},${serializeForSource(result)})`);(async()=>{let hiddenState;try{hiddenState=(await evaluateDeviceShellContext(session,contextId,`(() => {
|
|
407
407
|
const root = document.documentElement;
|
|
408
408
|
if (!root) return {};
|
|
409
409
|
const property = '--mearl-device-cutout-display';
|
|
@@ -419,7 +419,7 @@ ${SOURCE_BADGES[source]}
|
|
|
419
419
|
if (root.style.getPropertyValue(property) !== 'none') return;
|
|
420
420
|
if (state.value) root.style.setProperty(property, state.value, state.priority);
|
|
421
421
|
else root.style.removeProperty(property);
|
|
422
|
-
})()`).catch(()=>{})}})()})}function isCdpDeviceShellActive(session){return deviceShellStates.has(session)}function setCdpDeviceShellChildEnvironmentManagedByApp(session,managed){let state=deviceShellStates.get(session);state&&(state.childEnvironmentManagedByApp=managed)}async function resolveCdpDeviceShellPageEndpoint(session){let state=deviceShellStates.get(session);if(!state)return{client:session.client};let attached=Array.from(state.attachedWebViews.values()).filter(webView=>!webView.client.closed).sort((left,right)=>right.order-left.order),activeInParent=await resolveInteractiveWebViewFrame(session.client),attachedActive=activeInParent?attached.find(webView=>webView.frameId===activeInParent.id):void 0;if(attachedActive)return{client:attachedActive.client,url:activeInParent?.url};let attachedRoot=attached.find(webView=>webView.name==="__mearl_root__");if(attachedRoot){let active=await resolveInteractiveWebViewFrame(attachedRoot.client);return active&&active.id!==attachedRoot.frameId?{client:attachedRoot.client,frameId:active.id,url:active.url}:{client:attachedRoot.client,url:active?.url}}if(!activeInParent)throw new Error("Device shell business WebView is not ready");return{client:session.client,frameId:activeInParent.id,url:activeInParent.url}}async function sendCdpDeviceShellPageCommand(session,method,params={},timeoutMs){let send=(client2,command,commandParams)=>timeoutMs===void 0?client2.sendCommand(command,commandParams):client2.sendCommand(command,commandParams,timeoutMs),state=deviceShellStates.get(session);if(!state)return send(session.client,method,params);let endpoint=await resolveCdpDeviceShellPageEndpoint(session);if(endpoint.frameId===void 0)return send(endpoint.client,method,params);let contextId=state.executionContexts.get(endpoint.client)?.get(endpoint.frameId);if((method==="Runtime.evaluate"||method==="DOM.resolveNode")&&contextId===void 0){let deadline=Date.now()+1e3;for(;Date.now()<deadline&&contextId===void 0;){let currentEndpoint=await resolveCdpDeviceShellPageEndpoint(session);if(currentEndpoint.client!==endpoint.client||currentEndpoint.frameId!==endpoint.frameId)return sendCdpDeviceShellPageCommand(session,method,params,timeoutMs);await new Promise(resolve2=>setTimeout(resolve2,10)),contextId=state.executionContexts.get(endpoint.client)?.get(endpoint.frameId)}if(contextId===void 0)throw new Error("Device shell business WebView execution context is unavailable")}let nextParams={...params};if(method==="Runtime.evaluate"&&contextId!==void 0&&(nextParams.contextId=contextId),method==="DOM.resolveNode"&&contextId!==void 0&&(nextParams.executionContextId=contextId),method==="Accessibility.getFullAXTree"&&(nextParams.frameId=endpoint.frameId),method==="Page.navigate"&&(nextParams.frameId=endpoint.frameId),method==="Page.reload"){if(!endpoint.url)throw new Error("Device shell business WebView URL is unavailable");return send(endpoint.client,"Page.navigate",{url:endpoint.url,frameId:endpoint.frameId})}return send(endpoint.client,method,nextParams)}function getCdpDeviceShellInputOffset(session){let state=deviceShellStates.get(session);return state?{x:
|
|
422
|
+
})()`).catch(()=>{})}})()})}function isCdpDeviceShellActive(session){return deviceShellStates.has(session)}function setCdpDeviceShellChildEnvironmentManagedByApp(session,managed){let state=deviceShellStates.get(session);state&&(state.childEnvironmentManagedByApp=managed)}async function resolveCdpDeviceShellPageEndpoint(session){let state=deviceShellStates.get(session);if(!state)return{client:session.client};let updateActiveFrameOffset=name=>{state.activeFrameOffsetX=state.rootContainerManagedByApp&&name==="__mearl_layer__"?state.emulation.width/2:0},attached=Array.from(state.attachedWebViews.values()).filter(webView=>!webView.client.closed).sort((left,right)=>right.order-left.order),activeInParent=await resolveInteractiveWebViewFrame(session.client),attachedActive=activeInParent?attached.find(webView=>webView.frameId===activeInParent.id):void 0;if(attachedActive)return updateActiveFrameOffset(attachedActive.name),{client:attachedActive.client,url:activeInParent?.url};let attachedRoot=attached.find(webView=>webView.name==="__mearl_root__");if(attachedRoot){let active=await resolveInteractiveWebViewFrame(attachedRoot.client);return active&&active.id!==attachedRoot.frameId?(updateActiveFrameOffset(active.name),{client:attachedRoot.client,frameId:active.id,url:active.url}):(updateActiveFrameOffset(active?.name??attachedRoot.name),{client:attachedRoot.client,url:active?.url})}if(!activeInParent)throw new Error("Device shell business WebView is not ready");return updateActiveFrameOffset(activeInParent.name),{client:session.client,frameId:activeInParent.id,url:activeInParent.url}}async function sendCdpDeviceShellPageCommand(session,method,params={},timeoutMs){let send=(client2,command,commandParams)=>timeoutMs===void 0?client2.sendCommand(command,commandParams):client2.sendCommand(command,commandParams,timeoutMs),state=deviceShellStates.get(session);if(!state)return send(session.client,method,params);let endpoint=await resolveCdpDeviceShellPageEndpoint(session);if(endpoint.frameId===void 0)return send(endpoint.client,method,params);let contextId=state.executionContexts.get(endpoint.client)?.get(endpoint.frameId);if((method==="Runtime.evaluate"||method==="DOM.resolveNode")&&contextId===void 0){let deadline=Date.now()+1e3;for(;Date.now()<deadline&&contextId===void 0;){let currentEndpoint=await resolveCdpDeviceShellPageEndpoint(session);if(currentEndpoint.client!==endpoint.client||currentEndpoint.frameId!==endpoint.frameId)return sendCdpDeviceShellPageCommand(session,method,params,timeoutMs);await new Promise(resolve2=>setTimeout(resolve2,10)),contextId=state.executionContexts.get(endpoint.client)?.get(endpoint.frameId)}if(contextId===void 0)throw new Error("Device shell business WebView execution context is unavailable")}let nextParams={...params};if(method==="Runtime.evaluate"&&contextId!==void 0&&(nextParams.contextId=contextId),method==="DOM.resolveNode"&&contextId!==void 0&&(nextParams.executionContextId=contextId),method==="Accessibility.getFullAXTree"&&(nextParams.frameId=endpoint.frameId),method==="Page.navigate"&&(nextParams.frameId=endpoint.frameId),method==="Page.reload"){if(!endpoint.url)throw new Error("Device shell business WebView URL is unavailable");return send(endpoint.client,"Page.navigate",{url:endpoint.url,frameId:endpoint.frameId})}return send(endpoint.client,method,nextParams)}async function getCdpDeviceShellInputOffset(session){let state=deviceShellStates.get(session);return state?(state.rootContainerManagedByApp&&await resolveCdpDeviceShellPageEndpoint(session),{x:state.activeFrameOffsetX,y:state.statusBarHeight}):{x:0,y:0}}async function applyCdpDeviceShell(session,emulation,options={}){let config2=resolveDeviceShellConfig(emulation,options),configKey=JSON.stringify(config2),previous=deviceShellStates.get(session);if(previous?.configKey===configKey)return previous.emulation=emulation,previous.childEnvironmentManagedByApp||await Promise.all(Array.from(previous.attachedWebViews.values()).map(async webView=>{for(let{method,params,optional:optional2}of buildEnableEmulationCommands(emulation))await webView.client.sendCommand(method,params).catch(error48=>{if(!optional2)throw error48})})),!1;if(previous){for(let dispose of previous.disposeListeners.splice(0))dispose();for(let attached of previous.attachedWebViews.values())for(let dispose of attached.disposeListeners)dispose();previous.attachedWebViews.clear(),previous.executionContexts.clear(),await session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier:previous.documentScriptIdentifier}).catch(()=>{}),await session.client.sendCommand("Runtime.removeBinding",{name:DEVICE_SHELL_BINDING}).catch(()=>{})}await session.client.sendCommand("Runtime.addBinding",{name:DEVICE_SHELL_BINDING});let result=await session.client.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source:buildDeviceShellSource(config2)});if(typeof result.identifier!="string"||!result.identifier)throw deviceShellStates.delete(session),await session.client.sendCommand("Runtime.removeBinding",{name:DEVICE_SHELL_BINDING}).catch(()=>{}),new Error("Chrome did not return a device shell bootstrap script identifier");let state={configKey,documentScriptIdentifier:result.identifier,emulation,statusBarHeight:config2.statusBarHeight,executionContexts:new Map,attachedWebViews:new Map,nextAttachedOrder:0,childEnvironmentManagedByApp:options.rootContainerManagedByApp===!0,rootContainerManagedByApp:options.rootContainerManagedByApp===!0,activeFrameOffsetX:0,disposeListeners:[]};return deviceShellStates.set(session,state),state.disposeListeners.push(listenForDeviceShellRequests(session,state)),await enableDeviceShellFrameRouting(session,state),!0}async function clearCdpDeviceShell(session){let state=deviceShellStates.get(session);if(!state)return!1;deviceShellStates.delete(session);for(let dispose of state.disposeListeners.splice(0))dispose();for(let attached of state.attachedWebViews.values())for(let dispose of attached.disposeListeners)dispose();return state.attachedWebViews.clear(),state.executionContexts.clear(),await session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier:state.documentScriptIdentifier}).catch(()=>{}),await session.client.sendCommand("Runtime.removeBinding",{name:DEVICE_SHELL_BINDING}).catch(()=>{}),state.childEnvironmentManagedByApp||await session.client.sendCommand("Target.setAutoAttach",{autoAttach:!1,waitForDebuggerOnStart:!1,flatten:!0}).catch(()=>{}),!0}function hasLoadedRootWebView(frameTree){if(!frameTree)return!1;let frame=frameTree.frame;return frame?.name==="__mearl_root__"&&typeof frame.url=="string"&&/^https?:/i.test(frame.url)?!0:Array.isArray(frameTree.childFrames)?frameTree.childFrames.some(child=>hasLoadedRootWebView(child)):!1}async function waitForCdpDeviceShellLoad(session,timeoutMs=15e3){let deadline=Date.now()+timeoutMs;for(;Date.now()<deadline;){let result=await session.client.sendCommand("Page.getFrameTree").catch(()=>null);if(hasLoadedRootWebView(result?.frameTree))return;await new Promise(resolve2=>setTimeout(resolve2,50))}throw new Error(`Device shell root WebView load timeout after ${timeoutMs}ms`)}var RECORDING_INJECTED_SCRIPT=`
|
|
423
423
|
(function() {
|
|
424
424
|
if (window.__mtopRecording) return;
|
|
425
425
|
window.__mtopRecording = true;
|
|
@@ -594,7 +594,7 @@ ${SOURCE_BADGES[source]}
|
|
|
594
594
|
window.__mtopRecording = false;
|
|
595
595
|
return { endUrl: endUrl };
|
|
596
596
|
})()
|
|
597
|
-
`,RECORDING_BINDING_NAME="__mtopRecordReport",cdpRecordingSessions=new Map,RECORDING_MAX_REQUESTS=500,RECORDING_MAX_ACTIONS=1e3;async function cdpRecordStart(session,_data){if(cdpRecordingSessions.has(session.targetId))throw new Error(`Already recording on target ${session.targetId}. Call record_stop before starting a new recording.`);let pageClient=(await resolveCdpDeviceShellPageEndpoint(session)).client,recordingSession={targetId:session.targetId,startTime:Date.now(),startUrl:"",actions:[],client:pageClient};try{await pageClient.sendCommand("Runtime.addBinding",{name:RECORDING_BINDING_NAME})}catch(err){throw new Error(`Failed to register recording binding: ${err?.message??err}. CDP target may not support Runtime domain.`,{cause:err})}let nextSeq=1,onBindingCalled=params=>{if(params?.name===RECORDING_BINDING_NAME)try{let action=JSON.parse(params.payload);action.seq=nextSeq++,recordingSession.actions.push(action),recordingSession.actions.length>RECORDING_MAX_ACTIONS&&recordingSession.actions.splice(0,recordingSession.actions.length-RECORDING_MAX_ACTIONS)}catch{}};recordingSession.removeBindingListener=pageClient.on("Runtime.bindingCalled",onBindingCalled);try{let result=await pageClient.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source:RECORDING_INJECTED_SCRIPT});recordingSession.scriptIdentifier=result?.identifier}catch(err){throw recordingSession.removeBindingListener?.(),new Error(`Failed to register recording script: ${err?.message??err}.`,{cause:err})}try{let value=(await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:RECORDING_BOOTSTRAP_SCRIPT,returnByValue:!0})).result?.value??{};recordingSession.startUrl=value.startUrl??""}catch{recordingSession.startUrl=""}return cdpRecordingSessions.set(session.targetId,recordingSession),{recording:!0,tabId:session.targetId,startTime:recordingSession.startTime}}async function cdpRecordStop(session,_data){let recordingSession=cdpRecordingSessions.get(session.targetId);if(!recordingSession)return{wasRecording:!1,actions:[],requests:[],requestsTruncated:!1,duration:0,startUrl:"",endUrl:""};if(cdpRecordingSessions.delete(session.targetId),recordingSession.removeBindingListener?.(),recordingSession.scriptIdentifier)try{await recordingSession.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier:recordingSession.scriptIdentifier})}catch{}let endUrl="";try{endUrl=(await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:RECORDING_TEARDOWN_SCRIPT,returnByValue:!0})).result?.value?.endUrl??""}catch{}try{await recordingSession.client.sendCommand("Runtime.removeBinding",{name:RECORDING_BINDING_NAME})}catch{}let endTime=Date.now(),startTime=recordingSession.startTime,duration3=Math.round((endTime-startTime)/1e3),allRequests=session.buffers.requests.filter(r=>r.timestampMs>=startTime),requests=allRequests.length>RECORDING_MAX_REQUESTS?allRequests.slice(-RECORDING_MAX_REQUESTS):allRequests;return{wasRecording:!0,actions:annotateActionsWithRequests(recordingSession.actions,requests,endTime),requests:serializeRecordingRequests(requests),requestsTruncated:allRequests.length>RECORDING_MAX_REQUESTS,duration:duration3,startUrl:recordingSession.startUrl,endUrl}}async function releaseCdpRecordings(sessions){await Promise.allSettled(sessions.filter(session=>cdpRecordingSessions.has(session.targetId)).map(session=>cdpRecordStop(session,{})));for(let recordingSession of cdpRecordingSessions.values())recordingSession.removeBindingListener?.();cdpRecordingSessions.clear()}registerActions([{name:"record_start",session:"page",handler:cdpRecordStart},{name:"record_stop",session:"page",handler:cdpRecordStop}]);var WINDVANE="WindVane/8.7.0",WV_BRIDGE={global:"WindVane",style:"windvane"},MEGA_BRIDGE={global:"__megability_bridge__",style:"mega"},WV_NATIVE_BACK={event:"wvBackClickEvent",controlFunction:"_windvane_backControl"},FLIGGY_NATIVE_BACK={event:"WV.Back"},ALIPAY_NATIVE_BACK={event:"back"},FLIGGY_OVERLAY={enabledParam:"_fli_overlay",topRatioParam:"_fli_overlay_ratio",radiusParam:"_fli_overlay_radius",maskAlphaParam:"_fli_overlay_mask_alpha",tapCloseParam:"_fli_overlay_tap_close",tapCloseSelectors:["#qwen-titlebar .qwen-titlebar-icon-wrapper:last-child"],silentTapClose:!0,defaultTopRatio:.2,defaultRadius:0,defaultMaskAlpha:.3,defaultTapClose:!0},TAOBAO_OVERLAY={enabledParam:"useWebdialog",topRatioParam:"topRatio",heightRatioParam:"height_pct",radiusParam:"cornerRadius",maskAlphaParam:"maskAlpha",tapCloseParam:"tapEnable",tapCloseSelectors:["#qwen-titlebar .qwen-titlebar-icon-wrapper:last-child"],defaultTopRatio:.2,defaultRadius:6,defaultMaskAlpha:.5,defaultTapClose:!0},FLIGGY_IMAGE_PICKER={schemes:["page://ask_take_photo"],api:"mtop.trip.serverless.api.gateway",version:"2.0",fcId:"240417431173407785",fcGroup:"fl-images",uploadUrlFunction:"uploadByTokenUrl",prefix:"temp",region:"CN"},FLIGGY_LAYER_URL_PROXY={sourceHostPrefix:"edith.",pathPrefix:"/proxy/",targetHostSuffixes:["wapa.taobao.com"],defaultTargetHost:"market.wapa.taobao.com"},FLIGGY_ROOT_CONTAINER={statusBarHeightCookie:{name:"_fli_barHeight",domain:"taobao.com",path:"/"}},FLIGGY_TITLE_BAR_HIDDEN_PATHNAMES=["/app/trip/rx-home/pages/home","/app/trip/rx-trip-ai/pages/home"],FLIGGY_STATUS_BAR_BACKGROUND_COLORS={"/app/trip/rx-home/pages/home":"#fff","/app/trip/rx-trip-ai/pages/home":"#dbdbff"};function emptyActions(){return{open:[],close:[],title:[],navigationBar:[],statusBar:[],systemInfo:[],mtop:[],kvGet:[],kvSet:[],kvDelete:[],pageContext:[],responses:{},behaviors:{},noop:[],silent:[]}}function mergeActions(...maps){let out=emptyActions();for(let m of maps)out.open.push(...m.open),out.close.push(...m.close),out.title.push(...m.title),out.navigationBar.push(...m.navigationBar??[]),out.statusBar.push(...m.statusBar??[]),out.systemInfo.push(...m.systemInfo),out.mtop.push(...m.mtop),out.kvGet.push(...m.kvGet??[]),out.kvSet.push(...m.kvSet??[]),out.kvDelete.push(...m.kvDelete??[]),out.pageContext.push(...m.pageContext??[]),Object.assign(out.responses,m.responses??{}),Object.assign(out.behaviors,m.behaviors??{}),out.noop.push(...m.noop),out.silent.push(...m.silent??[]);return out}var APP_BRIDGE_BEHAVIORS=["navigate","closeAll","closeBackData","postMessage","notifySubscribe","notifyUnsubscribe","notifyPost","sharedFileRead","sharedFileWrite","sharedDataGet","sharedDataSet","legacyBroadcastCreate","legacyBroadcastPost","legacyBroadcastClose","memoryGet","memorySet","memoryDelete","availabilityMap","userInfo","networkInfo","geolocation","permission","prefetch","fptTrack","mtopStream","previewFile","toast","unsupportedNativeInput","payment","userTrack","calendar","networkQualityMonitor","beaconRequest"],APP_BRIDGE_BEHAVIOR_SET=new Set(APP_BRIDGE_BEHAVIORS),BRIDGE_ACTION_ARRAY_KEYS=["open","close","title","navigationBar","statusBar","systemInfo","mtop","kvGet","kvSet","kvDelete","pageContext","noop"];function isJsonValue2(value,seen=new Set){if(value===null||typeof value=="string"||typeof value=="boolean")return!0;if(typeof value=="number")return Number.isFinite(value);if(typeof value!="object"||seen.has(value))return!1;seen.add(value);let valid=Array.isArray(value)?value.every(item=>isJsonValue2(item,seen)):Object.values(value).every(item=>isJsonValue2(item,seen));return seen.delete(value),valid}function validateAppBridgeConfig(value){if(!value||typeof value!="object"||Array.isArray(value))throw new Error("bridgeConfig must be an object");let root=value;if(Object.keys(root).some(key=>key!=="methods"))throw new Error('bridgeConfig only supports the "methods" field');if(!root.methods||typeof root.methods!="object"||Array.isArray(root.methods))throw new Error("bridgeConfig.methods must be an object");let entries=Object.entries(root.methods);if(entries.length>200)throw new Error("bridgeConfig supports at most 200 methods");let methods2={};for(let[method,rawConfig]of entries){if(!method.trim()||method.length>200)throw new Error("bridgeConfig method names must contain 1-200 characters");if(method==="__proto__"||method==="prototype"||method==="constructor")throw new Error(`bridgeConfig method name "${method}" is reserved`);if(!rawConfig||typeof rawConfig!="object"||Array.isArray(rawConfig))throw new Error(`bridgeConfig.methods.${method} must be an object`);let methodConfig=rawConfig,supportedKeys=new Set(["behavior","response","noop","silent"]);if(Object.keys(methodConfig).some(key=>!supportedKeys.has(key)))throw new Error(`bridgeConfig.methods.${method} contains an unsupported field`);if("behavior"in methodConfig&&typeof methodConfig.behavior!="string")throw new Error(`bridgeConfig.methods.${method}.behavior must be a string`);let hasBehavior=typeof methodConfig.behavior=="string",hasResponse=Object.prototype.hasOwnProperty.call(methodConfig,"response"),hasNoop=methodConfig.noop===!0;if(Number(hasBehavior)+Number(hasResponse)+Number(hasNoop)!==1)throw new Error(`bridgeConfig.methods.${method} must define exactly one of behavior, response, or noop=true`);if(hasBehavior&&!APP_BRIDGE_BEHAVIOR_SET.has(methodConfig.behavior))throw new Error(`bridgeConfig.methods.${method} has an unsupported behavior`);if(hasResponse&&!isJsonValue2(methodConfig.response))throw new Error(`bridgeConfig.methods.${method}.response must be valid JSON data`);if("noop"in methodConfig&&methodConfig.noop!==!0)throw new Error(`bridgeConfig.methods.${method}.noop must be true when provided`);if("silent"in methodConfig&&typeof methodConfig.silent!="boolean")throw new Error(`bridgeConfig.methods.${method}.silent must be a boolean`);methods2[method]={...hasBehavior&&{behavior:methodConfig.behavior},...hasResponse&&{response:JSON.parse(JSON.stringify(methodConfig.response))},...hasNoop&&{noop:!0},...methodConfig.silent===!0&&{silent:!0}}}let normalized={methods:methods2};if(JSON.stringify(normalized).length>65536)throw new Error("bridgeConfig must not exceed 64 KiB");return normalized}function applyAppBridgeConfig(actions,config2){let out=mergeActions(actions);if(!config2)return out;let{methods:methods2}=validateAppBridgeConfig(config2);for(let[method,methodConfig]of Object.entries(methods2)){for(let key of BRIDGE_ACTION_ARRAY_KEYS){let values=out[key];values&&(out[key]=values.filter(value=>value!==method))}out.silent=(out.silent??[]).filter(value=>value!==method),delete out.responses?.[method],delete out.behaviors?.[method],methodConfig.behavior?out.behaviors[method]=methodConfig.behavior:Object.prototype.hasOwnProperty.call(methodConfig,"response")?out.responses[method]=methodConfig.response:methodConfig.noop&&out.noop.push(method),methodConfig.silent&&out.silent.push(method)}return out}var WV_ACTIONS={open:["WVNative.openWindow","Base.openBrowser","EtaoJsbridgeUtil.openWindow","TMBridge.pushWindow","Third.openThirdWeb"],close:["WebAppInterface.pop","Triver.pop","TMBridge.popWindow","EleWVHybridAPI.popWindow","Third.closeWebView"],title:["WebAppInterface.setCustomPageTitle"],navigationBar:["Triver.setNavigationBarStyle"],statusBar:["WebAppInterface.setStatusBarStyle","Application.setStatusBarStyle"],systemInfo:["WVNativeDetector.getModelInfo"],mtop:["MtopWVPlugin.send"],behaviors:{"WVLocation.getLocation":"geolocation","WVNetwork.getNetworkType":"networkInfo","WVFile.read":"sharedFileRead","WVFile.write":"sharedFileWrite","SharedData.getSharedData":"sharedDataGet","SharedData.setSharedData":"sharedDataSet","WVBroadcast.createChannel":"legacyBroadcastCreate","WVBroadcast.postMessage":"legacyBroadcastPost","WVBroadcast.close":"legacyBroadcastClose"},noop:["WVNative.enableHookNativeBack","WVNative.forbidPanGesture","WVNative.setGestureBack","WVTBUserTrack.toUT","WVTBUserTrack.toUT2"],silent:["WVNetwork.getNetworkType","WVNativeDetector.getModelInfo","WVTBUserTrack.toUT","WVTBUserTrack.toUT2"]},COMMON_SCHEME_RULES=[{match:"page:",param:"params"},{match:"taobaotravel:",param:"params"},{match:"alipays://platformapi/starth5app",param:"url"},{match:"alipays://platformapi/startapp",param:"page"},{match:"eleme://web",param:"url"},{match:"amapuri://webview/",param:"url"}],FEIZHU_WECHAT_HOST_SUFFIXES=["feizhu.com"],WECHAT_SCHEME_RULES=[{match:"/pages/main/webview",hostSuffixes:FEIZHU_WECHAT_HOST_SUFFIXES,param:"url",useCurrentOrigin:!0},...COMMON_SCHEME_RULES],WECHAT_MINI_PROGRAM={paymentRoutes:[{pathname:"/pages/utils/common-pay/index",hostSuffixes:FEIZHU_WECHAT_HOST_SUFFIXES,paymentParamsParam:"signStr",successUrlParams:["backUrl","successUrl"],failureUrlParams:["unSuccessUrl","errorUrl"],successResultParam:"__paymentRes",forwardParams:["ttid"],useCurrentOrigin:!0}],nativeRoutes:[{pathname:"/pages/utils/webview-bridge/index",hostSuffixes:FEIZHU_WECHAT_HOST_SUFFIXES,actions:["navigateMiniProgram","subscribeMessage"]}],messageRules:[{type:"BACK_DATA",action:"stageBackData",hostSuffixes:FEIZHU_WECHAT_HOST_SUFFIXES},{type:"BACK_MINI_APP",action:"closeAll",hostSuffixes:FEIZHU_WECHAT_HOST_SUFFIXES}]},WECHAT_TITLE_BAR_HOST_STYLES=[{hostSuffix:"feizhu.com",titleBarBackgroundColor:"#ffe033",statusBarBackgroundColor:"#ffe033"}],FLIGGY_SCHEME_RULES=[{match:"fliggy://order/detail",targetPath:"/app/trip/rx-flight-detail/pages/index",targetHostPrefix:"market",targetParams:{titleBarHidden:"2"}},...COMMON_SCHEME_RULES],WV_ACTIVE_EVENTS=["WV.Event.APP.Active"],FLIGGY_AI_UI_NOOPS=["handleLiveActivity","ai_ask_scroll_position","ai_ask_input_status","ai_ask_set_keyboard_tags","ai_ask_h5_awaken_input","ai_ask_reset_input","ai_ask_hide_input","home_ai_page_scroll","ai_ask_hide_keyboard","ai_ask_clear_keyboard_tags","ai_ask_init_mask","ai_ask_hide_mask","ai_ask_transfer_to_wenwen","ai_ask_transfer_to_mask","close_loading_view","open_loading_view","set_ai_ask_container_status","to_set_notifaction","home_refresh","ai_ask_page_load_success","ai_ask_set_session_info","ai_ask_input_set_mention_url","ai_ask_input_set_scene","ai_float_brain_panel_back_to_top_panel_page","ai_float_brain_panel_set_tools"],APP_PROFILES={fliggy:{name:"fliggy",label:"飞猪",appName:"LX",defaultAppVersion:"10.0.0",uaTokens:["AliTrip/{v}",WINDVANE],globals:{},bridges:[WV_BRIDGE,{global:"alitripBridge",style:"fliggy"},{global:"core",style:"fliggy"},{global:"methodChannel",style:"callback"}],activeEvents:WV_ACTIVE_EVENTS,actions:mergeActions(WV_ACTIONS,{...emptyActions(),open:["goto","ai_float_brain_panel_collapse_and_open_url"],close:[],title:["set_webview_title"],navigationBar:["set_ui"],statusBar:["set_status_bar_style"],systemInfo:["client_info"],kvGet:["get_kvcache"],kvSet:["set_kvcache"],kvDelete:["del_kvcache"],pageContext:["ai_float_brain_panel_get_page_context"],responses:{is_open_push:{is_open:!1},get_unread_message:{style:"POINT",count:0},get_v10_ab_info:{v10Version:!0},get_ai_ask_container_status:{status:"FULL"},ai_ask_get_keyboard_height:{height:0},get_idfa:{},get_caid:{},get_theme_conf:{},cppay_app_install:{result:""}},behaviors:{"page://goto":"navigate","page://close":"closeBackData",back:"closeBackData",user_info:"userInfo",ai_ask_get_memory_cache:"memoryGet",ai_ask_set_memory_cache:"memorySet",ai_ask_del_memory_cache:"memoryDelete",channelJudgeJsBridge:"availabilityMap",networktype:"networkInfo",network_quality_monitor:"networkQualityMonitor",request:"beaconRequest",store_calendar_event:"calendar",remove_calendar_event:"calendar",check_batch_calendar:"calendar",search_batch_calendar_events:"calendar",lbs:"geolocation",permission:"permission",cacheFetch:"prefetch",fptTrack:"fptTrack",toUT:"userTrack","WVTBUserTrack.toUT":"userTrack","WVTBUserTrack.toUT2":"userTrack",mtop_stream:"mtopStream",ai_ask_preview_file:"previewFile",toast:"toast",ai_ask_input_bridge:"unsupportedNativeInput",cppay:"payment",minipay:"payment",union_pay:"payment"},noop:["swipe_back","track_error_with_alarm","cacheUpdate","long_press_save_image",...FLIGGY_AI_UI_NOOPS],silent:["native://biz/mtop_normal_sign","toUT","get_idfa","get_caid","channelJudgeJsBridge","get_unread_message","get_v10_ab_info","lbs","networktype","network_quality_monitor","request","long_press_save_image","set_status_bar_style","get_theme_conf","cacheFetch","cppay_app_install","track_error_with_alarm",...FLIGGY_AI_UI_NOOPS]}),schemes:FLIGGY_SCHEME_RULES,imagePicker:FLIGGY_IMAGE_PICKER,geolocation:{reverseGeocodeApi:"mtop.trip.common.getCityCodeByLatitudeAndLongitude",version:"1.0"},layerUrlProxy:FLIGGY_LAYER_URL_PROXY,rootContainer:FLIGGY_ROOT_CONTAINER,titleBarHiddenPathnames:FLIGGY_TITLE_BAR_HIDDEN_PATHNAMES,statusBarBackgroundColors:FLIGGY_STATUS_BAR_BACKGROUND_COLORS,urlSyncHostSuffixes:["m.taobao.com","wapa.taobao.com"],overlay:FLIGGY_OVERLAY,popBeforeOpenParam:"_fli_popBeforeOpen",nativeBack:FLIGGY_NATIVE_BACK,forceH5Mtop:!0},taobao:{name:"taobao",label:"手机淘宝",appName:"TB",defaultAppVersion:"10.65.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE,MEGA_BRIDGE],activeEvents:WV_ACTIVE_EVENTS,actions:WV_ACTIONS,schemes:COMMON_SCHEME_RULES,overlay:TAOBAO_OVERLAY,nativeBack:WV_NATIVE_BACK},wechat:{name:"wechat",label:"微信",appName:"WeChat",defaultAppVersion:"8.0.58",uaFamily:"wechatMiniProgram",uaTokens:[],globals:{__wxjs_environment:"miniprogram"},bridges:[{global:"wx",style:"wechat"},{global:"wx.miniProgram",style:"wechatMiniProgram",persistent:!0}],activeEvents:[],actions:{...emptyActions(),open:["navigateTo","redirectTo","switchTab","reLaunch"],close:["navigateBack"],behaviors:{postMessage:"postMessage",getLocation:"geolocation"}},schemes:WECHAT_SCHEME_RULES,miniProgram:WECHAT_MINI_PROGRAM,titleBarHostStyles:WECHAT_TITLE_BAR_HOST_STYLES},tmall:{name:"tmall",label:"天猫",appName:"TM",defaultAppVersion:"15.22.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE],activeEvents:WV_ACTIVE_EVENTS,actions:WV_ACTIONS,schemes:COMMON_SCHEME_RULES,nativeBack:WV_NATIVE_BACK},alipay:{name:"alipay",label:"支付宝",appName:"AP",defaultAppVersion:"10.8.0",uaTokens:["AlipayClient/{v}"],globals:{},bridges:[{global:"AlipayJSBridge",style:"alipay"}],activeEvents:[],actions:{open:["pushWindow","startApp"],close:["popWindow"],title:["setTitle"],navigationBar:["hideBackButton","showBackButton"],systemInfo:["getSystemInfo"],mtop:[],behaviors:{getNetworkType:"networkInfo",addNotifyListener:"notifySubscribe",removeNotifyListener:"notifyUnsubscribe",postNotification:"notifyPost"},noop:["postWebViewMessage","setGestureBack"],silent:["getNetworkType"]},schemes:COMMON_SCHEME_RULES,nativeBack:ALIPAY_NATIVE_BACK},koubei:{name:"koubei",label:"口碑",appName:"KB",defaultAppVersion:"9.5.0",uaTokens:["KoubeiClient/{v}"],globals:{},bridges:[{global:"AlipayJSBridge",style:"alipay"}],activeEvents:[],actions:{open:["pushWindow","startApp"],close:["popWindow"],title:["setTitle"],navigationBar:["hideBackButton","showBackButton"],systemInfo:["getSystemInfo"],mtop:[],behaviors:{getNetworkType:"networkInfo",addNotifyListener:"notifySubscribe",removeNotifyListener:"notifyUnsubscribe",postNotification:"notifyPost"},noop:["postWebViewMessage","setGestureBack"],silent:["getNetworkType"]},schemes:COMMON_SCHEME_RULES,nativeBack:ALIPAY_NATIVE_BACK},"taobao-tj":{name:"taobao-tj",label:"淘宝特价版",appName:"LT",defaultAppVersion:"10.32.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE],activeEvents:WV_ACTIVE_EVENTS,actions:WV_ACTIONS,schemes:COMMON_SCHEME_RULES,nativeBack:WV_NATIVE_BACK},"taobao-live":{name:"taobao-live",label:"淘宝直播",appName:"TAOBAOLIVEAPP",defaultAppVersion:"3.10.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE],activeEvents:WV_ACTIVE_EVENTS,actions:WV_ACTIONS,schemes:COMMON_SCHEME_RULES,nativeBack:WV_NATIVE_BACK},xianyu:{name:"xianyu",label:"闲鱼",appName:"FM",defaultAppVersion:"7.15.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE],activeEvents:WV_ACTIVE_EVENTS,actions:WV_ACTIONS,schemes:COMMON_SCHEME_RULES,nativeBack:WV_NATIVE_BACK},etao:{name:"etao",label:"一淘",appName:"ET",defaultAppVersion:"9.27.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE],activeEvents:WV_ACTIVE_EVENTS,actions:WV_ACTIONS,schemes:COMMON_SCHEME_RULES,nativeBack:WV_NATIVE_BACK},eleme:{name:"eleme",label:"饿了么",appName:"ELMC",defaultAppVersion:"11.12.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE],activeEvents:WV_ACTIVE_EVENTS,actions:WV_ACTIONS,schemes:COMMON_SCHEME_RULES,nativeBack:WV_NATIVE_BACK},damai:{name:"damai",label:"大麦",appName:"DM",defaultAppVersion:"8.9.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE],activeEvents:WV_ACTIVE_EVENTS,actions:WV_ACTIONS,schemes:COMMON_SCHEME_RULES,nativeBack:WV_NATIVE_BACK},btrip:{name:"btrip",label:"阿里商旅",appName:"BLX",defaultAppVersion:"9.12.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE,{global:"methodChannel",style:"btrip"}],activeEvents:WV_ACTIVE_EVENTS,actions:mergeActions(WV_ACTIONS,{...emptyActions(),open:["goto"],behaviors:{back:"closeBackData"}}),schemes:COMMON_SCHEME_RULES,nativeBack:WV_NATIVE_BACK},amap:{name:"amap",label:"高德地图",appName:"amap",defaultAppVersion:"13.8.0",uaTokens:[],globals:{},bridges:[{global:"AmapApp.bridge",style:"amap"}],activeEvents:[],actions:{open:["loadSchema","infoH5JsAction"],close:[],title:["setWebViewTitle"],systemInfo:[],mtop:[],noop:["interceptNativeBackEvent"]},schemes:COMMON_SCHEME_RULES,nativeBack:{handler:"onNativeBackEvent"}},qianwen:{name:"qianwen",label:"千问",appName:"TONGYI",defaultAppVersion:"3.20.0",uaTokens:[],globals:{},bridges:[{global:"ucapi",style:"invoke"}],activeEvents:[],actions:{open:["biz.openPageUrl","webdialog.show"],close:["biz.closeWebPage","webdialog.pop"],title:[],systemInfo:[],mtop:[],behaviors:{"base.postmessage":"postMessage","biz.popToRootWindow":"closeAll","biz.popToTopChatWindow":"closeAll"},noop:[]},schemes:COMMON_SCHEME_RULES,messageEvent:"QKEVT_OnReceiveMessage"},lingyou:{name:"lingyou",label:"翎游",appName:"hongtu",defaultAppVersion:"1.5.0",uaTokens:["hongtu/{v}"],globals:{},bridges:[{global:"WKWebViewJavascriptBridge",style:"callHandler"},{global:"WebViewJavascriptBridge",style:"callHandler"}],activeEvents:[],actions:{...emptyActions(),open:["jumpPage"],close:["closePage"],title:["setPageTitle"]},schemes:COMMON_SCHEME_RULES},didi:{name:"didi",label:"滴滴出行",appName:"didi.passenger",defaultAppVersion:"6.9.0",uaTokens:["didi.passenger/{v}"],globals:{},bridges:[{global:"didiBridge",style:"didi"},{global:"Fusion",style:"didi"}],activeEvents:[],actions:{...emptyActions(),open:["openPage"],close:["closePage"]},schemes:COMMON_SCHEME_RULES},easybike:{name:"easybike",label:"易到用车",appName:"easybike",defaultAppVersion:"9.0.0",uaTokens:["app=easybike;"],globals:{},bridges:[{global:"webkit.messageHandlers.callNative",style:"easybikeNative"},{global:"AppFunctions",style:"easybikeNative"}],activeEvents:[],actions:mergeActions(WV_ACTIONS,{...emptyActions(),close:["business/hitch.closeWebView"]}),schemes:COMMON_SCHEME_RULES}};function buildAppProfileUa(profile,options={}){let os11=options.os??(options.devicePreset?DEVICE_PRESETS[options.devicePreset]?.appProfileOs:void 0)??"ios",version2=options.appVersion??profile.defaultAppVersion,deviceModel=options.deviceModel??(options.devicePreset?DEVICE_PRESETS[options.devicePreset]?.appProfileModel:void 0)??"Pixel 11";if(profile.uaFamily==="wechatMiniProgram")return os11==="android"?`Mozilla/5.0 (Linux; Android 17; ${deviceModel}; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/152.0.0.0 Mobile MicroMessenger/${version2} WeChat/arm64 NetType/WIFI Language/zh_CN miniProgram`:`Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/${version2} NetType/WIFI Language/zh_CN miniProgram`;let tokens=profile.uaTokens.map(t=>t.replaceAll("{v}",version2)).filter(Boolean),tail=tokens.length>0?` ${tokens.join(" ")}`:"";return os11==="android"?`Mozilla/5.0 (Linux; Android 17; ${deviceModel}) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/152.0.0.0 Mobile Safari/537.36 AliApp(${profile.appName}/${version2})${tail}`:`Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) AliApp(${profile.appName}/${version2})${tail}`}function resolveAppProfile(name,options={}){let profile=APP_PROFILES[name];if(!profile)throw new Error(`Unknown app profile "${name}". Available: ${Object.keys(APP_PROFILES).join(", ")}`);let os11=options.os??(options.devicePreset?DEVICE_PRESETS[options.devicePreset]?.appProfileOs:void 0)??"ios",version2=options.appVersion??profile.defaultAppVersion,recommendedPreset=os11==="android"?"pixel-11":"iphone-17-pro",devicePreset=options.devicePreset??recommendedPreset,emulation=resolveEmulationConfig({enabled:!0,preset:devicePreset,orientation:options.orientation}),deviceModel=options.deviceModel??DEVICE_PRESETS[devicePreset].appProfileModel,globals={...profile.globals,__APP_NAME__:profile.appName,__APP_VERSION__:version2,__FLI_DEVICE_MODEL__:deviceModel,__DEVICE_MODEL__:deviceModel},ua=buildAppProfileUa(profile,{...options,os:os11,deviceModel});return{profile:profile.name,label:profile.label,ua,injected:{profile:profile.name,label:profile.label,globals,bridges:profile.bridges,activeEvents:profile.activeEvents,maxTouchPoints:5,statusBarHeight:emulation.safeAreaInsets.top,safeAreaInsets:emulation.safeAreaInsets,deviceAppearance:{preset:devicePreset,orientation:emulation.orientation,cutout:emulation.appearance.cutout},language:"zh-Hans",userAgent:ua,navigatorPlatform:os11==="android"?"Linux armv8l":"iPhone",platform:os11==="android"?"Android":"iOS",systemVersion:os11==="android"?"17":"26.0",clientType:os11==="android"?"android":"iphone",actions:applyAppBridgeConfig(profile.actions,options.bridgeConfig),schemes:profile.schemes,...profile.miniProgram&&{miniProgram:profile.miniProgram},...profile.imagePicker&&{imagePicker:profile.imagePicker},...profile.geolocation&&{geolocation:profile.geolocation},...profile.overlay&&{overlay:profile.overlay},...profile.popBeforeOpenParam&&{popBeforeOpenParam:profile.popBeforeOpenParam},...profile.messageEvent&&{messageEvent:profile.messageEvent},...profile.nativeBack&&{nativeBack:profile.nativeBack},...profile.layerUrlProxy&&{layerUrlProxy:profile.layerUrlProxy},...profile.urlSyncHostSuffixes&&{urlSyncHostSuffixes:profile.urlSyncHostSuffixes},...profile.forceH5Mtop&&{forceH5Mtop:!0},simulateSystemBars:!1,rootContainer:{enabled:!1,...profile.rootContainer?.statusBarHeightCookie&&{initialCookies:[{...profile.rootContainer.statusBarHeightCookie,value:String(emulation.safeAreaInsets.top)}]}},titleBar:{navigationBarHeight:os11==="android"?48:44,backgroundColor:"#ffffff",textColor:"#0f131a",...profile.titleBarHiddenPathnames&&{hiddenPathnames:profile.titleBarHiddenPathnames},...profile.statusBarBackgroundColors&&{statusBarBackgroundColors:profile.statusBarBackgroundColors},...profile.titleBarHostStyles&&{hostStyles:profile.titleBarHostStyles}}},recommendedPreset}}function installAppProfileEnvironment(config2){let w=window;if(w.__mearlAppProfile__)return null;w.__mearlAppProfile__=config2.profile;let SRC="mearl-app-bridge",TAG=`[AppBridge:${config2.label}]`,ROOT_FRAME_NAME="__mearl_root__",LAYER_FRAME_NAME="__mearl_layer__",isTop=window===window.top,isRootFrame=!isTop&&window.name===ROOT_FRAME_NAME,isLayerFrame=!isTop&&window.name===LAYER_FRAME_NAME,isContainerFrame=isTop||isRootFrame||isLayerFrame,usesRootContainer=isTop&&config2.rootContainer?.enabled===!0,simulateSystemBars=config2.simulateSystemBars!==!1,safeAreaInsets=config2.safeAreaInsets??{top:config2.statusBarHeight,right:0,bottom:0,left:0},log2=(...args)=>console.info(TAG,...args);for(let[key,value]of Object.entries(config2.globals))try{w[key]=value}catch{}typeof w.__STATUS_BAR_HEIGHT__!="number"&&(w.__STATUS_BAR_HEIGHT__=config2.statusBarHeight),typeof w.__SAFE_AREA_INSET_BOTTOM__!="number"&&(w.__SAFE_AREA_INSET_BOTTOM__=safeAreaInsets.bottom);let applySafeAreaCssVariables=()=>{let root=document.documentElement;if(!root)return!1;try{return root.style.setProperty("--safe-area-inset-top",`${safeAreaInsets.top}px`),root.style.setProperty("--safe-area-inset-right",`${safeAreaInsets.right}px`),root.style.setProperty("--safe-area-inset-bottom",`${safeAreaInsets.bottom}px`),root.style.setProperty("--safe-area-inset-left",`${safeAreaInsets.left}px`),!0}catch{return!1}};if(!applySafeAreaCssVariables()){let observer=new MutationObserver(()=>{applySafeAreaCssVariables()&&observer.disconnect()});observer.observe(document,{childList:!0})}if(config2.forceH5Mtop){let downstreamMtopParamsHandler=w.MTOP_PARAMS_HANDLER,forceH5Mtop=params=>{let resolved=params;if(typeof downstreamMtopParamsHandler=="function")try{resolved=downstreamMtopParamsHandler.call(window,params)??params}catch{resolved=params}return{...resolved&&typeof resolved=="object"?resolved:{},useNative:!1}};try{Object.defineProperty(w,"MTOP_PARAMS_HANDLER",{configurable:!0,get:()=>forceH5Mtop,set:handler=>{handler!==forceH5Mtop&&(downstreamMtopParamsHandler=handler)}})}catch{w.MTOP_PARAMS_HANDLER=forceH5Mtop}}for(let[key,value]of[["userAgent",config2.userAgent],["platform",config2.navigatorPlatform],["vendor","Apple Computer, Inc."],["appVersion",config2.userAgent.replace(/^Mozilla\//,"")]])try{Object.defineProperty(navigator,key,{get:()=>value,configurable:!0})}catch{}try{Object.defineProperty(navigator,"maxTouchPoints",{get:()=>config2.maxTouchPoints})}catch{}return{w,SRC,TAG,ROOT_FRAME_NAME,LAYER_FRAME_NAME,isTop,isRootFrame,isLayerFrame,isContainerFrame,usesRootContainer,simulateSystemBars,safeAreaInsets,log:log2}}function installAppProfileSystemBars(config2,environment,host){let{SRC,isTop,isContainerFrame,simulateSystemBars,safeAreaInsets}=environment,externalDeviceChrome=config2.externalDeviceChrome===!0,titleBarMode="auto",titleBarRoot=null,titleBarSpacer=null,systemStatusView=null,systemBottomRoot=null,systemBottomSurface=null,rootTitleBarView=null,titleBarTitleVisible=!0,titleBarBackVisible=!0,titleBarBackground=config2.titleBar?.backgroundColor??"#ffffff",titleBarTextColor=config2.titleBar?.textColor??"#111111",titleBarStateExplicit=!1,presentedRootTitleBarState=null,normalizeProxyPathPrefix=prefix=>{let withLeadingSlash=prefix.startsWith("/")?prefix:`/${prefix}`;return withLeadingSlash.endsWith("/")?withLeadingSlash:`${withLeadingSlash}/`},matchesProxyTarget=(hostname3,suffixes)=>suffixes.some(suffix=>hostname3===suffix||hostname3.endsWith(`.${suffix}`)),normalizePathname=pathname=>{let withLeadingSlash=pathname.startsWith("/")?pathname:`/${pathname}`;return withLeadingSlash.length>1&&withLeadingSlash.endsWith("/")?withLeadingSlash.slice(0,-1):withLeadingSlash},businessPathname=href=>{try{let current=new URL(href,location.href),proxy=config2.layerUrlProxy;if(!proxy)return normalizePathname(current.pathname);let prefix=normalizeProxyPathPrefix(proxy.pathPrefix);if(!current.pathname.startsWith(prefix))return normalizePathname(current.pathname);let rest=current.pathname.slice(prefix.length),slash=rest.indexOf("/"),hostName=slash===-1?rest:rest.slice(0,slash),pathname=slash===-1?"/":rest.slice(slash),hostname3=new URL(`${current.protocol}//${hostName}`).hostname;return matchesProxyTarget(hostname3,proxy.targetHostSuffixes)?normalizePathname(pathname):normalizePathname(current.pathname)}catch{return null}},matchesConfiguredPathname=(href,pathnames)=>{let pathname=businessPathname(href);return pathname!==null&&pathnames.some(configuredPathname=>normalizePathname(configuredPathname)===pathname)},configuredHostStyle=(href=location.href)=>{try{let hostname3=new URL(href,location.href).hostname.toLowerCase();return(config2.titleBar?.hostStyles??[]).find(rule=>{let suffix=rule.hostSuffix.trim().replace(/^\.+/,"").toLowerCase();return suffix!==""&&(hostname3===suffix||hostname3.endsWith(`.${suffix}`))})}catch{return}},configuredTitleBarBackground=(href,fallback)=>configuredHostStyle(href)?.titleBarBackgroundColor??fallback,supportsWindVaneNavigationMeta=config2.bridges.some(bridge=>bridge.style==="windvane"),isTruthyParam=value=>value==="1"||value?.toLowerCase()==="true"||value?.toUpperCase()==="YES",isTransparentColor=value=>{let normalized=value.replace(/\s/g,"").toLowerCase();return normalized==="transparent"||normalized==="#0000"||normalized==="#00000000"||normalized==="rgba(0,0,0,0)"},fixedContainerTitleBarMode=()=>config2.profile==="wechat"?"normal":null,pageRequestedTitleBarMode=(href=location.href,includeMeta=!0)=>{try{let params=new URL(href,location.href).searchParams,webviewOptions=new URLSearchParams(params.get("__webview_options__")??""),option=key=>params.get(key)??webviewOptions.get(key);if(config2.profile==="fliggy"||config2.profile==="taobao"){let hidden=option("titleBarHidden");if(hidden==="1")return"status-inset";if(hidden==="2")return"status"}if(config2.profile==="taobao"&&option("disableNav")?.toUpperCase()==="YES")return isTruthyParam(option("status_bar_transparent"))?"status":"status-inset";if(config2.profile==="alipay"||config2.profile==="koubei"){if(option("showTitleBar")?.toUpperCase()==="NO")return"status-inset";let transparentTitle=option("transparentTitle")?.toLowerCase();if(transparentTitle&&["always","auto","custom"].includes(transparentTitle))return"overlay"}let overlayParam=config2.overlay?.enabledParam;return overlayParam&&isTruthyParam(params.get(overlayParam))?"status":!includeMeta||!supportsWindVaneNavigationMeta?null:document.getElementById("WV.Meta.Nav.HideNavBar")?.getAttribute("value")==="HideStatusBar"?"status":null}catch{return null}},pageRequestsHiddenTitleBar=(href=location.href)=>matchesConfiguredPathname(href,config2.titleBar?.hiddenPathnames??[]),configuredStatusBarBackground=(href=location.href)=>{let colors=config2.titleBar?.statusBarBackgroundColors??{},pathname=businessPathname(href);return pathname===null?null:Object.entries(colors).find(([configuredPathname])=>normalizePathname(configuredPathname)===pathname)?.[1]??configuredHostStyle(href)?.statusBarBackgroundColor??null},pageRequestsHiddenStatusBar=(href=location.href)=>{try{let params=new URL(href,location.href).searchParams;return isTruthyParam(params.get("statusBarHidden"))||isTruthyParam(params.get("hideStatusBar"))?!0:/(?:^|&)showStatusBar=NO(?:&|$)/i.test(params.get("__webview_options__")??"")}catch{return!1}},resolveTitleBarMode=(href,fallback,includeMeta)=>{let fixedMode=fixedContainerTitleBarMode();if(fixedMode)return fixedMode;if(titleBarMode!=="auto")return titleBarMode;if(pageRequestsHiddenStatusBar(href))return"hidden";if(pageRequestsHiddenTitleBar(href))return"status-inset";let requestedMode=pageRequestedTitleBarMode(href,includeMeta);return requestedMode||fallback},resolveStatusBarBackground=(href,mode,navigationBarBackground)=>configuredStatusBarBackground(href)??(mode==="normal"||mode==="status-inset"?navigationBarBackground:"transparent"),ownTitleBarState=()=>{let mode=resolveTitleBarMode(location.href,"normal",!0),background=configuredTitleBarBackground(location.href,titleBarBackground);return{mode,title:document.title||config2.label,titleVisible:titleBarTitleVisible,backVisible:titleBarBackVisible,background,statusBarBackground:resolveStatusBarBackground(location.href,mode,background),textColor:titleBarTextColor}},initialLayerTitleBarState=url2=>{let mode=fixedContainerTitleBarMode()??(pageRequestsHiddenStatusBar(url2)?"hidden":pageRequestsHiddenTitleBar(url2)?"status-inset":pageRequestedTitleBarMode(url2,!1)??"normal"),background=configuredTitleBarBackground(url2,config2.titleBar?.backgroundColor??"#ffffff");return{mode,title:config2.label,titleVisible:!0,backVisible:!0,background,statusBarBackground:mode==="status-inset"?background:resolveStatusBarBackground(url2,mode,background),textColor:config2.titleBar?.textColor??"#111111"}},parseReportedTitleBarState=value=>{if(!value||typeof value!="object")return null;let state=value;return!["normal","overlay","status","status-inset","hidden"].includes(String(state.mode))||typeof state.title!="string"||typeof state.titleVisible!="boolean"||typeof state.backVisible!="boolean"||typeof state.background!="string"||typeof state.textColor!="string"?null:{...state,statusBarBackground:typeof state.statusBarBackground=="string"?state.statusBarBackground:state.mode==="normal"||state.mode==="status-inset"?String(state.background):"transparent"}},resolvedTitleBarState=layer=>layer?layer.titleBarState??initialLayerTitleBarState(layer.url):presentedRootTitleBarState??ownTitleBarState(),resolvedRootTitleBarState=(fallback=ownTitleBarState())=>presentedRootTitleBarState??(host.getRootFrame()?{...fallback,statusBarBackground:configuredHostStyle(location.href)?.statusBarBackgroundColor??config2.titleBar?.backgroundColor??"#ffffff"}:fallback),renderNavigationBarView=(view,state)=>{let visible=state.mode==="normal"||state.mode==="overlay";view.root.style.display=visible?"block":"none",view.surface.style.visibility=visible?"visible":"hidden",view.surface.style.background=state.mode==="overlay"?"transparent":state.background,view.surface.style.borderBottom="none",view.surface.style.color=state.textColor,view.title.textContent=state.title,view.title.style.display=state.titleVisible?"block":"none",view.back.style.display=state.backVisible?"flex":"none",view.back.style.color=state.textColor},topFullLayer=()=>{let layers=host.getLayers();for(let index=layers.length-1;index>=0;index-=1)if(!layers[index].overlay&&!layers[index].closing)return layers[index]},activeTitleBarState=()=>{let layer=topFullLayer();return layer?resolvedTitleBarState(layer):resolvedRootTitleBarState()},syncActiveSystemBars=()=>{let state=activeTitleBarState();if(externalDeviceChrome&&isTop&&window.postMessage({source:"mearl-app-profile-runtime",type:"device-chrome-state",state:{statusBarBackground:state.statusBarBackground,textColor:state.textColor,bridgeConfig:{profile:config2.profile,actions:config2.actions}}},"*"),systemStatusView){let visible=state.mode!=="hidden";systemStatusView.root.style.display=visible?"block":"none",systemStatusView.surface.style.visibility=visible?"visible":"hidden",systemStatusView.surface.style.background=state.statusBarBackground,systemStatusView.surface.style.color=state.textColor}systemBottomRoot&&systemBottomSurface&&(systemBottomRoot.style.display=safeAreaInsets.bottom>0?"block":"none",systemBottomSurface.style.color=state.textColor)},syncLayerViewport=(layer,state)=>{if(layer.overlay)return;if(!simulateSystemBars){layer.frame.style.top="0px",layer.frame.style.height="100%";return}let totalHeight=config2.statusBarHeight+(config2.titleBar?.navigationBarHeight??0),offset=state.mode==="normal"?totalHeight:state.mode==="status-inset"?config2.statusBarHeight:0;layer.frame.style.top=`${offset}px`,layer.frame.style.height=offset>0?`calc(100% - ${offset}px)`:"100%",layer.frame.setAttribute("data-mearl-app-viewport-mode",state.mode),layer.frame.style.setProperty("--mearl-app-navigation-bar-height",`${config2.titleBar?.navigationBarHeight??0}px`),layer.frame.style.opacity=state.mode==="status-inset"&&!layer.titleBarStateReady?"0":"1",layer.titleBarView&&renderNavigationBarView(layer.titleBarView,state),topFullLayer()===layer&&syncActiveSystemBars()},syncRootFrameViewport=state=>{let rootFrame=host.getRootFrame();if(!rootFrame)return;if(!simulateSystemBars){rootFrame.style.top="0px",rootFrame.style.height="100%";return}let totalHeight=config2.statusBarHeight+(config2.titleBar?.navigationBarHeight??0),offset=state.mode==="normal"?totalHeight:state.mode==="status-inset"?config2.statusBarHeight:0;rootFrame.style.top=`${offset}px`,rootFrame.style.height=offset>0?`calc(100% - ${offset}px)`:"100%",rootFrame.setAttribute("data-mearl-app-viewport-mode",state.mode),rootFrame.style.setProperty("--mearl-app-navigation-bar-height",`${config2.titleBar?.navigationBarHeight??0}px`),rootFrame.style.opacity=state.mode==="status-inset"&&presentedRootTitleBarState===null&&!rootFrame.hasAttribute("data-mearl-webview-ready")?"0":"1"},syncSimulatedTitleBar=()=>{let ownState=ownTitleBarState();if(!isTop){if(isContainerFrame){if(!titleBarStateExplicit&&document.readyState==="loading")return;window.top?.postMessage({source:SRC,type:"titleBarState",state:ownState,explicit:titleBarStateExplicit},"*")}return}if(!titleBarRoot||!titleBarSpacer||!rootTitleBarView)return;let rootFrame=host.getRootFrame();!rootFrame&&host.getLayers().length===0&&host.getClosingLayerCount()===0&&(presentedRootTitleBarState=ownState);let state=resolvedRootTitleBarState(ownState);renderNavigationBarView(rootTitleBarView,state);let spacerHeight=state.mode==="normal"?config2.statusBarHeight+(config2.titleBar?.navigationBarHeight??0):state.mode==="status-inset"?config2.statusBarHeight:0;titleBarSpacer.style.display=!rootFrame&&spacerHeight>0?"block":"none",titleBarSpacer.style.height=`${spacerHeight}px`,titleBarSpacer.style.minHeight=`${spacerHeight}px`,syncRootFrameViewport(state),syncActiveSystemBars()},applyNavigationBarState=(api,params)=>{titleBarStateExplicit=!0;let p=params&&typeof params=="object"?params:{},displayValue=p.titlebar_display??p.titlebarDisplay??p.titleBarDisplay,display=typeof displayValue=="string"?displayValue.toLowerCase():"";api==="hideBackButton"&&(titleBarBackVisible=!1),api==="showBackButton"&&(titleBarBackVisible=!0),display==="hide"&&(titleBarMode="status"),display==="show"&&(titleBarMode="normal"),(p.isImmersive===!0||p.isTransparent===!0)&&(titleBarMode="overlay"),p.isImmersive===!1&&p.isTransparent===!1&&(titleBarMode="normal"),typeof p.isTitleVisible=="boolean"&&(titleBarTitleVisible=p.isTitleVisible),typeof p.title=="string"&&(document.title=p.title),typeof p.backgroundColor=="string"&&(titleBarBackground=p.backgroundColor,isTransparentColor(p.backgroundColor)&&(titleBarMode="overlay")),typeof p.barTextStyle=="string"&&(titleBarTextColor=p.barTextStyle==="white"?"#ffffff":"#111111"),syncSimulatedTitleBar()},applyStatusBarState=params=>{titleBarStateExplicit=!0;let p=params&&typeof params=="object"?params:{},style=typeof p.style=="string"?p.style.toLowerCase():"";style&&(titleBarTextColor=style==="white"||style.includes("light")?"#ffffff":"#111111"),syncSimulatedTitleBar()},createNavigationBarView=(placement,onBack)=>{let titleBar=config2.titleBar,root=document.createElement("div");root.setAttribute("data-mearl-app-titlebar",config2.profile),root.setAttribute("data-mearl-titlebar-owner",placement),root.style.cssText=`${placement==="root"?"position:fixed":"position:absolute"};left:0;right:0;top:${config2.statusBarHeight}px;height:${titleBar.navigationBarHeight}px;z-index:${placement==="root"?"2147482900":"2"};overflow:hidden;box-sizing:border-box;font-family:"PingFang SC",-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;`;let shadow=root.attachShadow({mode:"open"});shadow.innerHTML=`<style>
|
|
597
|
+
`,RECORDING_BINDING_NAME="__mtopRecordReport",cdpRecordingSessions=new Map,RECORDING_MAX_REQUESTS=500,RECORDING_MAX_ACTIONS=1e3;async function cdpRecordStart(session,_data){if(cdpRecordingSessions.has(session.targetId))throw new Error(`Already recording on target ${session.targetId}. Call record_stop before starting a new recording.`);let pageClient=(await resolveCdpDeviceShellPageEndpoint(session)).client,recordingSession={targetId:session.targetId,startTime:Date.now(),startUrl:"",actions:[],client:pageClient};try{await pageClient.sendCommand("Runtime.addBinding",{name:RECORDING_BINDING_NAME})}catch(err){throw new Error(`Failed to register recording binding: ${err?.message??err}. CDP target may not support Runtime domain.`,{cause:err})}let nextSeq=1,onBindingCalled=params=>{if(params?.name===RECORDING_BINDING_NAME)try{let action=JSON.parse(params.payload);action.seq=nextSeq++,recordingSession.actions.push(action),recordingSession.actions.length>RECORDING_MAX_ACTIONS&&recordingSession.actions.splice(0,recordingSession.actions.length-RECORDING_MAX_ACTIONS)}catch{}};recordingSession.removeBindingListener=pageClient.on("Runtime.bindingCalled",onBindingCalled);try{let result=await pageClient.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source:RECORDING_INJECTED_SCRIPT});recordingSession.scriptIdentifier=result?.identifier}catch(err){throw recordingSession.removeBindingListener?.(),new Error(`Failed to register recording script: ${err?.message??err}.`,{cause:err})}try{let value=(await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:RECORDING_BOOTSTRAP_SCRIPT,returnByValue:!0})).result?.value??{};recordingSession.startUrl=value.startUrl??""}catch{recordingSession.startUrl=""}return cdpRecordingSessions.set(session.targetId,recordingSession),{recording:!0,tabId:session.targetId,startTime:recordingSession.startTime}}async function cdpRecordStop(session,_data){let recordingSession=cdpRecordingSessions.get(session.targetId);if(!recordingSession)return{wasRecording:!1,actions:[],requests:[],requestsTruncated:!1,duration:0,startUrl:"",endUrl:""};if(cdpRecordingSessions.delete(session.targetId),recordingSession.removeBindingListener?.(),recordingSession.scriptIdentifier)try{await recordingSession.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier:recordingSession.scriptIdentifier})}catch{}let endUrl="";try{endUrl=(await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:RECORDING_TEARDOWN_SCRIPT,returnByValue:!0})).result?.value?.endUrl??""}catch{}try{await recordingSession.client.sendCommand("Runtime.removeBinding",{name:RECORDING_BINDING_NAME})}catch{}let endTime=Date.now(),startTime=recordingSession.startTime,duration3=Math.round((endTime-startTime)/1e3),allRequests=session.buffers.requests.filter(r=>r.timestampMs>=startTime),requests=allRequests.length>RECORDING_MAX_REQUESTS?allRequests.slice(-RECORDING_MAX_REQUESTS):allRequests;return{wasRecording:!0,actions:annotateActionsWithRequests(recordingSession.actions,requests,endTime),requests:serializeRecordingRequests(requests),requestsTruncated:allRequests.length>RECORDING_MAX_REQUESTS,duration:duration3,startUrl:recordingSession.startUrl,endUrl}}async function releaseCdpRecordings(sessions){await Promise.allSettled(sessions.filter(session=>cdpRecordingSessions.has(session.targetId)).map(session=>cdpRecordStop(session,{})));for(let recordingSession of cdpRecordingSessions.values())recordingSession.removeBindingListener?.();cdpRecordingSessions.clear()}registerActions([{name:"record_start",session:"page",handler:cdpRecordStart},{name:"record_stop",session:"page",handler:cdpRecordStop}]);var WINDVANE="WindVane/8.7.0",WV_BRIDGE={global:"WindVane",style:"windvane"},MEGA_BRIDGE={global:"__megability_bridge__",style:"mega"},WV_NATIVE_BACK={event:"wvBackClickEvent",controlFunction:"_windvane_backControl"},FLIGGY_NATIVE_BACK={event:"WV.Back"},ALIPAY_NATIVE_BACK={event:"back"},FLIGGY_OVERLAY={enabledParam:"_fli_overlay",topRatioParam:"_fli_overlay_ratio",radiusParam:"_fli_overlay_radius",maskAlphaParam:"_fli_overlay_mask_alpha",tapCloseParam:"_fli_overlay_tap_close",tapCloseSelectors:["#qwen-titlebar .qwen-titlebar-icon-wrapper:last-child"],silentTapClose:!0,defaultTopRatio:.2,defaultRadius:0,defaultMaskAlpha:.3,defaultTapClose:!0},TAOBAO_OVERLAY={enabledParam:"useWebdialog",topRatioParam:"topRatio",heightRatioParam:"height_pct",radiusParam:"cornerRadius",maskAlphaParam:"maskAlpha",tapCloseParam:"tapEnable",tapCloseSelectors:["#qwen-titlebar .qwen-titlebar-icon-wrapper:last-child"],defaultTopRatio:.2,defaultRadius:6,defaultMaskAlpha:.5,defaultTapClose:!0},FLIGGY_IMAGE_PICKER={schemes:["page://ask_take_photo"],api:"mtop.trip.serverless.api.gateway",version:"2.0",fcId:"240417431173407785",fcGroup:"fl-images",uploadUrlFunction:"uploadByTokenUrl",prefix:"temp",region:"CN"},FLIGGY_LAYER_URL_PROXY={sourceHostPrefix:"edith.",pathPrefix:"/proxy/",targetHostSuffixes:["wapa.taobao.com"],defaultTargetHost:"market.wapa.taobao.com"},FLIGGY_ROOT_CONTAINER={statusBarHeightCookie:{name:"_fli_barHeight",domain:"taobao.com",path:"/"}},FLIGGY_TITLE_BAR_HIDDEN_PATHNAMES=["/app/trip/rx-home/pages/home","/app/trip/rx-trip-ai/pages/home"],FLIGGY_STATUS_BAR_BACKGROUND_COLORS={"/app/trip/rx-home/pages/home":"#fff","/app/trip/rx-trip-ai/pages/home":"#dbdbff"};function emptyActions(){return{open:[],close:[],title:[],navigationBar:[],statusBar:[],systemInfo:[],mtop:[],kvGet:[],kvSet:[],kvDelete:[],pageContext:[],responses:{},behaviors:{},noop:[],silent:[]}}function mergeActions(...maps){let out=emptyActions();for(let m of maps)out.open.push(...m.open),out.close.push(...m.close),out.title.push(...m.title),out.navigationBar.push(...m.navigationBar??[]),out.statusBar.push(...m.statusBar??[]),out.systemInfo.push(...m.systemInfo),out.mtop.push(...m.mtop),out.kvGet.push(...m.kvGet??[]),out.kvSet.push(...m.kvSet??[]),out.kvDelete.push(...m.kvDelete??[]),out.pageContext.push(...m.pageContext??[]),Object.assign(out.responses,m.responses??{}),Object.assign(out.behaviors,m.behaviors??{}),out.noop.push(...m.noop),out.silent.push(...m.silent??[]);return out}var APP_BRIDGE_BEHAVIORS=["navigate","closeAll","closeBackData","postMessage","notifySubscribe","notifyUnsubscribe","notifyPost","sharedFileRead","sharedFileWrite","sharedDataGet","sharedDataSet","legacyBroadcastCreate","legacyBroadcastPost","legacyBroadcastClose","memoryGet","memorySet","memoryDelete","availabilityMap","userInfo","networkInfo","geolocation","permission","prefetch","fptTrack","mtopStream","previewFile","toast","unsupportedNativeInput","payment","userTrack","calendar","networkQualityMonitor","beaconRequest","voiceRecognition"],APP_BRIDGE_BEHAVIOR_SET=new Set(APP_BRIDGE_BEHAVIORS),BRIDGE_ACTION_ARRAY_KEYS=["open","close","title","navigationBar","statusBar","systemInfo","mtop","kvGet","kvSet","kvDelete","pageContext","noop"];function isJsonValue2(value,seen=new Set){if(value===null||typeof value=="string"||typeof value=="boolean")return!0;if(typeof value=="number")return Number.isFinite(value);if(typeof value!="object"||seen.has(value))return!1;seen.add(value);let valid=Array.isArray(value)?value.every(item=>isJsonValue2(item,seen)):Object.values(value).every(item=>isJsonValue2(item,seen));return seen.delete(value),valid}function validateAppBridgeConfig(value){if(!value||typeof value!="object"||Array.isArray(value))throw new Error("bridgeConfig must be an object");let root=value;if(Object.keys(root).some(key=>key!=="methods"))throw new Error('bridgeConfig only supports the "methods" field');if(!root.methods||typeof root.methods!="object"||Array.isArray(root.methods))throw new Error("bridgeConfig.methods must be an object");let entries=Object.entries(root.methods);if(entries.length>200)throw new Error("bridgeConfig supports at most 200 methods");let methods2={};for(let[method,rawConfig]of entries){if(!method.trim()||method.length>200)throw new Error("bridgeConfig method names must contain 1-200 characters");if(method==="__proto__"||method==="prototype"||method==="constructor")throw new Error(`bridgeConfig method name "${method}" is reserved`);if(!rawConfig||typeof rawConfig!="object"||Array.isArray(rawConfig))throw new Error(`bridgeConfig.methods.${method} must be an object`);let methodConfig=rawConfig,supportedKeys=new Set(["behavior","response","noop","silent"]);if(Object.keys(methodConfig).some(key=>!supportedKeys.has(key)))throw new Error(`bridgeConfig.methods.${method} contains an unsupported field`);if("behavior"in methodConfig&&typeof methodConfig.behavior!="string")throw new Error(`bridgeConfig.methods.${method}.behavior must be a string`);let hasBehavior=typeof methodConfig.behavior=="string",hasResponse=Object.prototype.hasOwnProperty.call(methodConfig,"response"),hasNoop=methodConfig.noop===!0;if(Number(hasBehavior)+Number(hasResponse)+Number(hasNoop)!==1)throw new Error(`bridgeConfig.methods.${method} must define exactly one of behavior, response, or noop=true`);if(hasBehavior&&!APP_BRIDGE_BEHAVIOR_SET.has(methodConfig.behavior))throw new Error(`bridgeConfig.methods.${method} has an unsupported behavior`);if(hasResponse&&!isJsonValue2(methodConfig.response))throw new Error(`bridgeConfig.methods.${method}.response must be valid JSON data`);if("noop"in methodConfig&&methodConfig.noop!==!0)throw new Error(`bridgeConfig.methods.${method}.noop must be true when provided`);if("silent"in methodConfig&&typeof methodConfig.silent!="boolean")throw new Error(`bridgeConfig.methods.${method}.silent must be a boolean`);methods2[method]={...hasBehavior&&{behavior:methodConfig.behavior},...hasResponse&&{response:JSON.parse(JSON.stringify(methodConfig.response))},...hasNoop&&{noop:!0},...methodConfig.silent===!0&&{silent:!0}}}let normalized={methods:methods2};if(JSON.stringify(normalized).length>65536)throw new Error("bridgeConfig must not exceed 64 KiB");return normalized}function applyAppBridgeConfig(actions,config2){let out=mergeActions(actions);if(!config2)return out;let{methods:methods2}=validateAppBridgeConfig(config2);for(let[method,methodConfig]of Object.entries(methods2)){for(let key of BRIDGE_ACTION_ARRAY_KEYS){let values=out[key];values&&(out[key]=values.filter(value=>value!==method))}out.silent=(out.silent??[]).filter(value=>value!==method),delete out.responses?.[method],delete out.behaviors?.[method],methodConfig.behavior?out.behaviors[method]=methodConfig.behavior:Object.prototype.hasOwnProperty.call(methodConfig,"response")?out.responses[method]=methodConfig.response:methodConfig.noop&&out.noop.push(method),methodConfig.silent&&out.silent.push(method)}return out}var WV_ACTIONS={open:["WVNative.openWindow","Base.openBrowser","EtaoJsbridgeUtil.openWindow","TMBridge.pushWindow","Third.openThirdWeb"],close:["WebAppInterface.pop","Triver.pop","TMBridge.popWindow","EleWVHybridAPI.popWindow","Third.closeWebView"],title:["WebAppInterface.setCustomPageTitle"],navigationBar:["Triver.setNavigationBarStyle"],statusBar:["WebAppInterface.setStatusBarStyle","Application.setStatusBarStyle"],systemInfo:["WVNativeDetector.getModelInfo"],mtop:["MtopWVPlugin.send"],behaviors:{"WVLocation.getLocation":"geolocation","WVNetwork.getNetworkType":"networkInfo","WVFile.read":"sharedFileRead","WVFile.write":"sharedFileWrite","SharedData.getSharedData":"sharedDataGet","SharedData.setSharedData":"sharedDataSet","WVBroadcast.createChannel":"legacyBroadcastCreate","WVBroadcast.postMessage":"legacyBroadcastPost","WVBroadcast.close":"legacyBroadcastClose"},noop:["WVNative.enableHookNativeBack","WVNative.forbidPanGesture","WVNative.setGestureBack","WVTBUserTrack.toUT","WVTBUserTrack.toUT2"],silent:["WVNetwork.getNetworkType","WVNativeDetector.getModelInfo","WVTBUserTrack.toUT","WVTBUserTrack.toUT2"]},COMMON_SCHEME_RULES=[{match:"page:",param:"params"},{match:"taobaotravel:",param:"params"},{match:"alipays://platformapi/starth5app",param:"url"},{match:"alipays://platformapi/startapp",param:"page"},{match:"eleme://web",param:"url"},{match:"amapuri://webview/",param:"url"}],FEIZHU_WECHAT_HOST_SUFFIXES=["feizhu.com"],WECHAT_SCHEME_RULES=[{match:"/pages/main/webview",hostSuffixes:FEIZHU_WECHAT_HOST_SUFFIXES,param:"url",useCurrentOrigin:!0},...COMMON_SCHEME_RULES],WECHAT_MINI_PROGRAM={paymentRoutes:[{pathname:"/pages/utils/common-pay/index",hostSuffixes:FEIZHU_WECHAT_HOST_SUFFIXES,paymentParamsParam:"signStr",successUrlParams:["backUrl","successUrl"],failureUrlParams:["unSuccessUrl","errorUrl"],successResultParam:"__paymentRes",forwardParams:["ttid"],useCurrentOrigin:!0}],nativeRoutes:[{pathname:"/pages/utils/webview-bridge/index",hostSuffixes:FEIZHU_WECHAT_HOST_SUFFIXES,actions:["navigateMiniProgram","subscribeMessage"]}],messageRules:[{type:"BACK_DATA",action:"stageBackData",hostSuffixes:FEIZHU_WECHAT_HOST_SUFFIXES},{type:"BACK_MINI_APP",action:"closeAll",hostSuffixes:FEIZHU_WECHAT_HOST_SUFFIXES}]},WECHAT_TITLE_BAR_HOST_STYLES=[{hostSuffix:"feizhu.com",titleBarBackgroundColor:"#ffe033",statusBarBackgroundColor:"#ffe033"}],FLIGGY_SCHEME_RULES=[{match:"fliggy://order/detail",targetPath:"/app/trip/rx-flight-detail/pages/index",targetHostPrefix:"market",targetParams:{titleBarHidden:"2"}},...COMMON_SCHEME_RULES],WV_ACTIVE_EVENTS=["WV.Event.APP.Active"],FLIGGY_AI_UI_NOOPS=["handleLiveActivity","ai_ask_scroll_position","ai_ask_input_status","ai_ask_set_keyboard_tags","ai_ask_h5_awaken_input","ai_ask_reset_input","ai_ask_hide_input","home_ai_page_scroll","ai_ask_hide_keyboard","ai_ask_clear_keyboard_tags","ai_ask_init_mask","ai_ask_hide_mask","ai_ask_transfer_to_wenwen","ai_ask_transfer_to_mask","close_loading_view","open_loading_view","set_ai_ask_container_status","to_set_notifaction","home_refresh","ai_ask_page_load_success","ai_ask_set_session_info","ai_ask_input_set_mention_url","ai_ask_input_set_scene","ai_float_brain_panel_back_to_top_panel_page","ai_float_brain_panel_set_tools"],APP_PROFILES={fliggy:{name:"fliggy",label:"飞猪",appName:"LX",defaultAppVersion:"10.0.0",uaTokens:["AliTrip/{v}",WINDVANE],globals:{},bridges:[WV_BRIDGE,{global:"alitripBridge",style:"fliggy"},{global:"core",style:"fliggy"},{global:"methodChannel",style:"callback"}],activeEvents:WV_ACTIVE_EVENTS,actions:mergeActions(WV_ACTIONS,{...emptyActions(),open:["goto","ai_float_brain_panel_collapse_and_open_url"],close:[],title:["set_webview_title"],navigationBar:["set_ui"],statusBar:["set_status_bar_style"],systemInfo:["client_info"],kvGet:["get_kvcache"],kvSet:["set_kvcache"],kvDelete:["del_kvcache"],pageContext:["ai_float_brain_panel_get_page_context"],responses:{is_open_push:{is_open:!1},get_unread_message:{style:"POINT",count:0},get_v10_ab_info:{v10Version:!0},get_ai_ask_container_status:{status:"FULL"},ai_ask_get_keyboard_height:{height:0},get_idfa:{},get_caid:{},get_theme_conf:{},cppay_app_install:{result:""}},behaviors:{"page://goto":"navigate","page://close":"closeBackData",back:"closeBackData",user_info:"userInfo",ai_ask_get_memory_cache:"memoryGet",ai_ask_set_memory_cache:"memorySet",ai_ask_del_memory_cache:"memoryDelete",channelJudgeJsBridge:"availabilityMap",networktype:"networkInfo",network_quality_monitor:"networkQualityMonitor",request:"beaconRequest",voice_recognition:"voiceRecognition",store_calendar_event:"calendar",remove_calendar_event:"calendar",check_batch_calendar:"calendar",search_batch_calendar_events:"calendar",lbs:"geolocation",permission:"permission",cacheFetch:"prefetch",fptTrack:"fptTrack",toUT:"userTrack","WVTBUserTrack.toUT":"userTrack","WVTBUserTrack.toUT2":"userTrack",mtop_stream:"mtopStream",ai_ask_preview_file:"previewFile",toast:"toast",ai_ask_input_bridge:"unsupportedNativeInput",cppay:"payment",minipay:"payment",union_pay:"payment"},noop:["swipe_back","track_error_with_alarm","cacheUpdate","long_press_save_image",...FLIGGY_AI_UI_NOOPS],silent:["native://biz/mtop_normal_sign","toUT","get_idfa","get_caid","channelJudgeJsBridge","get_unread_message","get_v10_ab_info","lbs","networktype","network_quality_monitor","request","long_press_save_image","set_status_bar_style","get_theme_conf","cacheFetch","cppay_app_install","track_error_with_alarm",...FLIGGY_AI_UI_NOOPS]}),schemes:FLIGGY_SCHEME_RULES,imagePicker:FLIGGY_IMAGE_PICKER,geolocation:{reverseGeocodeApi:"mtop.trip.common.getCityCodeByLatitudeAndLongitude",version:"1.0"},layerUrlProxy:FLIGGY_LAYER_URL_PROXY,rootContainer:FLIGGY_ROOT_CONTAINER,titleBarHiddenPathnames:FLIGGY_TITLE_BAR_HIDDEN_PATHNAMES,statusBarBackgroundColors:FLIGGY_STATUS_BAR_BACKGROUND_COLORS,urlSyncHostSuffixes:["m.taobao.com","wapa.taobao.com"],overlay:FLIGGY_OVERLAY,popBeforeOpenParam:"_fli_popBeforeOpen",nativeBack:FLIGGY_NATIVE_BACK,forceH5Mtop:!0},taobao:{name:"taobao",label:"手机淘宝",appName:"TB",defaultAppVersion:"10.65.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE,MEGA_BRIDGE],activeEvents:WV_ACTIVE_EVENTS,actions:WV_ACTIONS,schemes:COMMON_SCHEME_RULES,overlay:TAOBAO_OVERLAY,nativeBack:WV_NATIVE_BACK},wechat:{name:"wechat",label:"微信",appName:"WeChat",defaultAppVersion:"8.0.58",uaFamily:"wechatMiniProgram",uaTokens:[],globals:{__wxjs_environment:"miniprogram"},bridges:[{global:"wx",style:"wechat"},{global:"wx.miniProgram",style:"wechatMiniProgram",persistent:!0}],activeEvents:[],actions:{...emptyActions(),open:["navigateTo","redirectTo","switchTab","reLaunch"],close:["navigateBack"],behaviors:{postMessage:"postMessage",getLocation:"geolocation"}},schemes:WECHAT_SCHEME_RULES,miniProgram:WECHAT_MINI_PROGRAM,titleBarHostStyles:WECHAT_TITLE_BAR_HOST_STYLES},tmall:{name:"tmall",label:"天猫",appName:"TM",defaultAppVersion:"15.22.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE],activeEvents:WV_ACTIVE_EVENTS,actions:WV_ACTIONS,schemes:COMMON_SCHEME_RULES,nativeBack:WV_NATIVE_BACK},alipay:{name:"alipay",label:"支付宝",appName:"AP",defaultAppVersion:"10.8.0",uaTokens:["AlipayClient/{v}"],globals:{},bridges:[{global:"AlipayJSBridge",style:"alipay"}],activeEvents:[],actions:{open:["pushWindow","startApp"],close:["popWindow"],title:["setTitle"],navigationBar:["hideBackButton","showBackButton"],systemInfo:["getSystemInfo"],mtop:[],behaviors:{getNetworkType:"networkInfo",addNotifyListener:"notifySubscribe",removeNotifyListener:"notifyUnsubscribe",postNotification:"notifyPost"},noop:["postWebViewMessage","setGestureBack"],silent:["getNetworkType"]},schemes:COMMON_SCHEME_RULES,nativeBack:ALIPAY_NATIVE_BACK},koubei:{name:"koubei",label:"口碑",appName:"KB",defaultAppVersion:"9.5.0",uaTokens:["KoubeiClient/{v}"],globals:{},bridges:[{global:"AlipayJSBridge",style:"alipay"}],activeEvents:[],actions:{open:["pushWindow","startApp"],close:["popWindow"],title:["setTitle"],navigationBar:["hideBackButton","showBackButton"],systemInfo:["getSystemInfo"],mtop:[],behaviors:{getNetworkType:"networkInfo",addNotifyListener:"notifySubscribe",removeNotifyListener:"notifyUnsubscribe",postNotification:"notifyPost"},noop:["postWebViewMessage","setGestureBack"],silent:["getNetworkType"]},schemes:COMMON_SCHEME_RULES,nativeBack:ALIPAY_NATIVE_BACK},"taobao-tj":{name:"taobao-tj",label:"淘宝特价版",appName:"LT",defaultAppVersion:"10.32.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE],activeEvents:WV_ACTIVE_EVENTS,actions:WV_ACTIONS,schemes:COMMON_SCHEME_RULES,nativeBack:WV_NATIVE_BACK},"taobao-live":{name:"taobao-live",label:"淘宝直播",appName:"TAOBAOLIVEAPP",defaultAppVersion:"3.10.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE],activeEvents:WV_ACTIVE_EVENTS,actions:WV_ACTIONS,schemes:COMMON_SCHEME_RULES,nativeBack:WV_NATIVE_BACK},xianyu:{name:"xianyu",label:"闲鱼",appName:"FM",defaultAppVersion:"7.15.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE],activeEvents:WV_ACTIVE_EVENTS,actions:WV_ACTIONS,schemes:COMMON_SCHEME_RULES,nativeBack:WV_NATIVE_BACK},etao:{name:"etao",label:"一淘",appName:"ET",defaultAppVersion:"9.27.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE],activeEvents:WV_ACTIVE_EVENTS,actions:WV_ACTIONS,schemes:COMMON_SCHEME_RULES,nativeBack:WV_NATIVE_BACK},eleme:{name:"eleme",label:"饿了么",appName:"ELMC",defaultAppVersion:"11.12.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE],activeEvents:WV_ACTIVE_EVENTS,actions:WV_ACTIONS,schemes:COMMON_SCHEME_RULES,nativeBack:WV_NATIVE_BACK},damai:{name:"damai",label:"大麦",appName:"DM",defaultAppVersion:"8.9.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE],activeEvents:WV_ACTIVE_EVENTS,actions:WV_ACTIONS,schemes:COMMON_SCHEME_RULES,nativeBack:WV_NATIVE_BACK},btrip:{name:"btrip",label:"阿里商旅",appName:"BLX",defaultAppVersion:"9.12.0",uaTokens:[WINDVANE],globals:{},bridges:[WV_BRIDGE,{global:"methodChannel",style:"btrip"}],activeEvents:WV_ACTIVE_EVENTS,actions:mergeActions(WV_ACTIONS,{...emptyActions(),open:["goto"],behaviors:{back:"closeBackData"}}),schemes:COMMON_SCHEME_RULES,nativeBack:WV_NATIVE_BACK},amap:{name:"amap",label:"高德地图",appName:"amap",defaultAppVersion:"13.8.0",uaTokens:[],globals:{},bridges:[{global:"AmapApp.bridge",style:"amap"}],activeEvents:[],actions:{open:["loadSchema","infoH5JsAction"],close:[],title:["setWebViewTitle"],systemInfo:[],mtop:[],noop:["interceptNativeBackEvent"]},schemes:COMMON_SCHEME_RULES,nativeBack:{handler:"onNativeBackEvent"}},qianwen:{name:"qianwen",label:"千问",appName:"TONGYI",defaultAppVersion:"3.20.0",uaTokens:[],globals:{},bridges:[{global:"ucapi",style:"invoke"}],activeEvents:[],actions:{open:["biz.openPageUrl","webdialog.show"],close:["biz.closeWebPage","webdialog.pop"],title:[],systemInfo:[],mtop:[],behaviors:{"base.postmessage":"postMessage","biz.popToRootWindow":"closeAll","biz.popToTopChatWindow":"closeAll"},noop:[]},schemes:COMMON_SCHEME_RULES,messageEvent:"QKEVT_OnReceiveMessage"},lingyou:{name:"lingyou",label:"翎游",appName:"hongtu",defaultAppVersion:"1.5.0",uaTokens:["hongtu/{v}"],globals:{},bridges:[{global:"WKWebViewJavascriptBridge",style:"callHandler"},{global:"WebViewJavascriptBridge",style:"callHandler"}],activeEvents:[],actions:{...emptyActions(),open:["jumpPage"],close:["closePage"],title:["setPageTitle"]},schemes:COMMON_SCHEME_RULES},didi:{name:"didi",label:"滴滴出行",appName:"didi.passenger",defaultAppVersion:"6.9.0",uaTokens:["didi.passenger/{v}"],globals:{},bridges:[{global:"didiBridge",style:"didi"},{global:"Fusion",style:"didi"}],activeEvents:[],actions:{...emptyActions(),open:["openPage"],close:["closePage"]},schemes:COMMON_SCHEME_RULES},easybike:{name:"easybike",label:"易到用车",appName:"easybike",defaultAppVersion:"9.0.0",uaTokens:["app=easybike;"],globals:{},bridges:[{global:"webkit.messageHandlers.callNative",style:"easybikeNative"},{global:"AppFunctions",style:"easybikeNative"}],activeEvents:[],actions:mergeActions(WV_ACTIONS,{...emptyActions(),close:["business/hitch.closeWebView"]}),schemes:COMMON_SCHEME_RULES}};function buildAppProfileUa(profile,options={}){let os11=options.os??(options.devicePreset?DEVICE_PRESETS[options.devicePreset]?.appProfileOs:void 0)??"ios",version2=options.appVersion??profile.defaultAppVersion,deviceModel=options.deviceModel??(options.devicePreset?DEVICE_PRESETS[options.devicePreset]?.appProfileModel:void 0)??"Pixel 11";if(profile.uaFamily==="wechatMiniProgram")return os11==="android"?`Mozilla/5.0 (Linux; Android 17; ${deviceModel}; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/152.0.0.0 Mobile MicroMessenger/${version2} WeChat/arm64 NetType/WIFI Language/zh_CN miniProgram`:`Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/${version2} NetType/WIFI Language/zh_CN miniProgram`;let tokens=profile.uaTokens.map(t=>t.replaceAll("{v}",version2)).filter(Boolean),tail=tokens.length>0?` ${tokens.join(" ")}`:"";return os11==="android"?`Mozilla/5.0 (Linux; Android 17; ${deviceModel}) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/152.0.0.0 Mobile Safari/537.36 AliApp(${profile.appName}/${version2})${tail}`:`Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) AliApp(${profile.appName}/${version2})${tail}`}function resolveAppProfile(name,options={}){let profile=APP_PROFILES[name];if(!profile)throw new Error(`Unknown app profile "${name}". Available: ${Object.keys(APP_PROFILES).join(", ")}`);let os11=options.os??(options.devicePreset?DEVICE_PRESETS[options.devicePreset]?.appProfileOs:void 0)??"ios",version2=options.appVersion??profile.defaultAppVersion,recommendedPreset=os11==="android"?"pixel-11":"iphone-17-pro",devicePreset=options.devicePreset??recommendedPreset,emulation=resolveEmulationConfig({enabled:!0,preset:devicePreset,orientation:options.orientation}),deviceModel=options.deviceModel??DEVICE_PRESETS[devicePreset].appProfileModel,globals={...profile.globals,__APP_NAME__:profile.appName,__APP_VERSION__:version2,__FLI_DEVICE_MODEL__:deviceModel,__DEVICE_MODEL__:deviceModel},ua=buildAppProfileUa(profile,{...options,os:os11,deviceModel});return{profile:profile.name,label:profile.label,ua,injected:{profile:profile.name,label:profile.label,globals,bridges:profile.bridges,activeEvents:profile.activeEvents,maxTouchPoints:5,statusBarHeight:emulation.safeAreaInsets.top,safeAreaInsets:emulation.safeAreaInsets,deviceAppearance:{preset:devicePreset,orientation:emulation.orientation,cutout:emulation.appearance.cutout},language:"zh-Hans",userAgent:ua,navigatorPlatform:os11==="android"?"Linux armv8l":"iPhone",platform:os11==="android"?"Android":"iOS",systemVersion:os11==="android"?"17":"26.0",clientType:os11==="android"?"android":"iphone",actions:applyAppBridgeConfig(profile.actions,options.bridgeConfig),schemes:profile.schemes,...profile.miniProgram&&{miniProgram:profile.miniProgram},...profile.imagePicker&&{imagePicker:profile.imagePicker},...profile.geolocation&&{geolocation:profile.geolocation},...profile.overlay&&{overlay:profile.overlay},...profile.popBeforeOpenParam&&{popBeforeOpenParam:profile.popBeforeOpenParam},...profile.messageEvent&&{messageEvent:profile.messageEvent},...profile.nativeBack&&{nativeBack:profile.nativeBack},...profile.layerUrlProxy&&{layerUrlProxy:profile.layerUrlProxy},...profile.urlSyncHostSuffixes&&{urlSyncHostSuffixes:profile.urlSyncHostSuffixes},...profile.forceH5Mtop&&{forceH5Mtop:!0},simulateSystemBars:!1,rootContainer:{enabled:!1,...profile.rootContainer?.statusBarHeightCookie&&{initialCookies:[{...profile.rootContainer.statusBarHeightCookie,value:String(emulation.safeAreaInsets.top)}]}},titleBar:{navigationBarHeight:os11==="android"?48:44,backgroundColor:"#ffffff",textColor:"#0f131a",...profile.titleBarHiddenPathnames&&{hiddenPathnames:profile.titleBarHiddenPathnames},...profile.statusBarBackgroundColors&&{statusBarBackgroundColors:profile.statusBarBackgroundColors},...profile.titleBarHostStyles&&{hostStyles:profile.titleBarHostStyles}}},recommendedPreset}}function installAppProfileEnvironment(config2){let w=window;if(w.__mearlAppProfile__)return null;w.__mearlAppProfile__=config2.profile;let SRC="mearl-app-bridge",TAG=`[AppBridge:${config2.label}]`,ROOT_FRAME_NAME="__mearl_root__",LAYER_FRAME_NAME="__mearl_layer__",isTop=window===window.top,isRootFrame=!isTop&&window.name===ROOT_FRAME_NAME,isLayerFrame=!isTop&&window.name===LAYER_FRAME_NAME,isContainerFrame=isTop||isRootFrame||isLayerFrame,usesRootContainer=isTop&&config2.rootContainer?.enabled===!0,simulateSystemBars=config2.simulateSystemBars!==!1,safeAreaInsets=config2.safeAreaInsets??{top:config2.statusBarHeight,right:0,bottom:0,left:0},log2=(...args)=>console.info(TAG,...args);for(let[key,value]of Object.entries(config2.globals))try{w[key]=value}catch{}typeof w.__STATUS_BAR_HEIGHT__!="number"&&(w.__STATUS_BAR_HEIGHT__=config2.statusBarHeight),typeof w.__SAFE_AREA_INSET_BOTTOM__!="number"&&(w.__SAFE_AREA_INSET_BOTTOM__=safeAreaInsets.bottom);let applySafeAreaCssVariables=()=>{let root=document.documentElement;if(!root)return!1;try{return root.style.setProperty("--safe-area-inset-top",`${safeAreaInsets.top}px`),root.style.setProperty("--safe-area-inset-right",`${safeAreaInsets.right}px`),root.style.setProperty("--safe-area-inset-bottom",`${safeAreaInsets.bottom}px`),root.style.setProperty("--safe-area-inset-left",`${safeAreaInsets.left}px`),!0}catch{return!1}};if(!applySafeAreaCssVariables()){let observer=new MutationObserver(()=>{applySafeAreaCssVariables()&&observer.disconnect()});observer.observe(document,{childList:!0})}if(config2.forceH5Mtop){let downstreamMtopParamsHandler=w.MTOP_PARAMS_HANDLER,forceH5Mtop=params=>{let resolved=params;if(typeof downstreamMtopParamsHandler=="function")try{resolved=downstreamMtopParamsHandler.call(window,params)??params}catch{resolved=params}return{...resolved&&typeof resolved=="object"?resolved:{},useNative:!1}};try{Object.defineProperty(w,"MTOP_PARAMS_HANDLER",{configurable:!0,get:()=>forceH5Mtop,set:handler=>{handler!==forceH5Mtop&&(downstreamMtopParamsHandler=handler)}})}catch{w.MTOP_PARAMS_HANDLER=forceH5Mtop}}for(let[key,value]of[["userAgent",config2.userAgent],["platform",config2.navigatorPlatform],["vendor","Apple Computer, Inc."],["appVersion",config2.userAgent.replace(/^Mozilla\//,"")]])try{Object.defineProperty(navigator,key,{get:()=>value,configurable:!0})}catch{}try{Object.defineProperty(navigator,"maxTouchPoints",{get:()=>config2.maxTouchPoints})}catch{}return{w,SRC,TAG,ROOT_FRAME_NAME,LAYER_FRAME_NAME,isTop,isRootFrame,isLayerFrame,isContainerFrame,usesRootContainer,simulateSystemBars,safeAreaInsets,log:log2}}function installAppProfileSystemBars(config2,environment,host){let{SRC,isTop,isContainerFrame,simulateSystemBars,safeAreaInsets}=environment,externalDeviceChrome=config2.externalDeviceChrome===!0,titleBarMode="auto",titleBarRoot=null,titleBarSpacer=null,systemStatusView=null,systemBottomRoot=null,systemBottomSurface=null,rootTitleBarView=null,titleBarTitleVisible=!0,titleBarBackVisible=!0,titleBarBackground=config2.titleBar?.backgroundColor??"#ffffff",titleBarTextColor=config2.titleBar?.textColor??"#111111",titleBarStateExplicit=!1,presentedRootTitleBarState=null,normalizeProxyPathPrefix=prefix=>{let withLeadingSlash=prefix.startsWith("/")?prefix:`/${prefix}`;return withLeadingSlash.endsWith("/")?withLeadingSlash:`${withLeadingSlash}/`},matchesProxyTarget=(hostname3,suffixes)=>suffixes.some(suffix=>hostname3===suffix||hostname3.endsWith(`.${suffix}`)),normalizePathname=pathname=>{let withLeadingSlash=pathname.startsWith("/")?pathname:`/${pathname}`;return withLeadingSlash.length>1&&withLeadingSlash.endsWith("/")?withLeadingSlash.slice(0,-1):withLeadingSlash},businessPathname=href=>{try{let current=new URL(href,location.href),proxy=config2.layerUrlProxy;if(!proxy)return normalizePathname(current.pathname);let prefix=normalizeProxyPathPrefix(proxy.pathPrefix);if(!current.pathname.startsWith(prefix))return normalizePathname(current.pathname);let rest=current.pathname.slice(prefix.length),slash=rest.indexOf("/"),hostName=slash===-1?rest:rest.slice(0,slash),pathname=slash===-1?"/":rest.slice(slash),hostname3=new URL(`${current.protocol}//${hostName}`).hostname;return matchesProxyTarget(hostname3,proxy.targetHostSuffixes)?normalizePathname(pathname):normalizePathname(current.pathname)}catch{return null}},matchesConfiguredPathname=(href,pathnames)=>{let pathname=businessPathname(href);return pathname!==null&&pathnames.some(configuredPathname=>normalizePathname(configuredPathname)===pathname)},configuredHostStyle=(href=location.href)=>{try{let hostname3=new URL(href,location.href).hostname.toLowerCase();return(config2.titleBar?.hostStyles??[]).find(rule=>{let suffix=rule.hostSuffix.trim().replace(/^\.+/,"").toLowerCase();return suffix!==""&&(hostname3===suffix||hostname3.endsWith(`.${suffix}`))})}catch{return}},configuredTitleBarBackground=(href,fallback)=>configuredHostStyle(href)?.titleBarBackgroundColor??fallback,supportsWindVaneNavigationMeta=config2.bridges.some(bridge=>bridge.style==="windvane"),isTruthyParam=value=>value==="1"||value?.toLowerCase()==="true"||value?.toUpperCase()==="YES",isTransparentColor=value=>{let normalized=value.replace(/\s/g,"").toLowerCase();return normalized==="transparent"||normalized==="#0000"||normalized==="#00000000"||normalized==="rgba(0,0,0,0)"},fixedContainerTitleBarMode=()=>config2.profile==="wechat"?"normal":null,pageRequestedTitleBarMode=(href=location.href,includeMeta=!0)=>{try{let params=new URL(href,location.href).searchParams,webviewOptions=new URLSearchParams(params.get("__webview_options__")??""),option=key=>params.get(key)??webviewOptions.get(key);if(config2.profile==="fliggy"||config2.profile==="taobao"){let hidden=option("titleBarHidden");if(hidden==="1")return"status-inset";if(hidden==="2")return"status"}if(config2.profile==="taobao"&&option("disableNav")?.toUpperCase()==="YES")return isTruthyParam(option("status_bar_transparent"))?"status":"status-inset";if(config2.profile==="alipay"||config2.profile==="koubei"){if(option("showTitleBar")?.toUpperCase()==="NO")return"status-inset";let transparentTitle=option("transparentTitle")?.toLowerCase();if(transparentTitle&&["always","auto","custom"].includes(transparentTitle))return"overlay"}let overlayParam=config2.overlay?.enabledParam;return overlayParam&&isTruthyParam(params.get(overlayParam))?"status":!includeMeta||!supportsWindVaneNavigationMeta?null:document.getElementById("WV.Meta.Nav.HideNavBar")?.getAttribute("value")==="HideStatusBar"?"status":null}catch{return null}},pageRequestsHiddenTitleBar=(href=location.href)=>matchesConfiguredPathname(href,config2.titleBar?.hiddenPathnames??[]),configuredStatusBarBackground=(href=location.href)=>{let colors=config2.titleBar?.statusBarBackgroundColors??{},pathname=businessPathname(href);return pathname===null?null:Object.entries(colors).find(([configuredPathname])=>normalizePathname(configuredPathname)===pathname)?.[1]??configuredHostStyle(href)?.statusBarBackgroundColor??null},pageRequestsHiddenStatusBar=(href=location.href)=>{try{let params=new URL(href,location.href).searchParams;return isTruthyParam(params.get("statusBarHidden"))||isTruthyParam(params.get("hideStatusBar"))?!0:/(?:^|&)showStatusBar=NO(?:&|$)/i.test(params.get("__webview_options__")??"")}catch{return!1}},resolveTitleBarMode=(href,fallback,includeMeta)=>{let fixedMode=fixedContainerTitleBarMode();if(fixedMode)return fixedMode;if(titleBarMode!=="auto")return titleBarMode;if(pageRequestsHiddenStatusBar(href))return"hidden";if(pageRequestsHiddenTitleBar(href))return"status-inset";let requestedMode=pageRequestedTitleBarMode(href,includeMeta);return requestedMode||fallback},resolveStatusBarBackground=(href,mode,navigationBarBackground)=>configuredStatusBarBackground(href)??(mode==="normal"||mode==="status-inset"?navigationBarBackground:"transparent"),ownTitleBarState=()=>{let mode=resolveTitleBarMode(location.href,"normal",!0),background=configuredTitleBarBackground(location.href,titleBarBackground);return{mode,title:document.title||config2.label,titleVisible:titleBarTitleVisible,backVisible:titleBarBackVisible,background,statusBarBackground:resolveStatusBarBackground(location.href,mode,background),textColor:titleBarTextColor}},initialLayerTitleBarState=url2=>{let mode=fixedContainerTitleBarMode()??(pageRequestsHiddenStatusBar(url2)?"hidden":pageRequestsHiddenTitleBar(url2)?"status-inset":pageRequestedTitleBarMode(url2,!1)??"normal"),background=configuredTitleBarBackground(url2,config2.titleBar?.backgroundColor??"#ffffff");return{mode,title:config2.label,titleVisible:!0,backVisible:!0,background,statusBarBackground:mode==="status-inset"?background:resolveStatusBarBackground(url2,mode,background),textColor:config2.titleBar?.textColor??"#111111"}},parseReportedTitleBarState=value=>{if(!value||typeof value!="object")return null;let state=value;return!["normal","overlay","status","status-inset","hidden"].includes(String(state.mode))||typeof state.title!="string"||typeof state.titleVisible!="boolean"||typeof state.backVisible!="boolean"||typeof state.background!="string"||typeof state.textColor!="string"?null:{...state,statusBarBackground:typeof state.statusBarBackground=="string"?state.statusBarBackground:state.mode==="normal"||state.mode==="status-inset"?String(state.background):"transparent"}},resolvedTitleBarState=layer=>layer?layer.titleBarState??initialLayerTitleBarState(layer.url):presentedRootTitleBarState??ownTitleBarState(),resolvedRootTitleBarState=(fallback=ownTitleBarState())=>presentedRootTitleBarState??(host.getRootFrame()?{...fallback,statusBarBackground:configuredHostStyle(location.href)?.statusBarBackgroundColor??config2.titleBar?.backgroundColor??"#ffffff"}:fallback),renderNavigationBarView=(view,state)=>{let visible=state.mode==="normal"||state.mode==="overlay";view.root.style.display=visible?"block":"none",view.surface.style.visibility=visible?"visible":"hidden",view.surface.style.background=state.mode==="overlay"?"transparent":state.background,view.surface.style.borderBottom="none",view.surface.style.color=state.textColor,view.title.textContent=state.title,view.title.style.display=state.titleVisible?"block":"none",view.back.style.display=state.backVisible?"flex":"none",view.back.style.color=state.textColor},topFullLayer=()=>{let layers=host.getLayers();for(let index=layers.length-1;index>=0;index-=1)if(!layers[index].overlay&&!layers[index].closing)return layers[index]},activeTitleBarState=()=>{let layer=topFullLayer();return layer?resolvedTitleBarState(layer):resolvedRootTitleBarState()},syncActiveSystemBars=()=>{let state=activeTitleBarState();if(externalDeviceChrome&&isTop&&window.postMessage({source:"mearl-app-profile-runtime",type:"device-chrome-state",state:{statusBarBackground:state.statusBarBackground,textColor:state.textColor,bridgeConfig:{profile:config2.profile,actions:config2.actions}}},"*"),systemStatusView){let visible=state.mode!=="hidden";systemStatusView.root.style.display=visible?"block":"none",systemStatusView.surface.style.visibility=visible?"visible":"hidden",systemStatusView.surface.style.background=state.statusBarBackground,systemStatusView.surface.style.color=state.textColor}systemBottomRoot&&systemBottomSurface&&(systemBottomRoot.style.display=safeAreaInsets.bottom>0?"block":"none",systemBottomSurface.style.color=state.textColor)},syncLayerViewport=(layer,state)=>{if(layer.overlay)return;if(!simulateSystemBars){layer.frame.style.top="0px",layer.frame.style.height="100%";return}let totalHeight=config2.statusBarHeight+(config2.titleBar?.navigationBarHeight??0),offset=state.mode==="normal"?totalHeight:state.mode==="status-inset"?config2.statusBarHeight:0;layer.frame.style.top=`${offset}px`,layer.frame.style.height=offset>0?`calc(100% - ${offset}px)`:"100%",layer.frame.setAttribute("data-mearl-app-viewport-mode",state.mode),layer.frame.style.setProperty("--mearl-app-navigation-bar-height",`${config2.titleBar?.navigationBarHeight??0}px`),layer.frame.style.opacity=state.mode==="status-inset"&&!layer.titleBarStateReady?"0":"1",layer.titleBarView&&renderNavigationBarView(layer.titleBarView,state),topFullLayer()===layer&&syncActiveSystemBars()},syncRootFrameViewport=state=>{let rootFrame=host.getRootFrame();if(!rootFrame)return;if(!simulateSystemBars){rootFrame.style.top="0px",rootFrame.style.height="100%";return}let totalHeight=config2.statusBarHeight+(config2.titleBar?.navigationBarHeight??0),offset=state.mode==="normal"?totalHeight:state.mode==="status-inset"?config2.statusBarHeight:0;rootFrame.style.top=`${offset}px`,rootFrame.style.height=offset>0?`calc(100% - ${offset}px)`:"100%",rootFrame.setAttribute("data-mearl-app-viewport-mode",state.mode),rootFrame.style.setProperty("--mearl-app-navigation-bar-height",`${config2.titleBar?.navigationBarHeight??0}px`),rootFrame.style.opacity=state.mode==="status-inset"&&presentedRootTitleBarState===null&&!rootFrame.hasAttribute("data-mearl-webview-ready")?"0":"1"},syncSimulatedTitleBar=()=>{let ownState=ownTitleBarState();if(!isTop){if(isContainerFrame){if(!titleBarStateExplicit&&document.readyState==="loading")return;window.top?.postMessage({source:SRC,type:"titleBarState",state:ownState,explicit:titleBarStateExplicit},"*")}return}if(!titleBarRoot||!titleBarSpacer||!rootTitleBarView)return;let rootFrame=host.getRootFrame();!rootFrame&&host.getLayers().length===0&&host.getClosingLayerCount()===0&&(presentedRootTitleBarState=ownState);let state=resolvedRootTitleBarState(ownState);renderNavigationBarView(rootTitleBarView,state);let spacerHeight=state.mode==="normal"?config2.statusBarHeight+(config2.titleBar?.navigationBarHeight??0):state.mode==="status-inset"?config2.statusBarHeight:0;titleBarSpacer.style.display=!rootFrame&&spacerHeight>0?"block":"none",titleBarSpacer.style.height=`${spacerHeight}px`,titleBarSpacer.style.minHeight=`${spacerHeight}px`,syncRootFrameViewport(state),syncActiveSystemBars()},applyNavigationBarState=(api,params)=>{titleBarStateExplicit=!0;let p=params&&typeof params=="object"?params:{},displayValue=p.titlebar_display??p.titlebarDisplay??p.titleBarDisplay,display=typeof displayValue=="string"?displayValue.toLowerCase():"";api==="hideBackButton"&&(titleBarBackVisible=!1),api==="showBackButton"&&(titleBarBackVisible=!0),display==="hide"&&(titleBarMode="status"),display==="show"&&(titleBarMode="normal"),(p.isImmersive===!0||p.isTransparent===!0)&&(titleBarMode="overlay"),p.isImmersive===!1&&p.isTransparent===!1&&(titleBarMode="normal"),typeof p.isTitleVisible=="boolean"&&(titleBarTitleVisible=p.isTitleVisible),typeof p.title=="string"&&(document.title=p.title),typeof p.backgroundColor=="string"&&(titleBarBackground=p.backgroundColor,isTransparentColor(p.backgroundColor)&&(titleBarMode="overlay")),typeof p.barTextStyle=="string"&&(titleBarTextColor=p.barTextStyle==="white"?"#ffffff":"#111111"),syncSimulatedTitleBar()},applyStatusBarState=params=>{titleBarStateExplicit=!0;let p=params&&typeof params=="object"?params:{},style=typeof p.style=="string"?p.style.toLowerCase():"";style&&(titleBarTextColor=style==="white"||style.includes("light")?"#ffffff":"#111111"),syncSimulatedTitleBar()},createNavigationBarView=(placement,onBack)=>{let titleBar=config2.titleBar,root=document.createElement("div");root.setAttribute("data-mearl-app-titlebar",config2.profile),root.setAttribute("data-mearl-titlebar-owner",placement);let splitRoot=placement==="root"&&config2.rootContainer?.splitScreen===!0;splitRoot&&root.setAttribute("data-mearl-split-pane","left-titlebar"),root.style.cssText=`${placement==="root"?"position:fixed":"position:absolute"};left:0;${splitRoot?"right:auto;width:50%;":"right:0;"}top:${config2.statusBarHeight}px;height:${titleBar.navigationBarHeight}px;z-index:${placement==="root"?"2147482900":"2"};overflow:hidden;box-sizing:border-box;font-family:"PingFang SC",-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;`;let shadow=root.attachShadow({mode:"open"});shadow.innerHTML=`<style>
|
|
598
598
|
:host{all:initial}#surface{position:relative;width:100%;height:100%;box-sizing:border-box;color:#0f131a;-webkit-font-smoothing:antialiased;text-rendering:geometricPrecision}
|
|
599
599
|
#nav{height:100%;position:relative;display:grid;align-items:start}#back{appearance:none;border:0;background:transparent;position:absolute;left:9px;top:0;width:28px;height:42px;display:flex;align-items:center;justify-content:center;padding:0;color:inherit;cursor:pointer;-webkit-tap-highlight-color:transparent}
|
|
600
600
|
#back svg{width:24px;height:24px;fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}#title{position:absolute;left:80px;right:80px;top:0;height:42px;box-sizing:border-box;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:10px 0;text-align:center;font-size:18px;font-weight:700;line-height:22px}
|
|
@@ -622,10 +622,10 @@ ${SOURCE_BADGES[source]}
|
|
|
622
622
|
#surface[data-platform="android"]{font-family:Roboto,"Noto Sans SC",sans-serif}
|
|
623
623
|
#surface[data-platform="android"] #status{padding:0 12px;font-size:12px;font-weight:500;letter-spacing:0}
|
|
624
624
|
#surface[data-platform="android"] #indicators{gap:5px;transform:scale(.86);transform-origin:right center}
|
|
625
|
-
</style><div id="surface" data-platform="${config2.platform.toLowerCase()}" data-cutout="${String(cutoutKind!=="none")}" data-cutout-kind="${cutoutKind}"><div id="status"><span id="time"></span>${cutoutMarkup}<span id="indicators" aria-hidden="true"><svg id="signal" viewBox="0 0 18 12"><rect x="0" y="8" width="3" height="4" rx="1"/><rect x="5" y="6" width="3" height="6" rx="1"/><rect x="10" y="3" width="3" height="9" rx="1"/><rect x="15" y="0" width="3" height="12" rx="1"/></svg><svg id="wifi" viewBox="1 3.8 22 17.2"><path d="M2 8.82a15 15 0 0 1 20 0"/><path d="M5 12.859a10 10 0 0 1 14 0"/><path d="M8.5 16.429a5 5 0 0 1 7 0"/><path d="M12 20h.01"/></svg><svg id="battery" viewBox="0 0 28 13"><rect id="battery-outline" x=".65" y=".65" width="23" height="11.7" rx="3.1"/><rect id="battery-level" x="2.35" y="2.35" width="19.6" height="8.3" rx="1.7"/><path id="battery-cap" d="M25 4.1c1.1.35 1.7 1.15 1.7 2.4s-.6 2.05-1.7 2.4z"/></svg></span></div></div>`;let surface=shadow.getElementById("surface"),time3=shadow.getElementById("time"),cutout=shadow.getElementById("device-cutout"),cutoutStatusPath=shadow.querySelector("#cutout-check path"),localizedScreenshotText=config2.language.toLowerCase().startsWith("zh")?{idle:"截图",copied:"已复制",downloaded:"已下载",failed:"截图失败"}:{idle:"Screenshot",copied:"Copied",downloaded:"Downloaded",failed:"Capture failed"},setCutoutState=state=>{cutout&&(cutout.dataset.state=state,cutout.setAttribute("aria-label",localizedScreenshotText[state]),cutout.title=localizedScreenshotText[state],cutoutStatusPath&&cutoutStatusPath.setAttribute("d",state==="failed"?"M5.5 5.5l9 9m0-9-9 9":"m4.5 10.5 3.2 3.2 7.8-7.8"))},screenshotPending=!1,screenshotBlob=data=>{let binary=atob(data),bytes=new Uint8Array(binary.length);for(let index=0;index<binary.length;index+=1)bytes[index]=binary.charCodeAt(index);return new Blob([bytes],{type:"image/png"})},downloadScreenshot=blob=>{let link=document.createElement("a"),objectUrl=URL.createObjectURL(blob);link.href=objectUrl,link.download=`mearl-screenshot-${new Date().toISOString().replace(/[:.]/g,"-")}.png`,link.style.display="none",document.body.appendChild(link),link.click(),link.remove(),window.setTimeout(()=>URL.revokeObjectURL(objectUrl),1e3)},captureScreenshot=async()=>{if(!cutout||screenshotPending||cutout.dataset.state!=="idle")return;screenshotPending=!0,cutout.setAttribute("aria-busy","true");let requestId=Date.now()*1e3+Math.floor(Math.random()*1e3),timeoutTimer=0,onResponse=null,image=new Promise((resolve2,reject)=>{let cleanup=()=>{timeoutTimer&&window.clearTimeout(timeoutTimer),onResponse&&window.removeEventListener("message",onResponse)};onResponse=event=>{if(event.source!==window)return;let message=event.data;if(!message||message.source!=="mearl-content"||message.type!=="APP_BRIDGE_SCREENSHOT_RESPONSE"||message.requestId!==requestId)return;cleanup();let result=message.result;result?.success===!0&&typeof result.data=="string"?resolve2({data:result.data}):reject(new Error(String(result?.error??"screenshot failed")))},window.addEventListener("message",onResponse),timeoutTimer=window.setTimeout(()=>{cleanup(),reject(new Error("screenshot timeout"))},35e3)}).then(result=>screenshotBlob(result.data)),clipboardWrite=null;if(navigator.clipboard?.write&&typeof ClipboardItem<"u")try{clipboardWrite=navigator.clipboard.write([new ClipboardItem({"image/png":image})]),clipboardWrite.catch(()=>{})}catch{clipboardWrite=null}window.postMessage({source:SRC,type:"screenshot",requestId},"*");try{let blob=await image;if(clipboardWrite)try{await clipboardWrite,setCutoutState("copied")}catch{downloadScreenshot(blob),setCutoutState("downloaded")}else downloadScreenshot(blob),setCutoutState("downloaded")}catch{setCutoutState("failed")}finally{screenshotPending=!1,cutout.setAttribute("aria-busy","false")}window.setTimeout(()=>{screenshotPending||setCutoutState("idle")},1600)};hasDynamicIsland&&cutout&&(setCutoutState("idle"),cutout.addEventListener("click",()=>void captureScreenshot()));let updateTime=()=>{let now=new Date;time3&&(time3.textContent=`${String(now.getHours()).padStart(2,"0")}:${String(now.getMinutes()).padStart(2,"0")}`)};return window.addEventListener("mearl:page-time-change",updateTime),updateTime(),{root,surface,timeTimer:window.setInterval(updateTime,3e4)}},install=()=>{let titleBar=config2.titleBar;if(!titleBar||!isContainerFrame||!simulateSystemBars)return;let observeState=()=>{new MutationObserver(syncSimulatedTitleBar).observe(document.head??document.documentElement,{subtree:!0,childList:!0,characterData:!0,attributes:!0,attributeFilter:["content","value"]}),window.addEventListener("popstate",syncSimulatedTitleBar),window.addEventListener("hashchange",syncSimulatedTitleBar),document.readyState==="loading"&&document.addEventListener("DOMContentLoaded",syncSimulatedTitleBar,{once:!0});try{let pushState=history.pushState.bind(history),replaceState=history.replaceState.bind(history);history.pushState=function(...args){pushState(...args),syncSimulatedTitleBar()},history.replaceState=function(...args){replaceState(...args),syncSimulatedTitleBar()}}catch{}};if(!isTop){observeState(),syncSimulatedTitleBar();return}let mount=()=>{if(titleBarRoot||!document.body)return;let totalHeight=config2.statusBarHeight+titleBar.navigationBarHeight,navigationView=createNavigationBarView("root",host.requestNativeBack),statusView=externalDeviceChrome||config2.statusBarHeight<=0?null:createStatusBarView(),spacer=document.createElement("div");if(spacer.setAttribute("data-mearl-app-titlebar-spacer",""),spacer.style.cssText=`display:block;width:100%;height:${totalHeight}px;min-height:${totalHeight}px;flex:none;`,spacer.style.setProperty("--mearl-app-navigation-bar-height",`${titleBar.navigationBarHeight}px`),document.body.insertBefore(spacer,document.body.firstChild),document.body.appendChild(navigationView.root),statusView&&document.body.appendChild(statusView.root),!externalDeviceChrome&&safeAreaInsets.bottom>0){let bottomRoot=document.createElement("div");bottomRoot.setAttribute("data-mearl-app-system-bottom",config2.profile),bottomRoot.style.cssText=`position:fixed;left:0;right:0;bottom:0;height:${safeAreaInsets.bottom}px;z-index:2147483600;box-sizing:border-box;pointer-events:none;color:#111111;`;let bottomShadow=bottomRoot.attachShadow({mode:"open"});bottomShadow.innerHTML=`<style>:host{all:initial}#surface{appearance:none;border:0;padding:0;width:166px;max-width:100%;height:24px;position:absolute;left:50%;bottom:0;transform:translateX(-50%);display:block;box-sizing:border-box;pointer-events:auto;color:#111;background:transparent;cursor:pointer;-webkit-tap-highlight-color:transparent}#surface:focus-visible{outline:2px solid #2563eb;outline-offset:-2px}#indicator{position:absolute;left:50%;bottom:8px;transform:translateX(-50%);width:134px;height:5px;border-radius:999px;background:currentColor;opacity:.92;transition:transform 120ms ease,opacity 120ms ease}#surface:hover #indicator{opacity:1;transform:translateX(-50%) scaleX(1.05)}#surface[data-platform="android"] #indicator{bottom:6px;width:108px;height:4px;opacity:.82}</style><button id="surface" type="button" aria-label="打开桥模拟配置" title="桥模拟配置" data-platform="${config2.platform.toLowerCase()}"><span id="indicator" aria-hidden="true"></span></button>`,document.body.appendChild(bottomRoot),systemBottomRoot=bottomRoot,systemBottomSurface=bottomShadow.getElementById("surface"),systemBottomSurface?.addEventListener("click",()=>{window.postMessage({source:SRC,type:"showBridgeConfig",profile:config2.profile,actions:config2.actions},"*")})}rootTitleBarView=navigationView,systemStatusView=statusView,titleBarRoot=navigationView.root,titleBarSpacer=spacer,syncSimulatedTitleBar(),observeState()};document.body?mount():document.addEventListener("DOMContentLoaded",mount,{once:!0})},service={initialLayerTitleBarState,resolvedTitleBarState,parseReportedTitleBarState,setPresentedRootTitleBarState:state=>{presentedRootTitleBarState=state,syncSimulatedTitleBar()},markStateExplicit:()=>{titleBarStateExplicit=!0},applyNavigationBarState,applyStatusBarState,createNavigationBarView,destroyNavigationBarView:view=>view?.root.remove(),syncLayerViewport,syncActiveSystemBars,syncSimulatedTitleBar};return install(),service}function installAppProfilePageTransport(config2,environment){let{SRC,TAG,log:log2}=environment,appToast=null,appToastHideTimer=null,appToastRemoveTimer=null;function showAppToast(params){let p=params&&typeof params=="object"?params:{},messageValue=[p.message,p.msg,p.content,p.text].find(value=>typeof value=="string"&&value.trim().length>0);if(typeof messageValue!="string")return"missing message";let durationValue=Number(p.milliseconds??p.duration),duration3=Number.isFinite(durationValue)&&durationValue>0?durationValue:2e3,hideAfter=Math.min(6e4,Math.max(300,Math.round(duration3)));appToastHideTimer!==null&&window.clearTimeout(appToastHideTimer),appToastRemoveTimer!==null&&window.clearTimeout(appToastRemoveTimer);let toast=appToast?.isConnected===!0?appToast:document.createElement("div");return toast!==appToast&&(appToast=toast,toast.setAttribute("data-mearl-app-toast",""),toast.setAttribute("role","status"),toast.setAttribute("aria-live","polite"),Object.assign(toast.style,{position:"fixed",left:"50%",top:"50%",zIndex:"2147483647",maxWidth:"calc(100vw - 64px)",boxSizing:"border-box",padding:"14px 20px",borderRadius:"12px",background:"rgba(20, 20, 20, 0.88)",color:"#ffffff",fontFamily:'-apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif',fontSize:"16px",fontWeight:"400",lineHeight:"24px",textAlign:"center",whiteSpace:"pre-wrap",overflowWrap:"anywhere",pointerEvents:"none",opacity:"0",transform:"translate(-50%, -50%) scale(0.96)",transition:"opacity 180ms ease, transform 180ms ease"}),(document.body??document.documentElement).appendChild(toast)),toast.textContent=messageValue,toast.style.opacity="0",toast.style.transform="translate(-50%, -50%) scale(0.96)",toast.offsetWidth,toast.style.opacity="1",toast.style.transform="translate(-50%, -50%) scale(1)",appToastHideTimer=window.setTimeout(()=>{appToastHideTimer=null,toast.style.opacity="0",toast.style.transform="translate(-50%, -50%) scale(0.96)",appToastRemoveTimer=window.setTimeout(()=>{appToastRemoveTimer=null,appToast===toast&&(appToast=null),toast.remove()},180)},hideAfter),null}let bridgeRequestSeq=0,pendingMtop={},pendingMtopStreams={},pendingUserInfo={};function callMtop(params,succ,fail2){let id=++bridgeRequestSeq;pendingMtop[id]={succ,fail:fail2};let post=params.post,rawTimeout=params.timeout??params.timer,timeout=typeof rawTimeout=="number"?rawTimeout:typeof rawTimeout=="string"&&rawTimeout.trim()!==""?Number(rawTimeout):void 0,payload={...params,data:params.data!==void 0?params.data:params.param??{},method:params.method??(post===!0||post===1||post==="1"||post==="true"?"POST":"GET"),env:params.env??(/(^|\.)wapa\.taobao\.com$/i.test(location.hostname)?"pre":"online"),...Number.isFinite(timeout)&&{timeout}};window.postMessage({source:SRC,type:"mtop",requestId:id,payload},"*"),log2("mtop 代发 →",params.api)}function callMtopAsync(params){return new Promise((resolve2,reject)=>callMtop(params,resolve2,reject))}function callMtopStream(params,succ,fail2){let sessionId=typeof params.id=="string"?params.id:String(params.id??""),request=params.request&&typeof params.request=="object"?params.request:null;if(!sessionId||!request||typeof request.api!="string"){fail2?.("invalid mtop_stream params");return}let requestId=++bridgeRequestSeq;pendingMtopStreams[requestId]={sessionId},window.postMessage({source:SRC,type:"mtopStream",requestId,payload:{...request,timeout:params.timeout,method:params.method??request.method,env:/(^|\.)wapa\.taobao\.com$/i.test(location.hostname)?"pre":"online"}},"*"),succ?.({}),log2("mtop 流式代发 →",request.api)}function callUserInfo(fallback,succ){if(fallback.userId){succ?.(fallback);return}let requestId=++bridgeRequestSeq,timer=setTimeout(()=>{let pending=pendingUserInfo[requestId];pending&&(delete pendingUserInfo[requestId],pending.succ?.(pending.fallback))},1e3);pendingUserInfo[requestId]={fallback,succ,timer},window.postMessage({source:SRC,type:"userInfo",requestId},"*")}function emitMtopStreamEvent(sessionId,eventType,data){let detail=data&&typeof data=="object"?{...data,eventType}:{data,eventType};document.dispatchEvent(new CustomEvent(`mtop_stream${sessionId}`,{detail}))}function createUploadId(){try{if(typeof crypto.randomUUID=="function")return crypto.randomUUID()}catch{}return`${Date.now()}-${Math.random().toString(36).slice(2)}`}function pickDirectUploadTarget(response){if(!response||typeof response!="object")return null;let data=response.data;if(data?.success===!1)return null;let result=data?.result,target=Array.isArray(result?.urls)?result.urls[0]:void 0;if(!target||typeof target!="object")return null;let item=target;if(typeof item.put!="string"||!item.put||typeof item.get!="string"||!item.get)return null;let rawHeaders=item.putHeaders&&typeof item.putHeaders=="object"?item.putHeaders:{},putHeaders=Object.fromEntries(Object.entries(rawHeaders).map(([key,value])=>[key,String(value)]));return{put:item.put,get:item.get,putHeaders}}async function uploadImage(file2){let uploader=config2.imagePicker;if(!uploader)throw new Error("图片上传能力未配置");let env=/(^|\.)wapa\.taobao\.com$/i.test(location.hostname)?"pre":"online",response=await callMtopAsync({api:uploader.api,v:uploader.version,method:"POST",env,timeout:6e4,data:{fcId:uploader.fcId,fcGroup:uploader.fcGroup,fcName:uploader.uploadUrlFunction,fcData:JSON.stringify({requestType:"url",mimes:[file2.type||"image/jpeg"],prefix:uploader.prefix,region:uploader.region,uploadNumber:1}),fcConfig:JSON.stringify({timeout:6e4,disasterRecover:!0})}}),target=pickDirectUploadTarget(response);if(!target)throw new Error("获取图片上传地址失败");let uploadUrl=`${target.put}${target.put.includes("?")?"&":"?"}getAvatar=1`,uploadResponse=await fetch(uploadUrl,{method:"PUT",headers:target.putHeaders,body:file2});if(uploadResponse.status!==200)throw new Error(`图片直传失败: HTTP ${uploadResponse.status}`);return target.get}function openImagePicker(callbackCommandFn){let input=document.createElement("input");input.type="file",input.accept="image/*",input.style.display="none";let settled=!1,finish=()=>{settled=!0,input.remove()};input.addEventListener("cancel",finish,{once:!0}),input.addEventListener("change",()=>{let file2=input.files?.[0];if(!file2){finish();return}if(!file2.type.startsWith("image/")){finish(),console.error(TAG,"仅支持选择图片文件");return}uploadImage(file2).then(pic=>{typeof callbackCommandFn=="function"&&callbackCommandFn({pic,uuid:createUploadId(),timeStamp:Date.now()}),log2("图片选择并上传完成:",pic)}).catch(error48=>console.error(TAG,"图片上传失败:",error48)).finally(finish)},{once:!0}),(document.body??document.documentElement).appendChild(input),input.click(),window.addEventListener("focus",()=>{setTimeout(()=>{!settled&&!input.files?.length&&finish()},1e3)},{once:!0})}function showPaymentDialog(api,params,succeed,failed){document.querySelector('[data-mearl-payment-dialog="true"]')?.remove();let overlay=document.createElement("div");overlay.setAttribute("data-mearl-payment-dialog","true"),Object.assign(overlay.style,{position:"fixed",inset:"0",zIndex:"2147483647",display:"flex",alignItems:"center",justifyContent:"center",background:"rgba(0,0,0,0.5)"});let card=document.createElement("div");Object.assign(card.style,{background:"#fff",borderRadius:"12px",padding:"24px",width:"300px",textAlign:"center",fontFamily:"system-ui, sans-serif"});let title=document.createElement("div");Object.assign(title.style,{fontSize:"17px",fontWeight:"600",marginBottom:"8px"}),title.textContent="支付确认";let desc=document.createElement("div");Object.assign(desc.style,{fontSize:"14px",color:"#666",marginBottom:"20px"}),desc.textContent=`模拟 ${api} 支付,请选择操作`;let btnRow=document.createElement("div");Object.assign(btnRow.style,{display:"flex",gap:"12px"});let btnBase=(text,bg,color,action)=>{let btn=document.createElement("button");return btn.textContent=text,btn.setAttribute("data-mearl-action",action),Object.assign(btn.style,{flex:"1",padding:"10px 0",border:"none",borderRadius:"8px",fontSize:"15px",fontWeight:"500",cursor:"pointer",background:bg,color}),btn},confirmBtn=btnBase("完成支付","#1677ff","#fff","payment-confirm"),cancelBtn=btnBase("取消支付","#f5f5f5","#333","payment-cancel"),cleanup=()=>{overlay.remove()};confirmBtn.addEventListener("click",()=>{cleanup(),log2("用户完成支付",api),succeed(api==="wx.requestPayment"?{errMsg:"requestPayment:ok"}:{ResultStatus:"9000",resultStatus:"9000"})}),cancelBtn.addEventListener("click",()=>{cleanup(),log2("用户取消支付",api),failed(api==="wx.requestPayment"?{errMsg:"requestPayment:fail cancel"}:{ResultStatus:"6001",resultStatus:"6001"})}),btnRow.appendChild(cancelBtn),btnRow.appendChild(confirmBtn),card.appendChild(title),card.appendChild(desc),card.appendChild(btnRow),overlay.appendChild(card),(document.body??document.documentElement).appendChild(overlay)}function showMiniProgramActionDialog(action,params,confirmed,cancelled){document.querySelector('[data-mearl-mini-program-dialog="true"]')?.remove();let overlay=document.createElement("div");overlay.setAttribute("data-mearl-mini-program-dialog","true"),overlay.setAttribute("data-mearl-mini-program-action",action),Object.assign(overlay.style,{position:"fixed",inset:"0",zIndex:"2147483647",display:"flex",alignItems:"center",justifyContent:"center",background:"rgba(0,0,0,0.5)"});let card=document.createElement("div");Object.assign(card.style,{background:"#fff",borderRadius:"12px",padding:"24px",width:"300px",textAlign:"center",fontFamily:"system-ui, sans-serif"});let title=document.createElement("div");Object.assign(title.style,{fontSize:"17px",fontWeight:"600",marginBottom:"8px"}),title.textContent=action==="navigateMiniProgram"?"打开其他小程序":"订阅消息";let desc=document.createElement("div");Object.assign(desc.style,{fontSize:"14px",color:"#666",marginBottom:"20px"});let targetTitle=params.title?.trim()||"其他";desc.textContent=action==="navigateMiniProgram"?`即将打开“${targetTitle}”小程序,是否继续?`:"模拟微信订阅消息授权,请选择操作";let btnRow=document.createElement("div");Object.assign(btnRow.style,{display:"flex",gap:"12px"});let createButton=(text,background,color,actionName)=>{let button=document.createElement("button");return button.textContent=text,button.setAttribute("data-mearl-action",actionName),Object.assign(button.style,{flex:"1",padding:"10px 0",border:"none",borderRadius:"8px",fontSize:"15px",fontWeight:"500",cursor:"pointer",background,color}),button},confirmButton=createButton(action==="navigateMiniProgram"?"确定":"允许","#1677ff","#fff","mini-program-confirm"),cancelButton=createButton("取消","#f5f5f5","#333","mini-program-cancel"),cleanup=()=>overlay.remove();confirmButton.addEventListener("click",()=>{cleanup();let result=action==="navigateMiniProgram"?{errMsg:"navigateToMiniProgram:ok"}:{result:"SUCCESS",data:{totalCount:1,acceptCount:1}};log2("用户确认小程序原生能力",action,params.appId??params.scene??""),confirmed(result)}),cancelButton.addEventListener("click",()=>{cleanup();let result=action==="navigateMiniProgram"?{errMsg:"navigateToMiniProgram:fail cancel"}:{result:"CLOSE_BY_USER"};log2("用户取消小程序原生能力",action),cancelled(result)}),btnRow.appendChild(cancelButton),btnRow.appendChild(confirmButton),card.appendChild(title),card.appendChild(desc),card.appendChild(btnRow),overlay.appendChild(card),(document.body??document.documentElement).appendChild(overlay)}function handleMessage(msg){if(msg.source==="mearl-content"&&msg.type==="APP_BRIDGE_MTOP_RESPONSE"){let pending=pendingMtop[msg.requestId];if(!pending)return!0;delete pendingMtop[msg.requestId];let result=msg.result;return result?.success?pending.succ?.(result.response):pending.fail?.(result?.error??"mtop delegate failed"),!0}if(msg.source==="mearl-content"&&msg.type==="APP_BRIDGE_USER_INFO_RESPONSE"){let requestId=msg.requestId,pending=pendingUserInfo[requestId];if(!pending)return!0;delete pendingUserInfo[requestId],clearTimeout(pending.timer);let result=msg.result,response=result?.success&&result.response&&typeof result.response=="object"?result.response:{};return pending.succ?.({...pending.fallback,...response}),!0}if(msg.source==="mearl-content"&&msg.type==="APP_BRIDGE_MTOP_STREAM_EVENT"){let requestId=msg.requestId,pending=pendingMtopStreams[requestId];if(!pending)return!0;let eventType=msg.eventType;return emitMtopStreamEvent(pending.sessionId,eventType,msg.data),(eventType==="onFinish"||eventType==="onError")&&delete pendingMtopStreams[requestId],!0}return!1}return{showAppToast,callMtop,callMtopStream,callUserInfo,openImagePicker,showPaymentDialog,showMiniProgramActionDialog,handleMessage}}function installAppProfileBridgeProtocol(config2,environment,host){let{w,SRC,TAG,isTop,log:log2}=environment,{pageTransport,systemBars,requestOpen,requestClose,requestCloseAll,requestContainerData}=host,{showAppToast,callMtop,callMtopStream,callUserInfo,openImagePicker,showPaymentDialog,showMiniProgramActionDialog}=pageTransport,{applyNavigationBarState,applyStatusBarState,syncSimulatedTitleBar}=systemBars,NOT_IMPLEMENTED_PAYLOAD=JSON.stringify({ret:["HY_FAILED"],msg:"not implemented"}),FPT_STORAGE_KEY=`__mearl_app_fpt__:${config2.profile}`,CALENDAR_STORAGE_KEY=`__mearl_app_calendar_events__:${config2.profile}`,unsupportedNativeInputNotified=!1,stopNetworkQualityMonitor=null,simulatedPageHidden=!1,simulatedVisibilityInstalled=!1,hasPendingMiniProgramBackData=!1,pendingMiniProgramBackData,notificationListeners=new Map,megaListenerSeq=0,megaBroadcastListeners=new Map,megaLifeCycleListeners=new Set,megaPageCloseListeners=new Set,megaSystemBackListener=null,megaKVMutationVersion=0,MEGA_KV_TOTAL_SIZE=5*1024*1024,MEGA_KV_STORAGE_KEY=`__mearl_mega_kv__:${config2.profile}`;function readMegaKVStorage(){let storage=new Map;try{let parsed=JSON.parse(localStorage.getItem(MEGA_KV_STORAGE_KEY)??"{}");if(!parsed||typeof parsed!="object"||Array.isArray(parsed))return storage;for(let[bizId,rawEntries]of Object.entries(parsed)){if(!rawEntries||typeof rawEntries!="object"||Array.isArray(rawEntries))continue;let entries=new Map;for(let[key,value]of Object.entries(rawEntries))typeof value=="string"&&entries.set(key,value);storage.set(bizId,entries)}}catch{}return storage}let megaKVStorage=readMegaKVStorage();function megaKVSnapshot(){let snapshot={};for(let[bizId,values]of megaKVStorage)snapshot[bizId]=Object.fromEntries(values);return snapshot}function persistMegaKVStorage(){try{localStorage.setItem(MEGA_KV_STORAGE_KEY,JSON.stringify(megaKVSnapshot()))}catch{}}function replaceMegaKVStorage(value){if(!(!value||typeof value!="object"||Array.isArray(value))){megaKVStorage.clear();for(let[bizId,rawEntries]of Object.entries(value)){if(!rawEntries||typeof rawEntries!="object"||Array.isArray(rawEntries))continue;let entries=new Map;for(let[key,entryValue]of Object.entries(rawEntries))typeof entryValue=="string"&&entries.set(key,entryValue);megaKVStorage.set(bizId,entries)}persistMegaKVStorage()}}function applyMegaKVMutation(payload){let operation=typeof payload.operation=="string"?payload.operation:"",bizId=typeof payload.bizId=="string"?payload.bizId:"",key=typeof payload.key=="string"?payload.key:"";if(bizId){if(operation==="set"&&key&&typeof payload.value=="string"){let entries=megaKVStorage.get(bizId)??new Map;entries.set(key,payload.value),megaKVStorage.set(bizId,entries)}else if(operation==="remove"&&key){let entries=megaKVStorage.get(bizId);entries?.delete(key),entries?.size===0&&megaKVStorage.delete(bizId)}else if(operation==="clear")megaKVStorage.delete(bizId);else return;megaKVMutationVersion+=1,persistMegaKVStorage()}}function emitMegaCallback(callback,value){callback&&setTimeout(()=>callback(value),0)}function megaBroadcastBizId(value){return typeof value=="string"&&value?value:"__MEGA_GLOBAL_MESSAGE__"}function dispatchMegaBroadcast(payload){let bizId=megaBroadcastBizId(payload.bizId),eventName=typeof payload.eventName=="string"?payload.eventName:"";if(eventName)for(let listener of Array.from(megaBroadcastListeners.values()))listener.bizId!==bizId||listener.eventName!==eventName||(listener.once&&megaBroadcastListeners.delete(listener.id),emitMegaCallback(listener.callback,{statusCode:1,type:"onEvent",data:{detail:payload.detail}}),listener.once&&emitMegaCallback(listener.callback,{statusCode:99,type:"finish"}))}let documentPrototype=typeof Document=="function"?Document.prototype:null,nativeHiddenDescriptor=documentPrototype?Object.getOwnPropertyDescriptor(documentPrototype,"hidden"):void 0,nativeVisibilityDescriptor=documentPrototype?Object.getOwnPropertyDescriptor(documentPrototype,"visibilityState"):void 0;function installSimulatedVisibilityState(){if(!simulatedVisibilityInstalled){simulatedVisibilityInstalled=!0;try{Object.defineProperty(document,"hidden",{configurable:!0,get:()=>simulatedPageHidden||!!(nativeHiddenDescriptor?.get?.call(document)??!1)}),Object.defineProperty(document,"visibilityState",{configurable:!0,get:()=>simulatedPageHidden?"hidden":nativeVisibilityDescriptor?.get?.call(document)??"visible"})}catch{}}}function dispatchPageTransitionEvent(type){try{let event=typeof PageTransitionEvent=="function"?new PageTransitionEvent(type,{persisted:!1}):new Event(type);window.dispatchEvent(event)}catch{}}function dispatchActiveEvents(){for(let name of config2.activeEvents)try{document.dispatchEvent(new Event(name))}catch{}}function handlePageVisibility(hidden){if(hidden===simulatedPageHidden)return;installSimulatedVisibilityState(),simulatedPageHidden=hidden;let lifeCycleType=hidden?"onPageDisappear":"onPageAppear";for(let callback of megaLifeCycleListeners)emitMegaCallback(callback,{statusCode:1,type:lifeCycleType,data:{pageId:location.href}});try{document.dispatchEvent(new Event("visibilitychange"))}catch{}if(hidden){try{window.dispatchEvent(new Event("blur"))}catch{}dispatchPageTransitionEvent("pagehide");return}dispatchPageTransitionEvent("pageshow");try{window.dispatchEvent(new Event("focus"))}catch{}dispatchActiveEvents()}function resolveWindowFunction(path19){let parts=path19.split(".").filter(Boolean),owner=w;for(let index=0;index<parts.length-1;index+=1){let next=owner[parts[index]];if(!next||typeof next!="object")return null;owner=next}let fn=owner[parts[parts.length-1]];return typeof fn=="function"?fn.bind(owner):null}function handleNativeBack(){let megaHandled=!1;for(let callback of megaPageCloseListeners)megaHandled=!0,emitMegaCallback(callback,{statusCode:1,type:"onClose",data:{}});if(megaSystemBackListener&&(megaHandled=!0,emitMegaCallback(megaSystemBackListener,{statusCode:1,type:"onSuccess",data:{}})),megaHandled)return!0;let nativeBack=config2.nativeBack;if(!nativeBack)return!1;if(nativeBack.handler){let handler=resolveWindowFunction(nativeBack.handler);if(!handler)return!1;try{return handler(),!0}catch{return!1}}let controlled=!1;if(nativeBack.controlFunction){let control=resolveWindowFunction(nativeBack.controlFunction);if(!control)return!1;try{controlled=control()===!0}catch{return!1}if(!controlled)return!1}if(!nativeBack.event)return controlled;try{let event=new Event(nativeBack.event,{cancelable:!0});return document.dispatchEvent(event),controlled||event.defaultPrevented}catch{return controlled}}function handleAppMessage(message){if(!message||typeof message!="object")return;let payload=message;if(payload.kind==="megaBroadcast"){dispatchMegaBroadcast(payload);return}if(payload.kind==="megaKVStorage"){applyMegaKVMutation(payload);return}if(payload.kind==="legacyBroadcast"&&typeof payload.instanceId=="string"){try{let event=new CustomEvent(`Broadcast.Message.${payload.instanceId}`,{detail:payload.message});Object.defineProperty(event,"param",{configurable:!0,value:payload.message}),document.dispatchEvent(event)}catch{}return}if(payload.kind==="notification"&&typeof payload.name=="string"){let listener=notificationListeners.get(payload.name);listener&&setTimeout(()=>listener(payload.data),0);return}if(!(payload.kind!=="message"||!config2.messageEvent))try{document.dispatchEvent(new CustomEvent(config2.messageEvent,{detail:{data:payload.data}}))}catch{}}function sendAppMessage(message){if(isTop){handleAppMessage(message);return}window.top?.postMessage({source:SRC,type:"appMessageToOpener",message},"*")}function applyRuntimeResponses(responses){let current=config2.actions.responses??{};for(let[api,response]of Object.entries(responses))!response||typeof response!="object"||Array.isArray(response)||(current[api]=response);config2.actions.responses=current}function parseFpt(value){let entries=[],normalized=value.trim();if(!normalized)return entries;let pattern=/([0-9A-Za-z._-]+)\(([0-9A-Za-z._-]+)\)/g,consumed="";for(let match of normalized.matchAll(pattern))consumed+=match[0],entries.push([match[1],match[2]]);return consumed===normalized?entries:[]}function setFptEntry(entries,key,value){entries.delete(key),entries.set(key,value)}function readInitialFptEntries(){let entries=new Map;try{for(let[key,value]of parseFpt(sessionStorage.getItem(FPT_STORAGE_KEY)??""))setFptEntry(entries,key,value)}catch{}try{let currentFpt=new URL(location.href).searchParams.get("fpt")??"";for(let[key,value]of parseFpt(currentFpt))setFptEntry(entries,key,value)}catch{}return entries}let fptEntries=readInitialFptEntries();function serializeFpt(entries){return Array.from(entries,([key,value])=>`${key}(${value})`).join("")}function persistFpt(){try{let value=serializeFpt(fptEntries);value?sessionStorage.setItem(FPT_STORAGE_KEY,value):sessionStorage.removeItem(FPT_STORAGE_KEY)}catch{}}function decorateUrlWithFpt(rawUrl){let targetUrl=mapScheme(rawUrl)??rawUrl;if(fptEntries.size===0)return targetUrl;try{let url2=new URL(targetUrl,location.href);if(url2.protocol!=="http:"&&url2.protocol!=="https:")return targetUrl;let merged=new Map(fptEntries);for(let[key,value]of parseFpt(url2.searchParams.get("fpt")??""))setFptEntry(merged,key,value);return url2.searchParams.set("fpt",serializeFpt(merged)),url2.href}catch{return targetUrl}}function classify(api){let a=config2.actions;return a.open.includes(api)?"open":a.close.includes(api)?"close":a.title.includes(api)?"title":a.navigationBar?.includes(api)?"navigationBar":a.statusBar?.includes(api)?"statusBar":a.systemInfo.includes(api)?"systemInfo":a.mtop.includes(api)?"mtop":a.kvGet?.includes(api)?"kvGet":a.kvSet?.includes(api)?"kvSet":a.kvDelete?.includes(api)?"kvDelete":a.pageContext?.includes(api)?"pageContext":a.responses&&Object.prototype.hasOwnProperty.call(a.responses,api)?"response":a.behaviors&&Object.prototype.hasOwnProperty.call(a.behaviors,api)?a.behaviors[api]:a.noop.includes(api)?"noop":"unknown"}function pickUrl(params){if(!params||typeof params!="object")return null;let p=params,candidates=[p.url,p.data?.url,p.param?.url,p.value?.params?.url];for(let c of candidates)if(typeof c=="string"&&c)return c;return null}function pickCloseData(params){if(params&&typeof params=="object"){let p=params;if("data"in p&&p.data!==void 0)return p.data;if(Object.keys(p).length>0)return p}}function decodeCookieValue2(raw){let value=raw;for(let i=0;i<2;i+=1)try{let decoded=decodeURIComponent(value);if(decoded===value)break;value=decoded}catch{break}return value.replace(/\\u([0-9a-f]{4})/gi,(_match,hex3)=>String.fromCharCode(Number.parseInt(hex3,16)))}function readCookie(name){let prefix=`${name}=`,pair=document.cookie.split(";").map(value=>value.trim()).find(value=>value.startsWith(prefix));return pair?decodeCookieValue2(pair.slice(prefix.length)):""}function readUserCookie(name){let pageUserCookie=w.userCookie;if(!pageUserCookie||typeof pageUserCookie!="object")return"";let value=pageUserCookie[name];return typeof value=="string"?decodeCookieValue2(value):""}function readFirstUserCookie(names){for(let name of names){let value=readCookie(name)||readUserCookie(name);if(value&&value!=="null")return value}return""}let cbSeq=0,callbacks={};function stashCallback(fn){if(typeof fn!="function")return 0;let id=++cbSeq;return callbacks[id]=fn,id}function extractQuery(url2,param){let q=url2.indexOf("?");if(q===-1)return null;for(let pair of url2.slice(q+1).split("&")){let eq=pair.indexOf("=");if(eq>0&&pair.slice(0,eq)===param)return pair.slice(eq+1)}return null}function matchesHostSuffix(hostname3,suffixes){if(!suffixes?.length)return!0;let normalizedHost=hostname3.toLowerCase().replace(/\.$/,"");return suffixes.some(value=>{let suffix=value.toLowerCase().replace(/^\./,"").replace(/\.$/,"");return normalizedHost===suffix||normalizedHost.endsWith(`.${suffix}`)})}function matchesRouteHost(rawUrl,suffixes){if(!suffixes?.length)return!0;try{let parsed=new URL(rawUrl,location.href),hostname3=parsed.protocol==="http:"||parsed.protocol==="https:"?parsed.hostname:location.hostname;return matchesHostSuffix(hostname3,suffixes)}catch{return matchesHostSuffix(location.hostname,suffixes)}}function resolveSchemeValue(raw,depth){if(depth>3)return null;let value=raw;try{value=decodeURIComponent(raw)}catch{}if(value.startsWith("{"))try{let found=pickUrl(JSON.parse(value));if(!found)return null;value=found}catch{return null}if(/^https?:/i.test(value))return value;if(/^[a-z][a-z0-9+.-]*:/i.test(value))return mapScheme(value,depth+1);let nestedUrl=extractQuery(value,"url");return nestedUrl?resolveSchemeValue(nestedUrl,depth+1):null}function mapScheme(url2,depth=0){if(depth>3)return null;let lower=url2.toLowerCase();for(let rule of config2.schemes){if(!matchesRouteHost(url2,rule.hostSuffixes))continue;let normalizedMatch=rule.match.toLowerCase(),matchedUrl=url2;if(!lower.startsWith(normalizedMatch)){if(!normalizedMatch.startsWith("/"))continue;try{let parsed=new URL(url2,location.href);if(matchedUrl=`${parsed.pathname}${parsed.search}${parsed.hash}`,!matchedUrl.toLowerCase().startsWith(normalizedMatch))continue}catch{continue}}if(rule.targetPath){let suffix=matchedUrl.slice(rule.match.length);if(suffix&&!suffix.startsWith("?")&&!suffix.startsWith("#"))continue;try{let source=new URL(matchedUrl),origin=location.origin;if(rule.targetHostPrefix){let hostname3=location.hostname.toLowerCase(),domainSuffix=hostname3==="wapa.taobao.com"||hostname3.endsWith(".wapa.taobao.com")?"wapa.taobao.com":hostname3==="m.taobao.com"||hostname3.endsWith(".m.taobao.com")?"m.taobao.com":"";domainSuffix&&(origin=`https://${rule.targetHostPrefix}.${domainSuffix}`)}let target=new URL(rule.targetPath,`${origin}/`);target.search=source.search,target.hash=source.hash;for(let[key,value]of Object.entries(rule.targetParams??{}))target.searchParams.has(key)||target.searchParams.set(key,value);return target.href}catch{return null}}if(!rule.param)continue;let raw=extractQuery(matchedUrl,rule.param);if(!raw)return null;let resolved=resolveSchemeValue(raw,depth);if(!resolved||!rule.useCurrentOrigin)return resolved;try{let target=new URL(resolved);return`${location.origin}${target.pathname}${target.search}${target.hash}`}catch{return resolved}}return null}function firstRouteParam(params,names){for(let name of names){let value=params.get(name);if(value)return value}return""}function resolvePaymentCallbackUrl(rawUrl,paymentPageUrl,useCurrentOrigin,forwardParams,resultParam){if(!rawUrl)return null;try{let target=new URL(rawUrl,location.href);for(let name of forwardParams){let value=paymentPageUrl.searchParams.get(name);value&&!target.searchParams.get(name)&&target.searchParams.set(name,value)}resultParam&&target.searchParams.set(resultParam.name,JSON.stringify(resultParam.value));let resolved=useCurrentOrigin&&(target.protocol==="http:"||target.protocol==="https:")?`${location.origin}${target.pathname}${target.search}${target.hash}`:target.href;return decorateUrlWithFpt(resolved)}catch{return null}}function openPaymentCallback(rawUrl,paymentPageUrl,useCurrentOrigin,forwardParams,resultParam){let target=resolvePaymentCallbackUrl(rawUrl,paymentPageUrl,useCurrentOrigin,forwardParams,resultParam);target&&requestOpen(target,0,!1)}function handleMiniProgramPaymentRoute(rawUrl){let paymentPageUrl;try{paymentPageUrl=new URL(rawUrl,location.href)}catch{return!1}let normalizedPathname=paymentPageUrl.pathname.replace(/\/+$/,"")||"/",rule=config2.miniProgram?.paymentRoutes?.find(candidate=>(candidate.pathname.replace(/\/+$/,"")||"/")===normalizedPathname&&matchesHostSuffix(paymentPageUrl.hostname,candidate.hostSuffixes));if(!rule)return!1;let successUrl=firstRouteParam(paymentPageUrl.searchParams,rule.successUrlParams),failureUrl=firstRouteParam(paymentPageUrl.searchParams,rule.failureUrlParams),forwardParams=rule.forwardParams??[],useCurrentOrigin=rule.useCurrentOrigin===!0,paymentParams;try{let parsed=JSON.parse(paymentPageUrl.searchParams.get(rule.paymentParamsParam)??"");if(!parsed||typeof parsed!="object"||Array.isArray(parsed))throw new Error;paymentParams=parsed,paymentParams.timeStamp!==void 0&&(paymentParams.timeStamp=String(paymentParams.timeStamp))}catch{return log2("微信支付参数解析失败,执行失败回跳",rawUrl),openPaymentCallback(failureUrl,paymentPageUrl,useCurrentOrigin,forwardParams),!0}return showPaymentDialog("wx.requestPayment",paymentParams,result=>{openPaymentCallback(successUrl,paymentPageUrl,useCurrentOrigin,forwardParams,rule.successResultParam?{name:rule.successResultParam,value:result}:void 0)},()=>{openPaymentCallback(failureUrl,paymentPageUrl,useCurrentOrigin,forwardParams)}),!0}function finishMiniProgramNativeRoute(action,result,storageId){handleResume({data:action==="subscribeMessage"?result:void 0,storageId,callbackId:0,final:!0})}function handleMiniProgramNativeRoute(rawUrl){let nativePageUrl;try{nativePageUrl=new URL(rawUrl,location.href)}catch{return!1}let normalizedPathname=nativePageUrl.pathname.replace(/\/+$/,"")||"/",action=nativePageUrl.searchParams.get("action");if(action!=="navigateMiniProgram"&&action!=="subscribeMessage"||!config2.miniProgram?.nativeRoutes?.find(candidate=>(candidate.pathname.replace(/\/+$/,"")||"/")===normalizedPathname&&candidate.actions.includes(action)&&matchesHostSuffix(nativePageUrl.hostname,candidate.hostSuffixes)))return!1;let params={};nativePageUrl.searchParams.forEach((value,name)=>{params[name]=value});let storageId=nativePageUrl.searchParams.get("__storage_id");return handlePageVisibility(!0),showMiniProgramActionDialog(action,params,result=>finishMiniProgramNativeRoute(action,result,storageId),result=>finishMiniProgramNativeRoute(action,result,storageId)),!0}function handleMiniProgramPostMessage(data){let rules=config2.miniProgram?.messageRules;if(!rules?.length)return!1;let messages=Array.isArray(data)?data:[data],handled=!1;for(let value of messages){if(!value||typeof value!="object"||Array.isArray(value))continue;let message=value;if(typeof message.type!="string")continue;let rule=rules.find(candidate=>candidate.type===message.type&&matchesHostSuffix(location.hostname,candidate.hostSuffixes));rule&&(handled=!0,rule.action==="stageBackData"?(pendingMiniProgramBackData=message.data,hasPendingMiniProgramBackData=!0):rule.action==="closeAll"&&(isTop?requestCloseAll(message.data)||requestClose(message.data):window.top?.postMessage({source:SRC,type:"closeAll",data:message.data},"*")))}return handled}function matchesImagePickerScheme(url2){let lower=url2.toLowerCase();return config2.imagePicker?.schemes.some(scheme=>lower.startsWith(scheme))===!0}function handleMaybeScheme(url2){if(typeof url2!="string"||!url2||!/^[a-z][a-z0-9+.-]*:/i.test(url2)||/^(https?|about|blob|data|javascript):/i.test(url2))return!1;let mapped=mapScheme(url2);return mapped?(log2("scheme 映射为 H5 open:",url2,"→",mapped),requestOpen(decorateUrlWithFpt(mapped),0,!1)):log2("外部 scheme 已拦截(真机表现为唤端):",url2),!0}function handleResume(msg){let{data,storageId,callbackId,final,gotoEvent,silent}=msg;if(gotoEvent&&dispatchGotoEvent(data),callbackId&&callbacks[callbackId]){if(!silent)try{callbacks[callbackId]({backdata:data})}catch(e){console.error(TAG,"callbackCommand 执行失败",e)}final&&delete callbacks[callbackId]}if(data&&typeof data=="object"&&storageId)try{let d={...data};d.__$data=!0,d.__$storageId=String(storageId),localStorage.setItem("XPI_BACK_LISTENER_DATA_STORAGE",JSON.stringify(d))}catch{}simulatedPageHidden?handlePageVisibility(!1):dispatchActiveEvents()}function dispatchGotoEvent(data){if(data!==void 0)try{document.dispatchEvent(new CustomEvent("WV.GotoEvent",{detail:{data}}))}catch{}}function sendUserTrack(params){if(!params||typeof params!="object")return;let p=params,logkey=typeof p.logkey=="string"?p.logkey:"",gmkey=typeof p.gmkey=="string"?p.gmkey:typeof p.event=="string"?p.event:"",gokey=typeof p.gokey=="string"?p.gokey:"";if(!/^\/[0-9A-Za-z._/-]+$/.test(logkey)||!/^[0-9A-Za-z_-]+$/.test(gmkey))return;let pageWindow=w,aplus=pageWindow.goldlog??pageWindow.aplus;if(typeof aplus?.send!="function")return;let configuredHost=aplus.getMetaInfo?.("aplus-rhost-g"),host2=(typeof configuredHost=="string"?configuredHost:"gm.mmstat.com").replace(/^https?:\/\//i,"").replace(/^\/\//,"").split("/")[0];if(!(!host2||!/^[0-9A-Za-z.-]+$/.test(host2)))try{aplus.send(`//${host2}${logkey}`,`gmkey=${encodeURIComponent(gmkey)}&gokey=${gokey}&ts=${Date.now()}`,"GET")}catch{}}function readNetworkState(){let connection=navigator.connection;return navigator.onLine?connection?.type==="wifi"?"wifi":connection?.effectiveType??"unknown":"fail"}function networkTypeNumber(state){return{wifi:2,"slow-2g":3,"2g":3,"3g":4,"4g":5,"5g":6,fail:7}[state]??0}function calendarTimestamp(value){if(typeof value=="number"&&Number.isFinite(value))return value;if(typeof value!="string"||!value.trim())return null;let numeric=Number(value);if(Number.isFinite(numeric)&&numeric>0)return numeric;let parsed=Date.parse(value);return Number.isFinite(parsed)?parsed:null}function calendarEventFromParams(params){let p=params&&typeof params=="object"?params:{},stringValue=(...values)=>values.find(value=>typeof value=="string")??"";return{title:stringValue(p.calendar_title,p.title),startTime:calendarTimestamp(p.calendar_start_ms??p.start_time??p.calendar_start_datetime),endTime:calendarTimestamp(p.calendar_end_ms??p.end_time??p.calendar_end_datetime),url:stringValue(p.calendar_url,p.url),note:stringValue(p.calendar_note,p.note),location:stringValue(p.calendar_location,p.location)}}function readCalendarEvents(){try{let parsed=JSON.parse(localStorage.getItem(CALENDAR_STORAGE_KEY)??"[]");return Array.isArray(parsed)?parsed.filter(event=>event!==null&&typeof event=="object"&&typeof event.title=="string"):[]}catch{return[]}}function writeCalendarEvents(events){try{return localStorage.setItem(CALENDAR_STORAGE_KEY,JSON.stringify(events)),!0}catch{return!1}}function sameCalendarEvent(stored,candidate){return candidate.url?stored.url===candidate.url:!!candidate.title&&stored.title===candidate.title&&(candidate.startTime===null||stored.startTime===candidate.startTime)&&(candidate.endTime===null||stored.endTime===candidate.endTime)}function calendarEventResponse(event){return{title:event.title,start_time:event.startTime,end_time:event.endTime,url:event.url,note:event.note,location:event.location}}function dispatch(api,params,onSuccess,onFailure,callbackCommandFn){let succeed=value=>{onSuccess&&setTimeout(()=>onSuccess(value),0)},failed=reason=>{onFailure&&setTimeout(()=>onFailure(reason),0)},kind=classify(api),silent=config2.actions.silent?.includes(api)===!0;if(silent||log2("桥调用",api,`(${kind})`,params??""),kind==="open"||kind==="navigate"){let p=params&&typeof params=="object"?params:{},navigationData=p.data&&typeof p.data=="object"?p.data:void 0;if(kind==="navigate"&&navigationData?.type==="back"){isTop?requestCloseAll(navigationData.data,!0)||dispatchGotoEvent(navigationData.data):window.top?.postMessage({source:SRC,type:"closeAll",data:navigationData.data,gotoEvent:!0},"*"),succeed({});return}let url2=pickUrl(params);if(!url2){failed("missing url");return}if(matchesImagePickerScheme(url2)){openImagePicker(callbackCommandFn),succeed({});return}if(handleMiniProgramPaymentRoute(url2)){succeed({});return}if(handleMiniProgramNativeRoute(url2)){succeed({});return}let wd=p.useWebdialog===!0||p.useWebdialog==="true"||p.useWebdialog===1||p.useWebdialog==="1";requestOpen(decorateUrlWithFpt(url2),stashCallback(callbackCommandFn),wd,p),succeed({});return}if(kind==="closeAll"){isTop?requestCloseAll(void 0):window.top?.postMessage({source:SRC,type:"closeAll"},"*"),succeed({});return}if(kind==="closeBackData"){let p=params&&typeof params=="object"?params:{};requestClose(Object.prototype.hasOwnProperty.call(p,"backdata")?p.backdata:pickCloseData(p)),succeed({});return}if(kind==="close"){if(api==="navigateBack"&&hasPendingMiniProgramBackData){let data=pendingMiniProgramBackData;pendingMiniProgramBackData=void 0,hasPendingMiniProgramBackData=!1,requestClose(data)}else requestClose(pickCloseData(params));succeed({});return}if(kind==="postMessage"){let p=params&&typeof params=="object"?params:{},data=p.data??p;handleMiniProgramPostMessage(data)||sendAppMessage({kind:"message",data}),succeed({});return}if(kind==="notifySubscribe"){let p=params&&typeof params=="object"?params:{};if(typeof p.name!="string"||!p.name){failed("missing notification name");return}onSuccess&¬ificationListeners.set(p.name,onSuccess);return}if(kind==="notifyUnsubscribe"){let p=params&&typeof params=="object"?params:{};typeof p.name=="string"&¬ificationListeners.delete(p.name),succeed({});return}if(kind==="notifyPost"){let p=params&&typeof params=="object"?params:{};if(typeof p.name!="string"||!p.name){failed("missing notification name");return}sendAppMessage({kind:"notification",name:p.name,data:p.data}),succeed({});return}if(kind==="sharedFileRead"||kind==="sharedFileWrite"||kind==="sharedDataGet"||kind==="sharedDataSet"){requestContainerData(kind,params&&typeof params=="object"?params:{},succeed,failed);return}if(kind==="legacyBroadcastCreate"||kind==="legacyBroadcastPost"||kind==="legacyBroadcastClose"){requestContainerData(kind,params&&typeof params=="object"?params:{},succeed,failed);return}if(kind==="title"){let title=params&&typeof params=="object"?params.title??params.name:void 0;if(typeof title=="string"&&title){systemBars.markStateExplicit();try{document.title=title,syncSimulatedTitleBar()}catch{}isTop||window.top?.postMessage({source:SRC,type:"title",title},"*")}succeed({});return}if(kind==="navigationBar"){applyNavigationBarState(api,params),succeed({});return}if(kind==="statusBar"){applyStatusBarState(params),succeed({});return}if(kind==="systemInfo"){let model=config2.globals.__DEVICE_MODEL__||"iPhone",info={language:config2.language,model,systemVersion:config2.systemVersion,statusBarHeight:config2.statusBarHeight,platform:config2.platform,brand:config2.platform==="iOS"?"Apple":"Android",client_version:config2.globals.__APP_VERSION__??"",client_type:config2.clientType};succeed(api==="WVNativeDetector.getModelInfo"?{...info,platform:model}:info);return}if(kind==="mtop"){callMtop(params??{},onSuccess,onFailure);return}if(kind==="mtopStream"){callMtopStream(params??{},succeed,failed);return}if(kind==="kvGet"||kind==="kvSet"||kind==="kvDelete"){let p=params&&typeof params=="object"?params:{},key=typeof p.key=="string"?p.key:"";if(!key){failed("missing key");return}try{let storageKey=`__mearl_app_kv__:${key}`;if(kind==="kvGet"){let stored=localStorage.getItem(storageKey);stored!==null?succeed(stored):failed(JSON.stringify({ret:["HY_FAILED"],msg:"key not found"}))}else if(kind==="kvSet"){let value=typeof p.value=="string"?p.value:p.value===void 0?"":JSON.stringify(p.value);localStorage.setItem(storageKey,value),succeed({})}else localStorage.removeItem(storageKey),succeed({})}catch{failed(JSON.stringify({ret:["HY_FAILED"],msg:"kv storage unavailable"}))}return}if(kind==="pageContext"){succeed({pageContext:void 0});return}if(kind==="memoryGet"||kind==="memorySet"||kind==="memoryDelete"){let p=params&&typeof params=="object"?params:{},key=typeof p.key=="string"?p.key:"";if(!key){failed({error_message:"missing key"});return}try{let storageKey=`__mearl_app_memory__:${key}`;if(kind==="memoryGet"){let value=sessionStorage.getItem(storageKey);succeed(value===null?{}:{value})}else if(kind==="memorySet"){let value=typeof p.value=="string"?p.value:p.value===void 0?"":JSON.stringify(p.value);sessionStorage.setItem(storageKey,value),succeed({key,success:!0})}else sessionStorage.removeItem(storageKey),succeed({key,success:!0})}catch{failed({error_message:"memory cache unavailable"})}return}if(kind==="availabilityMap"){let p=params&&typeof params=="object"?params:{},channels=Array.isArray(p.data)?p.data.filter(value=>typeof value=="string"):[];succeed({res:"success",data:Object.fromEntries(channels.map(channel=>[channel,!1]))});return}if(kind==="userInfo"){let userId=readFirstUserCookie(["unb"]),userName=readFirstUserCookie(["_w_tb_nick","_nk_","snk","tracknick"]);callUserInfo({...userId&&{userId},...userName&&{userName}},succeed);return}if(kind==="networkInfo"){let state=readNetworkState();if(api==="WVNetwork.getNetworkType"){succeed({type:{wifi:"WIFI","slow-2g":"2G","2g":"2G","3g":"3G","4g":"4G"}[state]??"UNKNOWN"});return}if(config2.profile==="alipay"||config2.profile==="koubei"){succeed({networkAvailable:state!=="fail",networkType:{wifi:"WIFI","slow-2g":"2G","2g":"2G","3g":"3G","4g":"4G",fail:"NOTREACHABLE"}[state]??"UNKNOWN"});return}let type=networkTypeNumber(state);succeed({type,state:state==="slow-2g"?"2g":state});return}if(kind==="networkQualityMonitor"){let p=params&&typeof params=="object"?params:{},action=typeof p.action=="string"?p.action:"";if(action==="add_notify_network_quality"){if(!stopNetworkQualityMonitor){let notify=()=>{try{document.dispatchEvent(new CustomEvent("WV.NETWORK_TYPE_CHANGED",{detail:{new_network_type:networkTypeNumber(readNetworkState())}}))}catch{}},connection=navigator.connection;window.addEventListener("online",notify),window.addEventListener("offline",notify),connection?.addEventListener?.("change",notify),stopNetworkQualityMonitor=()=>{window.removeEventListener("online",notify),window.removeEventListener("offline",notify),connection?.removeEventListener?.("change",notify)}}succeed({});return}if(action==="remove_notify_network_quality"){stopNetworkQualityMonitor?.(),stopNetworkQualityMonitor=null,succeed({});return}failed({error_message:"unsupported network quality monitor action"});return}if(kind==="beaconRequest"){let url2=pickUrl(params);if(!url2){failed({error_message:"missing url"});return}try{let resolved=new URL(url2,location.href);if(resolved.protocol!=="http:"&&resolved.protocol!=="https:"){failed({error_message:"unsupported request protocol"});return}let image=new Image;image.referrerPolicy="no-referrer-when-downgrade",image.src=resolved.href,succeed({})}catch{failed({error_message:"invalid url"})}return}if(kind==="calendar"){let p=params&&typeof params=="object"?params:{},events=readCalendarEvents();if(api==="store_calendar_event"){let event=calendarEventFromParams(p);if(!event.title||event.startTime===null){failed({error_message:"calendar title and start time are required"});return}let next=events.filter(stored=>!sameCalendarEvent(stored,event));if(next.push(event),!writeCalendarEvents(next)){failed({error_message:"calendar storage unavailable"});return}succeed({success:!0});return}if(api==="remove_calendar_event"){let candidate=calendarEventFromParams(p),next=events.filter(stored=>!sameCalendarEvent(stored,candidate));if(!writeCalendarEvents(next)){failed({error_message:"calendar storage unavailable"});return}succeed({success:!0,removed:events.length-next.length});return}if(api==="check_batch_calendar"){let batch=Array.isArray(p.batch)?p.batch:[];succeed({batch:batch.map(item=>{let candidate=calendarEventFromParams(item);return{...item&&typeof item=="object"?item:{},success:events.some(stored=>sameCalendarEvent(stored,candidate))}})});return}let urls=Array.isArray(p.urls)?p.urls.filter(value=>typeof value=="string"):typeof p.url=="string"?[p.url]:[],titles=Array.isArray(p.calendar_titles)?p.calendar_titles.filter(value=>typeof value=="string"):typeof p.calendar_title=="string"?[p.calendar_title]:[],matched=events.filter(event=>(urls.length===0||urls.includes(event.url))&&(titles.length===0||titles.includes(event.title)));succeed({events:matched.map(calendarEventResponse)});return}if(kind==="geolocation"){let p=params&&typeof params=="object"?params:{},windvane=api==="WVLocation.getLocation",wechat=api==="getLocation"&&config2.bridges.some(bridge=>bridge.style==="wechat"),failLocation=(errorCode,errorMsg)=>{failed({errorCode,errorMsg,...windvane&&{ret:["HY_FAILED"],errMsg:errorCode===1?"PERMISSION_DENIED":"POSITION_UNAVAILABLE",message:errorMsg},...wechat&&{errMsg:`getLocation:fail ${errorMsg}`}})};if(wechat&&p.type&&p.type!=="wgs84"){failLocation(2,`unsupported coordinate type: ${String(p.type)}`);return}if(!navigator.geolocation){failLocation(2,"geolocation unavailable");return}let locate=()=>navigator.geolocation.getCurrentPosition(position=>{let{latitude,longitude,accuracy,altitude,altitudeAccuracy,heading,speed}=position.coords,coords={latitude,longitude,accuracy,altitude,altitudeAccuracy,heading,speed};if(api==="lbs"){let provider=config2.geolocation;if(!provider){failLocation(2,"reverse geocoding unavailable");return}callMtop({api:provider.reverseGeocodeApi,v:provider.version,data:{latitude,longitude,includeGJ:1},timeout:5e3},value=>{let response=value??{},address=response.data??{};if(!Array.isArray(response.ret)||!response.ret.some(ret=>typeof ret=="string"&&ret.startsWith("SUCCESS::"))||typeof address.cityName!="string"||!address.cityName.trim()||typeof address.cityCode!="string"||!address.cityCode.trim()){failLocation(2,"reverse geocoding returned no city");return}succeed({...coords,timestamp:position.timestamp,country:address.country,province:address.province,district:address.district,city:address.cityName,cityName:address.cityName,cityCode:address.cityCode,divisionId:address.divisionId,iataCode:address.iataCode,address:address.detail})},()=>failLocation(2,"reverse geocoding failed"));return}succeed(windvane?{ret:["HY_SUCCESS"],coords,timestamp:position.timestamp}:{...coords,timestamp:position.timestamp,...wechat&&{errMsg:"getLocation:ok"}})},error48=>failLocation(error48.code,error48.message),{enableHighAccuracy:p.enableHighAccuracy===!0||p.enableHighAcuracy===!0,timeout:1e4,maximumAge:p.useCache===!1?0:3e5});navigator.permissions?.query?navigator.permissions.query({name:"geolocation"}).then(status=>{status.state==="granted"?locate():failLocation(1,"location permission not granted")}).catch(locate):locate();return}if(kind==="permission"){let p=params&&typeof params=="object"?params:{},action=typeof p.action=="string"?p.action:"",permission=typeof p.permission=="string"?p.permission:"",permissionFailed=message=>failed({error_code:-1,error_message:message});if(permission==="album"||permission==="MODIFY_AUDIO_SETTINGS"){action==="check"||action==="request"?succeed({}):permissionFailed("unsupported permission action");return}let browserPermission=permission==="mic"?"microphone":permission==="camera"?"camera":permission==="lbs"?"geolocation":"";if(!browserPermission){permissionFailed("unsupported permission");return}if(action==="check"&&navigator.permissions?.query){navigator.permissions.query({name:browserPermission}).then(status=>{status.state==="granted"?succeed({}):permissionFailed("permission not granted")}).catch(()=>permissionFailed("permission check failed"));return}if(action==="request"&&(permission==="mic"||permission==="camera")){if(!navigator.mediaDevices?.getUserMedia){permissionFailed("media permission unavailable");return}navigator.mediaDevices.getUserMedia({audio:permission==="mic",video:permission==="camera"}).then(stream=>{for(let track of stream.getTracks())track.stop();succeed({})}).catch(()=>permissionFailed("permission denied"));return}if(action==="request"&&permission==="lbs"&&navigator.geolocation){navigator.geolocation.getCurrentPosition(()=>succeed({}),()=>permissionFailed("permission denied"),{timeout:1e4});return}permissionFailed("unsupported permission action");return}if(kind==="prefetch"){let p=params&&typeof params=="object"?params:{},url2=typeof p.url=="string"?p.url:"";if(!url2){failed({code:-1,errorMsg:"url is empty"});return}let resolvedUrl;try{resolvedUrl=new URL(url2,location.href).href}catch{failed({code:-1,errorMsg:"invalid url"});return}if(!Array.from(document.querySelectorAll('link[rel="prefetch"]')).some(link=>link.href===resolvedUrl)){let link=document.createElement("link");link.rel="prefetch",link.href=url2,(document.head??document.documentElement).appendChild(link)}succeed({});return}if(kind==="fptTrack"){let p=params&&typeof params=="object"?params:{},action=typeof p.action=="string"?p.action:"",actionParams=p.params&&typeof p.params=="object"?p.params:{},key=typeof actionParams.key=="string"?actionParams.key:"";if(action==="setFpt"){let value=typeof actionParams.value=="string"?actionParams.value:"";if(!key||!value||!/^[0-9A-Za-z._-]+$/.test(key)||!/^[0-9A-Za-z._-]+$/.test(value)||`${key}(${value})`.length>100){failed({error_message:"invalid fpt key or value"});return}setFptEntry(fptEntries,key,value),persistFpt()}else action==="deleteFpt"&&key&&(fptEntries.delete(key),persistFpt());succeed({});return}if(kind==="previewFile"){let p=params&&typeof params=="object"?params:{},fileUrl=typeof p.file_url=="string"?p.file_url:"",remoteUrl=typeof p.file_remote_url=="string"?p.file_remote_url:"",url2=(fileUrl.startsWith("http")?fileUrl:remoteUrl)||fileUrl||remoteUrl;url2?(requestOpen(url2,0,!1),succeed({})):failed({code:-1,errorMsg:"file_url is empty"});return}if(kind==="toast"){let error48=showAppToast(params);error48?failed({error_message:error48}):succeed({});return}if(kind==="unsupportedNativeInput"){let containerType="";try{containerType=new URL(location.href).searchParams.get("containerType")??""}catch{}!unsupportedNativeInputNotified&&(containerType==="h5_dx"||containerType==="flutter_h5")&&(unsupportedNativeInputNotified=!0,showAppToast({message:"当前页面使用原生输入框,请移除 URL 中的 containerType 参数以正常操作",milliseconds:4e3})),succeed({});return}if(kind==="payment"){log2("桥调用支付,等待用户确认",api,params),showPaymentDialog(api,params,succeed,failed);return}if(kind==="userTrack"){sendUserTrack(params),succeed({});return}if(kind==="response"){succeed(config2.actions.responses?.[api]);return}if(kind==="noop"){succeed({});return}silent||log2("未覆盖桥方法,回调 failure(页面库将走 H5 兜底):",api),failed(NOT_IMPLEMENTED_PAYLOAD)}let MEGA_SUPPORTED_APIS={stdPop:["showWeex2","showWeex","showH5","changeSize","close"],broadcast:["addEventListener","dispatchEvent","removeEventListener"],kvStorage:["setItem","getItem","removeItem","getAllKeys","clear","getCurrentInfo","getCurrentInfoAndKeys"],LifeCycle:["addPageLifeCycleListener","removePageLifeCycleListener"],Container:["interceptPageClose","disableInterceptPageClose"],navigator:["openURL","close","replace","setSystemBackBlockListener","removeSystemBackBlockListener"],NavBar:["setTitle"],Router:["popPage"]};function isMegaApiSupported(ability,api){return typeof ability=="string"&&typeof api=="string"&&MEGA_SUPPORTED_APIS[ability]?.includes(api)===!0}function megaParams(value){return value&&typeof value=="object"&&!Array.isArray(value)?value:{}}function megaError(callback,statusCode,message){emitMegaCallback(callback,{statusCode,type:"result",data:{errorMessage:typeof message=="string"?message:String(message??"")}})}function cloneMegaDetail(value){if(value===void 0)return{success:!0,value:void 0};try{return{success:!0,value:JSON.parse(JSON.stringify(value))}}catch{return{success:!1}}}function megaSuccess(data={}){return{statusCode:0,type:"result",data}}function megaFailure(message){return{statusCode:500,type:"result",data:{errorMessage:message}}}function megaKVParams(params){return{bizId:typeof params.bizID=="string"?params.bizID:typeof params.bizId=="string"?params.bizId:"",key:typeof params.key=="string"?params.key:"",value:typeof params.value=="string"?params.value:null}}function megaStringByteLength(value){try{return typeof TextEncoder=="function"?new TextEncoder().encode(value).length:value.length}catch{return value.length}}function megaKVUsedSize(entries){let size=0;for(let value of entries.values())size+=megaStringByteLength(value);return size}function reportMegaKVMutation(operation,bizId,key="",value,onSuccess,onFailure){requestContainerData("megaKVMutation",{operation,bizId,key,...value===void 0?{}:{value}},()=>onSuccess?.(),reason=>{log2("KVStorage 容器同步失败:",reason),onFailure?.(reason)})}function completeMegaKVMutation(operation,bizId,key,value,synchronous,callback){let result=megaSuccess();return reportMegaKVMutation(operation,bizId,key,value,synchronous?void 0:()=>emitMegaCallback(callback,result),synchronous?void 0:reason=>emitMegaCallback(callback,megaFailure(String(reason??"container sync failed")))),synchronous?result:null}function executeMegaKVStorage(api,params,synchronous,callback){let{bizId,key,value}=megaKVParams(params);if(!bizId)return megaFailure("missing bizID");let entries=megaKVStorage.get(bizId)??new Map;if(api==="setItem"){if(!key)return megaFailure("missing key");if(value===null||value==="")return megaFailure("missing value");let previousSize=megaStringByteLength(entries.get(key)??"");return megaKVUsedSize(entries)-previousSize+megaStringByteLength(value)>MEGA_KV_TOTAL_SIZE?megaFailure("KVStorage quota exceeded"):(entries.set(key,value),megaKVStorage.set(bizId,entries),megaKVMutationVersion+=1,persistMegaKVStorage(),completeMegaKVMutation("set",bizId,key,value,synchronous,callback))}if(api==="getItem"){if(!key)return megaFailure("missing key");let result=entries.get(key)??"";return megaSuccess(synchronous?{result}:result)}if(api==="removeItem")return key?(entries.delete(key),entries.size===0&&megaKVStorage.delete(bizId),megaKVMutationVersion+=1,persistMegaKVStorage(),completeMegaKVMutation("remove",bizId,key,void 0,synchronous,callback)):megaFailure("missing key");if(api==="getAllKeys"){let result=Array.from(entries.keys());return megaSuccess(synchronous?{result}:result)}if(api==="clear")return megaKVStorage.delete(bizId),megaKVMutationVersion+=1,persistMegaKVStorage(),completeMegaKVMutation("clear",bizId,"",void 0,synchronous,callback);if(api==="getCurrentInfo"||api==="getCurrentInfoAndKeys"){let data={totalSize:MEGA_KV_TOTAL_SIZE,freeSize:Math.max(MEGA_KV_TOTAL_SIZE-megaKVUsedSize(entries),0)};return api==="getCurrentInfoAndKeys"&&(data.keys=Array.from(entries.keys())),megaSuccess(data)}return{statusCode:405,type:"result",data:{}}}function handleMegaLifeCycle(api,callback){if(api==="addPageLifeCycleListener"){callback&&megaLifeCycleListeners.add(callback),emitMegaCallback(callback,megaSuccess());return}if(api==="removePageLifeCycleListener"){let listeners=Array.from(megaLifeCycleListeners);megaLifeCycleListeners.clear(),emitMegaCallback(callback,megaSuccess());for(let listener of listeners)emitMegaCallback(listener,{statusCode:99,type:"finish",data:{}});return}megaError(callback,405,`LifeCycle.${api} is not supported`)}function handleMegaContainer(api,callback){if(api==="interceptPageClose"){callback&&megaPageCloseListeners.add(callback),emitMegaCallback(callback,megaSuccess());return}if(api==="disableInterceptPageClose"){let listeners=Array.from(megaPageCloseListeners);megaPageCloseListeners.clear(),emitMegaCallback(callback,megaSuccess());for(let listener of listeners)emitMegaCallback(listener,{statusCode:99,type:"finish",data:{}});return}megaError(callback,405,`Container.${api} is not supported`)}function megaNavigationUrl(params){let rawUrl=pickUrl(params);if(!rawUrl)return null;if(!params.extQuery||typeof params.extQuery!="object"||Array.isArray(params.extQuery))return rawUrl;try{let target=new URL(rawUrl,location.href);for(let[key,value]of Object.entries(params.extQuery))value!=null&&target.searchParams.set(key,String(value));return target.href}catch{return rawUrl}}function handleMegaNavigator(api,params,callback){if(api==="openURL"||api==="replace"){let url2=megaNavigationUrl(params);if(!url2){megaError(callback,500,"missing url");return}let callbackId=api==="openURL"&&callback?stashCallback(value=>{let backdata=value&&typeof value=="object"?value.backdata:void 0;emitMegaCallback(callback,{statusCode:1,type:"onResult",data:{result:!0,...backdata===void 0?{}:{data:backdata}}}),emitMegaCallback(callback,{statusCode:99,type:"finish",data:{}})}):0;requestOpen(url2,callbackId,!1,{...params,...api==="replace"?{__mearlReplace:!0}:{}}),emitMegaCallback(callback,megaSuccess());return}if(api==="close"){emitMegaCallback(callback,megaSuccess()),requestClose(void 0);return}if(api==="setSystemBackBlockListener"){megaSystemBackListener&&megaSystemBackListener!==callback&&emitMegaCallback(megaSystemBackListener,{statusCode:99,type:"finish",data:{}}),megaSystemBackListener=callback??null,emitMegaCallback(callback,megaSuccess());return}if(api==="removeSystemBackBlockListener"){let listener=megaSystemBackListener;megaSystemBackListener=null,emitMegaCallback(callback,megaSuccess()),listener&&emitMegaCallback(listener,{statusCode:99,type:"finish",data:{}});return}megaError(callback,405,`navigator.${api} is not supported`)}function handleMegaNavBar(api,params,callback){if(api!=="setTitle"){megaError(callback,405,`NavBar.${api} is not supported`);return}applyNavigationBarState(api,params),emitMegaCallback(callback,megaSuccess())}function handleMegaRouter(api,callback){if(api!=="popPage"){megaError(callback,405,`Router.${api} is not supported`);return}emitMegaCallback(callback,megaSuccess()),requestClose(void 0)}function handleMegaStdPop(api,params,callback){if(api==="showH5"||api==="showWeex2"||api==="showWeex"){let url2=pickUrl(params),popId=typeof params.popId=="string"?params.popId.trim():"";if(!url2||!popId){megaError(callback,500,url2?"missing popId":"missing url");return}let callbackId=stashCallback(value=>{let result=value&&typeof value=="object"&&"backdata"in value?value.backdata:void 0;emitMegaCallback(callback,{statusCode:1,type:"onClose",data:result}),emitMegaCallback(callback,{statusCode:99,type:"finish"})});requestOpen(url2,callbackId,!0,{...params,__mearlMegaPopId:popId}),emitMegaCallback(callback,{statusCode:0,type:"result",data:{}});return}if(api==="close"){let popId=typeof params.popId=="string"?params.popId.trim():"";if(!popId){megaError(callback,500,"missing popId");return}let cloned=cloneMegaDetail(params.result);if(!cloned.success){megaError(callback,500,"result is not serializable");return}requestContainerData("megaPopClose",{popId,result:cloned.value},()=>emitMegaCallback(callback,{statusCode:0,type:"result",data:{}}),reason=>megaError(callback,500,reason));return}if(api==="changeSize"){let popId=typeof params.popId=="string"?params.popId.trim():"";if(!popId){megaError(callback,500,"missing popId");return}requestContainerData("megaPopResize",{...params,popId},()=>emitMegaCallback(callback,{statusCode:0,type:"result",data:{}}),reason=>megaError(callback,500,reason));return}megaError(callback,405,`stdPop.${api} is not supported`)}function handleMegaBroadcast(api,params,callback){let bizId=megaBroadcastBizId(params.bizId),eventName=typeof params.eventName=="string"?params.eventName.trim():"";if(!eventName){megaError(callback,500,"missing eventName");return}if(api==="addEventListener"){if(!callback)return;let id=`mearl-mega-listener-${++megaListenerSeq}`;megaBroadcastListeners.set(id,{id,bizId,eventName,once:params.once===!0,callback}),emitMegaCallback(callback,{statusCode:0,type:"result",data:{}}),emitMegaCallback(callback,{statusCode:1,type:"onAdd",data:{listenerId:id}});return}if(api==="dispatchEvent"){let detail=cloneMegaDetail(params.detail);if(!detail.success){megaError(callback,500,"detail is not serializable");return}requestContainerData("megaBroadcast",{message:{kind:"megaBroadcast",bizId,eventName,detail:detail.value}},()=>emitMegaCallback(callback,{statusCode:0,type:"result",data:{}}),reason=>megaError(callback,500,reason));return}if(api==="removeEventListener"){let listenerId=typeof params.listenerId=="string"?params.listenerId:"",removed=[];for(let listener of Array.from(megaBroadcastListeners.values()))listener.bizId!==bizId||listener.eventName!==eventName||listenerId&&listener.id!==listenerId||(megaBroadcastListeners.delete(listener.id),removed.push(listener));emitMegaCallback(callback,{statusCode:0,type:"result",data:{}});for(let listener of removed)emitMegaCallback(listener.callback,{statusCode:99,type:"finish"});return}megaError(callback,405,`broadcast.${api} is not supported`)}function makeMegaBridge(){return{asyncCall:(ability,api,rawParams,callback)=>{let params=megaParams(rawParams);if(ability==="ability"&&api==="available"){emitMegaCallback(callback,{statusCode:0,type:isMegaApiSupported(params.ability,params.api)?"YES":"NO",data:{}});return}if(ability==="ability"&&api==="batchFinishTrace"){emitMegaCallback(callback,{statusCode:0,type:"result",data:{}});return}if(!isMegaApiSupported(ability,api)){megaError(callback,405,`${ability}.${api} is not supported`);return}if(ability==="stdPop")handleMegaStdPop(api,params,callback);else if(ability==="broadcast")handleMegaBroadcast(api,params,callback);else if(ability==="kvStorage"){let result=executeMegaKVStorage(api,params,!1,callback);result&&emitMegaCallback(callback,result)}else ability==="LifeCycle"?handleMegaLifeCycle(api,callback):ability==="Container"?handleMegaContainer(api,callback):ability==="navigator"?handleMegaNavigator(api,params,callback):ability==="NavBar"?handleMegaNavBar(api,params,callback):handleMegaRouter(api,callback)},syncCall:(ability,api,rawParams)=>{let params=megaParams(rawParams);return ability==="ability"&&api==="available"?{statusCode:0,type:isMegaApiSupported(params.ability,params.api)?"YES":"NO",data:{}}:ability==="kvStorage"&&isMegaApiSupported(ability,api)?executeMegaKVStorage(api,params,!0)??megaFailure("container sync pending"):{statusCode:405,type:"result",data:{}}}}}function makeBridge(style){if(style==="mega")return makeMegaBridge();if(style==="easybikeNative"){let callNative=rawPayload=>{let payload;try{payload=typeof rawPayload=="string"?JSON.parse(rawPayload):rawPayload??{}}catch{return}let classMap=typeof payload.classMap=="string"?payload.classMap:"",method=typeof payload.method=="string"?payload.method:"",callbackId=typeof payload.callbackId=="string"||typeof payload.callbackId=="number"?String(payload.callbackId):"",params;try{params=typeof payload.params=="string"?payload.params?JSON.parse(payload.params):{}:payload.params??{}}catch{params={}}let complete=(code,data,msg="")=>{let callback=resolveWindowFunction("callBack");callbackId&&callback&&callback({callbackId,code,data,msg})};dispatch(`${classMap}.${method}`,params,value=>complete(0,value),error48=>complete(1,void 0,typeof error48=="string"?error48:String(error48??"")))};return{postMessage:callNative,callNative}}if(style==="windvane"){let call=(api,params,success2,failure)=>{let onSuccess=typeof success2=="function"?success2:void 0,onFailure=typeof failure=="function"?failure:void 0;if(onSuccess||onFailure){dispatch(api,params,onSuccess,onFailure);return}return new Promise((resolve2,reject)=>dispatch(api,params,resolve2,reject))};return{isAvailable:!0,version:"8.7.0",call2:call,call:(cls,method,params,succ,fail2)=>call(`${cls}.${method}`,params,succ,fail2)}}if(style==="fliggy"||style==="alipay"||style==="callback"){let bridge={call:(api,params,succ,fail2)=>{typeof params=="function"&&(fail2=succ,succ=params,params=void 0);let p=params&&typeof params=="object"?params:{},successFn=succ??(typeof p.success_callback=="function"?p.success_callback:void 0)??(typeof p.successCallback=="function"?p.successCallback:void 0),failureFn=fail2??(typeof p.fail_callback=="function"?p.fail_callback:void 0)??(typeof p.failure_callback=="function"?p.failure_callback:void 0)??(typeof p.failCallback=="function"?p.failCallback:void 0)??(typeof p.failureCallback=="function"?p.failureCallback:void 0);dispatch(api,p,res=>successFn?.(res),err=>{failureFn?failureFn(err):successFn?.({error:err})},p.callbackCommand??p.callback_command)},pushBack:(prefixOrApi,apiOrParams,paramsOrSucc,succ)=>{let api=prefixOrApi,params=apiOrParams,success2=paramsOrSucc;typeof apiOrParams=="string"&&(api=apiOrParams,params=paramsOrSucc,success2=succ);let p=params??{},successFn=(typeof success2=="function"?success2:void 0)??(typeof p.successCallback=="function"?p.successCallback:void 0);return dispatch(api,p,res=>successFn?.(res),void 0,p.callbackCommand??p.callback_command),bridge},sendUriScheme:uri=>(handleMaybeScheme(uri),bridge)};if(style==="fliggy"){let normalizedAppName=(config2.globals.__APP_NAME__??"").toUpperCase(),os11=config2.clientType==="iphone"?"ios":"android",isAliApp=name=>normalizedAppName===name.toUpperCase();Object.assign(bridge,{version:"1.0.21",device:{os:os11,OS:config2.platform,type:os11,version:config2.systemVersion,model:config2.globals.__DEVICE_MODEL__??""},platform:os11,isAliApp,isTmall:isAliApp("TM"),isTaobao:isAliApp("TB"),isAlipay:isAliApp("AP"),isAlitrip:isAliApp("LX"),isKoubei:isAliApp("KB"),isElm:isAliApp("ELMC"),isGaode:isAliApp("amap"),isUC:/UCBrowser/i.test(config2.userAgent),isWeibo:/Weibo/i.test(config2.userAgent),isWeixin:/MicroMessenger/i.test(config2.userAgent),isWindVane:config2.bridges.some(item=>item.style==="windvane"),isAlipayClient:/AlipayClient/i.test(config2.userAgent)})}return bridge}if(style==="btrip")return{call:(api,params)=>dispatch(api,params??{},void 0,void 0)};if(style==="invoke")return{invoke:(api,params)=>{let p=params??{};dispatch(api,p,p.success,p.fail)}};if(style==="callHandler")return{callHandler:(api,params)=>dispatch(api,params??{},void 0,void 0)};if(style==="amap")return{ready:cb=>cb?.(),send:(msg,cb)=>{let m=msg??{};dispatch(typeof m.action=="string"?m.action:"",m,res=>cb?.(res),err=>cb?.({error:err}))}};if(style==="didi")return{openPage:params=>dispatch("openPage",params??{},void 0,void 0),closePage:params=>dispatch("closePage",params??{},void 0,void 0)};if(style==="wechat"||style==="wechatMiniProgram"){let invoke2=(api,params)=>{let p=params&&typeof params=="object"?params:{};dispatch(api,p,value=>{p.success?.(value),p.complete?.(value)},error48=>{p.fail?.(error48),p.complete?.(error48)})};return style==="wechat"?{ready:callback=>{callback&&setTimeout(callback,0)},getLocation:params=>invoke2("getLocation",params)}:{navigateTo:params=>invoke2("navigateTo",params),redirectTo:params=>invoke2("redirectTo",params),switchTab:params=>invoke2("switchTab",params),reLaunch:params=>invoke2("reLaunch",params),navigateBack:params=>invoke2("navigateBack",params),postMessage:params=>invoke2("postMessage",params),getEnv:callback=>{callback&&setTimeout(()=>callback({miniprogram:!0}),0)}}}return{}}function setGlobal(path19,value){let parts=path19.split("."),obj=w;for(let i=0;i<parts.length-1;i++){let cur=obj[parts[i]];(!cur||typeof cur!="object")&&(obj[parts[i]]={}),obj=obj[parts[i]]}obj[parts[parts.length-1]]=value}function setPersistentGlobal(path19,value){let parts=path19.split(".").filter(Boolean);if(parts.length<2){setGlobal(path19,value);return}let[rootKey,...nestedParts]=parts,isObjectLike=candidate=>typeof candidate=="object"&&candidate!==null||typeof candidate=="function",attachBridge=candidate=>{let root=isObjectLike(candidate)?candidate:{},obj=root;for(let index=0;index<nestedParts.length-1;index+=1){let key=nestedParts[index],child=obj[key];if(!isObjectLike(child))try{obj[key]={}}catch{return root}obj=obj[key]}let leaf=nestedParts[nestedParts.length-1];try{Object.defineProperty(obj,leaf,{configurable:!1,enumerable:!0,get:()=>value,set:()=>{}})}catch{try{obj[leaf]=value}catch{}}return root},currentRoot=attachBridge(w[rootKey]);try{Object.defineProperty(w,rootKey,{configurable:!1,enumerable:!0,get:()=>currentRoot,set:next=>{currentRoot=attachBridge(next)}})}catch{w[rootKey]=currentRoot}}if(config2.bridges.some(spec=>spec.style==="mega")){let hydrationVersion=megaKVMutationVersion;requestContainerData("megaKVSnapshot",{},value=>{let entries=value&&typeof value=="object"?value.entries:void 0;megaKVMutationVersion===hydrationVersion&&replaceMegaKVStorage(entries)},()=>{})}for(let spec of config2.bridges)try{let bridge=makeBridge(spec.style);spec.persistent?setPersistentGlobal(spec.global,bridge):setGlobal(spec.global,bridge)}catch(e){console.error(TAG,"桥安装失败:",spec.global,e)}return{mapScheme,handleMaybeScheme,handleAppMessage,handleNativeBack,handleResume,handlePageVisibility,applyRuntimeResponses}}function installAppProfileContainerStack(config2,environment,links){let{SRC,TAG,simulateSystemBars,ROOT_FRAME_NAME,LAYER_FRAME_NAME,isTop,isRootFrame,isLayerFrame,isContainerFrame,usesRootContainer,log:log2}=environment,{pageTransport}=links,initialLayerTitleBarState=url2=>links.getSystemBars().initialLayerTitleBarState(url2),resolvedTitleBarState=layer=>links.getSystemBars().resolvedTitleBarState(layer),parseReportedTitleBarState=value=>links.getSystemBars().parseReportedTitleBarState(value),createSimulatedNavigationBarView=(placement,onBack)=>links.getSystemBars().createNavigationBarView(placement,onBack),destroySimulatedNavigationBarView=view=>links.getSystemBars().destroyNavigationBarView(view),syncLayerViewport=(layer,state)=>links.getSystemBars().syncLayerViewport(layer,state),syncActiveSystemBars=()=>links.getSystemBars().syncActiveSystemBars(),syncSimulatedTitleBar=()=>links.getSystemBars().syncSimulatedTitleBar(),rootContainerActive=!1,rootFrame=null,rootBusinessUrl=location.href,webViewEnvironmentRequestSeq=0,simulatedPageHidden=!1,runtimeResponses=null;function syncSimulatorStateToWindow(target){target&&(runtimeResponses&&target.postMessage({source:SRC,type:"runtimeResponses",profile:config2.profile,responses:runtimeResponses},"*"),simulatedPageHidden&&target.postMessage({source:SRC,type:"simulatorVisibility",hidden:!0},"*"))}function startPreparedWebViewNavigation(frame,target,canCommit,registerCleanup){let insets=config2.safeAreaInsets??{top:config2.statusBarHeight,right:0,bottom:0,left:0};if(!usesRootContainer||!Object.values(insets).some(value=>value>0)){canCommit()&&(frame.src=target);return}let requestId=++webViewEnvironmentRequestSeq,settled=!1,fallbackTimer=0,cleanup=()=>{settled||(settled=!0,clearTimeout(fallbackTimer),window.removeEventListener("message",handleResponse),registerCleanup?.(null))},commitNavigation=fallbackReason=>{cleanup(),fallbackReason&&console.warn(TAG,"WebView 环境准备未完成,降级提交导航",{target,requestId,reason:fallbackReason}),canCommit()&&(frame.src=target)},handleResponse=event=>{if(event.source!==window||event.data?.source!=="mearl-content"||event.data?.type!=="APP_BRIDGE_PREPARE_WEBVIEW_RESPONSE"||event.data?.requestId!==requestId)return;let result=event.data.result;result?.success===!0?commitNavigation():commitNavigation(String(result?.error??"unknown preparation failure"))};registerCleanup?.(cleanup),window.addEventListener("message",handleResponse),fallbackTimer=setTimeout(()=>commitNavigation("preparation timed out after 500ms"),500);try{window.postMessage({source:SRC,type:"prepareWebView",requestId},"*")}catch(error48){commitNavigation(error48 instanceof Error?error48.message:String(error48))}}function installRootContainer(){if(!usesRootContainer||!/^https?:$/i.test(location.protocol))return;let shellRoot,frame;try{for(let cookie of config2.rootContainer?.initialCookies??[]){if(!cookie.name)continue;let parts=[`${encodeURIComponent(cookie.name)}=${encodeURIComponent(cookie.value)}`,`Path=${cookie.path??"/"}`];cookie.domain&&parts.push(`Domain=${cookie.domain}`),document.cookie=parts.join("; ")}shellRoot=document.createElement("html");let shellHead=document.createElement("head"),charset=document.createElement("meta"),viewport=document.createElement("meta"),title=document.createElement("title"),shellBody=document.createElement("body");frame=document.createElement("iframe"),shellRoot.setAttribute("data-mearl-app-shell",""),shellBody.setAttribute("data-mearl-app-shell",""),charset.setAttribute("charset","utf-8"),viewport.name="viewport",viewport.content="width=device-width,initial-scale=1,viewport-fit=cover",shellHead.append(charset,viewport,title),shellRoot.append(shellHead,shellBody),shellRoot.style.cssText="width:100%;height:100%;margin:0;overflow:hidden;background:#fff;",shellBody.style.cssText="width:100%;height:100%;margin:0;overflow:hidden;background:#fff;",frame.name=ROOT_FRAME_NAME,frame.setAttribute("data-mearl-root-webview",config2.profile),frame.style.cssText="position:fixed;left:0;right:0;top:0;bottom:0;width:100%;height:100%;border:0;display:block;background:#fff;z-index:0;opacity:1;",frame.addEventListener("load",()=>{let committedSrc=frame.getAttribute("src");!committedSrc||committedSrc==="about:blank"||(syncSimulatorStateToWindow(frame.contentWindow),requestAnimationFrame(()=>{rootFrame!==frame||!frame.isConnected||(frame.setAttribute("data-mearl-webview-ready",""),syncSimulatedTitleBar())}))}),shellBody.appendChild(frame);let currentRoot=document.documentElement;currentRoot?document.replaceChild(shellRoot,currentRoot):document.appendChild(shellRoot)}catch(error48){console.warn(TAG,"根 WebView 容器创建失败,保留当前页面",error48),rootFrame=null;return}rootFrame=frame,rootContainerActive=!0;try{typeof window.stop=="function"&&window.stop()}catch(error48){console.warn(TAG,"停止外层文档加载失败,继续启动根 WebView",error48)}try{startPreparedWebViewNavigation(frame,rootBusinessUrl,()=>rootFrame===frame&&frame.isConnected)}catch(error48){console.warn(TAG,"根 WebView 环境准备启动失败,直接提交业务导航",error48),rootFrame===frame&&frame.isConnected&&(frame.src=rootBusinessUrl)}}installRootContainer();function normalizeProxyPathPrefix(prefix){let withLeadingSlash=prefix.startsWith("/")?prefix:`/${prefix}`;return withLeadingSlash.endsWith("/")?withLeadingSlash:`${withLeadingSlash}/`}function matchesProxyTarget(hostname3,suffixes){return suffixes.some(suffix=>hostname3===suffix||hostname3.endsWith(`.${suffix}`))}function mapLayerFrameUrl(url2){let proxy=config2.layerUrlProxy;if(!proxy||!location.hostname.startsWith(proxy.sourceHostPrefix))return url2;try{let target=new URL(url2,location.href);if(!/^https?:$/.test(target.protocol))return url2;let prefix=normalizeProxyPathPrefix(proxy.pathPrefix);if(target.hostname===location.hostname){if(target.pathname.startsWith(prefix))return url2;let derivedHost=location.pathname.startsWith(prefix)?location.pathname.slice(prefix.length).split("/")[0]:proxy.defaultTargetHost;return!derivedHost||!matchesProxyTarget(derivedHost,proxy.targetHostSuffixes)?url2:`${location.origin}${prefix}${derivedHost}${target.pathname}${target.search}${target.hash}`}return matchesProxyTarget(target.hostname,proxy.targetHostSuffixes)?`${location.origin}${prefix}${target.host}${target.pathname}${target.search}${target.hash}`:url2}catch{return url2}}function restoreLayerBusinessUrl(url2){let proxy=config2.layerUrlProxy;if(!proxy)return url2;try{let current=new URL(url2,location.href),prefix=normalizeProxyPathPrefix(proxy.pathPrefix);if(current.origin!==location.origin||!current.pathname.startsWith(prefix))return url2;let rest=current.pathname.slice(prefix.length),slash=rest.indexOf("/"),host=slash===-1?rest:rest.slice(0,slash);if(!host)return url2;let hostname3=new URL(`${current.protocol}//${host}`).hostname;if(!matchesProxyTarget(hostname3,proxy.targetHostSuffixes))return url2;let pathname=slash===-1?"/":rest.slice(slash);return`${current.protocol}//${host}${pathname}${current.search}${current.hash}`}catch{return url2}}let ANIM_MS=config2.animationMs??300;function boolParam(value,fallback){return value===!0||value===1||value==="1"||value==="true"?!0:value===!1||value===0||value==="0"||value==="false"?!1:value===""?!0:fallback}function numberParam(value,fallback,min,max){let parsed=typeof value=="number"?value:Number(value);return Number.isFinite(parsed)?Math.min(Math.max(parsed,min),max):fallback}function resolveOverlayPresentation(url2,params,explicitWebdialog){let query=null;try{query=new URL(url2,location.href).searchParams}catch{}let records=[],addRecord=value=>{value&&typeof value=="object"&&!Array.isArray(value)&&records.push(value)};addRecord(params?.pageParams),addRecord(params?.page_params),addRecord(params?.popConfig),addRecord(params?.data),addRecord(params?.param),addRecord(params);let read=key=>{for(let record2 of records)if(Object.prototype.hasOwnProperty.call(record2,key))return record2[key];return query?.has(key)?query.get(key):void 0},protocol=config2.overlay;if(!explicitWebdialog&&(!protocol||!boolParam(read(protocol.enabledParam),!1)))return null;let configuredTopRatio=protocol?read(protocol.topRatioParam):void 0,configuredHeightRatio=protocol?.heightRatioParam?read(protocol.heightRatioParam):void 0,configuredMaxHeight=read("maxHeight")??configuredHeightRatio,defaultTopRatio=protocol?.defaultTopRatio??.2;return{topRatio:configuredTopRatio!==void 0?numberParam(configuredTopRatio,defaultTopRatio,0,1):configuredMaxHeight!==void 0?1-numberParam(configuredMaxHeight,1-defaultTopRatio,0,1):defaultTopRatio,widthRatio:numberParam(read("maxWidth"),1,0,1),radius:numberParam((protocol?read(protocol.radiusParam):void 0)??read("cornerRadius"),protocol?.defaultRadius??0,0,50),maskAlpha:numberParam(protocol?read(protocol.maskAlphaParam):void 0,protocol?.defaultMaskAlpha??.3,0,1),tapClose:boolParam((protocol?read(protocol.tapCloseParam):void 0)??read("tapEnable"),protocol?.defaultTapClose??!0)}}function requestsPopBeforeOpen(url2,params){if(params?.__mearlReplace===!0)return!0;let key=config2.popBeforeOpenParam;if(!key)return!1;let records=[params?.pageParams,params?.page_params,params?.data,params?.param,params];for(let value of records){if(!value||typeof value!="object"||Array.isArray(value))continue;let record2=value;if(Object.prototype.hasOwnProperty.call(record2,key))return boolParam(record2[key],!1)}try{let query=new URL(url2,location.href).searchParams;return query.has(key)&&boolParam(query.get(key),!1)}catch{return!1}}let layers=[],forwardStack=[],layerSeq=0,enteringLayerCount=0,closingLayerCount=0,explicitLayerTitleBarStates=new Map,rootScrollStyles=null,pendingClose=null,nativeBackRequestSeq=0,pendingNativeBack=null,containerDataRequestSeq=0,containerDataCallbacks=new Map,sharedFiles=new Map,sharedData=new Map,legacyBroadcastChannels=new Set,MEGA_KV_STORAGE_KEY=`__mearl_mega_kv__:${config2.profile}`;function readMegaKVStorage(){let storage=new Map;try{let parsed=JSON.parse(localStorage.getItem(MEGA_KV_STORAGE_KEY)??"{}");if(!parsed||typeof parsed!="object"||Array.isArray(parsed))return storage;for(let[bizId,rawEntries]of Object.entries(parsed)){if(!rawEntries||typeof rawEntries!="object"||Array.isArray(rawEntries))continue;let entries=new Map;for(let[key,value]of Object.entries(rawEntries))typeof value=="string"&&entries.set(key,value);storage.set(bizId,entries)}}catch{}return storage}let megaKVStorage=readMegaKVStorage();function megaKVSnapshot(){let snapshot={};for(let[bizId,values]of megaKVStorage)snapshot[bizId]=Object.fromEntries(values);return snapshot}function persistMegaKVStorage(){try{localStorage.setItem(MEGA_KV_STORAGE_KEY,JSON.stringify(megaKVSnapshot()))}catch{}}let PENDING_CLOSE_TIMEOUT_MS=400,pendingHistoryDepth=null;function clearPendingClose(){pendingClose&&(clearTimeout(pendingClose.timer),pendingClose=null)}function clearPendingNativeBack(){pendingNativeBack&&(clearTimeout(pendingNativeBack.timer),pendingNativeBack=null)}function clearPendingHistoryDepth(){pendingHistoryDepth&&(clearTimeout(pendingHistoryDepth.timer),pendingHistoryDepth=null)}function syncHistoryAfterDirectClose(){clearPendingHistoryDepth();let depth=layers.length,timer=setTimeout(()=>{pendingHistoryDepth=null,console.warn(TAG,"WebView 已出栈,但浏览器历史未在预期时间内同步",{depth})},PENDING_CLOSE_TIMEOUT_MS);pendingHistoryDepth={depth,timer},history.back()}function armPendingClose(data,retries){clearPendingClose();let timer=setTimeout(()=>{pendingClose=null,log2("close 未等到 popstate,直接关栈顶兜底"),closeToDepth(Math.max(layers.length-1,0),data,!0)},PENDING_CLOSE_TIMEOUT_MS);pendingClose={data,retries,timer},history.back()}function parseStorageId(url2){try{return new URL(url2,location.href).searchParams.get("__storage_id")}catch{return null}}function titleBarStateCacheKey(url2){try{let parsed=new URL(url2,location.href);return parsed.hash="",parsed.href}catch{return url2}}function cacheExplicitTitleBarState(layer,state){explicitLayerTitleBarStates.set(titleBarStateCacheKey(layer.entryUrl),state),explicitLayerTitleBarStates.set(titleBarStateCacheKey(layer.url),state)}function readDepth(state){if(state&&typeof state=="object"){let d=state.__mearl_layer__;if(typeof d=="number")return d}return null}function mapUrlForSync(url2){let suffixes=config2.urlSyncHostSuffixes??[];try{let u=new URL(url2,location.href);if(!/^https?:$/.test(u.protocol)||!(suffixes.length===0||suffixes.some(s=>u.host===s||u.host.endsWith(`.${s}`))))return;if(u.origin===location.origin)return u.pathname+u.search+u.hash;let proxy=config2.layerUrlProxy;return proxy&&location.hostname.startsWith(proxy.sourceHostPrefix)&&matchesProxyTarget(u.hostname,proxy.targetHostSuffixes)?`${normalizeProxyPathPrefix(proxy.pathPrefix)}${u.host}${u.pathname}${u.search}${u.hash}`:u.pathname+u.search+u.hash}catch{return}}function createLayerEl(overlay,id){let el=document.createElement("div");el.setAttribute("data-mearl-layer",String(id)),el.style.cssText=`position:fixed;inset:0;z-index:${2147483e3+id%100*2};`;let frame=document.createElement("iframe");if(frame.name=LAYER_FRAME_NAME,frame.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-modals allow-downloads allow-popups"),frame.style.cssText="position:absolute;inset:0;width:100%;height:100%;border:0;display:block;background:#fff;z-index:0;opacity:1;",overlay){el.style.pointerEvents="none";let mask=document.createElement("div");mask.style.cssText=`position:absolute;inset:0;background:rgba(0,0,0,${overlay.maskAlpha});opacity:0;pointer-events:auto;`;let sheet=document.createElement("div"),width=overlay.widthRatio*100,left=(1-overlay.widthRatio)/2*100;return sheet.style.cssText=`position:absolute;left:${left}%;right:auto;bottom:0;width:${width}%;height:${(1-overlay.topRatio)*100}%;background:#fff;border-radius:${overlay.radius}px ${overlay.radius}px 0 0;overflow:hidden;pointer-events:auto;`,sheet.appendChild(frame),el.appendChild(mask),el.appendChild(sheet),{el,frame,animEl:sheet,mask}}return el.style.background="#fff",el.appendChild(frame),{el,frame,animEl:el,mask:null}}function setLayerInteractive(layer,interactive){layer.frame.style.pointerEvents=interactive?"":"none",layer.titleBarView&&(layer.titleBarView.root.style.pointerEvents=interactive?"":"none"),interactive?(layer.frame.removeAttribute("inert"),layer.frame.removeAttribute("aria-hidden"),layer.frame.removeAttribute("tabindex")):(layer.frame.setAttribute("inert",""),layer.frame.setAttribute("aria-hidden","true"),layer.frame.setAttribute("tabindex","-1"),layer.frame.blur()),layer.overlay?(layer.el.style.pointerEvents="none",layer.animEl.style.pointerEvents=interactive?"auto":"none",layer.mask&&(layer.mask.style.pointerEvents=interactive?"auto":"none")):layer.el.style.pointerEvents=interactive?"":"none"}function setRootFrameInteractive(interactive){rootFrame&&(rootFrame.style.pointerEvents=interactive?"":"none",interactive?(rootFrame.removeAttribute("inert"),rootFrame.removeAttribute("aria-hidden"),rootFrame.removeAttribute("tabindex")):(rootFrame.setAttribute("inert",""),rootFrame.setAttribute("aria-hidden","true"),rootFrame.setAttribute("tabindex","-1"),rootFrame.blur()))}function blockClosingLayerInteractions(layer){setLayerInteractive(layer,!1),layer.el.style.pointerEvents="auto"}function syncRootScrollLock(locked){let body=document.body;if(locked&&!rootScrollStyles){rootScrollStyles={html:document.documentElement.style.overflow,body:body?.style.overflow??null},document.documentElement.style.overflow="hidden",body&&(body.style.overflow="hidden");return}!locked&&rootScrollStyles&&(document.documentElement.style.overflow=rootScrollStyles.html,body&&rootScrollStyles.body!==null&&(body.style.overflow=rootScrollStyles.body),rootScrollStyles=null)}function syncLayerInteractivity(){let activeLayer=closingLayerCount===0&&enteringLayerCount===0?layers[layers.length-1]:void 0;for(let layer of layers)setLayerInteractive(layer,layer===activeLayer),!activeLayer&&layer===layers[layers.length-1]&&(layer.el.style.pointerEvents="auto");setRootFrameInteractive(layers.length===0&&enteringLayerCount===0&&closingLayerCount===0),syncRootScrollLock(layers.length>0||enteringLayerCount>0||closingLayerCount>0)}function finishLayerEntry(layer){layer.entering&&(layer.entering=!1,layer.enterTimer!==null&&clearTimeout(layer.enterTimer),layer.enterTimer=null,layer.enterTransitionEnd&&(layer.animEl.removeEventListener("transitionend",layer.enterTransitionEnd),layer.enterTransitionEnd=null),enteringLayerCount=Math.max(enteringLayerCount-1,0),syncLayerInteractivity())}function animateIn(layer){let t=layer.animEl;if(t.style.transform=layer.overlay?"translateY(100%)":"translateX(100%)",t.offsetWidth,t.style.transition=`transform ${ANIM_MS}ms ease`,t.style.transform="translate(0px, 0px)",layer.mask&&(layer.mask.style.transition=`opacity ${ANIM_MS}ms ease`,layer.mask.style.opacity="1"),ANIM_MS<=0){finishLayerEntry(layer);return}layer.enterTransitionEnd=event=>{event.target===t&&event.propertyName==="transform"&&finishLayerEntry(layer)},t.addEventListener("transitionend",layer.enterTransitionEnd),layer.enterTimer=setTimeout(()=>finishLayerEntry(layer),ANIM_MS+60)}function animateOut(layer,done){let t=layer.animEl;if(ANIM_MS<=0){t.style.transform=layer.overlay?"translateY(100%)":"translateX(100%)",layer.mask&&(layer.mask.style.opacity="0"),setTimeout(done,0);return}let settled=!1,fallbackTimer=0,finish=()=>{settled||(settled=!0,t.removeEventListener("transitionend",onTransitionEnd),clearTimeout(fallbackTimer),done())},onTransitionEnd=event=>{event.target===t&&event.propertyName==="transform"&&finish()};t.addEventListener("transitionend",onTransitionEnd),t.style.transition=`transform ${ANIM_MS}ms ease`,t.style.transform=layer.overlay?"translateY(100%)":"translateX(100%)",layer.mask&&(layer.mask.style.opacity="0"),fallbackTimer=setTimeout(finish,ANIM_MS+60)}function startLayerNavigation(layer,target){startPreparedWebViewNavigation(layer.frame,target,()=>!layer.closing&&layer.el.isConnected,cleanup=>{layer.navigationPreparationCleanup=cleanup})}function setPageVisibility(target,hidden){if(target===window){links.getBridgeProtocol().handlePageVisibility(hidden);return}try{target.postMessage({source:SRC,type:"simulatorVisibility",hidden},"*")}catch{}}function openLayer(url2,callbackId,overlay,openerWin,pushHistory,popId=null){clearPendingClose();let target=url2;if(!/^https?:/i.test(target)){let mapped=links.getBridgeProtocol().mapScheme(target);if(!mapped)return log2("open 失败,scheme 未映射:",url2),null;target=mapped}location.protocol==="https:"&&target.startsWith("http:")&&(target="https:"+target.slice(5));let presentation=overlay??resolveOverlayPresentation(target,void 0,!1);log2("open →",presentation?"(webdialog) ":"",target);let parts=createLayerEl(presentation,++layerSeq),restoredTitleBarState=explicitLayerTitleBarStates.get(titleBarStateCacheKey(target)),layer={id:layerSeq,win:parts.frame.contentWindow,frame:parts.frame,entryUrl:target,url:target,overlay:presentation,openerWin,callbackId,storageId:parseStorageId(target),popId,el:parts.el,animEl:parts.animEl,mask:parts.mask,entering:!0,enterTimer:null,enterTransitionEnd:null,closing:!1,navigationPreparationCleanup:null,titleBarState:restoredTitleBarState??initialLayerTitleBarState(target),titleBarStateExplicit:restoredTitleBarState!==void 0,titleBarStateReady:restoredTitleBarState!==void 0,titleBarView:null};if(popId&&layer.el.setAttribute("data-mearl-pop-id",popId),layer.mask&&presentation?.tapClose&&layer.mask.addEventListener("click",()=>requestOverlayClose(layer)),!presentation&&simulateSystemBars&&config2.titleBar&&(layer.titleBarView=createSimulatedNavigationBarView("layer",()=>requestNativeBack()),layer.titleBarView.root.setAttribute("data-mearl-layer-titlebar",String(layer.id)),parts.el.appendChild(layer.titleBarView.root)),layers.push(layer),setPageVisibility(openerWin,!0),enteringLayerCount+=1,syncLayerViewport(layer,layer.titleBarState),syncLayerInteractivity(),parts.frame.addEventListener("load",()=>{layer.win=parts.frame.contentWindow,parts.frame.name=LAYER_FRAME_NAME;let committedSrc=parts.frame.getAttribute("src");!committedSrc||committedSrc==="about:blank"||(syncSimulatorStateToWindow(parts.frame.contentWindow),requestAnimationFrame(()=>{layer.titleBarStateReady||layer.closing||!layer.el.isConnected||(layer.titleBarStateReady=!0,syncLayerViewport(layer,resolvedTitleBarState(layer)))}))}),(document.body??document.documentElement).appendChild(parts.el),layer.win=parts.frame.contentWindow,startLayerNavigation(layer,mapLayerFrameUrl(target)),animateIn(layer),pushHistory){forwardStack.length=0;try{history.pushState({__mearl_layer__:layers.length},"",mapUrlForSync(target))}catch{}}return layer}function replaceLayer(sourceLayer,url2,callbackId,overlay,popId=null){if(sourceLayer.closing||layers[layers.length-1]!==sourceLayer){openLayer(url2,callbackId,overlay,sourceLayer.win??window,!0,popId);return}let replacement=openLayer(url2,callbackId,overlay,sourceLayer.openerWin,!1,popId);if(!replacement)return;sourceLayer.navigationPreparationCleanup?.(),sourceLayer.navigationPreparationCleanup=null,sourceLayer.entering&&(sourceLayer.entering=!1,enteringLayerCount=Math.max(enteringLayerCount-1,0),sourceLayer.enterTimer!==null&&clearTimeout(sourceLayer.enterTimer),sourceLayer.enterTransitionEnd&&sourceLayer.animEl.removeEventListener("transitionend",sourceLayer.enterTransitionEnd));let sourceIndex=layers.indexOf(sourceLayer);sourceIndex>=0&&layers.splice(sourceIndex,1),destroySimulatedNavigationBarView(sourceLayer.titleBarView),sourceLayer.el.remove(),forwardStack.length=0,syncLayerInteractivity(),syncActiveSystemBars();try{history.replaceState({__mearl_layer__:layers.length},"",mapUrlForSync(replacement.url))}catch{}}function closeLayer(layer,data,final,gotoEvent=!1,resumeOpener=!0,silent=!1){if(layer.closing)return;layer.navigationPreparationCleanup?.(),layer.navigationPreparationCleanup=null,layer.entering&&(layer.entering=!1,enteringLayerCount=Math.max(enteringLayerCount-1,0),layer.enterTimer!==null&&clearTimeout(layer.enterTimer),layer.enterTimer=null,layer.enterTransitionEnd&&(layer.animEl.removeEventListener("transitionend",layer.enterTransitionEnd),layer.enterTransitionEnd=null)),layer.closing=!0;let idx=layers.indexOf(layer);idx>=0&&layers.splice(idx,1),closingLayerCount+=1,blockClosingLayerInteractions(layer),syncLayerInteractivity(),syncActiveSystemBars(),final?forwardStack.length=0:forwardStack.push({url:layer.url,overlay:layer.overlay,openerWin:layer.openerWin,callbackId:layer.callbackId,storageId:layer.storageId,popId:layer.popId}),log2("close ←",layer.url,data===void 0?"":data),animateOut(layer,()=>{if(destroySimulatedNavigationBarView(layer.titleBarView),layer.el.remove(),closingLayerCount=Math.max(closingLayerCount-1,0),syncLayerInteractivity(),syncActiveSystemBars(),!!resumeOpener)if(layer.openerWin===window)links.getBridgeProtocol().handleResume({data,storageId:layer.storageId,callbackId:layer.callbackId,final,gotoEvent,silent});else try{layer.openerWin.postMessage({source:SRC,type:"resume",data,storageId:layer.storageId,callbackId:layer.callbackId,final,gotoEvent,silent},"*")}catch{}})}function closeToDepth(depth,data,final){for(;layers.length>depth;){let revealsTarget=layers.length===depth+1;closeLayer(layers[layers.length-1],revealsTarget?data:void 0,final,!1,revealsTarget)}}function closeAllLayers(data,gotoEvent=!1){let depth=layers.length;for(;layers.length>0;){let isRootmostLayer=layers.length===1;closeLayer(layers[layers.length-1],isRootmostLayer?data:void 0,!0,isRootmostLayer&&gotoEvent,isRootmostLayer)}if(depth>0)try{history.go(-depth)}catch{}return depth>0}function requestOverlayClose(layer){if(!(layer.closing||layers[layers.length-1]!==layer)){if(!config2.overlay?.silentTapClose){for(let selector of config2.overlay?.tapCloseSelectors??[])try{let control=layer.frame.contentDocument?.querySelector(selector);if(typeof control?.click!="function")continue;control.click();return}catch{}requestCloseOnTop(void 0);return}pendingClose||pendingHistoryDepth||(closeLayer(layer,void 0,!0,!1,!0,!0),syncHistoryAfterDirectClose())}}function forwardToDepth(depth){for(;layers.length<depth&&forwardStack.length>0;){let entry=forwardStack.pop();openLayer(entry.url,entry.callbackId,entry.overlay,entry.openerWin,!1,entry.popId)}}function requestCloseOnTop(data){if(layers.length===0){history.back();return}if(rootContainerActive){closeLayer(layers[layers.length-1],data,!0),syncHistoryAfterDirectClose();return}armPendingClose(data,8)}function isActiveBusinessWindow(target){let topLayer=layers[layers.length-1];return topLayer?topLayer.frame.contentWindow===target:rootFrame?rootFrame.contentWindow===target:target===window}function finishNativeBack(requestId,target,handled){pendingNativeBack?.requestId!==requestId||pendingNativeBack.target!==target||(clearPendingNativeBack(),!handled&&isActiveBusinessWindow(target)&&requestCloseOnTop(void 0))}function requestNativeBack(){if(!isTop||pendingNativeBack)return;let target=layers[layers.length-1]?.frame.contentWindow??rootFrame?.contentWindow??window;if(!target||target===window){links.getBridgeProtocol().handleNativeBack()||requestCloseOnTop(void 0);return}let requestId=++nativeBackRequestSeq,timer=setTimeout(()=>finishNativeBack(requestId,target,!1),120);pendingNativeBack={requestId,target,timer};try{target.postMessage({source:SRC,type:"nativeBack",requestId},"*")}catch{finishNativeBack(requestId,target,!1)}}function layerForWindow(source){if(source)for(let layer of layers){if(layer.win===source)return layer;let currentWindow=layer.frame.contentWindow;if(currentWindow&¤tWindow===source)return layer.win=currentWindow,layer}}if(isTop){if(!rootContainerActive){let rawPushState=history.pushState.bind(history),rawReplaceState=history.replaceState.bind(history),withDepth=state=>state==null?{__mearl_layer__:layers.length}:typeof state=="object"&&!Array.isArray(state)?{...state,__mearl_layer__:layers.length}:state;try{history.pushState=function(...args){rawPushState(withDepth(args[0]),args[1],args[2])},history.replaceState=function(...args){rawReplaceState(withDepth(args[0]),args[1],args[2])}}catch{}}try{readDepth(history.state)===null&&history.replaceState({__mearl_layer__:0},"")}catch{}window.addEventListener("popstate",e=>{let depth=readDepth(e.state);if(pendingHistoryDepth){let expectedDepth=pendingHistoryDepth.depth;if(clearPendingHistoryDepth(),depth===expectedDepth)return;console.warn(TAG,"浏览器历史深度与 WebView 出栈事务不一致",{expectedDepth,actualDepth:depth})}if(rootContainerActive){if(depth===null)return;depth<layers.length?closeToDepth(depth,void 0,!1):depth>layers.length&&forwardToDepth(depth);return}if(pendingClose){if(depth!==null&&depth<layers.length){let{data}=pendingClose;clearPendingClose(),closeToDepth(depth,data,!0)}else if(pendingClose.retries>0)armPendingClose(pendingClose.data,pendingClose.retries-1);else{let{data}=pendingClose;clearPendingClose(),closeToDepth(layers.length-1,data,!0)}return}depth!==null&&(depth<layers.length?closeToDepth(depth,void 0,!1):depth>layers.length&&forwardToDepth(depth))})}function broadcastAppMessage(message){links.getBridgeProtocol().handleAppMessage(message);let targets=[rootFrame?.contentWindow??null,...layers.filter(layer=>!layer.closing).map(layer=>layer.frame.contentWindow)];for(let target of targets)if(!(!target||target===window))try{target.postMessage({source:SRC,type:"appMessage",message},"*")}catch{}}function closeMegaPop(popId,data){let index=layers.findIndex(layer=>layer.popId===popId&&!layer.closing);if(index<0)return!1;let closingDepth=layers.length-index;closeToDepth(index,data,!0);try{history.go(-closingDepth)}catch{}return!0}function resizeMegaPop(popId,params){let layer=layers.find(candidate=>candidate.popId===popId&&!candidate.closing);if(!layer?.overlay)return!1;if(params.maxHeight!==void 0){let maxHeight=numberParam(params.maxHeight,1-layer.overlay.topRatio,0,1);layer.overlay.topRatio=1-maxHeight,layer.animEl.style.height=`${maxHeight*100}%`}if(params.maxWidth!==void 0){let maxWidth=numberParam(params.maxWidth,1,0,1);layer.overlay.widthRatio=maxWidth,layer.animEl.style.width=`${maxWidth*100}%`,layer.animEl.style.left=`${(1-maxWidth)/2*100}%`,layer.animEl.style.right="auto"}return params.animated===!0&&(layer.animEl.style.transition="height 200ms ease, width 200ms ease, left 200ms ease"),!0}function executeContainerData(action,params){if(action==="sharedFileRead"||action==="sharedFileWrite"){let fileName=typeof params.fileName=="string"?params.fileName:"";if(!fileName)return{success:!1,value:"missing fileName"};if(action==="sharedFileRead")return{success:!0,value:{data:sharedFiles.get(fileName)??""}};let data=typeof params.data=="string"?params.data:String(params.data??"");return sharedFiles.set(fileName,data),{success:!0,value:{}}}if(action==="sharedDataGet"){let keys=Array.isArray(params.keys)?params.keys.filter(key=>typeof key=="string"):[],data={};for(let key of keys)sharedData.has(key)&&(data[key]=sharedData.get(key));return{success:!0,value:{data}}}if(action==="sharedDataSet"){if(!params.data||typeof params.data!="object"||Array.isArray(params.data))return{success:!1,value:"missing shared data"};for(let[key,value]of Object.entries(params.data))value==null?sharedData.delete(key):sharedData.set(key,value);return{success:!0,value:{}}}if(action==="megaBroadcast")return!params.message||typeof params.message!="object"||Array.isArray(params.message)?{success:!1,value:"missing broadcast message"}:(broadcastAppMessage(params.message),{success:!0,value:{}});if(action==="megaKVSnapshot")return{success:!0,value:{entries:megaKVSnapshot()}};if(action==="megaKVMutation"){let operation=typeof params.operation=="string"?params.operation:"",bizId=typeof params.bizId=="string"?params.bizId:"";if(!bizId)return{success:!1,value:"missing bizID"};let key=typeof params.key=="string"?params.key:"";if((operation==="set"||operation==="remove")&&!key)return{success:!1,value:"missing key"};if(operation==="set"){if(typeof params.value!="string")return{success:!1,value:"missing value"};let entries=megaKVStorage.get(bizId)??new Map;entries.set(key,params.value),megaKVStorage.set(bizId,entries)}else if(operation==="remove"){let entries=megaKVStorage.get(bizId);entries?.delete(key),entries?.size===0&&megaKVStorage.delete(bizId)}else if(operation==="clear")megaKVStorage.delete(bizId);else return{success:!1,value:"unsupported KVStorage operation"};return persistMegaKVStorage(),broadcastAppMessage({kind:"megaKVStorage",operation,bizId,key,value:params.value}),{success:!0,value:{}}}if(action==="legacyBroadcastCreate"){let instanceId=typeof params.instanceId=="string"?params.instanceId:"";return instanceId?(legacyBroadcastChannels.add(instanceId),{success:!0,value:{}}):{success:!1,value:"missing instanceId"}}if(action==="legacyBroadcastPost"){let instanceId=typeof params.instanceId=="string"?params.instanceId:"";return instanceId?legacyBroadcastChannels.has(instanceId)?(broadcastAppMessage({kind:"legacyBroadcast",instanceId,message:params.message}),{success:!0,value:{}}):{success:!1,value:"broadcast channel not found"}:{success:!1,value:"missing instanceId"}}if(action==="legacyBroadcastClose"){let instanceId=typeof params.instanceId=="string"?params.instanceId:"";return instanceId?(legacyBroadcastChannels.delete(instanceId),{success:!0,value:{}}):{success:!1,value:"missing instanceId"}}if(action==="megaPopClose"){let popId=typeof params.popId=="string"?params.popId:"";return popId?closeMegaPop(popId,params.result)?{success:!0,value:{}}:{success:!1,value:"popId not found"}:{success:!1,value:"missing popId"}}if(action==="megaPopResize"){let popId=typeof params.popId=="string"?params.popId:"";return popId?resizeMegaPop(popId,params)?{success:!0,value:{}}:{success:!1,value:"popId not found"}:{success:!1,value:"missing popId"}}return{success:!1,value:"unsupported container data action"}}function requestContainerData(action,params,onSuccess,onFailure){if(isTop){let result=executeContainerData(action,params);setTimeout(()=>result.success?onSuccess(result.value):onFailure(result.value),0);return}let requestId=++containerDataRequestSeq;containerDataCallbacks.set(requestId,{success:onSuccess,failure:onFailure});try{window.top?.postMessage({source:SRC,type:"containerDataRequest",requestId,action,params},"*")}catch(error48){containerDataCallbacks.delete(requestId),onFailure(error48 instanceof Error?error48.message:String(error48))}}function requestOpen(url2,callbackId,webdialog,params){let overlay=resolveOverlayPresentation(url2,params,webdialog),popBeforeOpen=requestsPopBeforeOpen(url2,params),popId=typeof params?.__mearlMegaPopId=="string"?params.__mearlMegaPopId:null;isTop?openLayer(url2,callbackId,overlay,window,!0,popId):window.top?.postMessage({source:SRC,type:"open",url:url2,callbackId,overlay,popBeforeOpen,popId},"*")}function requestClose(data){let payload;try{payload=data===void 0?void 0:JSON.parse(JSON.stringify(data))}catch{payload=void 0}isTop?requestCloseOnTop(payload):window.top?.postMessage({source:SRC,type:"close",data:payload},"*")}if(window.addEventListener("message",event=>{let msg=event.data;if(!(!msg||typeof msg!="object")){if(msg.source==="mearl-content"&&(msg.type==="APP_BRIDGE_SIMULATOR_VISIBILITY"||msg.type==="APP_BRIDGE_RUNTIME_RESPONSES")){if(!isTop||event.source!==window)return;if(msg.type==="APP_BRIDGE_SIMULATOR_VISIBILITY"&&typeof msg.hidden=="boolean"){simulatedPageHidden=msg.hidden,links.getBridgeProtocol().handlePageVisibility(msg.hidden);let lifecycleMessage={source:SRC,type:"simulatorVisibility",hidden:msg.hidden};rootFrame?.contentWindow?.postMessage(lifecycleMessage,"*");for(let layer of layers)layer.closing||layer.frame.contentWindow?.postMessage(lifecycleMessage,"*")}else if(msg.type==="APP_BRIDGE_RUNTIME_RESPONSES"&&msg.profile===config2.profile&&msg.responses&&typeof msg.responses=="object"&&!Array.isArray(msg.responses)){let responses=msg.responses;runtimeResponses={...runtimeResponses??{},...responses},links.getBridgeProtocol().applyRuntimeResponses(responses);let configMessage={source:SRC,type:"runtimeResponses",profile:config2.profile,responses};rootFrame?.contentWindow?.postMessage(configMessage,"*");for(let layer of layers)layer.closing||layer.frame.contentWindow?.postMessage(configMessage,"*")}return}if(msg.source===SRC){if(isTop){let sourceLayer=layerForWindow(event.source),sourceIsRoot=!!(rootFrame?.contentWindow&&rootFrame.contentWindow===event.source);if(!sourceLayer&&!sourceIsRoot)return;if(msg.type==="open"&&typeof msg.url=="string"){let rawOverlay=msg.overlay&&typeof msg.overlay=="object"?msg.overlay:void 0,overlay=rawOverlay?{topRatio:numberParam(rawOverlay.topRatio,.2,0,1),widthRatio:numberParam(rawOverlay.widthRatio,1,0,1),radius:numberParam(rawOverlay.radius,0,0,50),maskAlpha:numberParam(rawOverlay.maskAlpha,.3,0,1),tapClose:boolParam(rawOverlay.tapClose,!0)}:resolveOverlayPresentation(msg.url,void 0,!1),callbackId=typeof msg.callbackId=="number"?msg.callbackId:0,popId=typeof msg.popId=="string"&&msg.popId?msg.popId:null;msg.popBeforeOpen===!0&&sourceLayer?replaceLayer(sourceLayer,msg.url,callbackId,overlay,popId):openLayer(msg.url,callbackId,overlay,event.source??window,!0,popId)}else if(msg.type==="close")requestCloseOnTop(msg.data);else if(msg.type==="closeAll"){let gotoEvent=msg.gotoEvent===!0;if(gotoEvent&&sourceIsRoot&&layers.length===0&&msg.data!==void 0)try{event.source.postMessage({source:SRC,type:"resume",data:msg.data,storageId:null,callbackId:0,final:!0,gotoEvent:!0},"*")}catch{}else closeAllLayers(msg.data,gotoEvent)}else if(msg.type==="appMessageToOpener"&&sourceLayer){let target=sourceLayer.openerWin;if(target===window)links.getBridgeProtocol().handleAppMessage(msg.message);else try{target.postMessage({source:SRC,type:"appMessage",message:msg.message},"*")}catch{}}else if(msg.type==="containerDataRequest"&&typeof msg.requestId=="number"&&typeof msg.action=="string"&&msg.params&&typeof msg.params=="object"&&!Array.isArray(msg.params)&&event.source){let result=executeContainerData(msg.action,msg.params);try{event.source.postMessage({source:SRC,type:"containerDataResponse",requestId:msg.requestId,success:result.success,value:result.value},"*")}catch{}}else if(msg.type==="nativeBackResult"&&typeof msg.requestId=="number"&&typeof msg.handled=="boolean"&&event.source)finishNativeBack(msg.requestId,event.source,msg.handled);else if(msg.type==="urlChanged"&&typeof msg.url=="string"){let topLayer=layers[layers.length-1];if(sourceIsRoot&&!topLayer){rootBusinessUrl=msg.url;let mapped=mapUrlForSync(msg.url);if(mapped)try{history.replaceState({__mearl_layer__:0},"",mapped)}catch{}}else if(topLayer&&!topLayer.closing&&sourceLayer===topLayer){topLayer.url=msg.url,topLayer.titleBarStateExplicit&&topLayer.titleBarState&&cacheExplicitTitleBarState(topLayer,topLayer.titleBarState);let mapped=mapUrlForSync(msg.url);if(mapped)try{history.replaceState({__mearl_layer__:layers.length},"",mapped)}catch{}}}else if(msg.type==="title"&&typeof msg.title=="string"){let topLayer=layers[layers.length-1];if(sourceIsRoot&&!topLayer)try{document.title=msg.title,syncSimulatedTitleBar()}catch{}else if(topLayer&&sourceLayer===topLayer){document.title=msg.title;let state=resolvedTitleBarState(topLayer);topLayer.titleBarState={...state,title:msg.title},syncLayerViewport(topLayer,topLayer.titleBarState)}}else if(msg.type==="titleBarState"){let state=parseReportedTitleBarState(msg.state);if(state&&sourceIsRoot)links.getSystemBars().setPresentedRootTitleBarState(state);else if(state&&sourceLayer){let explicit=msg.explicit===!0;sourceLayer.titleBarStateReady=!0,explicit?(sourceLayer.titleBarState=state,sourceLayer.titleBarStateExplicit=!0,cacheExplicitTitleBarState(sourceLayer,state)):sourceLayer.titleBarStateExplicit||(sourceLayer.titleBarState=state);let resolvedState=sourceLayer.titleBarState??state;syncLayerViewport(sourceLayer,resolvedState)}}}else if(msg.type==="simulatorVisibility"&&typeof msg.hidden=="boolean"){if(event.source!==window.top)return;links.getBridgeProtocol().handlePageVisibility(msg.hidden)}else if(msg.type==="appMessage"){if(event.source!==window.top)return;links.getBridgeProtocol().handleAppMessage(msg.message)}else if(msg.type==="nativeBack"&&typeof msg.requestId=="number"){if(event.source!==window.top)return;let handled=links.getBridgeProtocol().handleNativeBack();window.top?.postMessage({source:SRC,type:"nativeBackResult",requestId:msg.requestId,handled},"*")}else if(msg.type==="containerDataResponse"&&typeof msg.requestId=="number"){if(event.source!==window.top)return;let callback=containerDataCallbacks.get(msg.requestId);if(!callback)return;containerDataCallbacks.delete(msg.requestId),msg.success===!0?callback.success(msg.value):callback.failure(msg.value)}else if(msg.type==="runtimeResponses"&&msg.profile===config2.profile&&msg.responses&&typeof msg.responses=="object"&&!Array.isArray(msg.responses)){if(event.source!==window.top)return;links.getBridgeProtocol().applyRuntimeResponses(msg.responses)}else if(msg.type==="resume"){if(event.source!==window.top)return;links.getBridgeProtocol().handleResume({data:msg.data,storageId:msg.storageId??null,callbackId:typeof msg.callbackId=="number"?msg.callbackId:0,final:msg.final===!0,gotoEvent:msg.gotoEvent===!0,silent:msg.silent===!0})}else event.source!==window.top&&window.top?.postMessage(msg,"*");return}pageTransport.handleMessage(msg)}}),!isTop&&isContainerFrame){let reportUrl=()=>{try{window.top?.postMessage({source:SRC,type:"urlChanged",url:restoreLayerBusinessUrl(location.href)},"*")}catch{}};try{let origPushState=history.pushState.bind(history),origReplaceState=history.replaceState.bind(history);history.pushState=function(...args){origPushState(...args),reportUrl()},history.replaceState=function(...args){origReplaceState(...args),reportUrl()},window.addEventListener("popstate",reportUrl),window.addEventListener("hashchange",reportUrl)}catch{}}if(isContainerFrame){let requestProxyLocationOpen=url2=>{if(links.getBridgeProtocol().handleMaybeScheme(url2))return!0;try{let current=new URL(restoreLayerBusinessUrl(location.href)),target=new URL(url2,current);return!/^https?:$/.test(target.protocol)||target.origin===current.origin&&target.pathname===current.pathname&&target.search===current.search?!1:(requestOpen(target.href,0,!1),!0)}catch{return!1}};Object.defineProperty(window,"__PROXY_LOCATION__",{value:{get href(){return location.href},set href(url2){requestProxyLocationOpen(url2)||(location.href=mapLayerFrameUrl(url2))},replace(url2){links.getBridgeProtocol().handleMaybeScheme(url2)||location.replace(mapLayerFrameUrl(url2))},assign(url2){requestProxyLocationOpen(url2)||location.assign(mapLayerFrameUrl(url2))}},writable:!1,configurable:!0})}if(isContainerFrame){document.addEventListener("click",event=>{let el=event.target;for(;el&&el.tagName!=="A";)el=el.parentElement;if(!el)return;let href=el.getAttribute("href");if(href){if(links.getBridgeProtocol().handleMaybeScheme(href)){event.preventDefault(),event.stopPropagation();return}/^https?:/i.test(href)&&el.getAttribute("target")==="_blank"&&(event.preventDefault(),event.stopPropagation(),requestOpen(href,0,!1))}},!0);let origOpen=window.open;window.open=function(url2,target,features){let urlStr=typeof url2=="string"?url2:url2 instanceof URL?url2.href:"";return links.getBridgeProtocol().handleMaybeScheme(urlStr)?null:/^https?:/i.test(urlStr)?(requestOpen(urlStr,0,!1),null):origOpen?origOpen.call(window,url2,target,features):null};try{let proto=Location.prototype,origAssign=proto.assign,origReplace=proto.replace;origAssign&&(proto.assign=function(url2){if(links.getBridgeProtocol().handleMaybeScheme(url2))return;let upgraded=location.protocol==="https:"&&url2.startsWith("http:")?"https:"+url2.slice(5):url2;origAssign.call(this,upgraded)}),origReplace&&(proto.replace=function(url2){if(links.getBridgeProtocol().handleMaybeScheme(url2))return;let upgraded=location.protocol==="https:"&&url2.startsWith("http:")?"https:"+url2.slice(5):url2;origReplace.call(this,upgraded)})}catch{}}return log2("容器环境已就绪",isTop?"(top)":isRootFrame?"(root)":isLayerFrame?"(layer)":"(iframe,仅桥)"),{getRootFrame:()=>rootFrame,getLayers:()=>layers,getClosingLayerCount:()=>closingLayerCount,requestOpen,requestClose,requestNativeBack,requestContainerData,closeAllLayers}}var APP_PROFILE_RUNTIME_FACTORIES={environment:installAppProfileEnvironment,containerStack:installAppProfileContainerStack,bridgeProtocol:installAppProfileBridgeProtocol,pageTransport:installAppProfilePageTransport,systemBars:installAppProfileSystemBars};function buildAppProfileRuntimeCallSource(configExpression){return`(${installAppProfileRuntime.toString()})(${configExpression},{environment:${installAppProfileEnvironment.toString()},pageTransport:${installAppProfilePageTransport.toString()},containerStack:${installAppProfileContainerStack.toString()},systemBars:${installAppProfileSystemBars.toString()},bridgeProtocol:${installAppProfileBridgeProtocol.toString()}})`}function installAppProfileRuntime(config2,factories=APP_PROFILE_RUNTIME_FACTORIES){let environment=factories.environment(config2);if(!environment)return;let pageTransport=factories.pageTransport(config2,environment),containerStack=factories.containerStack(config2,environment,{pageTransport,getSystemBars:()=>systemBars,getBridgeProtocol:()=>bridgeProtocol}),systemBars=factories.systemBars(config2,environment,{getRootFrame:containerStack.getRootFrame,getLayers:containerStack.getLayers,getClosingLayerCount:containerStack.getClosingLayerCount,requestClose:containerStack.requestClose,requestNativeBack:containerStack.requestNativeBack}),bridgeProtocol=factories.bridgeProtocol(config2,environment,{pageTransport,systemBars,requestOpen:containerStack.requestOpen,requestClose:containerStack.requestClose,requestCloseAll:containerStack.closeAllLayers,requestContainerData:containerStack.requestContainerData})}import https from"node:https";import http3 from"node:http";var TYPE_INTO_ELEMENT_SRC=typeIntoElement.toString(),CLICK_ELEMENT_VIA_JS_SRC=clickElementViaJS.toString(),GET_CLICK_COORDS_FROM_NODE_SRC=getClickCoordsFromNode.toString();function nodeFetch(urlStr,options={}){return new Promise((resolve2,reject)=>{let url2=new URL(urlStr),isHttps=url2.protocol==="https:",lib=isHttps?https:http3,{method="GET",headers={},body,timeoutMs=3e4}=options,req=lib.request({host:url2.hostname,port:url2.port||(isHttps?443:80),path:url2.pathname+url2.search,method,headers},res=>{let responseHeaders={};for(let[key,value]of Object.entries(res.headers))typeof value=="string"?responseHeaders[key]=value:Array.isArray(value)&&(responseHeaders[key]=value.join(", "));let chunks=[];res.on("data",chunk=>chunks.push(Buffer.from(chunk))),res.on("end",()=>{let bodyBuffer=Buffer.concat(chunks);resolve2({status:res.statusCode??0,statusText:res.statusMessage??"",headers:responseHeaders,body:bodyBuffer.toString("utf-8"),bodyBuffer})})});req.on("error",reject),req.setTimeout(timeoutMs,()=>{req.destroy(),reject(new Error(`Request timeout: ${urlStr}`))}),body&&req.write(body),req.end()})}async function getCookiesForUrl(session,targetUrl){let result=await session.client.sendCommand("Network.getCookies",{urls:[targetUrl]}),map2=new Map;for(let cookie of result.cookies??[])map2.set(cookie.name,cookie.value);return map2}async function waitForPageLoad(session,timeoutMs){if(isCdpDeviceShellActive(session)){let deadline=Date.now()+timeoutMs;for(;Date.now()<deadline;){if((await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:"document.readyState",returnByValue:!0}).catch(()=>null))?.result?.value==="complete")return;await new Promise(resolve2=>setTimeout(resolve2,50))}throw new Error(`Page load timeout after ${timeoutMs}ms`)}return new Promise((resolve2,reject)=>{let settled=!1,removeLoadListener=()=>{},finish=error48=>{settled||(settled=!0,clearTimeout(timer),removeLoadListener(),error48?reject(error48):resolve2())},timer=setTimeout(()=>{finish(new Error(`Page load timeout after ${timeoutMs}ms`))},timeoutMs);removeLoadListener=session.client.on("Page.loadEventFired",()=>finish()),session.client.sendCommand("Runtime.evaluate",{expression:"document.readyState",returnByValue:!0}).then(result=>{result.result?.value==="complete"&&finish()}).catch(()=>{})})}async function getPageViewportSize(session){let result=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`({
|
|
625
|
+
</style><div id="surface" data-platform="${config2.platform.toLowerCase()}" data-cutout="${String(cutoutKind!=="none")}" data-cutout-kind="${cutoutKind}"><div id="status"><span id="time"></span>${cutoutMarkup}<span id="indicators" aria-hidden="true"><svg id="signal" viewBox="0 0 18 12"><rect x="0" y="8" width="3" height="4" rx="1"/><rect x="5" y="6" width="3" height="6" rx="1"/><rect x="10" y="3" width="3" height="9" rx="1"/><rect x="15" y="0" width="3" height="12" rx="1"/></svg><svg id="wifi" viewBox="1 3.8 22 17.2"><path d="M2 8.82a15 15 0 0 1 20 0"/><path d="M5 12.859a10 10 0 0 1 14 0"/><path d="M8.5 16.429a5 5 0 0 1 7 0"/><path d="M12 20h.01"/></svg><svg id="battery" viewBox="0 0 28 13"><rect id="battery-outline" x=".65" y=".65" width="23" height="11.7" rx="3.1"/><rect id="battery-level" x="2.35" y="2.35" width="19.6" height="8.3" rx="1.7"/><path id="battery-cap" d="M25 4.1c1.1.35 1.7 1.15 1.7 2.4s-.6 2.05-1.7 2.4z"/></svg></span></div></div>`;let surface=shadow.getElementById("surface"),time3=shadow.getElementById("time"),cutout=shadow.getElementById("device-cutout"),cutoutStatusPath=shadow.querySelector("#cutout-check path"),localizedScreenshotText=config2.language.toLowerCase().startsWith("zh")?{idle:"截图",copied:"已复制",downloaded:"已下载",failed:"截图失败"}:{idle:"Screenshot",copied:"Copied",downloaded:"Downloaded",failed:"Capture failed"},setCutoutState=state=>{cutout&&(cutout.dataset.state=state,cutout.setAttribute("aria-label",localizedScreenshotText[state]),cutout.title=localizedScreenshotText[state],cutoutStatusPath&&cutoutStatusPath.setAttribute("d",state==="failed"?"M5.5 5.5l9 9m0-9-9 9":"m4.5 10.5 3.2 3.2 7.8-7.8"))},screenshotPending=!1,screenshotBlob=data=>{let binary=atob(data),bytes=new Uint8Array(binary.length);for(let index=0;index<binary.length;index+=1)bytes[index]=binary.charCodeAt(index);return new Blob([bytes],{type:"image/png"})},downloadScreenshot=blob=>{let link=document.createElement("a"),objectUrl=URL.createObjectURL(blob);link.href=objectUrl,link.download=`mearl-screenshot-${new Date().toISOString().replace(/[:.]/g,"-")}.png`,link.style.display="none",document.body.appendChild(link),link.click(),link.remove(),window.setTimeout(()=>URL.revokeObjectURL(objectUrl),1e3)},captureScreenshot=async()=>{if(!cutout||screenshotPending||cutout.dataset.state!=="idle")return;screenshotPending=!0,cutout.setAttribute("aria-busy","true");let requestId=Date.now()*1e3+Math.floor(Math.random()*1e3),timeoutTimer=0,onResponse=null,image=new Promise((resolve2,reject)=>{let cleanup=()=>{timeoutTimer&&window.clearTimeout(timeoutTimer),onResponse&&window.removeEventListener("message",onResponse)};onResponse=event=>{if(event.source!==window)return;let message=event.data;if(!message||message.source!=="mearl-content"||message.type!=="APP_BRIDGE_SCREENSHOT_RESPONSE"||message.requestId!==requestId)return;cleanup();let result=message.result;result?.success===!0&&typeof result.data=="string"?resolve2({data:result.data}):reject(new Error(String(result?.error??"screenshot failed")))},window.addEventListener("message",onResponse),timeoutTimer=window.setTimeout(()=>{cleanup(),reject(new Error("screenshot timeout"))},35e3)}).then(result=>screenshotBlob(result.data)),clipboardWrite=null;if(navigator.clipboard?.write&&typeof ClipboardItem<"u")try{clipboardWrite=navigator.clipboard.write([new ClipboardItem({"image/png":image})]),clipboardWrite.catch(()=>{})}catch{clipboardWrite=null}window.postMessage({source:SRC,type:"screenshot",requestId},"*");try{let blob=await image;if(clipboardWrite)try{await clipboardWrite,setCutoutState("copied")}catch{downloadScreenshot(blob),setCutoutState("downloaded")}else downloadScreenshot(blob),setCutoutState("downloaded")}catch{setCutoutState("failed")}finally{screenshotPending=!1,cutout.setAttribute("aria-busy","false")}window.setTimeout(()=>{screenshotPending||setCutoutState("idle")},1600)};hasDynamicIsland&&cutout&&(setCutoutState("idle"),cutout.addEventListener("click",()=>void captureScreenshot()));let updateTime=()=>{let now=new Date;time3&&(time3.textContent=`${String(now.getHours()).padStart(2,"0")}:${String(now.getMinutes()).padStart(2,"0")}`)};return window.addEventListener("mearl:page-time-change",updateTime),updateTime(),{root,surface,timeTimer:window.setInterval(updateTime,3e4)}},install=()=>{let titleBar=config2.titleBar;if(!titleBar||!isContainerFrame||!simulateSystemBars)return;let observeState=()=>{new MutationObserver(syncSimulatedTitleBar).observe(document.head??document.documentElement,{subtree:!0,childList:!0,characterData:!0,attributes:!0,attributeFilter:["content","value"]}),window.addEventListener("popstate",syncSimulatedTitleBar),window.addEventListener("hashchange",syncSimulatedTitleBar),document.readyState==="loading"&&document.addEventListener("DOMContentLoaded",syncSimulatedTitleBar,{once:!0});try{let pushState=history.pushState.bind(history),replaceState=history.replaceState.bind(history);history.pushState=function(...args){pushState(...args),syncSimulatedTitleBar()},history.replaceState=function(...args){replaceState(...args),syncSimulatedTitleBar()}}catch{}};if(!isTop){observeState(),syncSimulatedTitleBar();return}let mount=()=>{if(titleBarRoot||!document.body)return;let totalHeight=config2.statusBarHeight+titleBar.navigationBarHeight,navigationView=createNavigationBarView("root",host.requestNativeBack),statusView=externalDeviceChrome||config2.statusBarHeight<=0?null:createStatusBarView(),spacer=document.createElement("div");if(spacer.setAttribute("data-mearl-app-titlebar-spacer",""),spacer.style.cssText=`display:block;width:100%;height:${totalHeight}px;min-height:${totalHeight}px;flex:none;`,spacer.style.setProperty("--mearl-app-navigation-bar-height",`${titleBar.navigationBarHeight}px`),document.body.insertBefore(spacer,document.body.firstChild),document.body.appendChild(navigationView.root),statusView&&document.body.appendChild(statusView.root),!externalDeviceChrome&&safeAreaInsets.bottom>0){let bottomRoot=document.createElement("div");bottomRoot.setAttribute("data-mearl-app-system-bottom",config2.profile),bottomRoot.style.cssText=`position:fixed;left:0;right:0;bottom:0;height:${safeAreaInsets.bottom}px;z-index:2147483600;box-sizing:border-box;pointer-events:none;color:#111111;`;let bottomShadow=bottomRoot.attachShadow({mode:"open"});bottomShadow.innerHTML=`<style>:host{all:initial}#surface{appearance:none;border:0;padding:0;width:166px;max-width:100%;height:24px;position:absolute;left:50%;bottom:0;transform:translateX(-50%);display:block;box-sizing:border-box;pointer-events:auto;color:#111;background:transparent;cursor:pointer;-webkit-tap-highlight-color:transparent}#surface:focus-visible{outline:2px solid #2563eb;outline-offset:-2px}#indicator{position:absolute;left:50%;bottom:8px;transform:translateX(-50%);width:134px;height:5px;border-radius:999px;background:currentColor;opacity:.92;transition:transform 120ms ease,opacity 120ms ease}#surface:hover #indicator{opacity:1;transform:translateX(-50%) scaleX(1.05)}#surface[data-platform="android"] #indicator{bottom:6px;width:108px;height:4px;opacity:.82}</style><button id="surface" type="button" aria-label="打开桥模拟配置" title="桥模拟配置" data-platform="${config2.platform.toLowerCase()}"><span id="indicator" aria-hidden="true"></span></button>`,document.body.appendChild(bottomRoot),systemBottomRoot=bottomRoot,systemBottomSurface=bottomShadow.getElementById("surface"),systemBottomSurface?.addEventListener("click",()=>{window.postMessage({source:SRC,type:"showBridgeConfig",profile:config2.profile,actions:config2.actions},"*")})}rootTitleBarView=navigationView,systemStatusView=statusView,titleBarRoot=navigationView.root,titleBarSpacer=spacer,syncSimulatedTitleBar(),observeState()};document.body?mount():document.addEventListener("DOMContentLoaded",mount,{once:!0})},service={initialLayerTitleBarState,resolvedTitleBarState,parseReportedTitleBarState,setPresentedRootTitleBarState:state=>{presentedRootTitleBarState=state,syncSimulatedTitleBar()},markStateExplicit:()=>{titleBarStateExplicit=!0},applyNavigationBarState,applyStatusBarState,createNavigationBarView,destroyNavigationBarView:view=>view?.root.remove(),syncLayerViewport,syncActiveSystemBars,syncSimulatedTitleBar};return install(),service}function installAppProfilePageTransport(config2,environment){let{SRC,TAG,log:log2}=environment,appToast=null,appToastHideTimer=null,appToastRemoveTimer=null;function showAppToast(params){let p=params&&typeof params=="object"?params:{},messageValue=[p.message,p.msg,p.content,p.text].find(value=>typeof value=="string"&&value.trim().length>0);if(typeof messageValue!="string")return"missing message";let durationValue=Number(p.milliseconds??p.duration),duration3=Number.isFinite(durationValue)&&durationValue>0?durationValue:2e3,hideAfter=Math.min(6e4,Math.max(300,Math.round(duration3)));appToastHideTimer!==null&&window.clearTimeout(appToastHideTimer),appToastRemoveTimer!==null&&window.clearTimeout(appToastRemoveTimer);let toast=appToast?.isConnected===!0?appToast:document.createElement("div");return toast!==appToast&&(appToast=toast,toast.setAttribute("data-mearl-app-toast",""),toast.setAttribute("role","status"),toast.setAttribute("aria-live","polite"),Object.assign(toast.style,{position:"fixed",left:"50%",top:"50%",zIndex:"2147483647",maxWidth:"calc(100vw - 64px)",boxSizing:"border-box",padding:"14px 20px",borderRadius:"12px",background:"rgba(20, 20, 20, 0.88)",color:"#ffffff",fontFamily:'-apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif',fontSize:"16px",fontWeight:"400",lineHeight:"24px",textAlign:"center",whiteSpace:"pre-wrap",overflowWrap:"anywhere",pointerEvents:"none",opacity:"0",transform:"translate(-50%, -50%) scale(0.96)",transition:"opacity 180ms ease, transform 180ms ease"}),(document.body??document.documentElement).appendChild(toast)),toast.textContent=messageValue,toast.style.opacity="0",toast.style.transform="translate(-50%, -50%) scale(0.96)",toast.offsetWidth,toast.style.opacity="1",toast.style.transform="translate(-50%, -50%) scale(1)",appToastHideTimer=window.setTimeout(()=>{appToastHideTimer=null,toast.style.opacity="0",toast.style.transform="translate(-50%, -50%) scale(0.96)",appToastRemoveTimer=window.setTimeout(()=>{appToastRemoveTimer=null,appToast===toast&&(appToast=null),toast.remove()},180)},hideAfter),null}let bridgeRequestSeq=0,pendingMtop={},pendingMtopStreams={},pendingUserInfo={};function degradedUserInfo(fallback,reason){let result={...fallback};try{Object.defineProperties(result,{__mearlDegraded:{enumerable:!1,value:!0},__mearlDegradedReason:{enumerable:!1,value:reason}})}catch{}return console.warn(TAG,"userInfo 降级:",reason),result}function callMtop(params,succ,fail2){let id=++bridgeRequestSeq;pendingMtop[id]={succ,fail:fail2};let post=params.post,rawTimeout=params.timeout??params.timer,timeout=typeof rawTimeout=="number"?rawTimeout:typeof rawTimeout=="string"&&rawTimeout.trim()!==""?Number(rawTimeout):void 0,payload={...params,data:params.data!==void 0?params.data:params.param??{},method:params.method??(post===!0||post===1||post==="1"||post==="true"?"POST":"GET"),env:params.env??(/(^|\.)wapa\.taobao\.com$/i.test(location.hostname)?"pre":"online"),...Number.isFinite(timeout)&&{timeout}};window.postMessage({source:SRC,type:"mtop",requestId:id,payload},"*"),log2("mtop 代发 →",params.api)}function callMtopAsync(params){return new Promise((resolve2,reject)=>callMtop(params,resolve2,reject))}function callMtopStream(params,succ,fail2){let sessionId=typeof params.id=="string"?params.id:String(params.id??""),request=params.request&&typeof params.request=="object"?params.request:null;if(!sessionId||!request||typeof request.api!="string"){fail2?.("invalid mtop_stream params");return}let requestId=++bridgeRequestSeq;pendingMtopStreams[requestId]={sessionId},window.postMessage({source:SRC,type:"mtopStream",requestId,payload:{...request,timeout:params.timeout,method:params.method??request.method,env:/(^|\.)wapa\.taobao\.com$/i.test(location.hostname)?"pre":"online"}},"*"),succ?.({}),log2("mtop 流式代发 →",request.api)}function callUserInfo(fallback,succ){if(fallback.userId){succ?.(fallback);return}let requestId=++bridgeRequestSeq,timer=setTimeout(()=>{let pending=pendingUserInfo[requestId];pending&&(delete pendingUserInfo[requestId],pending.succ?.(degradedUserInfo(pending.fallback,"native relay timeout")))},1e3);pendingUserInfo[requestId]={fallback,succ,timer},window.postMessage({source:SRC,type:"userInfo",requestId},"*")}function emitMtopStreamEvent(sessionId,eventType,data){let detail=data&&typeof data=="object"?{...data,eventType}:{data,eventType};document.dispatchEvent(new CustomEvent(`mtop_stream${sessionId}`,{detail}))}function createUploadId(){try{if(typeof crypto.randomUUID=="function")return crypto.randomUUID()}catch{}return`${Date.now()}-${Math.random().toString(36).slice(2)}`}function pickDirectUploadTarget(response){if(!response||typeof response!="object")return null;let data=response.data;if(data?.success===!1)return null;let result=data?.result,target=Array.isArray(result?.urls)?result.urls[0]:void 0;if(!target||typeof target!="object")return null;let item=target;if(typeof item.put!="string"||!item.put||typeof item.get!="string"||!item.get)return null;let rawHeaders=item.putHeaders&&typeof item.putHeaders=="object"?item.putHeaders:{},putHeaders=Object.fromEntries(Object.entries(rawHeaders).map(([key,value])=>[key,String(value)]));return{put:item.put,get:item.get,putHeaders}}async function uploadImage(file2){let uploader=config2.imagePicker;if(!uploader)throw new Error("图片上传能力未配置");let env=/(^|\.)wapa\.taobao\.com$/i.test(location.hostname)?"pre":"online",response=await callMtopAsync({api:uploader.api,v:uploader.version,method:"POST",env,timeout:6e4,data:{fcId:uploader.fcId,fcGroup:uploader.fcGroup,fcName:uploader.uploadUrlFunction,fcData:JSON.stringify({requestType:"url",mimes:[file2.type||"image/jpeg"],prefix:uploader.prefix,region:uploader.region,uploadNumber:1}),fcConfig:JSON.stringify({timeout:6e4,disasterRecover:!0})}}),target=pickDirectUploadTarget(response);if(!target)throw new Error("获取图片上传地址失败");let uploadUrl=`${target.put}${target.put.includes("?")?"&":"?"}getAvatar=1`,uploadResponse=await fetch(uploadUrl,{method:"PUT",headers:target.putHeaders,body:file2});if(uploadResponse.status!==200)throw new Error(`图片直传失败: HTTP ${uploadResponse.status}`);return target.get}function openImagePicker(callbackCommandFn){let input=document.createElement("input");input.type="file",input.accept="image/*",input.style.display="none";let settled=!1,finish=()=>{settled=!0,input.remove()};input.addEventListener("cancel",finish,{once:!0}),input.addEventListener("change",()=>{let file2=input.files?.[0];if(!file2){finish();return}if(!file2.type.startsWith("image/")){finish(),console.error(TAG,"仅支持选择图片文件");return}uploadImage(file2).then(pic=>{typeof callbackCommandFn=="function"&&callbackCommandFn({pic,uuid:createUploadId(),timeStamp:Date.now()}),log2("图片选择并上传完成:",pic)}).catch(error48=>console.error(TAG,"图片上传失败:",error48)).finally(finish)},{once:!0}),(document.body??document.documentElement).appendChild(input),input.click(),window.addEventListener("focus",()=>{setTimeout(()=>{!settled&&!input.files?.length&&finish()},1e3)},{once:!0})}function showPaymentDialog(api,params,succeed,failed){document.querySelector('[data-mearl-payment-dialog="true"]')?.remove();let overlay=document.createElement("div");overlay.setAttribute("data-mearl-payment-dialog","true"),Object.assign(overlay.style,{position:"fixed",inset:"0",zIndex:"2147483647",display:"flex",alignItems:"center",justifyContent:"center",background:"rgba(0,0,0,0.5)"});let card=document.createElement("div");Object.assign(card.style,{background:"#fff",borderRadius:"12px",padding:"24px",width:"300px",textAlign:"center",fontFamily:"system-ui, sans-serif"});let title=document.createElement("div");Object.assign(title.style,{fontSize:"17px",fontWeight:"600",marginBottom:"8px"}),title.textContent="支付确认";let desc=document.createElement("div");Object.assign(desc.style,{fontSize:"14px",color:"#666",marginBottom:"20px"}),desc.textContent=`模拟 ${api} 支付,请选择操作`;let btnRow=document.createElement("div");Object.assign(btnRow.style,{display:"flex",gap:"12px"});let btnBase=(text,bg,color,action)=>{let btn=document.createElement("button");return btn.textContent=text,btn.setAttribute("data-mearl-action",action),Object.assign(btn.style,{flex:"1",padding:"10px 0",border:"none",borderRadius:"8px",fontSize:"15px",fontWeight:"500",cursor:"pointer",background:bg,color}),btn},confirmBtn=btnBase("完成支付","#1677ff","#fff","payment-confirm"),cancelBtn=btnBase("取消支付","#f5f5f5","#333","payment-cancel"),cleanup=()=>{overlay.remove()};confirmBtn.addEventListener("click",()=>{cleanup(),log2("用户完成支付",api),succeed(api==="wx.requestPayment"?{errMsg:"requestPayment:ok"}:{ResultStatus:"9000",resultStatus:"9000"})}),cancelBtn.addEventListener("click",()=>{cleanup(),log2("用户取消支付",api),failed(api==="wx.requestPayment"?{errMsg:"requestPayment:fail cancel"}:{ResultStatus:"6001",resultStatus:"6001"})}),btnRow.appendChild(cancelBtn),btnRow.appendChild(confirmBtn),card.appendChild(title),card.appendChild(desc),card.appendChild(btnRow),overlay.appendChild(card),(document.body??document.documentElement).appendChild(overlay)}function showMiniProgramActionDialog(action,params,confirmed,cancelled){document.querySelector('[data-mearl-mini-program-dialog="true"]')?.remove();let overlay=document.createElement("div");overlay.setAttribute("data-mearl-mini-program-dialog","true"),overlay.setAttribute("data-mearl-mini-program-action",action),Object.assign(overlay.style,{position:"fixed",inset:"0",zIndex:"2147483647",display:"flex",alignItems:"center",justifyContent:"center",background:"rgba(0,0,0,0.5)"});let card=document.createElement("div");Object.assign(card.style,{background:"#fff",borderRadius:"12px",padding:"24px",width:"300px",textAlign:"center",fontFamily:"system-ui, sans-serif"});let title=document.createElement("div");Object.assign(title.style,{fontSize:"17px",fontWeight:"600",marginBottom:"8px"}),title.textContent=action==="navigateMiniProgram"?"打开其他小程序":"订阅消息";let desc=document.createElement("div");Object.assign(desc.style,{fontSize:"14px",color:"#666",marginBottom:"20px"});let targetTitle=params.title?.trim()||"其他";desc.textContent=action==="navigateMiniProgram"?`即将打开“${targetTitle}”小程序,是否继续?`:"模拟微信订阅消息授权,请选择操作";let btnRow=document.createElement("div");Object.assign(btnRow.style,{display:"flex",gap:"12px"});let createButton=(text,background,color,actionName)=>{let button=document.createElement("button");return button.textContent=text,button.setAttribute("data-mearl-action",actionName),Object.assign(button.style,{flex:"1",padding:"10px 0",border:"none",borderRadius:"8px",fontSize:"15px",fontWeight:"500",cursor:"pointer",background,color}),button},confirmButton=createButton(action==="navigateMiniProgram"?"确定":"允许","#1677ff","#fff","mini-program-confirm"),cancelButton=createButton("取消","#f5f5f5","#333","mini-program-cancel"),cleanup=()=>overlay.remove();confirmButton.addEventListener("click",()=>{cleanup();let result=action==="navigateMiniProgram"?{errMsg:"navigateToMiniProgram:ok"}:{result:"SUCCESS",data:{totalCount:1,acceptCount:1}};log2("用户确认小程序原生能力",action,params.appId??params.scene??""),confirmed(result)}),cancelButton.addEventListener("click",()=>{cleanup();let result=action==="navigateMiniProgram"?{errMsg:"navigateToMiniProgram:fail cancel"}:{result:"CLOSE_BY_USER"};log2("用户取消小程序原生能力",action),cancelled(result)}),btnRow.appendChild(cancelButton),btnRow.appendChild(confirmButton),card.appendChild(title),card.appendChild(desc),card.appendChild(btnRow),overlay.appendChild(card),(document.body??document.documentElement).appendChild(overlay)}function handleMessage(msg){if(msg.source==="mearl-content"&&msg.type==="APP_BRIDGE_MTOP_RESPONSE"){let pending=pendingMtop[msg.requestId];if(!pending)return!0;delete pendingMtop[msg.requestId];let result=msg.result;return result?.success?pending.succ?.(result.response):pending.fail?.(result?.error??"mtop delegate failed"),!0}if(msg.source==="mearl-content"&&msg.type==="APP_BRIDGE_USER_INFO_RESPONSE"){let requestId=msg.requestId,pending=pendingUserInfo[requestId];if(!pending)return!0;delete pendingUserInfo[requestId],clearTimeout(pending.timer);let result=msg.result,response=result?.success&&result.response&&typeof result.response=="object"?result.response:{};return pending.succ?.(result?.success?{...pending.fallback,...response}:degradedUserInfo(pending.fallback,typeof result?.error=="string"&&result.error?result.error:"native relay failed")),!0}if(msg.source==="mearl-content"&&msg.type==="APP_BRIDGE_MTOP_STREAM_EVENT"){let requestId=msg.requestId,pending=pendingMtopStreams[requestId];if(!pending)return!0;let eventType=msg.eventType;return emitMtopStreamEvent(pending.sessionId,eventType,msg.data),(eventType==="onFinish"||eventType==="onError")&&delete pendingMtopStreams[requestId],!0}return!1}return{showAppToast,callMtop,callMtopStream,callUserInfo,openImagePicker,showPaymentDialog,showMiniProgramActionDialog,handleMessage}}function installAppProfileBridgeProtocol(config2,environment,host){let{w,SRC,TAG,isTop,log:log2}=environment,{pageTransport,systemBars,requestOpen,requestClose,requestCloseAll,requestContainerData}=host,{showAppToast,callMtop,callMtopStream,callUserInfo,openImagePicker,showPaymentDialog,showMiniProgramActionDialog}=pageTransport,{applyNavigationBarState,applyStatusBarState,syncSimulatedTitleBar}=systemBars,NOT_IMPLEMENTED_PAYLOAD=JSON.stringify({ret:["HY_FAILED"],msg:"not implemented"}),FPT_STORAGE_KEY=`__mearl_app_fpt__:${config2.profile}`,CALENDAR_STORAGE_KEY=`__mearl_app_calendar_events__:${config2.profile}`,unsupportedNativeInputNotified=!1,stopNetworkQualityMonitor=null,voiceRecognition=null,voiceRecognitionSession=0,voiceRecognitionTranscript="",voiceRecognitionInterimTranscript="",voiceRecognitionStopping=!1,voiceRecognitionRunning=!1,simulatedPageHidden=!1,simulatedVisibilityInstalled=!1,hasPendingMiniProgramBackData=!1,pendingMiniProgramBackData,notificationListeners=new Map,megaListenerSeq=0,megaBroadcastListeners=new Map,megaLifeCycleListeners=new Set,megaPageCloseListeners=new Set,megaSystemBackListener=null,megaKVMutationVersion=0,MEGA_KV_TOTAL_SIZE=5*1024*1024,MEGA_KV_STORAGE_KEY=`__mearl_mega_kv__:${config2.profile}`;function readMegaKVStorage(){let storage=new Map;try{let parsed=JSON.parse(localStorage.getItem(MEGA_KV_STORAGE_KEY)??"{}");if(!parsed||typeof parsed!="object"||Array.isArray(parsed))return storage;for(let[bizId,rawEntries]of Object.entries(parsed)){if(!rawEntries||typeof rawEntries!="object"||Array.isArray(rawEntries))continue;let entries=new Map;for(let[key,value]of Object.entries(rawEntries))typeof value=="string"&&entries.set(key,value);storage.set(bizId,entries)}}catch{}return storage}let megaKVStorage=readMegaKVStorage();function megaKVSnapshot(){let snapshot={};for(let[bizId,values]of megaKVStorage)snapshot[bizId]=Object.fromEntries(values);return snapshot}function persistMegaKVStorage(){try{localStorage.setItem(MEGA_KV_STORAGE_KEY,JSON.stringify(megaKVSnapshot()))}catch{}}function replaceMegaKVStorage(value){if(!(!value||typeof value!="object"||Array.isArray(value))){megaKVStorage.clear();for(let[bizId,rawEntries]of Object.entries(value)){if(!rawEntries||typeof rawEntries!="object"||Array.isArray(rawEntries))continue;let entries=new Map;for(let[key,entryValue]of Object.entries(rawEntries))typeof entryValue=="string"&&entries.set(key,entryValue);megaKVStorage.set(bizId,entries)}persistMegaKVStorage()}}function applyMegaKVMutation(payload){let operation=typeof payload.operation=="string"?payload.operation:"",bizId=typeof payload.bizId=="string"?payload.bizId:"",key=typeof payload.key=="string"?payload.key:"";if(bizId){if(operation==="set"&&key&&typeof payload.value=="string"){let entries=megaKVStorage.get(bizId)??new Map;entries.set(key,payload.value),megaKVStorage.set(bizId,entries)}else if(operation==="remove"&&key){let entries=megaKVStorage.get(bizId);entries?.delete(key),entries?.size===0&&megaKVStorage.delete(bizId)}else if(operation==="clear")megaKVStorage.delete(bizId);else return;megaKVMutationVersion+=1,persistMegaKVStorage()}}function emitMegaCallback(callback,value){callback&&setTimeout(()=>callback(value),0)}function megaBroadcastBizId(value){return typeof value=="string"&&value?value:"__MEGA_GLOBAL_MESSAGE__"}function dispatchMegaBroadcast(payload){let bizId=megaBroadcastBizId(payload.bizId),eventName=typeof payload.eventName=="string"?payload.eventName:"";if(eventName)for(let listener of Array.from(megaBroadcastListeners.values()))listener.bizId!==bizId||listener.eventName!==eventName||(listener.once&&megaBroadcastListeners.delete(listener.id),emitMegaCallback(listener.callback,{statusCode:1,type:"onEvent",data:{detail:payload.detail}}),listener.once&&emitMegaCallback(listener.callback,{statusCode:99,type:"finish"}))}let documentPrototype=typeof Document=="function"?Document.prototype:null,nativeHiddenDescriptor=documentPrototype?Object.getOwnPropertyDescriptor(documentPrototype,"hidden"):void 0,nativeVisibilityDescriptor=documentPrototype?Object.getOwnPropertyDescriptor(documentPrototype,"visibilityState"):void 0;function installSimulatedVisibilityState(){if(!simulatedVisibilityInstalled){simulatedVisibilityInstalled=!0;try{Object.defineProperty(document,"hidden",{configurable:!0,get:()=>simulatedPageHidden||!!(nativeHiddenDescriptor?.get?.call(document)??!1)}),Object.defineProperty(document,"visibilityState",{configurable:!0,get:()=>simulatedPageHidden?"hidden":nativeVisibilityDescriptor?.get?.call(document)??"visible"})}catch{}}}function dispatchPageTransitionEvent(type){try{let event=typeof PageTransitionEvent=="function"?new PageTransitionEvent(type,{persisted:!1}):new Event(type);window.dispatchEvent(event)}catch{}}function dispatchActiveEvents(){for(let name of config2.activeEvents)try{document.dispatchEvent(new Event(name))}catch{}}function handlePageVisibility(hidden){if(hidden===simulatedPageHidden)return;installSimulatedVisibilityState(),simulatedPageHidden=hidden;let lifeCycleType=hidden?"onPageDisappear":"onPageAppear";for(let callback of megaLifeCycleListeners)emitMegaCallback(callback,{statusCode:1,type:lifeCycleType,data:{pageId:location.href}});try{document.dispatchEvent(new Event("visibilitychange"))}catch{}if(hidden){try{window.dispatchEvent(new Event("blur"))}catch{}dispatchPageTransitionEvent("pagehide");return}dispatchPageTransitionEvent("pageshow");try{window.dispatchEvent(new Event("focus"))}catch{}dispatchActiveEvents()}function resolveWindowFunction(path19){let parts=path19.split(".").filter(Boolean),owner=w;for(let index=0;index<parts.length-1;index+=1){let next=owner[parts[index]];if(!next||typeof next!="object")return null;owner=next}let fn=owner[parts[parts.length-1]];return typeof fn=="function"?fn.bind(owner):null}function handleNativeBack(){let megaHandled=!1;for(let callback of megaPageCloseListeners)megaHandled=!0,emitMegaCallback(callback,{statusCode:1,type:"onClose",data:{}});if(megaSystemBackListener&&(megaHandled=!0,emitMegaCallback(megaSystemBackListener,{statusCode:1,type:"onSuccess",data:{}})),megaHandled)return!0;let nativeBack=config2.nativeBack;if(!nativeBack)return!1;if(nativeBack.handler){let handler=resolveWindowFunction(nativeBack.handler);if(!handler)return!1;try{return handler(),!0}catch{return!1}}let controlled=!1;if(nativeBack.controlFunction){let control=resolveWindowFunction(nativeBack.controlFunction);if(!control)return!1;try{controlled=control()===!0}catch{return!1}if(!controlled)return!1}if(!nativeBack.event)return controlled;try{let event=new Event(nativeBack.event,{cancelable:!0});return document.dispatchEvent(event),controlled||event.defaultPrevented}catch{return controlled}}function handleAppMessage(message){if(!message||typeof message!="object")return;let payload=message;if(payload.kind==="megaBroadcast"){dispatchMegaBroadcast(payload);return}if(payload.kind==="megaKVStorage"){applyMegaKVMutation(payload);return}if(payload.kind==="legacyBroadcast"&&typeof payload.instanceId=="string"){try{let event=new CustomEvent(`Broadcast.Message.${payload.instanceId}`,{detail:payload.message});Object.defineProperty(event,"param",{configurable:!0,value:payload.message}),document.dispatchEvent(event)}catch{}return}if(payload.kind==="notification"&&typeof payload.name=="string"){let listener=notificationListeners.get(payload.name);listener&&setTimeout(()=>listener(payload.data),0);return}if(!(payload.kind!=="message"||!config2.messageEvent))try{document.dispatchEvent(new CustomEvent(config2.messageEvent,{detail:{data:payload.data}}))}catch{}}function sendAppMessage(message){if(isTop){handleAppMessage(message);return}window.top?.postMessage({source:SRC,type:"appMessageToOpener",message},"*")}function applyRuntimeResponses(responses){let current=config2.actions.responses??{};for(let[api,response]of Object.entries(responses))!response||typeof response!="object"||Array.isArray(response)||(current[api]=response);config2.actions.responses=current}function parseFpt(value){let entries=[],normalized=value.trim();if(!normalized)return entries;let pattern=/([0-9A-Za-z._-]+)\(([0-9A-Za-z._-]+)\)/g,consumed="";for(let match of normalized.matchAll(pattern))consumed+=match[0],entries.push([match[1],match[2]]);return consumed===normalized?entries:[]}function setFptEntry(entries,key,value){entries.delete(key),entries.set(key,value)}function readInitialFptEntries(){let entries=new Map;try{for(let[key,value]of parseFpt(sessionStorage.getItem(FPT_STORAGE_KEY)??""))setFptEntry(entries,key,value)}catch{}try{let currentFpt=new URL(location.href).searchParams.get("fpt")??"";for(let[key,value]of parseFpt(currentFpt))setFptEntry(entries,key,value)}catch{}return entries}let fptEntries=readInitialFptEntries();function serializeFpt(entries){return Array.from(entries,([key,value])=>`${key}(${value})`).join("")}function persistFpt(){try{let value=serializeFpt(fptEntries);value?sessionStorage.setItem(FPT_STORAGE_KEY,value):sessionStorage.removeItem(FPT_STORAGE_KEY)}catch{}}function decorateUrlWithFpt(rawUrl){let targetUrl=mapScheme(rawUrl)??rawUrl;if(fptEntries.size===0)return targetUrl;try{let url2=new URL(targetUrl,location.href);if(url2.protocol!=="http:"&&url2.protocol!=="https:")return targetUrl;let merged=new Map(fptEntries);for(let[key,value]of parseFpt(url2.searchParams.get("fpt")??""))setFptEntry(merged,key,value);return url2.searchParams.set("fpt",serializeFpt(merged)),url2.href}catch{return targetUrl}}function classify(api){let a=config2.actions;return a.open.includes(api)?"open":a.close.includes(api)?"close":a.title.includes(api)?"title":a.navigationBar?.includes(api)?"navigationBar":a.statusBar?.includes(api)?"statusBar":a.systemInfo.includes(api)?"systemInfo":a.mtop.includes(api)?"mtop":a.kvGet?.includes(api)?"kvGet":a.kvSet?.includes(api)?"kvSet":a.kvDelete?.includes(api)?"kvDelete":a.pageContext?.includes(api)?"pageContext":a.responses&&Object.prototype.hasOwnProperty.call(a.responses,api)?"response":a.behaviors&&Object.prototype.hasOwnProperty.call(a.behaviors,api)?a.behaviors[api]:a.noop.includes(api)?"noop":"unknown"}function pickUrl(params){if(!params||typeof params!="object")return null;let p=params,candidates=[p.url,p.data?.url,p.param?.url,p.value?.params?.url];for(let c of candidates)if(typeof c=="string"&&c)return c;return null}function pickCloseData(params){if(params&&typeof params=="object"){let p=params;if("data"in p&&p.data!==void 0)return p.data;if(Object.keys(p).length>0)return p}}function decodeCookieValue2(raw){let value=raw;for(let i=0;i<2;i+=1)try{let decoded=decodeURIComponent(value);if(decoded===value)break;value=decoded}catch{break}return value.replace(/\\u([0-9a-f]{4})/gi,(_match,hex3)=>String.fromCharCode(Number.parseInt(hex3,16)))}function readCookie(name){let prefix=`${name}=`,pair=document.cookie.split(";").map(value=>value.trim()).find(value=>value.startsWith(prefix));return pair?decodeCookieValue2(pair.slice(prefix.length)):""}function readUserCookie(name){let pageUserCookie=w.userCookie;if(!pageUserCookie||typeof pageUserCookie!="object")return"";let value=pageUserCookie[name];return typeof value=="string"?decodeCookieValue2(value):""}function readFirstUserCookie(names){for(let name of names){let value=readCookie(name)||readUserCookie(name);if(value&&value!=="null")return value}return""}let cbSeq=0,callbacks={};function stashCallback(fn){if(typeof fn!="function")return 0;let id=++cbSeq;return callbacks[id]=fn,id}function extractQuery(url2,param){let q=url2.indexOf("?");if(q===-1)return null;for(let pair of url2.slice(q+1).split("&")){let eq=pair.indexOf("=");if(eq>0&&pair.slice(0,eq)===param)return pair.slice(eq+1)}return null}function matchesHostSuffix(hostname3,suffixes){if(!suffixes?.length)return!0;let normalizedHost=hostname3.toLowerCase().replace(/\.$/,"");return suffixes.some(value=>{let suffix=value.toLowerCase().replace(/^\./,"").replace(/\.$/,"");return normalizedHost===suffix||normalizedHost.endsWith(`.${suffix}`)})}function matchesRouteHost(rawUrl,suffixes){if(!suffixes?.length)return!0;try{let parsed=new URL(rawUrl,location.href),hostname3=parsed.protocol==="http:"||parsed.protocol==="https:"?parsed.hostname:location.hostname;return matchesHostSuffix(hostname3,suffixes)}catch{return matchesHostSuffix(location.hostname,suffixes)}}function resolveSchemeValue(raw,depth){if(depth>3)return null;let value=raw;try{value=decodeURIComponent(raw)}catch{}if(value.startsWith("{"))try{let found=pickUrl(JSON.parse(value));if(!found)return null;value=found}catch{return null}if(/^https?:/i.test(value))return value;if(/^[a-z][a-z0-9+.-]*:/i.test(value))return mapScheme(value,depth+1);let nestedUrl=extractQuery(value,"url");return nestedUrl?resolveSchemeValue(nestedUrl,depth+1):null}function mapScheme(url2,depth=0){if(depth>3)return null;let lower=url2.toLowerCase();for(let rule of config2.schemes){if(!matchesRouteHost(url2,rule.hostSuffixes))continue;let normalizedMatch=rule.match.toLowerCase(),matchedUrl=url2;if(!lower.startsWith(normalizedMatch)){if(!normalizedMatch.startsWith("/"))continue;try{let parsed=new URL(url2,location.href);if(matchedUrl=`${parsed.pathname}${parsed.search}${parsed.hash}`,!matchedUrl.toLowerCase().startsWith(normalizedMatch))continue}catch{continue}}if(rule.targetPath){let suffix=matchedUrl.slice(rule.match.length);if(suffix&&!suffix.startsWith("?")&&!suffix.startsWith("#"))continue;try{let source=new URL(matchedUrl),origin=location.origin;if(rule.targetHostPrefix){let hostname3=location.hostname.toLowerCase(),domainSuffix=hostname3==="wapa.taobao.com"||hostname3.endsWith(".wapa.taobao.com")?"wapa.taobao.com":hostname3==="m.taobao.com"||hostname3.endsWith(".m.taobao.com")?"m.taobao.com":"";domainSuffix&&(origin=`https://${rule.targetHostPrefix}.${domainSuffix}`)}let target=new URL(rule.targetPath,`${origin}/`);target.search=source.search,target.hash=source.hash;for(let[key,value]of Object.entries(rule.targetParams??{}))target.searchParams.has(key)||target.searchParams.set(key,value);return target.href}catch{return null}}if(!rule.param)continue;let raw=extractQuery(matchedUrl,rule.param);if(!raw)return null;let resolved=resolveSchemeValue(raw,depth);if(!resolved||!rule.useCurrentOrigin)return resolved;try{let target=new URL(resolved);return`${location.origin}${target.pathname}${target.search}${target.hash}`}catch{return resolved}}return null}function firstRouteParam(params,names){for(let name of names){let value=params.get(name);if(value)return value}return""}function resolvePaymentCallbackUrl(rawUrl,paymentPageUrl,useCurrentOrigin,forwardParams,resultParam){if(!rawUrl)return null;try{let target=new URL(rawUrl,location.href);for(let name of forwardParams){let value=paymentPageUrl.searchParams.get(name);value&&!target.searchParams.get(name)&&target.searchParams.set(name,value)}resultParam&&target.searchParams.set(resultParam.name,JSON.stringify(resultParam.value));let resolved=useCurrentOrigin&&(target.protocol==="http:"||target.protocol==="https:")?`${location.origin}${target.pathname}${target.search}${target.hash}`:target.href;return decorateUrlWithFpt(resolved)}catch{return null}}function openPaymentCallback(rawUrl,paymentPageUrl,useCurrentOrigin,forwardParams,resultParam){let target=resolvePaymentCallbackUrl(rawUrl,paymentPageUrl,useCurrentOrigin,forwardParams,resultParam);target&&requestOpen(target,0,!1)}function handleMiniProgramPaymentRoute(rawUrl){let paymentPageUrl;try{paymentPageUrl=new URL(rawUrl,location.href)}catch{return!1}let normalizedPathname=paymentPageUrl.pathname.replace(/\/+$/,"")||"/",rule=config2.miniProgram?.paymentRoutes?.find(candidate=>(candidate.pathname.replace(/\/+$/,"")||"/")===normalizedPathname&&matchesHostSuffix(paymentPageUrl.hostname,candidate.hostSuffixes));if(!rule)return!1;let successUrl=firstRouteParam(paymentPageUrl.searchParams,rule.successUrlParams),failureUrl=firstRouteParam(paymentPageUrl.searchParams,rule.failureUrlParams),forwardParams=rule.forwardParams??[],useCurrentOrigin=rule.useCurrentOrigin===!0,paymentParams;try{let parsed=JSON.parse(paymentPageUrl.searchParams.get(rule.paymentParamsParam)??"");if(!parsed||typeof parsed!="object"||Array.isArray(parsed))throw new Error;paymentParams=parsed,paymentParams.timeStamp!==void 0&&(paymentParams.timeStamp=String(paymentParams.timeStamp))}catch{return log2("微信支付参数解析失败,执行失败回跳",rawUrl),openPaymentCallback(failureUrl,paymentPageUrl,useCurrentOrigin,forwardParams),!0}return showPaymentDialog("wx.requestPayment",paymentParams,result=>{openPaymentCallback(successUrl,paymentPageUrl,useCurrentOrigin,forwardParams,rule.successResultParam?{name:rule.successResultParam,value:result}:void 0)},()=>{openPaymentCallback(failureUrl,paymentPageUrl,useCurrentOrigin,forwardParams)}),!0}function finishMiniProgramNativeRoute(action,result,storageId){handleResume({data:action==="subscribeMessage"?result:void 0,storageId,callbackId:0,final:!0})}function handleMiniProgramNativeRoute(rawUrl){let nativePageUrl;try{nativePageUrl=new URL(rawUrl,location.href)}catch{return!1}let normalizedPathname=nativePageUrl.pathname.replace(/\/+$/,"")||"/",action=nativePageUrl.searchParams.get("action");if(action!=="navigateMiniProgram"&&action!=="subscribeMessage"||!config2.miniProgram?.nativeRoutes?.find(candidate=>(candidate.pathname.replace(/\/+$/,"")||"/")===normalizedPathname&&candidate.actions.includes(action)&&matchesHostSuffix(nativePageUrl.hostname,candidate.hostSuffixes)))return!1;let params={};nativePageUrl.searchParams.forEach((value,name)=>{params[name]=value});let storageId=nativePageUrl.searchParams.get("__storage_id");return handlePageVisibility(!0),showMiniProgramActionDialog(action,params,result=>finishMiniProgramNativeRoute(action,result,storageId),result=>finishMiniProgramNativeRoute(action,result,storageId)),!0}function handleMiniProgramPostMessage(data){let rules=config2.miniProgram?.messageRules;if(!rules?.length)return!1;let messages=Array.isArray(data)?data:[data],handled=!1;for(let value of messages){if(!value||typeof value!="object"||Array.isArray(value))continue;let message=value;if(typeof message.type!="string")continue;let rule=rules.find(candidate=>candidate.type===message.type&&matchesHostSuffix(location.hostname,candidate.hostSuffixes));rule&&(handled=!0,rule.action==="stageBackData"?(pendingMiniProgramBackData=message.data,hasPendingMiniProgramBackData=!0):rule.action==="closeAll"&&(isTop?requestCloseAll(message.data)||requestClose(message.data):window.top?.postMessage({source:SRC,type:"closeAll",data:message.data},"*")))}return handled}function matchesImagePickerScheme(url2){let lower=url2.toLowerCase();return config2.imagePicker?.schemes.some(scheme=>lower.startsWith(scheme))===!0}function handleMaybeScheme(url2){if(typeof url2!="string"||!url2||!/^[a-z][a-z0-9+.-]*:/i.test(url2)||/^(https?|about|blob|data|javascript):/i.test(url2))return!1;let mapped=mapScheme(url2);return mapped?(log2("scheme 映射为 H5 open:",url2,"→",mapped),requestOpen(decorateUrlWithFpt(mapped),0,!1)):log2("外部 scheme 已拦截(真机表现为唤端):",url2),!0}function handleResume(msg){let{data,storageId,callbackId,final,gotoEvent,silent}=msg;if(gotoEvent&&dispatchGotoEvent(data),callbackId&&callbacks[callbackId]){if(!silent)try{callbacks[callbackId]({backdata:data})}catch(e){console.error(TAG,"callbackCommand 执行失败",e)}final&&delete callbacks[callbackId]}if(data&&typeof data=="object"&&storageId)try{let d={...data};d.__$data=!0,d.__$storageId=String(storageId),localStorage.setItem("XPI_BACK_LISTENER_DATA_STORAGE",JSON.stringify(d))}catch{}simulatedPageHidden?handlePageVisibility(!1):dispatchActiveEvents()}function dispatchGotoEvent(data){if(data!==void 0)try{document.dispatchEvent(new CustomEvent("WV.GotoEvent",{detail:{data}}))}catch{}}function sendUserTrack(params){if(!params||typeof params!="object")return;let p=params,logkey=typeof p.logkey=="string"?p.logkey:"",gmkey=typeof p.gmkey=="string"?p.gmkey:typeof p.event=="string"?p.event:"",gokey=typeof p.gokey=="string"?p.gokey:"";if(!/^\/[0-9A-Za-z._/-]+$/.test(logkey)||!/^[0-9A-Za-z_-]+$/.test(gmkey))return;let pageWindow=w,aplus=pageWindow.goldlog??pageWindow.aplus;if(typeof aplus?.send!="function")return;let configuredHost=aplus.getMetaInfo?.("aplus-rhost-g"),host2=(typeof configuredHost=="string"?configuredHost:"gm.mmstat.com").replace(/^https?:\/\//i,"").replace(/^\/\//,"").split("/")[0];if(!(!host2||!/^[0-9A-Za-z.-]+$/.test(host2)))try{aplus.send(`//${host2}${logkey}`,`gmkey=${encodeURIComponent(gmkey)}&gokey=${gokey}&ts=${Date.now()}`,"GET")}catch{}}function readNetworkState(){let connection=navigator.connection;return navigator.onLine?connection?.type==="wifi"?"wifi":connection?.effectiveType??"unknown":"fail"}function networkTypeNumber(state){return{wifi:2,"slow-2g":3,"2g":3,"3g":4,"4g":5,"5g":6,fail:7}[state]??0}function emitVoiceRecognitionEvent(name,detail){try{document.dispatchEvent(new CustomEvent(name,{detail}))}catch{}}function browserSpeechRecognitionConstructor(){let candidate=w.SpeechRecognition??w.webkitSpeechRecognition;return typeof candidate=="function"?candidate:null}function voiceRecognitionLanguage(){let language=config2.language||navigator.language||"zh-CN";return/^zh-hans$/i.test(language)?"zh-CN":/^zh-hant$/i.test(language)?"zh-TW":language}function localVoiceRecognitionLanguage(language){return/^zh-(cn|hans)$/i.test(language)?"cmn-Hans-CN":/^zh-(tw|hant)$/i.test(language)?"cmn-Hant-TW":language}function detachVoiceRecognition(recognition){recognition.onstart=null,recognition.onresult=null,recognition.onerror=null,recognition.onend=null,recognition.onspeechstart=null,recognition.onspeechend=null}function finishVoiceRecognition(recognition,status){if(voiceRecognition!==recognition)return;let content=voiceRecognitionInterimTranscript.trim()||voiceRecognitionTranscript.trim();voiceRecognition=null,voiceRecognitionSession+=1,voiceRecognitionRunning=!1,voiceRecognitionStopping=!1,voiceRecognitionInterimTranscript="",detachVoiceRecognition(recognition),emitVoiceRecognitionEvent("WV.Voicetone",{tone:0}),emitVoiceRecognitionEvent("WV.VoiceRecog",{content,finished:!0,status})}function cancelVoiceRecognition(notifyPage){let recognition=voiceRecognition;if(recognition){voiceRecognition=null,voiceRecognitionSession+=1,voiceRecognitionRunning=!1,voiceRecognitionStopping=!1,voiceRecognitionInterimTranscript="",detachVoiceRecognition(recognition);try{recognition.abort()}catch{}emitVoiceRecognitionEvent("WV.Voicetone",{tone:0}),notifyPage&&emitVoiceRecognitionEvent("WV.VoiceRecogFailed",{status:2})}}function startVoiceRecognition(succeed,failed){cancelVoiceRecognition(!1);let SpeechRecognition=browserSpeechRecognitionConstructor();if(!SpeechRecognition){let error48={error_code:-1,error_message:"speech recognition unavailable"};emitVoiceRecognitionEvent("WV.VoiceRecogFailed",{status:-1,...error48}),failed(error48);return}let recognition=new SpeechRecognition,session=++voiceRecognitionSession;voiceRecognition=recognition,voiceRecognitionTranscript="",voiceRecognitionInterimTranscript="",voiceRecognitionStopping=!1,voiceRecognitionRunning=!1,recognition.continuous=!0,recognition.interimResults=!0,recognition.maxAlternatives=1,recognition.lang=voiceRecognitionLanguage();let isCurrent=()=>voiceRecognition===recognition&&voiceRecognitionSession===session,recognitionFailed=!1,failRecognition=(message,code)=>{if(!isCurrent()||recognitionFailed)return;recognitionFailed=!0;let error48={error_code:-1,error_message:message,error:code};voiceRecognition=null,voiceRecognitionSession+=1,voiceRecognitionRunning=!1,voiceRecognitionStopping=!1,detachVoiceRecognition(recognition);try{recognition.abort()}catch{}emitVoiceRecognitionEvent("WV.Voicetone",{tone:0}),emitVoiceRecognitionEvent("WV.VoiceRecogFailed",{status:-1,...error48}),failed(error48)},beginRecognition=()=>{if(isCurrent())try{recognition.start(),voiceRecognitionRunning=!0,succeed({})}catch(error48){failRecognition(error48 instanceof Error?error48.message:"speech recognition start failed","start-failed")}};recognition.onstart=()=>{isCurrent()&&(voiceRecognitionRunning=!0)},recognition.onspeechstart=()=>{isCurrent()&&emitVoiceRecognitionEvent("WV.Voicetone",{tone:10})},recognition.onspeechend=()=>{isCurrent()&&emitVoiceRecognitionEvent("WV.Voicetone",{tone:0})},recognition.onresult=event=>{if(!isCurrent()||!event.results)return;let interimTranscript="",startIndex=Math.max(0,event.resultIndex??0);for(let index=startIndex;index<event.results.length;index+=1){let result=event.results[index],transcript=result?.[0]?.transcript??"";result?.isFinal?voiceRecognitionTranscript+=transcript:interimTranscript+=transcript}let content=`${voiceRecognitionTranscript}${interimTranscript}`.trim();voiceRecognitionInterimTranscript=content,content&&emitVoiceRecognitionEvent("WV.VoiceRecogPartial",{content})},recognition.onerror=event=>{if(!isCurrent())return;let code=event.error??"unknown";code!=="no-speech"&&(code==="aborted"&&voiceRecognitionStopping||failRecognition(event.message||`speech recognition failed: ${code}`,code))},recognition.onend=()=>{if(isCurrent()){if(voiceRecognitionRunning=!1,voiceRecognitionStopping){finishVoiceRecognition(recognition,1);return}setTimeout(()=>{if(!(!isCurrent()||voiceRecognitionStopping))try{recognition.start(),voiceRecognitionRunning=!0}catch(error48){failRecognition(error48 instanceof Error?error48.message:"speech recognition restart failed","restart-failed")}},0)}};let localLanguage=localVoiceRecognitionLanguage(recognition.lang);if(typeof recognition.processLocally=="boolean"&&typeof SpeechRecognition.available=="function"){SpeechRecognition.available({langs:[localLanguage],processLocally:!0}).then(availability=>{if(isCurrent()){if(availability==="available"){recognition.lang=localLanguage,recognition.processLocally=!0,beginRecognition();return}if((availability==="downloadable"||availability==="downloading")&&typeof SpeechRecognition.install=="function"){showAppToast({message:"正在准备语音识别,首次使用可能需要一些时间",milliseconds:3e3}),SpeechRecognition.install({langs:[localLanguage],processLocally:!0}).then(installed=>{if(!installed){isCurrent()&&beginRecognition();return}if(!isCurrent()){showAppToast({message:"语音识别已准备好,请再试一次",milliseconds:3e3});return}recognition.lang=localLanguage,recognition.processLocally=!0,beginRecognition()}).catch(()=>beginRecognition());return}beginRecognition()}}).catch(()=>beginRecognition());return}beginRecognition()}function calendarTimestamp(value){if(typeof value=="number"&&Number.isFinite(value))return value;if(typeof value!="string"||!value.trim())return null;let numeric=Number(value);if(Number.isFinite(numeric)&&numeric>0)return numeric;let parsed=Date.parse(value);return Number.isFinite(parsed)?parsed:null}function calendarEventFromParams(params){let p=params&&typeof params=="object"?params:{},stringValue=(...values)=>values.find(value=>typeof value=="string")??"";return{title:stringValue(p.calendar_title,p.title),startTime:calendarTimestamp(p.calendar_start_ms??p.start_time??p.calendar_start_datetime),endTime:calendarTimestamp(p.calendar_end_ms??p.end_time??p.calendar_end_datetime),url:stringValue(p.calendar_url,p.url),note:stringValue(p.calendar_note,p.note),location:stringValue(p.calendar_location,p.location)}}function readCalendarEvents(){try{let parsed=JSON.parse(localStorage.getItem(CALENDAR_STORAGE_KEY)??"[]");return Array.isArray(parsed)?parsed.filter(event=>event!==null&&typeof event=="object"&&typeof event.title=="string"):[]}catch{return[]}}function writeCalendarEvents(events){try{return localStorage.setItem(CALENDAR_STORAGE_KEY,JSON.stringify(events)),!0}catch{return!1}}function sameCalendarEvent(stored,candidate){return candidate.url?stored.url===candidate.url:!!candidate.title&&stored.title===candidate.title&&(candidate.startTime===null||stored.startTime===candidate.startTime)&&(candidate.endTime===null||stored.endTime===candidate.endTime)}function calendarEventResponse(event){return{title:event.title,start_time:event.startTime,end_time:event.endTime,url:event.url,note:event.note,location:event.location}}function dispatch(api,params,onSuccess,onFailure,callbackCommandFn){let succeed=value=>{onSuccess&&setTimeout(()=>onSuccess(value),0)},failed=reason=>{onFailure&&setTimeout(()=>onFailure(reason),0)},kind=classify(api),silent=config2.actions.silent?.includes(api)===!0;if(silent||log2("桥调用",api,`(${kind})`,params??""),kind==="open"||kind==="navigate"){let p=params&&typeof params=="object"?params:{},navigationData=p.data&&typeof p.data=="object"?p.data:void 0;if(kind==="navigate"&&navigationData?.type==="back"){isTop?requestCloseAll(navigationData.data,!0)||dispatchGotoEvent(navigationData.data):window.top?.postMessage({source:SRC,type:"closeAll",data:navigationData.data,gotoEvent:!0},"*"),succeed({});return}let url2=pickUrl(params);if(!url2){failed("missing url");return}if(matchesImagePickerScheme(url2)){openImagePicker(callbackCommandFn),succeed({});return}if(handleMiniProgramPaymentRoute(url2)){succeed({});return}if(handleMiniProgramNativeRoute(url2)){succeed({});return}let wd=p.useWebdialog===!0||p.useWebdialog==="true"||p.useWebdialog===1||p.useWebdialog==="1";requestOpen(decorateUrlWithFpt(url2),stashCallback(callbackCommandFn),wd,p),succeed({});return}if(kind==="closeAll"){isTop?requestCloseAll(void 0):window.top?.postMessage({source:SRC,type:"closeAll"},"*"),succeed({});return}if(kind==="closeBackData"){let p=params&&typeof params=="object"?params:{};requestClose(Object.prototype.hasOwnProperty.call(p,"backdata")?p.backdata:pickCloseData(p)),succeed({});return}if(kind==="close"){if(api==="navigateBack"&&hasPendingMiniProgramBackData){let data=pendingMiniProgramBackData;pendingMiniProgramBackData=void 0,hasPendingMiniProgramBackData=!1,requestClose(data)}else requestClose(pickCloseData(params));succeed({});return}if(kind==="postMessage"){let p=params&&typeof params=="object"?params:{},data=p.data??p;handleMiniProgramPostMessage(data)||sendAppMessage({kind:"message",data}),succeed({});return}if(kind==="notifySubscribe"){let p=params&&typeof params=="object"?params:{};if(typeof p.name!="string"||!p.name){failed("missing notification name");return}onSuccess&¬ificationListeners.set(p.name,onSuccess);return}if(kind==="notifyUnsubscribe"){let p=params&&typeof params=="object"?params:{};typeof p.name=="string"&¬ificationListeners.delete(p.name),succeed({});return}if(kind==="notifyPost"){let p=params&&typeof params=="object"?params:{};if(typeof p.name!="string"||!p.name){failed("missing notification name");return}sendAppMessage({kind:"notification",name:p.name,data:p.data}),succeed({});return}if(kind==="sharedFileRead"||kind==="sharedFileWrite"||kind==="sharedDataGet"||kind==="sharedDataSet"){requestContainerData(kind,params&&typeof params=="object"?params:{},succeed,failed);return}if(kind==="legacyBroadcastCreate"||kind==="legacyBroadcastPost"||kind==="legacyBroadcastClose"){requestContainerData(kind,params&&typeof params=="object"?params:{},succeed,failed);return}if(kind==="title"){let title=params&&typeof params=="object"?params.title??params.name:void 0;if(typeof title=="string"&&title){systemBars.markStateExplicit();try{document.title=title,syncSimulatedTitleBar()}catch{}isTop||window.top?.postMessage({source:SRC,type:"title",title},"*")}succeed({});return}if(kind==="navigationBar"){applyNavigationBarState(api,params),succeed({});return}if(kind==="statusBar"){applyStatusBarState(params),succeed({});return}if(kind==="systemInfo"){let model=config2.globals.__DEVICE_MODEL__||"iPhone",info={language:config2.language,model,systemVersion:config2.systemVersion,statusBarHeight:config2.statusBarHeight,platform:config2.platform,brand:config2.platform==="iOS"?"Apple":"Android",client_version:config2.globals.__APP_VERSION__??"",client_type:config2.clientType};succeed(api==="WVNativeDetector.getModelInfo"?{...info,platform:model}:info);return}if(kind==="mtop"){callMtop(params??{},onSuccess,onFailure);return}if(kind==="mtopStream"){callMtopStream(params??{},succeed,failed);return}if(kind==="kvGet"||kind==="kvSet"||kind==="kvDelete"){let p=params&&typeof params=="object"?params:{},key=typeof p.key=="string"?p.key:"";if(!key){failed("missing key");return}try{let storageKey=`__mearl_app_kv__:${key}`;if(kind==="kvGet"){let stored=localStorage.getItem(storageKey);stored!==null?succeed(stored):failed(JSON.stringify({ret:["HY_FAILED"],msg:"key not found"}))}else if(kind==="kvSet"){let value=typeof p.value=="string"?p.value:p.value===void 0?"":JSON.stringify(p.value);localStorage.setItem(storageKey,value),succeed({})}else localStorage.removeItem(storageKey),succeed({})}catch{failed(JSON.stringify({ret:["HY_FAILED"],msg:"kv storage unavailable"}))}return}if(kind==="pageContext"){succeed({pageContext:void 0});return}if(kind==="memoryGet"||kind==="memorySet"||kind==="memoryDelete"){let p=params&&typeof params=="object"?params:{},key=typeof p.key=="string"?p.key:"";if(!key){failed({error_message:"missing key"});return}try{let storageKey=`__mearl_app_memory__:${key}`;if(kind==="memoryGet"){let value=sessionStorage.getItem(storageKey);succeed(value===null?{}:{value})}else if(kind==="memorySet"){let value=typeof p.value=="string"?p.value:p.value===void 0?"":JSON.stringify(p.value);sessionStorage.setItem(storageKey,value),succeed({key,success:!0})}else sessionStorage.removeItem(storageKey),succeed({key,success:!0})}catch{failed({error_message:"memory cache unavailable"})}return}if(kind==="availabilityMap"){let p=params&&typeof params=="object"?params:{},channels=Array.isArray(p.data)?p.data.filter(value=>typeof value=="string"):[];succeed({res:"success",data:Object.fromEntries(channels.map(channel=>[channel,!1]))});return}if(kind==="userInfo"){let userId=readFirstUserCookie(["unb"]),userName=readFirstUserCookie(["_w_tb_nick","_nk_","snk","tracknick"]);callUserInfo({...userId&&{userId},...userName&&{userName}},succeed);return}if(kind==="networkInfo"){let state=readNetworkState();if(api==="WVNetwork.getNetworkType"){succeed({type:{wifi:"WIFI","slow-2g":"2G","2g":"2G","3g":"3G","4g":"4G"}[state]??"UNKNOWN"});return}if(config2.profile==="alipay"||config2.profile==="koubei"){succeed({networkAvailable:state!=="fail",networkType:{wifi:"WIFI","slow-2g":"2G","2g":"2G","3g":"3G","4g":"4G",fail:"NOTREACHABLE"}[state]??"UNKNOWN"});return}let type=networkTypeNumber(state);succeed({type,state:state==="slow-2g"?"2g":state});return}if(kind==="networkQualityMonitor"){let p=params&&typeof params=="object"?params:{},action=typeof p.action=="string"?p.action:"";if(action==="add_notify_network_quality"){if(!stopNetworkQualityMonitor){let notify=()=>{try{document.dispatchEvent(new CustomEvent("WV.NETWORK_TYPE_CHANGED",{detail:{new_network_type:networkTypeNumber(readNetworkState())}}))}catch{}},connection=navigator.connection;window.addEventListener("online",notify),window.addEventListener("offline",notify),connection?.addEventListener?.("change",notify),stopNetworkQualityMonitor=()=>{window.removeEventListener("online",notify),window.removeEventListener("offline",notify),connection?.removeEventListener?.("change",notify)}}succeed({});return}if(action==="remove_notify_network_quality"){stopNetworkQualityMonitor?.(),stopNetworkQualityMonitor=null,succeed({});return}failed({error_message:"unsupported network quality monitor action"});return}if(kind==="voiceRecognition"){let status=Number((params&&typeof params=="object"?params:{}).status);if(status===0){startVoiceRecognition(succeed,failed);return}if(status===1){let recognition=voiceRecognition;if(recognition)if(voiceRecognitionStopping=!0,voiceRecognitionRunning)try{recognition.stop()}catch{finishVoiceRecognition(recognition,1)}else finishVoiceRecognition(recognition,1);succeed({});return}if(status===2){cancelVoiceRecognition(!0),succeed({});return}failed({error_code:-1,error_message:"unsupported voice recognition status"});return}if(kind==="beaconRequest"){let url2=pickUrl(params);if(!url2){failed({error_message:"missing url"});return}try{let resolved=new URL(url2,location.href);if(resolved.protocol!=="http:"&&resolved.protocol!=="https:"){failed({error_message:"unsupported request protocol"});return}let image=new Image;image.referrerPolicy="no-referrer-when-downgrade",image.src=resolved.href,succeed({})}catch{failed({error_message:"invalid url"})}return}if(kind==="calendar"){let p=params&&typeof params=="object"?params:{},events=readCalendarEvents();if(api==="store_calendar_event"){let event=calendarEventFromParams(p);if(!event.title||event.startTime===null){failed({error_message:"calendar title and start time are required"});return}let next=events.filter(stored=>!sameCalendarEvent(stored,event));if(next.push(event),!writeCalendarEvents(next)){failed({error_message:"calendar storage unavailable"});return}succeed({success:!0});return}if(api==="remove_calendar_event"){let candidate=calendarEventFromParams(p),next=events.filter(stored=>!sameCalendarEvent(stored,candidate));if(!writeCalendarEvents(next)){failed({error_message:"calendar storage unavailable"});return}succeed({success:!0,removed:events.length-next.length});return}if(api==="check_batch_calendar"){let batch=Array.isArray(p.batch)?p.batch:[];succeed({batch:batch.map(item=>{let candidate=calendarEventFromParams(item);return{...item&&typeof item=="object"?item:{},success:events.some(stored=>sameCalendarEvent(stored,candidate))}})});return}let urls=Array.isArray(p.urls)?p.urls.filter(value=>typeof value=="string"):typeof p.url=="string"?[p.url]:[],titles=Array.isArray(p.calendar_titles)?p.calendar_titles.filter(value=>typeof value=="string"):typeof p.calendar_title=="string"?[p.calendar_title]:[],matched=events.filter(event=>(urls.length===0||urls.includes(event.url))&&(titles.length===0||titles.includes(event.title)));succeed({events:matched.map(calendarEventResponse)});return}if(kind==="geolocation"){let p=params&&typeof params=="object"?params:{},windvane=api==="WVLocation.getLocation",wechat=api==="getLocation"&&config2.bridges.some(bridge=>bridge.style==="wechat"),failLocation=(errorCode,errorMsg)=>{failed({errorCode,errorMsg,...windvane&&{ret:["HY_FAILED"],errMsg:errorCode===1?"PERMISSION_DENIED":"POSITION_UNAVAILABLE",message:errorMsg},...wechat&&{errMsg:`getLocation:fail ${errorMsg}`}})};if(wechat&&p.type&&p.type!=="wgs84"){failLocation(2,`unsupported coordinate type: ${String(p.type)}`);return}if(!navigator.geolocation){failLocation(2,"geolocation unavailable");return}let locate=()=>navigator.geolocation.getCurrentPosition(position=>{let{latitude,longitude,accuracy,altitude,altitudeAccuracy,heading,speed}=position.coords,coords={latitude,longitude,accuracy,altitude,altitudeAccuracy,heading,speed};if(api==="lbs"){let provider=config2.geolocation;if(!provider){failLocation(2,"reverse geocoding unavailable");return}callMtop({api:provider.reverseGeocodeApi,v:provider.version,data:{latitude,longitude,includeGJ:1},timeout:5e3},value=>{let response=value??{},address=response.data??{};if(!Array.isArray(response.ret)||!response.ret.some(ret=>typeof ret=="string"&&ret.startsWith("SUCCESS::"))||typeof address.cityName!="string"||!address.cityName.trim()||typeof address.cityCode!="string"||!address.cityCode.trim()){failLocation(2,"reverse geocoding returned no city");return}succeed({...coords,timestamp:position.timestamp,country:address.country,province:address.province,district:address.district,city:address.cityName,cityName:address.cityName,cityCode:address.cityCode,divisionId:address.divisionId,iataCode:address.iataCode,address:address.detail})},()=>failLocation(2,"reverse geocoding failed"));return}succeed(windvane?{ret:["HY_SUCCESS"],coords,timestamp:position.timestamp}:{...coords,timestamp:position.timestamp,...wechat&&{errMsg:"getLocation:ok"}})},error48=>failLocation(error48.code,error48.message),{enableHighAccuracy:p.enableHighAccuracy===!0||p.enableHighAcuracy===!0,timeout:1e4,maximumAge:p.useCache===!1?0:3e5});navigator.permissions?.query?navigator.permissions.query({name:"geolocation"}).then(status=>{status.state==="granted"?locate():failLocation(1,"location permission not granted")}).catch(locate):locate();return}if(kind==="permission"){let p=params&&typeof params=="object"?params:{},action=typeof p.action=="string"?p.action:"",permission=typeof p.permission=="string"?p.permission:"",permissionFailed=message=>failed({error_code:-1,error_message:message});if(permission==="album"||permission==="MODIFY_AUDIO_SETTINGS"){action==="check"||action==="request"?succeed({}):permissionFailed("unsupported permission action");return}let browserPermission=permission==="mic"?"microphone":permission==="camera"?"camera":permission==="lbs"?"geolocation":"";if(!browserPermission){permissionFailed("unsupported permission");return}if(action==="check"&&navigator.permissions?.query){navigator.permissions.query({name:browserPermission}).then(status=>{status.state==="granted"?succeed({}):permissionFailed("permission not granted")}).catch(()=>permissionFailed("permission check failed"));return}if(action==="request"&&(permission==="mic"||permission==="camera")){if(!navigator.mediaDevices?.getUserMedia){permissionFailed("media permission unavailable");return}navigator.mediaDevices.getUserMedia({audio:permission==="mic",video:permission==="camera"}).then(stream=>{for(let track of stream.getTracks())track.stop();succeed({})}).catch(()=>permissionFailed("permission denied"));return}if(action==="request"&&permission==="lbs"&&navigator.geolocation){navigator.geolocation.getCurrentPosition(()=>succeed({}),()=>permissionFailed("permission denied"),{timeout:1e4});return}permissionFailed("unsupported permission action");return}if(kind==="prefetch"){let p=params&&typeof params=="object"?params:{},url2=typeof p.url=="string"?p.url:"";if(!url2){failed({code:-1,errorMsg:"url is empty"});return}let resolvedUrl;try{resolvedUrl=new URL(url2,location.href).href}catch{failed({code:-1,errorMsg:"invalid url"});return}if(!Array.from(document.querySelectorAll('link[rel="prefetch"]')).some(link=>link.href===resolvedUrl)){let link=document.createElement("link");link.rel="prefetch",link.href=url2,(document.head??document.documentElement).appendChild(link)}succeed({});return}if(kind==="fptTrack"){let p=params&&typeof params=="object"?params:{},action=typeof p.action=="string"?p.action:"",actionParams=p.params&&typeof p.params=="object"?p.params:{},key=typeof actionParams.key=="string"?actionParams.key:"";if(action==="setFpt"){let value=typeof actionParams.value=="string"?actionParams.value:"";if(!key||!value||!/^[0-9A-Za-z._-]+$/.test(key)||!/^[0-9A-Za-z._-]+$/.test(value)||`${key}(${value})`.length>100){failed({error_message:"invalid fpt key or value"});return}setFptEntry(fptEntries,key,value),persistFpt()}else action==="deleteFpt"&&key&&(fptEntries.delete(key),persistFpt());succeed({});return}if(kind==="previewFile"){let p=params&&typeof params=="object"?params:{},fileUrl=typeof p.file_url=="string"?p.file_url:"",remoteUrl=typeof p.file_remote_url=="string"?p.file_remote_url:"",url2=(fileUrl.startsWith("http")?fileUrl:remoteUrl)||fileUrl||remoteUrl;url2?(requestOpen(url2,0,!1),succeed({})):failed({code:-1,errorMsg:"file_url is empty"});return}if(kind==="toast"){let error48=showAppToast(params);error48?failed({error_message:error48}):succeed({});return}if(kind==="unsupportedNativeInput"){let containerType="";try{containerType=new URL(location.href).searchParams.get("containerType")??""}catch{}!unsupportedNativeInputNotified&&(containerType==="h5_dx"||containerType==="flutter_h5")&&(unsupportedNativeInputNotified=!0,showAppToast({message:"当前页面使用原生输入框,请移除 URL 中的 containerType 参数以正常操作",milliseconds:4e3})),succeed({});return}if(kind==="payment"){log2("桥调用支付,等待用户确认",api,params),showPaymentDialog(api,params,succeed,failed);return}if(kind==="userTrack"){sendUserTrack(params),succeed({});return}if(kind==="response"){succeed(config2.actions.responses?.[api]);return}if(kind==="noop"){succeed({});return}silent||log2("未覆盖桥方法,回调 failure(页面库将走 H5 兜底):",api),failed(NOT_IMPLEMENTED_PAYLOAD)}let MEGA_SUPPORTED_APIS={stdPop:["showWeex2","showWeex","showH5","changeSize","close"],broadcast:["addEventListener","dispatchEvent","removeEventListener"],kvStorage:["setItem","getItem","removeItem","getAllKeys","clear","getCurrentInfo","getCurrentInfoAndKeys"],LifeCycle:["addPageLifeCycleListener","removePageLifeCycleListener"],Container:["interceptPageClose","disableInterceptPageClose"],navigator:["openURL","close","replace","setSystemBackBlockListener","removeSystemBackBlockListener"],NavBar:["setTitle"],Router:["popPage"]};function isMegaApiSupported(ability,api){return typeof ability=="string"&&typeof api=="string"&&MEGA_SUPPORTED_APIS[ability]?.includes(api)===!0}function megaParams(value){return value&&typeof value=="object"&&!Array.isArray(value)?value:{}}function megaError(callback,statusCode,message){emitMegaCallback(callback,{statusCode,type:"result",data:{errorMessage:typeof message=="string"?message:String(message??"")}})}function cloneMegaDetail(value){if(value===void 0)return{success:!0,value:void 0};try{return{success:!0,value:JSON.parse(JSON.stringify(value))}}catch{return{success:!1}}}function megaSuccess(data={}){return{statusCode:0,type:"result",data}}function megaFailure(message){return{statusCode:500,type:"result",data:{errorMessage:message}}}function megaKVParams(params){return{bizId:typeof params.bizID=="string"?params.bizID:typeof params.bizId=="string"?params.bizId:"",key:typeof params.key=="string"?params.key:"",value:typeof params.value=="string"?params.value:null}}function megaStringByteLength(value){try{return typeof TextEncoder=="function"?new TextEncoder().encode(value).length:value.length}catch{return value.length}}function megaKVUsedSize(entries){let size=0;for(let value of entries.values())size+=megaStringByteLength(value);return size}function reportMegaKVMutation(operation,bizId,key="",value,onSuccess,onFailure){requestContainerData("megaKVMutation",{operation,bizId,key,...value===void 0?{}:{value}},()=>onSuccess?.(),reason=>{log2("KVStorage 容器同步失败:",reason),onFailure?.(reason)})}function completeMegaKVMutation(operation,bizId,key,value,synchronous,callback){let result=megaSuccess();return reportMegaKVMutation(operation,bizId,key,value,synchronous?void 0:()=>emitMegaCallback(callback,result),synchronous?void 0:reason=>emitMegaCallback(callback,megaFailure(String(reason??"container sync failed")))),synchronous?result:null}function executeMegaKVStorage(api,params,synchronous,callback){let{bizId,key,value}=megaKVParams(params);if(!bizId)return megaFailure("missing bizID");let entries=megaKVStorage.get(bizId)??new Map;if(api==="setItem"){if(!key)return megaFailure("missing key");if(value===null||value==="")return megaFailure("missing value");let previousSize=megaStringByteLength(entries.get(key)??"");return megaKVUsedSize(entries)-previousSize+megaStringByteLength(value)>MEGA_KV_TOTAL_SIZE?megaFailure("KVStorage quota exceeded"):(entries.set(key,value),megaKVStorage.set(bizId,entries),megaKVMutationVersion+=1,persistMegaKVStorage(),completeMegaKVMutation("set",bizId,key,value,synchronous,callback))}if(api==="getItem"){if(!key)return megaFailure("missing key");let result=entries.get(key)??"";return megaSuccess(synchronous?{result}:result)}if(api==="removeItem")return key?(entries.delete(key),entries.size===0&&megaKVStorage.delete(bizId),megaKVMutationVersion+=1,persistMegaKVStorage(),completeMegaKVMutation("remove",bizId,key,void 0,synchronous,callback)):megaFailure("missing key");if(api==="getAllKeys"){let result=Array.from(entries.keys());return megaSuccess(synchronous?{result}:result)}if(api==="clear")return megaKVStorage.delete(bizId),megaKVMutationVersion+=1,persistMegaKVStorage(),completeMegaKVMutation("clear",bizId,"",void 0,synchronous,callback);if(api==="getCurrentInfo"||api==="getCurrentInfoAndKeys"){let data={totalSize:MEGA_KV_TOTAL_SIZE,freeSize:Math.max(MEGA_KV_TOTAL_SIZE-megaKVUsedSize(entries),0)};return api==="getCurrentInfoAndKeys"&&(data.keys=Array.from(entries.keys())),megaSuccess(data)}return{statusCode:405,type:"result",data:{}}}function handleMegaLifeCycle(api,callback){if(api==="addPageLifeCycleListener"){callback&&megaLifeCycleListeners.add(callback),emitMegaCallback(callback,megaSuccess());return}if(api==="removePageLifeCycleListener"){let listeners=Array.from(megaLifeCycleListeners);megaLifeCycleListeners.clear(),emitMegaCallback(callback,megaSuccess());for(let listener of listeners)emitMegaCallback(listener,{statusCode:99,type:"finish",data:{}});return}megaError(callback,405,`LifeCycle.${api} is not supported`)}function handleMegaContainer(api,callback){if(api==="interceptPageClose"){callback&&megaPageCloseListeners.add(callback),emitMegaCallback(callback,megaSuccess());return}if(api==="disableInterceptPageClose"){let listeners=Array.from(megaPageCloseListeners);megaPageCloseListeners.clear(),emitMegaCallback(callback,megaSuccess());for(let listener of listeners)emitMegaCallback(listener,{statusCode:99,type:"finish",data:{}});return}megaError(callback,405,`Container.${api} is not supported`)}function megaNavigationUrl(params){let rawUrl=pickUrl(params);if(!rawUrl)return null;if(!params.extQuery||typeof params.extQuery!="object"||Array.isArray(params.extQuery))return rawUrl;try{let target=new URL(rawUrl,location.href);for(let[key,value]of Object.entries(params.extQuery))value!=null&&target.searchParams.set(key,String(value));return target.href}catch{return rawUrl}}function handleMegaNavigator(api,params,callback){if(api==="openURL"||api==="replace"){let url2=megaNavigationUrl(params);if(!url2){megaError(callback,500,"missing url");return}let callbackId=api==="openURL"&&callback?stashCallback(value=>{let backdata=value&&typeof value=="object"?value.backdata:void 0;emitMegaCallback(callback,{statusCode:1,type:"onResult",data:{result:!0,...backdata===void 0?{}:{data:backdata}}}),emitMegaCallback(callback,{statusCode:99,type:"finish",data:{}})}):0;requestOpen(url2,callbackId,!1,{...params,...api==="replace"?{__mearlReplace:!0}:{}}),emitMegaCallback(callback,megaSuccess());return}if(api==="close"){emitMegaCallback(callback,megaSuccess()),requestClose(void 0);return}if(api==="setSystemBackBlockListener"){megaSystemBackListener&&megaSystemBackListener!==callback&&emitMegaCallback(megaSystemBackListener,{statusCode:99,type:"finish",data:{}}),megaSystemBackListener=callback??null,emitMegaCallback(callback,megaSuccess());return}if(api==="removeSystemBackBlockListener"){let listener=megaSystemBackListener;megaSystemBackListener=null,emitMegaCallback(callback,megaSuccess()),listener&&emitMegaCallback(listener,{statusCode:99,type:"finish",data:{}});return}megaError(callback,405,`navigator.${api} is not supported`)}function handleMegaNavBar(api,params,callback){if(api!=="setTitle"){megaError(callback,405,`NavBar.${api} is not supported`);return}applyNavigationBarState(api,params),emitMegaCallback(callback,megaSuccess())}function handleMegaRouter(api,callback){if(api!=="popPage"){megaError(callback,405,`Router.${api} is not supported`);return}emitMegaCallback(callback,megaSuccess()),requestClose(void 0)}function handleMegaStdPop(api,params,callback){if(api==="showH5"||api==="showWeex2"||api==="showWeex"){let url2=pickUrl(params),popId=typeof params.popId=="string"?params.popId.trim():"";if(!url2||!popId){megaError(callback,500,url2?"missing popId":"missing url");return}let callbackId=stashCallback(value=>{let result=value&&typeof value=="object"&&"backdata"in value?value.backdata:void 0;emitMegaCallback(callback,{statusCode:1,type:"onClose",data:result}),emitMegaCallback(callback,{statusCode:99,type:"finish"})});requestOpen(url2,callbackId,!0,{...params,__mearlMegaPopId:popId}),emitMegaCallback(callback,{statusCode:0,type:"result",data:{}});return}if(api==="close"){let popId=typeof params.popId=="string"?params.popId.trim():"";if(!popId){megaError(callback,500,"missing popId");return}let cloned=cloneMegaDetail(params.result);if(!cloned.success){megaError(callback,500,"result is not serializable");return}requestContainerData("megaPopClose",{popId,result:cloned.value},()=>emitMegaCallback(callback,{statusCode:0,type:"result",data:{}}),reason=>megaError(callback,500,reason));return}if(api==="changeSize"){let popId=typeof params.popId=="string"?params.popId.trim():"";if(!popId){megaError(callback,500,"missing popId");return}requestContainerData("megaPopResize",{...params,popId},()=>emitMegaCallback(callback,{statusCode:0,type:"result",data:{}}),reason=>megaError(callback,500,reason));return}megaError(callback,405,`stdPop.${api} is not supported`)}function handleMegaBroadcast(api,params,callback){let bizId=megaBroadcastBizId(params.bizId),eventName=typeof params.eventName=="string"?params.eventName.trim():"";if(!eventName){megaError(callback,500,"missing eventName");return}if(api==="addEventListener"){if(!callback)return;let id=`mearl-mega-listener-${++megaListenerSeq}`;megaBroadcastListeners.set(id,{id,bizId,eventName,once:params.once===!0,callback}),emitMegaCallback(callback,{statusCode:0,type:"result",data:{}}),emitMegaCallback(callback,{statusCode:1,type:"onAdd",data:{listenerId:id}});return}if(api==="dispatchEvent"){let detail=cloneMegaDetail(params.detail);if(!detail.success){megaError(callback,500,"detail is not serializable");return}requestContainerData("megaBroadcast",{message:{kind:"megaBroadcast",bizId,eventName,detail:detail.value}},()=>emitMegaCallback(callback,{statusCode:0,type:"result",data:{}}),reason=>megaError(callback,500,reason));return}if(api==="removeEventListener"){let listenerId=typeof params.listenerId=="string"?params.listenerId:"",removed=[];for(let listener of Array.from(megaBroadcastListeners.values()))listener.bizId!==bizId||listener.eventName!==eventName||listenerId&&listener.id!==listenerId||(megaBroadcastListeners.delete(listener.id),removed.push(listener));emitMegaCallback(callback,{statusCode:0,type:"result",data:{}});for(let listener of removed)emitMegaCallback(listener.callback,{statusCode:99,type:"finish"});return}megaError(callback,405,`broadcast.${api} is not supported`)}function makeMegaBridge(){return{asyncCall:(ability,api,rawParams,callback)=>{let params=megaParams(rawParams);if(ability==="ability"&&api==="available"){emitMegaCallback(callback,{statusCode:0,type:isMegaApiSupported(params.ability,params.api)?"YES":"NO",data:{}});return}if(ability==="ability"&&api==="batchFinishTrace"){emitMegaCallback(callback,{statusCode:0,type:"result",data:{}});return}if(!isMegaApiSupported(ability,api)){megaError(callback,405,`${ability}.${api} is not supported`);return}if(ability==="stdPop")handleMegaStdPop(api,params,callback);else if(ability==="broadcast")handleMegaBroadcast(api,params,callback);else if(ability==="kvStorage"){let result=executeMegaKVStorage(api,params,!1,callback);result&&emitMegaCallback(callback,result)}else ability==="LifeCycle"?handleMegaLifeCycle(api,callback):ability==="Container"?handleMegaContainer(api,callback):ability==="navigator"?handleMegaNavigator(api,params,callback):ability==="NavBar"?handleMegaNavBar(api,params,callback):handleMegaRouter(api,callback)},syncCall:(ability,api,rawParams)=>{let params=megaParams(rawParams);return ability==="ability"&&api==="available"?{statusCode:0,type:isMegaApiSupported(params.ability,params.api)?"YES":"NO",data:{}}:ability==="kvStorage"&&isMegaApiSupported(ability,api)?executeMegaKVStorage(api,params,!0)??megaFailure("container sync pending"):{statusCode:405,type:"result",data:{}}}}}function makeBridge(style){if(style==="mega")return makeMegaBridge();if(style==="easybikeNative"){let callNative=rawPayload=>{let payload;try{payload=typeof rawPayload=="string"?JSON.parse(rawPayload):rawPayload??{}}catch{return}let classMap=typeof payload.classMap=="string"?payload.classMap:"",method=typeof payload.method=="string"?payload.method:"",callbackId=typeof payload.callbackId=="string"||typeof payload.callbackId=="number"?String(payload.callbackId):"",params;try{params=typeof payload.params=="string"?payload.params?JSON.parse(payload.params):{}:payload.params??{}}catch{params={}}let complete=(code,data,msg="")=>{let callback=resolveWindowFunction("callBack");callbackId&&callback&&callback({callbackId,code,data,msg})};dispatch(`${classMap}.${method}`,params,value=>complete(0,value),error48=>complete(1,void 0,typeof error48=="string"?error48:String(error48??"")))};return{postMessage:callNative,callNative}}if(style==="windvane"){let call=(api,params,success2,failure)=>{let onSuccess=typeof success2=="function"?success2:void 0,onFailure=typeof failure=="function"?failure:void 0;if(onSuccess||onFailure){dispatch(api,params,onSuccess,onFailure);return}return new Promise((resolve2,reject)=>dispatch(api,params,resolve2,reject))};return{isAvailable:!0,version:"8.7.0",call2:call,call:(cls,method,params,succ,fail2)=>call(`${cls}.${method}`,params,succ,fail2)}}if(style==="fliggy"||style==="alipay"||style==="callback"){let bridge={call:(api,params,succ,fail2)=>{typeof params=="function"&&(fail2=succ,succ=params,params=void 0);let p=params&&typeof params=="object"?params:{},successFn=succ??(typeof p.success_callback=="function"?p.success_callback:void 0)??(typeof p.successCallback=="function"?p.successCallback:void 0),failureFn=fail2??(typeof p.fail_callback=="function"?p.fail_callback:void 0)??(typeof p.failure_callback=="function"?p.failure_callback:void 0)??(typeof p.failCallback=="function"?p.failCallback:void 0)??(typeof p.failureCallback=="function"?p.failureCallback:void 0);dispatch(api,p,res=>successFn?.(res),err=>{failureFn?failureFn(err):successFn?.({error:err})},p.callbackCommand??p.callback_command)},pushBack:(prefixOrApi,apiOrParams,paramsOrSucc,succ)=>{let api=prefixOrApi,params=apiOrParams,success2=paramsOrSucc;typeof apiOrParams=="string"&&(api=apiOrParams,params=paramsOrSucc,success2=succ);let p=params??{},successFn=(typeof success2=="function"?success2:void 0)??(typeof p.successCallback=="function"?p.successCallback:void 0);return dispatch(api,p,res=>successFn?.(res),void 0,p.callbackCommand??p.callback_command),bridge},sendUriScheme:uri=>(handleMaybeScheme(uri),bridge)};if(style==="fliggy"){let normalizedAppName=(config2.globals.__APP_NAME__??"").toUpperCase(),os11=config2.clientType==="iphone"?"ios":"android",isAliApp=name=>normalizedAppName===name.toUpperCase();Object.assign(bridge,{version:"1.0.21",device:{os:os11,OS:config2.platform,type:os11,version:config2.systemVersion,model:config2.globals.__DEVICE_MODEL__??""},platform:os11,isAliApp,isTmall:isAliApp("TM"),isTaobao:isAliApp("TB"),isAlipay:isAliApp("AP"),isAlitrip:isAliApp("LX"),isKoubei:isAliApp("KB"),isElm:isAliApp("ELMC"),isGaode:isAliApp("amap"),isUC:/UCBrowser/i.test(config2.userAgent),isWeibo:/Weibo/i.test(config2.userAgent),isWeixin:/MicroMessenger/i.test(config2.userAgent),isWindVane:config2.bridges.some(item=>item.style==="windvane"),isAlipayClient:/AlipayClient/i.test(config2.userAgent)})}return bridge}if(style==="btrip")return{call:(api,params)=>dispatch(api,params??{},void 0,void 0)};if(style==="invoke")return{invoke:(api,params)=>{let p=params??{};dispatch(api,p,p.success,p.fail)}};if(style==="callHandler")return{callHandler:(api,params)=>dispatch(api,params??{},void 0,void 0)};if(style==="amap")return{ready:cb=>cb?.(),send:(msg,cb)=>{let m=msg??{};dispatch(typeof m.action=="string"?m.action:"",m,res=>cb?.(res),err=>cb?.({error:err}))}};if(style==="didi")return{openPage:params=>dispatch("openPage",params??{},void 0,void 0),closePage:params=>dispatch("closePage",params??{},void 0,void 0)};if(style==="wechat"||style==="wechatMiniProgram"){let invoke2=(api,params)=>{let p=params&&typeof params=="object"?params:{};dispatch(api,p,value=>{p.success?.(value),p.complete?.(value)},error48=>{p.fail?.(error48),p.complete?.(error48)})};return style==="wechat"?{ready:callback=>{callback&&setTimeout(callback,0)},getLocation:params=>invoke2("getLocation",params)}:{navigateTo:params=>invoke2("navigateTo",params),redirectTo:params=>invoke2("redirectTo",params),switchTab:params=>invoke2("switchTab",params),reLaunch:params=>invoke2("reLaunch",params),navigateBack:params=>invoke2("navigateBack",params),postMessage:params=>invoke2("postMessage",params),getEnv:callback=>{callback&&setTimeout(()=>callback({miniprogram:!0}),0)}}}return{}}function setGlobal(path19,value){let parts=path19.split("."),obj=w;for(let i=0;i<parts.length-1;i++){let cur=obj[parts[i]];(!cur||typeof cur!="object")&&(obj[parts[i]]={}),obj=obj[parts[i]]}obj[parts[parts.length-1]]=value}function setPersistentGlobal(path19,value){let parts=path19.split(".").filter(Boolean);if(parts.length<2){setGlobal(path19,value);return}let[rootKey,...nestedParts]=parts,isObjectLike=candidate=>typeof candidate=="object"&&candidate!==null||typeof candidate=="function",attachBridge=candidate=>{let root=isObjectLike(candidate)?candidate:{},obj=root;for(let index=0;index<nestedParts.length-1;index+=1){let key=nestedParts[index],child=obj[key];if(!isObjectLike(child))try{obj[key]={}}catch{return root}obj=obj[key]}let leaf=nestedParts[nestedParts.length-1];try{Object.defineProperty(obj,leaf,{configurable:!1,enumerable:!0,get:()=>value,set:()=>{}})}catch{try{obj[leaf]=value}catch{}}return root},currentRoot=attachBridge(w[rootKey]);try{Object.defineProperty(w,rootKey,{configurable:!1,enumerable:!0,get:()=>currentRoot,set:next=>{currentRoot=attachBridge(next)}})}catch{w[rootKey]=currentRoot}}if(config2.bridges.some(spec=>spec.style==="mega")){let hydrationVersion=megaKVMutationVersion;requestContainerData("megaKVSnapshot",{},value=>{let entries=value&&typeof value=="object"?value.entries:void 0;megaKVMutationVersion===hydrationVersion&&replaceMegaKVStorage(entries)},()=>{})}for(let spec of config2.bridges)try{let bridge=makeBridge(spec.style);spec.persistent?setPersistentGlobal(spec.global,bridge):setGlobal(spec.global,bridge)}catch(e){console.error(TAG,"桥安装失败:",spec.global,e)}return{mapScheme,handleMaybeScheme,handleAppMessage,handleNativeBack,handleResume,handlePageVisibility,applyRuntimeResponses}}function installAppProfileContainerStack(config2,environment,links){let{SRC,TAG,simulateSystemBars,ROOT_FRAME_NAME,LAYER_FRAME_NAME,isTop,isRootFrame,isLayerFrame,isContainerFrame,usesRootContainer,log:log2}=environment,{pageTransport}=links,initialLayerTitleBarState=url2=>links.getSystemBars().initialLayerTitleBarState(url2),resolvedTitleBarState=layer=>links.getSystemBars().resolvedTitleBarState(layer),parseReportedTitleBarState=value=>links.getSystemBars().parseReportedTitleBarState(value),createSimulatedNavigationBarView=(placement,onBack)=>links.getSystemBars().createNavigationBarView(placement,onBack),destroySimulatedNavigationBarView=view=>links.getSystemBars().destroyNavigationBarView(view),syncLayerViewport=(layer,state)=>links.getSystemBars().syncLayerViewport(layer,state),syncActiveSystemBars=()=>links.getSystemBars().syncActiveSystemBars(),syncSimulatedTitleBar=()=>links.getSystemBars().syncSimulatedTitleBar(),rootContainerActive=!1,rootFrame=null,rootBusinessUrl=location.href,splitScreenActive=usesRootContainer&&config2.rootContainer?.splitScreen===!0,webViewEnvironmentRequestSeq=0,simulatedPageHidden=!1,runtimeResponses=null;function syncSimulatorStateToWindow(target){target&&(target.postMessage({source:SRC,type:"requestTitleBarState"},"*"),runtimeResponses&&target.postMessage({source:SRC,type:"runtimeResponses",profile:config2.profile,responses:runtimeResponses},"*"),simulatedPageHidden&&target.postMessage({source:SRC,type:"simulatorVisibility",hidden:!0},"*"))}function startPreparedWebViewNavigation(frame,target,canCommit,registerCleanup){let insets=config2.safeAreaInsets??{top:config2.statusBarHeight,right:0,bottom:0,left:0};if(!usesRootContainer||!Object.values(insets).some(value=>value>0)){canCommit()&&(frame.src=target);return}let requestId=++webViewEnvironmentRequestSeq,settled=!1,fallbackTimer=0,cleanup=()=>{settled||(settled=!0,clearTimeout(fallbackTimer),window.removeEventListener("message",handleResponse),registerCleanup?.(null))},commitNavigation=fallbackReason=>{cleanup(),fallbackReason&&console.warn(TAG,"WebView 环境准备未完成,降级提交导航",{target,requestId,reason:fallbackReason}),canCommit()&&(frame.src=target)},handleResponse=event=>{if(event.source!==window||event.data?.source!=="mearl-content"||event.data?.type!=="APP_BRIDGE_PREPARE_WEBVIEW_RESPONSE"||event.data?.requestId!==requestId)return;let result=event.data.result;result?.success===!0?commitNavigation():commitNavigation(String(result?.error??"unknown preparation failure"))};registerCleanup?.(cleanup),window.addEventListener("message",handleResponse),fallbackTimer=setTimeout(()=>commitNavigation("preparation timed out after 500ms"),500);try{window.postMessage({source:SRC,type:"prepareWebView",requestId},"*")}catch(error48){commitNavigation(error48 instanceof Error?error48.message:String(error48))}}function installRootContainer(){if(!usesRootContainer||!/^https?:$/i.test(location.protocol))return;let shellRoot,frame;try{for(let cookie of config2.rootContainer?.initialCookies??[]){if(!cookie.name)continue;let parts=[`${encodeURIComponent(cookie.name)}=${encodeURIComponent(cookie.value)}`,`Path=${cookie.path??"/"}`];cookie.domain&&parts.push(`Domain=${cookie.domain}`),document.cookie=parts.join("; ")}shellRoot=document.createElement("html");let shellHead=document.createElement("head"),charset=document.createElement("meta"),viewport=document.createElement("meta"),title=document.createElement("title"),shellBody=document.createElement("body");frame=document.createElement("iframe"),shellRoot.setAttribute("data-mearl-app-shell",""),shellBody.setAttribute("data-mearl-app-shell",""),charset.setAttribute("charset","utf-8"),viewport.name="viewport",viewport.content="width=device-width,initial-scale=1,viewport-fit=cover",shellHead.append(charset,viewport,title),shellRoot.append(shellHead,shellBody),shellRoot.style.cssText="width:100%;height:100%;margin:0;overflow:hidden;background:#fff;",shellBody.style.cssText="width:100%;height:100%;margin:0;overflow:hidden;background:#fff;",frame.name=ROOT_FRAME_NAME,frame.setAttribute("data-mearl-root-webview",config2.profile),frame.setAttribute("allow","microphone; on-device-speech-recognition"),splitScreenActive&&frame.setAttribute("data-mearl-split-pane","left"),frame.style.cssText=splitScreenActive?"position:fixed;left:0;right:auto;top:0;bottom:0;width:50%;height:100%;border:0;border-right:1px solid rgba(15,23,42,.14);box-sizing:border-box;display:block;background:#fff;z-index:0;opacity:1;":"position:fixed;left:0;right:0;top:0;bottom:0;width:100%;height:100%;border:0;display:block;background:#fff;z-index:0;opacity:1;",frame.addEventListener("load",()=>{let committedSrc=frame.getAttribute("src");!committedSrc||committedSrc==="about:blank"||(syncSimulatorStateToWindow(frame.contentWindow),requestAnimationFrame(()=>{rootFrame!==frame||!frame.isConnected||(frame.setAttribute("data-mearl-webview-ready",""),syncSimulatedTitleBar())}))}),shellBody.appendChild(frame);let currentRoot=document.documentElement;currentRoot?document.replaceChild(shellRoot,currentRoot):document.appendChild(shellRoot)}catch(error48){console.warn(TAG,"根 WebView 容器创建失败,保留当前页面",error48),rootFrame=null;return}rootFrame=frame,rootContainerActive=!0;try{typeof window.stop=="function"&&window.stop()}catch(error48){console.warn(TAG,"停止外层文档加载失败,继续启动根 WebView",error48)}try{startPreparedWebViewNavigation(frame,rootBusinessUrl,()=>rootFrame===frame&&frame.isConnected)}catch(error48){console.warn(TAG,"根 WebView 环境准备启动失败,直接提交业务导航",error48),rootFrame===frame&&frame.isConnected&&(frame.src=rootBusinessUrl)}}installRootContainer();function normalizeProxyPathPrefix(prefix){let withLeadingSlash=prefix.startsWith("/")?prefix:`/${prefix}`;return withLeadingSlash.endsWith("/")?withLeadingSlash:`${withLeadingSlash}/`}function matchesProxyTarget(hostname3,suffixes){return suffixes.some(suffix=>hostname3===suffix||hostname3.endsWith(`.${suffix}`))}function mapLayerFrameUrl(url2){let proxy=config2.layerUrlProxy;if(!proxy||!location.hostname.startsWith(proxy.sourceHostPrefix))return url2;try{let target=new URL(url2,location.href);if(!/^https?:$/.test(target.protocol))return url2;let prefix=normalizeProxyPathPrefix(proxy.pathPrefix);if(target.hostname===location.hostname){if(target.pathname.startsWith(prefix))return url2;let derivedHost=location.pathname.startsWith(prefix)?location.pathname.slice(prefix.length).split("/")[0]:proxy.defaultTargetHost;return!derivedHost||!matchesProxyTarget(derivedHost,proxy.targetHostSuffixes)?url2:`${location.origin}${prefix}${derivedHost}${target.pathname}${target.search}${target.hash}`}return matchesProxyTarget(target.hostname,proxy.targetHostSuffixes)?`${location.origin}${prefix}${target.host}${target.pathname}${target.search}${target.hash}`:url2}catch{return url2}}function restoreLayerBusinessUrl(url2){let proxy=config2.layerUrlProxy;if(!proxy)return url2;try{let current=new URL(url2,location.href),prefix=normalizeProxyPathPrefix(proxy.pathPrefix);if(current.origin!==location.origin||!current.pathname.startsWith(prefix))return url2;let rest=current.pathname.slice(prefix.length),slash=rest.indexOf("/"),host=slash===-1?rest:rest.slice(0,slash);if(!host)return url2;let hostname3=new URL(`${current.protocol}//${host}`).hostname;if(!matchesProxyTarget(hostname3,proxy.targetHostSuffixes))return url2;let pathname=slash===-1?"/":rest.slice(slash);return`${current.protocol}//${host}${pathname}${current.search}${current.hash}`}catch{return url2}}let ANIM_MS=config2.animationMs??300;function boolParam(value,fallback){return value===!0||value===1||value==="1"||value==="true"?!0:value===!1||value===0||value==="0"||value==="false"?!1:value===""?!0:fallback}function numberParam(value,fallback,min,max){let parsed=typeof value=="number"?value:Number(value);return Number.isFinite(parsed)?Math.min(Math.max(parsed,min),max):fallback}function resolveOverlayPresentation(url2,params,explicitWebdialog){let query=null;try{query=new URL(url2,location.href).searchParams}catch{}let records=[],addRecord=value=>{value&&typeof value=="object"&&!Array.isArray(value)&&records.push(value)};addRecord(params?.pageParams),addRecord(params?.page_params),addRecord(params?.popConfig),addRecord(params?.data),addRecord(params?.param),addRecord(params);let read=key=>{for(let record2 of records)if(Object.prototype.hasOwnProperty.call(record2,key))return record2[key];return query?.has(key)?query.get(key):void 0},protocol=config2.overlay;if(!explicitWebdialog&&(!protocol||!boolParam(read(protocol.enabledParam),!1)))return null;let configuredTopRatio=protocol?read(protocol.topRatioParam):void 0,configuredHeightRatio=protocol?.heightRatioParam?read(protocol.heightRatioParam):void 0,configuredMaxHeight=read("maxHeight")??configuredHeightRatio,defaultTopRatio=protocol?.defaultTopRatio??.2;return{topRatio:configuredTopRatio!==void 0?numberParam(configuredTopRatio,defaultTopRatio,0,1):configuredMaxHeight!==void 0?1-numberParam(configuredMaxHeight,1-defaultTopRatio,0,1):defaultTopRatio,widthRatio:numberParam(read("maxWidth"),1,0,1),radius:numberParam((protocol?read(protocol.radiusParam):void 0)??read("cornerRadius"),protocol?.defaultRadius??0,0,50),maskAlpha:numberParam(protocol?read(protocol.maskAlphaParam):void 0,protocol?.defaultMaskAlpha??.3,0,1),tapClose:boolParam((protocol?read(protocol.tapCloseParam):void 0)??read("tapEnable"),protocol?.defaultTapClose??!0)}}function requestsPopBeforeOpen(url2,params){if(params?.__mearlReplace===!0)return!0;let key=config2.popBeforeOpenParam;if(!key)return!1;let records=[params?.pageParams,params?.page_params,params?.data,params?.param,params];for(let value of records){if(!value||typeof value!="object"||Array.isArray(value))continue;let record2=value;if(Object.prototype.hasOwnProperty.call(record2,key))return boolParam(record2[key],!1)}try{let query=new URL(url2,location.href).searchParams;return query.has(key)&&boolParam(query.get(key),!1)}catch{return!1}}let layers=[],forwardStack=[],layerSeq=0,enteringLayerCount=0,closingLayerCount=0,explicitLayerTitleBarStates=new Map,rootScrollStyles=null,pendingClose=null,nativeBackRequestSeq=0,pendingNativeBack=null,containerDataRequestSeq=0,containerDataCallbacks=new Map,sharedFiles=new Map,sharedData=new Map,legacyBroadcastChannels=new Set,MEGA_KV_STORAGE_KEY=`__mearl_mega_kv__:${config2.profile}`;function readMegaKVStorage(){let storage=new Map;try{let parsed=JSON.parse(localStorage.getItem(MEGA_KV_STORAGE_KEY)??"{}");if(!parsed||typeof parsed!="object"||Array.isArray(parsed))return storage;for(let[bizId,rawEntries]of Object.entries(parsed)){if(!rawEntries||typeof rawEntries!="object"||Array.isArray(rawEntries))continue;let entries=new Map;for(let[key,value]of Object.entries(rawEntries))typeof value=="string"&&entries.set(key,value);storage.set(bizId,entries)}}catch{}return storage}let megaKVStorage=readMegaKVStorage();function megaKVSnapshot(){let snapshot={};for(let[bizId,values]of megaKVStorage)snapshot[bizId]=Object.fromEntries(values);return snapshot}function persistMegaKVStorage(){try{localStorage.setItem(MEGA_KV_STORAGE_KEY,JSON.stringify(megaKVSnapshot()))}catch{}}let PENDING_CLOSE_TIMEOUT_MS=400,pendingHistoryDepth=null,pendingSplitRootOpen=null;function clearPendingClose(){pendingClose&&(clearTimeout(pendingClose.timer),pendingClose=null)}function clearPendingNativeBack(){pendingNativeBack&&(clearTimeout(pendingNativeBack.timer),pendingNativeBack=null)}function clearPendingHistoryDepth(){pendingHistoryDepth&&(clearTimeout(pendingHistoryDepth.timer),pendingHistoryDepth=null)}function syncHistoryAfterDirectClose(){clearPendingHistoryDepth();let depth=layers.length,timer=setTimeout(()=>{pendingHistoryDepth=null,console.warn(TAG,"WebView 已出栈,但浏览器历史未在预期时间内同步",{depth})},PENDING_CLOSE_TIMEOUT_MS);pendingHistoryDepth={depth,timer},history.back()}function armPendingClose(data,retries){clearPendingClose();let timer=setTimeout(()=>{pendingClose=null,log2("close 未等到 popstate,直接关栈顶兜底"),closeToDepth(Math.max(layers.length-1,0),data,!0)},PENDING_CLOSE_TIMEOUT_MS);pendingClose={data,retries,timer},history.back()}function parseStorageId(url2){try{return new URL(url2,location.href).searchParams.get("__storage_id")}catch{return null}}function titleBarStateCacheKey(url2){try{let parsed=new URL(url2,location.href);return parsed.hash="",parsed.href}catch{return url2}}function cacheExplicitTitleBarState(layer,state){explicitLayerTitleBarStates.set(titleBarStateCacheKey(layer.entryUrl),state),explicitLayerTitleBarStates.set(titleBarStateCacheKey(layer.url),state)}function readDepth(state){if(state&&typeof state=="object"){let d=state.__mearl_layer__;if(typeof d=="number")return d}return null}function mapUrlForSync(url2){let suffixes=config2.urlSyncHostSuffixes??[];try{let u=new URL(url2,location.href);if(!/^https?:$/.test(u.protocol)||!(suffixes.length===0||suffixes.some(s=>u.host===s||u.host.endsWith(`.${s}`))))return;if(u.origin===location.origin)return u.pathname+u.search+u.hash;let proxy=config2.layerUrlProxy;return proxy&&location.hostname.startsWith(proxy.sourceHostPrefix)&&matchesProxyTarget(u.hostname,proxy.targetHostSuffixes)?`${normalizeProxyPathPrefix(proxy.pathPrefix)}${u.host}${u.pathname}${u.search}${u.hash}`:u.pathname+u.search+u.hash}catch{return}}function createLayerEl(overlay,id){let el=document.createElement("div");el.setAttribute("data-mearl-layer",String(id)),splitScreenActive&&el.setAttribute("data-mearl-split-pane","right"),el.style.cssText=splitScreenActive?`position:fixed;left:50%;right:0;top:0;bottom:0;width:50%;z-index:${2147483e3+id%100*2};`:`position:fixed;inset:0;z-index:${2147483e3+id%100*2};`;let frame=document.createElement("iframe");if(frame.name=LAYER_FRAME_NAME,frame.setAttribute("allow","microphone; on-device-speech-recognition"),frame.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-modals allow-downloads allow-popups"),frame.style.cssText="position:absolute;inset:0;width:100%;height:100%;border:0;display:block;background:#fff;z-index:0;opacity:1;",overlay){el.style.pointerEvents="none";let mask=document.createElement("div");mask.style.cssText=`position:absolute;inset:0;background:rgba(0,0,0,${overlay.maskAlpha});opacity:0;pointer-events:auto;`;let sheet=document.createElement("div"),width=overlay.widthRatio*100,left=(1-overlay.widthRatio)/2*100;return sheet.style.cssText=`position:absolute;left:${left}%;right:auto;bottom:0;width:${width}%;height:${(1-overlay.topRatio)*100}%;background:#fff;border-radius:${overlay.radius}px ${overlay.radius}px 0 0;overflow:hidden;pointer-events:auto;`,sheet.appendChild(frame),el.appendChild(mask),el.appendChild(sheet),{el,frame,animEl:sheet,mask}}return el.style.background="#fff",el.appendChild(frame),{el,frame,animEl:el,mask:null}}function setLayerInteractive(layer,interactive){layer.frame.style.pointerEvents=interactive?"":"none",layer.titleBarView&&(layer.titleBarView.root.style.pointerEvents=interactive?"":"none"),interactive?(layer.frame.removeAttribute("inert"),layer.frame.removeAttribute("aria-hidden"),layer.frame.removeAttribute("tabindex")):(layer.frame.setAttribute("inert",""),layer.frame.setAttribute("aria-hidden","true"),layer.frame.setAttribute("tabindex","-1"),layer.frame.blur()),layer.overlay?(layer.el.style.pointerEvents="none",layer.animEl.style.pointerEvents=interactive?"auto":"none",layer.mask&&(layer.mask.style.pointerEvents=interactive?"auto":"none")):layer.el.style.pointerEvents=interactive?"":"none"}function setRootFrameInteractive(interactive){rootFrame&&(rootFrame.style.pointerEvents=interactive?"":"none",interactive?(rootFrame.removeAttribute("inert"),rootFrame.removeAttribute("aria-hidden"),rootFrame.removeAttribute("tabindex")):(rootFrame.setAttribute("inert",""),rootFrame.setAttribute("aria-hidden","true"),rootFrame.setAttribute("tabindex","-1"),rootFrame.blur()))}function blockClosingLayerInteractions(layer){setLayerInteractive(layer,!1),layer.el.style.pointerEvents="auto"}function syncRootScrollLock(locked){let body=document.body;if(locked&&!rootScrollStyles){rootScrollStyles={html:document.documentElement.style.overflow,body:body?.style.overflow??null},document.documentElement.style.overflow="hidden",body&&(body.style.overflow="hidden");return}!locked&&rootScrollStyles&&(document.documentElement.style.overflow=rootScrollStyles.html,body&&rootScrollStyles.body!==null&&(body.style.overflow=rootScrollStyles.body),rootScrollStyles=null)}function syncLayerInteractivity(){let activeLayer=closingLayerCount===0&&enteringLayerCount===0?layers[layers.length-1]:void 0;for(let layer of layers)setLayerInteractive(layer,layer===activeLayer),!activeLayer&&layer===layers[layers.length-1]&&(layer.el.style.pointerEvents="auto");setRootFrameInteractive(splitScreenActive?pendingSplitRootOpen===null:layers.length===0&&enteringLayerCount===0&&closingLayerCount===0),syncRootScrollLock(layers.length>0||enteringLayerCount>0||closingLayerCount>0)}function finishLayerEntry(layer){layer.entering&&(layer.entering=!1,layer.enterTimer!==null&&clearTimeout(layer.enterTimer),layer.enterTimer=null,layer.enterTransitionEnd&&(layer.animEl.removeEventListener("transitionend",layer.enterTransitionEnd),layer.enterTransitionEnd=null),enteringLayerCount=Math.max(enteringLayerCount-1,0),syncLayerInteractivity())}function animateIn(layer){let t=layer.animEl;if(t.style.transform=layer.overlay?"translateY(100%)":"translateX(100%)",t.offsetWidth,t.style.transition=`transform ${ANIM_MS}ms ease`,t.style.transform="translate(0px, 0px)",layer.mask&&(layer.mask.style.transition=`opacity ${ANIM_MS}ms ease`,layer.mask.style.opacity="1"),ANIM_MS<=0){finishLayerEntry(layer);return}layer.enterTransitionEnd=event=>{event.target===t&&event.propertyName==="transform"&&finishLayerEntry(layer)},t.addEventListener("transitionend",layer.enterTransitionEnd),layer.enterTimer=setTimeout(()=>finishLayerEntry(layer),ANIM_MS+60)}function animateOut(layer,done){let t=layer.animEl;if(ANIM_MS<=0){t.style.transform=layer.overlay?"translateY(100%)":"translateX(100%)",layer.mask&&(layer.mask.style.opacity="0"),setTimeout(done,0);return}let settled=!1,fallbackTimer=0,finish=()=>{settled||(settled=!0,t.removeEventListener("transitionend",onTransitionEnd),clearTimeout(fallbackTimer),done())},onTransitionEnd=event=>{event.target===t&&event.propertyName==="transform"&&finish()};t.addEventListener("transitionend",onTransitionEnd),t.style.transition=`transform ${ANIM_MS}ms ease`,t.style.transform=layer.overlay?"translateY(100%)":"translateX(100%)",layer.mask&&(layer.mask.style.opacity="0"),fallbackTimer=setTimeout(finish,ANIM_MS+60)}function startLayerNavigation(layer,target){startPreparedWebViewNavigation(layer.frame,target,()=>!layer.closing&&layer.el.isConnected,cleanup=>{layer.navigationPreparationCleanup=cleanup})}function setPageVisibility(target,hidden){if(target===window){links.getBridgeProtocol().handlePageVisibility(hidden);return}try{target.postMessage({source:SRC,type:"simulatorVisibility",hidden},"*")}catch{}}function openLayer(url2,callbackId,overlay,openerWin,pushHistory,popId=null,animateEntry=!0){clearPendingClose();let target=url2;if(!/^https?:/i.test(target)){let mapped=links.getBridgeProtocol().mapScheme(target);if(!mapped)return log2("open 失败,scheme 未映射:",url2),null;target=mapped}location.protocol==="https:"&&target.startsWith("http:")&&(target="https:"+target.slice(5));let presentation=overlay??resolveOverlayPresentation(target,void 0,!1);log2("open →",presentation?"(webdialog) ":"",target);let parts=createLayerEl(presentation,++layerSeq),restoredTitleBarState=explicitLayerTitleBarStates.get(titleBarStateCacheKey(target)),layer={id:layerSeq,win:parts.frame.contentWindow,frame:parts.frame,entryUrl:target,url:target,overlay:presentation,openerWin,callbackId,storageId:parseStorageId(target),popId,el:parts.el,animEl:parts.animEl,mask:parts.mask,entering:animateEntry,enterTimer:null,enterTransitionEnd:null,closing:!1,navigationPreparationCleanup:null,titleBarState:restoredTitleBarState??initialLayerTitleBarState(target),titleBarStateExplicit:restoredTitleBarState!==void 0,titleBarStateReady:restoredTitleBarState!==void 0,titleBarView:null};if(popId&&layer.el.setAttribute("data-mearl-pop-id",popId),layer.mask&&presentation?.tapClose&&layer.mask.addEventListener("click",()=>requestOverlayClose(layer)),!presentation&&simulateSystemBars&&config2.titleBar&&(layer.titleBarView=createSimulatedNavigationBarView("layer",()=>requestNativeBack()),layer.titleBarView.root.setAttribute("data-mearl-layer-titlebar",String(layer.id)),parts.el.appendChild(layer.titleBarView.root)),layers.push(layer),splitScreenActive&&rootFrame?.contentWindow===openerWin||setPageVisibility(openerWin,!0),animateEntry&&(enteringLayerCount+=1),syncLayerViewport(layer,layer.titleBarState),syncLayerInteractivity(),parts.frame.addEventListener("load",()=>{layer.win=parts.frame.contentWindow,parts.frame.name=LAYER_FRAME_NAME;let committedSrc=parts.frame.getAttribute("src");!committedSrc||committedSrc==="about:blank"||(syncSimulatorStateToWindow(parts.frame.contentWindow),requestAnimationFrame(()=>{layer.titleBarStateReady||layer.closing||!layer.el.isConnected||(layer.titleBarStateReady=!0,syncLayerViewport(layer,resolvedTitleBarState(layer)))}))}),(document.body??document.documentElement).appendChild(parts.el),layer.win=parts.frame.contentWindow,startLayerNavigation(layer,mapLayerFrameUrl(target)),animateEntry&&animateIn(layer),pushHistory){forwardStack.length=0;try{history.pushState({__mearl_layer__:layers.length},"",mapUrlForSync(target))}catch{}}return layer}function replaceLayer(sourceLayer,url2,callbackId,overlay,popId=null){if(sourceLayer.closing||layers[layers.length-1]!==sourceLayer){openLayer(url2,callbackId,overlay,sourceLayer.win??window,!0,popId);return}let replacement=openLayer(url2,callbackId,overlay,sourceLayer.openerWin,!1,popId);if(!replacement)return;sourceLayer.navigationPreparationCleanup?.(),sourceLayer.navigationPreparationCleanup=null,sourceLayer.entering&&(sourceLayer.entering=!1,enteringLayerCount=Math.max(enteringLayerCount-1,0),sourceLayer.enterTimer!==null&&clearTimeout(sourceLayer.enterTimer),sourceLayer.enterTransitionEnd&&sourceLayer.animEl.removeEventListener("transitionend",sourceLayer.enterTransitionEnd));let sourceIndex=layers.indexOf(sourceLayer);sourceIndex>=0&&layers.splice(sourceIndex,1),destroySimulatedNavigationBarView(sourceLayer.titleBarView),sourceLayer.el.remove(),forwardStack.length=0,syncLayerInteractivity(),syncActiveSystemBars();try{history.replaceState({__mearl_layer__:layers.length},"",mapUrlForSync(replacement.url))}catch{}}function closeLayer(layer,data,final,gotoEvent=!1,resumeOpener=!0,silent=!1,immediate=!1){if(layer.closing)return;layer.navigationPreparationCleanup?.(),layer.navigationPreparationCleanup=null,layer.entering&&(layer.entering=!1,enteringLayerCount=Math.max(enteringLayerCount-1,0),layer.enterTimer!==null&&clearTimeout(layer.enterTimer),layer.enterTimer=null,layer.enterTransitionEnd&&(layer.animEl.removeEventListener("transitionend",layer.enterTransitionEnd),layer.enterTransitionEnd=null)),layer.closing=!0;let idx=layers.indexOf(layer);idx>=0&&layers.splice(idx,1),closingLayerCount+=1,blockClosingLayerInteractions(layer),syncLayerInteractivity(),syncActiveSystemBars(),final?forwardStack.length=0:forwardStack.push({url:layer.url,overlay:layer.overlay,openerWin:layer.openerWin,callbackId:layer.callbackId,storageId:layer.storageId,popId:layer.popId}),log2("close ←",layer.url,data===void 0?"":data);let finishClose=()=>{if(destroySimulatedNavigationBarView(layer.titleBarView),layer.el.remove(),closingLayerCount=Math.max(closingLayerCount-1,0),syncLayerInteractivity(),syncActiveSystemBars(),!!resumeOpener)if(layer.openerWin===window)links.getBridgeProtocol().handleResume({data,storageId:layer.storageId,callbackId:layer.callbackId,final,gotoEvent,silent});else try{layer.openerWin.postMessage({source:SRC,type:"resume",data,storageId:layer.storageId,callbackId:layer.callbackId,final,gotoEvent,silent},"*")}catch{}};immediate?finishClose():animateOut(layer,finishClose)}function closeToDepth(depth,data,final){for(;layers.length>depth;){let revealsTarget=layers.length===depth+1;closeLayer(layers[layers.length-1],revealsTarget?data:void 0,final,!1,revealsTarget)}}function closeAllLayers(data,gotoEvent=!1,silent=!1,immediate=!1){let depth=layers.length;for(;layers.length>0;){let isRootmostLayer=layers.length===1;closeLayer(layers[layers.length-1],isRootmostLayer?data:void 0,!0,isRootmostLayer&&gotoEvent,isRootmostLayer,silent,immediate)}if(depth>0)try{history.go(-depth)}catch{}return depth>0}function openFromSplitRoot(url2,callbackId,overlay,openerWin,popId){if(pendingSplitRootOpen){pendingSplitRootOpen={url:url2,callbackId,overlay,openerWin,popId};return}if(layers.length===0){openLayer(url2,callbackId,overlay,openerWin,!0,popId);return}pendingSplitRootOpen={url:url2,callbackId,overlay,openerWin,popId},closeAllLayers(void 0,!1,!0,!0)}function finishPendingSplitRootOpen(){let pending=pendingSplitRootOpen;pending&&(pendingSplitRootOpen=null,openLayer(pending.url,pending.callbackId,pending.overlay,pending.openerWin,!0,pending.popId,!1))}function requestOverlayClose(layer){if(!(layer.closing||layers[layers.length-1]!==layer)){if(!config2.overlay?.silentTapClose){for(let selector of config2.overlay?.tapCloseSelectors??[])try{let control=layer.frame.contentDocument?.querySelector(selector);if(typeof control?.click!="function")continue;control.click();return}catch{}requestCloseOnTop(void 0);return}pendingClose||pendingHistoryDepth||(closeLayer(layer,void 0,!0,!1,!0,!0),syncHistoryAfterDirectClose())}}function forwardToDepth(depth){for(;layers.length<depth&&forwardStack.length>0;){let entry=forwardStack.pop();openLayer(entry.url,entry.callbackId,entry.overlay,entry.openerWin,!1,entry.popId)}}function requestCloseOnTop(data){if(layers.length===0){history.back();return}if(rootContainerActive){closeLayer(layers[layers.length-1],data,!0),syncHistoryAfterDirectClose();return}armPendingClose(data,8)}function isActiveBusinessWindow(target){let topLayer=layers[layers.length-1];return topLayer?topLayer.frame.contentWindow===target:rootFrame?rootFrame.contentWindow===target:target===window}function finishNativeBack(requestId,target,handled){pendingNativeBack?.requestId!==requestId||pendingNativeBack.target!==target||(clearPendingNativeBack(),!handled&&isActiveBusinessWindow(target)&&requestCloseOnTop(void 0))}function requestNativeBack(){if(!isTop||pendingNativeBack)return;let target=layers[layers.length-1]?.frame.contentWindow??rootFrame?.contentWindow??window;if(!target||target===window){links.getBridgeProtocol().handleNativeBack()||requestCloseOnTop(void 0);return}let requestId=++nativeBackRequestSeq,timer=setTimeout(()=>finishNativeBack(requestId,target,!1),120);pendingNativeBack={requestId,target,timer};try{target.postMessage({source:SRC,type:"nativeBack",requestId},"*")}catch{finishNativeBack(requestId,target,!1)}}function layerForWindow(source){if(source)for(let layer of layers){if(layer.win===source)return layer;let currentWindow=layer.frame.contentWindow;if(currentWindow&¤tWindow===source)return layer.win=currentWindow,layer}}if(isTop){if(!rootContainerActive){let rawPushState=history.pushState.bind(history),rawReplaceState=history.replaceState.bind(history),withDepth=state=>state==null?{__mearl_layer__:layers.length}:typeof state=="object"&&!Array.isArray(state)?{...state,__mearl_layer__:layers.length}:state;try{history.pushState=function(...args){rawPushState(withDepth(args[0]),args[1],args[2])},history.replaceState=function(...args){rawReplaceState(withDepth(args[0]),args[1],args[2])}}catch{}}try{readDepth(history.state)===null&&history.replaceState({__mearl_layer__:0},"")}catch{}window.addEventListener("popstate",e=>{let depth=readDepth(e.state);if(pendingSplitRootOpen&&depth===0){finishPendingSplitRootOpen();return}if(pendingHistoryDepth){let expectedDepth=pendingHistoryDepth.depth;if(clearPendingHistoryDepth(),depth===expectedDepth)return;console.warn(TAG,"浏览器历史深度与 WebView 出栈事务不一致",{expectedDepth,actualDepth:depth})}if(rootContainerActive){if(depth===null)return;depth<layers.length?closeToDepth(depth,void 0,!1):depth>layers.length&&forwardToDepth(depth);return}if(pendingClose){if(depth!==null&&depth<layers.length){let{data}=pendingClose;clearPendingClose(),closeToDepth(depth,data,!0)}else if(pendingClose.retries>0)armPendingClose(pendingClose.data,pendingClose.retries-1);else{let{data}=pendingClose;clearPendingClose(),closeToDepth(layers.length-1,data,!0)}return}depth!==null&&(depth<layers.length?closeToDepth(depth,void 0,!1):depth>layers.length&&forwardToDepth(depth))})}function broadcastAppMessage(message){links.getBridgeProtocol().handleAppMessage(message);let targets=[rootFrame?.contentWindow??null,...layers.filter(layer=>!layer.closing).map(layer=>layer.frame.contentWindow)];for(let target of targets)if(!(!target||target===window))try{target.postMessage({source:SRC,type:"appMessage",message},"*")}catch{}}function closeMegaPop(popId,data){let index=layers.findIndex(layer=>layer.popId===popId&&!layer.closing);if(index<0)return!1;let closingDepth=layers.length-index;closeToDepth(index,data,!0);try{history.go(-closingDepth)}catch{}return!0}function resizeMegaPop(popId,params){let layer=layers.find(candidate=>candidate.popId===popId&&!candidate.closing);if(!layer?.overlay)return!1;if(params.maxHeight!==void 0){let maxHeight=numberParam(params.maxHeight,1-layer.overlay.topRatio,0,1);layer.overlay.topRatio=1-maxHeight,layer.animEl.style.height=`${maxHeight*100}%`}if(params.maxWidth!==void 0){let maxWidth=numberParam(params.maxWidth,1,0,1);layer.overlay.widthRatio=maxWidth,layer.animEl.style.width=`${maxWidth*100}%`,layer.animEl.style.left=`${(1-maxWidth)/2*100}%`,layer.animEl.style.right="auto"}return params.animated===!0&&(layer.animEl.style.transition="height 200ms ease, width 200ms ease, left 200ms ease"),!0}function executeContainerData(action,params){if(action==="sharedFileRead"||action==="sharedFileWrite"){let fileName=typeof params.fileName=="string"?params.fileName:"";if(!fileName)return{success:!1,value:"missing fileName"};if(action==="sharedFileRead")return{success:!0,value:{data:sharedFiles.get(fileName)??""}};let data=typeof params.data=="string"?params.data:String(params.data??"");return sharedFiles.set(fileName,data),{success:!0,value:{}}}if(action==="sharedDataGet"){let keys=Array.isArray(params.keys)?params.keys.filter(key=>typeof key=="string"):[],data={};for(let key of keys)sharedData.has(key)&&(data[key]=sharedData.get(key));return{success:!0,value:{data}}}if(action==="sharedDataSet"){if(!params.data||typeof params.data!="object"||Array.isArray(params.data))return{success:!1,value:"missing shared data"};for(let[key,value]of Object.entries(params.data))value==null?sharedData.delete(key):sharedData.set(key,value);return{success:!0,value:{}}}if(action==="megaBroadcast")return!params.message||typeof params.message!="object"||Array.isArray(params.message)?{success:!1,value:"missing broadcast message"}:(broadcastAppMessage(params.message),{success:!0,value:{}});if(action==="megaKVSnapshot")return{success:!0,value:{entries:megaKVSnapshot()}};if(action==="megaKVMutation"){let operation=typeof params.operation=="string"?params.operation:"",bizId=typeof params.bizId=="string"?params.bizId:"";if(!bizId)return{success:!1,value:"missing bizID"};let key=typeof params.key=="string"?params.key:"";if((operation==="set"||operation==="remove")&&!key)return{success:!1,value:"missing key"};if(operation==="set"){if(typeof params.value!="string")return{success:!1,value:"missing value"};let entries=megaKVStorage.get(bizId)??new Map;entries.set(key,params.value),megaKVStorage.set(bizId,entries)}else if(operation==="remove"){let entries=megaKVStorage.get(bizId);entries?.delete(key),entries?.size===0&&megaKVStorage.delete(bizId)}else if(operation==="clear")megaKVStorage.delete(bizId);else return{success:!1,value:"unsupported KVStorage operation"};return persistMegaKVStorage(),broadcastAppMessage({kind:"megaKVStorage",operation,bizId,key,value:params.value}),{success:!0,value:{}}}if(action==="legacyBroadcastCreate"){let instanceId=typeof params.instanceId=="string"?params.instanceId:"";return instanceId?(legacyBroadcastChannels.add(instanceId),{success:!0,value:{}}):{success:!1,value:"missing instanceId"}}if(action==="legacyBroadcastPost"){let instanceId=typeof params.instanceId=="string"?params.instanceId:"";return instanceId?legacyBroadcastChannels.has(instanceId)?(broadcastAppMessage({kind:"legacyBroadcast",instanceId,message:params.message}),{success:!0,value:{}}):{success:!1,value:"broadcast channel not found"}:{success:!1,value:"missing instanceId"}}if(action==="legacyBroadcastClose"){let instanceId=typeof params.instanceId=="string"?params.instanceId:"";return instanceId?(legacyBroadcastChannels.delete(instanceId),{success:!0,value:{}}):{success:!1,value:"missing instanceId"}}if(action==="megaPopClose"){let popId=typeof params.popId=="string"?params.popId:"";return popId?closeMegaPop(popId,params.result)?{success:!0,value:{}}:{success:!1,value:"popId not found"}:{success:!1,value:"missing popId"}}if(action==="megaPopResize"){let popId=typeof params.popId=="string"?params.popId:"";return popId?resizeMegaPop(popId,params)?{success:!0,value:{}}:{success:!1,value:"popId not found"}:{success:!1,value:"missing popId"}}return{success:!1,value:"unsupported container data action"}}function requestContainerData(action,params,onSuccess,onFailure){if(isTop){let result=executeContainerData(action,params);setTimeout(()=>result.success?onSuccess(result.value):onFailure(result.value),0);return}let requestId=++containerDataRequestSeq;containerDataCallbacks.set(requestId,{success:onSuccess,failure:onFailure});try{window.top?.postMessage({source:SRC,type:"containerDataRequest",requestId,action,params},"*")}catch(error48){containerDataCallbacks.delete(requestId),onFailure(error48 instanceof Error?error48.message:String(error48))}}function requestOpen(url2,callbackId,webdialog,params){let overlay=resolveOverlayPresentation(url2,params,webdialog),popBeforeOpen=requestsPopBeforeOpen(url2,params),popId=typeof params?.__mearlMegaPopId=="string"?params.__mearlMegaPopId:null;isTop?openLayer(url2,callbackId,overlay,window,!0,popId):window.top?.postMessage({source:SRC,type:"open",url:url2,callbackId,overlay,popBeforeOpen,popId},"*")}function requestClose(data){let payload;try{payload=data===void 0?void 0:JSON.parse(JSON.stringify(data))}catch{payload=void 0}isTop?requestCloseOnTop(payload):window.top?.postMessage({source:SRC,type:"close",data:payload},"*")}if(window.addEventListener("message",event=>{let msg=event.data;if(!(!msg||typeof msg!="object")){if(msg.source==="mearl-content"&&(msg.type==="APP_BRIDGE_SIMULATOR_VISIBILITY"||msg.type==="APP_BRIDGE_RUNTIME_RESPONSES")){if(!isTop||event.source!==window)return;if(msg.type==="APP_BRIDGE_SIMULATOR_VISIBILITY"&&typeof msg.hidden=="boolean"){simulatedPageHidden=msg.hidden,links.getBridgeProtocol().handlePageVisibility(msg.hidden);let lifecycleMessage={source:SRC,type:"simulatorVisibility",hidden:msg.hidden};rootFrame?.contentWindow?.postMessage(lifecycleMessage,"*");for(let layer of layers)layer.closing||layer.frame.contentWindow?.postMessage(lifecycleMessage,"*")}else if(msg.type==="APP_BRIDGE_RUNTIME_RESPONSES"&&msg.profile===config2.profile&&msg.responses&&typeof msg.responses=="object"&&!Array.isArray(msg.responses)){let responses=msg.responses;runtimeResponses={...runtimeResponses??{},...responses},links.getBridgeProtocol().applyRuntimeResponses(responses);let configMessage={source:SRC,type:"runtimeResponses",profile:config2.profile,responses};rootFrame?.contentWindow?.postMessage(configMessage,"*");for(let layer of layers)layer.closing||layer.frame.contentWindow?.postMessage(configMessage,"*")}return}if(msg.source===SRC){if(isTop){let sourceLayer=layerForWindow(event.source),sourceIsRoot=!!(rootFrame?.contentWindow&&rootFrame.contentWindow===event.source);if(!sourceLayer&&!sourceIsRoot)return;if(msg.type==="open"&&typeof msg.url=="string"){let rawOverlay=msg.overlay&&typeof msg.overlay=="object"?msg.overlay:void 0,overlay=rawOverlay?{topRatio:numberParam(rawOverlay.topRatio,.2,0,1),widthRatio:numberParam(rawOverlay.widthRatio,1,0,1),radius:numberParam(rawOverlay.radius,0,0,50),maskAlpha:numberParam(rawOverlay.maskAlpha,.3,0,1),tapClose:boolParam(rawOverlay.tapClose,!0)}:resolveOverlayPresentation(msg.url,void 0,!1),callbackId=typeof msg.callbackId=="number"?msg.callbackId:0,popId=typeof msg.popId=="string"&&msg.popId?msg.popId:null;splitScreenActive&&sourceIsRoot?openFromSplitRoot(msg.url,callbackId,overlay,event.source??window,popId):msg.popBeforeOpen===!0&&sourceLayer?replaceLayer(sourceLayer,msg.url,callbackId,overlay,popId):openLayer(msg.url,callbackId,overlay,event.source??window,!0,popId)}else if(msg.type==="close")requestCloseOnTop(msg.data);else if(msg.type==="closeAll"){let gotoEvent=msg.gotoEvent===!0;if(gotoEvent&&sourceIsRoot&&layers.length===0&&msg.data!==void 0)try{event.source.postMessage({source:SRC,type:"resume",data:msg.data,storageId:null,callbackId:0,final:!0,gotoEvent:!0},"*")}catch{}else closeAllLayers(msg.data,gotoEvent)}else if(msg.type==="appMessageToOpener"&&sourceLayer){let target=sourceLayer.openerWin;if(target===window)links.getBridgeProtocol().handleAppMessage(msg.message);else try{target.postMessage({source:SRC,type:"appMessage",message:msg.message},"*")}catch{}}else if(msg.type==="containerDataRequest"&&typeof msg.requestId=="number"&&typeof msg.action=="string"&&msg.params&&typeof msg.params=="object"&&!Array.isArray(msg.params)&&event.source){let result=executeContainerData(msg.action,msg.params);try{event.source.postMessage({source:SRC,type:"containerDataResponse",requestId:msg.requestId,success:result.success,value:result.value},"*")}catch{}}else if(msg.type==="nativeBackResult"&&typeof msg.requestId=="number"&&typeof msg.handled=="boolean"&&event.source)finishNativeBack(msg.requestId,event.source,msg.handled);else if(msg.type==="urlChanged"&&typeof msg.url=="string"){let topLayer=layers[layers.length-1];if(sourceIsRoot&&!topLayer){rootBusinessUrl=msg.url;let mapped=mapUrlForSync(msg.url);if(mapped)try{history.replaceState({__mearl_layer__:0},"",mapped)}catch{}}else if(topLayer&&!topLayer.closing&&sourceLayer===topLayer){topLayer.url=msg.url,topLayer.titleBarStateExplicit&&topLayer.titleBarState&&cacheExplicitTitleBarState(topLayer,topLayer.titleBarState);let mapped=mapUrlForSync(msg.url);if(mapped)try{history.replaceState({__mearl_layer__:layers.length},"",mapped)}catch{}}}else if(msg.type==="title"&&typeof msg.title=="string"){let topLayer=layers[layers.length-1];if(sourceIsRoot&&!topLayer)try{document.title=msg.title,syncSimulatedTitleBar()}catch{}else if(topLayer&&sourceLayer===topLayer){document.title=msg.title;let state=resolvedTitleBarState(topLayer);topLayer.titleBarState={...state,title:msg.title},syncLayerViewport(topLayer,topLayer.titleBarState)}}else if(msg.type==="titleBarState"){let state=parseReportedTitleBarState(msg.state);if(state&&sourceIsRoot)links.getSystemBars().setPresentedRootTitleBarState(state);else if(state&&sourceLayer){let explicit=msg.explicit===!0;sourceLayer.titleBarStateReady=!0,explicit?(sourceLayer.titleBarState=state,sourceLayer.titleBarStateExplicit=!0,cacheExplicitTitleBarState(sourceLayer,state)):sourceLayer.titleBarStateExplicit||(sourceLayer.titleBarState=state);let resolvedState=sourceLayer.titleBarState??state;syncLayerViewport(sourceLayer,resolvedState)}}}else if(msg.type==="requestTitleBarState"){if(event.source!==window.top)return;syncSimulatedTitleBar()}else if(msg.type==="simulatorVisibility"&&typeof msg.hidden=="boolean"){if(event.source!==window.top)return;links.getBridgeProtocol().handlePageVisibility(msg.hidden)}else if(msg.type==="appMessage"){if(event.source!==window.top)return;links.getBridgeProtocol().handleAppMessage(msg.message)}else if(msg.type==="nativeBack"&&typeof msg.requestId=="number"){if(event.source!==window.top)return;let handled=links.getBridgeProtocol().handleNativeBack();window.top?.postMessage({source:SRC,type:"nativeBackResult",requestId:msg.requestId,handled},"*")}else if(msg.type==="containerDataResponse"&&typeof msg.requestId=="number"){if(event.source!==window.top)return;let callback=containerDataCallbacks.get(msg.requestId);if(!callback)return;containerDataCallbacks.delete(msg.requestId),msg.success===!0?callback.success(msg.value):callback.failure(msg.value)}else if(msg.type==="runtimeResponses"&&msg.profile===config2.profile&&msg.responses&&typeof msg.responses=="object"&&!Array.isArray(msg.responses)){if(event.source!==window.top)return;links.getBridgeProtocol().applyRuntimeResponses(msg.responses)}else if(msg.type==="resume"){if(event.source!==window.top)return;links.getBridgeProtocol().handleResume({data:msg.data,storageId:msg.storageId??null,callbackId:typeof msg.callbackId=="number"?msg.callbackId:0,final:msg.final===!0,gotoEvent:msg.gotoEvent===!0,silent:msg.silent===!0})}else event.source!==window.top&&window.top?.postMessage(msg,"*");return}pageTransport.handleMessage(msg)}}),!isTop&&isContainerFrame){let reportUrl=()=>{try{window.top?.postMessage({source:SRC,type:"urlChanged",url:restoreLayerBusinessUrl(location.href)},"*")}catch{}};try{let origPushState=history.pushState.bind(history),origReplaceState=history.replaceState.bind(history);history.pushState=function(...args){origPushState(...args),reportUrl()},history.replaceState=function(...args){origReplaceState(...args),reportUrl()},window.addEventListener("popstate",reportUrl),window.addEventListener("hashchange",reportUrl)}catch{}}if(isContainerFrame){let requestProxyLocationOpen=url2=>{if(links.getBridgeProtocol().handleMaybeScheme(url2))return!0;try{let current=new URL(restoreLayerBusinessUrl(location.href)),target=new URL(url2,current);return!/^https?:$/.test(target.protocol)||target.origin===current.origin&&target.pathname===current.pathname&&target.search===current.search?!1:(requestOpen(target.href,0,!1),!0)}catch{return!1}};Object.defineProperty(window,"__PROXY_LOCATION__",{value:{get href(){return location.href},set href(url2){requestProxyLocationOpen(url2)||(location.href=mapLayerFrameUrl(url2))},replace(url2){links.getBridgeProtocol().handleMaybeScheme(url2)||location.replace(mapLayerFrameUrl(url2))},assign(url2){requestProxyLocationOpen(url2)||location.assign(mapLayerFrameUrl(url2))}},writable:!1,configurable:!0})}if(isContainerFrame){document.addEventListener("click",event=>{let el=event.target;for(;el&&el.tagName!=="A";)el=el.parentElement;if(!el)return;let href=el.getAttribute("href");if(href){if(links.getBridgeProtocol().handleMaybeScheme(href)){event.preventDefault(),event.stopPropagation();return}/^https?:/i.test(href)&&el.getAttribute("target")==="_blank"&&(event.preventDefault(),event.stopPropagation(),requestOpen(href,0,!1))}},!0);let origOpen=window.open;window.open=function(url2,target,features){let urlStr=typeof url2=="string"?url2:url2 instanceof URL?url2.href:"";return links.getBridgeProtocol().handleMaybeScheme(urlStr)?null:/^https?:/i.test(urlStr)?(requestOpen(urlStr,0,!1),null):origOpen?origOpen.call(window,url2,target,features):null};try{let proto=Location.prototype,origAssign=proto.assign,origReplace=proto.replace;origAssign&&(proto.assign=function(url2){if(links.getBridgeProtocol().handleMaybeScheme(url2))return;let upgraded=location.protocol==="https:"&&url2.startsWith("http:")?"https:"+url2.slice(5):url2;origAssign.call(this,upgraded)}),origReplace&&(proto.replace=function(url2){if(links.getBridgeProtocol().handleMaybeScheme(url2))return;let upgraded=location.protocol==="https:"&&url2.startsWith("http:")?"https:"+url2.slice(5):url2;origReplace.call(this,upgraded)})}catch{}}return log2("容器环境已就绪",isTop?"(top)":isRootFrame?"(root)":isLayerFrame?"(layer)":"(iframe,仅桥)"),{getRootFrame:()=>rootFrame,getLayers:()=>layers,getClosingLayerCount:()=>closingLayerCount,requestOpen,requestClose,requestNativeBack,requestContainerData,closeAllLayers}}var APP_PROFILE_RUNTIME_FACTORIES={environment:installAppProfileEnvironment,containerStack:installAppProfileContainerStack,bridgeProtocol:installAppProfileBridgeProtocol,pageTransport:installAppProfilePageTransport,systemBars:installAppProfileSystemBars};function buildAppProfileRuntimeCallSource(configExpression){return`(${installAppProfileRuntime.toString()})(${configExpression},{environment:${installAppProfileEnvironment.toString()},pageTransport:${installAppProfilePageTransport.toString()},containerStack:${installAppProfileContainerStack.toString()},systemBars:${installAppProfileSystemBars.toString()},bridgeProtocol:${installAppProfileBridgeProtocol.toString()}})`}function installAppProfileRuntime(config2,factories=APP_PROFILE_RUNTIME_FACTORIES){let environment=factories.environment(config2);if(!environment)return;let pageTransport=factories.pageTransport(config2,environment),containerStack=factories.containerStack(config2,environment,{pageTransport,getSystemBars:()=>systemBars,getBridgeProtocol:()=>bridgeProtocol}),systemBars=factories.systemBars(config2,environment,{getRootFrame:containerStack.getRootFrame,getLayers:containerStack.getLayers,getClosingLayerCount:containerStack.getClosingLayerCount,requestClose:containerStack.requestClose,requestNativeBack:containerStack.requestNativeBack}),bridgeProtocol=factories.bridgeProtocol(config2,environment,{pageTransport,systemBars,requestOpen:containerStack.requestOpen,requestClose:containerStack.requestClose,requestCloseAll:containerStack.closeAllLayers,requestContainerData:containerStack.requestContainerData})}import https from"node:https";import http3 from"node:http";var TYPE_INTO_ELEMENT_SRC=typeIntoElement.toString(),CLICK_ELEMENT_VIA_JS_SRC=clickElementViaJS.toString(),GET_CLICK_COORDS_FROM_NODE_SRC=getClickCoordsFromNode.toString();async function readCdpCurrentUrl(session,action){let url2=(await session.client.sendCommand("Runtime.evaluate",{expression:"location.href",returnByValue:!0})).result?.value;if(typeof url2!="string"||!url2)throw new Error(`${action}: could not read the current page URL`);return session.url=url2,url2}function nodeFetch(urlStr,options={}){return new Promise((resolve2,reject)=>{let url2=new URL(urlStr),isHttps=url2.protocol==="https:",lib=isHttps?https:http3,{method="GET",headers={},body,timeoutMs=3e4}=options,req=lib.request({host:url2.hostname,port:url2.port||(isHttps?443:80),path:url2.pathname+url2.search,method,headers},res=>{let responseHeaders={};for(let[key,value]of Object.entries(res.headers))typeof value=="string"?responseHeaders[key]=value:Array.isArray(value)&&(responseHeaders[key]=value.join(", "));let chunks=[];res.on("data",chunk=>chunks.push(Buffer.from(chunk))),res.on("end",()=>{let bodyBuffer=Buffer.concat(chunks);resolve2({status:res.statusCode??0,statusText:res.statusMessage??"",headers:responseHeaders,body:bodyBuffer.toString("utf-8"),bodyBuffer})})});req.on("error",reject),req.setTimeout(timeoutMs,()=>{req.destroy(),reject(new Error(`Request timeout: ${urlStr}`))}),body&&req.write(body),req.end()})}async function getCookiesForUrl(session,targetUrl){let result=await session.client.sendCommand("Network.getCookies",{urls:[targetUrl]}),map2=new Map;for(let cookie of result.cookies??[])map2.set(cookie.name,cookie.value);return map2}async function waitForPageLoad(session,timeoutMs){if(isCdpDeviceShellActive(session)){let deadline=Date.now()+timeoutMs;for(;Date.now()<deadline;){if((await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:"document.readyState",returnByValue:!0}).catch(()=>null))?.result?.value==="complete")return;await new Promise(resolve2=>setTimeout(resolve2,50))}throw new Error(`Page load timeout after ${timeoutMs}ms`)}return new Promise((resolve2,reject)=>{let settled=!1,removeLoadListener=()=>{},finish=error48=>{settled||(settled=!0,clearTimeout(timer),removeLoadListener(),error48?reject(error48):resolve2())},timer=setTimeout(()=>{finish(new Error(`Page load timeout after ${timeoutMs}ms`))},timeoutMs);removeLoadListener=session.client.on("Page.loadEventFired",()=>finish()),session.client.sendCommand("Runtime.evaluate",{expression:"document.readyState",returnByValue:!0}).then(result=>{result.result?.value==="complete"&&finish()}).catch(()=>{})})}async function getPageViewportSize(session){let result=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`({
|
|
626
626
|
width: window.visualViewport ? window.visualViewport.width : window.innerWidth,
|
|
627
627
|
height: window.visualViewport ? window.visualViewport.height : window.innerHeight
|
|
628
|
-
})`,returnByValue:!0}),width=result.result?.value?.width,height=result.result?.value?.height;return typeof width!="number"||typeof height!="number"||width<=0||height<=0?null:{width,height}}async function getCdpInputViewportSize(session){let metrics;try{metrics=await session.client.sendCommand("Page.getLayoutMetrics",{})}catch{return null}let viewport=metrics.cssVisualViewport??metrics.visualViewport??metrics.cssLayoutViewport??metrics.layoutViewport,width=viewport?.clientWidth,height=viewport?.clientHeight;return typeof width!="number"||typeof height!="number"||width<=0||height<=0?null:{width,height}}async function toCdpInputPoint(session,x,y){if(isCdpDeviceShellActive(session)){let offset=getCdpDeviceShellInputOffset(session);return{x:x+offset.x,y:y+offset.y}}let[pageViewport,cdpViewport]=await Promise.all([getPageViewportSize(session),getCdpInputViewportSize(session)]);if(!pageViewport||!cdpViewport)return{x,y};let scaleX=cdpViewport.width/pageViewport.width,scaleY=cdpViewport.height/pageViewport.height;return!Number.isFinite(scaleX)||!Number.isFinite(scaleY)||scaleX<=0||scaleY<=0||Math.abs(scaleX-1)<.01&&Math.abs(scaleY-1)<.01?{x,y}:{x:x*scaleX,y:y*scaleY}}async function dispatchCdpClick(session,x,y,pointerType){let point=await toCdpInputPoint(session,x,y);if(pointerType==="touch"){await sendCdpInputCommand(session,"Input.dispatchTouchEvent",{type:"touchStart",touchPoints:[point]}),await sendCdpInputCommand(session,"Input.dispatchTouchEvent",{type:"touchEnd",touchPoints:[]});return}await sendCdpInputCommand(session,"Input.dispatchMouseEvent",{type:"mouseMoved",x:point.x,y:point.y}),await sendCdpInputCommand(session,"Input.dispatchMouseEvent",{type:"mousePressed",x:point.x,y:point.y,button:"left",buttons:1,clickCount:1}),await sendCdpInputCommand(session,"Input.dispatchMouseEvent",{type:"mouseReleased",x:point.x,y:point.y,button:"left",buttons:0,clickCount:1})}async function dispatchCdpDrag(session,from,to,pointerType,durationMs){let[start,end]=await Promise.all([toCdpInputPoint(session,from.x,from.y),toCdpInputPoint(session,to.x,to.y)]),path19=buildPageDragPath(start,end,durationMs),waitForNextPoint=async()=>{path19.intervalMs<=0||await new Promise(resolve2=>setTimeout(resolve2,path19.intervalMs))};if(pointerType==="touch"){await sendCdpInputCommand(session,"Input.dispatchTouchEvent",{type:"touchStart",touchPoints:[start]});let primaryError2;try{for(let point of path19.points)await waitForNextPoint(),await sendCdpInputCommand(session,"Input.dispatchTouchEvent",{type:"touchMove",touchPoints:[point]})}catch(error48){throw primaryError2=error48,error48}finally{await sendCdpInputCommand(session,"Input.dispatchTouchEvent",{type:"touchEnd",touchPoints:[]}).catch(error48=>{if(primaryError2===void 0)throw error48})}return{steps:path19.points.length}}await sendCdpInputCommand(session,"Input.dispatchMouseEvent",{type:"mouseMoved",x:start.x,y:start.y}),await sendCdpInputCommand(session,"Input.dispatchMouseEvent",{type:"mousePressed",x:start.x,y:start.y,button:"left",buttons:1,clickCount:1});let primaryError;try{for(let point of path19.points)await waitForNextPoint(),await sendCdpInputCommand(session,"Input.dispatchMouseEvent",{type:"mouseMoved",x:point.x,y:point.y,button:"left",buttons:1})}catch(error48){throw primaryError=error48,error48}finally{await sendCdpInputCommand(session,"Input.dispatchMouseEvent",{type:"mouseReleased",x:end.x,y:end.y,button:"left",buttons:0,clickCount:1}).catch(error48=>{if(primaryError===void 0)throw error48})}return{steps:path19.points.length}}async function sendCdpInputCommand(session,method,params){try{await session.client.sendCommand(method,params,1e4)}catch(error48){if(error48 instanceof Error&&error48.message===`CDP command timeout: ${method}`){let eventType=typeof params.type=="string"?` (${params.type})`:"";throw new Error(`CDP ${method}${eventType} timed out after ${1e4}ms. The page may already have changed; verify its current state before retrying
|
|
628
|
+
})`,returnByValue:!0}),width=result.result?.value?.width,height=result.result?.value?.height;return typeof width!="number"||typeof height!="number"||width<=0||height<=0?null:{width,height}}async function getCdpInputViewportSize(session){let metrics;try{metrics=await session.client.sendCommand("Page.getLayoutMetrics",{})}catch{return null}let viewport=metrics.cssVisualViewport??metrics.visualViewport??metrics.cssLayoutViewport??metrics.layoutViewport,width=viewport?.clientWidth,height=viewport?.clientHeight;return typeof width!="number"||typeof height!="number"||width<=0||height<=0?null:{width,height}}async function toCdpInputPoint(session,x,y){if(isCdpDeviceShellActive(session)){let offset=await getCdpDeviceShellInputOffset(session);return{x:x+offset.x,y:y+offset.y}}let[pageViewport,cdpViewport]=await Promise.all([getPageViewportSize(session),getCdpInputViewportSize(session)]);if(!pageViewport||!cdpViewport)return{x,y};let scaleX=cdpViewport.width/pageViewport.width,scaleY=cdpViewport.height/pageViewport.height;return!Number.isFinite(scaleX)||!Number.isFinite(scaleY)||scaleX<=0||scaleY<=0||Math.abs(scaleX-1)<.01&&Math.abs(scaleY-1)<.01?{x,y}:{x:x*scaleX,y:y*scaleY}}async function dispatchCdpClick(session,x,y,pointerType){let point=await toCdpInputPoint(session,x,y);if(pointerType==="touch"){await sendCdpInputCommand(session,"Input.dispatchTouchEvent",{type:"touchStart",touchPoints:[point]}),await sendCdpInputCommand(session,"Input.dispatchTouchEvent",{type:"touchEnd",touchPoints:[]});return}await sendCdpInputCommand(session,"Input.dispatchMouseEvent",{type:"mouseMoved",x:point.x,y:point.y}),await sendCdpInputCommand(session,"Input.dispatchMouseEvent",{type:"mousePressed",x:point.x,y:point.y,button:"left",buttons:1,clickCount:1}),await sendCdpInputCommand(session,"Input.dispatchMouseEvent",{type:"mouseReleased",x:point.x,y:point.y,button:"left",buttons:0,clickCount:1})}async function dispatchCdpDrag(session,from,to,pointerType,durationMs){let[start,end]=await Promise.all([toCdpInputPoint(session,from.x,from.y),toCdpInputPoint(session,to.x,to.y)]),path19=buildPageDragPath(start,end,durationMs),waitForNextPoint=async()=>{path19.intervalMs<=0||await new Promise(resolve2=>setTimeout(resolve2,path19.intervalMs))};if(pointerType==="touch"){await sendCdpInputCommand(session,"Input.dispatchTouchEvent",{type:"touchStart",touchPoints:[start]});let primaryError2;try{for(let point of path19.points)await waitForNextPoint(),await sendCdpInputCommand(session,"Input.dispatchTouchEvent",{type:"touchMove",touchPoints:[point]})}catch(error48){throw primaryError2=error48,error48}finally{await sendCdpInputCommand(session,"Input.dispatchTouchEvent",{type:"touchEnd",touchPoints:[]}).catch(error48=>{if(primaryError2===void 0)throw error48})}return{steps:path19.points.length}}await sendCdpInputCommand(session,"Input.dispatchMouseEvent",{type:"mouseMoved",x:start.x,y:start.y}),await sendCdpInputCommand(session,"Input.dispatchMouseEvent",{type:"mousePressed",x:start.x,y:start.y,button:"left",buttons:1,clickCount:1});let primaryError;try{for(let point of path19.points)await waitForNextPoint(),await sendCdpInputCommand(session,"Input.dispatchMouseEvent",{type:"mouseMoved",x:point.x,y:point.y,button:"left",buttons:1})}catch(error48){throw primaryError=error48,error48}finally{await sendCdpInputCommand(session,"Input.dispatchMouseEvent",{type:"mouseReleased",x:end.x,y:end.y,button:"left",buttons:0,clickCount:1}).catch(error48=>{if(primaryError===void 0)throw error48})}return{steps:path19.points.length}}async function sendCdpInputCommand(session,method,params){try{await session.client.sendCommand(method,params,1e4)}catch(error48){if(error48 instanceof Error&&error48.message===`CDP command timeout: ${method}`){let eventType=typeof params.type=="string"?` (${params.type})`:"",targetHint=method==="Input.dispatchTouchEvent"?'Touch input can stall on a hidden, background, or headless target; use clickMode "auto" or make the target visible. ':"";throw new Error(`CDP ${method}${eventType} timed out after ${1e4}ms. `+targetHint+"The page may already have changed; verify its current state before retrying.",{cause:error48})}throw error48}}async function resolveBackendNodeObjectId(session,backendNodeId){let objectId=(await sendCdpDeviceShellPageCommand(session,"DOM.resolveNode",{backendNodeId})).object?.objectId;if(!objectId)throw new Error(`Cannot resolve element for backendNodeId ${backendNodeId}`);return objectId}var SCREENSHOT_HIDDEN_DISPLAY_PROPERTIES=["--mearl-side-panel-toggle-display","--mearl-device-cutout-display"],screenshotQueueTails=new WeakMap;async function runScreenshotExclusive(session,operation){let previous=screenshotQueueTails.get(session)??Promise.resolve(),unlock,tail=new Promise(resolve2=>{unlock=resolve2});screenshotQueueTails.set(session,tail),await previous;try{return await operation()}finally{unlock(),screenshotQueueTails.get(session)===tail&&screenshotQueueTails.delete(session)}}async function hideScreenshotArtifacts(session){return(await session.client.sendCommand("Runtime.evaluate",{expression:`
|
|
629
629
|
(() => {
|
|
630
630
|
const root = document.documentElement;
|
|
631
631
|
if (!root) return [];
|
|
@@ -663,7 +663,7 @@ ${SOURCE_BADGES[source]}
|
|
|
663
663
|
height: r.height,
|
|
664
664
|
devicePixelRatio: window.devicePixelRatio || 1
|
|
665
665
|
};
|
|
666
|
-
})()`,returnByValue:!0})).result?.value;if(!rect||rect.error)throw new Error(rect?.error??`Element not found: ${selector}`);if(rect.width<=0||rect.height<=0)throw new Error(`Element matched by "${selector}" has no visible size`);let offset=getCdpDeviceShellInputOffset(session);params.clip={x:rect.x+offset.x,y:rect.y+offset.y,width:rect.width,height:rect.height,scale:rect.devicePixelRatio};let base64Data2=(await session.client.sendCommand("Page.captureScreenshot",params)).data,width2=Math.round(rect.width*rect.devicePixelRatio),height2=Math.round(rect.height*rect.devicePixelRatio);return{meta:{format,width:width2,height:height2,size:Math.ceil(base64Data2.length*3/4),url:info.url??"",title:info.title??""},data:base64Data2}}let base64Data=(await session.client.sendCommand("Page.captureScreenshot",params)).data,width=Math.round((info.w??1920)*(info.dpr??1)),height=Math.round((info.h??1080)*(info.dpr??1));return{meta:{format,width,height,size:Math.ceil(base64Data.length*3/4),url:info.url??"",title:info.title??""},data:base64Data}}async function cdpPageScreenshot(session,data){return runScreenshotExclusive(session,()=>withHiddenScreenshotArtifacts(session,()=>capturePageScreenshot(session,data)))}async function cdpPageSelectedElement(session,_data){return{element:(await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`(() => {
|
|
666
|
+
})()`,returnByValue:!0})).result?.value;if(!rect||rect.error)throw new Error(rect?.error??`Element not found: ${selector}`);if(rect.width<=0||rect.height<=0)throw new Error(`Element matched by "${selector}" has no visible size`);let offset=await getCdpDeviceShellInputOffset(session);params.clip={x:rect.x+offset.x,y:rect.y+offset.y,width:rect.width,height:rect.height,scale:rect.devicePixelRatio};let base64Data2=(await session.client.sendCommand("Page.captureScreenshot",params)).data,width2=Math.round(rect.width*rect.devicePixelRatio),height2=Math.round(rect.height*rect.devicePixelRatio);return{meta:{format,width:width2,height:height2,size:Math.ceil(base64Data2.length*3/4),url:info.url??"",title:info.title??""},data:base64Data2}}let base64Data=(await session.client.sendCommand("Page.captureScreenshot",params)).data,width=Math.round((info.w??1920)*(info.dpr??1)),height=Math.round((info.h??1080)*(info.dpr??1));return{meta:{format,width,height,size:Math.ceil(base64Data.length*3/4),url:info.url??"",title:info.title??""},data:base64Data}}async function cdpPageScreenshot(session,data){return runScreenshotExclusive(session,()=>withHiddenScreenshotArtifacts(session,()=>capturePageScreenshot(session,data)))}async function cdpPageSelectedElement(session,_data){return{element:(await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`(() => {
|
|
667
667
|
const el = document.activeElement;
|
|
668
668
|
if (!el || el === document.body) return null;
|
|
669
669
|
const rect = el.getBoundingClientRect();
|
|
@@ -688,7 +688,7 @@ Content-Type: ${file2.contentType}\r
|
|
|
688
688
|
\r
|
|
689
689
|
`),file2.content,Buffer.from(`\r
|
|
690
690
|
`))}return chunks.push(Buffer.from(`--${boundary}--\r
|
|
691
|
-
`)),{contentType:`multipart/form-data; boundary=${boundary}`,body:Buffer.concat(chunks)}}function hasMultipartPayload(data){return data.formData!==void 0||data.files!==void 0}async function executeNodeSendRequest(data,cookieMap=new Map){let{url:url2,method="GET",headers={},params,body,formData,files,responseType="auto",timeout=3e4}=data;if(!url2||typeof url2!="string"||url2.trim()==="")throw new Error("Invalid url: url must be a non-empty string");let normalizedMethod=method.toUpperCase();if(!ALLOWED_METHODS.has(normalizedMethod))throw new Error(`Invalid method: ${method}. Allowed: ${[...ALLOWED_METHODS].join(", ")}`);if(!Number.isFinite(timeout)||timeout<=0)throw new Error("timeout must be a positive number");let targetUrl=new URL(url2);for(let[key,value]of Object.entries(params??{}))targetUrl.searchParams.set(key,String(value));let requestHeaders={Accept:"application/json, text/plain, */*","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",...headers},resolvedSourceHeaders=getSendRequestSourceHeaders(targetUrl,headers);resolvedSourceHeaders.referer?setHeader(requestHeaders,"Referer",resolvedSourceHeaders.referer):removeHeader(requestHeaders,"Referer"),resolvedSourceHeaders.origin?setHeader(requestHeaders,"Origin",resolvedSourceHeaders.origin):removeHeader(requestHeaders,"Origin");let cookieHeader=[...cookieMap.entries()].map(([key,value])=>`${key}=${value}`).join("; ");cookieHeader&&setHeader(requestHeaders,"Cookie",cookieHeader);let xsrfToken=cookieMap.get("XSRF-TOKEN");xsrfToken&&!findSendRequestHeaderName(requestHeaders,"x-xsrf-token")&&setHeader(requestHeaders,"X-XSRF-TOKEN",xsrfToken);let requestBody;if(hasMultipartPayload(data)){if(body!=null)throw new Error("body cannot be combined with formData or files");if(normalizedMethod==="GET"||normalizedMethod==="HEAD")throw new Error(`${normalizedMethod} requests cannot use formData or files`);if(findSendRequestHeaderName(requestHeaders,"content-type"))throw new Error("Do not set Content-Type when using formData or files; Mearl sets the boundary");let multipart=await buildMultipartBody(formData,files);requestBody=multipart.body,setHeader(requestHeaders,"Content-Type",multipart.contentType),setHeader(requestHeaders,"Content-Length",String(multipart.body.byteLength))}else body!=null&&!["GET","HEAD"].includes(normalizedMethod)&&(typeof body=="string"?(requestBody=body,findSendRequestHeaderName(requestHeaders,"content-type")||setHeader(requestHeaders,"Content-Type","text/plain")):(requestBody=JSON.stringify(body),findSendRequestHeaderName(requestHeaders,"content-type")||setHeader(requestHeaders,"Content-Type","application/json")));let result=await nodeFetch(targetUrl.toString(),{method:normalizedMethod,headers:requestHeaders,body:requestBody,timeoutMs:timeout}),contentType=(result.headers["content-type"]??"").split(";")[0].trim().toLowerCase(),responseHeaders=Object.fromEntries(Object.entries(result.headers).filter(([name])=>name.toLowerCase()!=="set-cookie"&&name.toLowerCase()!=="set-cookie2")),responseBody,bodyType;if(responseType==="auto"&&isBinarySendRequestContentType(contentType))responseBody=result.bodyBuffer.toString("base64"),bodyType="base64";else{let trimmed=result.body.trimStart();if(responseType==="json"||responseType==="auto"&&contentType.includes("application/json")||responseType==="auto"&&(trimmed.startsWith("{")||trimmed.startsWith("[")))try{responseBody=JSON.parse(result.body),bodyType="json"}catch{if(responseType==="json")throw new Error("send_request expected a JSON response");responseBody=result.body,bodyType="text"}else responseBody=result.body,bodyType="text"}return{success:!0,status:result.status,statusText:result.statusText,headers:responseHeaders,body:responseBody,bodyType,attachedCookieCount:cookieMap.size}}async function cdpSendRequest(session,data){if(!data.url||typeof data.url!="string")throw new Error("Invalid url: url must be a non-empty string");let cookieMap=new Map;if(data.withCookies!==!1)try{cookieMap=await getCookiesForUrl(session,new URL(data.url).toString())}catch{}return executeNodeSendRequest(data,cookieMap)}async function prepareCdpMtopRequest(session,data,stream=!1){let resolved=resolveMtopRequest(data),cookieMap=await getCookiesForUrl(session,resolved.gatewayUrl.toString()),prepared=prepareSignedMtopRequest(resolved,cookieMap,stream);return{...prepared,requestHeaders:{...prepared.cookieHeader?{Cookie:prepared.cookieHeader}:{},...prepared.requestHeaders}}}async function cdpSendMtopRequest(session,data){let prepared=await prepareCdpMtopRequest(session,data),result=await nodeFetch(prepared.targetUrl.toString(),{method:prepared.normalizedMethod,headers:prepared.requestHeaders,body:prepared.body,timeoutMs:prepared.timeout});return{success:!0,response:parseMtopResponseText(result.body),requestData:prepared.requestData}}async function cdpSendMtopStreamRequest(session,data,callbacks){let prepared=await prepareCdpMtopRequest(session,data,!0),controller=new AbortController,timeoutId=setTimeout(()=>controller.abort(),prepared.timeout);try{await callbacks.onRequestPrepared?.({method:prepared.normalizedMethod,url:prepared.targetUrl.toString(),requestHeaders:Object.entries(prepared.requestHeaders).map(([name,value])=>({name,value}))});let response=await fetch(prepared.targetUrl,{method:prepared.normalizedMethod,headers:prepared.requestHeaders,body:prepared.body,signal:controller.signal}),responseHeaders=[];return response.headers.forEach((value,name)=>{name.toLowerCase()!=="set-cookie"&&responseHeaders.push({name,value})}),await callbacks.onResponse?.({status:response.status,statusText:response.statusText,responseHeaders}),{success:!0,response:await consumeMtopSseResponse(response,event=>callbacks.onReceive(event.data)),requestData:prepared.requestData}}catch(error48){throw error48 instanceof Error&&error48.name==="AbortError"?new Error(`send_mtop_stream timed out after ${prepared.timeout}ms: ${prepared.api}`,{cause:error48}):new Error(`send_mtop_stream failed: ${error48 instanceof Error?error48.message:String(error48)}`,{cause:error48})}finally{clearTimeout(timeoutId)}}registerActions([{name:"send_request",session:"page",handler:cdpSendRequest},{name:"send_mtop_request",session:"page",handler:cdpSendMtopRequest}]);var registries=new WeakMap;function getPageRefRegistry(session){let registry2=registries.get(session);if(!registry2){registry2=new BackendNodeRefRegistry,registries.set(session,registry2);let activeRegistry=registry2;session.client.on("Page.frameNavigated",params=>{params.frame?.parentId||activeRegistry.clearDocument()})}return registry2}function beginPageSnapshotRefs(session){return getPageRefRegistry(session).beginSnapshot()}function resolvePageRef(session,ref){return registries.get(session)?.resolve(ref)}function deletePageRef(session,ref){registries.get(session)?.delete(ref)}function clearPageRefsForNavigation(session){registries.get(session)?.clearDocument()}async function enrichCdpPageChangeSetWithRefs(session,observation){return enrichPageChangeSetWithRefs(observation,getPageRefRegistry(session),selectors=>resolveUniqueBackendNodeIds((method,params)=>sendCdpDeviceShellPageCommand(session,method,params),selectors),(node,backendNodeId)=>({backendNodeId,role:node.role??"",name:node.name??""}))}var APP_PROFILE_BINDING="__mearlCdpAppProfileRelay",appProfileStates=new WeakMap;function serializeForSource2(value){return JSON.stringify(value).replace(/[\u2028\u2029]/g,character=>character==="\u2028"?"\\u2028":"\\u2029")}function installCdpAppProfileRelay(bindingName){let browser=globalThis,target=globalThis;target.__mearlCdpAppProfileRelayInstalled__||(target.__mearlCdpAppProfileRelayInstalled__=!0,browser.addEventListener("message",event=>{if(event.source!==globalThis)return;let message=event.data;if(!message||message.source!=="mearl-app-bridge")return;let requestId=message.requestId;if(typeof requestId!="number")return;if(message.type==="prepareWebView"){browser.postMessage({source:"mearl-content",type:"APP_BRIDGE_PREPARE_WEBVIEW_RESPONSE",requestId,result:{success:!0}},"*");return}if(message.type!=="mtop"&&message.type!=="mtopStream"&&message.type!=="userInfo"&&message.type!=="screenshot")return;let binding=target[bindingName];if(typeof binding=="function")try{binding(JSON.stringify({type:message.type,requestId,payload:message.payload}))}catch{}}))}function installEarlyAppProfileEnvironment(config2){let browser=globalThis,target=globalThis;for(let[key,value]of Object.entries(config2.globals))try{target[key]=value}catch{}let insets=config2.safeAreaInsets??{top:config2.statusBarHeight,right:0,bottom:0,left:0};target.__STATUS_BAR_HEIGHT__=config2.statusBarHeight,target.__SAFE_AREA_INSET_BOTTOM__=insets.bottom;for(let[key,value]of[["userAgent",config2.userAgent],["platform",config2.navigatorPlatform],["vendor","Apple Computer, Inc."],["appVersion",config2.userAgent.replace(/^Mozilla\//,"")],["maxTouchPoints",config2.maxTouchPoints]])try{Object.defineProperty(browser.navigator,key,{configurable:!0,get:()=>value})}catch{}}function installWhenDocumentElementExists(install){let browser=globalThis;if(browser.document.documentElement){install();return}let observer=new browser.MutationObserver(()=>{browser.document.documentElement&&(observer.disconnect(),install())});observer.observe(browser.document,{childList:!0})}function buildDocumentSource(config2){return`;(() => {const config=${serializeForSource2(config2)};(${installCdpAppProfileRelay.toString()})(${JSON.stringify(APP_PROFILE_BINDING)});(${installEarlyAppProfileEnvironment.toString()})(config);(${installWhenDocumentElementExists.toString()})(() => {${buildAppProfileRuntimeCallSource("config")};});})();`}function appProfileEmulationCommands(config2,userAgent){return buildEnableEmulationCommands(config2).map(command=>command.method==="Emulation.setUserAgentOverride"?{...command,params:{userAgent,platform:config2.platform}}:command)}async function sendCommands(client2,commands){for(let{method,params,optional:optional2}of commands)await client2.sendCommand(method,params).catch(error48=>{if(!optional2)throw error48})}async function postRuntimeMessage(client2,executionContextId,message){await client2.sendCommand("Runtime.evaluate",{expression:`window.postMessage(${serializeForSource2(message)}, '*')`,...typeof executionContextId=="number"?{contextId:executionContextId}:{}})}function listenForBridgeRequests(session,client2,state){return client2.on("Runtime.bindingCalled",params=>{if(params?.name!==APP_PROFILE_BINDING||appProfileStates.get(session)!==state)return;let request;try{request=JSON.parse(params.payload)}catch{return}if(typeof request.requestId!="number")return;let requestId=request.requestId,contextId=typeof params.executionContextId=="number"?params.executionContextId:void 0,reply=message=>postRuntimeMessage(client2,contextId,{requestId,source:"mearl-content",...message});(async()=>{if(request.type==="screenshot"){if(client2!==session.client)return;try{let result=await cdpPageScreenshot(session,{format:"png"});await reply({type:"APP_BRIDGE_SCREENSHOT_RESPONSE",result:{success:!0,...result}})}catch(error48){await reply({type:"APP_BRIDGE_SCREENSHOT_RESPONSE",result:{success:!1,error:error48 instanceof Error?error48.message:String(error48)}})}return}if(request.type==="userInfo"){try{let result=await session.client.sendCommand("Network.getCookies",{urls:[session.url]}),response=resolveAppProfileUserInfo(session.url,(result.cookies??[]).map(cookie=>({name:cookie.name,value:cookie.value})));await reply({type:"APP_BRIDGE_USER_INFO_RESPONSE",result:{success:!0,response}})}catch(error48){await reply({type:"APP_BRIDGE_USER_INFO_RESPONSE",result:{success:!1,error:error48 instanceof Error?error48.message:String(error48)}})}return}let payload=request.payload??{},mtopPayload={...payload,...typeof payload.v=="string"&&payload.version===void 0?{version:payload.v}:{}},streamCapture;try{if(request.type==="mtopStream"){await cdpSendMtopStreamRequest(session,mtopPayload,{onRequestPrepared:metadata=>{streamCapture=recordCdpMtopStreamStart(session.buffers,{api:String(mtopPayload.api??""),url:metadata.url,method:metadata.method,requestHeaders:metadata.requestHeaders,requestData:mtopPayload.data??null})},onResponse:metadata=>{streamCapture&&recordCdpMtopStreamResponse(session.buffers,streamCapture,metadata)},onReceive:async data=>{streamCapture&&recordCdpMtopStreamChunk(session.buffers,streamCapture,data),await reply({type:"APP_BRIDGE_MTOP_STREAM_EVENT",eventType:"onReceive",data})}}),streamCapture&&recordCdpMtopStreamEnd(session.buffers,streamCapture),await reply({type:"APP_BRIDGE_MTOP_STREAM_EVENT",eventType:"onFinish",data:{}});return}let result=await cdpSendMtopRequest(session,mtopPayload);await reply({type:"APP_BRIDGE_MTOP_RESPONSE",result})}catch(error48){let message=error48 instanceof Error?error48.message:String(error48);request.type==="mtopStream"?(streamCapture&&recordCdpMtopStreamEnd(session.buffers,streamCapture,{error:message}),await reply({type:"APP_BRIDGE_MTOP_STREAM_EVENT",eventType:"onError",data:{ret:["HY_FAILED"],msg:message}})):await reply({type:"APP_BRIDGE_MTOP_RESPONSE",result:{success:!1,error:message}})}})().catch(()=>{})})}async function installChildTarget2(session,state,params,source){let sessionId=params.sessionId;if(typeof sessionId!="string")return;let child=session.client.createChildSession(sessionId);try{if(params.targetInfo?.type!=="iframe"||appProfileStates.get(session)!==state)return;await child.sendCommand("Runtime.enable");let frameName=(await child.sendCommand("Runtime.evaluate",{expression:"window.name",returnByValue:!0})).result?.value;if(frameName!=="__mearl_root__"&&frameName!=="__mearl_layer__")return;state.emulation?await sendCommands(child,appProfileEmulationCommands(state.emulation,state.config.userAgent)):await child.sendCommand("Emulation.setUserAgentOverride",{userAgent:state.config.userAgent,platform:state.config.navigatorPlatform}),await child.sendCommand("Runtime.addBinding",{name:APP_PROFILE_BINDING}),state.disposeListeners.push(listenForBridgeRequests(session,child,state)),state.childClients.push(child),await child.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source}).catch(()=>{}),await child.sendCommand("Runtime.evaluate",{expression:source})}finally{await child.sendCommand("Runtime.runIfWaitingForDebugger").catch(()=>{})}}async function disposeState(session,state){appProfileStates.get(session)===state&&appProfileStates.delete(session),setCdpDeviceShellChildEnvironmentManagedByApp(session,!1);for(let dispose of state.disposeListeners.splice(0))dispose();isCdpDeviceShellActive(session)||await session.client.sendCommand("Target.setAutoAttach",{autoAttach:!1,waitForDebuggerOnStart:!1,flatten:!0}).catch(()=>{}),await session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier:state.documentScriptIdentifier}).catch(()=>{}),await Promise.allSettled([session.client,...state.childClients].map(client2=>client2.sendCommand("Runtime.removeBinding",{name:APP_PROFILE_BINDING})));let deviceEmulation=session.emulation?.config;if(deviceEmulation){let commands=buildEnableEmulationCommands(deviceEmulation);await sendCommands(session.client,commands),await Promise.allSettled(state.childClients.map(client2=>sendCommands(client2,commands)))}else await Promise.allSettled([session.client,...state.childClients].map(client2=>client2.sendCommand("Emulation.setUserAgentOverride",{userAgent:""})))}function resolveCdpAppProfile(profile,options={}){return{profile:resolveAppProfile(profile,{os:options.os,appVersion:options.appVersion,deviceModel:options.deviceModel,devicePreset:options.devicePreset,orientation:options.orientation,bridgeConfig:options.bridgeConfig})}}async function applyResolvedCdpAppProfile(session,resolved){let previous=appProfileStates.get(session);previous&&await disposeState(session,previous);let source=buildDocumentSource(resolved.profile.injected),deviceEmulation=session.emulation?.config;deviceEmulation?await sendCommands(session.client,appProfileEmulationCommands(deviceEmulation,resolved.profile.ua)):await session.client.sendCommand("Emulation.setUserAgentOverride",{userAgent:resolved.profile.ua,platform:resolved.profile.injected.navigatorPlatform}),await session.client.sendCommand("Runtime.enable"),await session.client.sendCommand("Runtime.addBinding",{name:APP_PROFILE_BINDING});let script=await session.client.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source});if(typeof script.identifier!="string"||!script.identifier)throw deviceEmulation?await sendCommands(session.client,buildEnableEmulationCommands(deviceEmulation)):await session.client.sendCommand("Emulation.setUserAgentOverride",{userAgent:""}).catch(()=>{}),new Error("Chrome did not return an app profile bootstrap script identifier");let state={config:resolved.profile.injected,documentScriptIdentifier:script.identifier,emulation:deviceEmulation,disposeListeners:[],childClients:[]};appProfileStates.set(session,state),setCdpDeviceShellChildEnvironmentManagedByApp(session,!0),state.disposeListeners.push(listenForBridgeRequests(session,session.client,state)),state.disposeListeners.push(session.client.on("Target.attachedToTarget",params=>{installChildTarget2(session,state,params,source).catch(()=>{})})),state.disposeListeners.push(session.client.on("Target.detachedFromTarget",params=>{let sessionId=params?.sessionId;typeof sessionId!="string"||appProfileStates.get(session)!==state||(state.childClients=state.childClients.filter(client2=>client2.sessionId!==sessionId))})),await session.client.sendCommand("Target.setAutoAttach",{autoAttach:!0,waitForDebuggerOnStart:!0,flatten:!0,filter:[{type:"iframe"},{exclude:!0}]})}async function updateCdpAppProfileDeviceEmulation(session,emulation){let state=appProfileStates.get(session);if(state)return state.emulation=emulation??void 0,await Promise.allSettled(state.childClients.map(client2=>emulation?sendCommands(client2,appProfileEmulationCommands(emulation,state.config.userAgent)):client2.sendCommand("Emulation.setUserAgentOverride",{userAgent:state.config.userAgent,platform:state.config.navigatorPlatform}))),{userAgent:state.config.userAgent,platform:state.config.navigatorPlatform}}function isCdpAppProfileActive(session){return appProfileStates.has(session)}async function waitForCdpAppProfileLoad(session,timeoutMs=3e4){if(isCdpDeviceShellActive(session)){await waitForCdpDeviceShellLoad(session,Math.min(timeoutMs,15e3));return}await waitForPageLoad(session,timeoutMs)}async function clearCdpAppProfile(session,reload=!0){let state=appProfileStates.get(session);if(!state)return{enabled:!1,reloaded:!1};await disposeState(session,state);let reloaded=!1;return reload&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),await waitForCdpAppProfileLoad(session),reloaded=!0),{enabled:!1,reloaded}}async function cdpSetAppProfile(session,data){if(typeof data?.enabled!="boolean")throw new Error('set_app_profile: "enabled" is required (true to enable, false to clear)');if(!data.enabled){if(data.emulation===void 0)return clearCdpAppProfile(session,data.reload!==!1);let hadDeviceShell=await clearCdpDeviceShell(session),appResult=await clearCdpAppProfile(session,!1);await sendCommands(session.client,buildDisableEmulationCommands()),session.emulation=void 0;let reloaded2=!1;return(data.reload!==!1||hadDeviceShell)&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),await waitForPageLoad(session,3e4),reloaded2=!0),{...appResult,device:{enabled:!1,deviceShell:!1,reloaded:reloaded2},reloaded:reloaded2}}if(!data.profile||typeof data.profile!="string")throw new Error('set_app_profile: "profile" is required when enabled=true');let resolved=resolveCdpAppProfile(data.profile,{...data,devicePreset:session.emulation?.config?.presetName,orientation:session.emulation?.config?.orientation});if(data.emulation!==void 0){let emulation=resolveEmulationConfig({enabled:!0,preset:resolved.profile.recommendedPreset,...data.emulation}),targetOs=emulation.platform==="Android"||emulation.platform==="OpenHarmony"?"android":"ios",targetDeviceModel=data.deviceModel??(emulation.presetName?DEVICE_PRESETS[emulation.presetName].appProfileModel:resolved.profile.injected.globals.__DEVICE_MODEL__),appResolved=resolveCdpAppProfile(data.profile,{...data,os:targetOs,deviceModel:targetDeviceModel}),deviceShell=data.emulation.deviceShell??!0;session.emulation={mobile:emulation.mobile,touch:emulation.touch,config:emulation,deviceShell},await applyResolvedCdpAppProfile(session,appResolved);let shellChanged=deviceShell?await applyCdpDeviceShell(session,emulation):await clearCdpDeviceShell(session);deviceShell&&setCdpDeviceShellChildEnvironmentManagedByApp(session,!0);let reloaded2=!1;return(data.reload!==!1||shellChanged)&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),deviceShell?await waitForCdpDeviceShellLoad(session):await waitForPageLoad(session,3e4),reloaded2=!0),{enabled:!0,profile:appResolved.profile.profile,label:appResolved.profile.label,userAgent:appResolved.profile.ua,os:appResolved.profile.injected.platform==="Android"?"android":"ios",device:{enabled:!0,preset:emulation.presetName,viewport:{width:emulation.width,height:emulation.height,deviceScaleFactor:emulation.deviceScaleFactor,scale:emulation.scale??1},userAgent:emulation.userAgent,mobile:emulation.mobile,touch:emulation.touch,orientation:emulation.orientation,deviceShell,reloaded:reloaded2},reloaded:reloaded2}}await applyResolvedCdpAppProfile(session,resolved);let reloaded=!1;return data.reload!==!1&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),await waitForCdpAppProfileLoad(session),reloaded=!0),{enabled:!0,profile:resolved.profile.profile,label:resolved.profile.label,userAgent:resolved.profile.ua,os:resolved.profile.injected.platform==="Android"?"android":"ios",reloaded}}registerActions([{name:"set_app_profile",session:"page",handler:cdpSetAppProfile}]);async function releaseCdpControl(session){let pageSessions=session.listOpenPageSessions(),targetIds=new Set(pageSessions.map(pageSession=>pageSession.targetId)),affectedTabIds=session.listRegisteredTabIds(targetIds).sort((a,b)=>a-b),hadActiveControl=session.hasActiveConnections();try{await releaseCdpRecordings(pageSessions)}finally{await Promise.allSettled(pageSessions.map(async pageSession=>{let[,deviceShell]=await Promise.allSettled([clearCdpAppProfile(pageSession,!1),clearCdpDeviceShell(pageSession),releaseControlledIndicator(pageSession)]);deviceShell.status==="fulfilled"&&deviceShell.value&&await pageSession.client.sendCommand("Page.reload",{}).catch(()=>{})})),clearCdpMockState(),session.close()}return{released:!0,hadActiveControl,affectedTabIds}}var SAMPLE_PAGE_READINESS_SRC=samplePageReadinessInPage.toString(),DISPOSE_PAGE_READINESS_SRC=disposePageReadinessObserverInPage.toString();async function startCdpNavigationObserver(cdpSession2,pageSession,urlBefore,options={}){let pageEndpoint=await resolveCdpDeviceShellPageEndpoint(pageSession),pageClient=pageEndpoint.client;await ensureCdpDomain(pageClient,"Page"),await ensureCdpDomain(pageClient,"Runtime"),options.trackNetwork&&await ensureCdpDomain(pageClient,"Network");let browserClient=null,baselineTargetIds=new Set;if(options.trackOpenedTabs)try{browserClient=await cdpSession2.getBrowserClient();let targets=await browserClient.sendCommand("Target.getTargets");for(let target of targets.targetInfos??[])baselineTargetIds.add(target.targetId)}catch{browserClient=null}let frameTree=await pageClient.sendCommand("Page.getFrameTree"),observedFrameId=pageEndpoint.frameId??frameTree.frameTree?.frame?.id,observesParentTargetSubframe=pageClient===pageSession.client&&pageEndpoint.frameId!==void 0,tracker=createNavigationSettlementTracker({urlBefore,trackNetwork:options.trackNetwork,networkAvailable:options.trackNetwork===!0,networkIdleMs:options.networkIdleMs,contentReadyAfterMs:options.contentReadyAfterMs,sampleContent:async()=>(await sendCdpDeviceShellPageCommand(pageSession,"Runtime.evaluate",{expression:`(${SAMPLE_PAGE_READINESS_SRC})(${options.networkIdleMs??500})`,returnByValue:!0})).result?.value}),removeFrameNavigated=pageClient.on("Page.frameNavigated",params=>{observedFrameId&¶ms.frame?.id!==observedFrameId||tracker.markStarted(params.frame?.url)}),removeWithinDocument=pageClient.on("Page.navigatedWithinDocument",params=>{observedFrameId&¶ms.frameId!==observedFrameId||(tracker.markStarted(params.url),tracker.markDocumentComplete(params.url))}),removeLoad=pageClient.on("Page.loadEventFired",()=>{observesParentTargetSubframe||tracker.hasStarted()&&tracker.markDocumentComplete()}),removeFrameStoppedLoading=pageClient.on("Page.frameStoppedLoading",params=>{observedFrameId&¶ms.frameId!==observedFrameId||tracker.hasStarted()&&tracker.markDocumentComplete()}),removeRequestStarted=options.trackNetwork?pageClient.on("Network.requestWillBeSent",params=>{isPotentialNavigationRequest(params.type??"",params.request?.url??"")&&tracker.requestStarted(params.requestId)}):()=>{},onRequestFinished=params=>tracker.requestFinished(params.requestId),removeRequestFinished=options.trackNetwork?pageClient.on("Network.loadingFinished",onRequestFinished):()=>{},removeRequestFailed=options.trackNetwork?pageClient.on("Network.loadingFailed",onRequestFinished):()=>{};return{hasStarted:tracker.hasStarted,hasNetworkActivity:tracker.hasNetworkActivity,waitForStart:tracker.waitForStart,waitForNetworkIdle:tracker.waitForNetworkIdle,waitForResult:async timeoutMs=>{let result=await tracker.waitForResult(timeoutMs);try{let pageState=await sendCdpDeviceShellPageCommand(pageSession,"Runtime.evaluate",{expression:"({ title: document.title, url: location.href })",returnByValue:!0});return{...result,title:pageState.result?.value?.title??result.title,urlAfter:pageState.result?.value?.url??result.urlAfter}}catch{return result}},getOpenedTabs:async timeoutMs=>{if(!browserClient||options.sourceTabId===void 0)return[];let candidates=((await browserClient.sendCommand("Target.getTargets")).targetInfos??[]).filter(target=>target.type==="page"&&target.openerId===pageSession.targetId&&!baselineTargetIds.has(target.targetId));return(await Promise.all(candidates.map(async candidate=>{let tabId=await cdpSession2.ensureTargetRegistered(candidate.targetId),ready=!1;try{let openedPageSession=await cdpSession2.getPageSession(tabId);await ensureCdpDomain(openedPageSession.client,"Page"),await waitForPageLoad(openedPageSession,timeoutMs),ready=!0}catch{}let targetInfo=await browserClient.sendCommand("Target.getTargetInfo",{targetId:candidate.targetId}).then(result=>result.targetInfo).catch(()=>null);return targetInfo?{tabId,openerTabId:options.sourceTabId,url:targetInfo.url??candidate.url??"",title:targetInfo.title??candidate.title??"",ready,settledBy:ready?"load":"timeout"}:null}))).filter(tab=>tab!==null)},dispose:async()=>{removeFrameNavigated(),removeWithinDocument(),removeLoad(),removeFrameStoppedLoading(),removeRequestStarted(),removeRequestFinished(),removeRequestFailed(),tracker.dispose(),await sendCdpDeviceShellPageCommand(pageSession,"Runtime.evaluate",{expression:`(${DISPOSE_PAGE_READINESS_SRC})()`,returnByValue:!1}).catch(()=>{})}}}var INSTALL_PAGE_OBSERVER_SRC=installPageObserverInPage.toString(),DISPOSE_PAGE_OBSERVER_SRC=disposePageObserverInPage.toString(),PAGE_OBSERVER_GLOBAL="__MEARL_PAGE_OBSERVER__",observationTargets=new WeakMap;function evaluationError(result){return result.exceptionDetails?result.exceptionDetails.exception?.description??result.exceptionDetails.text??"Page observation evaluation failed":null}async function startPageObservation(session){let result=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`(${INSTALL_PAGE_OBSERVER_SRC})()`,returnByValue:!0}),error48=evaluationError(result);if(error48)throw new Error(error48);let checkpoint=result.result?.value;if(!checkpoint||typeof checkpoint.version!="number")throw new Error("Page observer did not return a checkpoint");let endpoint=await resolveCdpDeviceShellPageEndpoint(session);return observationTargets.set(checkpoint,{...endpoint,startedAt:Date.now()}),checkpoint}async function finishPageObservation(session,checkpoint,options={}){let startedTarget=observationTargets.get(checkpoint),currentTarget=await resolveCdpDeviceShellPageEndpoint(session);if(startedTarget&¤tTarget.url&&(currentTarget.client!==startedTarget.client||currentTarget.frameId!==startedTarget.frameId||currentTarget.url!==(startedTarget.url??checkpoint.url))){let title=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:"document.title",returnByValue:!0}).then(result2=>typeof result2.result?.value=="string"?result2.result.value:"").catch(()=>"");return{mode:"navigation",urlBefore:checkpoint.url,urlAfter:currentTarget.url,title,elapsed:Date.now()-startedTarget.startedAt,loaded:!0,ready:!0,settledBy:"load",pendingRequests:0,fullSnapshotRecommended:!0,snapshotReasons:["navigation"]}}let{quietMs,firstChangeTimeoutMs,timeoutMs}=resolvePageObservationWaitOptions(options),expression=`(() => {
|
|
691
|
+
`)),{contentType:`multipart/form-data; boundary=${boundary}`,body:Buffer.concat(chunks)}}function hasMultipartPayload(data){return data.formData!==void 0||data.files!==void 0}async function executeNodeSendRequest(data,cookieMap=new Map){let{url:url2,method="GET",headers={},params,body,formData,files,responseType="auto",timeout=3e4}=data;if(!url2||typeof url2!="string"||url2.trim()==="")throw new Error("Invalid url: url must be a non-empty string");let normalizedMethod=method.toUpperCase();if(!ALLOWED_METHODS.has(normalizedMethod))throw new Error(`Invalid method: ${method}. Allowed: ${[...ALLOWED_METHODS].join(", ")}`);if(!Number.isFinite(timeout)||timeout<=0)throw new Error("timeout must be a positive number");let targetUrl=new URL(url2);for(let[key,value]of Object.entries(params??{}))targetUrl.searchParams.set(key,String(value));let requestHeaders={Accept:"application/json, text/plain, */*","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",...headers},resolvedSourceHeaders=getSendRequestSourceHeaders(targetUrl,headers);resolvedSourceHeaders.referer?setHeader(requestHeaders,"Referer",resolvedSourceHeaders.referer):removeHeader(requestHeaders,"Referer"),resolvedSourceHeaders.origin?setHeader(requestHeaders,"Origin",resolvedSourceHeaders.origin):removeHeader(requestHeaders,"Origin");let cookieHeader=[...cookieMap.entries()].map(([key,value])=>`${key}=${value}`).join("; ");cookieHeader&&setHeader(requestHeaders,"Cookie",cookieHeader);let xsrfToken=cookieMap.get("XSRF-TOKEN");xsrfToken&&!findSendRequestHeaderName(requestHeaders,"x-xsrf-token")&&setHeader(requestHeaders,"X-XSRF-TOKEN",xsrfToken);let requestBody;if(hasMultipartPayload(data)){if(body!=null)throw new Error("body cannot be combined with formData or files");if(normalizedMethod==="GET"||normalizedMethod==="HEAD")throw new Error(`${normalizedMethod} requests cannot use formData or files`);if(findSendRequestHeaderName(requestHeaders,"content-type"))throw new Error("Do not set Content-Type when using formData or files; Mearl sets the boundary");let multipart=await buildMultipartBody(formData,files);requestBody=multipart.body,setHeader(requestHeaders,"Content-Type",multipart.contentType),setHeader(requestHeaders,"Content-Length",String(multipart.body.byteLength))}else body!=null&&!["GET","HEAD"].includes(normalizedMethod)&&(typeof body=="string"?(requestBody=body,findSendRequestHeaderName(requestHeaders,"content-type")||setHeader(requestHeaders,"Content-Type","text/plain")):(requestBody=JSON.stringify(body),findSendRequestHeaderName(requestHeaders,"content-type")||setHeader(requestHeaders,"Content-Type","application/json")));let result=await nodeFetch(targetUrl.toString(),{method:normalizedMethod,headers:requestHeaders,body:requestBody,timeoutMs:timeout}),contentType=(result.headers["content-type"]??"").split(";")[0].trim().toLowerCase(),responseHeaders=Object.fromEntries(Object.entries(result.headers).filter(([name])=>name.toLowerCase()!=="set-cookie"&&name.toLowerCase()!=="set-cookie2")),responseBody,bodyType;if(responseType==="auto"&&isBinarySendRequestContentType(contentType))responseBody=result.bodyBuffer.toString("base64"),bodyType="base64";else{let trimmed=result.body.trimStart();if(responseType==="json"||responseType==="auto"&&contentType.includes("application/json")||responseType==="auto"&&(trimmed.startsWith("{")||trimmed.startsWith("[")))try{responseBody=JSON.parse(result.body),bodyType="json"}catch{if(responseType==="json")throw new Error("send_request expected a JSON response");responseBody=result.body,bodyType="text"}else responseBody=result.body,bodyType="text"}return{success:!0,status:result.status,statusText:result.statusText,headers:responseHeaders,body:responseBody,bodyType,attachedCookieCount:cookieMap.size}}async function cdpSendRequest(session,data){if(!data.url||typeof data.url!="string")throw new Error("Invalid url: url must be a non-empty string");let cookieMap=new Map;if(data.withCookies!==!1)try{cookieMap=await getCookiesForUrl(session,new URL(data.url).toString())}catch{}return executeNodeSendRequest(data,cookieMap)}async function prepareCdpMtopRequest(session,data,stream=!1){let resolved=resolveMtopRequest(data),cookieMap=await getCookiesForUrl(session,resolved.gatewayUrl.toString()),prepared=prepareSignedMtopRequest(resolved,cookieMap,stream);return{...prepared,requestHeaders:{...prepared.cookieHeader?{Cookie:prepared.cookieHeader}:{},...prepared.requestHeaders}}}async function cdpSendMtopRequest(session,data){let prepared=await prepareCdpMtopRequest(session,data),result=await nodeFetch(prepared.targetUrl.toString(),{method:prepared.normalizedMethod,headers:prepared.requestHeaders,body:prepared.body,timeoutMs:prepared.timeout});return{success:!0,response:parseMtopResponseText(result.body),requestData:prepared.requestData}}async function cdpSendMtopStreamRequest(session,data,callbacks){let prepared=await prepareCdpMtopRequest(session,data,!0),controller=new AbortController,timeoutId=setTimeout(()=>controller.abort(),prepared.timeout);try{await callbacks.onRequestPrepared?.({method:prepared.normalizedMethod,url:prepared.targetUrl.toString(),requestHeaders:Object.entries(prepared.requestHeaders).map(([name,value])=>({name,value}))});let response=await fetch(prepared.targetUrl,{method:prepared.normalizedMethod,headers:prepared.requestHeaders,body:prepared.body,signal:controller.signal}),responseHeaders=[];return response.headers.forEach((value,name)=>{name.toLowerCase()!=="set-cookie"&&responseHeaders.push({name,value})}),await callbacks.onResponse?.({status:response.status,statusText:response.statusText,responseHeaders}),{success:!0,response:await consumeMtopSseResponse(response,event=>callbacks.onReceive(event.data)),requestData:prepared.requestData}}catch(error48){throw error48 instanceof Error&&error48.name==="AbortError"?new Error(`send_mtop_stream timed out after ${prepared.timeout}ms: ${prepared.api}`,{cause:error48}):new Error(`send_mtop_stream failed: ${error48 instanceof Error?error48.message:String(error48)}`,{cause:error48})}finally{clearTimeout(timeoutId)}}registerActions([{name:"send_request",session:"page",handler:cdpSendRequest},{name:"send_mtop_request",session:"page",handler:cdpSendMtopRequest}]);var registries=new WeakMap;function getPageRefRegistry(session){let registry2=registries.get(session);if(!registry2){registry2=new BackendNodeRefRegistry,registries.set(session,registry2);let activeRegistry=registry2;session.client.on("Page.frameNavigated",params=>{params.frame?.parentId||activeRegistry.clearDocument()})}return registry2}function beginPageSnapshotRefs(session){return getPageRefRegistry(session).beginSnapshot()}function resolvePageRef(session,ref){return registries.get(session)?.resolve(ref)}function deletePageRef(session,ref){registries.get(session)?.delete(ref)}function clearPageRefsForNavigation(session){registries.get(session)?.clearDocument()}async function enrichCdpPageChangeSetWithRefs(session,observation){return enrichPageChangeSetWithRefs(observation,getPageRefRegistry(session),selectors=>resolveUniqueBackendNodeIds((method,params)=>sendCdpDeviceShellPageCommand(session,method,params),selectors),(node,backendNodeId)=>({backendNodeId,role:node.role??"",name:node.name??""}))}var APP_PROFILE_BINDING="__mearlCdpAppProfileRelay",APP_PROFILE_RESTORE_HINT="__mearlCdpAppProfileRestoreHint__",APP_PROFILE_RESTORE_STATE="__mearlCdpAppProfileState__",APP_PROFILE_RESTORE_WORLD="__mearl_cdp_app_profile_state__",APP_PROFILE_RESTORE_VERSION=1,MAX_APP_PROFILE_RESTORE_STATE_LENGTH=7e4,appProfileStates=new WeakMap;function serializeForSource2(value){return JSON.stringify(value).replace(/[\u2028\u2029]/g,character=>character==="\u2028"?"\\u2028":"\\u2029")}function installCdpAppProfileRelay(bindingName){let browser=globalThis,target=globalThis;target.__mearlCdpAppProfileRelayInstalled__||(target.__mearlCdpAppProfileRelayInstalled__=!0,browser.addEventListener("message",event=>{if(event.source!==globalThis)return;let message=event.data;if(!message||message.source!=="mearl-app-bridge")return;let requestId=message.requestId;if(typeof requestId!="number")return;if(message.type==="prepareWebView"){browser.postMessage({source:"mearl-content",type:"APP_BRIDGE_PREPARE_WEBVIEW_RESPONSE",requestId,result:{success:!0}},"*");return}if(message.type!=="mtop"&&message.type!=="mtopStream"&&message.type!=="userInfo"&&message.type!=="screenshot")return;let replyFailure=reason=>{if(browser.console?.warn("[Mearl] App bridge relay unavailable:",reason),message.type==="mtopStream"){browser.postMessage({source:"mearl-content",type:"APP_BRIDGE_MTOP_STREAM_EVENT",requestId,eventType:"onError",data:{ret:["HY_FAILED"],msg:reason}},"*");return}let responseTypes={mtop:"APP_BRIDGE_MTOP_RESPONSE",userInfo:"APP_BRIDGE_USER_INFO_RESPONSE",screenshot:"APP_BRIDGE_SCREENSHOT_RESPONSE"};browser.postMessage({source:"mearl-content",type:responseTypes[String(message.type)],requestId,result:{success:!1,error:reason}},"*")},binding=target[bindingName];if(typeof binding!="function"){replyFailure("native relay binding is unavailable");return}try{binding(JSON.stringify({type:message.type,requestId,payload:message.payload}))}catch(error48){replyFailure(error48 instanceof Error?error48.message:"native relay call failed")}}))}function installEarlyAppProfileEnvironment(config2,restoreHintName){let browser=globalThis,target=globalThis;try{Object.defineProperty(target,restoreHintName,{configurable:!0,enumerable:!1,writable:!1,value:!0})}catch{target[restoreHintName]=!0}for(let[key,value]of Object.entries(config2.globals))try{target[key]=value}catch{}let insets=config2.safeAreaInsets??{top:config2.statusBarHeight,right:0,bottom:0,left:0};target.__STATUS_BAR_HEIGHT__=config2.statusBarHeight,target.__SAFE_AREA_INSET_BOTTOM__=insets.bottom;for(let[key,value]of[["userAgent",config2.userAgent],["platform",config2.navigatorPlatform],["vendor","Apple Computer, Inc."],["appVersion",config2.userAgent.replace(/^Mozilla\//,"")],["maxTouchPoints",config2.maxTouchPoints]])try{Object.defineProperty(browser.navigator,key,{configurable:!0,get:()=>value})}catch{}}function installWhenDocumentElementExists(install,waitForBody=!1){let browser=globalThis,isReady=()=>!!(browser.document.documentElement&&(!waitForBody||browser.document.body));if(isReady()){install();return}let observer=new browser.MutationObserver(()=>{isReady()&&(observer.disconnect(),install())});observer.observe(browser.document,{childList:!0,subtree:waitForBody})}function buildDocumentSource(config2){return`;(() => {const config=${serializeForSource2(config2)};(${installCdpAppProfileRelay.toString()})(${JSON.stringify(APP_PROFILE_BINDING)});(${installEarlyAppProfileEnvironment.toString()})(config,${JSON.stringify(APP_PROFILE_RESTORE_HINT)});(${installWhenDocumentElementExists.toString()})(() => {${buildAppProfileRuntimeCallSource("config")};},config.rootContainer?.enabled===true&&window===window.top);})();`}function usesAppProfileSplitScreen(emulation){return emulation?.deviceShell===!0&&emulation.splitScreen===!0&&emulation.config?.orientation==="landscape"}function resolveAppProfileRuntimeConfig(baseConfig,emulation){if(!usesAppProfileSplitScreen(emulation)||!emulation?.config){let rootContainer={...baseConfig.rootContainer};return delete rootContainer.splitScreen,{...baseConfig,rootContainer:{...rootContainer,enabled:!1},simulateSystemBars:!1,externalDeviceChrome:!1}}let device=emulation.config;return{...baseConfig,statusBarHeight:24,safeAreaInsets:device.safeAreaInsets,deviceAppearance:{preset:device.presetName??baseConfig.deviceAppearance?.preset??"iphone-17-pro",orientation:device.orientation,cutout:device.appearance.cutout},rootContainer:{...baseConfig.rootContainer,enabled:!0,splitScreen:!0},simulateSystemBars:!0,externalDeviceChrome:!1}}function buildRestoreHintSource(){return`;(() => {try{Object.defineProperty(globalThis,${JSON.stringify(APP_PROFILE_RESTORE_HINT)},{configurable:true,enumerable:false,writable:false,value:true});}catch{globalThis[${JSON.stringify(APP_PROFILE_RESTORE_HINT)}]=true;}})();`}function buildRestoreStateSource(restoreState,activeDocument){return`;(() => {const state=${serializeForSource2({...restoreState,activeDocument})};try{Object.defineProperty(globalThis,${JSON.stringify(APP_PROFILE_RESTORE_STATE)},{configurable:true,enumerable:false,writable:false,value:state});}catch{globalThis[${JSON.stringify(APP_PROFILE_RESTORE_STATE)}]=state;}})();`}function snapshotCdpAppProfileEmulation(emulation){let config2=emulation?.config;if(!config2)return;let landscape=config2.orientation==="landscape";return{...config2.presetName?{preset:config2.presetName}:{},width:landscape?config2.height:config2.width,height:landscape?config2.width:config2.height,deviceScaleFactor:config2.deviceScaleFactor,scale:config2.scale??1,mobile:config2.mobile,userAgent:config2.userAgent,orientation:config2.orientation,touch:config2.touch,deviceShell:emulation.deviceShell===!0,splitScreen:emulation.splitScreen===!0}}function resolveCdpAppProfileRestoreEmulation(emulation){return resolveEmulationConfig({enabled:!0,...emulation})}async function getRestoreExecutionContext(session){let frameId=(await session.client.sendCommand("Page.getFrameTree")).frameTree?.frame?.id;if(typeof frameId!="string"||!frameId)throw new Error("Chrome did not return the main frame id");let world=await session.client.sendCommand("Page.createIsolatedWorld",{frameId,worldName:APP_PROFILE_RESTORE_WORLD,grantUniveralAccess:!1});if(typeof world.executionContextId!="number")throw new Error("Chrome did not return the App profile restore execution context");return world.executionContextId}function appProfileEmulationCommands(config2,userAgent){return buildEnableEmulationCommands(config2).map(command=>command.method==="Emulation.setUserAgentOverride"?{...command,params:{userAgent,platform:config2.platform}}:command)}async function sendCommands(client2,commands){for(let{method,params,optional:optional2}of commands)await client2.sendCommand(method,params).catch(error48=>{if(!optional2)throw error48})}async function postRuntimeMessage(client2,executionContextId,message){await client2.sendCommand("Runtime.evaluate",{expression:`window.postMessage(${serializeForSource2(message)}, '*')`,...typeof executionContextId=="number"?{contextId:executionContextId}:{}})}function listenForBridgeRequests(session,client2,state){return client2.on("Runtime.bindingCalled",params=>{if(params?.name!==APP_PROFILE_BINDING||appProfileStates.get(session)!==state)return;let request;try{request=JSON.parse(params.payload)}catch{return}if(typeof request.requestId!="number")return;let requestId=request.requestId,contextId=typeof params.executionContextId=="number"?params.executionContextId:void 0,reply=message=>postRuntimeMessage(client2,contextId,{requestId,source:"mearl-content",...message});(async()=>{if(request.type==="screenshot"){if(client2!==session.client)return;try{let result=await cdpPageScreenshot(session,{format:"png"});await reply({type:"APP_BRIDGE_SCREENSHOT_RESPONSE",result:{success:!0,...result}})}catch(error48){await reply({type:"APP_BRIDGE_SCREENSHOT_RESPONSE",result:{success:!1,error:error48 instanceof Error?error48.message:String(error48)}})}return}if(request.type==="userInfo"){try{let currentUrl=await readCdpCurrentUrl(session,"user_info"),result=await session.client.sendCommand("Network.getCookies",{urls:[currentUrl]}),response=resolveAppProfileUserInfo(currentUrl,(result.cookies??[]).map(cookie=>({name:cookie.name,value:cookie.value})));await reply({type:"APP_BRIDGE_USER_INFO_RESPONSE",result:{success:!0,response}})}catch(error48){await reply({type:"APP_BRIDGE_USER_INFO_RESPONSE",result:{success:!1,error:error48 instanceof Error?error48.message:String(error48)}})}return}let payload=request.payload??{},mtopPayload={...payload,...typeof payload.v=="string"&&payload.version===void 0?{version:payload.v}:{}},streamCapture;try{if(request.type==="mtopStream"){await cdpSendMtopStreamRequest(session,mtopPayload,{onRequestPrepared:metadata=>{streamCapture=recordCdpMtopStreamStart(session.buffers,{api:String(mtopPayload.api??""),url:metadata.url,method:metadata.method,requestHeaders:metadata.requestHeaders,requestData:mtopPayload.data??null})},onResponse:metadata=>{streamCapture&&recordCdpMtopStreamResponse(session.buffers,streamCapture,metadata)},onReceive:async data=>{streamCapture&&recordCdpMtopStreamChunk(session.buffers,streamCapture,data),await reply({type:"APP_BRIDGE_MTOP_STREAM_EVENT",eventType:"onReceive",data})}}),streamCapture&&recordCdpMtopStreamEnd(session.buffers,streamCapture),await reply({type:"APP_BRIDGE_MTOP_STREAM_EVENT",eventType:"onFinish",data:{}});return}let result=await cdpSendMtopRequest(session,mtopPayload);await reply({type:"APP_BRIDGE_MTOP_RESPONSE",result})}catch(error48){let message=error48 instanceof Error?error48.message:String(error48);request.type==="mtopStream"?(streamCapture&&recordCdpMtopStreamEnd(session.buffers,streamCapture,{error:message}),await reply({type:"APP_BRIDGE_MTOP_STREAM_EVENT",eventType:"onError",data:{ret:["HY_FAILED"],msg:message}})):await reply({type:"APP_BRIDGE_MTOP_RESPONSE",result:{success:!1,error:message}})}})().catch(()=>{})})}async function installChildTarget2(session,state,params){let sessionId=params.sessionId;if(typeof sessionId!="string")return;let child=session.client.createChildSession(sessionId);try{if(params.targetInfo?.type!=="iframe"||appProfileStates.get(session)!==state)return;await child.sendCommand("Runtime.enable");let frameName=(await child.sendCommand("Runtime.evaluate",{expression:"window.name",returnByValue:!0})).result?.value;if(frameName!=="__mearl_root__"&&frameName!=="__mearl_layer__")return;let source=buildDocumentSource(state.config);state.emulation?await sendCommands(child,appProfileEmulationCommands(state.emulation,state.config.userAgent)):await child.sendCommand("Emulation.setUserAgentOverride",{userAgent:state.config.userAgent,platform:state.config.navigatorPlatform}),await child.sendCommand("Runtime.addBinding",{name:APP_PROFILE_BINDING}),state.disposeListeners.push(listenForBridgeRequests(session,child,state)),state.childClients.push(child),await child.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source}).catch(()=>{}),await child.sendCommand("Runtime.evaluate",{expression:source})}finally{await child.sendCommand("Runtime.runIfWaitingForDebugger").catch(()=>{})}}async function disposeState(session,state){appProfileStates.get(session)===state&&appProfileStates.delete(session),setCdpDeviceShellChildEnvironmentManagedByApp(session,!1);for(let dispose of state.disposeListeners.splice(0))dispose();isCdpDeviceShellActive(session)||await session.client.sendCommand("Target.setAutoAttach",{autoAttach:!1,waitForDebuggerOnStart:!1,flatten:!0}).catch(()=>{}),await Promise.allSettled(state.documentScriptIdentifiers.map(identifier=>session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier}))),await Promise.allSettled([session.client,...state.childClients].map(client2=>client2.sendCommand("Runtime.removeBinding",{name:APP_PROFILE_BINDING})));try{let contextId=await getRestoreExecutionContext(session);await session.client.sendCommand("Runtime.evaluate",{contextId,expression:`delete globalThis[${JSON.stringify(APP_PROFILE_RESTORE_STATE)}]`})}catch{}await session.client.sendCommand("Runtime.evaluate",{expression:`delete globalThis[${JSON.stringify(APP_PROFILE_RESTORE_HINT)}]`}).catch(()=>{});let deviceEmulation=session.emulation?.config;if(deviceEmulation){let commands=buildEnableEmulationCommands(deviceEmulation);await sendCommands(session.client,commands),await Promise.allSettled(state.childClients.map(client2=>sendCommands(client2,commands)))}else await Promise.allSettled([session.client,...state.childClients].map(client2=>client2.sendCommand("Emulation.setUserAgentOverride",{userAgent:""})))}async function rollbackAppProfileInstall(session,documentScriptIdentifiers,deviceEmulation){await Promise.allSettled([...documentScriptIdentifiers.map(identifier=>session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier})),session.client.sendCommand("Runtime.removeBinding",{name:APP_PROFILE_BINDING}),session.client.sendCommand("Runtime.evaluate",{expression:`delete globalThis[${JSON.stringify(APP_PROFILE_RESTORE_HINT)}]`})]),deviceEmulation?await sendCommands(session.client,buildEnableEmulationCommands(deviceEmulation)).catch(()=>{}):await session.client.sendCommand("Emulation.setUserAgentOverride",{userAgent:""}).catch(()=>{})}function resolveCdpAppProfile(profile,options={}){let resolved=resolveAppProfile(profile,{os:options.os,appVersion:options.appVersion,deviceModel:options.deviceModel,devicePreset:options.devicePreset,orientation:options.orientation,bridgeConfig:options.bridgeConfig}),restoreOptions={os:resolved.injected.platform==="Android"?"android":"ios",appVersion:resolved.injected.globals.__APP_VERSION__??"",deviceModel:resolved.injected.globals.__DEVICE_MODEL__??"",...resolved.injected.deviceAppearance?.preset?{devicePreset:resolved.injected.deviceAppearance.preset}:{},...resolved.injected.deviceAppearance?.orientation?{orientation:resolved.injected.deviceAppearance.orientation}:{},...options.bridgeConfig?{bridgeConfig:JSON.parse(JSON.stringify(options.bridgeConfig))}:{}};return{profile:resolved,restoreState:{version:APP_PROFILE_RESTORE_VERSION,profile:resolved.profile,options:restoreOptions}}}function isFiniteNumberInRange(value,minimum,maximum){return typeof value=="number"&&Number.isFinite(value)&&value>=minimum&&value<=maximum}function isCdpAppProfileRestoreEmulation(value){if(!value||typeof value!="object"||Array.isArray(value))return!1;let emulation=value,supportedKeys=new Set(["preset","width","height","deviceScaleFactor","scale","mobile","userAgent","orientation","touch","deviceShell","splitScreen"]);return!Object.keys(emulation).some(key=>!supportedKeys.has(key))&&(emulation.preset===void 0||typeof emulation.preset=="string"&&Object.hasOwn(DEVICE_PRESETS,emulation.preset))&&isFiniteNumberInRange(emulation.width,1,1e5)&&isFiniteNumberInRange(emulation.height,1,1e5)&&isFiniteNumberInRange(emulation.deviceScaleFactor,0,100)&&isFiniteNumberInRange(emulation.scale,Number.MIN_VALUE,100)&&typeof emulation.mobile=="boolean"&&typeof emulation.userAgent=="string"&&emulation.userAgent.length<=4096&&(emulation.orientation==="portrait"||emulation.orientation==="landscape")&&typeof emulation.touch=="boolean"&&typeof emulation.deviceShell=="boolean"&&(emulation.splitScreen===void 0||typeof emulation.splitScreen=="boolean")}function parseCdpAppProfileRestoreState(value){if(!value||typeof value!="object"||Array.isArray(value))return null;try{if(JSON.stringify(value).length>MAX_APP_PROFILE_RESTORE_STATE_LENGTH)return null}catch{return null}let state=value,supportedStateKeys=new Set(["version","profile","options","emulation","activeDocument"]);if(Object.keys(state).some(key=>!supportedStateKeys.has(key))||state.version!==APP_PROFILE_RESTORE_VERSION||typeof state.profile!="string"||typeof state.activeDocument!="boolean"||state.emulation!==void 0&&!isCdpAppProfileRestoreEmulation(state.emulation)||!state.options||typeof state.options!="object"||Array.isArray(state.options))return null;let options=state.options,supportedKeys=new Set(["os","appVersion","deviceModel","devicePreset","orientation","bridgeConfig"]);return Object.keys(options).some(key=>!supportedKeys.has(key))||options.os!=="ios"&&options.os!=="android"||typeof options.appVersion!="string"||options.appVersion.length>100||typeof options.deviceModel!="string"||options.deviceModel.length>200||options.devicePreset!==void 0&&(typeof options.devicePreset!="string"||!Object.hasOwn(DEVICE_PRESETS,options.devicePreset))||options.orientation!==void 0&&options.orientation!=="portrait"&&options.orientation!=="landscape"?null:value}function restoreStateForSession(restoreState,emulation){let result={...restoreState},emulationSnapshot=snapshotCdpAppProfileEmulation(emulation);return emulationSnapshot?result.emulation=emulationSnapshot:delete result.emulation,result}async function writeCurrentRestoreState(session,restoreState){let activeProfile=await session.client.sendCommand("Runtime.evaluate",{expression:`globalThis.__mearlAppProfile__===${JSON.stringify(restoreState.profile)}`,returnByValue:!0}),contextId=await getRestoreExecutionContext(session);await session.client.sendCommand("Runtime.evaluate",{contextId,expression:buildRestoreStateSource(restoreState,activeProfile.result?.value===!0)})}async function replaceRestoreState(session,state,restoreState){let result=await session.client.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source:buildRestoreStateSource(restoreState,!0),worldName:APP_PROFILE_RESTORE_WORLD});if(typeof result.identifier!="string"||!result.identifier)throw new Error("Chrome did not return an app profile restore script identifier");let identifier=result.identifier;try{await writeCurrentRestoreState(session,restoreState)}catch(error48){throw await session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier}).catch(()=>{}),error48}let previousIdentifier=state.restoreScriptIdentifier;state.restoreState=restoreState,state.restoreScriptIdentifier=identifier,state.documentScriptIdentifiers.push(identifier),await session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier:previousIdentifier}).then(()=>!0,()=>!1)&&(state.documentScriptIdentifiers=state.documentScriptIdentifiers.filter(scriptIdentifier=>scriptIdentifier!==previousIdentifier))}async function replaceAppProfileDocumentSource(session,state,config2){let result=await session.client.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source:buildDocumentSource(config2)});if(typeof result.identifier!="string"||!result.identifier)throw new Error("Chrome did not return an App profile bootstrap script identifier");let previousIdentifier=state.profileScriptIdentifier;state.config=config2,state.profileScriptIdentifier=result.identifier,state.documentScriptIdentifiers.push(result.identifier),await session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier:previousIdentifier}).then(()=>!0,()=>!1)&&(state.documentScriptIdentifiers=state.documentScriptIdentifiers.filter(identifier=>identifier!==previousIdentifier))}async function restoreCdpAppProfile(session){if(appProfileStates.has(session))return!0;let pageState=(await session.client.sendCommand("Runtime.evaluate",{expression:`({profile:typeof globalThis.__mearlAppProfile__==='string'?globalThis.__mearlAppProfile__:null,restoreHint:globalThis[${JSON.stringify(APP_PROFILE_RESTORE_HINT)}]===true})`,returnByValue:!0,silent:!0})).result?.value;if(typeof pageState?.profile!="string"&&pageState?.restoreHint!==!0)return!1;let contextId=await getRestoreExecutionContext(session),stateProbe=await session.client.sendCommand("Runtime.evaluate",{contextId,expression:`globalThis[${JSON.stringify(APP_PROFILE_RESTORE_STATE)}]??null`,returnByValue:!0}),restoreState=parseCdpAppProfileRestoreState(stateProbe.result?.value);if(!restoreState||restoreState.activeDocument&&typeof pageState?.profile=="string"&&pageState.profile!==restoreState.profile)return!1;let resolved;try{resolved=resolveCdpAppProfile(restoreState.profile,restoreState.options)}catch{return!1}let restoredEmulation;try{restoredEmulation=restoreState.emulation?resolveCdpAppProfileRestoreEmulation(restoreState.emulation):void 0}catch{return!1}let previousEmulation=session.emulation;restoredEmulation&&restoreState.emulation&&(session.emulation={mobile:restoredEmulation.mobile,touch:restoredEmulation.touch,config:restoredEmulation,deviceShell:restoreState.emulation.deviceShell,splitScreen:restoreState.emulation.splitScreen===!0});try{await applyResolvedCdpAppProfile(session,resolved),restoredEmulation&&restoreState.emulation?.deviceShell&&(await applyCdpDeviceShell(session,restoredEmulation,{rootContainerManagedByApp:usesAppProfileSplitScreen(session.emulation)}),setCdpDeviceShellChildEnvironmentManagedByApp(session,!0)),restoreState.activeDocument&&await session.client.sendCommand("Runtime.evaluate",{expression:buildDocumentSource(resolved.profile.injected)})}catch(error48){await clearCdpDeviceShell(session).catch(()=>{});let state=appProfileStates.get(session);throw state&&await disposeState(session,state),session.emulation=previousEmulation,restoredEmulation&&(previousEmulation?.config?await sendCommands(session.client,buildEnableEmulationCommands(previousEmulation.config)).catch(()=>{}):await sendCommands(session.client,buildDisableEmulationCommands()).catch(()=>{})),new Error(`Failed to restore App profile for target ${session.targetId}: ${error48 instanceof Error?error48.message:String(error48)}`,{cause:error48})}return!0}async function applyResolvedCdpAppProfile(session,resolved){let previous=appProfileStates.get(session);previous&&await disposeState(session,previous);let baseConfig=resolved.profile.injected,config2=resolveAppProfileRuntimeConfig(baseConfig,session.emulation),source=buildDocumentSource(config2),deviceEmulation=session.emulation?.config,restoreState=restoreStateForSession(resolved.restoreState,session.emulation);deviceEmulation?await sendCommands(session.client,appProfileEmulationCommands(deviceEmulation,resolved.profile.ua)):await session.client.sendCommand("Emulation.setUserAgentOverride",{userAgent:resolved.profile.ua,platform:resolved.profile.injected.navigatorPlatform}),await session.client.sendCommand("Runtime.enable"),await session.client.sendCommand("Runtime.addBinding",{name:APP_PROFILE_BINDING});let documentScriptIdentifiers=[],state;try{let script=await session.client.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source});if(typeof script.identifier!="string"||!script.identifier)throw new Error("Chrome did not return an app profile bootstrap script identifier");documentScriptIdentifiers.push(script.identifier);let restoreScript=await session.client.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source:buildRestoreStateSource(restoreState,!0),worldName:APP_PROFILE_RESTORE_WORLD});if(typeof restoreScript.identifier!="string"||!restoreScript.identifier)throw new Error("Chrome did not return an app profile restore script identifier");documentScriptIdentifiers.push(restoreScript.identifier),await writeCurrentRestoreState(session,restoreState),await session.client.sendCommand("Runtime.evaluate",{expression:buildRestoreHintSource()});let installedState={baseConfig,config:config2,documentScriptIdentifiers,profileScriptIdentifier:script.identifier,restoreScriptIdentifier:restoreScript.identifier,restoreState,emulation:deviceEmulation,disposeListeners:[],childClients:[]};state=installedState,appProfileStates.set(session,installedState),setCdpDeviceShellChildEnvironmentManagedByApp(session,!0),installedState.disposeListeners.push(listenForBridgeRequests(session,session.client,installedState)),installedState.disposeListeners.push(session.client.on("Target.attachedToTarget",params=>{installChildTarget2(session,installedState,params).catch(()=>{})})),installedState.disposeListeners.push(session.client.on("Target.detachedFromTarget",params=>{let sessionId=params?.sessionId;typeof sessionId!="string"||appProfileStates.get(session)!==installedState||(installedState.childClients=installedState.childClients.filter(client2=>client2.sessionId!==sessionId))})),await session.client.sendCommand("Target.setAutoAttach",{autoAttach:!0,waitForDebuggerOnStart:!0,flatten:!0,filter:[{type:"iframe"},{exclude:!0}]})}catch(error48){throw state?await disposeState(session,state):await rollbackAppProfileInstall(session,documentScriptIdentifiers,deviceEmulation),error48}}async function updateCdpAppProfileDeviceEmulation(session,emulation,deviceShell=session.emulation?.deviceShell===!0,splitScreen=session.emulation?.splitScreen===!0){let state=appProfileStates.get(session);if(!state)return;let nextSessionEmulation=emulation?{mobile:emulation.mobile,touch:emulation.touch,config:emulation,deviceShell,splitScreen}:void 0,nextConfig=resolveAppProfileRuntimeConfig(state.baseConfig,nextSessionEmulation);return JSON.stringify(nextConfig)!==JSON.stringify(state.config)&&await replaceAppProfileDocumentSource(session,state,nextConfig),await replaceRestoreState(session,state,restoreStateForSession(state.restoreState,nextSessionEmulation)),state.emulation=emulation??void 0,await Promise.allSettled(state.childClients.map(client2=>emulation?sendCommands(client2,appProfileEmulationCommands(emulation,state.config.userAgent)):client2.sendCommand("Emulation.setUserAgentOverride",{userAgent:state.config.userAgent,platform:state.config.navigatorPlatform}))),{userAgent:state.config.userAgent,platform:state.config.navigatorPlatform}}function isCdpAppProfileActive(session){return appProfileStates.has(session)}async function waitForCdpAppProfileLoad(session,timeoutMs=3e4){if(isCdpDeviceShellActive(session)){await waitForCdpDeviceShellLoad(session,Math.min(timeoutMs,15e3));return}await waitForPageLoad(session,timeoutMs)}async function clearCdpAppProfile(session,reload=!0){let state=appProfileStates.get(session);if(!state)return{enabled:!1,reloaded:!1};await disposeState(session,state),session.emulation?.deviceShell&&session.emulation.config&&await applyCdpDeviceShell(session,session.emulation.config);let reloaded=!1;return reload&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),await waitForCdpAppProfileLoad(session),reloaded=!0),{enabled:!1,reloaded}}async function cdpSetAppProfile(session,data){if(typeof data?.enabled!="boolean")throw new Error('set_app_profile: "enabled" is required (true to enable, false to clear)');if(!data.enabled){if(data.emulation===void 0)return clearCdpAppProfile(session,data.reload!==!1);let hadDeviceShell=await clearCdpDeviceShell(session),appResult=await clearCdpAppProfile(session,!1);await sendCommands(session.client,buildDisableEmulationCommands()),session.emulation=void 0;let reloaded2=!1;return(data.reload!==!1||hadDeviceShell)&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),await waitForPageLoad(session,3e4),reloaded2=!0),{...appResult,device:{enabled:!1,deviceShell:!1,splitScreen:!1,reloaded:reloaded2},reloaded:reloaded2}}if(!data.profile||typeof data.profile!="string")throw new Error('set_app_profile: "profile" is required when enabled=true');let resolved=resolveCdpAppProfile(data.profile,{...data,devicePreset:session.emulation?.config?.presetName,orientation:session.emulation?.config?.orientation});if(data.emulation!==void 0){let emulation=resolveEmulationConfig({enabled:!0,preset:resolved.profile.recommendedPreset,...data.emulation}),targetOs=emulation.platform==="Android"||emulation.platform==="OpenHarmony"?"android":"ios",targetDeviceModel=data.deviceModel??(emulation.presetName?DEVICE_PRESETS[emulation.presetName].appProfileModel:resolved.profile.injected.globals.__DEVICE_MODEL__),appResolved=resolveCdpAppProfile(data.profile,{...data,os:targetOs,deviceModel:targetDeviceModel}),deviceShell=data.emulation.deviceShell??!0,splitScreen=deviceShell&&data.emulation.splitScreen===!0&&emulation.orientation==="landscape";session.emulation={mobile:emulation.mobile,touch:emulation.touch,config:emulation,deviceShell,splitScreen},await applyResolvedCdpAppProfile(session,appResolved);let shellChanged2=deviceShell?await applyCdpDeviceShell(session,emulation,{rootContainerManagedByApp:splitScreen}):await clearCdpDeviceShell(session);deviceShell&&setCdpDeviceShellChildEnvironmentManagedByApp(session,!0);let reloaded2=!1;return(data.reload!==!1||shellChanged2)&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),deviceShell?await waitForCdpDeviceShellLoad(session):await waitForPageLoad(session,3e4),reloaded2=!0),{enabled:!0,profile:appResolved.profile.profile,label:appResolved.profile.label,userAgent:appResolved.profile.ua,os:appResolved.profile.injected.platform==="Android"?"android":"ios",device:{enabled:!0,preset:emulation.presetName,viewport:{width:emulation.width,height:emulation.height,deviceScaleFactor:emulation.deviceScaleFactor,scale:emulation.scale??1},userAgent:emulation.userAgent,mobile:emulation.mobile,touch:emulation.touch,orientation:emulation.orientation,deviceShell,splitScreen,reloaded:reloaded2},reloaded:reloaded2}}await applyResolvedCdpAppProfile(session,resolved);let shellChanged=session.emulation?.deviceShell&&session.emulation.config?await applyCdpDeviceShell(session,session.emulation.config,{rootContainerManagedByApp:usesAppProfileSplitScreen(session.emulation)}):!1,reloaded=!1;return(data.reload!==!1||shellChanged)&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),await waitForCdpAppProfileLoad(session),reloaded=!0),{enabled:!0,profile:resolved.profile.profile,label:resolved.profile.label,userAgent:resolved.profile.ua,os:resolved.profile.injected.platform==="Android"?"android":"ios",reloaded}}registerPageSessionInitializer(async session=>{try{await restoreCdpAppProfile(session)}catch(error48){console.warn(`[CDP] Failed to restore App profile for target ${session.targetId}:`,error48 instanceof Error?error48.message:String(error48))}});registerActions([{name:"set_app_profile",session:"page",handler:cdpSetAppProfile}]);async function releaseCdpControl(session){let pageSessions=session.listOpenPageSessions(),targetIds=new Set(pageSessions.map(pageSession=>pageSession.targetId)),affectedTabIds=session.listRegisteredTabIds(targetIds).sort((a,b)=>a-b),hadActiveControl=session.hasActiveConnections();try{await releaseCdpRecordings(pageSessions)}finally{await Promise.allSettled(pageSessions.map(async pageSession=>{let[,deviceShell]=await Promise.allSettled([clearCdpAppProfile(pageSession,!1),clearCdpDeviceShell(pageSession),releaseControlledIndicator(pageSession)]);deviceShell.status==="fulfilled"&&deviceShell.value&&await pageSession.client.sendCommand("Page.reload",{}).catch(()=>{})})),clearCdpMockState(),session.close()}return{released:!0,hadActiveControl,affectedTabIds}}var SAMPLE_PAGE_READINESS_SRC=samplePageReadinessInPage.toString(),DISPOSE_PAGE_READINESS_SRC=disposePageReadinessObserverInPage.toString();async function startCdpNavigationObserver(cdpSession2,pageSession,urlBefore,options={}){let pageEndpoint=await resolveCdpDeviceShellPageEndpoint(pageSession),pageClient=pageEndpoint.client;await ensureCdpDomain(pageClient,"Page"),await ensureCdpDomain(pageClient,"Runtime"),options.trackNetwork&&await ensureCdpDomain(pageClient,"Network");let browserClient=null,baselineTargetIds=new Set;if(options.trackOpenedTabs)try{browserClient=await cdpSession2.getBrowserClient();let targets=await browserClient.sendCommand("Target.getTargets");for(let target of targets.targetInfos??[])baselineTargetIds.add(target.targetId)}catch{browserClient=null}let frameTree=await pageClient.sendCommand("Page.getFrameTree"),observedFrameId=pageEndpoint.frameId??frameTree.frameTree?.frame?.id,observesParentTargetSubframe=pageClient===pageSession.client&&pageEndpoint.frameId!==void 0,tracker=createNavigationSettlementTracker({urlBefore,trackNetwork:options.trackNetwork,networkAvailable:options.trackNetwork===!0,networkIdleMs:options.networkIdleMs,contentReadyAfterMs:options.contentReadyAfterMs,sampleContent:async()=>(await sendCdpDeviceShellPageCommand(pageSession,"Runtime.evaluate",{expression:`(${SAMPLE_PAGE_READINESS_SRC})(${options.networkIdleMs??500})`,returnByValue:!0})).result?.value}),removeFrameNavigated=pageClient.on("Page.frameNavigated",params=>{observedFrameId&¶ms.frame?.id!==observedFrameId||tracker.markStarted(params.frame?.url)}),removeWithinDocument=pageClient.on("Page.navigatedWithinDocument",params=>{observedFrameId&¶ms.frameId!==observedFrameId||(tracker.markStarted(params.url),tracker.markDocumentComplete(params.url))}),removeLoad=pageClient.on("Page.loadEventFired",()=>{observesParentTargetSubframe||tracker.hasStarted()&&tracker.markDocumentComplete()}),removeFrameStoppedLoading=pageClient.on("Page.frameStoppedLoading",params=>{observedFrameId&¶ms.frameId!==observedFrameId||tracker.hasStarted()&&tracker.markDocumentComplete()}),removeRequestStarted=options.trackNetwork?pageClient.on("Network.requestWillBeSent",params=>{isPotentialNavigationRequest(params.type??"",params.request?.url??"")&&tracker.requestStarted(params.requestId)}):()=>{},onRequestFinished=params=>tracker.requestFinished(params.requestId),removeRequestFinished=options.trackNetwork?pageClient.on("Network.loadingFinished",onRequestFinished):()=>{},removeRequestFailed=options.trackNetwork?pageClient.on("Network.loadingFailed",onRequestFinished):()=>{};return{hasStarted:tracker.hasStarted,hasNetworkActivity:tracker.hasNetworkActivity,waitForStart:tracker.waitForStart,waitForNetworkIdle:tracker.waitForNetworkIdle,waitForResult:async timeoutMs=>{let result=await tracker.waitForResult(timeoutMs);try{let pageState=await sendCdpDeviceShellPageCommand(pageSession,"Runtime.evaluate",{expression:"({ title: document.title, url: location.href })",returnByValue:!0});return{...result,title:pageState.result?.value?.title??result.title,urlAfter:pageState.result?.value?.url??result.urlAfter}}catch{return result}},getOpenedTabs:async timeoutMs=>{if(!browserClient||options.sourceTabId===void 0)return[];let candidates=((await browserClient.sendCommand("Target.getTargets")).targetInfos??[]).filter(target=>target.type==="page"&&target.openerId===pageSession.targetId&&!baselineTargetIds.has(target.targetId));return(await Promise.all(candidates.map(async candidate=>{let tabId=await cdpSession2.ensureTargetRegistered(candidate.targetId),ready=!1;try{let openedPageSession=await cdpSession2.getPageSession(tabId);await ensureCdpDomain(openedPageSession.client,"Page"),await waitForPageLoad(openedPageSession,timeoutMs),ready=!0}catch{}let targetInfo=await browserClient.sendCommand("Target.getTargetInfo",{targetId:candidate.targetId}).then(result=>result.targetInfo).catch(()=>null);return targetInfo?{tabId,openerTabId:options.sourceTabId,url:targetInfo.url??candidate.url??"",title:targetInfo.title??candidate.title??"",ready,settledBy:ready?"load":"timeout"}:null}))).filter(tab=>tab!==null)},dispose:async()=>{removeFrameNavigated(),removeWithinDocument(),removeLoad(),removeFrameStoppedLoading(),removeRequestStarted(),removeRequestFinished(),removeRequestFailed(),tracker.dispose(),await sendCdpDeviceShellPageCommand(pageSession,"Runtime.evaluate",{expression:`(${DISPOSE_PAGE_READINESS_SRC})()`,returnByValue:!1}).catch(()=>{})}}}var INSTALL_PAGE_OBSERVER_SRC=installPageObserverInPage.toString(),DISPOSE_PAGE_OBSERVER_SRC=disposePageObserverInPage.toString(),PAGE_OBSERVER_GLOBAL="__MEARL_PAGE_OBSERVER__",observationTargets=new WeakMap;function evaluationError(result){return result.exceptionDetails?result.exceptionDetails.exception?.description??result.exceptionDetails.text??"Page observation evaluation failed":null}async function startPageObservation(session){let result=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`(${INSTALL_PAGE_OBSERVER_SRC})()`,returnByValue:!0}),error48=evaluationError(result);if(error48)throw new Error(error48);let checkpoint=result.result?.value;if(!checkpoint||typeof checkpoint.version!="number")throw new Error("Page observer did not return a checkpoint");let endpoint=await resolveCdpDeviceShellPageEndpoint(session);return observationTargets.set(checkpoint,{...endpoint,startedAt:Date.now()}),checkpoint}async function finishPageObservation(session,checkpoint,options={}){let startedTarget=observationTargets.get(checkpoint),currentTarget=await resolveCdpDeviceShellPageEndpoint(session);if(startedTarget&¤tTarget.url&&(currentTarget.client!==startedTarget.client||currentTarget.frameId!==startedTarget.frameId||currentTarget.url!==(startedTarget.url??checkpoint.url))){let title=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:"document.title",returnByValue:!0}).then(result2=>typeof result2.result?.value=="string"?result2.result.value:"").catch(()=>"");return{mode:"navigation",urlBefore:checkpoint.url,urlAfter:currentTarget.url,title,elapsed:Date.now()-startedTarget.startedAt,loaded:!0,ready:!0,settledBy:"load",pendingRequests:0,fullSnapshotRecommended:!0,snapshotReasons:["navigation"]}}let{quietMs,firstChangeTimeoutMs,timeoutMs}=resolvePageObservationWaitOptions(options),expression=`(() => {
|
|
692
692
|
const state = globalThis[${JSON.stringify(PAGE_OBSERVER_GLOBAL)}];
|
|
693
693
|
if (!state || typeof state.waitSince !== 'function') {
|
|
694
694
|
throw new Error('Page observer is unavailable after the action');
|
|
@@ -700,7 +700,7 @@ Content-Type: ${file2.contentType}\r
|
|
|
700
700
|
${firstChangeTimeoutMs},
|
|
701
701
|
${timeoutMs}
|
|
702
702
|
);
|
|
703
|
-
})()`,result=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression,returnByValue:!0,awaitPromise:!0},timeoutMs+2e3),error48=evaluationError(result);if(error48)throw new Error(error48);let changeSet=result.result?.value;if(!changeSet||changeSet.mode!=="delta")throw new Error("Page observer did not return a change set");return changeSet}async function disposePageObservation(session){await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`(${DISPOSE_PAGE_OBSERVER_SRC})()`,returnByValue:!1}).catch(()=>{})}function filterRequests(buffers,opts){let pattern=opts.filter?compileTextPattern(opts.filter):void 0;return queryCapturedEntries(buffers.requests.filter(request=>Number.isSafeInteger(request.captureSequence)),buffers.capture,{after:opts.after,since:opts.since,limit:opts.count??10},request=>(!opts.source||opts.source==="all"||request.source===opts.source)&&(!pattern||matchesTextPattern(request.url,pattern)||matchesTextPattern(request.apiName,pattern)),buffers.capture.droppedRequestsThroughSequence,"requests")}async function cdpGetRequests(session,data){let opts={count:data.count??10,filter:data.filter,since:data.since,after:data.after,source:data.source,applyHiddenFilter:data.applyHiddenFilter!==!1},captured=filterRequests(session.buffers,opts),serializeOpts={includeBody:data.includeBody!==!1,includeHeaders:data.includeHeaders===!0,maxBodySize:data.maxBodySize??5e4,fields:data.fields,keysOnly:data.keysOnly===!0};return{meta:{count:captured.entries.length,totalMatched:captured.totalMatched,totalInBuffer:session.buffers.requests.length,filter:data.filter,since:data.since,after:data.after,nextCursor:captured.nextCursor,hasMore:captured.hasMore,gap:captured.gap,source:"cdp"},requests:captured.entries.map(r=>serializeRequest(r,serializeOpts))}}async function cdpGetLogs(session,data){let{level,since,after,limit=100,filter}=data,pattern=filter?compileTextPattern(filter):void 0,captured=queryCapturedEntries(session.buffers.logs,session.buffers.capture,{after,since,limit},log2=>(!level||level==="all"||log2.level===level)&&(!pattern||matchesTextPattern(log2.message,pattern)||log2.args.some(arg=>matchesTextPattern(arg,pattern))),session.buffers.capture.droppedLogsThroughSequence,"logs"),captureStatus=session.buffers.logs.length===0?"armed":"active";return{meta:{count:captured.entries.length,totalMatched:captured.totalMatched,totalInBuffer:session.buffers.logs.length,level:level||"all",since,after,filter,nextCursor:captured.nextCursor,hasMore:captured.hasMore,gap:captured.gap,captureStatus,...captureStatus==="armed"&&{hint:"Log capture is active, but this tab has no captured history yet. Reload the current tab or repeat the triggering action, then call get_logs again."},source:"cdp"},logs:captured.entries}}async function cdpCaptureCheckpoint(session,_data){return{tabId:session.tabId,cursor:captureCheckpoint(session.buffers.capture),timestampMs:Date.now(),captureStatus:session.buffers.capture.currentSequence===0?"armed":"active"}}async function collectCdpPageDiagnostics(session,after,diagnostics){let result={};if(diagnostics.logs){let options=diagnostics.logs===!0?{level:"error",limit:100}:{level:"error",limit:100,...diagnostics.logs};result.logs=await cdpGetLogs(session,{...options,after})}if(diagnostics.requests){let options=diagnostics.requests===!0?{source:"all",includeBody:!1,count:100}:{source:"all",includeBody:!1,count:100,...diagnostics.requests};result.requests=await cdpGetRequests(session,{...options,after})}if(diagnostics.events){let options=diagnostics.events===!0?{source:"all",limit:100}:{source:"all",limit:100,...diagnostics.events};result.events=await cdpGetEvents(session,{...options,after})}return result}async function cdpGetEvents(session,data){let{source="all",event_type,since,after,limit=20,filter,includeRaw=!1}=data,response=queryCapturedTrackingEvents(session.buffers.events,session.buffers.capture,{source,event_type,since,after,limit,filter},session.buffers.capture.droppedEventsThroughSequence),captureStatus=response.totalInBuffer===0?"armed":"active",hint=response.events.length===0&&captureStatus==="armed"?TRACKING_CAPTURE_ARMED_HINT:void 0;return{meta:{count:response.events.length,totalMatched:response.totalMatched,totalInBuffer:response.totalInBuffer,source,captureStatus,captureSource:"cdp",includeRaw,after,nextCursor:response.nextCursor,hasMore:response.hasMore,gap:response.gap,hint},events:response.events.map(event=>formatTrackingEvent(event,includeRaw))}}registerActions([{name:"tab_checkpoint",session:"page",handler:cdpCaptureCheckpoint},{name:"capture_checkpoint",session:"page",handler:cdpCaptureCheckpoint},{name:"get_requests",session:"page",handler:cdpGetRequests},{name:"get_logs",session:"page",handler:cdpGetLogs},{name:"get_events",session:"page",handler:cdpGetEvents}]);async function cdpRunActions(session,data,controlSource="local"){let{actions,tabId}=data;if(!Array.isArray(actions)||actions.length===0)throw new Error("actions must be a non-empty array");if(actions.length>50)throw new Error("actions array exceeds maximum of 50 steps");let results=[];for(let i=0;i<actions.length;i++){let step=actions[i],stepAction=String(step.action??"");if(!stepAction)return{results,completedSteps:results.length,totalSteps:actions.length,error:`Step ${i}: action must be a non-empty string`,failedStep:i};if(!isBrowserCommandAction(stepAction))return{results,completedSteps:results.length,totalSteps:actions.length,error:`Step ${i}: unsupported action "${stepAction}"`,failedStep:i};if(stepAction==="run_actions")return{results,completedSteps:results.length,totalSteps:actions.length,error:`Step ${i}: composite action "${stepAction}" is not allowed in run_actions`,failedStep:i};if(stepAction==="browser_release")return{results,completedSteps:results.length,totalSteps:actions.length,error:`Step ${i}: browser-level action "${stepAction}" is not allowed in run_actions`,failedStep:i};let mergedData={...step.data};tabId!==void 0&&mergedData.tabId===void 0&&(mergedData.tabId=tabId);try{let result=await dispatchCdpAction(session,stepAction,mergedData,controlSource);results.push({step:i,action:stepAction,success:!0,data:result})}catch(error48){let errorMessage2=error48 instanceof Error?error48.message:String(error48);return results.push({step:i,action:stepAction,success:!1,error:errorMessage2}),{results,completedSteps:i,totalSteps:actions.length,error:errorMessage2,failedStep:i}}}return{results,completedSteps:actions.length,totalSteps:actions.length}}async function cdpObservedPageAction(session,action,data,controlSource="local"){let{actionData,observe,diagnostics}=splitObservedActionPayload(action,data),{tabId}=actionData;if(typeof tabId!="number")throw new Error(`${action} requires a numeric tabId`);let pageSession=await session.getPageSession(tabId);if(await ensureControlledIndicator(pageSession,controlSource),observe===!1){if(!diagnostics)return dispatchCdpAction(session,action,actionData,controlSource);let cursor=captureCheckpoint(pageSession.buffers.capture),actionResult,actionFailure;try{actionResult=await dispatchCdpAction(session,action,actionData,controlSource)}catch(error48){actionFailure=describePageActionFailure(error48)}let result2={action:{name:action,success:actionFailure===void 0,...actionResult!==void 0?{data:actionResult}:{},...actionFailure||{}}};return actionFailure?.stage==="precondition"?result2:{...result2,diagnostics:await collectCdpPageDiagnostics(pageSession,cursor,diagnostics)}}let diagnosticsCursor,result=await runPageAct({action,actionData,observe},{startObservation:()=>startPageObservation(pageSession),finishObservation:(checkpoint,options)=>finishPageObservation(pageSession,checkpoint,options),startNavigationObserver:options=>startCdpNavigationObserver(session,pageSession,options.urlBefore,options),executeAction:(name,params)=>(diagnostics&&(diagnosticsCursor=captureCheckpoint(pageSession.buffers.capture)),dispatchCdpAction(session,name,{...params,tabId},controlSource)),finalizeObservation:observation=>observation.mode==="delta"?enrichCdpPageChangeSetWithRefs(pageSession,observation):Promise.resolve(observation),disposeObservation:()=>disposePageObservation(pageSession)});return!diagnostics||!diagnosticsCursor||result.action.stage==="precondition"?result:{...result,diagnostics:await collectCdpPageDiagnostics(pageSession,diagnosticsCursor,diagnostics)}}registerActions([{name:"run_actions",session:"browser",handler:cdpRunActions}]);import{randomUUID as randomUUID4}from"node:crypto";import{createReadStream}from"node:fs";var FILE_CHUNK_BYTES=256*1024,TRANSFER_ACTION_TIMEOUT_MS=15e3;async function sendFileChunks(transferId,fileIndex,file2,send){let chunkIndex=0,sendChunk=async chunk=>{await send("__send_request_file_chunk",{transferId,fileIndex,chunkIndex,base64:chunk.toString("base64")},TRANSFER_ACTION_TIMEOUT_MS),chunkIndex+=1};if(file2.filePath){for await(let chunk of createReadStream(file2.filePath,{highWaterMark:FILE_CHUNK_BYTES}))await sendChunk(Buffer.isBuffer(chunk)?chunk:Buffer.from(chunk));return}let content=file2.content;for(let offset=0;offset<content.byteLength;offset+=FILE_CHUNK_BYTES)await sendChunk(content.subarray(offset,offset+FILE_CHUNK_BYTES))}async function prepareFileTransfer(data,send){let files=await resolveSendRequestFiles(data.files??[]);if(files.length===0)throw new Error("files must contain at least one file");let transferId=randomUUID4();await send("__send_request_file_start",{transferId,files:files.map(file2=>file2.descriptor),url:data.url,withCookies:data.withCookies},TRANSFER_ACTION_TIMEOUT_MS);try{for(let index=0;index<files.length;index+=1)await sendFileChunks(transferId,index,files[index],send)}catch(error48){throw await send("__send_request_file_abort",{transferId},TRANSFER_ACTION_TIMEOUT_MS).catch(()=>{}),error48}let{files:_files,...request}=data;return{transferId,request}}async function abortFileTransfer(transferId,send){await send("__send_request_file_abort",{transferId},TRANSFER_ACTION_TIMEOUT_MS).catch(()=>{})}function hasSendRequestFiles(data){return!!data&&typeof data=="object"&&Array.isArray(data.files)&&data.files.length>0}function hasRunActionsSendRequestFiles(data){if(!data||typeof data!="object")return!1;let actions=data.actions;return Array.isArray(actions)&&actions.some(step=>step?.action==="send_request"&&hasSendRequestFiles(step.data))}async function sendRequestWithTransferredFiles(data,send){let prepared=await prepareFileTransfer(data,send);try{let requestTimeout=Number(data.timeout??3e4);return await send("__send_request_with_files",{...prepared.request,transferId:prepared.transferId},(Number.isFinite(requestTimeout)&&requestTimeout>0?requestTimeout:3e4)+5e3)}catch(error48){throw await abortFileTransfer(prepared.transferId,send),error48}}async function sendRunActionsWithTransferredFiles(data,send,resolveTimeoutMs){if(!Array.isArray(data.actions))throw new Error("actions must be an array");let preparedTransferIds=[];try{let actions=[];for(let index=0;index<data.actions.length;index+=1){let step=data.actions[index],action=String(step.action??"");if(action.startsWith("__"))throw new Error(`Step ${index}: internal action "${action}" is not available to clients`);if(action!=="send_request"||!hasSendRequestFiles(step.data)){actions.push(step);continue}let prepared=await prepareFileTransfer(step.data,send);preparedTransferIds.push(prepared.transferId),actions.push({action:"__send_request_with_files",data:{...prepared.request,transferId:prepared.transferId}})}let transformed={...data,actions};return await send("run_actions",transformed,resolveTimeoutMs(transformed))}finally{await Promise.all(preparedTransferIds.map(transferId=>abortFileTransfer(transferId,send)))}}import fs2 from"node:fs";import path2 from"node:path";import{spawn as spawn3,spawnSync}from"node:child_process";var processes=new Map,CONNECTORS_SUBDIR="connectors",REGISTRY_DIR=keyedDir(CONNECTORS_SUBDIR),OFFICIAL_NPM_REGISTRY="https://registry.npmjs.org",STATUS_POLL_MS=5e3;function recordFileFor(serverUrl){return keyedConfigFile(CONNECTORS_SUBDIR,serverUrl)}var logFn=()=>{},isDaemon=!1,sendToExtensionFn=()=>{},nativeHostVersion="unknown",lastPushedKey="",statusWatcher=null;function initCloudConnector(deps){logFn=deps.log,isDaemon=deps.isDaemonMode,sendToExtensionFn=deps.sendToExtension,nativeHostVersion=deps.version,startStatusWatcher()}function liveRecords(){return readLiveRecords(REGISTRY_DIR)}function reconcile(){let live=new Map;for(let record2 of liveRecords())live.set(record2.serverUrl,{serverUrl:record2.serverUrl,pid:record2.pid,...record2.connectorId?{connectorId:record2.connectorId}:{},...record2.name?{name:record2.name}:{}});for(let[serverUrl,entry]of processes)isAlive(entry.pid)?live.has(serverUrl)||live.set(serverUrl,{serverUrl,pid:entry.pid,...entry.connectorId?{connectorId:entry.connectorId}:{},...entry.name?{name:entry.name}:{}}):processes.delete(serverUrl);return Array.from(live.values())}function connectorsKey(connectors){return connectors.map(c=>`${c.serverUrl}@${c.pid}@${c.connectorId??""}@${c.name??""}`).sort().join("|")}function pushStatus(connectors){isDaemon||(lastPushedKey=connectorsKey(connectors),sendToExtensionFn({type:"cloud_connector_status_changed",data:{connectors}}))}function notifyStatusChanged(){pushStatus(reconcile())}function pushIfChanged(){let connectors=reconcile();return connectorsKey(connectors)!==lastPushedKey&&pushStatus(connectors),connectors}function startStatusWatcher(){isDaemon||statusWatcher||(statusWatcher=setInterval(()=>{try{pushIfChanged()}catch{}},STATUS_POLL_MS),statusWatcher.unref?.())}function registerConnector(serverUrl,pid,child){let record2=readRecord(recordFileFor(serverUrl)),entry={pid,serverUrl,...record2?.connectorId?{connectorId:record2.connectorId}:{},...record2?.name?{name:record2.name}:{},...child?{process:child}:{}};return processes.set(serverUrl,entry),notifyStatusChanged(),entry}function clearConnector(serverUrl,expected){let entry=processes.get(serverUrl);entry&&entry.pid!==expected.pid||expected.child&&entry?.process&&entry.process!==expected.child||(processes.delete(serverUrl),removeRecordIfPid(recordFileFor(serverUrl),expected.pid),notifyStatusChanged())}function findLiveConnector(serverUrl){let entry=processes.get(serverUrl);if(entry&&isAlive(entry.pid))return entry.pid;let record2=readRecord(recordFileFor(serverUrl));return record2&&isAlive(record2.pid)?record2.pid:(entry&&processes.delete(serverUrl),record2&&removeRecordIfPid(recordFileFor(serverUrl),record2.pid),null)}function findBin(bin,env){let lookupCommand=process.platform==="win32"?"where":"which",result=spawnSync(lookupCommand,[bin],{encoding:"utf-8",env});return result.status===0&&result.stdout.split(/\r?\n/).find(Boolean)||null}function getBinVersion(binPath){try{let result=spawnSync(process.execPath,[binPath,"--version"],{encoding:"utf-8",timeout:5e3});return result.status===0?result.stdout.trim():null}catch{return null}}function makeDirectCommand(connectorPath){return process.platform!=="win32"?{command:process.execPath,argsPrefix:[connectorPath],displayName:`${process.execPath} ${connectorPath}`}:{command:connectorPath,argsPrefix:[],displayName:connectorPath}}function resolveCloudConnectorCommand(){let connectorBin=process.platform==="win32"?"mearl-cloud-connector.cmd":"mearl-cloud-connector",pathDelimiter=process.platform==="win32"?";":":",nodeDir=path2.dirname(process.execPath),enrichedPath=[nodeDir,process.env.PATH].filter(Boolean).join(pathDelimiter),enrichedEnv={...process.env,PATH:enrichedPath},connectorPath=findBin(connectorBin,enrichedEnv);if(connectorPath){let installedVersion=getBinVersion(connectorPath);if(installedVersion===nativeHostVersion)return logFn(`Cloud connector ${installedVersion} found at ${connectorPath}`),makeDirectCommand(connectorPath);logFn(`Cloud connector version mismatch: installed=${installedVersion}, expected=${nativeHostVersion}`)}let npmBin=process.platform==="win32"?"npm.cmd":"npm",npmPath=path2.join(nodeDir,npmBin),npmCommand=fs2.existsSync(npmPath)?npmPath:npmBin,targetPackage=`@mearl/cloud-connector@${nativeHostVersion}`;logFn(`Installing ${targetPackage} globally via ${npmCommand}...`);let install=spawnSync(npmCommand,["install","-g",targetPackage,"--prefer-offline",`--registry=${OFFICIAL_NPM_REGISTRY}`],{encoding:"utf-8",env:enrichedEnv,timeout:3e4});if(install.status===0){let newPath=findBin(connectorBin,enrichedEnv);if(newPath)return logFn(`Global install succeeded: ${newPath}`),makeDirectCommand(newPath)}logFn(`Global install failed (status=${install.status}), falling back to npx`),install.stderr&&logFn(install.stderr.trim());let npxBin=process.platform==="win32"?"npx.cmd":"npx",npxPath=path2.join(nodeDir,npxBin),npxCommand=fs2.existsSync(npxPath)?npxPath:npxBin;return{command:npxCommand,argsPrefix:[`@mearl/cloud-connector@${nativeHostVersion}`],displayName:`${npxCommand} @mearl/cloud-connector@${nativeHostVersion}`,env:enrichedEnv}}function startCloudConnector(serverUrl){return new Promise(resolve2=>{let existingPid=findLiveConnector(serverUrl);if(existingPid){logFn(`Reusing existing cloud connector for ${serverUrl} (pid=${existingPid})`);let entry=registerConnector(serverUrl,existingPid);resolve2({success:!0,pid:existingPid,...entry.connectorId?{connectorId:entry.connectorId}:{},...entry.name?{name:entry.name}:{},reused:!0});return}let connectorCommand=resolveCloudConnectorCommand();logFn(`Starting cloud connector via ${connectorCommand.displayName}`);let child=spawn3(connectorCommand.command,[...connectorCommand.argsPrefix,serverUrl,"--fail-fast"],{detached:!0,env:connectorCommand.env,stdio:["ignore","pipe","pipe"],windowsHide:!0}),settled=!1,outputBuffer="",startupTimer=setTimeout(()=>{finish(!1,{error:"Cloud connector startup timeout"}),child.kill()},6e4),finish=(ok,result={})=>{if(!settled)if(settled=!0,clearTimeout(startupTimer),ok&&child.pid){let entry=registerConnector(serverUrl,child.pid,child);resolve2({success:!0,pid:child.pid,...entry.connectorId?{connectorId:entry.connectorId}:{},...entry.name?{name:entry.name}:{}})}else resolve2({success:!1,error:result.error||"Failed to spawn cloud connector"})};child.once("error",error48=>{logFn(`Failed to spawn cloud connector: ${error48.message}`),finish(!1,{error:error48.message})});let handleOutput=chunk=>{let text=chunk.toString();outputBuffer=(outputBuffer+text).slice(-2e3),logFn(`[CloudConnector] ${text.trim()}`),text.includes("[CloudConnector] Connected to")&&finish(!0)};child.stdout?.on("data",handleOutput),child.stderr?.on("data",handleOutput),child.once("spawn",()=>{child.once("exit",(code,signal)=>{child.pid&&clearConnector(serverUrl,{pid:child.pid,child}),logFn(`Cloud connector exited for ${serverUrl}: code=${code??"null"} signal=${signal??"null"}`),settled||finish(!1,{error:outputBuffer.trim()||`Cloud connector exited before connected: code=${code??"null"} signal=${signal??"null"}`})}),child.unref()})})}function stopCloudConnector(serverUrl){let pid=processes.get(serverUrl)?.pid??readRecord(recordFileFor(serverUrl))?.pid;if(!pid)return{success:!1,error:"Cloud connector not found"};try{return isAlive(pid)&&process.kill(pid),clearConnector(serverUrl,{pid}),logFn(`Stopped cloud connector for ${serverUrl} (pid=${pid})`),{success:!0}}catch(error48){let err=error48;return err.code==="ESRCH"?(clearConnector(serverUrl,{pid}),{success:!0}):(logFn(`Failed to stop cloud connector: ${err.message}`),{success:!1,error:err.message})}}function listCloudConnectors(){return{connectors:pushIfChanged()}}function currentCapture(pageSession){return{tabId:pageSession.tabId,cursor:captureCheckpoint(pageSession.buffers.capture),timestampMs:Date.now(),captureStatus:pageSession.buffers.capture.currentSequence===0?"armed":"active"}}async function cdpTabOpen(session,data,controlSource="local"){let{url:url2,active=!1,emulation,reuse="never",match,appProfile}=data;if(!url2||typeof url2!="string")throw new Error("Invalid url: url must be a non-empty string");if(!["never","prefer","require"].includes(reuse))throw new Error('Invalid reuse: expected "never", "prefer", or "require"');if(data.os!==void 0&&data.os!=="ios"&&data.os!=="android")throw new Error('Invalid os: expected "ios" or "android"');if(data.os!==void 0&&!appProfile)throw new Error("tab_open os requires appProfile.");if(data.bridgeConfig!==void 0&&!appProfile)throw new Error("tab_open bridgeConfig requires appProfile.");let resolvedProfile=appProfile?resolveCdpAppProfile(appProfile,{os:data.os,devicePreset:emulation?.preset,orientation:emulation?.orientation,bridgeConfig:data.bridgeConfig}):void 0,emulationConfig=emulation?resolveEmulationConfig({...emulation,enabled:!0}):void 0,browserClient=await session.getBrowserClient();if(reuse!=="never"){let pages=((await browserClient.sendCommand("Target.getTargets")).targetInfos??[]).filter(target=>target.type==="page"&&!target.url.startsWith("chrome-extension://")&&!target.url.startsWith("about:")&&!target.url.startsWith("chrome://")),existing=selectMatchingTab(pages,url2,match);if(existing){if(emulation||appProfile)throw new Error("tab_open cannot apply pre-navigation emulation or appProfile to a reused tab.");active&&await browserClient.sendCommand("Target.activateTarget",{targetId:existing.targetId});let tabId2=await session.ensureTargetRegistered(existing.targetId),pageSession2=await session.getPageSession(tabId2);await ensureControlledIndicator(pageSession2,controlSource);let capture2=currentCapture(pageSession2);return{tabId:tabId2,url:existing.url??url2,title:existing.title??"",opened:!1,reused:!0,capture:capture2}}if(reuse==="require")throw new Error('tab_open did not find a matching existing tab and reuse is "require".')}let targetId=(await browserClient.sendCommand("Target.createTarget",{url:"about:blank",background:!active})).targetId,tabId=await session.registerTarget(targetId),pageSession=await session.getPageSession(tabId);await ensureControlledIndicator(pageSession,controlSource);let capture=currentCapture(pageSession);if(emulationConfig){for(let{method,params,optional:optional2}of buildEnableEmulationCommands(emulationConfig))await pageSession.client.sendCommand(method,params).catch(error48=>{if(!optional2)throw error48});pageSession.emulation={mobile:emulationConfig.mobile,touch:emulationConfig.touch,config:emulationConfig,deviceShell:emulation?.deviceShell===!0},emulation?.deviceShell&&await applyCdpDeviceShell(pageSession,emulationConfig)}resolvedProfile&&await applyResolvedCdpAppProfile(pageSession,resolvedProfile),await pageSession.client.sendCommand("Page.navigate",{url:url2}),emulation?.deviceShell?await waitForCdpDeviceShellLoad(pageSession):resolvedProfile?await waitForCdpAppProfileLoad(pageSession):await waitForPageLoad(pageSession,3e4);let targetInfo=await browserClient.sendCommand("Target.getTargetInfo",{targetId}).then(result2=>result2.targetInfo).catch(()=>null);return{tabId,url:targetInfo?.url??url2,title:targetInfo?.title??"",opened:!0,reused:!1,capture,...emulationConfig&&{emulation:{preset:emulationConfig.presetName,viewport:{width:emulationConfig.width,height:emulationConfig.height,deviceScaleFactor:emulationConfig.deviceScaleFactor,scale:emulationConfig.scale??1},userAgent:emulationConfig.userAgent,mobile:emulationConfig.mobile,touch:emulationConfig.touch,orientation:emulationConfig.orientation,deviceShell:emulation?.deviceShell===!0}},...resolvedProfile&&{appProfile:{profile:resolvedProfile.profile.profile,label:resolvedProfile.profile.label,userAgent:resolvedProfile.profile.ua,os:resolvedProfile.profile.injected.platform==="Android"?"android":"ios"}}}}async function cdpTabClose(session,data){let{tabId}=data;if(typeof tabId!="number")throw new Error("Invalid tabId: tabId must be a number");let browserClient=await session.getBrowserClient(),pageSession=await session.getPageSession(tabId);return await browserClient.sendCommand("Target.closeTarget",{targetId:pageSession.targetId}),{success:!0}}async function cdpTabList(session,_data){let pages=((await(await session.getBrowserClient()).sendCommand("Target.getTargets")).targetInfos??[]).filter(t=>t.type==="page"&&!t.url.startsWith("chrome-extension://")&&!t.url.startsWith("about:")&&!t.url.startsWith("chrome://")),tabs=await Promise.all(pages.map(async t=>{let tabId=await session.ensureTargetRegistered(t.targetId);return{id:tabId,tabId,url:t.url,title:t.title??"",active:!1}}));return{tabs,count:tabs.length}}registerActions([{name:"tab_open",session:"browser",handler:cdpTabOpen},{name:"tab_close",session:"browser",handler:cdpTabClose},{name:"tab_list",session:"browser",handler:cdpTabList}]);var GET_DRAG_COORDS_FROM_NODE_SRC=getDragCoordsFromNode.toString();function resolveSnapshotRef(session,ref){let entry=resolvePageRef(session,ref);if(!entry)throw new PageActionPreconditionError(`Ref ${ref} not found. Run page_snapshot first to get fresh refs.`);return entry}async function withSnapshotRef(session,ref,operation){let entry=resolveSnapshotRef(session,ref);try{return await operation(entry)}catch(error48){throw deletePageRef(session,ref),error48}}async function clickBySelectorJs(session,selector){let value=(await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`(() => {
|
|
703
|
+
})()`,result=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression,returnByValue:!0,awaitPromise:!0},timeoutMs+2e3),error48=evaluationError(result);if(error48)throw new Error(error48);let changeSet=result.result?.value;if(!changeSet||changeSet.mode!=="delta")throw new Error("Page observer did not return a change set");return changeSet}async function disposePageObservation(session){await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`(${DISPOSE_PAGE_OBSERVER_SRC})()`,returnByValue:!1}).catch(()=>{})}function filterRequests(buffers,opts){let pattern=opts.filter?compileTextPattern(opts.filter):void 0;return queryCapturedEntries(buffers.requests.filter(request=>Number.isSafeInteger(request.captureSequence)),buffers.capture,{after:opts.after,since:opts.since,limit:opts.count??10},request=>(!opts.source||opts.source==="all"||request.source===opts.source)&&(!pattern||matchesTextPattern(request.url,pattern)||matchesTextPattern(request.apiName,pattern)),buffers.capture.droppedRequestsThroughSequence,"requests")}async function cdpGetRequests(session,data){let opts={count:data.count??10,filter:data.filter,since:data.since,after:data.after,source:data.source,applyHiddenFilter:data.applyHiddenFilter!==!1},captured=filterRequests(session.buffers,opts),serializeOpts={includeBody:data.includeBody!==!1,includeHeaders:data.includeHeaders===!0,maxBodySize:data.maxBodySize??5e4,fields:data.fields,keysOnly:data.keysOnly===!0};return{meta:{count:captured.entries.length,totalMatched:captured.totalMatched,totalInBuffer:session.buffers.requests.length,filter:data.filter,since:data.since,after:data.after,nextCursor:captured.nextCursor,hasMore:captured.hasMore,gap:captured.gap,source:"cdp"},requests:captured.entries.map(r=>serializeRequest(r,serializeOpts))}}async function cdpGetLogs(session,data){let{level,since,after,limit=100,filter}=data,pattern=filter?compileTextPattern(filter):void 0,captured=queryCapturedEntries(session.buffers.logs,session.buffers.capture,{after,since,limit},log2=>(!level||level==="all"||log2.level===level)&&(!pattern||matchesTextPattern(log2.message,pattern)||log2.args.some(arg=>matchesTextPattern(arg,pattern))),session.buffers.capture.droppedLogsThroughSequence,"logs"),captureStatus=session.buffers.logs.length===0?"armed":"active";return{meta:{count:captured.entries.length,totalMatched:captured.totalMatched,totalInBuffer:session.buffers.logs.length,level:level||"all",since,after,filter,nextCursor:captured.nextCursor,hasMore:captured.hasMore,gap:captured.gap,captureStatus,...captureStatus==="armed"&&{hint:"Log capture is active, but this tab has no captured history yet. Reload the current tab or repeat the triggering action, then call get_logs again."},source:"cdp"},logs:captured.entries}}async function cdpCaptureCheckpoint(session,_data){return{tabId:session.tabId,cursor:captureCheckpoint(session.buffers.capture),timestampMs:Date.now(),captureStatus:session.buffers.capture.currentSequence===0?"armed":"active"}}async function collectCdpPageDiagnostics(session,after,diagnostics){let result={};if(diagnostics.logs){let options=diagnostics.logs===!0?{level:"error",limit:100}:{level:"error",limit:100,...diagnostics.logs};result.logs=await cdpGetLogs(session,{...options,after})}if(diagnostics.requests){let options=diagnostics.requests===!0?{source:"all",includeBody:!1,count:100}:{source:"all",includeBody:!1,count:100,...diagnostics.requests};result.requests=await cdpGetRequests(session,{...options,after})}if(diagnostics.events){let options=diagnostics.events===!0?{source:"all",limit:100}:{source:"all",limit:100,...diagnostics.events};result.events=await cdpGetEvents(session,{...options,after})}return result}async function cdpGetEvents(session,data){let{source="all",event_type,since,after,limit=20,filter,includeRaw=!1}=data,response=queryCapturedTrackingEvents(session.buffers.events,session.buffers.capture,{source,event_type,since,after,limit,filter},session.buffers.capture.droppedEventsThroughSequence),captureStatus=response.totalInBuffer===0?"armed":"active",hint=response.events.length===0&&captureStatus==="armed"?TRACKING_CAPTURE_ARMED_HINT:void 0;return{meta:{count:response.events.length,totalMatched:response.totalMatched,totalInBuffer:response.totalInBuffer,source,captureStatus,captureSource:"cdp",includeRaw,after,nextCursor:response.nextCursor,hasMore:response.hasMore,gap:response.gap,hint},events:response.events.map(event=>formatTrackingEvent(event,includeRaw))}}registerActions([{name:"tab_checkpoint",session:"page",handler:cdpCaptureCheckpoint},{name:"capture_checkpoint",session:"page",handler:cdpCaptureCheckpoint},{name:"get_requests",session:"page",handler:cdpGetRequests},{name:"get_logs",session:"page",handler:cdpGetLogs},{name:"get_events",session:"page",handler:cdpGetEvents}]);async function cdpRunActions(session,data,controlSource="local"){let{actions,tabId}=data;if(!Array.isArray(actions)||actions.length===0)throw new Error("actions must be a non-empty array");if(actions.length>50)throw new Error("actions array exceeds maximum of 50 steps");let results=[];for(let i=0;i<actions.length;i++){let step=actions[i],stepAction=String(step.action??"");if(!stepAction)return{results,completedSteps:results.length,totalSteps:actions.length,error:`Step ${i}: action must be a non-empty string`,failedStep:i};if(!isBrowserCommandAction(stepAction))return{results,completedSteps:results.length,totalSteps:actions.length,error:`Step ${i}: unsupported action "${stepAction}"`,failedStep:i};if(stepAction==="run_actions")return{results,completedSteps:results.length,totalSteps:actions.length,error:`Step ${i}: composite action "${stepAction}" is not allowed in run_actions`,failedStep:i};if(stepAction==="browser_release")return{results,completedSteps:results.length,totalSteps:actions.length,error:`Step ${i}: browser-level action "${stepAction}" is not allowed in run_actions`,failedStep:i};let mergedData={...step.data};tabId!==void 0&&mergedData.tabId===void 0&&(mergedData.tabId=tabId);try{let result=await dispatchCdpAction(session,stepAction,mergedData,controlSource);results.push({step:i,action:stepAction,success:!0,data:result})}catch(error48){let errorMessage2=error48 instanceof Error?error48.message:String(error48);return results.push({step:i,action:stepAction,success:!1,error:errorMessage2}),{results,completedSteps:i,totalSteps:actions.length,error:errorMessage2,failedStep:i}}}return{results,completedSteps:actions.length,totalSteps:actions.length}}async function cdpObservedPageAction(session,action,data,controlSource="local"){let{actionData,observe,diagnostics}=splitObservedActionPayload(action,data),{tabId}=actionData;if(typeof tabId!="number")throw new Error(`${action} requires a numeric tabId`);let pageSession=await session.getPageSession(tabId);if(await ensureControlledIndicator(pageSession,controlSource),observe===!1){if(!diagnostics)return dispatchCdpAction(session,action,actionData,controlSource);let cursor=captureCheckpoint(pageSession.buffers.capture),actionResult,actionFailure;try{actionResult=await dispatchCdpAction(session,action,actionData,controlSource)}catch(error48){actionFailure=describePageActionFailure(error48)}let result2={action:{name:action,success:actionFailure===void 0,...actionResult!==void 0?{data:actionResult}:{},...actionFailure||{}}};return actionFailure?.stage==="precondition"?result2:{...result2,diagnostics:await collectCdpPageDiagnostics(pageSession,cursor,diagnostics)}}let diagnosticsCursor,result=await runPageAct({action,actionData,observe},{startObservation:()=>startPageObservation(pageSession),finishObservation:(checkpoint,options)=>finishPageObservation(pageSession,checkpoint,options),startNavigationObserver:options=>startCdpNavigationObserver(session,pageSession,options.urlBefore,options),executeAction:(name,params)=>(diagnostics&&(diagnosticsCursor=captureCheckpoint(pageSession.buffers.capture)),dispatchCdpAction(session,name,{...params,tabId},controlSource)),finalizeObservation:observation=>observation.mode==="delta"?enrichCdpPageChangeSetWithRefs(pageSession,observation):Promise.resolve(observation),disposeObservation:()=>disposePageObservation(pageSession)});return!diagnostics||!diagnosticsCursor||result.action.stage==="precondition"?result:{...result,diagnostics:await collectCdpPageDiagnostics(pageSession,diagnosticsCursor,diagnostics)}}registerActions([{name:"run_actions",session:"browser",handler:cdpRunActions}]);import{randomUUID as randomUUID4}from"node:crypto";import{createReadStream}from"node:fs";var FILE_CHUNK_BYTES=256*1024,TRANSFER_ACTION_TIMEOUT_MS=15e3;async function sendFileChunks(transferId,fileIndex,file2,send){let chunkIndex=0,sendChunk=async chunk=>{await send("__send_request_file_chunk",{transferId,fileIndex,chunkIndex,base64:chunk.toString("base64")},TRANSFER_ACTION_TIMEOUT_MS),chunkIndex+=1};if(file2.filePath){for await(let chunk of createReadStream(file2.filePath,{highWaterMark:FILE_CHUNK_BYTES}))await sendChunk(Buffer.isBuffer(chunk)?chunk:Buffer.from(chunk));return}let content=file2.content;for(let offset=0;offset<content.byteLength;offset+=FILE_CHUNK_BYTES)await sendChunk(content.subarray(offset,offset+FILE_CHUNK_BYTES))}async function prepareFileTransfer(data,send){let files=await resolveSendRequestFiles(data.files??[]);if(files.length===0)throw new Error("files must contain at least one file");let transferId=randomUUID4();await send("__send_request_file_start",{transferId,files:files.map(file2=>file2.descriptor),url:data.url,withCookies:data.withCookies},TRANSFER_ACTION_TIMEOUT_MS);try{for(let index=0;index<files.length;index+=1)await sendFileChunks(transferId,index,files[index],send)}catch(error48){throw await send("__send_request_file_abort",{transferId},TRANSFER_ACTION_TIMEOUT_MS).catch(()=>{}),error48}let{files:_files,...request}=data;return{transferId,request}}async function abortFileTransfer(transferId,send){await send("__send_request_file_abort",{transferId},TRANSFER_ACTION_TIMEOUT_MS).catch(()=>{})}function hasSendRequestFiles(data){return!!data&&typeof data=="object"&&Array.isArray(data.files)&&data.files.length>0}function hasRunActionsSendRequestFiles(data){if(!data||typeof data!="object")return!1;let actions=data.actions;return Array.isArray(actions)&&actions.some(step=>step?.action==="send_request"&&hasSendRequestFiles(step.data))}async function sendRequestWithTransferredFiles(data,send){let prepared=await prepareFileTransfer(data,send);try{let requestTimeout=Number(data.timeout??3e4);return await send("__send_request_with_files",{...prepared.request,transferId:prepared.transferId},(Number.isFinite(requestTimeout)&&requestTimeout>0?requestTimeout:3e4)+5e3)}catch(error48){throw await abortFileTransfer(prepared.transferId,send),error48}}async function sendRunActionsWithTransferredFiles(data,send,resolveTimeoutMs){if(!Array.isArray(data.actions))throw new Error("actions must be an array");let preparedTransferIds=[];try{let actions=[];for(let index=0;index<data.actions.length;index+=1){let step=data.actions[index],action=String(step.action??"");if(action.startsWith("__"))throw new Error(`Step ${index}: internal action "${action}" is not available to clients`);if(action!=="send_request"||!hasSendRequestFiles(step.data)){actions.push(step);continue}let prepared=await prepareFileTransfer(step.data,send);preparedTransferIds.push(prepared.transferId),actions.push({action:"__send_request_with_files",data:{...prepared.request,transferId:prepared.transferId}})}let transformed={...data,actions};return await send("run_actions",transformed,resolveTimeoutMs(transformed))}finally{await Promise.all(preparedTransferIds.map(transferId=>abortFileTransfer(transferId,send)))}}import fs2 from"node:fs";import path2 from"node:path";import{spawn as spawn3,spawnSync}from"node:child_process";var processes=new Map,CONNECTORS_SUBDIR="connectors",REGISTRY_DIR=keyedDir(CONNECTORS_SUBDIR),OFFICIAL_NPM_REGISTRY="https://registry.npmjs.org",STATUS_POLL_MS=5e3;function recordFileFor(serverUrl){return keyedConfigFile(CONNECTORS_SUBDIR,serverUrl)}var logFn=()=>{},isDaemon=!1,sendToExtensionFn=()=>{},nativeHostVersion="unknown",lastPushedKey="",statusWatcher=null;function initCloudConnector(deps){logFn=deps.log,isDaemon=deps.isDaemonMode,sendToExtensionFn=deps.sendToExtension,nativeHostVersion=deps.version,startStatusWatcher()}function liveRecords(){return readLiveRecords(REGISTRY_DIR)}function reconcile(){let live=new Map;for(let record2 of liveRecords())live.set(record2.serverUrl,{serverUrl:record2.serverUrl,pid:record2.pid,...record2.connectorId?{connectorId:record2.connectorId}:{},...record2.name?{name:record2.name}:{}});for(let[serverUrl,entry]of processes)isAlive(entry.pid)?live.has(serverUrl)||live.set(serverUrl,{serverUrl,pid:entry.pid,...entry.connectorId?{connectorId:entry.connectorId}:{},...entry.name?{name:entry.name}:{}}):processes.delete(serverUrl);return Array.from(live.values())}function connectorsKey(connectors){return connectors.map(c=>`${c.serverUrl}@${c.pid}@${c.connectorId??""}@${c.name??""}`).sort().join("|")}function pushStatus(connectors){isDaemon||(lastPushedKey=connectorsKey(connectors),sendToExtensionFn({type:"cloud_connector_status_changed",data:{connectors}}))}function notifyStatusChanged(){pushStatus(reconcile())}function pushIfChanged(){let connectors=reconcile();return connectorsKey(connectors)!==lastPushedKey&&pushStatus(connectors),connectors}function startStatusWatcher(){isDaemon||statusWatcher||(statusWatcher=setInterval(()=>{try{pushIfChanged()}catch{}},STATUS_POLL_MS),statusWatcher.unref?.())}function registerConnector(serverUrl,pid,child){let record2=readRecord(recordFileFor(serverUrl)),entry={pid,serverUrl,...record2?.connectorId?{connectorId:record2.connectorId}:{},...record2?.name?{name:record2.name}:{},...child?{process:child}:{}};return processes.set(serverUrl,entry),notifyStatusChanged(),entry}function clearConnector(serverUrl,expected){let entry=processes.get(serverUrl);entry&&entry.pid!==expected.pid||expected.child&&entry?.process&&entry.process!==expected.child||(processes.delete(serverUrl),removeRecordIfPid(recordFileFor(serverUrl),expected.pid),notifyStatusChanged())}function findLiveConnector(serverUrl){let entry=processes.get(serverUrl);if(entry&&isAlive(entry.pid))return entry.pid;let record2=readRecord(recordFileFor(serverUrl));return record2&&isAlive(record2.pid)?record2.pid:(entry&&processes.delete(serverUrl),record2&&removeRecordIfPid(recordFileFor(serverUrl),record2.pid),null)}function findBin(bin,env){let lookupCommand=process.platform==="win32"?"where":"which",result=spawnSync(lookupCommand,[bin],{encoding:"utf-8",env});return result.status===0&&result.stdout.split(/\r?\n/).find(Boolean)||null}function getBinVersion(binPath){try{let result=spawnSync(process.execPath,[binPath,"--version"],{encoding:"utf-8",timeout:5e3});return result.status===0?result.stdout.trim():null}catch{return null}}function makeDirectCommand(connectorPath){return process.platform!=="win32"?{command:process.execPath,argsPrefix:[connectorPath],displayName:`${process.execPath} ${connectorPath}`}:{command:connectorPath,argsPrefix:[],displayName:connectorPath}}function resolveCloudConnectorCommand(){let connectorBin=process.platform==="win32"?"mearl-cloud-connector.cmd":"mearl-cloud-connector",pathDelimiter=process.platform==="win32"?";":":",nodeDir=path2.dirname(process.execPath),enrichedPath=[nodeDir,process.env.PATH].filter(Boolean).join(pathDelimiter),enrichedEnv={...process.env,PATH:enrichedPath},connectorPath=findBin(connectorBin,enrichedEnv);if(connectorPath){let installedVersion=getBinVersion(connectorPath);if(installedVersion===nativeHostVersion)return logFn(`Cloud connector ${installedVersion} found at ${connectorPath}`),makeDirectCommand(connectorPath);logFn(`Cloud connector version mismatch: installed=${installedVersion}, expected=${nativeHostVersion}`)}let npmBin=process.platform==="win32"?"npm.cmd":"npm",npmPath=path2.join(nodeDir,npmBin),npmCommand=fs2.existsSync(npmPath)?npmPath:npmBin,targetPackage=`@mearl/cloud-connector@${nativeHostVersion}`;logFn(`Installing ${targetPackage} globally via ${npmCommand}...`);let install=spawnSync(npmCommand,["install","-g",targetPackage,"--prefer-offline",`--registry=${OFFICIAL_NPM_REGISTRY}`],{encoding:"utf-8",env:enrichedEnv,timeout:3e4});if(install.status===0){let newPath=findBin(connectorBin,enrichedEnv);if(newPath)return logFn(`Global install succeeded: ${newPath}`),makeDirectCommand(newPath)}logFn(`Global install failed (status=${install.status}), falling back to npx`),install.stderr&&logFn(install.stderr.trim());let npxBin=process.platform==="win32"?"npx.cmd":"npx",npxPath=path2.join(nodeDir,npxBin),npxCommand=fs2.existsSync(npxPath)?npxPath:npxBin;return{command:npxCommand,argsPrefix:[`@mearl/cloud-connector@${nativeHostVersion}`],displayName:`${npxCommand} @mearl/cloud-connector@${nativeHostVersion}`,env:enrichedEnv}}function startCloudConnector(serverUrl){return new Promise(resolve2=>{let existingPid=findLiveConnector(serverUrl);if(existingPid){logFn(`Reusing existing cloud connector for ${serverUrl} (pid=${existingPid})`);let entry=registerConnector(serverUrl,existingPid);resolve2({success:!0,pid:existingPid,...entry.connectorId?{connectorId:entry.connectorId}:{},...entry.name?{name:entry.name}:{},reused:!0});return}let connectorCommand=resolveCloudConnectorCommand();logFn(`Starting cloud connector via ${connectorCommand.displayName}`);let child=spawn3(connectorCommand.command,[...connectorCommand.argsPrefix,serverUrl,"--fail-fast"],{detached:!0,env:connectorCommand.env,stdio:["ignore","pipe","pipe"],windowsHide:!0}),settled=!1,outputBuffer="",startupTimer=setTimeout(()=>{finish(!1,{error:"Cloud connector startup timeout"}),child.kill()},6e4),finish=(ok,result={})=>{if(!settled)if(settled=!0,clearTimeout(startupTimer),ok&&child.pid){let entry=registerConnector(serverUrl,child.pid,child);resolve2({success:!0,pid:child.pid,...entry.connectorId?{connectorId:entry.connectorId}:{},...entry.name?{name:entry.name}:{}})}else resolve2({success:!1,error:result.error||"Failed to spawn cloud connector"})};child.once("error",error48=>{logFn(`Failed to spawn cloud connector: ${error48.message}`),finish(!1,{error:error48.message})});let handleOutput=chunk=>{let text=chunk.toString();outputBuffer=(outputBuffer+text).slice(-2e3),logFn(`[CloudConnector] ${text.trim()}`),text.includes("[CloudConnector] Connected to")&&finish(!0)};child.stdout?.on("data",handleOutput),child.stderr?.on("data",handleOutput),child.once("spawn",()=>{child.once("exit",(code,signal)=>{child.pid&&clearConnector(serverUrl,{pid:child.pid,child}),logFn(`Cloud connector exited for ${serverUrl}: code=${code??"null"} signal=${signal??"null"}`),settled||finish(!1,{error:outputBuffer.trim()||`Cloud connector exited before connected: code=${code??"null"} signal=${signal??"null"}`})}),child.unref()})})}function stopCloudConnector(serverUrl){let pid=processes.get(serverUrl)?.pid??readRecord(recordFileFor(serverUrl))?.pid;if(!pid)return{success:!1,error:"Cloud connector not found"};try{return isAlive(pid)&&process.kill(pid),clearConnector(serverUrl,{pid}),logFn(`Stopped cloud connector for ${serverUrl} (pid=${pid})`),{success:!0}}catch(error48){let err=error48;return err.code==="ESRCH"?(clearConnector(serverUrl,{pid}),{success:!0}):(logFn(`Failed to stop cloud connector: ${err.message}`),{success:!1,error:err.message})}}function listCloudConnectors(){return{connectors:pushIfChanged()}}function currentCapture(pageSession){return{tabId:pageSession.tabId,cursor:captureCheckpoint(pageSession.buffers.capture),timestampMs:Date.now(),captureStatus:pageSession.buffers.capture.currentSequence===0?"armed":"active"}}async function cdpTabOpen(session,data,controlSource="local"){let{url:url2,active=!1,emulation,reuse="never",match,appProfile}=data;if(!url2||typeof url2!="string")throw new Error("Invalid url: url must be a non-empty string");if(!["never","prefer","require"].includes(reuse))throw new Error('Invalid reuse: expected "never", "prefer", or "require"');if(data.os!==void 0&&data.os!=="ios"&&data.os!=="android")throw new Error('Invalid os: expected "ios" or "android"');if(data.os!==void 0&&!appProfile)throw new Error("tab_open os requires appProfile.");if(data.bridgeConfig!==void 0&&!appProfile)throw new Error("tab_open bridgeConfig requires appProfile.");let resolvedProfile=appProfile?resolveCdpAppProfile(appProfile,{os:data.os,devicePreset:emulation?.preset,orientation:emulation?.orientation,bridgeConfig:data.bridgeConfig}):void 0,emulationConfig=emulation?resolveEmulationConfig({...emulation,enabled:!0}):void 0,splitScreen=emulation?.deviceShell===!0&&emulation?.splitScreen===!0&&emulationConfig?.orientation==="landscape"&&!!resolvedProfile,browserClient=await session.getBrowserClient();if(reuse!=="never"){let pages=((await browserClient.sendCommand("Target.getTargets")).targetInfos??[]).filter(target=>target.type==="page"&&isImplicitlySelectablePageUrl(target.url)),existing=selectMatchingTab(pages,url2,match);if(existing){if(emulation||appProfile)throw new Error("tab_open cannot apply pre-navigation emulation or appProfile to a reused tab.");active&&await browserClient.sendCommand("Target.activateTarget",{targetId:existing.targetId});let tabId2=await session.ensureTargetRegistered(existing.targetId),pageSession2=await session.getPageSession(tabId2);await ensureControlledIndicator(pageSession2,controlSource);let capture2=currentCapture(pageSession2);return{tabId:tabId2,url:existing.url??url2,title:existing.title??"",opened:!1,reused:!0,capture:capture2}}if(reuse==="require")throw new Error('tab_open did not find a matching existing tab and reuse is "require".')}let targetId=(await browserClient.sendCommand("Target.createTarget",{url:"about:blank",background:!active})).targetId,tabId=await session.registerTarget(targetId),pageSession=await session.getPageSession(tabId);await ensureControlledIndicator(pageSession,controlSource);let capture=currentCapture(pageSession);if(emulationConfig){for(let{method,params,optional:optional2}of buildEnableEmulationCommands(emulationConfig))await pageSession.client.sendCommand(method,params).catch(error48=>{if(!optional2)throw error48});pageSession.emulation={mobile:emulationConfig.mobile,touch:emulationConfig.touch,config:emulationConfig,deviceShell:emulation?.deviceShell===!0,splitScreen},emulation?.deviceShell&&await applyCdpDeviceShell(pageSession,emulationConfig,{rootContainerManagedByApp:splitScreen})}resolvedProfile&&await applyResolvedCdpAppProfile(pageSession,resolvedProfile),await pageSession.client.sendCommand("Page.navigate",{url:url2}),emulation?.deviceShell?await waitForCdpDeviceShellLoad(pageSession):resolvedProfile?await waitForCdpAppProfileLoad(pageSession):await waitForPageLoad(pageSession,3e4);let targetInfo=await browserClient.sendCommand("Target.getTargetInfo",{targetId}).then(result2=>result2.targetInfo).catch(()=>null),openedUrl=targetInfo?.url??url2;return{tabId,url:openedUrl,title:targetInfo?.title??"",opened:!0,reused:!1,capture,...!isImplicitlySelectablePageUrl(openedUrl)&&{note:"This URL is excluded from implicit CDP target selection. Pass this tabId to subsequent page actions."},...emulationConfig&&{emulation:{preset:emulationConfig.presetName,viewport:{width:emulationConfig.width,height:emulationConfig.height,deviceScaleFactor:emulationConfig.deviceScaleFactor,scale:emulationConfig.scale??1},userAgent:emulationConfig.userAgent,mobile:emulationConfig.mobile,touch:emulationConfig.touch,orientation:emulationConfig.orientation,deviceShell:emulation?.deviceShell===!0,splitScreen}},...resolvedProfile&&{appProfile:{profile:resolvedProfile.profile.profile,label:resolvedProfile.profile.label,userAgent:resolvedProfile.profile.ua,os:resolvedProfile.profile.injected.platform==="Android"?"android":"ios"}}}}async function cdpTabClose(session,data){let{tabId}=data;if(typeof tabId!="number")throw new Error("Invalid tabId: tabId must be a number");let browserClient=await session.getBrowserClient(),pageSession=await session.getPageSession(tabId);return await browserClient.sendCommand("Target.closeTarget",{targetId:pageSession.targetId}),{success:!0}}async function cdpTabList(session,_data){let pages=((await(await session.getBrowserClient()).sendCommand("Target.getTargets")).targetInfos??[]).filter(t=>t.type==="page"&&isImplicitlySelectablePageUrl(t.url)),tabs=await Promise.all(pages.map(async t=>{let tabId=await session.ensureTargetRegistered(t.targetId);return{id:tabId,tabId,url:t.url,title:t.title??"",active:!1}}));return{tabs,count:tabs.length}}registerActions([{name:"tab_open",session:"browser",handler:cdpTabOpen},{name:"tab_close",session:"browser",handler:cdpTabClose},{name:"tab_list",session:"browser",handler:cdpTabList}]);var GET_DRAG_COORDS_FROM_NODE_SRC=getDragCoordsFromNode.toString();function resolveSnapshotRef(session,ref){let entry=resolvePageRef(session,ref);if(!entry)throw new PageActionPreconditionError(`Ref ${ref} not found. Run page_snapshot first to get fresh refs.`);return entry}async function withSnapshotRef(session,ref,operation){let entry=resolveSnapshotRef(session,ref);try{return await operation(entry)}catch(error48){throw deletePageRef(session,ref),error48}}async function clickBySelectorJs(session,selector){let value=(await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`(() => {
|
|
704
704
|
const sel = ${JSON.stringify(selector)};
|
|
705
705
|
const el = document.querySelector(sel);
|
|
706
706
|
if (!el) return { clicked: false, error: 'Element not found: ' + sel };
|
|
@@ -733,7 +733,7 @@ Content-Type: ${file2.contentType}\r
|
|
|
733
733
|
const r = fn.call(el);
|
|
734
734
|
if (!r) return { error: 'Cannot resolve element coordinates' };
|
|
735
735
|
return r;
|
|
736
|
-
})()`,returnByValue:!0})).result?.value;if(!value)throw new Error("coord evaluation returned no value");if(value.error)throw new PageActionPreconditionError(value.error);return value}async function getElementCoordsByBackendNodeId(session,backendNodeId){let objectId=await resolveBackendNodeObjectId(session,backendNodeId),value=(await sendCdpDeviceShellPageCommand(session,"Runtime.callFunctionOn",{objectId,functionDeclaration:GET_CLICK_COORDS_FROM_NODE_SRC,returnByValue:!0})).result?.value;if(value===null)throw new PageActionPreconditionError(`Cannot resolve clickable element for backendNodeId ${backendNodeId}`);if(!value)throw new Error("coord evaluation returned no value");return value}async function resolveScopeBackendNodeId(session,scope){if(checkPageActionPrecondition(()=>validatePageElementSelector(scope,"page_click scope")),scope.startsWith("@e"))return resolveSnapshotRef(session,scope).backendNodeId;let evaluated=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`document.querySelector(${JSON.stringify(scope)})`,returnByValue:!1});if(evaluated.exceptionDetails){let message=evaluated.exceptionDetails.exception?.description??evaluated.exceptionDetails.text??"invalid selector";throw new PageActionPreconditionError(`page_click: invalid scope "${scope}": ${message}`)}let objectId=evaluated.result?.objectId;if(!objectId||evaluated.result?.subtype==="null")throw new PageActionPreconditionError(`page_click: scope not found: ${scope}`);try{let backendNodeId=(await sendCdpDeviceShellPageCommand(session,"DOM.describeNode",{objectId})).node?.backendNodeId;if(backendNodeId===void 0)throw new PageActionPreconditionError(`page_click: cannot resolve scope: ${scope}`);return backendNodeId}finally{await sendCdpDeviceShellPageCommand(session,"Runtime.releaseObject",{objectId}).catch(()=>{})}}async function cdpPageClick(session,data){let{selector,text,role,exact,scope,clickMode,point,frameId,coordinateSpace}=data??{},hasSelector=typeof selector=="string"&&selector.length>0,hasText=typeof text=="string"&&text.length>0,hasPoint=point&&Number.isFinite(point.x)&&Number.isFinite(point.y)&&point.x>=0&&point.y>=0,provided=[hasSelector&&"selector",hasText&&"text",hasPoint&&"point"].filter(Boolean);if(clickMode!==void 0&&!["auto","dom","mouse","touch"].includes(clickMode))throw new PageActionPreconditionError('page_click: "clickMode" must be one of auto, dom, mouse, touch');if(scope!==void 0&&!hasText)throw new PageActionPreconditionError('page_click: "scope" is only supported with the "text" target');if(coordinateSpace!==void 0&&!["outer-viewport","active-frame"].includes(coordinateSpace))throw new PageActionPreconditionError('page_click: "coordinateSpace" must be one of outer-viewport, active-frame');if(coordinateSpace!==void 0&&!hasPoint)throw new PageActionPreconditionError('page_click: "coordinateSpace" is only supported with the "point" target');if(frameId!==void 0||coordinateSpace==="active-frame")throw new PageActionPreconditionError("page_click: frameId and active-frame coordinates require the browser extension backend");if(scope!==void 0&&checkPageActionPrecondition(()=>validatePageElementSelector(scope,"page_click scope")),hasSelector&&checkPageActionPrecondition(()=>validatePageElementSelector(selector,"page_click")),provided.length===0)throw new PageActionPreconditionError('page_click: provide exactly one of "selector", "text", or "point". For text matching, pass "text" (and optionally "role"/"exact"). For coordinate clicks, pass "point": { x, y } in viewport pixels.');if(provided.length>1)throw new PageActionPreconditionError(`page_click: provide exactly one of "selector", "text", or "point" — got ${provided.length} (${provided.join(", ")}).`);let requestedMode=clickMode??"auto",[visibilityResult,touchEmulationEnabled]=requestedMode==="auto"?await Promise.all([sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:"document.visibilityState",returnByValue:!0}),prefersTouchInput(session)]):[void 0,!1]
|
|
736
|
+
})()`,returnByValue:!0})).result?.value;if(!value)throw new Error("coord evaluation returned no value");if(value.error)throw new PageActionPreconditionError(value.error);return value}async function getElementCoordsByBackendNodeId(session,backendNodeId){let objectId=await resolveBackendNodeObjectId(session,backendNodeId),value=(await sendCdpDeviceShellPageCommand(session,"Runtime.callFunctionOn",{objectId,functionDeclaration:GET_CLICK_COORDS_FROM_NODE_SRC,returnByValue:!0})).result?.value;if(value===null)throw new PageActionPreconditionError(`Cannot resolve clickable element for backendNodeId ${backendNodeId}`);if(!value)throw new Error("coord evaluation returned no value");return value}async function resolveScopeBackendNodeId(session,scope){if(checkPageActionPrecondition(()=>validatePageElementSelector(scope,"page_click scope")),scope.startsWith("@e"))return resolveSnapshotRef(session,scope).backendNodeId;let evaluated=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`document.querySelector(${JSON.stringify(scope)})`,returnByValue:!1});if(evaluated.exceptionDetails){let message=evaluated.exceptionDetails.exception?.description??evaluated.exceptionDetails.text??"invalid selector";throw new PageActionPreconditionError(`page_click: invalid scope "${scope}": ${message}`)}let objectId=evaluated.result?.objectId;if(!objectId||evaluated.result?.subtype==="null")throw new PageActionPreconditionError(`page_click: scope not found: ${scope}`);try{let backendNodeId=(await sendCdpDeviceShellPageCommand(session,"DOM.describeNode",{objectId})).node?.backendNodeId;if(backendNodeId===void 0)throw new PageActionPreconditionError(`page_click: cannot resolve scope: ${scope}`);return backendNodeId}finally{await sendCdpDeviceShellPageCommand(session,"Runtime.releaseObject",{objectId}).catch(()=>{})}}async function cdpPageClick(session,data){let{selector,text,role,exact,scope,clickMode,point,frameId,coordinateSpace}=data??{},hasSelector=typeof selector=="string"&&selector.length>0,hasText=typeof text=="string"&&text.length>0,hasPoint=point&&Number.isFinite(point.x)&&Number.isFinite(point.y)&&point.x>=0&&point.y>=0,provided=[hasSelector&&"selector",hasText&&"text",hasPoint&&"point"].filter(Boolean);if(clickMode!==void 0&&!["auto","dom","mouse","touch"].includes(clickMode))throw new PageActionPreconditionError('page_click: "clickMode" must be one of auto, dom, mouse, touch');if(scope!==void 0&&!hasText)throw new PageActionPreconditionError('page_click: "scope" is only supported with the "text" target');if(coordinateSpace!==void 0&&!["outer-viewport","active-frame"].includes(coordinateSpace))throw new PageActionPreconditionError('page_click: "coordinateSpace" must be one of outer-viewport, active-frame');if(coordinateSpace!==void 0&&!hasPoint)throw new PageActionPreconditionError('page_click: "coordinateSpace" is only supported with the "point" target');if(frameId!==void 0||coordinateSpace==="active-frame")throw new PageActionPreconditionError("page_click: frameId and active-frame coordinates require the browser extension backend");if(scope!==void 0&&checkPageActionPrecondition(()=>validatePageElementSelector(scope,"page_click scope")),hasSelector&&checkPageActionPrecondition(()=>validatePageElementSelector(selector,"page_click")),provided.length===0)throw new PageActionPreconditionError('page_click: provide exactly one of "selector", "text", or "point". For text matching, pass "text" (and optionally "role"/"exact"). For coordinate clicks, pass "point": { x, y } in viewport pixels.');if(provided.length>1)throw new PageActionPreconditionError(`page_click: provide exactly one of "selector", "text", or "point" — got ${provided.length} (${provided.join(", ")}).`);let requestedMode=clickMode??"auto",[visibilityResult,touchEmulationEnabled]=requestedMode==="auto"||requestedMode==="touch"?await Promise.all([sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:"document.visibilityState",returnByValue:!0}),prefersTouchInput(session)]):[void 0,!1];if(requestedMode==="touch"&&visibilityResult?.result?.value==="hidden")throw new PageActionPreconditionError(PAGE_CLICK_HIDDEN_TOUCH_ERROR);let policy=resolvePageClickDispatchPolicy(requestedMode,visibilityResult?.result?.value,touchEmulationEnabled),effectiveClickMode=policy.clickMode,finalize2=result=>policy.fallbackReason?{...result,fallbackReason:policy.fallbackReason}:result;if(hasSelector){if(selector.startsWith("@e")){let ref=selector,result=await withSnapshotRef(session,ref,async entry=>{let dispatchTarget2;if(effectiveClickMode==="dom"||policy.stateAwareControls&&isNativeToggleControl(entry.role))dispatchTarget2=await clickByBackendNodeJs(session,entry.backendNodeId);else{let coord=await getElementCoordsByBackendNodeId(session,entry.backendNodeId);policy.stateAwareControls&&isNativeToggleControl(void 0,coord.inputType)?dispatchTarget2=await clickByBackendNodeJs(session,entry.backendNodeId):(await dispatchCdpClick(session,coord.x,coord.y,effectiveClickMode),dispatchTarget2={...coord,dispatchMode:"trusted-input",pointerType:effectiveClickMode})}return createPageClickResult({kind:"ref",selector:ref,role:entry.role,name:entry.name},dispatchTarget2)});return finalize2(result)}if(effectiveClickMode!=="dom"){let coord=await getElementCoordsBySelector(session,selector);if(policy.stateAwareControls&&isNativeToggleControl(void 0,coord.inputType)){let dispatchTarget2=await clickBySelectorJs(session,selector);return finalize2(createPageClickResult({kind:"selector",selector},dispatchTarget2))}return await dispatchCdpClick(session,coord.x,coord.y,effectiveClickMode),finalize2(createPageClickResult({kind:"selector",selector},{...coord,dispatchMode:"trusted-input",pointerType:effectiveClickMode}))}let dispatchTarget=await clickBySelectorJs(session,selector);return finalize2(createPageClickResult({kind:"selector",selector},dispatchTarget))}if(hasText){let scopeBackendNodeId=scope?await resolveScopeBackendNodeId(session,scope):void 0,nodes=(await sendCdpDeviceShellPageCommand(session,scopeBackendNodeId===void 0?"Accessibility.getFullAXTree":"Accessibility.queryAXTree",scopeBackendNodeId===void 0?{}:{backendNodeId:scopeBackendNodeId})).nodes??[],{hits}=matchAXNodesByText(nodes,{text,role,exact});if(hits.length===0){let exactSuffix=exact===!1?" (substring match)":"",roleSuffix=role?` with role "${role}"`:"";throw new PageActionPreconditionError(`page_click: text "${text}"${roleSuffix}${exactSuffix}${scope?` in scope "${scope}"`:""} not found. Run page_snapshot to inspect the page, or try exact: false for substring matching.`)}if(hits.length>1){let candidates=formatAXTextMatchCandidates(hits);throw new PageActionPreconditionError(`page_click: text "${text}"${scope?` in scope "${scope}"`:""} matched ${hits.length} elements. Refine with "role" or "exact: true", or run page_snapshot and use an "@eN" ref:
|
|
737
737
|
${candidates}`)}let hit=hits[0],dispatchTarget;if(effectiveClickMode==="dom"||policy.stateAwareControls&&isNativeToggleControl(hit.role))dispatchTarget=await clickByBackendNodeJs(session,hit.backendNodeId);else{let coord=await getElementCoordsByBackendNodeId(session,hit.backendNodeId);await dispatchCdpClick(session,coord.x,coord.y,effectiveClickMode),dispatchTarget={...coord,dispatchMode:"trusted-input",pointerType:effectiveClickMode}}return finalize2(createPageClickResult({kind:"text",name:hit.name,role:hit.role||void 0,...scope?{scope}:{}},dispatchTarget))}if(!point)throw new PageActionPreconditionError("page_click point is required");if(effectiveClickMode==="dom"){let dispatchTarget=await clickByPointJs(session,point);return finalize2(createPageClickResult({kind:"point",point},dispatchTarget))}return await dispatchCdpClick(session,point.x,point.y,effectiveClickMode),finalize2(createPageClickResult({kind:"point",point},{tag:"",text:"",dispatchMode:"trusted-input",pointerType:effectiveClickMode}))}async function scrollDragSourceIntoView(session,endpoint){if(typeof endpoint!="string")return;if(validatePageElementSelector(endpoint,"page_drag from"),endpoint.startsWith("@e")){let entry=resolveSnapshotRef(session,endpoint),objectId=await resolveBackendNodeObjectId(session,entry.backendNodeId);await sendCdpDeviceShellPageCommand(session,"Runtime.callFunctionOn",{objectId,functionDeclaration:`function() {
|
|
738
738
|
const el = this.nodeType === Node.TEXT_NODE ? this.parentElement : this;
|
|
739
739
|
if (!el) return false;
|
|
@@ -759,7 +759,7 @@ ${candidates}`)}let hit=hits[0],dispatchTarget;if(effectiveClickMode==="dom"||po
|
|
|
759
759
|
if (!el) return { typed: false, tag: '', error: 'Element not found: ' + sel };
|
|
760
760
|
const fn = (${TYPE_INTO_ELEMENT_SRC});
|
|
761
761
|
return fn(el, v, c);
|
|
762
|
-
})(${JSON.stringify(selector)}, ${JSON.stringify(text)}, ${JSON.stringify(clearFirst)})`,value=(await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression,returnByValue:!0})).result?.value;if(!value)throw new Error("cdp_page_type: evaluation returned no value");if(value.error)throw new PageActionPreconditionError(value.error);if(!value.typed)throw new PageActionPreconditionError("cdp_page_type: failed to type");return{typed:!0,tag:value.tag}}async function cdpPageScroll(session,data){let input=checkPageActionPrecondition(()=>resolvePageScrollInput(data??{}));if(input.selector?.startsWith("@e"))return withSnapshotRef(session,input.selector,async entry=>{let objectId=await resolveBackendNodeObjectId(session,entry.backendNodeId),result2=await sendCdpDeviceShellPageCommand(session,"Runtime.callFunctionOn",{objectId,functionDeclaration:SCROLL_ELEMENT_IN_PAGE_SOURCE,arguments:[{value:input.direction},{value:input.distance},{value:input.selector},{value:input.containerPolicy}],returnByValue:!0});return unwrapPageScrollResult(result2.result?.value,`Cannot resolve scroll container for ref ${input.selector}`)});let result=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:buildPageScrollExpression(input),returnByValue:!0});if(result.exceptionDetails)throw new Error(result.exceptionDetails.exception?.description??result.exceptionDetails.text??"page_scroll evaluation failed");return unwrapPageScrollResult(result.result?.value,"page_scroll evaluation returned no value")}async function cdpPageEval(session,data){let{expression,awaitPromise=!0}=data;if(!expression||typeof expression!="string")throw new PageActionPreconditionError("Invalid expression");let result=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression,returnByValue:!0,awaitPromise});if(result.exceptionDetails)throw new Error(result.exceptionDetails.exception?.description??result.exceptionDetails.text??"Evaluation error");return{result:result.result?.value}}async function cdpPagePress(session,data){let{key}=data;if(!key||typeof key!="string")throw new PageActionPreconditionError("Invalid key");return await session.client.sendCommand("Input.dispatchKeyEvent",{type:"keyDown",key}),await session.client.sendCommand("Input.dispatchKeyEvent",{type:"keyUp",key}),{success:!0,key}}async function cdpPageWait(session,data){let options=resolvePageWaitInput(data),startedAt=Date.now();if(options.mode==="time")return await new Promise(resolve2=>setTimeout(resolve2,options.time)),{success:!0,waited:!0,elapsed:options.time,mode:options.mode};let expression=options.mode==="selector"?`!!document.querySelector(${JSON.stringify(options.selector)})`:options.condition;for(;Date.now()-startedAt<options.timeout;){let result=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression,returnByValue:!0,awaitPromise:options.mode==="condition"});if(result.exceptionDetails)throw new Error(result.exceptionDetails.exception?.description??result.exceptionDetails.text??`page_wait ${options.mode} evaluation failed`);let value=result.result?.value;if(value)return{success:!0,waited:!0,elapsed:Date.now()-startedAt,mode:options.mode,value};await new Promise(resolve2=>setTimeout(resolve2,options.interval))}throw options.mode==="selector"?new Error(`page_wait selector ${JSON.stringify(options.selector)} was not found after ${options.timeout}ms.`):new Error(`page_wait condition was not met after ${options.timeout}ms.`)}async function cdpPageNavigate(session,data){let input=resolvePageNavigateInput(data);if(input.mode==="refresh")return clearPageRefsForNavigation(session),await sendCdpDeviceShellPageCommand(session,"Page.reload",{},35e3),await waitForPageLoad(session,3e4),{success:!0,...await readPageIdentity(session),refreshed:!0};if(input.mode==="history"){let navigationHistory=await sendCdpDeviceShellPageCommand(session,"Page.getNavigationHistory"),targetIndex=navigationHistory.currentIndex+(input.history==="back"?-1:1),targetEntry=navigationHistory.entries?.[targetIndex];if(!targetEntry)throw new Error(`page_navigate: no ${input.history==="back"?"previous":"next"} history entry`);return clearPageRefsForNavigation(session),await sendCdpDeviceShellPageCommand(session,"Page.navigateToHistoryEntry",{entryId:targetEntry.id},35e3),await waitForHistoryIndex(session,targetIndex,3e4),{success:!0,...await readPageIdentity(session),history:input.history}}clearPageRefsForNavigation(session);let result=await sendCdpDeviceShellPageCommand(session,"Page.navigate",{url:input.url},35e3);return await waitForPageLoad(session,3e4),{success:!0,url:result.url??input.url,frameId:result.frameId}}async function readPageIdentity(session){let evaluated=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:"({ url: location.href, title: document.title })",returnByValue:!0});return{url:evaluated.result?.value?.url??"",title:evaluated.result?.value?.title??""}}async function waitForHistoryIndex(session,targetIndex,timeoutMs){let deadline=Date.now()+timeoutMs;for(;Date.now()<deadline;){try{if((await sendCdpDeviceShellPageCommand(session,"Page.getNavigationHistory")).currentIndex===targetIndex&&(await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:"document.readyState",returnByValue:!0})).result?.value!=="loading")return}catch{}await new Promise(resolve2=>setTimeout(resolve2,50))}throw new Error(`Page history navigation timeout after ${timeoutMs}ms`)}async function cdpPageUpload(session,data){let{selector,filePaths}=data??{};if(typeof selector!="string"||selector.length===0)throw new PageActionPreconditionError('page_upload: "selector" is required (CSS selector or @eN snapshot ref)');if(checkPageActionPrecondition(()=>validatePageElementSelector(selector,"page_upload")),!Array.isArray(filePaths)||filePaths.length===0||filePaths.some(filePath=>typeof filePath!="string"||filePath.length===0))throw new PageActionPreconditionError("Invalid filePaths: must be a non-empty array of file path strings");let described;if(selector.startsWith("@e"))described=await withSnapshotRef(session,selector,entry=>sendCdpDeviceShellPageCommand(session,"DOM.describeNode",{backendNodeId:entry.backendNodeId}));else{let evaluated=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`document.querySelector(${JSON.stringify(selector)})`,returnByValue:!1}),objectId=evaluated.result?.objectId;if(!objectId||evaluated.result?.subtype==="null")throw new PageActionPreconditionError(`Element not found: ${selector}`);try{described=await sendCdpDeviceShellPageCommand(session,"DOM.describeNode",{objectId})}finally{await sendCdpDeviceShellPageCommand(session,"Runtime.releaseObject",{objectId}).catch(()=>{})}}let backendNodeId=described.node?.backendNodeId,tag=String(described.node?.nodeName??"").toLowerCase();if(backendNodeId===void 0)throw new PageActionPreconditionError(`Cannot resolve file input: ${selector}`);if(tag!=="input")throw new PageActionPreconditionError(`Element <${tag||"unknown"}> is not a file input. selector must point to an <input type="file"> element.`);return await sendCdpDeviceShellPageCommand(session,"DOM.setFileInputFiles",{files:filePaths,backendNodeId}),{uploaded:!0,fileCount:filePaths.length,tag}}async function cdpSetDeviceEmulation(session,data){let{enabled}=data??{};if(typeof enabled!="boolean")throw new Error('set_device_emulation: "enabled" is required (true to enable, false to clear)');if(enabled===!1){let hadDeviceShell2=await clearCdpDeviceShell(session),appEnvironment2=await updateCdpAppProfileDeviceEmulation(session,null);for(let{method,params}of buildDisableEmulationCommands())await session.client.sendCommand(method,params).catch(()=>{});appEnvironment2&&await session.client.sendCommand("Emulation.setUserAgentOverride",{userAgent:appEnvironment2.userAgent,platform:appEnvironment2.platform}),session.emulation=void 0;let reloaded2=!1;if(hadDeviceShell2){clearPageRefsForNavigation(session);try{await session.client.sendCommand("Page.reload",{}),await waitForPageLoad(session,3e4),reloaded2=!0}catch{}}return{enabled:!1,reloaded:reloaded2}}let config2=resolveEmulationConfig(data),deviceShell=data.deviceShell===!0,hadDeviceShell=isCdpDeviceShellActive(session),appEnvironment=await updateCdpAppProfileDeviceEmulation(session,config2),commands=buildEnableEmulationCommands(config2).map(command=>command.method==="Emulation.setUserAgentOverride"&&appEnvironment?{...command,params:{userAgent:appEnvironment.userAgent,platform:config2.platform}}:command);for(let{method,params,optional:optional2}of commands)await session.client.sendCommand(method,params).catch(error48=>{if(!optional2)throw error48});session.emulation={mobile:config2.mobile,touch:config2.touch,config:config2,deviceShell};let deviceShellChanged=deviceShell?await applyCdpDeviceShell(session,config2):await clearCdpDeviceShell(session);deviceShell&&appEnvironment&&setCdpDeviceShellChildEnvironmentManagedByApp(session,!0);let reloaded=!1;if(data?.reload!==!1||deviceShellChanged||hadDeviceShell!==deviceShell){clearPageRefsForNavigation(session);try{await session.client.sendCommand("Page.reload",{}),deviceShell?await waitForCdpDeviceShellLoad(session):isCdpAppProfileActive(session)?await waitForCdpAppProfileLoad(session):await waitForPageLoad(session,3e4),reloaded=!0}catch{}}return{enabled:!0,preset:config2.presetName,viewport:{width:config2.width,height:config2.height,deviceScaleFactor:config2.deviceScaleFactor,scale:config2.scale??1},userAgent:config2.userAgent,mobile:config2.mobile,touch:config2.touch,orientation:config2.orientation,deviceShell,reloaded}}async function cdpPageHover(session,data){let{selector}=data??{};if(typeof selector!="string"||selector.length===0)throw new PageActionPreconditionError('page_hover: "selector" is required (CSS selector or @eN snapshot ref)');checkPageActionPrecondition(()=>validatePageElementSelector(selector,"page_hover"));let coord=selector.startsWith("@e")?await withSnapshotRef(session,selector,entry=>getElementCoordsByBackendNodeId(session,entry.backendNodeId)):await getElementCoordsBySelector(session,selector),offset=getCdpDeviceShellInputOffset(session);return await session.client.sendCommand("Input.dispatchMouseEvent",{type:"mouseMoved",x:coord.x+offset.x,y:coord.y+offset.y}),{hovered:!0,tag:coord.tag,text:coord.text}}registerActions([{name:"page_click",session:"page",handler:cdpPageClick},{name:"page_drag",session:"page",handler:cdpPageDrag},{name:"page_type",session:"page",handler:cdpPageType},{name:"page_hover",session:"page",handler:cdpPageHover},{name:"page_scroll",session:"page",handler:cdpPageScroll},{name:"page_eval",session:"page",handler:cdpPageEval},{name:"page_press",session:"page",handler:cdpPagePress},{name:"page_wait",session:"page",handler:cdpPageWait},{name:"page_navigate",session:"page",handler:cdpPageNavigate},{name:"page_upload",session:"page",handler:cdpPageUpload},{name:"set_device_emulation",session:"page",handler:cdpSetDeviceEmulation}]);async function cdpSetTimezone(session,data){if(typeof data?.timezone!="string")throw new Error('set_timezone: "timezone" is required (IANA timezone or empty string to clear)');let timezone=data.timezone.trim();return await session.client.sendCommand("Emulation.setTimezoneOverride",{timezoneId:timezone}),{enabled:timezone.length>0,timezone:timezone||null}}registerActions([{name:"set_timezone",session:"page",handler:cdpSetTimezone}]);async function readCurrentUrl(session,action){let url2=(await session.client.sendCommand("Runtime.evaluate",{expression:"location.href",returnByValue:!0})).result?.value;if(typeof url2!="string"||!url2)throw new Error(`${action}: could not read the current page URL`);return url2}function reloadPageAndWait(session,timeoutMs){return new Promise((resolve2,reject)=>{let settled=!1,removeListener=()=>{},finish=error48=>{settled||(settled=!0,clearTimeout(timer),removeListener(),error48?reject(error48):resolve2())},timer=setTimeout(()=>{finish(new Error(`Page load timeout after ${timeoutMs}ms`))},timeoutMs);removeListener=session.client.on("Page.loadEventFired",()=>finish()),session.client.sendCommand("Page.reload").catch(error48=>{finish(error48 instanceof Error?error48:new Error(String(error48)))})})}async function cdpSetCookie(session,data){let url2=await readCurrentUrl(session,"set_cookie"),target=resolveSetCookieTarget(url2,data??{});if((await session.client.sendCommand("Network.setCookie",{name:target.cookieName,value:target.cookieValue,url:target.cookieUrl,path:target.path,secure:target.cookieUrl.startsWith("https:"),...target.cookieDomain?{domain:target.cookieDomain}:{}})).success===!1)throw new Error(`set_cookie: failed to set ${target.cookieName}`);return target.reload&&await reloadPageAndWait(session,3e4),{...typeof data?.tabId=="number"?{tabId:data.tabId}:{},url:url2,name:target.cookieName,domain:target.domain,path:target.path,reloaded:target.reload}}async function cdpGetCookie(session,data){let url2=await readCurrentUrl(session,"get_cookie"),target=resolveGetCookieTarget(url2,data??{}),result=await session.client.sendCommand("Network.getCookies",{urls:[target.cookieUrl]}),cookie=selectReadableCookie(result.cookies??[],target);return{...typeof data?.tabId=="number"?{tabId:data.tabId}:{},url:data?.url?target.cookieUrl:url2,name:target.cookieName,found:!!cookie,...cookie?{value:cookie.value,domain:cookie.domain,path:cookie.path}:{}}}registerActions([{name:"get_cookie",session:"page",handler:cdpGetCookie},{name:"set_cookie",session:"page",handler:cdpSetCookie}]);var READ_DOM_CHECKED_STATE_SOURCE=readDOMCheckedState.toString();async function readDOMCheckedState2(session,backendNodeId){let objectId=(await sendCdpDeviceShellPageCommand(session,"DOM.resolveNode",{backendNodeId})).object?.objectId;if(objectId)try{let value=(await sendCdpDeviceShellPageCommand(session,"Runtime.callFunctionOn",{objectId,functionDeclaration:READ_DOM_CHECKED_STATE_SOURCE,returnByValue:!0})).result?.value;return value===!0||value===!1||value==="mixed"?value:void 0}finally{await sendCdpDeviceShellPageCommand(session,"Runtime.releaseObject",{objectId}).catch(()=>{})}}function buildSnapshotTree(nodeMap,nodeId,snapshotRefs){let node=nodeMap.get(nodeId);if(!node)return null;let role=node.role?.value??"generic",name=node.name?.value??"",value=node.value?.value,description=node.description?.value;if(ALWAYS_SKIP_ROLES.has(role)||role==="StaticText"&&!name)return null;if(role==="SvgRoot"){let ref2;node.backendDOMNodeId!==void 0&&(ref2=snapshotRefs.register({backendNodeId:node.backendDOMNodeId,role,name}));let svgChildCount=node.childIds?.length??0;return{role:"SvgRoot",name:name||`(${svgChildCount} elements)`,backendDOMNodeId:node.backendDOMNodeId,ref:ref2}}let children=[];if(node.childIds)for(let childId of node.childIds){let child=buildSnapshotTree(nodeMap,childId,snapshotRefs);child&&children.push(child)}if(node.ignored)return children.length===0?null:children.length===1?children[0]:{role:"group",name:"",children};if(SKIP_ROLES.has(role)&&!name)return children.length===0?null:children.length===1?children[0]:{role:"group",name:"",children};children.length===1&&children[0].role==="StaticText"&&children[0].name===name&&!children[0].children&&(children.length=0);let ref;node.backendDOMNodeId!==void 0&&(ref=snapshotRefs.register({backendNodeId:node.backendDOMNodeId,role,name}));let props=extractAXProperties(node),result={role,name,backendDOMNodeId:node.backendDOMNodeId};return ref&&(result.ref=ref),value!==void 0&&value!==""&&(result.value=String(value)),description&&(result.description=description),props.focused&&(result.focused=!0),props.checked!==void 0&&(result.checked=props.checked),props.disabled&&(result.disabled=!0),props.required&&(result.required=!0),props.expanded!==void 0&&(result.expanded=props.expanded),props.selected&&(result.selected=!0),props.level!==void 0&&(result.level=props.level),children.length>0&&(result.children=children),result}async function resolveRootBackendNodeId(session,selector){let evaluated=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`document.querySelector(${JSON.stringify(selector)})`,returnByValue:!1});if(evaluated.exceptionDetails){let message=evaluated.exceptionDetails.exception?.description??evaluated.exceptionDetails.text??"invalid selector";throw new Error(`page_snapshot: invalid rootSelector "${selector}": ${message}`)}let objectId=evaluated.result?.objectId;if(!objectId||evaluated.result?.subtype==="null")throw new Error(`page_snapshot: rootSelector not found: ${selector}`);try{let backendNodeId=(await sendCdpDeviceShellPageCommand(session,"DOM.describeNode",{objectId})).node?.backendNodeId;if(backendNodeId===void 0)throw new Error(`page_snapshot: cannot resolve rootSelector: ${selector}`);return backendNodeId}finally{await sendCdpDeviceShellPageCommand(session,"Runtime.releaseObject",{objectId}).catch(()=>{})}}async function resolveAncestorBackendNodeId(session,backendNodeId,ancestorDepth){if(ancestorDepth===0)return backendNodeId;let objectId=(await sendCdpDeviceShellPageCommand(session,"DOM.resolveNode",{backendNodeId})).object?.objectId;if(!objectId)throw new Error("page_snapshot: cannot resolve rootRef in the current document");let ancestorObjectId;try{let ancestor=await sendCdpDeviceShellPageCommand(session,"Runtime.callFunctionOn",{objectId,functionDeclaration:`function(depth) {
|
|
762
|
+
})(${JSON.stringify(selector)}, ${JSON.stringify(text)}, ${JSON.stringify(clearFirst)})`,value=(await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression,returnByValue:!0})).result?.value;if(!value)throw new Error("cdp_page_type: evaluation returned no value");if(value.error)throw new PageActionPreconditionError(value.error);if(!value.typed)throw new PageActionPreconditionError("cdp_page_type: failed to type");return{typed:!0,tag:value.tag}}async function cdpPageScroll(session,data){let input=checkPageActionPrecondition(()=>resolvePageScrollInput(data??{}));if(input.selector?.startsWith("@e"))return withSnapshotRef(session,input.selector,async entry=>{let objectId=await resolveBackendNodeObjectId(session,entry.backendNodeId),result2=await sendCdpDeviceShellPageCommand(session,"Runtime.callFunctionOn",{objectId,functionDeclaration:SCROLL_ELEMENT_IN_PAGE_SOURCE,arguments:[{value:input.direction},{value:input.distance},{value:input.selector},{value:input.containerPolicy}],returnByValue:!0});return unwrapPageScrollResult(result2.result?.value,`Cannot resolve scroll container for ref ${input.selector}`)});let result=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:buildPageScrollExpression(input),returnByValue:!0});if(result.exceptionDetails)throw new Error(result.exceptionDetails.exception?.description??result.exceptionDetails.text??"page_scroll evaluation failed");return unwrapPageScrollResult(result.result?.value,"page_scroll evaluation returned no value")}async function cdpPageEval(session,data){let{expression,awaitPromise=!0}=data;if(!expression||typeof expression!="string")throw new PageActionPreconditionError("Invalid expression");let result=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression,returnByValue:!0,awaitPromise});if(result.exceptionDetails)throw new Error(result.exceptionDetails.exception?.description??result.exceptionDetails.text??"Evaluation error");return{result:result.result?.value}}async function cdpPagePress(session,data){let{key}=data;if(!key||typeof key!="string")throw new PageActionPreconditionError("Invalid key");return await session.client.sendCommand("Input.dispatchKeyEvent",{type:"keyDown",key}),await session.client.sendCommand("Input.dispatchKeyEvent",{type:"keyUp",key}),{success:!0,key}}async function cdpPageWait(session,data){let options=resolvePageWaitInput(data),startedAt=Date.now();if(options.mode==="time")return await new Promise(resolve2=>setTimeout(resolve2,options.time)),{success:!0,waited:!0,elapsed:options.time,mode:options.mode};let expression=options.mode==="selector"?`!!document.querySelector(${JSON.stringify(options.selector)})`:options.condition;for(;Date.now()-startedAt<options.timeout;){let result=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression,returnByValue:!0,awaitPromise:options.mode==="condition"});if(result.exceptionDetails)throw new Error(result.exceptionDetails.exception?.description??result.exceptionDetails.text??`page_wait ${options.mode} evaluation failed`);let value=result.result?.value;if(value)return{success:!0,waited:!0,elapsed:Date.now()-startedAt,mode:options.mode,value};await new Promise(resolve2=>setTimeout(resolve2,options.interval))}throw options.mode==="selector"?new Error(`page_wait selector ${JSON.stringify(options.selector)} was not found after ${options.timeout}ms.`):new Error(`page_wait condition was not met after ${options.timeout}ms.`)}async function cdpPageNavigate(session,data){let input=resolvePageNavigateInput(data);if(input.mode==="refresh")return clearPageRefsForNavigation(session),await sendCdpDeviceShellPageCommand(session,"Page.reload",{},35e3),await waitForPageLoad(session,3e4),{success:!0,...await readPageIdentity(session),refreshed:!0};if(input.mode==="history"){let navigationHistory=await sendCdpDeviceShellPageCommand(session,"Page.getNavigationHistory"),targetIndex=navigationHistory.currentIndex+(input.history==="back"?-1:1),targetEntry=navigationHistory.entries?.[targetIndex];if(!targetEntry)throw new Error(`page_navigate: no ${input.history==="back"?"previous":"next"} history entry`);return clearPageRefsForNavigation(session),await sendCdpDeviceShellPageCommand(session,"Page.navigateToHistoryEntry",{entryId:targetEntry.id},35e3),await waitForHistoryIndex(session,targetIndex,3e4),{success:!0,...await readPageIdentity(session),history:input.history}}clearPageRefsForNavigation(session);let result=await sendCdpDeviceShellPageCommand(session,"Page.navigate",{url:input.url},35e3);return await waitForPageLoad(session,3e4),{success:!0,url:result.url??input.url,frameId:result.frameId}}async function readPageIdentity(session){let evaluated=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:"({ url: location.href, title: document.title })",returnByValue:!0});return{url:evaluated.result?.value?.url??"",title:evaluated.result?.value?.title??""}}async function waitForHistoryIndex(session,targetIndex,timeoutMs){let deadline=Date.now()+timeoutMs;for(;Date.now()<deadline;){try{if((await sendCdpDeviceShellPageCommand(session,"Page.getNavigationHistory")).currentIndex===targetIndex&&(await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:"document.readyState",returnByValue:!0})).result?.value!=="loading")return}catch{}await new Promise(resolve2=>setTimeout(resolve2,50))}throw new Error(`Page history navigation timeout after ${timeoutMs}ms`)}async function cdpPageUpload(session,data){let{selector,filePaths}=data??{};if(typeof selector!="string"||selector.length===0)throw new PageActionPreconditionError('page_upload: "selector" is required (CSS selector or @eN snapshot ref)');if(checkPageActionPrecondition(()=>validatePageElementSelector(selector,"page_upload")),!Array.isArray(filePaths)||filePaths.length===0||filePaths.some(filePath=>typeof filePath!="string"||filePath.length===0))throw new PageActionPreconditionError("Invalid filePaths: must be a non-empty array of file path strings");let described;if(selector.startsWith("@e"))described=await withSnapshotRef(session,selector,entry=>sendCdpDeviceShellPageCommand(session,"DOM.describeNode",{backendNodeId:entry.backendNodeId}));else{let evaluated=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`document.querySelector(${JSON.stringify(selector)})`,returnByValue:!1}),objectId=evaluated.result?.objectId;if(!objectId||evaluated.result?.subtype==="null")throw new PageActionPreconditionError(`Element not found: ${selector}`);try{described=await sendCdpDeviceShellPageCommand(session,"DOM.describeNode",{objectId})}finally{await sendCdpDeviceShellPageCommand(session,"Runtime.releaseObject",{objectId}).catch(()=>{})}}let backendNodeId=described.node?.backendNodeId,tag=String(described.node?.nodeName??"").toLowerCase();if(backendNodeId===void 0)throw new PageActionPreconditionError(`Cannot resolve file input: ${selector}`);if(tag!=="input")throw new PageActionPreconditionError(`Element <${tag||"unknown"}> is not a file input. selector must point to an <input type="file"> element.`);return await sendCdpDeviceShellPageCommand(session,"DOM.setFileInputFiles",{files:filePaths,backendNodeId}),{uploaded:!0,fileCount:filePaths.length,tag}}async function cdpSetDeviceEmulation(session,data){let{enabled}=data??{};if(typeof enabled!="boolean")throw new Error('set_device_emulation: "enabled" is required (true to enable, false to clear)');if(enabled===!1){let hadDeviceShell2=await clearCdpDeviceShell(session),appEnvironment2=await updateCdpAppProfileDeviceEmulation(session,null);for(let{method,params}of buildDisableEmulationCommands())await session.client.sendCommand(method,params).catch(()=>{});appEnvironment2&&await session.client.sendCommand("Emulation.setUserAgentOverride",{userAgent:appEnvironment2.userAgent,platform:appEnvironment2.platform}),session.emulation=void 0;let reloaded2=!1;if(hadDeviceShell2){clearPageRefsForNavigation(session);try{await session.client.sendCommand("Page.reload",{}),await waitForPageLoad(session,3e4),reloaded2=!0}catch{}}return{enabled:!1,deviceShell:!1,splitScreen:!1,reloaded:reloaded2}}let config2=resolveEmulationConfig(data),deviceShell=data.deviceShell===!0,splitScreen=deviceShell&&isCdpAppProfileActive(session)&&data.splitScreen===!0&&config2.orientation==="landscape",hadDeviceShell=isCdpDeviceShellActive(session),appEnvironment=await updateCdpAppProfileDeviceEmulation(session,config2,deviceShell,splitScreen),commands=buildEnableEmulationCommands(config2).map(command=>command.method==="Emulation.setUserAgentOverride"&&appEnvironment?{...command,params:{userAgent:appEnvironment.userAgent,platform:config2.platform}}:command);for(let{method,params,optional:optional2}of commands)await session.client.sendCommand(method,params).catch(error48=>{if(!optional2)throw error48});session.emulation={mobile:config2.mobile,touch:config2.touch,config:config2,deviceShell,splitScreen};let deviceShellChanged=deviceShell?await applyCdpDeviceShell(session,config2,{rootContainerManagedByApp:splitScreen}):await clearCdpDeviceShell(session);deviceShell&&appEnvironment&&setCdpDeviceShellChildEnvironmentManagedByApp(session,!0);let reloaded=!1;if(data?.reload!==!1||deviceShellChanged||hadDeviceShell!==deviceShell){clearPageRefsForNavigation(session);try{await session.client.sendCommand("Page.reload",{}),deviceShell?await waitForCdpDeviceShellLoad(session):isCdpAppProfileActive(session)?await waitForCdpAppProfileLoad(session):await waitForPageLoad(session,3e4),reloaded=!0}catch{}}return{enabled:!0,preset:config2.presetName,viewport:{width:config2.width,height:config2.height,deviceScaleFactor:config2.deviceScaleFactor,scale:config2.scale??1},userAgent:config2.userAgent,mobile:config2.mobile,touch:config2.touch,orientation:config2.orientation,deviceShell,splitScreen,reloaded}}async function cdpPageHover(session,data){let{selector}=data??{};if(typeof selector!="string"||selector.length===0)throw new PageActionPreconditionError('page_hover: "selector" is required (CSS selector or @eN snapshot ref)');checkPageActionPrecondition(()=>validatePageElementSelector(selector,"page_hover"));let coord=selector.startsWith("@e")?await withSnapshotRef(session,selector,entry=>getElementCoordsByBackendNodeId(session,entry.backendNodeId)):await getElementCoordsBySelector(session,selector),offset=await getCdpDeviceShellInputOffset(session);return await session.client.sendCommand("Input.dispatchMouseEvent",{type:"mouseMoved",x:coord.x+offset.x,y:coord.y+offset.y}),{hovered:!0,tag:coord.tag,text:coord.text}}registerActions([{name:"page_click",session:"page",handler:cdpPageClick},{name:"page_drag",session:"page",handler:cdpPageDrag},{name:"page_type",session:"page",handler:cdpPageType},{name:"page_hover",session:"page",handler:cdpPageHover},{name:"page_scroll",session:"page",handler:cdpPageScroll},{name:"page_eval",session:"page",handler:cdpPageEval},{name:"page_press",session:"page",handler:cdpPagePress},{name:"page_wait",session:"page",handler:cdpPageWait},{name:"page_navigate",session:"page",handler:cdpPageNavigate},{name:"page_upload",session:"page",handler:cdpPageUpload},{name:"set_device_emulation",session:"page",handler:cdpSetDeviceEmulation}]);async function cdpSetTimezone(session,data){if(typeof data?.timezone!="string")throw new Error('set_timezone: "timezone" is required (IANA timezone or empty string to clear)');let timezone=data.timezone.trim();return await session.client.sendCommand("Emulation.setTimezoneOverride",{timezoneId:timezone}),{enabled:timezone.length>0,timezone:timezone||null}}registerActions([{name:"set_timezone",session:"page",handler:cdpSetTimezone}]);function reloadPageAndWait(session,timeoutMs){return new Promise((resolve2,reject)=>{let settled=!1,removeListener=()=>{},finish=error48=>{settled||(settled=!0,clearTimeout(timer),removeListener(),error48?reject(error48):resolve2())},timer=setTimeout(()=>{finish(new Error(`Page load timeout after ${timeoutMs}ms`))},timeoutMs);removeListener=session.client.on("Page.loadEventFired",()=>finish()),session.client.sendCommand("Page.reload").catch(error48=>{finish(error48 instanceof Error?error48:new Error(String(error48)))})})}async function cdpSetCookie(session,data){let url2=await readCdpCurrentUrl(session,"set_cookie"),target=resolveSetCookieTarget(url2,data??{});if((await session.client.sendCommand("Network.setCookie",{name:target.cookieName,value:target.cookieValue,url:target.cookieUrl,path:target.path,secure:target.cookieUrl.startsWith("https:"),...target.cookieDomain?{domain:target.cookieDomain}:{}})).success===!1)throw new Error(`set_cookie: failed to set ${target.cookieName}`);return target.reload&&await reloadPageAndWait(session,3e4),{...typeof data?.tabId=="number"?{tabId:data.tabId}:{},url:url2,name:target.cookieName,domain:target.domain,path:target.path,reloaded:target.reload}}async function cdpGetCookie(session,data){let url2=await readCdpCurrentUrl(session,"get_cookie"),target=resolveGetCookieTarget(url2,data??{}),result=await session.client.sendCommand("Network.getCookies",{urls:[target.cookieUrl]}),cookie=selectReadableCookie(result.cookies??[],target);return{...typeof data?.tabId=="number"?{tabId:data.tabId}:{},url:data?.url?target.cookieUrl:url2,name:target.cookieName,found:!!cookie,...cookie?{value:cookie.value,domain:cookie.domain,path:cookie.path}:{}}}registerActions([{name:"get_cookie",session:"page",handler:cdpGetCookie},{name:"set_cookie",session:"page",handler:cdpSetCookie}]);var READ_DOM_CHECKED_STATE_SOURCE=readDOMCheckedState.toString();async function readDOMCheckedState2(session,backendNodeId){let objectId=(await sendCdpDeviceShellPageCommand(session,"DOM.resolveNode",{backendNodeId})).object?.objectId;if(objectId)try{let value=(await sendCdpDeviceShellPageCommand(session,"Runtime.callFunctionOn",{objectId,functionDeclaration:READ_DOM_CHECKED_STATE_SOURCE,returnByValue:!0})).result?.value;return value===!0||value===!1||value==="mixed"?value:void 0}finally{await sendCdpDeviceShellPageCommand(session,"Runtime.releaseObject",{objectId}).catch(()=>{})}}function buildSnapshotTree(nodeMap,nodeId,snapshotRefs){let node=nodeMap.get(nodeId);if(!node)return null;let role=node.role?.value??"generic",name=node.name?.value??"",value=node.value?.value,description=node.description?.value;if(ALWAYS_SKIP_ROLES.has(role)||role==="StaticText"&&!name)return null;if(role==="SvgRoot"){let ref2;node.backendDOMNodeId!==void 0&&(ref2=snapshotRefs.register({backendNodeId:node.backendDOMNodeId,role,name}));let svgChildCount=node.childIds?.length??0;return{role:"SvgRoot",name:name||`(${svgChildCount} elements)`,backendDOMNodeId:node.backendDOMNodeId,ref:ref2}}let children=[];if(node.childIds)for(let childId of node.childIds){let child=buildSnapshotTree(nodeMap,childId,snapshotRefs);child&&children.push(child)}if(node.ignored)return children.length===0?null:children.length===1?children[0]:{role:"group",name:"",children};if(SKIP_ROLES.has(role)&&!name)return children.length===0?null:children.length===1?children[0]:{role:"group",name:"",children};children.length===1&&children[0].role==="StaticText"&&children[0].name===name&&!children[0].children&&(children.length=0);let ref;node.backendDOMNodeId!==void 0&&(ref=snapshotRefs.register({backendNodeId:node.backendDOMNodeId,role,name}));let props=extractAXProperties(node),result={role,name,backendDOMNodeId:node.backendDOMNodeId};return ref&&(result.ref=ref),value!==void 0&&value!==""&&(result.value=String(value)),description&&(result.description=description),props.focused&&(result.focused=!0),props.checked!==void 0&&(result.checked=props.checked),props.disabled&&(result.disabled=!0),props.required&&(result.required=!0),props.expanded!==void 0&&(result.expanded=props.expanded),props.selected&&(result.selected=!0),props.level!==void 0&&(result.level=props.level),children.length>0&&(result.children=children),result}async function resolveRootBackendNodeId(session,selector){let evaluated=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`document.querySelector(${JSON.stringify(selector)})`,returnByValue:!1});if(evaluated.exceptionDetails){let message=evaluated.exceptionDetails.exception?.description??evaluated.exceptionDetails.text??"invalid selector";throw new Error(`page_snapshot: invalid rootSelector "${selector}": ${message}`)}let objectId=evaluated.result?.objectId;if(!objectId||evaluated.result?.subtype==="null")throw new Error(`page_snapshot: rootSelector not found: ${selector}`);try{let backendNodeId=(await sendCdpDeviceShellPageCommand(session,"DOM.describeNode",{objectId})).node?.backendNodeId;if(backendNodeId===void 0)throw new Error(`page_snapshot: cannot resolve rootSelector: ${selector}`);return backendNodeId}finally{await sendCdpDeviceShellPageCommand(session,"Runtime.releaseObject",{objectId}).catch(()=>{})}}async function resolveAncestorBackendNodeId(session,backendNodeId,ancestorDepth){if(ancestorDepth===0)return backendNodeId;let objectId=(await sendCdpDeviceShellPageCommand(session,"DOM.resolveNode",{backendNodeId})).object?.objectId;if(!objectId)throw new Error("page_snapshot: cannot resolve rootRef in the current document");let ancestorObjectId;try{let ancestor=await sendCdpDeviceShellPageCommand(session,"Runtime.callFunctionOn",{objectId,functionDeclaration:`function(depth) {
|
|
763
763
|
let element = this && this.nodeType === 3 ? this.parentElement : this;
|
|
764
764
|
let remaining = depth;
|
|
765
765
|
while (element && element.parentElement && remaining > 0) {
|
|
@@ -767,8 +767,8 @@ ${candidates}`)}let hit=hits[0],dispatchTarget;if(effectiveClickMode==="dom"||po
|
|
|
767
767
|
remaining -= 1;
|
|
768
768
|
}
|
|
769
769
|
return element;
|
|
770
|
-
}`,arguments:[{value:ancestorDepth}],returnByValue:!1});if(ancestorObjectId=ancestor.result?.objectId,!ancestorObjectId||ancestor.result?.subtype==="null")throw new Error("page_snapshot: cannot resolve an ancestor for rootRef");let ancestorBackendNodeId=(await sendCdpDeviceShellPageCommand(session,"DOM.describeNode",{objectId:ancestorObjectId})).node?.backendNodeId;if(ancestorBackendNodeId===void 0)throw new Error("page_snapshot: cannot resolve an ancestor for rootRef");return ancestorBackendNodeId}finally{ancestorObjectId&&await sendCdpDeviceShellPageCommand(session,"Runtime.releaseObject",{objectId:ancestorObjectId}).catch(()=>{}),await sendCdpDeviceShellPageCommand(session,"Runtime.releaseObject",{objectId}).catch(()=>{})}}async function getViewportBackendNodeIds(session){let[metrics,captured]=await Promise.all([sendCdpDeviceShellPageCommand(session,"Page.getLayoutMetrics",{}),sendCdpDeviceShellPageCommand(session,"DOMSnapshot.captureSnapshot",{computedStyles:[],includeDOMRects:!0,includePaintOrder:!1})]),viewport=resolveDOMSnapshotViewportBounds(metrics);if(!viewport)throw new Error("page_snapshot: viewport metrics are unavailable");let{left,top,width,height}=viewport,right=left+width,bottom=top+height,visible=new Set;for(let document2 of captured.documents??[]){let backendNodeIds=document2.nodes?.backendNodeId??[],nodeIndexes=document2.layout?.nodeIndex??[],bounds=document2.layout?.bounds??[];for(let index=0;index<nodeIndexes.length;index+=1){let box=bounds[index],backendNodeId=backendNodeIds[nodeIndexes[index]];if(!box||backendNodeId===void 0)continue;let[x,y,boxWidth,boxHeight]=box;boxWidth<=0||boxHeight<=0||x<right&&x+boxWidth>left&&y<bottom&&y+boxHeight>top&&visible.add(backendNodeId)}}return visible}async function cdpPageSnapshot(session,data){let mode=data?.mode??"full",rootSelector=data?.rootSelector,rootRef=data?.rootRef,ancestorDepth=data?.ancestorDepth??0,query=resolvePageSnapshotQuery(data?.query);if(!["full","interactive","viewport"].includes(mode))throw new Error("page_snapshot: mode must be one of full, interactive, viewport");if(rootSelector!==void 0&&(typeof rootSelector!="string"||!rootSelector.trim()))throw new Error("page_snapshot: rootSelector must be a non-empty CSS selector");if(rootRef!==void 0&&(typeof rootRef!="string"||!/^@e\d+$/.test(rootRef)))throw new Error('page_snapshot: rootRef must be a snapshot ref like "@e3"');if(rootSelector!==void 0&&rootRef!==void 0)throw new Error("page_snapshot: rootSelector and rootRef are mutually exclusive");if(!Number.isInteger(ancestorDepth)||ancestorDepth<0||ancestorDepth>20)throw new Error("page_snapshot: ancestorDepth must be an integer between 0 and 20");if(ancestorDepth>0&&rootRef===void 0)throw new Error("page_snapshot: ancestorDepth requires rootRef");let rootBackendNodeId;if(rootSelector)rootBackendNodeId=await resolveRootBackendNodeId(session,rootSelector);else if(rootRef){let entry=resolvePageRef(session,rootRef);if(!entry)throw new Error(`Ref ${rootRef} not found. Run page_snapshot first to get fresh refs.`);rootBackendNodeId=await resolveAncestorBackendNodeId(session,entry.backendNodeId,ancestorDepth)}let snapshotRefs=beginPageSnapshotRefs(session),[result,visibleBackendNodeIds]=await Promise.all([sendCdpDeviceShellPageCommand(session,rootBackendNodeId===void 0?"Accessibility.getFullAXTree":"Accessibility.queryAXTree",rootBackendNodeId===void 0?{depth:data?.depth}:{backendNodeId:rootBackendNodeId}),mode==="viewport"||mode==="interactive"?getViewportBackendNodeIds(session):Promise.resolve(void 0)]),nodes=result.nodes??[];await reconcileAXCheckedStates(nodes,backendNodeId=>readDOMCheckedState2(session,backendNodeId));let nodeMap=new Map;for(let node of nodes)nodeMap.set(node.nodeId,node);let rootNode=nodes[0];if(!rootNode)return snapshotRefs.commit(new Set),{snapshot:"(empty page)",refs:{},elementCount:0,outputNodeCount:1,mode,...rootSelector?{rootSelector}:{},...rootRef?{rootRef,ancestorDepth}:{},...query?{query,matches:[],matchCount:0}:{}};let rawTree=buildSnapshotTree(nodeMap,rootNode.nodeId,snapshotRefs),viewportFilteredTree=mode==="interactive"?filterSnapshotTree(rawTree,"viewport",visibleBackendNodeIds):rawTree,effectiveMode=mode;mode==="interactive"&&!hasInteractiveSnapshotNode(viewportFilteredTree)&&(effectiveMode="viewport");let modeFilteredTree=mode==="interactive"?effectiveMode==="interactive"?filterSnapshotTree(viewportFilteredTree,"interactive"):viewportFilteredTree:filterSnapshotTree(rawTree,effectiveMode,visibleBackendNodeIds),queryResult=query?filterSnapshotTreeByQuery(modeFilteredTree,query):{tree:modeFilteredTree,matches:[]},limitedMatches=query?limitPageSnapshotQueryMatches(queryResult.matches):{matches:[],truncated:!1},tree=queryResult.tree,lines=[];tree&&formatSnapshotNode(tree,0,lines);let formatted=formatSnapshotWithLimits(lines.length>0?lines:[query?"(no matches)":"(empty page)"],{maxChars:data?.maxChars,maxNodes:data?.maxNodes}),refs={},outputRefKeys=new Set(Array.from(formatted.snapshot.matchAll(/(?:^|\n)\s*(@e\d+)\s/g),match=>match[1]));for(let match of limitedMatches.matches)match.ref&&outputRefKeys.add(match.ref);snapshotRefs.commit(outputRefKeys);let registry2=getPageRefRegistry(session);for(let ref of outputRefKeys){let entry=registry2.resolve(ref);entry&&(refs[ref.slice(1)]={backendNodeId:entry.backendNodeId})}return{snapshot:formatted.snapshot,refs,elementCount:countSnapshotNodes(tree),outputNodeCount:formatted.outputNodeCount,mode,...rootSelector?{rootSelector}:{},...rootRef?{rootRef,ancestorDepth}:{},...query?{query,matches:limitedMatches.matches,matchCount:queryResult.matches.length,...limitedMatches.truncated?{matchesTruncated:!0}:{}}:{},...effectiveMode!==mode?{fallbackMode:"viewport"}:{},...formatted.truncated?{truncated:!0}:{}}}async function cdpPageFrames(session,_data){let result=await session.client.sendCommand("Page.getFrameTree",{});function flattenFrameTree(tree){if(!tree)return[];let{frame,childFrames=[]}=tree;return[{frameId:frame.id,parentFrameId:frame.parentId??null,url:frame.url,name:frame.name??""},...childFrames.flatMap(flattenFrameTree)]}let frames=flattenFrameTree(result.frameTree);return{frames,count:frames.length}}registerActions([{name:"page_snapshot",session:"page",handler:cdpPageSnapshot},{name:"page_frames",session:"page",handler:cdpPageFrames}]);var MEARL_SERVICE_COOKIE_DOMAINS=["tdbank.alibaba-inc.com","ats2.alibaba-inc.com","g.alibaba-inc.com","login.alibaba-inc.com","token-hub.alibaba-inc.com","alibaba-inc.com"],MEARL_SERVICE_COOKIE_HOSTS=new Set(MEARL_SERVICE_COOKIE_DOMAINS);function normalizeCookieDomain2(input){let value=input.trim();if(!value)throw new Error("Cookie domain must be a non-empty string");let hostname3;try{hostname3=new URL(value.includes("://")?value:`https://${value}`).hostname}catch{throw new Error(`Invalid cookie domain: ${input}`)}if(hostname3=hostname3.toLowerCase().replace(/^\.+/,"").replace(/\.+$/,""),!hostname3)throw new Error(`Invalid cookie domain: ${input}`);return hostname3}function normalizeCookieDomains(inputs){if(!Array.isArray(inputs))throw new Error("copyCookieDomains must be an array of domains");return[...new Set(inputs.map(value=>normalizeCookieDomain2(String(value))))]}function isMearlServiceCookie(cookie){let domain2=normalizeCookieDomain2(cookie.domain);return MEARL_SERVICE_COOKIE_HOSTS.has(domain2)?!0:domain2.endsWith(".tdbank.alibaba-inc.com")||domain2.endsWith(".ats2.alibaba-inc.com")}function normalizeCookieCopyScope(input){let presets=input.presets??[];if(!Array.isArray(presets)||presets.some(preset=>preset!=="mearl-services"))throw new Error("copyCookieDomains.presets contains an unsupported preset");return{includeMearlServices:presets.includes("mearl-services"),domains:normalizeCookieDomains(input.domains??[])}}function resolveCookieCopyPlan(input){let includeMearlServices=!1,explicitDomains=[];if(input==="mearl-services")includeMearlServices=!0;else if(Array.isArray(input))explicitDomains=normalizeCookieDomains(input);else if(input!=null&&typeof input=="object"){let scope=normalizeCookieCopyScope(input);includeMearlServices=scope.includeMearlServices,explicitDomains=scope.domains}else if(input!==void 0)throw new Error('copyCookieDomains must be an array of domains, "mearl-services", or a scope object');return includeMearlServices?{domains:[...new Set([...MEARL_SERVICE_COOKIE_DOMAINS,...explicitDomains])],select:cookies=>cookies.filter(cookie=>isMearlServiceCookie(cookie)||explicitDomains.some(domain2=>cookieMatchesDomain(cookie.domain,domain2)))}:{domains:explicitDomains,select:cookies=>cookies}}function cookieMatchesDomain(cookieDomain,requestedDomain){let cookieHost=cookieDomain.toLowerCase().replace(/^\.+/,"");return cookieHost===requestedDomain||cookieHost.endsWith(`.${requestedDomain}`)||requestedDomain.endsWith(`.${cookieHost}`)}function toTransferableCookie(cookie){let result={name:String(cookie.name),value:String(cookie.value),domain:String(cookie.domain),path:String(cookie.path||"/"),secure:!!cookie.secure,httpOnly:!!cookie.httpOnly};return["Strict","Lax","None"].includes(cookie.sameSite)&&(result.sameSite=cookie.sameSite),typeof cookie.expires=="number"&&cookie.expires>0&&(result.expires=cookie.expires),["Low","Medium","High"].includes(cookie.priority)&&(result.priority=cookie.priority),typeof cookie.sameParty=="boolean"&&(result.sameParty=cookie.sameParty),["Unset","NonSecure","Secure"].includes(cookie.sourceScheme)&&(result.sourceScheme=cookie.sourceScheme),typeof cookie.sourcePort=="number"&&(result.sourcePort=cookie.sourcePort),cookie.partitionKey?.topLevelSite&&(result.partitionKey={topLevelSite:String(cookie.partitionKey.topLevelSite),...typeof cookie.partitionKey.hasCrossSiteAncestor=="boolean"?{hasCrossSiteAncestor:cookie.partitionKey.hasCrossSiteAncestor}:{}}),result}async function cdpExportCookies(session,domains){let requestedDomains=normalizeCookieDomains(domains);return((await(await session.getBrowserClient()).sendCommand("Storage.getCookies",{})).cookies??[]).filter(cookie=>requestedDomains.some(domain2=>cookieMatchesDomain(String(cookie.domain),domain2))).map(toTransferableCookie)}async function cdpImportCookies(session,cookies){if(cookies.length===0)return 0;let browser=await session.getBrowserClient();return cdpImportCookiesWithClient(browser,cookies)}async function cdpImportCookiesWithClient(browser,cookies){return cookies.length===0?0:(await browser.sendCommand("Storage.setCookies",{cookies}),cookies.length)}var BROWSERS_SUBDIR="browsers",STALE_RECORD_TTL_MS=5*6e4,FOCUS_WRITE_THROTTLE_MS=1e3,identity=null,logFn2=()=>{};function initBrowserRegistry(deps){logFn2=deps.log}function recordFileFor2(browserId){return keyedConfigFile(BROWSERS_SUBDIR,browserId)}function ownsRecord(browserId){let existing=readRecord(recordFileFor2(browserId));return!existing||existing.pid===process.pid||!isAlive(existing.pid)}function persist(patch){if(!identity)return;let file2=recordFileFor2(identity.browserId);if(!ownsRecord(identity.browserId))return;let previous=readRecord(file2),record2={pid:process.pid,browserId:identity.browserId,socketPath:identity.socketPath,browserName:identity.browserName,nativeHostVersion:identity.nativeHostVersion,transport:identity.transport,startedAt:identity.startedAt,lastFocusedAt:previous?.lastFocusedAt,extensionVersion:previous?.extensionVersion,...patch,updatedAt:Date.now()};try{writeRecord(file2,record2)}catch(error48){logFn2("browser-registry: failed to write record:",String(error48))}}function registerBrowser(info){let startedAt=identity?.startedAt??new Date().toISOString();identity={browserId:info.browserId,socketPath:info.socketPath,browserName:info.browserName,nativeHostVersion:info.nativeHostVersion,transport:info.transport,startedAt};let previous=readRecord(recordFileFor2(info.browserId));persist({lastFocusedAt:previous?.lastFocusedAt??info.lastFocusedAt??Date.now(),extensionVersion:info.extensionVersion}),logFn2(`browser-registry: registered ${info.browserName} (${info.browserId})`)}var lastFocusWriteAt=0,focusFlushTimer=null;function writeFocusNow(){lastFocusWriteAt=Date.now(),persist({lastFocusedAt:lastFocusWriteAt})}function touchFocus(){if(!identity)return;let elapsed=Date.now()-lastFocusWriteAt;if(elapsed>=FOCUS_WRITE_THROTTLE_MS){writeFocusNow();return}focusFlushTimer||(focusFlushTimer=setTimeout(()=>{focusFlushTimer=null,writeFocusNow()},FOCUS_WRITE_THROTTLE_MS-elapsed),focusFlushTimer.unref())}function unregisterBrowser(){if(focusFlushTimer&&(clearTimeout(focusFlushTimer),focusFlushTimer=null),!identity)return;let file2=recordFileFor2(identity.browserId),existing=readRecord(file2);existing&&existing.pid!==process.pid||removeRecord(file2)}function pruneDeadBrowsers(){let now=Date.now();for(let file2 of listRecordFiles(keyedDir(BROWSERS_SUBDIR))){let rec=readRecord(file2);if(!rec){removeRecord(file2);continue}isAlive(rec.pid)||now-(rec.updatedAt??0)>STALE_RECORD_TTL_MS&&removeRecord(file2)}}function listRegisteredBrowsers(){let records=[];for(let file2 of listRecordFiles(keyedDir(BROWSERS_SUBDIR))){let record2=readRecord(file2);record2&&isAlive(record2.pid)&&records.push(record2)}return records.sort((a,b)=>(b.lastFocusedAt??0)-(a.lastFocusedAt??0)||(b.updatedAt??0)-(a.updatedAt??0))}function providerIdentity(descriptor){return{id:descriptor.providerId,name:descriptor.name,builtin:descriptor.builtin===!0,version:descriptor.version,protocolVersion:descriptor.protocolVersion}}async function ensureDiscoverableCdpBrowser(discovery){return discovery.isPublished()?!0:await discovery.isAvailable()?(discovery.publish(),discovery.monitor(),!0):!1}function ordinaryBrowser(record2){return{browserId:record2.browserId,name:record2.browserName,type:"regular",status:record2.status==="pairing"?"pairing":"connected",extensionVersion:record2.extensionVersion,nativeHostVersion:record2.nativeHostVersion,transport:record2.transport,pairing:record2.pairing}}function externalProviderBrowser(record2){if(!record2.provider||!record2.persistence||!record2.operations)throw new Error(`Provider browser record is incomplete: ${record2.browserId}`);let status=record2.status??"connected";return{browserId:record2.browserId,name:record2.browserName,type:"managed",status,extensionVersion:record2.extensionVersion,nativeHostVersion:record2.nativeHostVersion,transport:record2.transport,provider:record2.provider,ownership:record2.ownership,persistence:record2.persistence,operations:record2.operations,pairing:record2.pairing,references:record2.references,details:record2.details}}function providerBrowserInfo(entry,route){let{browser,provider}=entry,status=route&&(route.status===void 0||route.status==="connected")?"connected":browser.status;return{browserId:browser.browserId,name:browser.name,type:"managed",status,transport:route?.transport??(browser.control.kind==="host"?browser.control.transport:provider.builtin?void 0:"provider"),extensionVersion:route?.extensionVersion,nativeHostVersion:route?.nativeHostVersion,provider,ownership:browser.ownership,persistence:browser.persistence,operations:browser.operations,pairing:browser.pairing,references:browser.references,details:browser.details}}function mergeBrowserInventory(routes,providerBrowsers){let providerById=new Map(providerBrowsers.map(entry=>[entry.browser.browserId,entry])),browsers=[];for(let route of routes){let providerEntry=providerById.get(route.browserId);providerEntry?(providerById.delete(route.browserId),browsers.push(providerBrowserInfo(providerEntry,route))):route.provider||route.transport==="provider"?browsers.push(externalProviderBrowser(route)):browsers.push(ordinaryBrowser(route))}let inactive=[...providerById.values()].sort((a,b)=>{let aCreated=String(a.browser.details?.createdAt??"");return String(b.browser.details?.createdAt??"").localeCompare(aCreated)}).map(entry=>providerBrowserInfo(entry));return browsers.push(...inactive),{count:browsers.length,connectedCount:browsers.filter(browser=>browser.status==="connected").length,browsers}}async function providerInventory(runtimes){return(await Promise.all(runtimes.map(async runtime=>{let provider=providerIdentity(runtime.definition.descriptor);return(await runtime.listBrowsers()).map(browser=>({provider,browser}))}))).flat()}async function listBrowserInventory(runtimes){return mergeBrowserInventory(listRegisteredBrowsers(),await providerInventory(runtimes))}import{randomUUID as randomUUID5}from"node:crypto";var NATIVE_HOST_VERSION="2.15.1";import fs3 from"node:fs";import os2 from"node:os";import path3 from"node:path";var MEARL_CONFIG_FILE=path3.join(os2.homedir(),".mearl","config.json");function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function readMearlConfig(configFile=MEARL_CONFIG_FILE){try{let parsed=JSON.parse(fs3.readFileSync(configFile,"utf8"));return isRecord(parsed)?parsed:{}}catch{return{}}}function writeMearlConfig(config2,configFile=MEARL_CONFIG_FILE){let configDirectory=path3.dirname(configFile),temporaryFile=`${configFile}.${process.pid}.tmp`;fs3.mkdirSync(configDirectory,{recursive:!0});try{fs3.writeFileSync(temporaryFile,`${JSON.stringify(config2,null,2)}
|
|
771
|
-
`,{mode:384}),fs3.renameSync(temporaryFile,configFile)}catch(error48){try{fs3.unlinkSync(temporaryFile)}catch{}throw error48}}
|
|
770
|
+
}`,arguments:[{value:ancestorDepth}],returnByValue:!1});if(ancestorObjectId=ancestor.result?.objectId,!ancestorObjectId||ancestor.result?.subtype==="null")throw new Error("page_snapshot: cannot resolve an ancestor for rootRef");let ancestorBackendNodeId=(await sendCdpDeviceShellPageCommand(session,"DOM.describeNode",{objectId:ancestorObjectId})).node?.backendNodeId;if(ancestorBackendNodeId===void 0)throw new Error("page_snapshot: cannot resolve an ancestor for rootRef");return ancestorBackendNodeId}finally{ancestorObjectId&&await sendCdpDeviceShellPageCommand(session,"Runtime.releaseObject",{objectId:ancestorObjectId}).catch(()=>{}),await sendCdpDeviceShellPageCommand(session,"Runtime.releaseObject",{objectId}).catch(()=>{})}}async function getViewportBackendNodeIds(session){let[metrics,captured]=await Promise.all([sendCdpDeviceShellPageCommand(session,"Page.getLayoutMetrics",{}),sendCdpDeviceShellPageCommand(session,"DOMSnapshot.captureSnapshot",{computedStyles:[],includeDOMRects:!0,includePaintOrder:!1})]),viewport=resolveDOMSnapshotViewportBounds(metrics);if(!viewport)throw new Error("page_snapshot: viewport metrics are unavailable");let{left,top,width,height}=viewport,right=left+width,bottom=top+height,visible=new Set;for(let document2 of captured.documents??[]){let backendNodeIds=document2.nodes?.backendNodeId??[],nodeIndexes=document2.layout?.nodeIndex??[],bounds=document2.layout?.bounds??[];for(let index=0;index<nodeIndexes.length;index+=1){let box=bounds[index],backendNodeId=backendNodeIds[nodeIndexes[index]];if(!box||backendNodeId===void 0)continue;let[x,y,boxWidth,boxHeight]=box;boxWidth<=0||boxHeight<=0||x<right&&x+boxWidth>left&&y<bottom&&y+boxHeight>top&&visible.add(backendNodeId)}}return visible}async function cdpPageSnapshot(session,data){let mode=data?.mode??"full",rootSelector=data?.rootSelector,rootRef=data?.rootRef,ancestorDepth=data?.ancestorDepth??0,query=resolvePageSnapshotQuery(data?.query);if(!["full","interactive","viewport"].includes(mode))throw new Error("page_snapshot: mode must be one of full, interactive, viewport");if(rootSelector!==void 0&&(typeof rootSelector!="string"||!rootSelector.trim()))throw new Error("page_snapshot: rootSelector must be a non-empty CSS selector");if(rootRef!==void 0&&(typeof rootRef!="string"||!/^@e\d+$/.test(rootRef)))throw new Error('page_snapshot: rootRef must be a snapshot ref like "@e3"');if(rootSelector!==void 0&&rootRef!==void 0)throw new Error("page_snapshot: rootSelector and rootRef are mutually exclusive");if(!Number.isInteger(ancestorDepth)||ancestorDepth<0||ancestorDepth>20)throw new Error("page_snapshot: ancestorDepth must be an integer between 0 and 20");if(ancestorDepth>0&&rootRef===void 0)throw new Error("page_snapshot: ancestorDepth requires rootRef");let rootBackendNodeId;if(rootSelector)rootBackendNodeId=await resolveRootBackendNodeId(session,rootSelector);else if(rootRef){let entry=resolvePageRef(session,rootRef);if(!entry)throw new Error(`Ref ${rootRef} not found. Run page_snapshot first to get fresh refs.`);rootBackendNodeId=await resolveAncestorBackendNodeId(session,entry.backendNodeId,ancestorDepth)}let snapshotRefs=beginPageSnapshotRefs(session),[result,visibleBackendNodeIds]=await Promise.all([sendCdpDeviceShellPageCommand(session,rootBackendNodeId===void 0?"Accessibility.getFullAXTree":"Accessibility.queryAXTree",rootBackendNodeId===void 0?{depth:data?.depth}:{backendNodeId:rootBackendNodeId}),mode==="viewport"||mode==="interactive"?getViewportBackendNodeIds(session):Promise.resolve(void 0)]),nodes=result.nodes??[];await reconcileAXCheckedStates(nodes,backendNodeId=>readDOMCheckedState2(session,backendNodeId));let nodeMap=new Map;for(let node of nodes)nodeMap.set(node.nodeId,node);let rootNode=nodes[0];if(!rootNode)return snapshotRefs.commit(new Set),{snapshot:"(empty page)",refs:{},elementCount:0,outputNodeCount:1,mode,...rootSelector?{rootSelector}:{},...rootRef?{rootRef,ancestorDepth}:{},...query?{query,matches:[],matchCount:0}:{}};let rawTree=buildSnapshotTree(nodeMap,rootNode.nodeId,snapshotRefs),viewportFilteredTree=mode==="interactive"?filterSnapshotTree(rawTree,"viewport",visibleBackendNodeIds):rawTree,effectiveMode=mode;mode==="interactive"&&!hasInteractiveSnapshotNode(viewportFilteredTree)&&(effectiveMode="viewport");let modeFilteredTree=mode==="interactive"?effectiveMode==="interactive"?filterSnapshotTree(viewportFilteredTree,"interactive"):viewportFilteredTree:filterSnapshotTree(rawTree,effectiveMode,visibleBackendNodeIds),queryResult=query?filterSnapshotTreeByQuery(modeFilteredTree,query):{tree:modeFilteredTree,matches:[]},limitedMatches=query?limitPageSnapshotQueryMatches(queryResult.matches):{matches:[],truncated:!1},tree=queryResult.tree,lines=[];tree&&formatSnapshotNode(tree,0,lines);let formatted=formatSnapshotWithLimits(lines.length>0?lines:[query?"(no matches)":"(empty page)"],{maxChars:data?.maxChars,maxNodes:data?.maxNodes}),refs={},outputRefKeys=new Set(Array.from(formatted.snapshot.matchAll(/(?:^|\n)\s*(@e\d+)\s/g),match=>match[1]));for(let match of limitedMatches.matches)match.ref&&outputRefKeys.add(match.ref);snapshotRefs.commit(outputRefKeys);let registry2=getPageRefRegistry(session);for(let ref of outputRefKeys){let entry=registry2.resolve(ref);entry&&(refs[ref.slice(1)]={backendNodeId:entry.backendNodeId})}return{snapshot:formatted.snapshot,refs,elementCount:countSnapshotNodes(tree),outputNodeCount:formatted.outputNodeCount,mode,...rootSelector?{rootSelector}:{},...rootRef?{rootRef,ancestorDepth}:{},...query?{query,matches:limitedMatches.matches,matchCount:queryResult.matches.length,...limitedMatches.truncated?{matchesTruncated:!0}:{}}:{},...effectiveMode!==mode?{fallbackMode:"viewport"}:{},...formatted.truncated?{truncated:!0}:{}}}async function cdpPageFrames(session,_data){let result=await session.client.sendCommand("Page.getFrameTree",{});function flattenFrameTree(tree){if(!tree)return[];let{frame,childFrames=[]}=tree;return[{frameId:frame.id,parentFrameId:frame.parentId??null,url:frame.url,name:frame.name??""},...childFrames.flatMap(flattenFrameTree)]}let frames=flattenFrameTree(result.frameTree);return{frames,count:frames.length}}registerActions([{name:"page_snapshot",session:"page",handler:cdpPageSnapshot},{name:"page_frames",session:"page",handler:cdpPageFrames}]);var MEARL_SERVICE_COOKIE_DOMAINS=["tdbank.alibaba-inc.com","ats2.alibaba-inc.com","g.alibaba-inc.com","login.alibaba-inc.com","token-hub.alibaba-inc.com","alibaba-inc.com"],MEARL_SERVICE_COOKIE_HOSTS=new Set(MEARL_SERVICE_COOKIE_DOMAINS);function normalizeCookieDomain2(input){let value=input.trim();if(!value)throw new Error("Cookie domain must be a non-empty string");let hostname3;try{hostname3=new URL(value.includes("://")?value:`https://${value}`).hostname}catch{throw new Error(`Invalid cookie domain: ${input}`)}if(hostname3=hostname3.toLowerCase().replace(/^\.+/,"").replace(/\.+$/,""),!hostname3)throw new Error(`Invalid cookie domain: ${input}`);return hostname3}function normalizeCookieDomains(inputs){if(!Array.isArray(inputs))throw new Error("copyCookieDomains must be an array of domains");return[...new Set(inputs.map(value=>normalizeCookieDomain2(String(value))))]}function isMearlServiceCookie(cookie){let domain2=normalizeCookieDomain2(cookie.domain);return MEARL_SERVICE_COOKIE_HOSTS.has(domain2)?!0:domain2.endsWith(".tdbank.alibaba-inc.com")||domain2.endsWith(".ats2.alibaba-inc.com")}function normalizeCookieCopyScope(input){let presets=input.presets??[];if(!Array.isArray(presets)||presets.some(preset=>preset!=="mearl-services"))throw new Error("copyCookieDomains.presets contains an unsupported preset");return{includeMearlServices:presets.includes("mearl-services"),domains:normalizeCookieDomains(input.domains??[])}}function resolveCookieCopyPlan(input){let includeMearlServices=!1,explicitDomains=[];if(input==="mearl-services")includeMearlServices=!0;else if(Array.isArray(input))explicitDomains=normalizeCookieDomains(input);else if(input!=null&&typeof input=="object"){let scope=normalizeCookieCopyScope(input);includeMearlServices=scope.includeMearlServices,explicitDomains=scope.domains}else if(input!==void 0)throw new Error('copyCookieDomains must be an array of domains, "mearl-services", or a scope object');return includeMearlServices?{domains:[...new Set([...MEARL_SERVICE_COOKIE_DOMAINS,...explicitDomains])],select:cookies=>cookies.filter(cookie=>isMearlServiceCookie(cookie)||explicitDomains.some(domain2=>cookieMatchesDomain(cookie.domain,domain2)))}:{domains:explicitDomains,select:cookies=>cookies}}function cookieMatchesDomain(cookieDomain,requestedDomain){let cookieHost=cookieDomain.toLowerCase().replace(/^\.+/,"");return cookieHost===requestedDomain||cookieHost.endsWith(`.${requestedDomain}`)||requestedDomain.endsWith(`.${cookieHost}`)}function toTransferableCookie(cookie){let result={name:String(cookie.name),value:String(cookie.value),domain:String(cookie.domain),path:String(cookie.path||"/"),secure:!!cookie.secure,httpOnly:!!cookie.httpOnly};return["Strict","Lax","None"].includes(cookie.sameSite)&&(result.sameSite=cookie.sameSite),typeof cookie.expires=="number"&&cookie.expires>0&&(result.expires=cookie.expires),["Low","Medium","High"].includes(cookie.priority)&&(result.priority=cookie.priority),typeof cookie.sameParty=="boolean"&&(result.sameParty=cookie.sameParty),["Unset","NonSecure","Secure"].includes(cookie.sourceScheme)&&(result.sourceScheme=cookie.sourceScheme),typeof cookie.sourcePort=="number"&&(result.sourcePort=cookie.sourcePort),cookie.partitionKey?.topLevelSite&&(result.partitionKey={topLevelSite:String(cookie.partitionKey.topLevelSite),...typeof cookie.partitionKey.hasCrossSiteAncestor=="boolean"?{hasCrossSiteAncestor:cookie.partitionKey.hasCrossSiteAncestor}:{}}),result}async function cdpExportCookies(session,domains){let requestedDomains=normalizeCookieDomains(domains);return((await(await session.getBrowserClient()).sendCommand("Storage.getCookies",{})).cookies??[]).filter(cookie=>requestedDomains.some(domain2=>cookieMatchesDomain(String(cookie.domain),domain2))).map(toTransferableCookie)}async function cdpImportCookies(session,cookies){if(cookies.length===0)return 0;let browser=await session.getBrowserClient();return cdpImportCookiesWithClient(browser,cookies)}async function cdpImportCookiesWithClient(browser,cookies){return cookies.length===0?0:(await browser.sendCommand("Storage.setCookies",{cookies}),cookies.length)}var BROWSERS_SUBDIR="browsers",STALE_RECORD_TTL_MS=5*6e4,FOCUS_WRITE_THROTTLE_MS=1e3,identity=null,logFn2=()=>{};function initBrowserRegistry(deps){logFn2=deps.log}function recordFileFor2(browserId){return keyedConfigFile(BROWSERS_SUBDIR,browserId)}function ownsRecord(browserId){let existing=readRecord(recordFileFor2(browserId));return!existing||existing.pid===process.pid||!isAlive(existing.pid)}function persist(patch){if(!identity)return;let file2=recordFileFor2(identity.browserId);if(!ownsRecord(identity.browserId))return;let previous=readRecord(file2),record2={pid:process.pid,browserId:identity.browserId,socketPath:identity.socketPath,browserName:identity.browserName,nativeHostVersion:identity.nativeHostVersion,transport:identity.transport,startedAt:identity.startedAt,lastFocusedAt:previous?.lastFocusedAt,extensionVersion:previous?.extensionVersion,...patch,updatedAt:Date.now()};try{writeRecord(file2,record2)}catch(error48){logFn2("browser-registry: failed to write record:",String(error48))}}function registerBrowser(info){let startedAt=identity?.startedAt??new Date().toISOString();identity={browserId:info.browserId,socketPath:info.socketPath,browserName:info.browserName,nativeHostVersion:info.nativeHostVersion,transport:info.transport,startedAt};let previous=readRecord(recordFileFor2(info.browserId));persist({lastFocusedAt:previous?.lastFocusedAt??info.lastFocusedAt??Date.now(),extensionVersion:info.extensionVersion}),logFn2(`browser-registry: registered ${info.browserName} (${info.browserId})`)}var lastFocusWriteAt=0,focusFlushTimer=null;function writeFocusNow(){lastFocusWriteAt=Date.now(),persist({lastFocusedAt:lastFocusWriteAt})}function touchFocus(){if(!identity)return;let elapsed=Date.now()-lastFocusWriteAt;if(elapsed>=FOCUS_WRITE_THROTTLE_MS){writeFocusNow();return}focusFlushTimer||(focusFlushTimer=setTimeout(()=>{focusFlushTimer=null,writeFocusNow()},FOCUS_WRITE_THROTTLE_MS-elapsed),focusFlushTimer.unref())}function unregisterBrowser(){if(focusFlushTimer&&(clearTimeout(focusFlushTimer),focusFlushTimer=null),!identity)return;let file2=recordFileFor2(identity.browserId),existing=readRecord(file2);existing&&existing.pid!==process.pid||removeRecord(file2)}function pruneDeadBrowsers(){let now=Date.now();for(let file2 of listRecordFiles(keyedDir(BROWSERS_SUBDIR))){let rec=readRecord(file2);if(!rec){removeRecord(file2);continue}isAlive(rec.pid)||now-(rec.updatedAt??0)>STALE_RECORD_TTL_MS&&removeRecord(file2)}}function listRegisteredBrowsers(){let records=[];for(let file2 of listRecordFiles(keyedDir(BROWSERS_SUBDIR))){let record2=readRecord(file2);record2&&isAlive(record2.pid)&&records.push(record2)}return records.sort((a,b)=>(b.lastFocusedAt??0)-(a.lastFocusedAt??0)||(b.updatedAt??0)-(a.updatedAt??0))}function providerIdentity(descriptor){return{id:descriptor.providerId,name:descriptor.name,builtin:descriptor.builtin===!0,version:descriptor.version,protocolVersion:descriptor.protocolVersion}}async function ensureDiscoverableCdpBrowser(discovery){return discovery.isPublished()?!0:await discovery.isAvailable()?(discovery.publish(),discovery.monitor(),!0):!1}function ordinaryBrowser(record2){return{browserId:record2.browserId,name:record2.browserName,type:"regular",status:record2.status==="pairing"?"pairing":"connected",extensionVersion:record2.extensionVersion,nativeHostVersion:record2.nativeHostVersion,transport:record2.transport,pairing:record2.pairing}}function externalProviderBrowser(record2){if(!record2.provider||!record2.persistence||!record2.operations)throw new Error(`Provider browser record is incomplete: ${record2.browserId}`);let status=record2.status??"connected";return{browserId:record2.browserId,name:record2.browserName,type:"managed",status,extensionVersion:record2.extensionVersion,nativeHostVersion:record2.nativeHostVersion,transport:record2.transport,provider:record2.provider,ownership:record2.ownership,persistence:record2.persistence,operations:record2.operations,pairing:record2.pairing,references:record2.references,details:record2.details}}function providerBrowserInfo(entry,route){let{browser,provider}=entry,status=route&&(route.status===void 0||route.status==="connected")?"connected":browser.status;return{browserId:browser.browserId,name:browser.name,type:"managed",status,transport:route?.transport??(browser.control.kind==="host"?browser.control.transport:provider.builtin?void 0:"provider"),extensionVersion:route?.extensionVersion,nativeHostVersion:route?.nativeHostVersion,provider,ownership:browser.ownership,persistence:browser.persistence,operations:browser.operations,pairing:browser.pairing,references:browser.references,details:browser.details}}function mergeBrowserInventory(routes,providerBrowsers){let providerById=new Map(providerBrowsers.map(entry=>[entry.browser.browserId,entry])),browsers=[];for(let route of routes){let providerEntry=providerById.get(route.browserId);providerEntry?(providerById.delete(route.browserId),browsers.push(providerBrowserInfo(providerEntry,route))):route.provider||route.transport==="provider"?browsers.push(externalProviderBrowser(route)):browsers.push(ordinaryBrowser(route))}let inactive=[...providerById.values()].sort((a,b)=>{let aCreated=String(a.browser.details?.createdAt??"");return String(b.browser.details?.createdAt??"").localeCompare(aCreated)}).map(entry=>providerBrowserInfo(entry));return browsers.push(...inactive),{count:browsers.length,connectedCount:browsers.filter(browser=>browser.status==="connected").length,browsers}}async function providerInventory(runtimes){return(await Promise.all(runtimes.map(async runtime=>{let provider=providerIdentity(runtime.definition.descriptor);return(await runtime.listBrowsers()).map(browser=>({provider,browser}))}))).flat()}async function listBrowserInventory(runtimes){return mergeBrowserInventory(listRegisteredBrowsers(),await providerInventory(runtimes))}import{randomUUID as randomUUID5}from"node:crypto";var NATIVE_HOST_VERSION="2.15.3";import fs3 from"node:fs";import os2 from"node:os";import path3 from"node:path";var MEARL_CONFIG_FILE=path3.join(os2.homedir(),".mearl","config.json");function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function readMearlConfig(configFile=MEARL_CONFIG_FILE){try{let parsed=JSON.parse(fs3.readFileSync(configFile,"utf8"));return isRecord(parsed)?parsed:{}}catch{return{}}}function writeMearlConfig(config2,configFile=MEARL_CONFIG_FILE){let configDirectory=path3.dirname(configFile),temporaryFile=`${configFile}.${process.pid}.tmp`;fs3.mkdirSync(configDirectory,{recursive:!0});try{fs3.writeFileSync(temporaryFile,`${JSON.stringify(config2,null,2)}
|
|
771
|
+
`,{mode:384}),fs3.renameSync(temporaryFile,configFile)}catch(error48){try{fs3.unlinkSync(temporaryFile)}catch{}throw error48}}var MEASUREMENT_ID="G-W84LJDZ6PH",API_SECRET="X233siI5RrGYLhlD0kBKEQ",ENDPOINT=`https://www.google-analytics.com/mp/collect?measurement_id=${MEASUREMENT_ID}&api_secret=${API_SECRET}`,CLIENT_ID_PATTERN=/^\d+\.\d+$/,BUILD_CHANNEL=NATIVE_HOST_VERSION==="unknown"?"development":"production";function writeConfig(config2){try{writeMearlConfig(config2)}catch{}}var clientId=null;function createClientId(seed=randomUUID5()){let first=2166136261,second=2246822519;for(let index=0;index<seed.length;index++){let code=seed.charCodeAt(index);first=Math.imul(first^code,16777619)>>>0,second=Math.imul(second^code,3266489917)>>>0}return`${first||1}.${second||1}`}function getClientId(){if(clientId)return clientId;let config2=readMearlConfig();return config2.clientId&&CLIENT_ID_PATTERN.test(config2.clientId)?(clientId=config2.clientId,clientId):(clientId=createClientId(config2.clientId),writeConfig({...config2,clientId}),clientId)}function setAnalyticsClientId(value){return typeof value!="string"||!CLIENT_ID_PATTERN.test(value)?!1:(clientId=value,!0)}function classifyAnalyticsError(error48){let message=error48 instanceof Error?error48.message:String(error48);return/timed?\s*out|timeout/i.test(message)?"timeout":/permission|not authorized|access denied|forbidden/i.test(message)?"permission_denied":/not found|no matching|does not exist/i.test(message)?"not_found":/not connected|disconnected|unavailable|connection (?:failed|closed)/i.test(message)?"unavailable":/invalid|required|must be|unsupported/i.test(message)?"invalid_request":"execution_error"}function trackAction(action,params){let payload={client_id:getClientId(),events:[{name:"agent_action",params:{action,...params,mearl_version:NATIVE_HOST_VERSION,runtime:"native_host",build_channel:BUILD_CHANNEL}}]};fetch(ENDPOINT,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(payload),keepalive:!0}).catch(()=>{})}import{open}from"node:fs/promises";import path5 from"node:path";var TRUNCATED_MARKER=`
|
|
772
772
|
… [middle truncated for Native Messaging] …
|
|
773
773
|
`;function truncateUtf82(value,maxBytes){if(Buffer.byteLength(value,"utf8")<=maxBytes)return value;let markerBytes=Buffer.byteLength(TRUNCATED_MARKER,"utf8");if(maxBytes<=markerBytes)return"";let source=Buffer.from(value,"utf8"),contentBytes=maxBytes-markerBytes,headBytes=Math.ceil(contentBytes/2),tailBytes=Math.floor(contentBytes/2);do{let truncated=`${source.subarray(0,headBytes).toString("utf8")}${TRUNCATED_MARKER}${source.subarray(source.length-tailBytes).toString("utf8")}`;if(Buffer.byteLength(truncated,"utf8")<=maxBytes)return truncated;headBytes>=tailBytes?headBytes-=1:tailBytes-=1}while(headBytes>0&&tailBytes>0);return""}function sanitizeValue(value,budget,depth){if(value===null||typeof value=="boolean"||typeof value=="number")return value;if(typeof value=="string"){let available=Math.max(0,budget.remaining),next2=truncateUtf82(value,available),bytes=Buffer.byteLength(next2,"utf8");return budget.remaining=Math.max(0,budget.remaining-bytes),next2!==value&&(budget.truncated=!0),next2}if(typeof value>"u")return null;if(typeof value!="object")return String(value);if(depth>=12||budget.remaining<=0)return budget.truncated=!0,{__transportTruncated:!0};if(budget.seen.has(value))return budget.truncated=!0,"[Circular]";if(budget.seen.add(value),Array.isArray(value)){let next2=value.slice(0,160).map(entry=>sanitizeValue(entry,budget,depth+1));return value.length>160&&(budget.truncated=!0,next2.push({__transportTruncated:!0,originalLength:value.length})),next2}let entries=Object.entries(value),next={};for(let[index,[key,entry]]of entries.entries()){if(index>=160||budget.remaining<=0){budget.truncated=!0;break}budget.remaining=Math.max(0,budget.remaining-Buffer.byteLength(key,"utf8")),next[key]=sanitizeValue(entry,budget,depth+1)}return budget.truncated&&(next.__transportTruncated=!0),next}function sanitizeAgentChatEvent(event){let budget={remaining:409600,truncated:!1,seen:new WeakSet},next={...event,params:sanitizeValue(event.params,budget,0)},bytes=Buffer.byteLength(JSON.stringify(next),"utf8");return bytes<=524288?next:{...event,params:{__transportTruncated:!0,originalBytes:bytes,message:"Agent event exceeded the Native Messaging transport limit."}}}import fs4 from"node:fs";import path4 from"node:path";import{execFile}from"node:child_process";function selectedPath(stdout){return stdout.replace(/[\r\n]+$/,"")||null}var runDirectoryPickerCommand=(command,args)=>new Promise((resolve2,reject)=>{execFile(command,args,{encoding:"utf8",windowsHide:!0},(error48,stdout)=>{if(!error48){resolve2(selectedPath(stdout));return}if(error48.code===1){resolve2(null);return}reject(error48)})});function isMissingCommand(error48){return error48 instanceof Error&&error48.code==="ENOENT"}async function pickWorkspaceDirectory(platform=process.platform,run=runDirectoryPickerCommand){let directory;if(platform==="darwin")directory=await run("osascript",["-e",'POSIX path of (choose folder with prompt "Select a workspace for Agent Chat")']);else if(platform==="win32"){let script=["Add-Type -AssemblyName System.Windows.Forms;","$dialog = New-Object System.Windows.Forms.FolderBrowserDialog;","$dialog.Description = 'Select a workspace for Agent Chat';","if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {","[Console]::OutputEncoding = [System.Text.Encoding]::UTF8;","Write-Output $dialog.SelectedPath;","}"].join(" ");directory=await run("powershell.exe",["-NoProfile","-STA","-Command",script])}else if(platform==="linux")try{directory=await run("zenity",["--file-selection","--directory","--title=Select a workspace for Agent Chat"])}catch(error48){if(!isMissingCommand(error48))throw error48;try{directory=await run("kdialog",["--getexistingdirectory",".","--title","Select a workspace for Agent Chat"])}catch(fallbackError){throw isMissingCommand(fallbackError)?new Error("Install zenity or kdialog to select an Agent Chat workspace",{cause:fallbackError}):fallbackError}}else throw new Error(`Directory selection is not supported on ${platform}`);return directory?resolveWorkspaceDirectory(directory):null}function resolveWorkspaceDirectory(directory){if(typeof directory!="string"||!directory)throw new Error("Workspace directory is required");if(!path4.isAbsolute(directory))throw new Error("Workspace directory must be an absolute path");let resolved;try{resolved=fs4.realpathSync.native(directory)}catch(error48){throw new Error(`Workspace directory does not exist: ${directory}`,{cause:error48})}if(!fs4.statSync(resolved).isDirectory())throw new Error(`Workspace path is not a directory: ${directory}`);return resolved}var MAX_REPLAY_EVENTS=1e3,MAX_REPLAY_BYTES=2048*1024,MAX_REPLAY_PAGE_BYTES=524288,MAX_SKILL_FILE_BYTES=1024*1024,SUPPORTED_IMAGE_MIME_TYPES=new Set(AGENT_CHAT_SUPPORTED_IMAGE_MIME_TYPES),REPLAY_SNAPSHOT_METHODS=new Set(["thread/settings/updated"]);function createAgentDeveloperInstructions({cwd,tabId,initialPageUrl,initialPageTitle}){return[...cwd?[createAgentDirectoryContextInstructions(cwd)]:[],...tabId!==void 0?[createBrowserAgentDeveloperInstructions(tabId,{...initialPageUrl?{url:initialPageUrl}:{},...initialPageTitle?{title:initialPageTitle}:{}})]:[]].join(`
|
|
774
774
|
|
|
@@ -824,7 +824,7 @@ ${output.stderr}`,"project")))}return{cli,updates:(await Promise.all(commands)).
|
|
|
824
824
|
`;for(;;)try{let handle=fs10.openSync(lockPath,"wx",384);try{fs10.writeFileSync(handle,owner,"utf8")}finally{fs10.closeSync(handle)}break}catch(error48){if(!(error48 instanceof Error)||!("code"in error48)||error48.code!=="EEXIST")throw error48;let existing=readLockState(lockPath),staleAfter=existing?.owner?NATIVE_HOST_UPDATE_TIMEOUT_MS:INVALID_UPDATE_LOCK_GRACE_MS,referenceTime=existing?.owner?.startedAt??existing?.modifiedAt,expired=referenceTime!==void 0&&Date.now()-referenceTime>staleAfter,ownerAlive=existing?.owner?isAlive(existing.owner.pid):!1;if(expired&&!ownerAlive)try{fs10.unlinkSync(lockPath);continue}catch{}if(Date.now()-startedAt>NATIVE_HOST_UPDATE_TIMEOUT_MS+1e4)throw new NativeHostUpdateFailure("lock-timeout","Another Mearl Native Host update did not finish in time");await wait(UPDATE_LOCK_POLL_MS)}try{return await operation()}finally{try{fs10.readFileSync(lockPath,"utf8")===owner&&fs10.unlinkSync(lockPath)}catch{}}}function classifyUpdateFailure(output){return/\b(?:E404|ETARGET)\b|no matching version found|404\s+not found|package.+not found/i.test(output)?"package-unavailable":/\b(?:EAI_AGAIN|ECONNREFUSED|ECONNRESET|ENETUNREACH|ENOTFOUND|ERR_SOCKET_TIMEOUT)\b|fetch failed|network request/i.test(output)?"network":"setup-failed"}function nativeHostUpdateCommand(targetVersion){if(!isMearlReleaseVersion(targetVersion))throw new Error("The Native Host update target must be a valid Mearl release");let releaseLine=mearlReleaseLineForVersion(targetVersion);return{args:["--yes",`@mearl/setup@${releaseLine}`,"update","--local","--yes","--target-line",releaseLine,"--skip-skill"]}}function currentNativeHostPackageRoot(entryPath){let current=path11.dirname(entryPath);for(let depth=0;depth<12;depth+=1){try{if(JSON.parse(fs10.readFileSync(path11.join(current,"package.json"),"utf8")).name==="@mearl/native-host")return current}catch{}let parent=path11.dirname(current);if(parent===current)break;current=parent}return null}function currentPackageManagerInstallation(environment,nodePath,platform){let packageRoot=currentNativeHostPackageRoot(fileURLToPath(import.meta.url));return packageRoot?resolvePackageManagerInstallation(packageRoot,"@mearl/native-host",{env:environment,platform,processExecPath:nodePath}):null}async function installedLocalPackagesMatch(targetReleaseLine,environment,runner){let installedVersions=[];for(let executableName of["mearl-native-host","mearl"]){let executable=findExecutable(executableName,{env:environment});if(!executable)return!1;try{let result=await runner(executable,["--version"],{capture:!0,env:environment,timeoutMs:5e3}),installedVersion=result.stdout.trim();if(result.code!==0||!isMearlReleaseVersionInLine(installedVersion,targetReleaseLine))return!1;installedVersions.push(installedVersion)}catch{return!1}}return new Set(installedVersions).size===1}async function runNativeHostUpdate(targetVersion,options={}){let command=nativeHostUpdateCommand(targetVersion),targetReleaseLine=mearlReleaseLineForVersion(targetVersion),environment=options.environment??process.env,platform=options.platform??process.platform,nodePath=options.nodePath??process.execPath,currentInstallation=currentPackageManagerInstallation(environment,nodePath,platform),managerCommand=options.packageManagerCommand===void 0?currentInstallation?.command??null:options.packageManagerCommand,packageBinDirectory=options.packageBinDirectory===void 0?currentInstallation?.binDirectory??null:options.packageBinDirectory,childEnvironment=prependNodePath(environment,nodePath);managerCommand&&(childEnvironment=prependCommandPath(managerCommand,childEnvironment)),packageBinDirectory&&(childEnvironment=prependPathDirectory(packageBinDirectory,childEnvironment));let packageRunner=options.packageRunner??findExecutable("npx",{env:childEnvironment,extraDirectories:[path11.dirname(nodePath)],platform});if(!packageRunner)throw new NativeHostUpdateFailure("package-unavailable","The package runner is unavailable");let runner=options.runner??runCommand,areTargetsInstalled=options.areTargetsInstalled??((version2,env)=>installedLocalPackagesMatch(version2,env,runner));await(options.withUpdateLock??((version2,operation)=>withNativeHostUpdateLock(options.updateLockPath??UPDATE_LOCK_PATH,version2,operation)))(targetVersion,async()=>{let result;try{result=await runner(packageRunner,command.args,{capture:!0,env:childEnvironment,timeoutMs:options.timeoutMs??NATIVE_HOST_UPDATE_TIMEOUT_MS})}catch(error48){let message=error48 instanceof Error?error48.message:String(error48),classified=classifyUpdateFailure(message);throw new NativeHostUpdateFailure(/timed out/i.test(message)?"timeout":classified==="setup-failed"?"unknown":classified,"The Native Host update process did not complete")}if(result.code!==0)throw new NativeHostUpdateFailure(classifyUpdateFailure(`${result.stderr.slice(0,8192)}
|
|
825
825
|
${result.stdout.slice(0,8192)}`),"The Mearl setup release line did not complete successfully");if(!await areTargetsInstalled(targetReleaseLine,childEnvironment))throw new NativeHostUpdateFailure("verification-failed","The installed Native Host and client do not match the Extension release line")})}var NativeHostUpdateCoordinator=class{constructor(options){this.options=options}#automaticAttempted=!1;#operation=null;evaluate(extensionVersion2,checkForUpdates){if(checkForUpdates!==!0||this.#automaticAttempted||this.#operation)return;if(!isMearlReleaseVersion(extensionVersion2)||!isMearlReleaseVersion(this.options.hostVersion)){this.options.log("Skipped Native Host update check because a release version was invalid");return}let targetVersion=extensionVersion2;if(compareMearlReleaseLines(this.options.hostVersion,targetVersion)>=0)return;this.#automaticAttempted=!0;let operation=this.options.runUpdate(targetVersion).then(()=>this.options.requestRestart()).catch(error48=>{let category=error48 instanceof NativeHostUpdateFailure?error48.updateError:"unknown";this.options.log(`Native Host automatic update failed (${category})`)}).finally(()=>{this.#operation===operation&&(this.#operation=null)});this.#operation=operation}};import fs15 from"node:fs";import path15 from"node:path";import{randomUUID as randomUUID7}from"node:crypto";import fs14 from"node:fs";import os8 from"node:os";import path14 from"node:path";import{createHash as createHash2,randomUUID as randomUUID6}from"node:crypto";import WebSocket2 from"ws";init_generated_browser_action_protocol();var OBSERVED_PAGE_ACTIONS=new Set(PAGE_ACT_ACTIONS2);import net from"node:net";import fs13 from"node:fs";import os7 from"node:os";import path13 from"node:path";import{createRequire}from"node:module";import fs11 from"node:fs";import fs12 from"node:fs";import os6 from"node:os";import path12 from"node:path";var BROWSERS_DIR=path12.join(os6.homedir(),".mearl","browsers");var require2=createRequire(import.meta.url),CLIENT_VERSION=require2("../package.json").version,MAX_SOCKET_BUFFER_SIZE=64*1024*1024,SOCKET_PATH=process.platform==="win32"?"\\\\.\\pipe\\mearl-agent":path13.join(os7.tmpdir(),"mearl-agent.sock");import{existsSync as existsSync5,readFileSync as readFileSync4}from"node:fs";import{homedir as homedir2}from"node:os";import{join as join5}from"node:path";var MEARL_CONFIG_DIR=join5(homedir2(),".mearl");var import_extract_zip=__toESM(require_extract_zip(),1);import WebSocket3 from"ws";var MEARL_EXTENSION_DOWNLOAD_PAGE="https://mearl.alibaba-inc.com/",MEARL_EXTENSION_REMOTE_CONFIG_URL=`${MEARL_EXTENSION_DOWNLOAD_PAGE}config.json`;var MEARL_EXTENSION_ID="aoehhjnofngknnjefamjbplchbolghkm",MEARL_EXTENSION_SETUP_MARKER=".mearl-setup.json";var MAX_ARCHIVE_BYTES=64*1024*1024,SHA256_PATTERN=/^[a-f\d]{64}$/i;function extensionArchiveUrl(version2){if(!isMearlReleaseVersion(version2))throw new Error(`Invalid Mearl browser extension version: ${version2}`);return new URL(`mearl-chrome-v${version2}.zip`,MEARL_EXTENSION_DOWNLOAD_PAGE).toString()}function validateExtensionRelease(release){if(!isMearlReleaseVersion(release.version))throw new Error("Remote extension config has an invalid latestVersion");let expectedArchiveUrl=extensionArchiveUrl(release.version),archiveUrl;try{archiveUrl=new URL(release.archiveUrl).toString()}catch{throw new Error("Remote extension config has an invalid downloadUrl")}if(archiveUrl!==expectedArchiveUrl)throw new Error("Remote extension downloadUrl does not match latestVersion");if(release.sha256!==void 0&&!SHA256_PATTERN.test(release.sha256))throw new Error("Remote extension config has an invalid downloadSha256");return{archiveUrl,...release.sha256?{sha256:release.sha256.toLowerCase()}:{},version:release.version}}async function fetchBrowserExtensionRelease(fetchImpl=fetch){let response=await fetchImpl(MEARL_EXTENSION_REMOTE_CONFIG_URL,{cache:"no-store"});if(!response.ok)throw new Error(`Extension config returned HTTP ${response.status}`);let config2=await response.json();return validateExtensionRelease({archiveUrl:typeof config2.downloadUrl=="string"?config2.downloadUrl:"",...typeof config2.downloadSha256=="string"?{sha256:config2.downloadSha256}:{},version:typeof config2.latestVersion=="string"?config2.latestVersion:""})}function sameExtensionPath(left,right){let normalizedLeft=path14.normalize(path14.resolve(left)),normalizedRight=path14.normalize(path14.resolve(right));return process.platform==="win32"?normalizedLeft.toLowerCase()===normalizedRight.toLowerCase():normalizedLeft===normalizedRight}function setupMarkerPath(directory){return path14.join(directory,MEARL_EXTENSION_SETUP_MARKER)}function hasSetupMarker(targetDirectory){try{let marker=JSON.parse(fs14.readFileSync(setupMarkerPath(targetDirectory),"utf8"));return marker.schemaVersion===1&&marker.extensionId===MEARL_EXTENSION_ID&&typeof marker.path=="string"&&sameExtensionPath(marker.path,targetDirectory)}catch{return!1}}async function writeSetupMarker(directory,targetDirectory){let marker={extensionId:MEARL_EXTENSION_ID,path:path14.resolve(targetDirectory),schemaVersion:1};await fs14.promises.writeFile(setupMarkerPath(directory),`${JSON.stringify(marker,null,2)}
|
|
826
826
|
`,{mode:384})}async function replaceDirectory(stagingDirectory,targetDirectory){let backupDirectory=`${targetDirectory}.backup-${randomUUID6()}`,targetExists=fs14.existsSync(targetDirectory);try{targetExists&&await fs14.promises.rename(targetDirectory,backupDirectory),await fs14.promises.rename(stagingDirectory,targetDirectory)}catch(error48){throw!fs14.existsSync(targetDirectory)&&fs14.existsSync(backupDirectory)&&await fs14.promises.rename(backupDirectory,targetDirectory),error48}targetExists&&await fs14.promises.rm(backupDirectory,{force:!0,recursive:!0})}function readExtensionManifest(directory){let manifestPath=path14.join(directory,"manifest.json"),parsed;try{parsed=JSON.parse(fs14.readFileSync(manifestPath,"utf8"))}catch(error48){throw new Error(`Downloaded extension has no valid manifest.json: ${error48 instanceof Error?error48.message:error48}`,{cause:error48})}if(parsed.manifest_version!==3||typeof parsed.name!="string"||typeof parsed.key!="string"||parsed.key.length===0)throw new Error("Downloaded archive is not a valid Manifest V3 extension");if(!isMearlReleaseVersion(parsed.version))throw new Error("Downloaded extension manifest has an invalid version");return parsed}async function downloadAndReplaceExtension(releaseInput,targetDirectory,fetchImpl,extractArchive){let release=validateExtensionRelease(releaseInput),parentDirectory=path14.dirname(targetDirectory),stagingDirectory=`${targetDirectory}.staging-${randomUUID6()}`,archivePath=path14.join(parentDirectory,`.mearl-extension-${randomUUID6()}.zip`);await fs14.promises.mkdir(parentDirectory,{recursive:!0});try{let response=await fetchImpl(release.archiveUrl,{redirect:"follow"});if(!response.ok)throw new Error(`Extension archive returned HTTP ${response.status}: ${release.archiveUrl}`);if(Number(response.headers.get("content-length")??0)>MAX_ARCHIVE_BYTES)throw new Error(`Extension archive exceeds ${MAX_ARCHIVE_BYTES} bytes`);let archive=Buffer.from(await response.arrayBuffer());if(archive.length===0||archive.length>MAX_ARCHIVE_BYTES)throw new Error("Extension archive is empty or too large");if(release.sha256&&createHash2("sha256").update(archive).digest("hex")!==release.sha256)throw new Error("Extension archive SHA256 does not match remote config");await fs14.promises.writeFile(archivePath,archive,{mode:384}),await fs14.promises.mkdir(stagingDirectory,{recursive:!0}),await extractArchive(archivePath,stagingDirectory);let manifest=readExtensionManifest(stagingDirectory);if(manifest.version!==release.version)throw new Error(`Extension archive version ${String(manifest.version)} does not match ${release.version}`);return await writeSetupMarker(stagingDirectory,targetDirectory),await replaceDirectory(stagingDirectory,targetDirectory),release}finally{await fs14.promises.rm(archivePath,{force:!0}),await fs14.promises.rm(stagingDirectory,{force:!0,recursive:!0})}}async function updateSetupManagedBrowserExtensionFiles(options,dependencies={}){let targetDirectory=path14.resolve(options.targetDirectory);if(!hasSetupMarker(targetDirectory))throw new Error("The running extension is not managed by Mearl setup");let fetchImpl=dependencies.fetch??fetch,extractArchive=dependencies.extractArchive??((archivePath,destination)=>(0,import_extract_zip.default)(archivePath,{dir:destination}));return{...await downloadAndReplaceExtension(options.release,targetDirectory,fetchImpl,extractArchive),path:targetDirectory}}var EXTENSION_UPDATE_LOCK_PATH=path15.join(DAEMON_HOME,"extension-update.lock"),EXTENSION_UPDATE_LOCK_STALE_MS=10*6e4,INVALID_UPDATE_LOCK_GRACE_MS2=1e4;function readUpdateLock(lockPath){try{let stat2=fs15.lstatSync(lockPath);if(!stat2.isFile()||stat2.isSymbolicLink()||stat2.size>4096)return{modifiedAt:stat2.mtimeMs,owner:null};try{let value=JSON.parse(fs15.readFileSync(lockPath,"utf8")),owner=typeof value.id=="string"&&Number.isInteger(value.pid)&&(value.pid??0)>0&&typeof value.startedAt=="number"?value:null;return{modifiedAt:stat2.mtimeMs,owner}}catch{return{modifiedAt:stat2.mtimeMs,owner:null}}}catch{return null}}async function withExtensionUpdateLock(operation,dependencies){let lockPath=dependencies.lockPath??EXTENSION_UPDATE_LOCK_PATH,now=dependencies.now??Date.now,isProcessAlive=dependencies.isProcessAlive??isAlive;fs15.mkdirSync(path15.dirname(lockPath),{recursive:!0,mode:448});let owner={id:randomUUID7(),pid:process.pid,startedAt:now()},serializedOwner=`${JSON.stringify(owner)}
|
|
827
|
-
`;for(let attempt=0;attempt<2;attempt+=1)try{fs15.writeFileSync(lockPath,serializedOwner,{encoding:"utf8",flag:"wx",mode:384});break}catch(error48){if(!(error48 instanceof Error)||!("code"in error48)||error48.code!=="EEXIST")throw error48;let state=readUpdateLock(lockPath);if(!(state===null||(state.owner?now()-state.owner.startedAt>EXTENSION_UPDATE_LOCK_STALE_MS&&!isProcessAlive(state.owner.pid):now()-state.modifiedAt>INVALID_UPDATE_LOCK_GRACE_MS2))||attempt>0)throw new Error("Another extension update is already running",{cause:error48});try{fs15.unlinkSync(lockPath)}catch(unlinkError){throw new Error("Another extension update is already running",{cause:unlinkError})}}try{return await operation()}finally{try{fs15.readFileSync(lockPath,"utf8")===serializedOwner&&fs15.unlinkSync(lockPath)}catch{}}}async function updateSetupManagedExtension(request,dependencies={}){if(!isMearlReleaseVersion(request.currentVersion))throw new Error("The running extension reported an invalid version");if(!request.setupManagedPath||!path15.isAbsolute(request.setupManagedPath))throw new Error("A setup-managed extension path is required");let release=await(dependencies.fetchRelease??fetchBrowserExtensionRelease)(),changelogUrl=`https://mearl.alibaba-inc.com/changelog.html#v${release.version}`;return compareMearlReleaseVersions(release.version,request.currentVersion)<=0?{changelogUrl,updated:!1,version:request.currentVersion}:withExtensionUpdateLock(async()=>(await(dependencies.updateFiles??updateSetupManagedBrowserExtensionFiles)({release,targetDirectory:request.setupManagedPath}),{changelogUrl,updated:!0,version:release.version}),dependencies)}var PERSISTENT_DAEMON_OPTIONS=["--browser-headless","--browser-id","--browser-name","--cdp-endpoint-file","--cdp-port","--cdp-user-data-dir"];function shouldExitWithoutLegacySocket(options,hasLegacySocket){return!hasLegacySocket&&options.discoverCdp}function stripNativeMessagingLaunchArgs(argv){let[origin,parentWindow,...rest]=argv;return/^chrome-extension:\/\/[a-z]{32}\/$/.test(origin??"")?/^--parent-window=\d+$/.test(parentWindow??"")?rest:argv.slice(1):argv}function hasExplicitDaemonConfig(argv){let args=stripNativeMessagingLaunchArgs(argv);return args.includes("--daemon")?args.some(argument=>PERSISTENT_DAEMON_OPTIONS.some(option=>argument===option||argument.startsWith(`${option}=`))):!1}function toNativeHostDaemonConfig(options){return{browserHeadless:options.browserHeadless,browserId:options.browserId,browserName:options.browserName,...options.cdpEndpointFile?{cdpEndpointFile:options.cdpEndpointFile}:{},cdpPort:options.cdpPort,...options.cdpUserDataDir?{cdpUserDataDir:options.cdpUserDataDir}:{}}}async function parseNativeHostRuntimeArgs(argv,persistedDaemonConfig){let args=stripNativeMessagingLaunchArgs(argv),options={},readValue=(index,name)=>{let argument=args[index];if(argument===name){let value=args[index+1];if(value===void 0||value.startsWith("-"))throw new Error(`argument missing for option '${name}'`);return{nextIndex:index+1,value}}return argument?.startsWith(`${name}=`)?{nextIndex:index,value:argument.slice(name.length+1)}:null},parseInteger=(value,label,minimum,maximum)=>{let parsed=Number(value);if(!Number.isInteger(parsed)||parsed<minimum||parsed>maximum)throw new Error(`${label} must be an integer from ${minimum} to ${maximum}`);return parsed};for(let index=0;index<args.length;index+=1){let argument=args[index];if(argument==="--daemon"){options.daemon=!0;continue}if(argument==="--discover-cdp"){options.discoverCdp=!0;continue}if(argument==="--skip-browser-registration"){options.skipBrowserRegistration=!0;continue}if(argument==="--browser-headless"){options.browserHeadless=!0;continue}if(argument==="--version"||argument==="-v"){options.version=!0;continue}if(argument==="--help"||argument==="-h"){options.help=!0;continue}let cdpPort=readValue(index,"--cdp-port");if(cdpPort){options.cdpPort=parseInteger(cdpPort.value,"cdp-port",1,65535),index=cdpPort.nextIndex;continue}let stringOptions=[["--cdp-user-data-dir","cdpUserDataDir"],["--cdp-endpoint-file","cdpEndpointFile"],["--browser-id","browserId"],["--browser-name","browserName"]],matchedStringOption=!1;for(let[name,property]of stringOptions){let parsed=readValue(index,name);if(parsed){options[property]=parsed.value,index=parsed.nextIndex,matchedStringOption=!0;break}}if(!matchedStringOption)throw new Error(argument?.startsWith("-")?`unknown option '${argument}'`:`unexpected argument '${argument}'`)}let daemonDefaults=options.daemon&&!hasExplicitDaemonConfig(argv)?persistedDaemonConfig:void 0;return{browserHeadless:options.browserHeadless??daemonDefaults?.browserHeadless??!1,browserId:options.browserId??daemonDefaults?.browserId??"cdp",browserName:options.browserName??daemonDefaults?.browserName??"CDP",...options.cdpEndpointFile??daemonDefaults?.cdpEndpointFile?{cdpEndpointFile:options.cdpEndpointFile??daemonDefaults?.cdpEndpointFile}:{},cdpPort:options.cdpPort??daemonDefaults?.cdpPort??9222,...options.cdpUserDataDir??daemonDefaults?.cdpUserDataDir?{cdpUserDataDir:options.cdpUserDataDir??daemonDefaults?.cdpUserDataDir}:{},daemon:options.daemon===!0,discoverCdp:options.discoverCdp===!0,help:options.help===!0,skipBrowserRegistration:options.skipBrowserRegistration===!0,version:options.version===!0}}var OPEN_SANDBOX_PORT_PLACEHOLDER="{port}",AONE_PORT_MAPPING_URL="http://127.0.0.1:58596/api/port-mapping";function normalizeBrowserAccessUrl(value){if(typeof value!="string"||!value.trim())return null;let input=/^[a-z][a-z\d+.-]*:\/\//i.test(value.trim())?value.trim():`https://${value.trim()}`;try{let parsed=new URL(input);return parsed.protocol==="ws:"&&(parsed.protocol="http:"),parsed.protocol==="wss:"&&(parsed.protocol="https:"),!["http:","https:"].includes(parsed.protocol)||!parsed.hostname?null:parsed.toString()}catch{return null}}function resolveSandboxBrowserAccessCapability(env=process.env){return env.OPENSANDBOX_ID?.trim()?{kind:"sandbox-novnc",environment:"opensandbox",port:6080}:env.AONE_SANDBOX_ID?.trim()?{kind:"sandbox-novnc",environment:"aone",port:6080}:null}function resolveOpenSandboxBrowserAccessUrl(port,env=process.env){if(!env.OPENSANDBOX_ID?.trim())return null;let template=env.AONE_SANDBOX_ENDPOINT_TEMPLATE?.trim();return template?.includes(OPEN_SANDBOX_PORT_PLACEHOLDER)?normalizeBrowserAccessUrl(template.replaceAll(OPEN_SANDBOX_PORT_PLACEHOLDER,String(port))):null}async function resolveAoneBrowserAccessUrl(port,dependencies){let response=await(dependencies.fetch??globalThis.fetch)(`${AONE_PORT_MAPPING_URL}?port=${port}`,{signal:AbortSignal.timeout(5e3)});if(!response.ok)throw new Error(`AONE Sandbox port mapping failed with HTTP ${response.status}`);let payload=await response.json(),url2=payload.success?normalizeBrowserAccessUrl(payload.url):null;if(!url2)throw new Error(`AONE Sandbox did not return a browser access URL for port ${port}`);return url2}async function resolveSandboxBrowserAccess(dependencies={}){let env=dependencies.env??process.env,capability=resolveSandboxBrowserAccessCapability(env);if(!capability)throw new Error("The selected browser is not running in a supported sandbox");if(capability.environment==="opensandbox"){let url3=resolveOpenSandboxBrowserAccessUrl(capability.port,env);if(url3)return{...capability,url:url3};if(!env.AONE_SANDBOX_ID?.trim())throw new Error("OpenSandbox browser access is unavailable because AONE_SANDBOX_ENDPOINT_TEMPLATE is missing or invalid")}let url2=await resolveAoneBrowserAccessUrl(capability.port,dependencies);return{...capability,environment:"aone",url:url2}}import net2 from"node:net";import{chmodSync,rmSync as rmSync3}from"node:fs";import{dirname as dirname3}from"node:path";var MAX_REQUEST_BYTES=16*1024*1024;import{closeSync as closeSync4,existsSync as existsSync6,mkdtempSync,mkdirSync as mkdirSync3,openSync as openSync4,readFileSync as readFileSync5,renameSync as renameSync4,rmSync as rmSync4,writeFileSync as writeFileSync3}from"node:fs";import{spawn as spawn9,spawnSync as spawnSync2}from"node:child_process";import{randomUUID as randomUUID8}from"node:crypto";import{tmpdir}from"node:os";import{join as join6}from"node:path";function stoppedPersistentBrowserRecord(record2,deleteProfile){if(deleteProfile||record2.persistent!==!0)return null;let stopped={...record2,pid:0};return"hostPid"in stopped?{...stopped,hostPid:0}:stopped}var MANAGED_BROWSERS_SUBDIR="managed-browsers",MANAGED_BROWSER_LOCKS_SUBDIR="managed-browser-locks",MANAGED_PROFILES_SUBDIR="managed-profiles",LAUNCH_TIMEOUT_MS=15e3;function validateName(value){let name=typeof value=="string"?value.trim():"";if(!name)throw new Error("name is required");if(name.length>64)throw new Error("name must be at most 64 characters");if(/[/\\\0\r\n]/.test(name))throw new Error("name contains unsupported characters");return name}function managedBrowserId(name){return`managed:${name.toLocaleLowerCase("en-US")}`}function chromeExecutableCandidates(platform=process.platform){let envPath=process.env.MEARL_CHROME_PATH,candidates=envPath?[envPath]:[];if(platform==="darwin")return candidates.concat(["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary","/Applications/Chromium.app/Contents/MacOS/Chromium"]);if(platform==="win32"){let local=process.env.LOCALAPPDATA??"",programFiles=process.env.PROGRAMFILES??"",programFilesX86=process.env["PROGRAMFILES(X86)"]??"";return candidates.concat([join6(local,"Google","Chrome","Application","chrome.exe"),join6(programFiles,"Google","Chrome","Application","chrome.exe"),join6(programFilesX86,"Google","Chrome","Application","chrome.exe")])}return candidates.concat(["/usr/bin/google-chrome","/usr/bin/google-chrome-stable","/usr/bin/chromium","/usr/bin/chromium-browser"])}function resolveChromeExecutable(explicitPath){if(explicitPath){if(!existsSync6(explicitPath))throw new Error(`Chrome executable not found: ${explicitPath}`);return explicitPath}let found=chromeExecutableCandidates().find(candidate=>candidate&&existsSync6(candidate));if(!found)throw new Error("Chrome executable not found. Set executablePath or MEARL_CHROME_PATH.");return found}function desktopChromeUserAgent(version2,platform=process.platform){if(!/^\d+(?:\.\d+){1,3}$/.test(version2))throw new Error(`Invalid Chrome version: ${version2}`);return`Mozilla/5.0 (${platform==="darwin"?"Macintosh; Intel Mac OS X 10_15_7":platform==="win32"?"Windows NT 10.0; Win64; x64":"X11; Linux x86_64"}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version2} Safari/537.36`}function resolveChromeVersion(executablePath){let result=spawnSync2(executablePath,["--version"],{encoding:"utf8",windowsHide:!0}),version2=`${result.stdout??""} ${result.stderr??""}`.match(/\b(\d+(?:\.\d+){1,3})\b/)?.[1];if(!version2)throw new Error(`Could not determine Chrome version from: ${executablePath}`);return version2}function resolveUserAgentMode(value){if(value===void 0||value==="default")return"default";if(value==="desktop")return"desktop";throw new Error('userAgentMode must be "default" or "desktop"')}function buildManagedChromeArgs(options){return[`--user-data-dir=${options.userDataDir}`,"--remote-debugging-port=0","--no-first-run","--no-default-browser-check","--disable-background-networking",...options.headless?["--headless=new"]:[],...options.userAgent?[`--user-agent=${options.userAgent}`]:[],"about:blank"]}function browserSummary(record2,running){return{browserId:record2.browserId,name:record2.name,provider:"local",headless:record2.headless,persistent:record2.persistent,cdpPort:record2.cdpPort,createdAt:record2.createdAt,copiedCookies:record2.copiedCookies,running}}function isManagedProcess(pid,commandMarker,platform=process.platform){if(!isAlive(pid))return!1;try{if(platform==="win32"){let escapedMarker=commandMarker.replace(/'/g,"''");return spawnSync2("powershell.exe",["-NoProfile","-NonInteractive","-Command",`$p = Get-CimInstance Win32_Process -Filter 'ProcessId = ${pid}'; if ($p.CommandLine -and $p.CommandLine.Contains('${escapedMarker}')) { exit 0 } else { exit 1 }`],{windowsHide:!0,stdio:"ignore"}).status===0}let result=spawnSync2("ps",["-p",String(pid),"-o","command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return result.status===0&&result.stdout.includes(commandMarker)}catch{return!1}}function listRecords(){let records=[];for(let file2 of listRecordFiles(keyedDir(MANAGED_BROWSERS_SUBDIR))){let record2=readRecord(file2);if(!record2){removeRecord(file2);continue}let running=isManagedProcess(record2.pid,record2.userDataDir);if(!running&&(signalProcess(record2.hostPid,"SIGTERM",`--browser-id ${record2.browserId}`),removeRecord(keyedConfigFile("browsers",record2.browserId)),!record2.persistent)){removeRecord(file2),rmSync4(record2.userDataDir,{recursive:!0,force:!0});continue}records.push({record:record2,running})}return records}function listManagedBrowsers(){return listRecords().map(({record:record2,running})=>browserSummary(record2,running))}function findManagedRecord(selector){let normalized=selector.trim().toLowerCase();return listRecords().find(({record:record2})=>record2.browserId.toLowerCase()===normalized||record2.name.toLowerCase()===normalized)?.record??null}async function waitForActivePort(userDataDir){let deadline=Date.now()+LAUNCH_TIMEOUT_MS;for(;Date.now()<deadline;){let info=readDevToolsActivePort(userDataDir);if(info)return info.port;await new Promise(resolve2=>setTimeout(resolve2,100))}throw new Error(`Chrome did not expose a CDP port within ${LAUNCH_TIMEOUT_MS}ms`)}async function waitForBrowserRegistration(browserId,expectedPid){let file2=keyedConfigFile("browsers",browserId),deadline=Date.now()+LAUNCH_TIMEOUT_MS;for(;Date.now()<deadline;){if(readRecord(file2)?.pid===expectedPid&&isAlive(expectedPid))return;await new Promise(resolve2=>setTimeout(resolve2,100))}throw new Error(`Managed browser ${browserId} did not register within ${LAUNCH_TIMEOUT_MS}ms`)}function signalProcess(pid,signal,commandMarker){if(isManagedProcess(pid,commandMarker)){if(process.platform==="win32"){spawnSync2("taskkill",["/PID",String(pid),"/T","/F"],{windowsHide:!0,stdio:"ignore"});return}try{process.kill(pid,signal)}catch{}}}async function stopProcess(pid,commandMarker){signalProcess(pid,"SIGTERM",commandMarker);let deadline=Date.now()+3e3;for(;Date.now()<deadline&&isManagedProcess(pid,commandMarker);)await new Promise(resolve2=>setTimeout(resolve2,50));isManagedProcess(pid,commandMarker)&&signalProcess(pid,"SIGKILL",commandMarker)}function profileDirectory(browserId,persistent){if(!persistent)return mkdtempSync(join6(tmpdir(),"mearl-browser-"));let dir=join6(DAEMON_HOME,MANAGED_PROFILES_SUBDIR,hashKey(browserId));return mkdirSync3(dir,{recursive:!0}),dir}async function removeStoppedInstance(browserId){let file2=keyedConfigFile(MANAGED_BROWSERS_SUBDIR,browserId),record2=readRecord(file2);!record2||isManagedProcess(record2.pid,record2.userDataDir)||(await stopProcess(record2.hostPid,`--browser-id ${record2.browserId}`),removeRecord(file2),removeRecord(keyedConfigFile("browsers",record2.browserId)),record2.persistent||rmSync4(record2.userDataDir,{recursive:!0,force:!0}))}function acquireLaunchLock(browserId){let lockDir=keyedDir(MANAGED_BROWSER_LOCKS_SUBDIR),lockFile=keyedConfigFile(MANAGED_BROWSER_LOCKS_SUBDIR,browserId);mkdirSync3(lockDir,{recursive:!0});let token=`${process.pid}:${randomUUID8()}`,tryAcquire=()=>{try{return writeFileSync3(lockFile,token,{flag:"wx"}),!0}catch(error48){if(error48.code!=="EEXIST")throw error48;return!1}};if(!tryAcquire()){let observedToken="";try{observedToken=readFileSync5(lockFile,"utf-8")}catch{}let ownerPid=Number(observedToken.split(":",1)[0]);if(Number.isInteger(ownerPid)&&!isAlive(ownerPid)){let staleFile=`${lockFile}.${process.pid}.${randomUUID8()}.stale`;try{if(readFileSync5(lockFile,"utf-8")!==observedToken)throw new Error("Launch lock owner changed");if(renameSync4(lockFile,staleFile),readFileSync5(staleFile,"utf-8")===observedToken)rmSync4(staleFile,{force:!0});else try{renameSync4(staleFile,lockFile)}catch{}}catch{}}if(!tryAcquire())throw new Error(`Managed browser launch already in progress: ${browserId}`)}return()=>{try{readFileSync5(lockFile,"utf-8")===token&&rmSync4(lockFile,{force:!0})}catch{}}}async function launchManagedBrowser(input,deps){let name=validateName(input.name),browserId=managedBrowserId(name),cookieCopy=resolveCookieCopyPlan(input.copyCookieDomains),copyCookieDomains=cookieCopy.domains,headless=input.headless!==!1,persistent=input.persistent===!0,executablePath=resolveChromeExecutable(input.executablePath),userAgent=resolveUserAgentMode(input.userAgentMode)==="desktop"?desktopChromeUserAgent(resolveChromeVersion(executablePath)):void 0,userDataDir=profileDirectory(browserId,persistent),logDir=keyedDir(MANAGED_BROWSERS_SUBDIR);mkdirSync3(logDir,{recursive:!0});let logPath=join6(logDir,`${hashKey(browserId)}.log`),logFd=openSync4(logPath,"a"),chromePid=0,hostPid=0,session=null,recordWritten=!1,releaseLock=null;try{if(releaseLock=acquireLaunchLock(browserId),await removeStoppedInstance(browserId),findManagedRecord(browserId))throw new Error(`Managed browser already running: ${browserId}`);let exportedCookies=copyCookieDomains.length>0?await deps.exportCookies(copyCookieDomains):[],cookies=cookieCopy.select(exportedCookies),chromeArgs=buildManagedChromeArgs({userDataDir,headless,userAgent});rmSync4(join6(userDataDir,"DevToolsActivePort"),{force:!0});let chrome=spawn9(executablePath,chromeArgs,{detached:!0,stdio:["ignore","ignore",logFd],windowsHide:headless});if(await new Promise((resolve2,reject)=>{chrome.once("error",reject),chrome.once("spawn",resolve2)}),chromePid=chrome.pid??0,!chromePid)throw new Error("Chrome launched without a process id");chrome.unref();let cdpPort=await waitForActivePort(userDataDir);session=new CdpSession({port:cdpPort,userDataDir});let copiedCookieCount=await cdpImportCookies(session,cookies);input.url&&await(await session.getBrowserClient()).sendCommand("Target.createTarget",{url:input.url,background:headless}),session.close(),session=null;let host=spawn9(process.execPath,[deps.nativeHostScript,"--daemon","--cdp-port",String(cdpPort),"--cdp-user-data-dir",userDataDir,"--browser-id",browserId,"--browser-name",name,...headless?["--browser-headless"]:[]],{detached:!0,stdio:"ignore",windowsHide:!0});if(await new Promise((resolve2,reject)=>{host.once("error",reject),host.once("spawn",resolve2)}),hostPid=host.pid??0,!hostPid)throw new Error("Native host launched without a process id");host.unref();let record2={pid:chromePid,hostPid,browserId,name,headless,persistent,userDataDir,executablePath,cdpPort,createdAt:new Date().toISOString(),...copyCookieDomains.length>0?{copiedCookies:{domains:copyCookieDomains,count:copiedCookieCount}}:{}};return writeRecord(keyedConfigFile(MANAGED_BROWSERS_SUBDIR,browserId),record2),recordWritten=!0,await waitForBrowserRegistration(browserId,hostPid),deps.log(`managed browser launched: ${browserId}, chrome=${chromePid}, host=${hostPid}`),{...browserSummary(record2,!0),created:!0,reused:!1}}catch(error48){throw session?.close(),hostPid&&await stopProcess(hostPid,`--browser-id ${browserId}`),chromePid&&await stopProcess(chromePid,userDataDir),recordWritten&&removeRecord(keyedConfigFile(MANAGED_BROWSERS_SUBDIR,browserId)),persistent||rmSync4(userDataDir,{recursive:!0,force:!0}),error48}finally{releaseLock?.(),closeSync4(logFd)}}async function closeManagedBrowser(selector,options={}){let record2=findManagedRecord(selector);if(!record2)throw new Error(`Managed browser not found: ${selector}`);let recordFile=keyedConfigFile(MANAGED_BROWSERS_SUBDIR,record2.browserId);await stopProcess(record2.pid,record2.userDataDir);let closingOwnHost=record2.hostPid===process.pid;closingOwnHost||await stopProcess(record2.hostPid,`--browser-id ${record2.browserId}`),removeRecord(keyedConfigFile("browsers",record2.browserId));let deleteProfile=options.deleteProfile===!0||!record2.persistent,stoppedRecord=stoppedPersistentBrowserRecord(record2,deleteProfile);return stoppedRecord?writeRecord(recordFile,stoppedRecord):(removeRecord(recordFile),rmSync4(record2.userDataDir,{recursive:!0,force:!0})),closingOwnHost&&setTimeout(()=>process.kill(process.pid,"SIGTERM"),250).unref(),{browserId:record2.browserId,closed:!0,profileDeleted:deleteProfile}}var commonLaunchProperties={name:{type:"string",minLength:1},persistent:{type:"boolean",default:!0},copyCookieDomains:{type:"object",component:"cookie-sync",properties:{presets:{type:"array",items:{type:"string",enum:["mearl-services"]}},domains:{type:"array",items:{type:"string",minLength:1}}}}};function connectedBrowserIds(){return new Set(listRegisteredBrowsers().filter(browser=>browser.status===void 0||browser.status==="connected").map(browser=>browser.browserId))}function commonDetails(browser){return{headless:browser.headless,createdAt:browser.createdAt,...browser.copiedCookies?{copiedCookies:{domains:browser.copiedCookies.domains,count:browser.copiedCookies.count}}:{}}}function localBrowser(browser,connected){let stopped=!browser.running;return{browserId:browser.browserId,name:browser.name,status:stopped?"stopped":connected.has(browser.browserId)?"connected":"running_disconnected",control:stopped?{kind:"none"}:{kind:"host",transport:"cdp",browserId:browser.browserId},ownership:"owned",persistence:browser.persistent?"persistent":"ephemeral",operations:stopped?["start","deleteData"]:["close","deleteData"],references:[{kind:"profile",id:browser.browserId,label:"Profile"}],details:{...commonDetails(browser),cdpPort:browser.cdpPort}}}function localDefinition(deps){return{descriptor:{providerId:"local",name:"Local Chrome",version:NATIVE_HOST_VERSION,protocolVersion:2,builtin:!0},browserType:{name:"本地浏览器",inputSchema:{type:"object",required:["name"],additionalProperties:!0,properties:{...commonLaunchProperties,headless:{type:"boolean",default:!0}}}},listBrowsers:()=>{let connected=connectedBrowserIds();return listManagedBrowsers().map(browser=>localBrowser(browser,connected))},launch:async options=>{let summary=await launchManagedBrowser(options,{nativeHostScript:deps.nativeHostScript,exportCookies:deps.exportCookies,log:deps.log});return localBrowser(summary,connectedBrowserIds())},start:async({browserId})=>{let summary=listManagedBrowsers().find(browser=>browser.browserId===browserId);if(!summary)throw new Error(`Local browser not found: ${browserId}`);let launched=await launchManagedBrowser({name:summary.name,persistent:summary.persistent,headless:summary.headless},{nativeHostScript:deps.nativeHostScript,exportCookies:deps.exportCookies,log:deps.log});return localBrowser(launched,connectedBrowserIds())},close:({browserId,deleteData})=>closeManagedBrowser(browserId,{deleteProfile:deleteData})}}function createBuiltinBrowserProviders(deps){return[createProviderRuntime(localDefinition(deps))]}import net3 from"node:net";var MAX_RESPONSE_BUFFER_SIZE=16*1024*1024;function requestBrowserSocket(socketPath,action,data,version2,timeoutMs=6e4,browserId,host){let id=`browser_manager_${Date.now()}_${Math.random().toString(36).slice(2,10)}`;return new Promise((resolve2,reject)=>{let client2=net3.createConnection(socketPath),lines=new Utf8LineBuffer(MAX_RESPONSE_BUFFER_SIZE),settled=!1,finish=(error48,result)=>{settled||(settled=!0,clearTimeout(timer),client2.removeAllListeners(),client2.destroy(),error48?reject(error48):resolve2(result))},timer=setTimeout(()=>finish(new Error(`Browser request timeout after ${timeoutMs}ms`)),timeoutMs);client2.on("connect",()=>{client2.write(`${JSON.stringify({id,action,data,version:version2,controlSource:"local",...browserId?{browserId}:{},...host?{host}:{}})}
|
|
827
|
+
`;for(let attempt=0;attempt<2;attempt+=1)try{fs15.writeFileSync(lockPath,serializedOwner,{encoding:"utf8",flag:"wx",mode:384});break}catch(error48){if(!(error48 instanceof Error)||!("code"in error48)||error48.code!=="EEXIST")throw error48;let state=readUpdateLock(lockPath);if(!(state===null||(state.owner?now()-state.owner.startedAt>EXTENSION_UPDATE_LOCK_STALE_MS&&!isProcessAlive(state.owner.pid):now()-state.modifiedAt>INVALID_UPDATE_LOCK_GRACE_MS2))||attempt>0)throw new Error("Another extension update is already running",{cause:error48});try{fs15.unlinkSync(lockPath)}catch(unlinkError){throw new Error("Another extension update is already running",{cause:unlinkError})}}try{return await operation()}finally{try{fs15.readFileSync(lockPath,"utf8")===serializedOwner&&fs15.unlinkSync(lockPath)}catch{}}}async function updateSetupManagedExtension(request,dependencies={}){if(!isMearlReleaseVersion(request.currentVersion))throw new Error("The running extension reported an invalid version");if(!request.setupManagedPath||!path15.isAbsolute(request.setupManagedPath))throw new Error("A setup-managed extension path is required");let release=await(dependencies.fetchRelease??fetchBrowserExtensionRelease)(),changelogUrl=`https://mearl.alibaba-inc.com/changelog.html#v${release.version}`;return compareMearlReleaseVersions(release.version,request.currentVersion)<=0?{changelogUrl,updated:!1,version:request.currentVersion}:withExtensionUpdateLock(async()=>(await(dependencies.updateFiles??updateSetupManagedBrowserExtensionFiles)({release,targetDirectory:request.setupManagedPath}),{changelogUrl,updated:!0,version:release.version}),dependencies)}function shouldExitWithoutLegacySocket(options,hasLegacySocket){return!hasLegacySocket&&options.discoverCdp}function stripNativeMessagingLaunchArgs(argv){let[origin,parentWindow,...rest]=argv;return/^chrome-extension:\/\/[a-z]{32}\/$/.test(origin??"")?/^--parent-window=\d+$/.test(parentWindow??"")?rest:argv.slice(1):argv}async function parseNativeHostRuntimeArgs(argv){let args=stripNativeMessagingLaunchArgs(argv),options={},readValue=(index,name)=>{let argument=args[index];if(argument===name){let value=args[index+1];if(value===void 0||value.startsWith("-"))throw new Error(`argument missing for option '${name}'`);return{nextIndex:index+1,value}}return argument?.startsWith(`${name}=`)?{nextIndex:index,value:argument.slice(name.length+1)}:null},parseInteger=(value,label,minimum,maximum)=>{let parsed=Number(value);if(!Number.isInteger(parsed)||parsed<minimum||parsed>maximum)throw new Error(`${label} must be an integer from ${minimum} to ${maximum}`);return parsed};for(let index=0;index<args.length;index+=1){let argument=args[index];if(argument==="--daemon"){options.daemon=!0;continue}if(argument==="--discover-cdp"){options.discoverCdp=!0;continue}if(argument==="--skip-browser-registration"){options.skipBrowserRegistration=!0;continue}if(argument==="--browser-headless"){options.browserHeadless=!0;continue}if(argument==="--version"||argument==="-v"){options.version=!0;continue}if(argument==="--help"||argument==="-h"){options.help=!0;continue}let cdpPort=readValue(index,"--cdp-port");if(cdpPort){options.cdpPort=parseInteger(cdpPort.value,"cdp-port",1,65535),index=cdpPort.nextIndex;continue}let stringOptions=[["--cdp-user-data-dir","cdpUserDataDir"],["--cdp-endpoint-file","cdpEndpointFile"],["--browser-id","browserId"],["--browser-name","browserName"]],matchedStringOption=!1;for(let[name,property]of stringOptions){let parsed=readValue(index,name);if(parsed){options[property]=parsed.value,index=parsed.nextIndex,matchedStringOption=!0;break}}if(!matchedStringOption)throw new Error(argument?.startsWith("-")?`unknown option '${argument}'`:`unexpected argument '${argument}'`)}return{browserHeadless:options.browserHeadless??!1,browserId:options.browserId??"cdp",browserName:options.browserName??"CDP",...options.cdpEndpointFile?{cdpEndpointFile:options.cdpEndpointFile}:{},cdpPort:options.cdpPort??9222,...options.cdpUserDataDir?{cdpUserDataDir:options.cdpUserDataDir}:{},daemon:options.daemon===!0,discoverCdp:options.discoverCdp===!0,help:options.help===!0,skipBrowserRegistration:options.skipBrowserRegistration===!0,version:options.version===!0}}var OPEN_SANDBOX_PORT_PLACEHOLDER="{port}",AONE_PORT_MAPPING_URL="http://127.0.0.1:58596/api/port-mapping";function normalizeBrowserAccessUrl(value){if(typeof value!="string"||!value.trim())return null;let input=/^[a-z][a-z\d+.-]*:\/\//i.test(value.trim())?value.trim():`https://${value.trim()}`;try{let parsed=new URL(input);return parsed.protocol==="ws:"&&(parsed.protocol="http:"),parsed.protocol==="wss:"&&(parsed.protocol="https:"),!["http:","https:"].includes(parsed.protocol)||!parsed.hostname?null:parsed.toString()}catch{return null}}function resolveSandboxBrowserAccessCapability(env=process.env){return env.OPENSANDBOX_ID?.trim()?{kind:"sandbox-novnc",environment:"opensandbox",port:6080}:env.AONE_SANDBOX_ID?.trim()?{kind:"sandbox-novnc",environment:"aone",port:6080}:null}function resolveOpenSandboxBrowserAccessUrl(port,env=process.env){if(!env.OPENSANDBOX_ID?.trim())return null;let template=env.AONE_SANDBOX_ENDPOINT_TEMPLATE?.trim();return template?.includes(OPEN_SANDBOX_PORT_PLACEHOLDER)?normalizeBrowserAccessUrl(template.replaceAll(OPEN_SANDBOX_PORT_PLACEHOLDER,String(port))):null}async function resolveAoneBrowserAccessUrl(port,dependencies){let response=await(dependencies.fetch??globalThis.fetch)(`${AONE_PORT_MAPPING_URL}?port=${port}`,{signal:AbortSignal.timeout(5e3)});if(!response.ok)throw new Error(`AONE Sandbox port mapping failed with HTTP ${response.status}`);let payload=await response.json(),url2=payload.success?normalizeBrowserAccessUrl(payload.url):null;if(!url2)throw new Error(`AONE Sandbox did not return a browser access URL for port ${port}`);return url2}async function resolveSandboxBrowserAccess(dependencies={}){let env=dependencies.env??process.env,capability=resolveSandboxBrowserAccessCapability(env);if(!capability)throw new Error("The selected browser is not running in a supported sandbox");if(capability.environment==="opensandbox"){let url3=resolveOpenSandboxBrowserAccessUrl(capability.port,env);if(url3)return{...capability,url:url3};if(!env.AONE_SANDBOX_ID?.trim())throw new Error("OpenSandbox browser access is unavailable because AONE_SANDBOX_ENDPOINT_TEMPLATE is missing or invalid")}let url2=await resolveAoneBrowserAccessUrl(capability.port,dependencies);return{...capability,environment:"aone",url:url2}}import net2 from"node:net";import{chmodSync,rmSync as rmSync3}from"node:fs";import{dirname as dirname3}from"node:path";var MAX_REQUEST_BYTES=16*1024*1024;import{closeSync as closeSync4,existsSync as existsSync6,mkdtempSync,mkdirSync as mkdirSync3,openSync as openSync4,readFileSync as readFileSync5,renameSync as renameSync4,rmSync as rmSync4,writeFileSync as writeFileSync3}from"node:fs";import{spawn as spawn9,spawnSync as spawnSync2}from"node:child_process";import{randomUUID as randomUUID8}from"node:crypto";import{tmpdir}from"node:os";import{join as join6}from"node:path";function stoppedPersistentBrowserRecord(record2,deleteProfile){if(deleteProfile||record2.persistent!==!0)return null;let stopped={...record2,pid:0};return"hostPid"in stopped?{...stopped,hostPid:0}:stopped}var MANAGED_BROWSERS_SUBDIR="managed-browsers",MANAGED_BROWSER_LOCKS_SUBDIR="managed-browser-locks",MANAGED_PROFILES_SUBDIR="managed-profiles",LAUNCH_TIMEOUT_MS=15e3;function validateName(value){let name=typeof value=="string"?value.trim():"";if(!name)throw new Error("name is required");if(name.length>64)throw new Error("name must be at most 64 characters");if(/[/\\\0\r\n]/.test(name))throw new Error("name contains unsupported characters");return name}function managedBrowserId(name){return`managed:${name.toLocaleLowerCase("en-US")}`}function chromeExecutableCandidates(platform=process.platform){let envPath=process.env.MEARL_CHROME_PATH,candidates=envPath?[envPath]:[];if(platform==="darwin")return candidates.concat(["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary","/Applications/Chromium.app/Contents/MacOS/Chromium"]);if(platform==="win32"){let local=process.env.LOCALAPPDATA??"",programFiles=process.env.PROGRAMFILES??"",programFilesX86=process.env["PROGRAMFILES(X86)"]??"";return candidates.concat([join6(local,"Google","Chrome","Application","chrome.exe"),join6(programFiles,"Google","Chrome","Application","chrome.exe"),join6(programFilesX86,"Google","Chrome","Application","chrome.exe")])}return candidates.concat(["/usr/bin/google-chrome","/usr/bin/google-chrome-stable","/usr/bin/chromium","/usr/bin/chromium-browser"])}function resolveChromeExecutable(explicitPath){if(explicitPath){if(!existsSync6(explicitPath))throw new Error(`Chrome executable not found: ${explicitPath}`);return explicitPath}let found=chromeExecutableCandidates().find(candidate=>candidate&&existsSync6(candidate));if(!found)throw new Error("Chrome executable not found. Set executablePath or MEARL_CHROME_PATH.");return found}function desktopChromeUserAgent(version2,platform=process.platform){if(!/^\d+(?:\.\d+){1,3}$/.test(version2))throw new Error(`Invalid Chrome version: ${version2}`);return`Mozilla/5.0 (${platform==="darwin"?"Macintosh; Intel Mac OS X 10_15_7":platform==="win32"?"Windows NT 10.0; Win64; x64":"X11; Linux x86_64"}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version2} Safari/537.36`}function resolveChromeVersion(executablePath){let result=spawnSync2(executablePath,["--version"],{encoding:"utf8",windowsHide:!0}),version2=`${result.stdout??""} ${result.stderr??""}`.match(/\b(\d+(?:\.\d+){1,3})\b/)?.[1];if(!version2)throw new Error(`Could not determine Chrome version from: ${executablePath}`);return version2}function resolveUserAgentMode(value){if(value===void 0||value==="default")return"default";if(value==="desktop")return"desktop";throw new Error('userAgentMode must be "default" or "desktop"')}function buildManagedChromeArgs(options){return[`--user-data-dir=${options.userDataDir}`,"--remote-debugging-port=0","--no-first-run","--no-default-browser-check","--disable-background-networking",...options.headless?["--headless=new"]:[],...options.userAgent?[`--user-agent=${options.userAgent}`]:[],"about:blank"]}function browserSummary(record2,running){return{browserId:record2.browserId,name:record2.name,provider:"local",headless:record2.headless,persistent:record2.persistent,cdpPort:record2.cdpPort,createdAt:record2.createdAt,copiedCookies:record2.copiedCookies,running}}function isManagedProcess(pid,commandMarker,platform=process.platform){if(!isAlive(pid))return!1;try{if(platform==="win32"){let escapedMarker=commandMarker.replace(/'/g,"''");return spawnSync2("powershell.exe",["-NoProfile","-NonInteractive","-Command",`$p = Get-CimInstance Win32_Process -Filter 'ProcessId = ${pid}'; if ($p.CommandLine -and $p.CommandLine.Contains('${escapedMarker}')) { exit 0 } else { exit 1 }`],{windowsHide:!0,stdio:"ignore"}).status===0}let result=spawnSync2("ps",["-p",String(pid),"-o","command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return result.status===0&&result.stdout.includes(commandMarker)}catch{return!1}}function listRecords(){let records=[];for(let file2 of listRecordFiles(keyedDir(MANAGED_BROWSERS_SUBDIR))){let record2=readRecord(file2);if(!record2){removeRecord(file2);continue}let running=isManagedProcess(record2.pid,record2.userDataDir);if(!running&&(signalProcess(record2.hostPid,"SIGTERM",`--browser-id ${record2.browserId}`),removeRecord(keyedConfigFile("browsers",record2.browserId)),!record2.persistent)){removeRecord(file2),rmSync4(record2.userDataDir,{recursive:!0,force:!0});continue}records.push({record:record2,running})}return records}function listManagedBrowsers(){return listRecords().map(({record:record2,running})=>browserSummary(record2,running))}function findManagedRecord(selector){let normalized=selector.trim().toLowerCase();return listRecords().find(({record:record2})=>record2.browserId.toLowerCase()===normalized||record2.name.toLowerCase()===normalized)?.record??null}async function waitForActivePort(userDataDir){let deadline=Date.now()+LAUNCH_TIMEOUT_MS;for(;Date.now()<deadline;){let info=readDevToolsActivePort(userDataDir);if(info)return info.port;await new Promise(resolve2=>setTimeout(resolve2,100))}throw new Error(`Chrome did not expose a CDP port within ${LAUNCH_TIMEOUT_MS}ms`)}async function waitForBrowserRegistration(browserId,expectedPid){let file2=keyedConfigFile("browsers",browserId),deadline=Date.now()+LAUNCH_TIMEOUT_MS;for(;Date.now()<deadline;){if(readRecord(file2)?.pid===expectedPid&&isAlive(expectedPid))return;await new Promise(resolve2=>setTimeout(resolve2,100))}throw new Error(`Managed browser ${browserId} did not register within ${LAUNCH_TIMEOUT_MS}ms`)}function signalProcess(pid,signal,commandMarker){if(isManagedProcess(pid,commandMarker)){if(process.platform==="win32"){spawnSync2("taskkill",["/PID",String(pid),"/T","/F"],{windowsHide:!0,stdio:"ignore"});return}try{process.kill(pid,signal)}catch{}}}async function stopProcess(pid,commandMarker){signalProcess(pid,"SIGTERM",commandMarker);let deadline=Date.now()+3e3;for(;Date.now()<deadline&&isManagedProcess(pid,commandMarker);)await new Promise(resolve2=>setTimeout(resolve2,50));isManagedProcess(pid,commandMarker)&&signalProcess(pid,"SIGKILL",commandMarker)}function profileDirectory(browserId,persistent){if(!persistent)return mkdtempSync(join6(tmpdir(),"mearl-browser-"));let dir=join6(DAEMON_HOME,MANAGED_PROFILES_SUBDIR,hashKey(browserId));return mkdirSync3(dir,{recursive:!0}),dir}async function removeStoppedInstance(browserId){let file2=keyedConfigFile(MANAGED_BROWSERS_SUBDIR,browserId),record2=readRecord(file2);!record2||isManagedProcess(record2.pid,record2.userDataDir)||(await stopProcess(record2.hostPid,`--browser-id ${record2.browserId}`),removeRecord(file2),removeRecord(keyedConfigFile("browsers",record2.browserId)),record2.persistent||rmSync4(record2.userDataDir,{recursive:!0,force:!0}))}function acquireLaunchLock(browserId){let lockDir=keyedDir(MANAGED_BROWSER_LOCKS_SUBDIR),lockFile=keyedConfigFile(MANAGED_BROWSER_LOCKS_SUBDIR,browserId);mkdirSync3(lockDir,{recursive:!0});let token=`${process.pid}:${randomUUID8()}`,tryAcquire=()=>{try{return writeFileSync3(lockFile,token,{flag:"wx"}),!0}catch(error48){if(error48.code!=="EEXIST")throw error48;return!1}};if(!tryAcquire()){let observedToken="";try{observedToken=readFileSync5(lockFile,"utf-8")}catch{}let ownerPid=Number(observedToken.split(":",1)[0]);if(Number.isInteger(ownerPid)&&!isAlive(ownerPid)){let staleFile=`${lockFile}.${process.pid}.${randomUUID8()}.stale`;try{if(readFileSync5(lockFile,"utf-8")!==observedToken)throw new Error("Launch lock owner changed");if(renameSync4(lockFile,staleFile),readFileSync5(staleFile,"utf-8")===observedToken)rmSync4(staleFile,{force:!0});else try{renameSync4(staleFile,lockFile)}catch{}}catch{}}if(!tryAcquire())throw new Error(`Managed browser launch already in progress: ${browserId}`)}return()=>{try{readFileSync5(lockFile,"utf-8")===token&&rmSync4(lockFile,{force:!0})}catch{}}}async function launchManagedBrowser(input,deps){let name=validateName(input.name),browserId=managedBrowserId(name),cookieCopy=resolveCookieCopyPlan(input.copyCookieDomains),copyCookieDomains=cookieCopy.domains,headless=input.headless!==!1,persistent=input.persistent===!0,executablePath=resolveChromeExecutable(input.executablePath),userAgent=resolveUserAgentMode(input.userAgentMode)==="desktop"?desktopChromeUserAgent(resolveChromeVersion(executablePath)):void 0,userDataDir=profileDirectory(browserId,persistent),logDir=keyedDir(MANAGED_BROWSERS_SUBDIR);mkdirSync3(logDir,{recursive:!0});let logPath=join6(logDir,`${hashKey(browserId)}.log`),logFd=openSync4(logPath,"a"),chromePid=0,hostPid=0,session=null,recordWritten=!1,releaseLock=null;try{if(releaseLock=acquireLaunchLock(browserId),await removeStoppedInstance(browserId),findManagedRecord(browserId))throw new Error(`Managed browser already running: ${browserId}`);let exportedCookies=copyCookieDomains.length>0?await deps.exportCookies(copyCookieDomains):[],cookies=cookieCopy.select(exportedCookies),chromeArgs=buildManagedChromeArgs({userDataDir,headless,userAgent});rmSync4(join6(userDataDir,"DevToolsActivePort"),{force:!0});let chrome=spawn9(executablePath,chromeArgs,{detached:!0,stdio:["ignore","ignore",logFd],windowsHide:headless});if(await new Promise((resolve2,reject)=>{chrome.once("error",reject),chrome.once("spawn",resolve2)}),chromePid=chrome.pid??0,!chromePid)throw new Error("Chrome launched without a process id");chrome.unref();let cdpPort=await waitForActivePort(userDataDir);session=new CdpSession({port:cdpPort,userDataDir});let copiedCookieCount=await cdpImportCookies(session,cookies);input.url&&await(await session.getBrowserClient()).sendCommand("Target.createTarget",{url:input.url,background:headless}),session.close(),session=null;let host=spawn9(process.execPath,[deps.nativeHostScript,"--daemon","--cdp-port",String(cdpPort),"--cdp-user-data-dir",userDataDir,"--browser-id",browserId,"--browser-name",name,...headless?["--browser-headless"]:[]],{detached:!0,stdio:"ignore",windowsHide:!0});if(await new Promise((resolve2,reject)=>{host.once("error",reject),host.once("spawn",resolve2)}),hostPid=host.pid??0,!hostPid)throw new Error("Native host launched without a process id");host.unref();let record2={pid:chromePid,hostPid,browserId,name,headless,persistent,userDataDir,executablePath,cdpPort,createdAt:new Date().toISOString(),...copyCookieDomains.length>0?{copiedCookies:{domains:copyCookieDomains,count:copiedCookieCount}}:{}};return writeRecord(keyedConfigFile(MANAGED_BROWSERS_SUBDIR,browserId),record2),recordWritten=!0,await waitForBrowserRegistration(browserId,hostPid),deps.log(`managed browser launched: ${browserId}, chrome=${chromePid}, host=${hostPid}`),{...browserSummary(record2,!0),created:!0,reused:!1}}catch(error48){throw session?.close(),hostPid&&await stopProcess(hostPid,`--browser-id ${browserId}`),chromePid&&await stopProcess(chromePid,userDataDir),recordWritten&&removeRecord(keyedConfigFile(MANAGED_BROWSERS_SUBDIR,browserId)),persistent||rmSync4(userDataDir,{recursive:!0,force:!0}),error48}finally{releaseLock?.(),closeSync4(logFd)}}async function closeManagedBrowser(selector,options={}){let record2=findManagedRecord(selector);if(!record2)throw new Error(`Managed browser not found: ${selector}`);let recordFile=keyedConfigFile(MANAGED_BROWSERS_SUBDIR,record2.browserId);await stopProcess(record2.pid,record2.userDataDir);let closingOwnHost=record2.hostPid===process.pid;closingOwnHost||await stopProcess(record2.hostPid,`--browser-id ${record2.browserId}`),removeRecord(keyedConfigFile("browsers",record2.browserId));let deleteProfile=options.deleteProfile===!0||!record2.persistent,stoppedRecord=stoppedPersistentBrowserRecord(record2,deleteProfile);return stoppedRecord?writeRecord(recordFile,stoppedRecord):(removeRecord(recordFile),rmSync4(record2.userDataDir,{recursive:!0,force:!0})),closingOwnHost&&setTimeout(()=>process.kill(process.pid,"SIGTERM"),250).unref(),{browserId:record2.browserId,closed:!0,profileDeleted:deleteProfile}}var commonLaunchProperties={name:{type:"string",minLength:1},persistent:{type:"boolean",default:!0},copyCookieDomains:{type:"object",component:"cookie-sync",properties:{presets:{type:"array",items:{type:"string",enum:["mearl-services"]}},domains:{type:"array",items:{type:"string",minLength:1}}}}};function connectedBrowserIds(){return new Set(listRegisteredBrowsers().filter(browser=>browser.status===void 0||browser.status==="connected").map(browser=>browser.browserId))}function commonDetails(browser){return{headless:browser.headless,createdAt:browser.createdAt,...browser.copiedCookies?{copiedCookies:{domains:browser.copiedCookies.domains,count:browser.copiedCookies.count}}:{}}}function localBrowser(browser,connected){let stopped=!browser.running;return{browserId:browser.browserId,name:browser.name,status:stopped?"stopped":connected.has(browser.browserId)?"connected":"running_disconnected",control:stopped?{kind:"none"}:{kind:"host",transport:"cdp",browserId:browser.browserId},ownership:"owned",persistence:browser.persistent?"persistent":"ephemeral",operations:stopped?["start","deleteData"]:["close","deleteData"],references:[{kind:"profile",id:browser.browserId,label:"Profile"}],details:{...commonDetails(browser),cdpPort:browser.cdpPort}}}function localDefinition(deps){return{descriptor:{providerId:"local",name:"Local Chrome",version:NATIVE_HOST_VERSION,protocolVersion:2,builtin:!0},browserType:{name:"本地浏览器",inputSchema:{type:"object",required:["name"],additionalProperties:!0,properties:{...commonLaunchProperties,headless:{type:"boolean",default:!0}}}},listBrowsers:()=>{let connected=connectedBrowserIds();return listManagedBrowsers().map(browser=>localBrowser(browser,connected))},launch:async options=>{let summary=await launchManagedBrowser(options,{nativeHostScript:deps.nativeHostScript,exportCookies:deps.exportCookies,log:deps.log});return localBrowser(summary,connectedBrowserIds())},start:async({browserId})=>{let summary=listManagedBrowsers().find(browser=>browser.browserId===browserId);if(!summary)throw new Error(`Local browser not found: ${browserId}`);let launched=await launchManagedBrowser({name:summary.name,persistent:summary.persistent,headless:summary.headless},{nativeHostScript:deps.nativeHostScript,exportCookies:deps.exportCookies,log:deps.log});return localBrowser(launched,connectedBrowserIds())},close:({browserId,deleteData})=>closeManagedBrowser(browserId,{deleteProfile:deleteData})}}function createBuiltinBrowserProviders(deps){return[createProviderRuntime(localDefinition(deps))]}import net3 from"node:net";var MAX_RESPONSE_BUFFER_SIZE=16*1024*1024;function requestBrowserSocket(socketPath,action,data,version2,timeoutMs=6e4,browserId,host){let id=`browser_manager_${Date.now()}_${Math.random().toString(36).slice(2,10)}`;return new Promise((resolve2,reject)=>{let client2=net3.createConnection(socketPath),lines=new Utf8LineBuffer(MAX_RESPONSE_BUFFER_SIZE),settled=!1,finish=(error48,result)=>{settled||(settled=!0,clearTimeout(timer),client2.removeAllListeners(),client2.destroy(),error48?reject(error48):resolve2(result))},timer=setTimeout(()=>finish(new Error(`Browser request timeout after ${timeoutMs}ms`)),timeoutMs);client2.on("connect",()=>{client2.write(`${JSON.stringify({id,action,data,version:version2,controlSource:"local",...browserId?{browserId}:{},...host?{host}:{}})}
|
|
828
828
|
`)}),client2.on("data",chunk=>{let result=lines.push(chunk);if(result.overflow){finish(new Error("Browser response exceeded the supported size"));return}for(let line of result.lines){let response;try{response=JSON.parse(line)}catch{continue}if(response.id===id){response.success?finish(void 0,response.data):finish(new Error(response.error||"Browser request failed"));return}}}),client2.on("error",error48=>finish(error48)),client2.on("end",()=>finish(new Error("Browser connection closed before responding"))),client2.on("close",()=>finish(new Error("Browser connection closed before responding")))})}function listExternalBrowserProviders(){return listInstalledProviders().map(provider=>({provider:{id:provider.providerId,name:provider.name,builtin:!1,version:provider.version,protocolVersion:provider.protocolVersion},browserType:provider.browserType}))}async function requireLiveProvider(providerId){let warnings=await ensureInstalledProvidersRunning(),live=readLiveProvider(providerId);if(!live){let warning=warnings.find(item=>item.startsWith(`provider ${providerId}:`));throw new Error(warning??`Provider did not start: ${providerId}`)}return{socketPath:live.socketPath}}async function launchProviderBrowser(input){let providerId=input.provider.trim();if(!listInstalledProviders().find(item=>item.providerId===providerId))throw new Error(`Provider is not registered: ${providerId}`);let live=await requireLiveProvider(providerId),result=await(input.host?requestBrowserSocket(live.socketPath,"browser_launch",input.providerOptions,NATIVE_HOST_VERSION,6e4,void 0,input.host):requestBrowserSocket(live.socketPath,"browser_launch",input.providerOptions,NATIVE_HOST_VERSION));return validateProviderBrowser(result),{...result,browserId:providerBrowserKey(providerId,result.browserId)}}function findProviderBrowser(selector){let normalized=selector.toLowerCase(),exact=listRegisteredBrowsers().filter(browser=>browser.transport==="provider").filter(browser=>browser.browserId.toLowerCase()===normalized||browser.providerBrowserId?.toLowerCase()===normalized||browser.browserName.toLowerCase()===normalized);if(exact.length>1)throw new Error(`Provider browser selector is ambiguous: ${selector}`);return exact[0]??null}function requireProviderBrowser(browser){if(browser.transport!=="provider"||!browser.providerBrowserId)throw new Error(`Browser is not managed by an external Provider: ${browser.browserId}`);return browser.providerBrowserId}function closeProviderBrowser(browser,options={}){return requestBrowserSocket(browser.socketPath,"browser_close",{deleteProfile:options.deleteProfile===!0},NATIVE_HOST_VERSION,6e4,requireProviderBrowser(browser))}function detachProviderBrowser(browser){return requestBrowserSocket(browser.socketPath,"browser_release",{},NATIVE_HOST_VERSION,6e4,requireProviderBrowser(browser))}async function accessProviderBrowser(browser){return(await requestBrowserSocket(browser.socketPath,"get_browser_access_url",{},NATIVE_HOST_VERSION,6e4,requireProviderBrowser(browser))).browserAccess}async function startProviderBrowser(browser){let result=await requestBrowserSocket(browser.socketPath,"browser_manager_start",{},NATIVE_HOST_VERSION,12e4,requireProviderBrowser(browser));return validateProviderBrowser(result),{...result,browserId:browser.browserId}}function syncProviderBrowserCookies(browser,scope,host){let browserId=requireProviderBrowser(browser);return host?requestBrowserSocket(browser.socketPath,"browser_manager_sync_cookies",{scope},NATIVE_HOST_VERSION,12e4,browserId,host):requestBrowserSocket(browser.socketPath,"browser_manager_sync_cookies",{scope},NATIVE_HOST_VERSION,12e4,browserId)}async function configureProvider(providerId,options){if(!listInstalledProviders().find(item=>item.providerId===providerId)?.browserType.configuration)throw new Error(`Provider does not support configuration: ${providerId}`);let live=await requireLiveProvider(providerId);return requestBrowserSocket(live.socketPath,"browser_provider_configure",options,NATIVE_HOST_VERSION)}var BrowserProviderCoordinator=class{constructor(runtimes,hostServices){this.runtimes=runtimes;this.hostServices=hostServices}async hostContext(options){if(!this.hostServices)return;let result={};if(options.copyCookieDomains!==void 0){let plan=resolveCookieCopyPlan(options.copyCookieDomains);result.cookies=plan.select(await this.hostServices.exportCookies(plan.domains))}return options.userAgentMode==="desktop"&&(result.userAgent=await this.hostServices.getBrowserUserAgent()),Object.keys(result).length>0?result:void 0}definitions(){return{providers:[...this.runtimes.map(runtime=>{let descriptor=runtime.definition.descriptor;return{provider:providerIdentity(descriptor),browserType:runtime.definition.browserType}}),...listExternalBrowserProviders()]}}get providerRuntimes(){return this.runtimes}async launch(input){let providerId=input.provider?.trim()||"local",runtime=this.runtimes.find(item=>item.definition.descriptor.providerId===providerId),builtinOptions={...input};if(delete builtinOptions.provider,delete builtinOptions.providerOptions,input.providerOptions&&Object.keys(builtinOptions).length>0)throw new Error("Use either providerOptions or flat launch options, not both");if(runtime){let descriptor=runtime.definition.descriptor,options={...input.providerOptions??builtinOptions};return Array.isArray(options.copyCookieDomains)&&(options.copyCookieDomains={domains:options.copyCookieDomains}),options.copyCookieDomains==="mearl-services"&&(options.copyCookieDomains={presets:["mearl-services"]}),providerBrowserInfo({provider:providerIdentity(descriptor),browser:await runtime.launch(options)})}let external=listExternalBrowserProviders().find(provider=>provider.provider.id===providerId);if(!external)throw new Error(`Provider is not registered: ${providerId}`);if(Object.keys(builtinOptions).length>0)throw new Error("External Provider launch options must be supplied in providerOptions");let host=await this.hostContext(input.providerOptions??{});return providerBrowserInfo({provider:external.provider,browser:await launchProviderBrowser({provider:providerId,providerOptions:input.providerOptions??{},...host?{host}:{}})})}async close(selector,deleteProfile=!1){let match=await this.requireOne(selector);return"external"in match?closeProviderBrowser(match.external,{deleteProfile}):match.runtime.close({browserId:match.browser.browserId,deleteData:deleteProfile})}async start(selector){let match=await this.requireOne(selector);if("external"in match){if(!match.external.provider)throw new Error("Provider identity is missing");return providerBrowserInfo({provider:match.external.provider,browser:await startProviderBrowser(match.external)})}let descriptor=match.runtime.definition.descriptor;return providerBrowserInfo({provider:providerIdentity(descriptor),browser:await match.runtime.start({browserId:match.browser.browserId})})}async syncCookies(selector,scope){let match=await this.requireOne(selector);if("external"in match){let host=await this.hostContext({copyCookieDomains:scope});return host?syncProviderBrowserCookies(match.external,scope,host):syncProviderBrowserCookies(match.external,scope)}return match.runtime.syncCookies({browserId:match.browser.browserId,scope})}async access(selector){let match=await this.requireOne(selector);return{browserAccess:"runtime"in match?await match.runtime.getAccess({browserId:match.browser.browserId}):await accessProviderBrowser(match.external)}}async detach(selector){let match=await this.requireOne(selector);return"runtime"in match?match.runtime.detach({browserId:match.browser.browserId}):detachProviderBrowser(match.external)}async configure(providerId,options){let runtime=this.runtimes.find(item=>item.definition.descriptor.providerId===providerId);return runtime?runtime.configure(options):configureProvider(providerId,options)}async findRuntimeBrowsers(selector){let normalized=selector.trim().toLowerCase();return(await Promise.all(this.runtimes.map(async runtime=>(await runtime.listBrowsers()).map(browser=>({runtime,browser}))))).flat().filter(entry=>entry.browser.browserId.toLowerCase()===normalized||entry.browser.name.toLowerCase()===normalized)}async requireOne(selector){let matches=await this.findRuntimeBrowsers(selector),external=findProviderBrowser(selector);if(matches.length+ +!!external>1)throw new Error(`Browser name is ambiguous: ${selector}. Use the full browserId from browser_list.`);if(matches[0])return matches[0];if(external)return{external};throw new Error(`Provider browser not found: ${selector}`)}};process.env.MEARL_NATIVE_HOST_ENTRY??=fileURLToPath3(import.meta.url);var cliArgs=process.argv.slice(2),cliArg=cliArgs[0];if(cliArg==="--init"||cliArg==="--uninstall"||cliArg==="init"||cliArg==="uninstall"){let{runCli:runCli2}=await Promise.resolve().then(()=>(init_install(),install_exports));process.exit(await runCli2(cliArgs))}function printCliHelp(){console.error(`mearl-native-host v${NATIVE_HOST_VERSION}
|
|
829
829
|
|
|
830
830
|
Usage:
|
|
@@ -867,7 +867,7 @@ Examples:
|
|
|
867
867
|
mearl-native-host uninstall --mode skills
|
|
868
868
|
mearl-native-host init --extension-id abcdefghijklmnopqrstuvwxyzabcdef
|
|
869
869
|
mearl-native-host --daemon
|
|
870
|
-
mearl-native-host --version`)}!cliArg&&process.stdin.isTTY&&(printCliHelp(),process.exit(0));var runtimeArgs={browserId:"cdp",browserHeadless:!1,browserName:"CDP",cdpPort:9222,daemon:!1,discoverCdp:!1,help:!1,skipBrowserRegistration:!1,version:!1};if(cliArgs.length>0)try{
|
|
870
|
+
mearl-native-host --version`)}!cliArg&&process.stdin.isTTY&&(printCliHelp(),process.exit(0));var runtimeArgs={browserId:"cdp",browserHeadless:!1,browserName:"CDP",cdpPort:9222,daemon:!1,discoverCdp:!1,help:!1,skipBrowserRegistration:!1,version:!1};if(cliArgs.length>0)try{runtimeArgs=await parseNativeHostRuntimeArgs(cliArgs)}catch(error48){console.error(`Error: ${error48 instanceof Error?error48.message:String(error48)}`),printCliHelp(),process.exit(2)}runtimeArgs.version&&(console.log(NATIVE_HOST_VERSION),process.exit(0));runtimeArgs.help&&(printCliHelp(),process.exit(0));var isDaemonMode=runtimeArgs.daemon,discoverCdp=runtimeArgs.discoverCdp,skipBrowserRegistration=runtimeArgs.skipBrowserRegistration,CDP_ENDPOINT_FILE=runtimeArgs.cdpEndpointFile,CDP_PORT=runtimeArgs.cdpPort,CDP_USER_DATA_DIR=runtimeArgs.cdpUserDataDir,BROWSER_HEADLESS=runtimeArgs.browserHeadless,CDP_BROWSER_ID=runtimeArgs.browserId,CDP_BROWSER_NAME=runtimeArgs.browserName,CDP_ENDPOINT_SOURCE=cliArgs.some(argument=>["--cdp-port","--cdp-user-data-dir","--cdp-endpoint-file"].some(option=>argument===option||argument.startsWith(`${option}=`)))?"command-line":"built-in default";function describeCdpEndpoint(){return CDP_ENDPOINT_FILE?`endpoint-file (source=${CDP_ENDPOINT_SOURCE})`:`127.0.0.1:${CDP_PORT} (source=${CDP_ENDPOINT_SOURCE})`}function oneLineError(value){return value.replace(/[\r\n]+/g," ").trim().slice(0,500)}function socketPathFor(suffix){return process.platform==="win32"?`\\\\.\\pipe\\mearl-agent${suffix}`:path18.join(os10.tmpdir(),`mearl-agent${suffix}.sock`)}var LEGACY_SOCKET_PATH=socketPathFor(""),INSTANCE_SOCKET_PATH=socketPathFor(`-${process.pid}`),LOG_FILE=path18.join(os10.tmpdir(),"mearl-native-host.log"),DEFAULT_TIMEOUT_MS=15e3,INVENTORY_IDLE_EXIT_MS=1e3,DISCOVERY_REQUEST_IDLE_EXIT_MS=5e3,MAX_SOCKET_BUFFER_SIZE2=64*1024*1024,extensionVersion=null,versionWarningEmitted=!1,cdpPermissionNoticeLogged=!1,EXTENSION_INSTALL_URL="https://chromewebstore.google.com/detail/mearl/aoehhjnofngknnjefamjbplchbolghkm";function majorMinor(version2){let parts=version2.split(".");return parts.length>=2?`${parts[0]}.${parts[1]}`:version2}function extractChromeVersion(input){let match=/Chrome\/([\d.]+)/.exec(input);return match?match[1].split(".").slice(0,3).join("."):null}async function fetchCdpBrowserVersion(){if(CDP_ENDPOINT_FILE)try{return(await(await getCdpSession().getBrowserClient()).sendCommand("Browser.getVersion",{},5e3)).product??null}catch{return null}let port=readDevToolsActivePort(CDP_USER_DATA_DIR)?.port??CDP_PORT;return new Promise(resolve2=>{let req=http4.get(`http://localhost:${port}/json/version`,res=>{let data="";res.on("data",chunk=>data+=chunk),res.on("end",()=>{try{let info=JSON.parse(data);resolve2(info.Browser??null)}catch{resolve2(null)}})});req.on("error",()=>resolve2(null)),req.setTimeout(2e3,()=>{req.destroy(),resolve2(null)})})}async function getCurrentBrowserUserAgent(){if(extensionVersion!==null)try{let result=await sendRequestToExtension("get_browser_info",{},3e3,!0);if(result.userAgent?.trim())return result.userAgent}catch{}try{let result=await(await getCdpSession().getBrowserClient()).sendCommand("Browser.getVersion",{},5e3);if(result.userAgent?.trim())return result.userAgent}catch{}throw new Error("Could not determine the control browser user agent for userAgentMode=desktop")}function currentBrowserSupportsSandboxAccess(){return!BROWSER_HEADLESS}function resolveBrowserAccessCapability(){return currentBrowserSupportsSandboxAccess()?resolveSandboxBrowserAccessCapability():null}async function resolveBrowserAccess(){if(!resolveBrowserAccessCapability())throw new Error("The selected browser does not expose a browser access URL");return resolveSandboxBrowserAccess()}async function collectVersions(includeInstallationInfo=!1){let browserAccess=resolveBrowserAccessCapability(),info={nativeHost:NATIVE_HOST_VERSION,extension:extensionVersion,browser:null,...browserAccess?{browserAccess}:{}};if(extensionVersion!==null)try{let browserInfo=await sendRequestToExtension("get_browser_info",{},3e3,!0);browserInfo?.userAgent&&(info.browser=extractChromeVersion(browserInfo.userAgent)),browserInfo?.extensionVersion&&(info.extension=browserInfo.extensionVersion),includeInstallationInfo&&(browserInfo?.extensionId&&(info.extensionId=browserInfo.extensionId),(typeof browserInfo?.setupManagedPath=="string"||browserInfo?.setupManagedPath===null)&&(info.setupManagedPath=browserInfo.setupManagedPath))}catch{}if(!info.browser){let cdpBrowser=await fetchCdpBrowserVersion();cdpBrowser&&(info.browser=extractChromeVersion(cdpBrowser))}return info}function buildVersionWarning(clientVersion){let versions=[clientVersion?{name:"client",version:clientVersion}:null,{name:"native-host",version:NATIVE_HOST_VERSION},extensionVersion?{name:"extension",version:extensionVersion}:null].filter(Boolean);return new Set(versions.map(v=>majorMinor(v.version))).size<=1?null:["⚠️ Mearl version mismatch detected:",versions.map(v=>` - ${v.name}: ${v.version}`).join(`
|
|
871
871
|
`),"","This may cause unexpected behavior. To update:"," npx @mearl/setup update --local",` Browser extension: ${EXTENSION_INSTALL_URL}`].join(`
|
|
872
872
|
`)}var pendingRequests=new Map,nativeMessageBuffer=Buffer.alloc(0),socketServer=null,legacyServer=null,inventoryExitTimer=null,cdpRegistrationTimer=null,cdpBrowserPublished=!1;function cancelInventoryExit(){inventoryExitTimer&&(clearTimeout(inventoryExitTimer),inventoryExitTimer=null)}function scheduleInventoryExit(delayMs=INVENTORY_IDLE_EXIT_MS){cancelInventoryExit(),inventoryExitTimer=setTimeout(()=>cleanupAndExit(0),delayMs),inventoryExitTimer.unref()}var cdpSession=null,cdpAutoReconnectEnabled=!0;function getCdpSession(){return cdpAutoReconnectEnabled=!0,cdpSession||(cdpSession=CDP_ENDPOINT_FILE?new CdpSession({endpointResolver:async()=>{let endpoint=fs18.readFileSync(CDP_ENDPOINT_FILE,"utf8").trim(),url2=new URL(endpoint);if(url2.protocol!=="ws:"&&url2.protocol!=="wss:")throw new Error(`Unsupported CDP WebSocket protocol: ${url2.protocol}`);return url2.toString()}}):new CdpSession({port:CDP_PORT,userDataDir:CDP_USER_DATA_DIR})),cdpSession}function log(...args){let msg=`[${new Date().toISOString()}] [NativeHost] ${args.join(" ")}
|
|
873
873
|
`;try{fs18.appendFileSync(LOG_FILE,msg)}catch{}}function sendToExtension(message){let json2=JSON.stringify(message),length=Buffer.byteLength(json2,"utf-8"),header=Buffer.alloc(4);header.writeUInt32LE(length,0),process.stdout.write(header),process.stdout.write(json2)}var nativeHostUpdateCoordinator=new NativeHostUpdateCoordinator({hostVersion:NATIVE_HOST_VERSION,log,runUpdate:targetVersion=>runNativeHostUpdate(targetVersion),requestRestart:()=>{restartAfterUpdate()}}),agentChatManager=null,agentSkillManager=new AgentSkillManager;function getAgentChatManager(){return agentChatManager||(agentChatManager=new AgentChatManager([new CodexAgentProvider(log,NATIVE_HOST_VERSION,INSTANCE_SOCKET_PATH),new QoderAgentProvider(log,NATIVE_HOST_VERSION)],event=>{sendToExtension({type:"agent_chat_event",data:event})})),agentChatManager}var agentServiceHandlers={agent_chat_pick_directory:async()=>({path:await pickWorkspaceDirectory()}),agent_chat_status:()=>getAgentChatManager().getStatus(),agent_chat_prepare:async data=>(await getAgentChatManager().prepare(data),{ok:!0}),agent_chat_list_sessions:data=>getAgentChatManager().listSessions(data),agent_chat_start:data=>getAgentChatManager().startSession(data),agent_chat_send:data=>getAgentChatManager().sendMessage(data),agent_chat_interrupt:async data=>(await getAgentChatManager().interrupt(data),{ok:!0}),agent_chat_close:async data=>(await getAgentChatManager().closeSession(data),{ok:!0}),agent_chat_events:data=>getAgentChatManager().getEvents(data),agent_chat_refresh:data=>getAgentChatManager().refreshSession(data),agent_chat_open_app:async data=>(await getAgentChatManager().openSession(data),{ok:!0}),agent_chat_respond:data=>(getAgentChatManager().respondToRequest(data),{ok:!0}),agent_skills_installed:async data=>{let[cli,skills]=await Promise.all([agentSkillManager.getStatus(),getAgentChatManager().listSkills(data)]);return{cli,skills}},agent_skills_read:data=>getAgentChatManager().readSkill(data),agent_skills_install:data=>agentSkillManager.install(data),agent_skills_check_updates:data=>agentSkillManager.checkUpdates(data),agent_skills_update:data=>agentSkillManager.update(data),agent_skills_uninstall:data=>agentSkillManager.uninstall(data)};function dispatchAgentServiceAction(action,request){let handler=agentServiceHandlers[action];return Promise.resolve(handler(request))}var browserProviderCoordinator=null;function getBrowserProviderCoordinator(){if(browserProviderCoordinator)return browserProviderCoordinator;let runtimes=createBuiltinBrowserProviders({nativeHostScript:fileURLToPath3(import.meta.url),exportCookies:async domains=>extensionVersion!==null?(await sendRequestToExtension("__export_cookies",{domains},2e4,!0)).cookies??[]:cdpExportCookies(getCdpSession(),domains),log});return browserProviderCoordinator=new BrowserProviderCoordinator(runtimes,{exportCookies:async domains=>extensionVersion!==null?(await sendRequestToExtension("__export_cookies",{domains},2e4,!0)).cookies??[]:cdpExportCookies(getCdpSession(),domains),getBrowserUserAgent:getCurrentBrowserUserAgent}),browserProviderCoordinator}async function launchBrowser(data){return getBrowserProviderCoordinator().launch(data)}async function closeBrowser(data){let selector=String(data?.browser??data?.browserId??data?.name??"").trim();if(!selector)throw new Error("browser is required");return getBrowserProviderCoordinator().close(selector,data?.deleteProfile===!0)}async function getManagedBrowserAccess(data){let selector=String(data?.browser??data?.browserId??"").trim();if(!selector)throw new Error("browser is required");return(await getBrowserProviderCoordinator().access(selector)).browserAccess}function appendWarnings(result,warnings){let merged=[...new Set([...result.warnings??[],...warnings])];return{...result,...merged.length>0?{warnings:merged}:{}}}async function handleExtensionControlMessage(message){let{id,action,data={}}=message;if(isAgentServiceAction(action)){let result=await dispatchAgentServiceAction(action,data);sendToExtension({id,success:!0,data:result});return}if(action==="browser_list"){let providerWarnings=await ensureInstalledProvidersRunning(),inventory=await listBrowserInventory(getBrowserProviderCoordinator().providerRuntimes);sendToExtension({id,success:!0,data:appendWarnings(inventory,providerWarnings)});return}if(action==="browser_provider_list"){sendToExtension({id,success:!0,data:getBrowserProviderCoordinator().definitions()});return}if(action==="browser_launch"){let result=await launchBrowser(data);sendToExtension({id,success:!0,data:result});return}if(action==="browser_close"){let result=await closeBrowser(data);sendToExtension({id,success:!0,data:result});return}if(action==="browser_manager_release"){let selector=String(data?.browser??data?.browserId??"").trim();if(!selector)throw new Error("browser is required");let result=await getBrowserProviderCoordinator().detach(selector);sendToExtension({id,success:!0,data:result});return}if(action==="browser_manager_start"||action==="browser_manager_sync_cookies"){let selector=String(data?.browser??"").trim();if(!selector)throw new Error("browser is required");let coordinator=getBrowserProviderCoordinator(),result=action==="browser_manager_start"?await coordinator.start(selector):await coordinator.syncCookies(selector,data?.scope);sendToExtension({id,success:!0,data:result});return}if(action==="get_browser_access_url"){let browserAccess=await getManagedBrowserAccess(data);sendToExtension({id,success:!0,data:{browserAccess}});return}if(action==="browser_provider_configure"){if(typeof data?.provider!="string"||!data.provider.trim())throw new Error("provider is required");let result=await getBrowserProviderCoordinator().configure(data.provider,data.options);sendToExtension({id,success:!0,data:result});return}if(action==="start_cloud_connector"){let serverUrl=data?.serverUrl;if(!serverUrl||typeof serverUrl!="string"){sendToExtension({id,success:!1,error:"serverUrl is required"});return}let result=await startCloudConnector(serverUrl);sendToExtension({id,success:result.success,data:result,error:result.error});return}if(action==="stop_cloud_connector"){let serverUrl=data?.serverUrl;if(!serverUrl||typeof serverUrl!="string"){sendToExtension({id,success:!1,error:"serverUrl is required"});return}let result=stopCloudConnector(serverUrl);sendToExtension({id,success:result.success,data:result,error:result.error});return}if(action==="list_cloud_connectors"){sendToExtension({id,success:!0,data:listCloudConnectors()});return}if(action==="update_setup_extension"){let result=await updateSetupManagedExtension({currentVersion:data?.currentVersion,setupManagedPath:data?.setupManagedPath});sendToExtension({id,success:!0,data:result});return}sendToExtension({id,success:!1,error:`Unknown extension action: ${action}`})}function handleExtensionMessage(message){if(message&&message.type==="ping"){message.version&&(extensionVersion=message.version,log(`Extension version: ${extensionVersion}, Native Host version: ${NATIVE_HOST_VERSION}`)),setAnalyticsClientId(message.analyticsClientId),registerBrowser({browserId:typeof message.browserId=="string"?message.browserId:"default",socketPath:INSTANCE_SOCKET_PATH,browserName:typeof message.browserName=="string"?message.browserName:"Browser",nativeHostVersion:NATIVE_HOST_VERSION,transport:"extension",extensionVersion:extensionVersion??void 0}),sendToExtension({type:"pong",timestamp:Date.now(),version:NATIVE_HOST_VERSION}),nativeHostUpdateCoordinator.evaluate(message.version,message.checkForUpdates);return}if(message&&message.type==="browser_focus"){touchFocus();return}if(!message||typeof message!="object"||!message.id)return;let pending=pendingRequests.get(message.id);if(!pending){message.action&&handleExtensionControlMessage(message).catch(error48=>{sendToExtension({id:message.id,success:!1,error:error48 instanceof Error?error48.message:String(error48)})});return}clearTimeout(pending.timer),pendingRequests.delete(message.id),message.success?pending.resolve(message.data):pending.reject(new Error(message.error||"Unknown error from extension"))}function processNativeMessages(){for(;nativeMessageBuffer.length>=4;){let length=nativeMessageBuffer.readUInt32LE(0);if(nativeMessageBuffer.length<4+length)return;let jsonBytes=nativeMessageBuffer.subarray(4,4+length);nativeMessageBuffer=nativeMessageBuffer.subarray(4+length);try{let message=JSON.parse(jsonBytes.toString("utf-8"));handleExtensionMessage(message)}catch(error48){log("Failed to parse extension message:",String(error48))}}}function setupNativeMessageInput(){process.stdin.on("readable",()=>{let chunk;for(;(chunk=process.stdin.read())!==null;)nativeMessageBuffer=Buffer.concat([nativeMessageBuffer,chunk]),processNativeMessages()}),process.stdin.on("end",()=>{log("Extension disconnected (stdin end)"),cleanupAndExit(0)}),process.stdin.on("error",error48=>{log("stdin error:",String(error48)),cleanupAndExit(1)})}function sendRequestToExtension(action,data,timeoutMs,trustedInternal=!1,controlSource="local"){let id=`${Date.now()}_${Math.random().toString(36).slice(2,10)}`;return new Promise((resolve2,reject)=>{let timer=setTimeout(()=>{pendingRequests.delete(id),reject(new Error(`Request timeout after ${timeoutMs}ms`))},timeoutMs);pendingRequests.set(id,{resolve:resolve2,reject,timer}),sendToExtension(createExtensionRequestMessage(id,action,data,trustedInternal,controlSource))})}function toTimeoutMs(action,data){if(action==="send_request"||action==="__send_request_with_files")return Number(data&&data.timeout?data.timeout:3e4)+5e3;if(action==="send_mtop_request")return Number(data&&data.timeout?data.timeout:1e4)+5e3;if(action==="page_wait")return Number(data?.time??data?.timeout??1e4)+5e3;if(action==="tab_open")return 4e4;if(action==="run_actions"){let timeoutMs=(Array.isArray(data?.actions)?data.actions:[{}]).reduce((total,step)=>{let stepAction=String(step?.action??"");return!stepAction||stepAction==="run_actions"?total+DEFAULT_TIMEOUT_MS:total+toTimeoutMs(stepAction,step?.data??{})},0);return Math.max(DEFAULT_TIMEOUT_MS,timeoutMs)}if(shouldObservePageAction(action,data)){let observationMs=Math.min(Math.max(Number(data?.observe?.timeoutMs??3e3),500),3e4),navigationGraceMs=Math.min(Math.max(Number(data?.observe?.navigationGraceMs??1e3),0),5e3),navigationTimeoutMs=Math.min(Math.max(Number(data?.observe?.navigationTimeoutMs??15e3),1e3),3e4);return Math.max(DEFAULT_TIMEOUT_MS,observationMs+navigationGraceMs+4e3+navigationTimeoutMs+5e3)}return DEFAULT_TIMEOUT_MS}async function handleSocketRequest(socket,line){let request;try{request=JSON.parse(line)}catch{socket.write(JSON.stringify({id:"",success:!1,error:`Invalid JSON request: ${line}`})+`
|
|
@@ -880,7 +880,7 @@ Examples:
|
|
|
880
880
|
`);return}if(action==="get_browser_access_url"){try{let browserAccess=data?.browser?await getManagedBrowserAccess(data):await resolveBrowserAccess();socket.write(JSON.stringify({id,success:!0,data:{browserAccess}})+`
|
|
881
881
|
`)}catch(error48){socket.write(JSON.stringify({id,success:!1,error:error48 instanceof Error?error48.message:String(error48)})+`
|
|
882
882
|
`)}return}if(isInternalExtensionAction(action)){socket.write(JSON.stringify({id,success:!1,error:"Internal action is not available to clients"})+`
|
|
883
|
-
`);return}if(action==="browser_list"){let providerWarnings=await ensureInstalledProvidersRunning();discoverCdp&&cancelInventoryExit();let
|
|
883
|
+
`);return}if(action==="browser_list"){let providerWarnings=await ensureInstalledProvidersRunning();discoverCdp&&cancelInventoryExit();let shouldDiscover=isDaemonMode&&!skipBrowserRegistration,discoveryProbeError,discovered=shouldDiscover?await ensureDiscoverableCdpBrowser({isPublished:()=>cdpBrowserPublished,isAvailable:async()=>{let probe=await getCdpSession().probeAvailability();return discoveryProbeError=probe.error?oneLineError(probe.error):void 0,log(`CDP discovery probe ${describeCdpEndpoint()} -> ${probe.available?"ok":`fail (${discoveryProbeError||"unknown error"})`}`),probe.available},publish:publishDaemonBrowser,monitor:monitorConnectedDaemonBrowser}):!1,inventory=await listBrowserInventory(getBrowserProviderCoordinator().providerRuntimes),discoveryWarnings=shouldDiscover&&!discovered?[`CDP discovery probe ${describeCdpEndpoint()} failed: ${discoveryProbeError||"unknown error"}`]:[],data2=appendWarnings(inventory,[...providerWarnings,...discoveryWarnings]),response=JSON.stringify({id,success:!0,data:data2})+`
|
|
884
884
|
`;skipBrowserRegistration||discoverCdp&&!discovered?(socket.end(response),scheduleInventoryExit()):socket.write(response);return}if(action==="browser_close"){try{let result=await closeBrowser(data);socket.write(JSON.stringify({id,success:!0,data:result})+`
|
|
885
885
|
`)}catch(error48){socket.write(JSON.stringify({id,success:!1,error:error48 instanceof Error?error48.message:String(error48)})+`
|
|
886
886
|
`)}return}if(action==="browser_release"){let startedAt2=Date.now(),affectedTabIds=new Set,transports=[],failures=[],released=!0,hadActiveControl=!1;try{let releaseErrors=[];if(extensionVersion!==null)try{let result=await sendRequestToExtension(action,data,toTimeoutMs(action,data));released=released&&result?.released!==!1,hadActiveControl=hadActiveControl||result?.hadActiveControl===!0,result?.hadActiveControl&&transports.push("extension");for(let tabId of result?.affectedTabIds??[])affectedTabIds.add(tabId);Array.isArray(result?.failures)&&failures.push(...result.failures)}catch(error48){releaseErrors.push(`extension: ${error48 instanceof Error?error48.message:String(error48)}`)}if(cdpSession){let session=cdpSession;cdpSession=null;try{let result=await releaseCdpControl(session);released=released&&result.released,hadActiveControl=hadActiveControl||result.hadActiveControl,result.hadActiveControl&&transports.push("cdp");for(let tabId of result.affectedTabIds)affectedTabIds.add(tabId)}catch(error48){session.close(),releaseErrors.push(`cdp: ${error48 instanceof Error?error48.message:String(error48)}`)}}if(cdpAutoReconnectEnabled=!1,releaseErrors.length>0)throw new Error(`Failed to fully release browser control (${releaseErrors.join("; ")})`);trackAction(action,{success:released,transport:transports.join("+")||"none",duration_ms:Date.now()-startedAt2,extension_version:extensionVersion??"not_connected"});let response=JSON.stringify({id,success:!0,data:{released,hadActiveControl,transports,affectedTabIds:Array.from(affectedTabIds).sort((a,b)=>a-b),...failures.length>0&&{failures}}})+`
|
|
@@ -890,4 +890,4 @@ Examples:
|
|
|
890
890
|
`)}return}if(!isExtensionBrowserAction(action)&&(typeof action!="string"||!action.startsWith("__"))){socket.write(JSON.stringify({id,success:!1,error:`Unsupported action: ${String(action)}`})+`
|
|
891
891
|
`);return}let useExtension=!(request.transport==="cdp")&&extensionVersion!==null,transport=useExtension?"extension":"cdp",startedAt=Date.now();try{let result;useExtension?action==="send_request"&&hasSendRequestFiles(data)?result=await sendRequestWithTransferredFiles(data,(internalAction,payload,timeoutMs)=>sendRequestToExtension(internalAction,payload,timeoutMs,!0,controlSource)):action==="run_actions"&&hasRunActionsSendRequestFiles(data)?result=await sendRunActionsWithTransferredFiles(data,(internalAction,payload,timeoutMs)=>sendRequestToExtension(internalAction,payload,timeoutMs,!0,controlSource),transformed=>toTimeoutMs("run_actions",transformed)):result=await sendRequestToExtension(action,data,toTimeoutMs(action,data),!1,controlSource):(cdpPermissionNoticeLogged||(cdpPermissionNoticeLogged=!0,log("CDP mode: domain permission checks are not enforced — all actions run without domain authorization")),result=await handleViaCdp(action,data,toTimeoutMs(action,data),controlSource)),trackAction(action,{success:!0,transport,duration_ms:Date.now()-startedAt,extension_version:extensionVersion??"not_connected"});let response={id,success:!0,data:result};if(!versionWarningEmitted){let versionWarning=buildVersionWarning(clientVersion);versionWarning&&(versionWarningEmitted=!0,response.versionWarning=versionWarning)}socket.write(JSON.stringify(response)+`
|
|
892
892
|
`)}catch(error48){let message=error48 instanceof Error?error48.message:String(error48);trackAction(action,{success:!1,transport,duration_ms:Date.now()-startedAt,error_code:classifyAnalyticsError(error48),extension_version:extensionVersion??"not_connected"}),socket.write(JSON.stringify({id,success:!1,error:message})+`
|
|
893
|
-
`)}}async function handleSocketLine(socket,line){await handleSocketRequest(socket,line)}async function handleViaCdp(action,data,_timeoutMs,controlSource){if(action==="set_rule"||action==="get_rules")throw new Error(`${action} requires the Mearl browser extension. Install it from https://chromewebstore.google.com/detail/mearl/aoehhjnofngknnjefamjbplchbolghkm`);if(!getRegisteredActionNames().includes(action))throw new Error(`Action "${action}" is not supported in CDP mode`);if(!await getCdpSession().isAvailable())throw CDP_ENDPOINT_FILE?new Error("The remote CDP endpoint is not available"):new Error(`Chrome DevTools remote debugging is not available on port ${CDP_PORT}. Enable it via chrome://inspect/#remote-debugging (Chrome 145+) or install the Mearl extension.`);return isDaemonMode&&!skipBrowserRegistration&&(publishDaemonBrowser(),shouldReconnectDaemonBrowser()||monitorConnectedDaemonBrowser()),shouldObservePageAction(action,data)?cdpObservedPageAction(getCdpSession(),action,data,controlSource):dispatchCdpAction(getCdpSession(),action,data,controlSource)}function onSocketConnection(socket){let lineBuffer=new Utf8LineBuffer(MAX_SOCKET_BUFFER_SIZE2);socket.on("data",chunk=>{let result=lineBuffer.push(chunk);if(result.overflow){log(`socket request exceeded ${MAX_SOCKET_BUFFER_SIZE2} bytes; closing connection`),socket.destroy();return}for(let line of result.lines)line.trim()&&handleSocketLine(socket,line)}),socket.on("error",error48=>{log("socket error:",String(error48))})}function isPathAlive(socketPath){return new Promise(resolve2=>{if(process.platform!=="win32"&&!fs18.existsSync(socketPath)){resolve2(!1);return}let client2=net4.createConnection(socketPath),done=alive=>{client2.removeAllListeners(),client2.destroy(),resolve2(alive)},timer=setTimeout(()=>done(!1),500);client2.on("connect",()=>{clearTimeout(timer),done(!0)}),client2.on("error",()=>{clearTimeout(timer),done(!1)})})}function listenOn(socketPath){return new Promise((resolve2,reject)=>{if(process.platform!=="win32"&&fs18.existsSync(socketPath))try{fs18.unlinkSync(socketPath)}catch{}let server=net4.createServer(onSocketConnection);server.once("error",reject),server.listen(socketPath,()=>{if(process.platform!=="win32")try{fs18.chmodSync(socketPath,384)}catch(error48){server.close();try{fs18.unlinkSync(socketPath)}catch{}reject(error48);return}server.removeListener("error",reject),server.on("error",error48=>log("socket server error:",String(error48))),log(`listening on ${socketPath}`),resolve2(server)})})}async function tryBindLegacySocket(){if(await isPathAlive(LEGACY_SOCKET_PATH)){log("legacy socket already owned by a live host, skipping");return}try{legacyServer=await listenOn(LEGACY_SOCKET_PATH)}catch(error48){log("legacy socket bind failed (raced):",String(error48)),legacyServer=null}}function releaseLegacySocket(){if(!legacyServer)return;let server=legacyServer;legacyServer=null;try{server.close()}catch{}if(process.platform!=="win32")try{fs18.existsSync(LEGACY_SOCKET_PATH)&&fs18.unlinkSync(LEGACY_SOCKET_PATH)}catch{}}async function startSocketServer(){socketServer=await listenOn(INSTANCE_SOCKET_PATH),skipBrowserRegistration||await tryBindLegacySocket()}function cleanupInstanceSocketFile(){if(process.platform!=="win32")try{fs18.existsSync(INSTANCE_SOCKET_PATH)&&fs18.unlinkSync(INSTANCE_SOCKET_PATH)}catch(error48){log("cleanup socket file failed:",String(error48))}}function cleanupAndExit(code){cancelInventoryExit(),cdpRegistrationTimer&&(clearInterval(cdpRegistrationTimer),cdpRegistrationTimer=null),cdpSession?.close(),agentChatManager?.dispose(),agentChatManager=null,unregisterBrowser(),cdpBrowserPublished=!1,releaseLegacySocket();let finish=()=>{cleanupInstanceSocketFile(),process.exit(code)};if(socketServer){socketServer.close(finish),socketServer=null;return}finish()}function restartAfterUpdate(){setTimeout(()=>process.exit(0),2e3).unref(),cleanupAndExit(0)}function publishDaemonBrowser(){cancelInventoryExit(),!cdpBrowserPublished&&(registerBrowser({browserId:CDP_BROWSER_ID,socketPath:INSTANCE_SOCKET_PATH,browserName:CDP_BROWSER_NAME,nativeHostVersion:NATIVE_HOST_VERSION,transport:"cdp",lastFocusedAt:CDP_BROWSER_ID.startsWith("managed:")?0:void 0}),cdpBrowserPublished=!0)}function unpublishDaemonBrowser(){cdpBrowserPublished&&(unregisterBrowser(),cdpBrowserPublished=!1)}function shouldReconnectDaemonBrowser(){return!!CDP_ENDPOINT_FILE||CDP_BROWSER_ID.startsWith("managed:")}function monitorConnectedDaemonBrowser(){cdpRegistrationTimer||(cdpRegistrationTimer=setInterval(()=>{getCdpSession().hasActiveConnections()||(unpublishDaemonBrowser(),cdpRegistrationTimer&&clearInterval(cdpRegistrationTimer),cdpRegistrationTimer=null)},2e3),cdpRegistrationTimer.unref())}async function monitorReconnectableDaemonBrowser(){let checking=!1,refresh=async()=>{if(!checking&&cdpAutoReconnectEnabled){checking=!0;try{await getCdpSession().isAvailable()?publishDaemonBrowser():unpublishDaemonBrowser()}finally{checking=!1}}};await refresh(),cdpRegistrationTimer=setInterval(()=>{refresh()},2e3),cdpRegistrationTimer.unref()}async function main(){if(initBrowserRegistry({log}),pruneDeadBrowsers(),initCloudConnector({log,isDaemonMode,sendToExtension,version:NATIVE_HOST_VERSION}),isDaemonMode?log(`running in ${skipBrowserRegistration?"browser inventory":discoverCdp?"CDP discovery":"CDP"} daemon mode, pid=${process.pid}, version=${NATIVE_HOST_VERSION}`):setupNativeMessageInput(),await startSocketServer(),shouldExitWithoutLegacySocket(runtimeArgs,!!legacyServer)){cleanupAndExit(0);return}discoverCdp&&scheduleInventoryExit(DISCOVERY_REQUEST_IDLE_EXIT_MS),isDaemonMode&&!skipBrowserRegistration&&shouldReconnectDaemonBrowser()&&await monitorReconnectableDaemonBrowser(),process.on("SIGINT",()=>cleanupAndExit(0)),process.on("SIGTERM",()=>cleanupAndExit(0)),process.on("uncaughtException",error48=>{log("uncaughtException:",String(error48)),cleanupAndExit(1)}),process.on("unhandledRejection",error48=>{log("unhandledRejection:",String(error48)),cleanupAndExit(1)})}main().catch(error48=>{log("main() failed:",String(error48)),process.exit(1)});
|
|
893
|
+
`)}}async function handleSocketLine(socket,line){await handleSocketRequest(socket,line)}async function handleViaCdp(action,data,_timeoutMs,controlSource){if(action==="set_rule"||action==="get_rules")throw new Error(`${action} requires the Mearl browser extension. Install it from https://chromewebstore.google.com/detail/mearl/aoehhjnofngknnjefamjbplchbolghkm`);if(!getRegisteredActionNames().includes(action))throw new Error(`Action "${action}" is not supported in CDP mode`);if(!await getCdpSession().isAvailable())throw CDP_ENDPOINT_FILE?new Error("The remote CDP endpoint is not available"):new Error(`Chrome DevTools remote debugging is not available on port ${CDP_PORT}. Enable it via chrome://inspect/#remote-debugging (Chrome 145+) or install the Mearl extension.`);return isDaemonMode&&!skipBrowserRegistration&&(publishDaemonBrowser(),shouldReconnectDaemonBrowser()||monitorConnectedDaemonBrowser()),shouldObservePageAction(action,data)?cdpObservedPageAction(getCdpSession(),action,data,controlSource):dispatchCdpAction(getCdpSession(),action,data,controlSource)}function onSocketConnection(socket){let lineBuffer=new Utf8LineBuffer(MAX_SOCKET_BUFFER_SIZE2);socket.on("data",chunk=>{let result=lineBuffer.push(chunk);if(result.overflow){log(`socket request exceeded ${MAX_SOCKET_BUFFER_SIZE2} bytes; closing connection`),socket.destroy();return}for(let line of result.lines)line.trim()&&handleSocketLine(socket,line)}),socket.on("error",error48=>{log("socket error:",String(error48))})}function isPathAlive(socketPath){return new Promise(resolve2=>{if(process.platform!=="win32"&&!fs18.existsSync(socketPath)){resolve2(!1);return}let client2=net4.createConnection(socketPath),done=alive=>{client2.removeAllListeners(),client2.destroy(),resolve2(alive)},timer=setTimeout(()=>done(!1),500);client2.on("connect",()=>{clearTimeout(timer),done(!0)}),client2.on("error",()=>{clearTimeout(timer),done(!1)})})}function listenOn(socketPath){return new Promise((resolve2,reject)=>{if(process.platform!=="win32"&&fs18.existsSync(socketPath))try{fs18.unlinkSync(socketPath)}catch{}let server=net4.createServer(onSocketConnection);server.once("error",reject),server.listen(socketPath,()=>{if(process.platform!=="win32")try{fs18.chmodSync(socketPath,384)}catch(error48){server.close();try{fs18.unlinkSync(socketPath)}catch{}reject(error48);return}server.removeListener("error",reject),server.on("error",error48=>log("socket server error:",String(error48))),log(`listening on ${socketPath}`),resolve2(server)})})}async function tryBindLegacySocket(){if(await isPathAlive(LEGACY_SOCKET_PATH)){log("legacy socket already owned by a live host, skipping");return}try{legacyServer=await listenOn(LEGACY_SOCKET_PATH)}catch(error48){log("legacy socket bind failed (raced):",String(error48)),legacyServer=null}}function releaseLegacySocket(){if(!legacyServer)return;let server=legacyServer;legacyServer=null;try{server.close()}catch{}if(process.platform!=="win32")try{fs18.existsSync(LEGACY_SOCKET_PATH)&&fs18.unlinkSync(LEGACY_SOCKET_PATH)}catch{}}async function startSocketServer(){socketServer=await listenOn(INSTANCE_SOCKET_PATH),skipBrowserRegistration||await tryBindLegacySocket()}function cleanupInstanceSocketFile(){if(process.platform!=="win32")try{fs18.existsSync(INSTANCE_SOCKET_PATH)&&fs18.unlinkSync(INSTANCE_SOCKET_PATH)}catch(error48){log("cleanup socket file failed:",String(error48))}}function cleanupAndExit(code){cancelInventoryExit(),cdpRegistrationTimer&&(clearInterval(cdpRegistrationTimer),cdpRegistrationTimer=null),cdpSession?.close(),agentChatManager?.dispose(),agentChatManager=null,unregisterBrowser(),cdpBrowserPublished=!1,releaseLegacySocket();let finish=()=>{cleanupInstanceSocketFile(),process.exit(code)};if(socketServer){socketServer.close(finish),socketServer=null;return}finish()}function restartAfterUpdate(){setTimeout(()=>process.exit(0),2e3).unref(),cleanupAndExit(0)}function publishDaemonBrowser(){cancelInventoryExit(),!cdpBrowserPublished&&(registerBrowser({browserId:CDP_BROWSER_ID,socketPath:INSTANCE_SOCKET_PATH,browserName:CDP_BROWSER_NAME,nativeHostVersion:NATIVE_HOST_VERSION,transport:"cdp",lastFocusedAt:CDP_BROWSER_ID.startsWith("managed:")?0:void 0}),cdpBrowserPublished=!0)}function unpublishDaemonBrowser(){cdpBrowserPublished&&(unregisterBrowser(),cdpBrowserPublished=!1)}function shouldReconnectDaemonBrowser(){return!!CDP_ENDPOINT_FILE||CDP_BROWSER_ID.startsWith("managed:")}function monitorConnectedDaemonBrowser(){cdpRegistrationTimer||(cdpRegistrationTimer=setInterval(()=>{getCdpSession().hasActiveConnections()||(unpublishDaemonBrowser(),cdpRegistrationTimer&&clearInterval(cdpRegistrationTimer),cdpRegistrationTimer=null)},2e3),cdpRegistrationTimer.unref())}async function monitorReconnectableDaemonBrowser(){let checking=!1,refresh=async()=>{if(!checking&&cdpAutoReconnectEnabled){checking=!0;try{await getCdpSession().isAvailable()?publishDaemonBrowser():unpublishDaemonBrowser()}finally{checking=!1}}};await refresh(),cdpRegistrationTimer=setInterval(()=>{refresh()},2e3),cdpRegistrationTimer.unref()}async function main(){if(initBrowserRegistry({log}),pruneDeadBrowsers(),initCloudConnector({log,isDaemonMode,sendToExtension,version:NATIVE_HOST_VERSION}),isDaemonMode?log(`running in ${skipBrowserRegistration?"browser inventory":discoverCdp?"CDP discovery":"CDP"} daemon mode, pid=${process.pid}, version=${NATIVE_HOST_VERSION}, cdp=${describeCdpEndpoint()}`):setupNativeMessageInput(),await startSocketServer(),shouldExitWithoutLegacySocket(runtimeArgs,!!legacyServer)){cleanupAndExit(0);return}discoverCdp&&scheduleInventoryExit(DISCOVERY_REQUEST_IDLE_EXIT_MS),isDaemonMode&&!skipBrowserRegistration&&shouldReconnectDaemonBrowser()&&await monitorReconnectableDaemonBrowser(),process.on("SIGINT",()=>cleanupAndExit(0)),process.on("SIGTERM",()=>cleanupAndExit(0)),process.on("uncaughtException",error48=>{log("uncaughtException:",String(error48)),cleanupAndExit(1)}),process.on("unhandledRejection",error48=>{log("unhandledRejection:",String(error48)),cleanupAndExit(1)})}main().catch(error48=>{log("main() failed:",String(error48)),process.exit(1)});
|