agent-device 0.21.11 → 0.21.12

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.
Files changed (38) hide show
  1. package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.11.apk → agent-device-android-ime-helper-0.21.12.apk} +0 -0
  2. package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.12.apk.sha256 +1 -0
  3. package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.11.manifest.json → agent-device-android-ime-helper-0.21.12.manifest.json} +4 -4
  4. package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.11.apk → agent-device-android-snapshot-helper-0.21.12.apk} +0 -0
  5. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.12.apk.sha256 +1 -0
  6. package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.11.manifest.json → agent-device-android-snapshot-helper-0.21.12.manifest.json} +6 -6
  7. package/apple/fold-helper/Fold.m +97 -0
  8. package/apple/macos-helper/Package.swift +1 -8
  9. package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/main.swift +0 -2
  10. package/dist/src/back-mode.js +1 -1
  11. package/dist/src/cli-help.js +4 -2
  12. package/dist/src/client-types.d.ts +2 -4
  13. package/dist/src/device-input-state.d.ts +1 -1
  14. package/dist/src/device-rotation.js +1 -1
  15. package/dist/src/helper.js +2 -2
  16. package/dist/src/interactor.js +3 -3
  17. package/dist/src/internal/bin.js +1 -1
  18. package/dist/src/internal/daemon.js +2 -2
  19. package/dist/src/macos-facade.js +1 -1
  20. package/dist/src/provider-webdriver.js +1 -1
  21. package/dist/src/registry.js +35 -35
  22. package/dist/src/runtime4.js +4 -4
  23. package/dist/src/script.js +1 -1
  24. package/dist/src/sdk-batch.js +1 -1
  25. package/dist/src/sdk-selectors.d.ts +12 -1
  26. package/dist/src/simulator-facade.js +1 -1
  27. package/dist/src/simulator.js +1 -1
  28. package/package.json +2 -1
  29. package/server.json +2 -2
  30. package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.11.apk.sha256 +0 -1
  31. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.11.apk.sha256 +0 -1
  32. package/apple/macos-helper/Sources/AgentDeviceMacOSDeviceHub/DeviceHubPose.swift +0 -47
  33. package/apple/macos-helper/Sources/AgentDeviceMacOSDeviceHub/DeviceHubWindowInventory.swift +0 -65
  34. package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/DeviceHubPose.swift +0 -225
  35. package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/DeviceHubSidebar.swift +0 -57
  36. package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/DeviceHubWindowDiscovery.swift +0 -108
  37. package/apple/macos-helper/Tests/AgentDeviceMacOSDeviceHubTests/DeviceHubPoseTests.swift +0 -30
  38. package/apple/macos-helper/Tests/AgentDeviceMacOSDeviceHubTests/DeviceHubWindowInventoryTests.swift +0 -65
@@ -1 +1 @@
1
- import{D as e,j as t}from"./sdk-contracts.js";import{a as n,b as r}from"./sdk-device.js";import{Qt as i}from"./sdk-batch.js";import{d as a}from"./scroll-gesture.js";import{c as o}from"./sdk-remote-config.js";import"./device.js";import{a as s,o as c}from"./device-rotation.js";import{c as l}from"./exec.js";import"./command.js";import{r as u}from"./version.js";import{n as d,r as f,t as p}from"./capabilities.js";import{t as ee}from"./webdriver-source.js";import{t as m}from"./providers.js";import h from"node:path";import te from"node:fs";import g from"node:fs/promises";import{setTimeout as ne}from"node:timers/promises";function re(e,t){let n=e?.bundleId??t?.appIdentifierHint,r=e?.packageName??t?.packageNameHint;return{bundleId:n,packageName:r,appName:e?.appName,launchTarget:ae(e?.launchTarget,n,r)}}function ie(e){return e===`ios`?`xctest`:`android`}function ae(...e){return e.find(e=>e!==void 0)}function oe(e){let t=async(t,n,r,i,a)=>{let o=e.findSessionForDevice(t);if(!o)return;let s=await ce(e,o,t,n,r,i,a);return await o.client.installApp(s?.appReference??r,a),re(s,i)};return Object.freeze({fact:t=>se(e.findSessionForDevice(t)),installApp:t,installInstallablePath:async(e,n,r,i)=>await t(e,``,n,r,i),deployApp:async(e,n,r)=>_(await t(e,n.app,n.appPath,{relaunch:n.replaceExisting,appIdentifierHint:n.app,packageNameHint:n.app},r),n.app),deployMaterializedApp:async(e,n,r)=>_(await t(e,``,n.artifact.installablePath,{appIdentifierHint:n.artifact.bundleId,packageNameHint:n.artifact.packageName},r))})}function se(e){return e?p(e.capabilities,`install`)?Object.freeze({available:!0}):Object.freeze({available:!1,reason:`owner-capability-missing`,hint:f(e.capabilities,`install`)}):Object.freeze({available:!1,reason:`owner-capability-missing`,hint:`The WebDriver provider session is no longer active for this device.`})}async function ce(t,n,i,a,o,s,c){if(!p(n.capabilities,`install`))throw new e(`UNSUPPORTED_OPERATION`,f(n.capabilities,`install`),{provider:t.provider,deviceId:i.id,platform:r(i)});let l=n.prepared.uploadApp??t.uploadApp;if(l)return await l({provider:t.provider,lease:n.lease,device:i,app:a,appPath:o,options:s,signal:c})}function _(t,n){if(!t)throw new e(`UNSUPPORTED_OPERATION`,`The WebDriver provider session no longer supports app deployment.`);return{...t.bundleId?{bundleId:t.bundleId}:{},...t.packageName?{packageName:t.packageName}:{},...t.appName?{appName:t.appName}:{},...t.launchTarget??n?{launchTarget:t.launchTarget??n}:{}}}function v(e){return{provider:e.provider,providerSessionId:e.providerSessionId,status:e.artifacts.length>0?`ready`:`pending`,cloudArtifacts:e.artifacts,...e.artifacts.length>0?{}:{message:e.pendingMessage}}}function le(e){return{provider:e.provider,providerSessionId:e.providerSessionId,status:`unavailable`,cloudArtifacts:[],message:e.error instanceof Error?e.error.message:String(e.error)}}function y(e){return{"x-agent-device-client":`agent-device-cli`,"x-agent-device-version":e}}async function ue(n,r){try{await r()}catch(r){n instanceof e&&(n.details={...n.details,cleanupError:t(r)})}}function de(e,t){return typeof e==`function`?e(t):e}function b(e){return`Basic ${Buffer.from(`${e.username}:${e.accessKey}`).toString(`base64`)}`}function fe(e){let t=0;for(;t<e.length&&e.charCodeAt(t)===47;)t+=1;return t===0?e:e.slice(t)}function pe(e){let t=e.length-1;for(;t>=0&&e.charCodeAt(t)===47;)--t;return t===e.length-1?e:e.slice(0,t+1)}function me(e){if(e.pathname.endsWith(`/`))return e;let t=new URL(e);return t.pathname=`${t.pathname}/`,t}const x=`webdriver_request_timeout`;function S(t){return t instanceof e&&t.details?.reason===x}var he=class{endpoint;headers;requestPolicy;constructor(e){this.endpoint=me(new URL(e.endpoint)),this.headers={...y(e.clientVersion),...e.auth?{Authorization:b(e.auth)}:{},...e.headers},this.requestPolicy={timeoutMs:e.requestPolicy?.timeoutMs??3e4,retryAttempts:e.requestPolicy?.retryAttempts??1,retryDelayMs:e.requestPolicy?.retryDelayMs??250}}async requestValue(e,t,n,r){return await this.requestValueWithRetries(e,t,n,{retryAttempts:r?.retryAttempts??this.requestPolicy.retryAttempts,timeoutMs:r?.timeoutMs??this.requestPolicy.timeoutMs,signal:r?.signal})}async requestValueWithRetries(e,t,n,r){let i;for(let a=0;a<=r.retryAttempts;a+=1)try{return await this.requestValueOnce(e,t,n,r.timeoutMs,r.signal)}catch(e){if(i=e,!ge(e,a,r.retryAttempts,r.signal))throw e;await ne(this.requestPolicy.retryDelayMs,void 0,{signal:r.signal})}throw i}async requestValueOnce(e,t,n,r,i){let{ok:a,status:o,text:s}=await this.fetchWebDriver(e,t,n,r,i),c=s?ve(s):{};if(!a)throw ye(o,c);return _e(c)}async fetchWebDriver(e,t,n,r,i){let a=AbortSignal.timeout(r),o=i?AbortSignal.any([i,a]):a;try{let r=await fetch(new URL(fe(t),this.endpoint),{method:e,headers:{Accept:`application/json`,...n===void 0?{}:{"Content-Type":`application/json`},...this.headers},body:n===void 0?void 0:JSON.stringify(n),signal:o});return{ok:r.ok,status:r.status,text:await r.text()}}catch(n){throw a.aborted&&!i?.aborted?be(e,t,r,n):n}}};function ge(e,t,n,r){return!r?.aborted&&xe(e)&&t<n}function _e(e){if(!e||typeof e!=`object`)return e;let t=e;return`value`in t?t.value:e}function ve(t){try{return JSON.parse(t)}catch(n){throw new e(`COMMAND_FAILED`,`WebDriver response was not valid JSON.`,{text:t},n)}}function ye(t,n){let r=n&&typeof n==`object`&&`value`in n?n.value:n,i=r&&typeof r==`object`&&typeof r.message==`string`?r.message:`WebDriver request failed with HTTP ${t}.`;return new e(`COMMAND_FAILED`,i,{status:t,response:n})}function be(t,n,r,i){return new e(`COMMAND_FAILED`,`WebDriver ${t} ${n} timed out after ${r}ms.`,{reason:x,method:t,path:n,timeoutMs:r},i instanceof Error?i:void 0)}function xe(t){if(S(t))return!0;if(t instanceof e){let e=t.details?.status;return typeof e==`number`&&e>=500}return t instanceof TypeError}var Se=class{transport;sessionCreateTimeoutMs;sessionId;constructor(e){this.transport=new he(e),this.sessionCreateTimeoutMs=e.requestPolicy?.sessionCreateTimeoutMs??18e4}async createSession(e,t){let n=we(await this.requestValue(`POST`,`/session`,{capabilities:Ce(e)},{retryAttempts:0,timeoutMs:Oe(this.sessionCreateTimeoutMs,t?.deadline)}));return this.sessionId=n.sessionId,n}async deleteSession(){let e=this.requireSessionId();await this.requestValue(`DELETE`,`/session/${e}`),this.sessionId=void 0}async installApp(e,t){await this.sessionRequest(`POST`,`/appium/device/install_app`,{appPath:e},{signal:t})}async activateApp(e){try{await this.sessionRequest(`POST`,`/appium/device/activate_app`,{appId:e})}catch{await this.executeScript(`mobile: activateApp`,[{appId:e,bundleId:e}])}}async terminateApp(e){try{await this.sessionRequest(`POST`,`/appium/device/terminate_app`,{appId:e})}catch{await this.executeScript(`mobile: terminateApp`,[{appId:e,bundleId:e}])}}async performActions(e){await this.sessionRequest(`POST`,`/actions`,{actions:e})}async releaseActions(){await this.sessionRequest(`DELETE`,`/actions`,void 0,{retryAttempts:0})}async sendKeys(e){await this.sessionRequest(`POST`,`/keys`,{value:Array.from(e)})}async hideKeyboard(){await this.sessionRequest(`POST`,`/appium/device/hide_keyboard`,void 0,{retryAttempts:0})}async isKeyboardShown(e){let t;try{t=await this.sessionRequest(`GET`,`/appium/device/is_keyboard_shown`,void 0,{retryAttempts:0,...e===void 0?{}:{timeoutMs:e}})}catch(e){if(O(e))return`unsupported`;throw e}return typeof t==`boolean`?t:`unsupported`}async activeElement(e){let t=e===void 0?void 0:Date.now()+e,n;try{n=De(await this.sessionRequest(`GET`,`/element/active`,void 0,T(t)))}catch(e){if(O(e))return`unsupported`;if(D(e))return`none`;throw e}if(n===void 0)return`unsupported`;try{let e=await this.sessionRequest(`GET`,`/element/${encodeURIComponent(n)}/rect`,void 0,T(t));return{id:n,rect:C(e)}}catch(e){if(O(e))return`unsupported`;if(D(e))return`none`;throw e}}async back(){await this.sessionRequest(`POST`,`/back`)}async setRotation(e){await this.sessionRequest(`POST`,`/rotation`,{x:0,y:0,z:e})}async setOrientation(e){await this.sessionRequest(`POST`,`/orientation`,{orientation:e})}async source(t){let n=await this.sessionRequest(`GET`,`/source`,void 0,t);if(typeof n!=`string`)throw new e(`COMMAND_FAILED`,`WebDriver source response was not a string`,{valueType:typeof n});return n}async screenshot(t){let n=await this.sessionRequest(`GET`,`/screenshot`);if(typeof n!=`string`)throw new e(`COMMAND_FAILED`,`WebDriver screenshot response was not base64 text`,{valueType:typeof n});await g.writeFile(t,Buffer.from(n,`base64`))}async windowRect(){return C(await this.sessionRequest(`GET`,`/window/rect`))}async executeScript(e,t=[]){return await this.sessionRequest(`POST`,`/execute/sync`,{script:e,args:t})}async sessionRequest(e,t,n,r){let i=this.requireSessionId();return await this.requestValue(e,`/session/${i}${t}`,n,r)}requireSessionId(){if(!this.sessionId)throw new e(`SESSION_NOT_FOUND`,`WebDriver session has not been created yet.`);return this.sessionId}async requestValue(e,t,n,r){return await this.transport.requestValue(e,t,n,r)}};function C(t){if(!t||typeof t!=`object`)throw new e(`COMMAND_FAILED`,`WebDriver window rect response was empty.`);let n=t,r={x:w(n,`x`),y:w(n,`y`),width:w(n,`width`),height:w(n,`height`)};if(r.x===void 0||r.y===void 0||r.width===void 0||r.height===void 0)throw new e(`COMMAND_FAILED`,`WebDriver window rect response was invalid.`,{response:n});return r}function w(e,t){let n=e[t];return typeof n==`number`&&Number.isFinite(n)?n:void 0}function Ce(e){return`alwaysMatch`in e||`firstMatch`in e?e:{alwaysMatch:e}}function we(t){if(!t||typeof t!=`object`)throw new e(`COMMAND_FAILED`,`WebDriver create-session response was empty.`);let n=t,r=typeof n.sessionId==`string`?n.sessionId:typeof n.session_id==`string`?n.session_id:void 0;if(!r)throw new e(`COMMAND_FAILED`,`WebDriver create-session response missed sessionId.`,{response:n});return{sessionId:r,capabilities:n.capabilities&&typeof n.capabilities==`object`?n.capabilities:{}}}const Te=new Set([405,501]),Ee=new Set([`unknown command`,`unknown method`]);function De(e){if(!e||typeof e!=`object`)return;let t=e,n=t[`element-6066-11e4-a52e-4f735466cecf`]??t.ELEMENT;return typeof n==`string`&&n.length>0?n:void 0}function T(e){return e===void 0?{retryAttempts:0}:{retryAttempts:0,timeoutMs:E(e)}}function Oe(e,t){return t===void 0?e:Math.min(e,E(t))}function E(e){return Math.max(0,e-Date.now())}function D(t){return t instanceof e&&k(t).toLowerCase()===`no such element`}function O(t){if(!(t instanceof e))return!1;let n=t.details?.status;return typeof n==`number`&&Te.has(n)?!0:Ee.has(k(t).toLowerCase())}function k(e){let t=e.details?.response,n=t&&typeof t==`object`?t.value:void 0,r=n&&typeof n==`object`?n.error:void 0;return typeof r==`string`?r:``}function A(e,t){return{type:`pointer`,id:e,parameters:{pointerType:`touch`},actions:t}}async function ke(e){return j(ee(e,`android`).nodes)}function Ae(e){return j(ee(e).nodes)}function j(e){let t=e.flatMap(e=>je(e)&&Me(e.rect)?[e.rect]:[]).sort((e,t)=>t.width*t.height-e.width*e.height)[0];return t?{x:t.x,y:t.y,width:t.width,height:t.height}:void 0}function je(e){let t=e.type?.toLowerCase()??``;return e.visibleToUser!==!1&&(t.includes(`scrollview`)||t.includes(`listview`)||t.includes(`recyclerview`))}function Me(e){return!!e&&e.width>=50&&e.height>=50}async function Ne(t,n,r){let i=[];for(let e of n===`android`?[`rotation`,`orientation`]:[`orientation`,`rotation`])try{await Re(t,e,r);return}catch(t){if(!Ie(t))throw t;i.push({transport:e,error:t instanceof Error?t.message:String(t)})}throw new e(`COMMAND_FAILED`,`Could not set device orientation to ${r} on the hosted WebDriver session.`,{hint:`The provider driver rejected both orientation endpoints. Set the orientation as a session capability instead, for example connect --provider-device-orientation portrait.`,rotation:r,attempts:i})}const Pe=new Set([`unknown command`,`unknown method`]),Fe=new Set([404,405]);function Ie(t){if(!(t instanceof e)||t.code===`SESSION_NOT_FOUND`)return!1;let n=Le(t.details?.response);if(n)return Pe.has(n);let r=t.details?.status;return typeof r==`number`&&Fe.has(r)}function Le(e){if(!e||typeof e!=`object`)return``;let t=e.value;if(!t||typeof t!=`object`)return``;let n=t.error;return typeof n==`string`?n:``}async function Re(e,t,n){if(t===`rotation`){await e.setRotation(c(n));return}await e.setOrientation(s(n))}const M=1500;function ze(e){return new Promise(t=>setTimeout(t,e))}function N(t,n,r){return new e(`COMMAND_FAILED`,`fill tapped (${t}, ${n}) but ${r}`,{reason:`text_entry_focus_not_observed`,x:t,y:n,hint:`The tap most likely missed the field. Re-check the target with snapshot -i and fill the element it reports, rather than retrying the same coordinates.`})}function Be(t,n){return new e(`COMMAND_FAILED`,`fill tapped (${t}, ${n}) but this driver reports neither the focused element nor keyboard state, so the text was not sent`,{reason:`text_entry_focus_unobservable`,x:t,y:n,hint:`This provider cannot confirm a field took focus. Use press <target> followed by type <text> to enter it anyway, accepting that nothing witnesses which field receives the keys.`})}function Ve(e,t,n){return t>=e.x&&t<=e.x+e.width&&n>=e.y&&n<=e.y+e.height}function He(e){return new Ue(e.client,e.backend,e.capabilities,e.targetId)}var Ue=class{client;backend;capabilities;targetId;constructor(e,t,n,r){this.client=e,this.backend=t,this.capabilities=n,this.targetId=r}async open(e,t){if(t?.url){await this.client.executeScript(`mobile: deepLink`,[{url:t.url,package:e}]);return}let n=t?.appBundleId??e;n&&await this.client.activateApp(n)}async openDevice(){await this.client.executeScript(`mobile: activateApp`,[{}])}async close(e){e&&await this.client.terminateApp(e)}async tap(e,t){return this.requireSupport(`tap`),await this.pointerGesture(`tap`,[{type:`pointerMove`,duration:0,x:e,y:t},{type:`pointerDown`,button:0},{type:`pointerUp`,button:0}]),{backend:`webdriver`,x:e,y:t}}async doubleTap(e,t){return this.requireSupport(`doubleTap`),await this.pointerGesture(`doubleTap`,[{type:`pointerMove`,duration:0,x:e,y:t},{type:`pointerDown`,button:0},{type:`pointerUp`,button:0},{type:`pause`,duration:80},{type:`pointerDown`,button:0},{type:`pointerUp`,button:0}]),{backend:`webdriver`,x:e,y:t}}async swipe(e,t,n,r,i=400){return this.requireSupport(`swipe`),await this.pointerGesture(`swipe`,[{type:`pointerMove`,duration:0,x:e,y:t},{type:`pointerDown`,button:0},{type:`pointerMove`,duration:i,x:n,y:r},{type:`pointerUp`,button:0}]),{backend:`webdriver`,x1:e,y1:t,x2:n,y2:r,durationMs:i}}async longPress(e,t,n=600){return this.requireSupport(`longPress`),await this.pointerGesture(`longPress`,[{type:`pointerMove`,duration:0,x:e,y:t},{type:`pointerDown`,button:0},{type:`pause`,duration:n},{type:`pointerUp`,button:0}]),{backend:`webdriver`,x:e,y:t,durationMs:n}}async focus(e,t){return await this.tap(e,t)}async type(e){this.requireSupport(`type`),await this.client.sendKeys(e)}async fill(t,n,r,i){if(this.requireSupport(`fill`),r.length===0)throw new e(`UNSUPPORTED_OPERATION`,`fill with empty text (clear field) is not supported on the webdriver backend`,{hint:`Use a visible clear/reset control in the app, or fill the field with the intended replacement text directly.`});let a=await this.readTextEntryState();await this.tap(t,n);let o=await this.awaitTextEntryReadiness(a,t,n);return await this.type(r),{backend:`webdriver`,x:t,y:n,text:r,textEntryReadiness:o}}async scroll(e,t){this.requireSupport(`scroll`);let n=t?.durationMs??350;await this.client.hideKeyboard().catch(()=>void 0);let r=await this.scrollGestureFrame(),i=a({direction:e,amount:t?.amount,pixels:t?.pixels,referenceWidth:r.width,referenceHeight:r.height}),o={...i,x1:i.x1+r.x,y1:i.y1+r.y,x2:i.x2+r.x,y2:i.y2+r.y};return await this.swipe(o.x1,o.y1,o.x2,o.y2,n),{backend:`webdriver`,...o,distance:i.pixels,durationMs:n}}async gestureViewport(){return await this.scrollGestureFrame()}async performGesture(e){return this.requireSupport(Ge(e)),await this.client.performActions(e.pointers.map(e=>A(`gesture-pointer-${e.pointerId}`,We(e.samples)))),await this.client.releaseActions().catch(()=>void 0),{backend:`webdriver-w3c-actions`}}async screenshot(e,t){this.requireSupport(`screenshot`),await this.client.screenshot(e)}async snapshot(e){return this.requireSupport(`snapshot`),await this.captureSource(e?.signal)}async captureSource(e){let t=await this.readSource(e);if(this.backend===`xctest`){let{acquireWebDriverIosSnapshot:e}=await import(`./webdriver-ios-snapshot.js`);return e(t,this.targetId)}let{parseWebDriverSourceFacts:n}=await import(`./webdriver-source.js`).then(e=>e.n);return{backend:`android`,producer:`appium-source`,nodes:n(t,`android`).nodes}}async readSource(e){try{return await this.client.source(e===void 0?{}:{signal:e})}catch(e){throw S(e)?Ke(e):e}}async back(e){this.requireSupport(`back`),await this.client.back()}async home(){this.requireSupport(`home`),await this.client.executeScript(`mobile: pressButton`,[{name:`home`}])}async setOrientation(e){this.requireSupport(`orientation`),await Ne(this.client,this.backend,e)}async appSwitcher(){this.requireSupport(`appSwitcher`),await this.client.executeScript(`mobile: pressButton`,[{name:`appSwitch`}])}async tvRemote(e,t){this.unsupported(`tvRemote`)}async readClipboard(){this.requireSupport(`clipboard.read`);let e=await this.client.executeScript(`mobile: getClipboard`,[{}]);return typeof e==`string`?e:``}async writeClipboard(e){this.requireSupport(`clipboard.write`),await this.client.executeScript(`mobile: setClipboard`,[{content:e}])}async setSetting(e,t,n,r){this.unsupported(`settings`)}async readAlert(){this.unsupported(`alert`)}async awaitAlert(){this.unsupported(`alert`)}async acceptAlert(){this.unsupported(`alert`)}async dismissAlert(){this.unsupported(`alert`)}async awaitTextEntryReadiness(e,t,n){let r=e.keyboard,i=Date.now()+2e3,a=e.focusedElementId,o=await this.pollWithinBudget(i,async e=>{let r=await this.client.activeElement(e);return r===`unsupported`?`abandon`:r===`none`?`retry`:r.id!==a||Ve(r.rect,t,n)?`satisfied`:`retry`});if(o===`satisfied`)return`focused-element`;if(o===`expired`)throw N(t,n,`nothing there took text-entry focus, so the text was not sent`);if(r===`unsupported`)throw Be(t,n);if(r)throw N(t,n,`the keyboard was already up and this driver cannot report which field holds focus, so the text was not sent`);if(await this.pollWithinBudget(i,async e=>await this.client.isKeyboardShown(e)===!0?`satisfied`:`retry`)===`satisfied`)return`keyboard-shown`;throw N(t,n,`no keyboard appeared, so the text was not sent`)}async readTextEntryState(){let[e,t]=await Promise.all([this.client.isKeyboardShown(M),this.client.activeElement(M)]);return{keyboard:e,focusedElementId:t===`none`||t===`unsupported`?void 0:t.id}}async pollWithinBudget(e,t){let n=!1,r;for(;;){let i=e-Date.now();if(i<=0)break;try{let e=await t(Math.min(M,i));if(n=!0,e!==`retry`)return e}catch(e){r=e}let a=e-Date.now();if(a<=0)break;await ze(Math.min(100,a))}if(!n&&r!==void 0)throw r;return`expired`}async pointerGesture(e,t){await this.client.performActions([A(e,t)]),await this.client.releaseActions().catch(()=>void 0)}async scrollGestureFrame(){return await this.client.source().then(e=>this.backend===`xctest`?Ae(e):ke(e)).catch(()=>void 0)||await this.client.windowRect()}requireSupport(e){p(this.capabilities,e)||this.unsupported(e)}unsupported(t){throw new e(`UNSUPPORTED_OPERATION`,f(this.capabilities,t),{provider:this.capabilities.provider,platform:this.capabilities.platform,operation:t})}};function We(t){let n=t[0];if(!n)throw new e(`INVALID_ARGS`,`WebDriver gesture pointer requires samples`);let r=[{type:`pointerMove`,duration:0,x:n.point.x,y:n.point.y},{type:`pointerDown`,button:0}];for(let e=1;e<t.length;e+=1){let n=t[e-1],i=t[e];r.push({type:`pointerMove`,duration:i.offsetMs-n.offsetMs,x:i.point.x,y:i.point.y})}return r.push({type:`pointerUp`,button:0}),r}function Ge(e){if(e.topology===`single`)return`swipe`;switch(e.intent){case`pan`:case`transform`:return`transformGesture`;case`pinch`:return`pinch`;case`rotate`:return`rotateGesture`}}function Ke(t){return new e(`COMMAND_FAILED`,`The cloud driver did not finish reading the screen in its budget.`,{...t.details,hint:`A screen that never goes idle (looping video, live ticker, continuous animation) gives the driver no moment to read the UI tree. This read has the transport's own budget and does not grow with --timeout; take a screenshot, or drive the screen from refs an earlier snapshot already captured.`},t)}var qe=class{sessionsByLeaseId=new Map;ownedDeviceIds=new Set;releasedProviderSessionIdsByLeaseId=new Map;options;constructor(e){this.options=e}ownsDevice(e){return this.ownedDeviceIds.has(e.id)}findSessionForDevice(e){return[...this.sessionsByLeaseId.values()].find(t=>t.device.id===e.id)}findSessionForLease(e){return this.sessionsByLeaseId.get(e)}getInteractor(e){return this.findSessionForDevice(e)?.interactor}heartbeat(e){if(e.leaseProvider===this.options.provider&&this.sessionsByLeaseId.has(e.leaseId))return{provider:this.options.provider}}async allocate(e,t){if(e.leaseProvider!==this.options.provider)return;if(this.sessionsByLeaseId.has(e.leaseId))return this.heartbeat(e);let n=await this.prepareSession(e,t),r=new Se({clientVersion:this.options.clientVersion,endpoint:n.endpoint,auth:n.auth,headers:n.headers,requestPolicy:this.options.requestPolicy}),i=await this.createSessionWithPreparedCleanup(r,n,e,t),a=this.deviceForLease(e,n),o=n.providerSessionId??i.sessionId,s=d({provider:this.options.provider,platform:n.platform,overrides:this.options.capabilityOverrides});return this.sessionsByLeaseId.set(e.leaseId,Object.freeze({lease:e,device:a,client:r,prepared:n,capabilities:s,webDriverSessionId:i.sessionId,providerSessionId:o,interactor:He({client:r,backend:ie(n.platform),capabilities:s,targetId:a.id})})),this.ownedDeviceIds.add(a.id),{provider:this.options.provider,deviceId:a.id,sessionId:i.sessionId,providerSessionId:o,capabilities:s,...n.providerData}}async release(e){if(e.leaseProvider!==this.options.provider)return;let t=this.sessionsByLeaseId.get(e.leaseId);if(!t)return;this.sessionsByLeaseId.delete(e.leaseId),this.releasedProviderSessionIdsByLeaseId.set(e.leaseId,t.providerSessionId);let n=await this.closeSession(t),r=await this.safeListArtifacts(t);return{provider:this.options.provider,providerSessionId:t.providerSessionId,...n.cleanup,...n.warnings.length>0?{warnings:n.warnings}:{},...r?{cloudArtifacts:r}:{}}}async listCloudArtifacts(e){if(e.provider!==this.options.provider)return;let t=this.sessionsByLeaseId.get(e.leaseId??``);return t?await this.listActiveCloudArtifacts(t,e.providerSessionId):await this.listReleasedCloudArtifacts(e)}async listActiveCloudArtifacts(e,t){if(!(t&&t!==e.providerSessionId))return await this.safeListArtifacts(e)}async listReleasedCloudArtifacts(e){let t=this.releasedProviderSessionIdsByLeaseId.get(e.leaseId??``);if(!(!t||!this.options.listArtifacts)&&!(e.providerSessionId&&e.providerSessionId!==t))return await this.options.listArtifacts({provider:this.options.provider,providerSessionId:t})}async shutdown(){await Promise.allSettled([...this.sessionsByLeaseId.values()].map(async e=>await this.closeSession(e))),this.sessionsByLeaseId.clear(),this.ownedDeviceIds.clear()}async createSessionWithPreparedCleanup(e,t,n,r){try{return await e.createSession(t.webdriverCapabilities,{deadline:r?.deadline})}catch(e){let r=S(e)?Je(e,this.options.provider,n,t):e;throw await ue(r,()=>t.cleanup?.()),r}}async prepareSession(e,t){let n=this.baseSessionForLease(e);return this.options.prepareSession?await this.options.prepareSession({lease:e,req:t,base:n}):n}baseSessionForLease(e){let t=typeof this.options.webdriverCapabilities==`function`?this.options.webdriverCapabilities(e):this.options.webdriverCapabilities??{};return{provider:this.options.provider,endpoint:this.options.endpoint,platform:this.options.platform,deviceName:this.options.deviceName,auth:this.options.auth,headers:this.options.headers,webdriverCapabilities:P(this.options.platform,this.options.deviceName,t)}}deviceForLease(e,t){return{...n(t.platform),...t.platform===`ios`?{appleOs:`ios`}:{},id:t.deviceId??this.options.deviceId?.(e)??`${this.options.provider}:${t.platform}:${e.leaseId}`,name:t.deviceName,kind:`device`,target:`mobile`,booted:!0}}async closeSession(e){let n=[],r;try{await e.client.deleteSession()}catch(e){n.push({code:`WEBDRIVER_SESSION_DELETE_FAILED`,message:t(e)})}try{r=await e.prepared.cleanup?.()}catch(e){n.push({code:`PROVIDER_CLEANUP_FAILED`,message:t(e)})}return{cleanup:r,warnings:n}}async safeListArtifacts(e){let t=e.prepared.listArtifacts??this.options.listArtifacts;if(t)try{return await t({provider:this.options.provider,lease:e.lease,device:e.device,webDriverSessionId:e.webDriverSessionId,providerSessionId:e.providerSessionId})}catch(t){return le({provider:this.options.provider,providerSessionId:e.providerSessionId,error:t})}}};function P(e,t,n={}){return{platformName:e===`ios`?`iOS`:`Android`,"appium:deviceName":t,...n}}function Je(t,n,r,i){let a=t.details?.timeoutMs;return new e(`COMMAND_FAILED`,`${n} did not create the WebDriver session within ${String(a)}ms.`,{reason:`provider_session_create_timeout`,provider:n,leaseId:r.leaseId,runId:r.runId,timeoutMs:a,...i.providerSessionId?{providerSessionId:i.providerSessionId}:{},hint:`${n} may still finish creating the session after agent-device stopped waiting, and that session would keep billing until the provider reaps it. Before retrying, check ${n} for a running session created for lease ${r.leaseId} (run ${r.runId}) and stop it.`},t)}function F(e){return new Ye(e)}var Ye=class{provider;owner;leaseLifecycle;cloudArtifacts;deviceInventoryProvider;capabilities;platformRuntimeModule;sessions;deployment;constructor(e){this.provider=e.provider,this.owner=i(e.provider,e.platform),this.capabilities=d({provider:e.provider,platform:e.platform,overrides:e.capabilityOverrides}),this.sessions=new qe(e),this.deployment=oe({provider:e.provider,uploadApp:e.uploadApp,findSessionForDevice:e=>this.sessions.findSessionForDevice(e)}),this.platformRuntimeModule=Object.freeze({owner:this.owner,loadRuntime:async e=>await this.loadRuntime(e)}),this.leaseLifecycle={allocate:async(e,t)=>await this.sessions.allocate(e,t),heartbeat:async e=>this.sessions.heartbeat(e),release:async e=>await this.sessions.release(e)},this.cloudArtifacts={listCloudArtifacts:async e=>await this.sessions.listCloudArtifacts(e)},this.deviceInventoryProvider=async e=>{if(e.leaseProvider!==this.provider)return null;if(!e.leaseId)return[];let t=this.sessions.findSessionForLease(e.leaseId);return t?[t.device]:[]}}async loadRuntime(e){let{createWebDriverPlatformRuntimeOwner:t}=await import(`./platform-runtime2.js`);return t({host:e,owner:this.owner,ownsDevice:e=>this.ownsDevice(e),isSessionActive:e=>this.sessions.findSessionForDevice(e)!==void 0,deployment:this.deployment,capabilities:this.capabilities,snapshotAvailable:this.capabilities.operations.snapshot.support!==`unsupported`,screenshotAvailable:this.capabilities.operations.screenshot.support!==`unsupported`,getInteractor:e=>this.getInteractor(e)})}ownsDevice(e){return this.sessions.ownsDevice(e)}getInteractor(e){return this.sessions.getInteractor(e)}async installApp(e,t,n,r){return await this.deployment.installApp(e,t,n,r)}async installInstallablePath(e,t,n){return await this.deployment.installInstallablePath(e,t,n)}async shutdown(){await this.sessions.shutdown()}};async function I(e,t,n){return t?v({provider:e,providerSessionId:t,artifacts:(await Promise.all([n.listArtifacts(t,`FILE`),n.listArtifacts(t,`LOG`)])).flat().flatMap(n=>Ze(e,t,n)),pendingMessage:`AWS Device Farm artifacts are not ready yet.`}):void 0}function Xe(e){if(!e||typeof e!=`object`)return[];let t=e.artifacts;return Array.isArray(t)?t:[]}function Ze(e,t,n){let r=n.url;return typeof r!=`string`||r.length===0?[]:[{provider:e,providerSessionId:t,kind:Qe(n.type),name:n.name??n.type??`AWS Device Farm artifact`,url:r,providerArtifactId:n.arn,extension:n.extension,availability:`ready`,metadata:{awsType:n.type,...n.metadata?{awsMetadata:n.metadata}:{}}}]}function Qe(e){switch(e){case`VIDEO`:return`video`;case`APPIUM_SERVER_OUTPUT`:return`appium-log`;case`DEVICE_LOG`:return`device-log`;case`MESSAGE_LOG`:case`UNKNOWN`:return`automation-log`;default:return`raw`}}m.awsDeviceFarm;const $e={install:{support:`unsupported`,note:`Pass appArn when creating the remote access session; local artifact upload/install is not implemented.`},portReverse:{support:`unsupported`,note:`AWS Device Farm remote access does not expose agent-device port reverse.`},artifacts:{support:`supported`,note:`AWS Device Farm remote access exposes provider-hosted video, Appium logs, and device logs after session completion.`}};function L(e){let t=R(e);return{createRemoteAccessSession:async e=>z(await t(`create-remote-access-session`,[`--project-arn`,e.projectArn,`--device-arn`,e.deviceArn,`--name`,e.name,...e.appArn?[`--app-arn`,e.appArn]:[],...e.interactionMode?[`--interaction-mode`,e.interactionMode]:[],...e.configuration?[`--configuration`,JSON.stringify(e.configuration)]:[]])),getRemoteAccessSession:async e=>z(await t(`get-remote-access-session`,[`--arn`,e])),stopRemoteAccessSession:async e=>z(await t(`stop-remote-access-session`,[`--arn`,e])),listArtifacts:async(e,n)=>Xe(await t(`list-artifacts`,[`--arn`,e,`--type`,n]))}}function et(t){return async({lease:n,req:r,base:i})=>{let a=await t.client.createRemoteAccessSession({projectArn:t.projectArn,deviceArn:t.deviceArn,appArn:t.appArn,name:de(t.sessionName,n)??`agent-device-${n.leaseId}`,interactionMode:t.interactionMode,configuration:t.configuration}),o,s;try{if(o=await rt(a.arn,t,r),s=tt(o),!s)throw new e(`COMMAND_FAILED`,`AWS Device Farm did not expose a WebDriver endpoint.`,{sessionArn:o.arn,status:o.status})}catch(e){throw await ue(e,()=>t.client.stopRemoteAccessSession(a.arn)),e}let c=o.device?.name??t.deviceName,l=typeof t.webdriverCapabilities==`function`?t.webdriverCapabilities(n):t.webdriverCapabilities??{},u=t.platform===`android`?{"appium:autoLaunch":!1}:{};return{...i,endpoint:s,platform:t.platform,deviceName:c,webdriverCapabilities:P(t.platform,c,{...u,...l}),cleanup:async()=>(await t.client.stopRemoteAccessSession(o.arn),{awsDeviceFarmSessionArn:o.arn}),providerSessionId:o.arn,providerData:{awsDeviceFarmSessionArn:o.arn}}}}function tt(e){let t=e.endpoints&&typeof e.endpoints==`object`?Object.values(e.endpoints):[],n=[e.remoteDriverEndpoint,e.endpoint,...t,e.remoteDebugUrl,e.remoteRecordAppUrl].filter(e=>typeof e==`string`&&e.length>0).find(e=>!/^wss?:\/\//i.test(e));return n?nt(n):void 0}function nt(e){return/^https?:\/\//i.test(e)?e:`http://${e}`}async function rt(t,n,r){let i=n.pollIntervalMs??5e3,a=Date.now(),o=r?.deadline??a+(n.startupTimeoutMs??12e4),s=r?.signal,c=await n.client.getRemoteAccessSession(t);for(;Date.now()<o;){if(s?.throwIfAborted(),c.status===`RUNNING`)return c;at(c),await ne(i,void 0,{signal:s}).catch(()=>s?.throwIfAborted()),c=await n.client.getRemoteAccessSession(t)}throw new e(`COMMAND_FAILED`,`Timed out waiting for AWS Device Farm remote access.`,{sessionArn:t,status:c.status,result:c.result,timeoutMs:o-a})}const it=new Set([`ERRORED`,`STOPPED`,`COMPLETED`]);function at(t){if(!(!t.status||!it.has(t.status)))throw new e(`COMMAND_FAILED`,`AWS Device Farm remote access session did not start.`,{sessionArn:t.arn,status:t.status,result:t.result})}async function ot(t,n,r){let i=await t(n,r);try{return JSON.parse(i.stdout)}catch(t){throw new e(`COMMAND_FAILED`,`AWS Device Farm returned invalid JSON.`,void 0,t)}}function R(e){let t=e.region?[`--region`,e.region]:[],n=e.awsCommand??`aws`;return async(r,i)=>await ot(e.runHostCommand,n,[`devicefarm`,r,...t,...i,`--output`,`json`])}function z(t){if(!t||typeof t!=`object`)throw new e(`COMMAND_FAILED`,`AWS Device Farm response was not an object.`,{response:t});let n=t.remoteAccessSession;if(!n||typeof n!=`object`)throw new e(`COMMAND_FAILED`,`AWS Device Farm response missed remoteAccessSession.`,{response:t});return n}const B=[{field:`providerDeviceOrientation`,capability:`deviceOrientation`,flag:`--provider-device-orientation`,type:`enum`,enumValues:o},{field:`providerGeoLocation`,capability:`geoLocation`,flag:`--provider-geo-location`,type:`string`},{field:`providerTimezone`,capability:`timezone`,flag:`--provider-timezone`,type:`string`},{field:`providerAppiumVersion`,capability:`appiumVersion`,flag:`--provider-appium-version`,type:`string`},{field:`providerLanguage`,capability:`language`,flag:`--provider-language`,type:`string`},{field:`providerLocale`,capability:`locale`,flag:`--provider-locale`,type:`string`},{field:`providerNetworkProfile`,capability:`networkProfile`,flag:`--provider-network-profile`,type:`string`},{field:`providerCustomNetwork`,capability:`customNetwork`,flag:`--provider-custom-network`,type:`string`},{field:`providerNoResignApp`,capability:`resignApp`,flag:`--provider-no-resign-app`,type:`negated-boolean`,platform:`ios`}];function st(e,t){pt(e);let n={};for(let r of B){let i=e[r.field];i!==void 0&&i!==!1&&i!==``&&(ft(r,t),n[r.capability]=r.type!==`negated-boolean`&&i)}return n}function ct(e){return B.filter(t=>{let n=e?.[t.field];return n!==void 0&&n!==!1&&n!==``}).map(e=>e.flag)}function V(t,n){let r=ct(t);if(r.length===0)return;let i=r.length!==1;throw new e(`INVALID_ARGS`,`${r.join(`, `)} ${i?`are`:`is`} only supported by BrowserStack, not ${n}.`,{hint:`Drop ${i?`those flags`:`the flag`} or use the browserstack provider.`,provider:n,flags:r})}function lt(e){let t={};for(let n of B){let r=e?.[n.field];if(n.type===`negated-boolean`){r===!0&&(t.providerNoResignApp=!0);continue}typeof r==`string`&&r.length!==0&&ut(t,n,r)}return t}function ut(e,t,n){if(t.field===`providerDeviceOrientation`){e.providerDeviceOrientation=dt(t,n);return}t.field!==`providerNoResignApp`&&(e[t.field]=n)}function dt(t,n){let r=o.find(e=>e===n);if(r)return r;throw new e(`INVALID_ARGS`,`Invalid ${t.flag} value: ${n}.`,{hint:`Use ${o.join(`|`)}.`,flag:t.flag,capability:t.capability})}function ft(t,n){if(!(!t.platform||t.platform===n))throw new e(`INVALID_ARGS`,`${t.flag} applies to ${t.platform} sessions only, but the session platform is ${n}.`,{hint:`Drop ${t.flag} or connect with --platform ${t.platform}.`,flag:t.flag,capability:t.capability,platform:n})}function pt(t){if(!(!t.providerNetworkProfile||!t.providerCustomNetwork))throw new e(`INVALID_ARGS`,`BrowserStack accepts either a named network profile or a custom network shape, not both.`,{hint:`Pass only one of --provider-network-profile or --provider-custom-network.`,networkProfile:t.providerNetworkProfile,customNetwork:t.providerCustomNetwork})}m.browserStack;const mt={install:{support:`partial`,note:`Local app artifacts are uploaded to BrowserStack App Automate, then installed with Appium.`},portReverse:{support:`unsupported`,note:`Use BrowserStack Local for network tunneling; agent-device port reverse is not available.`},artifacts:{support:`supported`,note:`BrowserStack session details expose provider-hosted video, Appium logs, device logs, and dashboard links.`}};async function H(e,t,n){return t?v({provider:e,providerSessionId:t,artifacts:yt(e,t,await vt(t,n)),pendingMessage:`BrowserStack artifacts are not ready yet.`}):void 0}async function U(t,n,r){r?.throwIfAborted();let i=await g.readFile(t),a=new FormData;a.set(`file`,new Blob([i]),h.basename(t));let o=await fetch(n.endpoint??`https://api-cloud.browserstack.com/app-automate/upload`,{method:`POST`,headers:{...y(n.clientVersion),Authorization:b(n)},body:a,signal:r}),s=await o.json(),c=bt(s);if(!o.ok||!c)throw new e(`COMMAND_FAILED`,`BrowserStack app upload failed.`,{status:o.status,response:s});return c}function ht(e){return async({appPath:t,options:n,signal:r})=>({appReference:await U(t,e,r),bundleId:n?.appIdentifierHint,packageName:n?.packageNameHint,launchTarget:n?.appIdentifierHint??n?.packageNameHint})}function gt(e){let{"bstack:options":t,...n}=e.configured??{};return{"appium:deviceName":e.deviceName,"appium:platformVersion":e.osVersion,...e.app?{"appium:app":e.app}:{},...n,"bstack:options":{...e.projectName?{projectName:e.projectName}:{},buildName:e.buildName,sessionName:e.sessionName,...e.deviceFeatures??{},..._t(t)}}}function _t(e){return e&&typeof e==`object`&&!Array.isArray(e)?e:{}}async function vt(t,n){let r=new URL(`${pe(String(n.endpoint??`https://api-cloud.browserstack.com/app-automate/sessions`))}/${t}.json`),i=await fetch(r,{headers:{...y(n.clientVersion),Authorization:b(n)}}),a=await i.json();if(!i.ok||!a||typeof a!=`object`)throw new e(`COMMAND_FAILED`,`BrowserStack session details lookup failed.`,{status:i.status,response:a});let o=a.automation_session??a;return o&&typeof o==`object`?o:{}}function yt(e,t,n){return[W(e,t,n,`video_url`,`video`,`Session video`),W(e,t,n,`appium_logs_url`,`appium-log`,`Appium logs`),W(e,t,n,`device_logs_url`,`device-log`,`Device logs`),W(e,t,n,`browser_url`,`provider-session`,`BrowserStack dashboard`),W(e,t,n,`public_url`,`provider-session`,`Public session link`)].filter(e=>e!==void 0)}function W(e,t,n,r,i,a){let o=n[r];if(typeof o==`string`&&o.length!==0)return{provider:e,providerSessionId:t,kind:i,name:a,url:o,availability:`ready`}}function bt(e){if(!e||typeof e!=`object`)return;let t=e.app_url;return typeof t==`string`?t:void 0}function G(e){return/^arn:[^:]+:devicefarm:([^:]+):/.exec(e)?.[1]}async function xt(t,n){let r=R({runHostCommand:n,region:t.region}),[i,a,o]=await Promise.all([r(`get-project`,[`--arn`,t.projectArn]),r(`get-device`,[`--arn`,t.deviceArn]),t.appArn?r(`get-upload`,[`--arn`,t.appArn]):void 0]),s=K(i,`project`),c=K(a,`device`),l=Ct(c.platform);if(l!==t.platform)throw new e(`INVALID_ARGS`,`AWS Device Farm device "${q(c.name)??t.deviceArn}" is ${l}, not ${t.platform}.`);let u=t.appArn?St(K(o,`upload`),t):{status:`missing`,message:`No app upload is attached; AWS Device Farm does not support install after allocation. Reconnect with --aws-app-arn <arn>.`};return{provider:`aws-device-farm`,service:`AWS Device Farm`,verificationMessage:t.appArn?`Credentials, project, device, and app upload verified.`:`Credentials, project, and device verified.`,project:{name:q(s.name),reference:t.projectArn},device:{status:`verified`,name:q(c.name)??t.deviceArn,reference:t.deviceArn,platform:l,osVersion:q(c.os),availability:q(c.availability)},app:u}}function St(t,n){let r=q(t.status);if(r!==`SUCCEEDED`)throw new e(`COMMAND_FAILED`,`AWS Device Farm app upload is not ready (${r??`unknown status`}).`,{status:r,hint:`Wait for the upload to succeed or reconnect with a different --aws-app-arn.`});let i=n.platform===`android`?`ANDROID_APP`:`IOS_APP`,a=q(t.type);if(a!==i)throw new e(`INVALID_ARGS`,`AWS Device Farm app upload type is ${a??`unknown`}, expected ${i}.`);return{status:`verified`,name:q(t.name),reference:n.appArn}}function K(t,n){if(!t||typeof t!=`object`)throw new e(`COMMAND_FAILED`,`AWS Device Farm ${n} response was not an object.`);let r=t[n];if(!r||typeof r!=`object`||Array.isArray(r))throw new e(`COMMAND_FAILED`,`AWS Device Farm response missed ${n}.`);return r}function Ct(t){if(t===`ANDROID`)return`android`;if(t===`IOS`)return`ios`;throw new e(`UNSUPPORTED_PLATFORM`,`AWS Device Farm device platform is ${String(t)}.`)}function q(e){return typeof e==`string`&&e.length>0?e:void 0}async function wt(t,n){let r={username:t.username,accessKey:t.accessKey},i=Dt(await J(t.devicesEndpoint??`https://api-cloud.browserstack.com/app-automate/devices.json`,r,n)).find(e=>e.device===t.deviceName&&e.os.toLowerCase()===t.platform&&Et(e.osVersion,t.osVersion));if(!i)throw new e(`INVALID_ARGS`,`BrowserStack device "${t.deviceName}" with ${t.platform} ${t.osVersion} is not available.`,{hint:`Choose an exact device and OS version from the BrowserStack App Automate device list.`});let a=await Tt(t,r,n);return{provider:`browserstack`,service:`BrowserStack`,verificationMessage:a.status===`verified`?`Credentials, device, and uploaded app verified.`:`Credentials and device access verified; app availability is checked when the session is created.`,device:{status:`verified`,name:i.device,platform:t.platform,osVersion:i.osVersion},app:a}}async function Tt(e,t,n){let{app:r}=e;if(r.startsWith(`bs://`)){let i=Ot(await J(e.appsEndpoint??`https://api-cloud.browserstack.com/app-automate/recent_apps?limit=100`,t,n)).find(e=>e.reference===r);return i?{status:`verified`,...i}:{status:`configured`,reference:r,message:`App reference was not found in the 100 most recent uploads; BrowserStack validates it when creating the session.`}}return/^https?:\/\//i.test(r)?{status:`configured`,reference:r,message:`Public app URL configured; BrowserStack validates it when creating the session.`}:{status:`configured`,name:h.basename(r),reference:r,message:`Local app artifact is ready and will be uploaded when creating the session.`}}async function J(t,n,r){try{let i=await fetch(t,{headers:{...y(r),Authorization:b(n)},signal:AbortSignal.timeout(15e3)});if(!i.ok){let t=i.status===401||i.status===403;throw new e(t?`UNAUTHORIZED`:`COMMAND_FAILED`,`BrowserStack rejected connection verification.`,{status:i.status,hint:t?`Check BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY.`:`Retry connect or check the BrowserStack service status.`})}return await i.json()}catch(t){throw t instanceof e?t:new e(`COMMAND_FAILED`,`BrowserStack connection verification failed.`,{hint:`Check network access to api-cloud.browserstack.com and retry connect.`},t)}}function Et(e,t){let n=e=>e.replace(/(?:\.0)+$/,``);return n(e)===n(t)}function Dt(t){if(!Array.isArray(t))throw new e(`COMMAND_FAILED`,`BrowserStack device verification response was not a list.`);return t.flatMap(e=>{let t=Y(e),n=t?.os_version;return t&&typeof t.device==`string`&&typeof t.os==`string`&&(typeof n==`string`||typeof n==`number`)?[{device:t.device,os:t.os,osVersion:String(n)}]:[]})}function Ot(t){let n=Y(t);if(n&&Object.keys(n).length===0)return[];if(!Array.isArray(t))throw new e(`COMMAND_FAILED`,`BrowserStack app verification response was not a list.`);return t.flatMap(e=>{let t=Y(e);return!t||typeof t.app_url!=`string`?[]:[{reference:t.app_url,...typeof t.app_name==`string`?{name:t.app_name}:{},...typeof t.app_version==`string`?{version:t.app_version}:{}}]})}function Y(e){return e&&typeof e==`object`&&!Array.isArray(e)?e:void 0}async function kt(e,t){return e.provider===`browserstack`?await wt(e,t.clientVersion):await xt(e,t.runHostCommand)}function At(e){return[{provider:m.browserStack,createRuntime:t=>F({clientVersion:e.clientVersion,provider:m.browserStack,platform:`android`,deviceName:`BrowserStack device`,endpoint:t.BROWSERSTACK_WEBDRIVER_ENDPOINT??`https://hub-cloud.browserstack.com/wd/hub/`,capabilityOverrides:mt,listArtifacts:async({provider:n,providerSessionId:r})=>{let i=$(t,`BROWSERSTACK_USERNAME`,`BrowserStack artifact lookup`),a=$(t,`BROWSERSTACK_ACCESS_KEY`,`BrowserStack artifact lookup`);return await H(n,r,{clientVersion:e.clientVersion,username:i,accessKey:a,endpoint:t.BROWSERSTACK_SESSION_DETAILS_ENDPOINT})},prepareSession:async({req:n,lease:r,base:i})=>{let a=X(n,`BrowserStack`),o=$(t,`BROWSERSTACK_USERNAME`,`BrowserStack`),s=$(t,`BROWSERSTACK_ACCESS_KEY`,`BrowserStack`),c=Nt(a,`BrowserStack`),l=Z(a,`device`,`BrowserStack requires --device <name>.`),u=Z(a,`providerOsVersion`,`BrowserStack requires --provider-os-version <version>.`),d=await jt({clientVersion:e.clientVersion,app:Z(a,`providerApp`,`BrowserStack requires --provider-app <bs://app-id-or-local-path>.`),cwd:a.cwd,username:o,accessKey:s,uploadEndpoint:t.BROWSERSTACK_APP_UPLOAD_ENDPOINT,signal:a.signal});return{...i,platform:c,deviceName:l,auth:{username:o,accessKey:s},uploadApp:ht({clientVersion:e.clientVersion,username:o,accessKey:s,endpoint:t.BROWSERSTACK_APP_UPLOAD_ENDPOINT??`https://api-cloud.browserstack.com/app-automate/upload`}),webdriverCapabilities:gt({deviceName:l,osVersion:u,app:d,projectName:Q(a,`providerProject`),buildName:Q(a,`providerBuild`)??r.runId,sessionName:Q(a,`providerSessionName`)??r.leaseId,deviceFeatures:st(lt(a.flags),c),configured:P(c,l)})}}}),listArtifactsFromEnv:async(t,n)=>{let r=$(n,`BROWSERSTACK_USERNAME`,`BrowserStack artifact lookup`),i=$(n,`BROWSERSTACK_ACCESS_KEY`,`BrowserStack artifact lookup`);return await H(m.browserStack,t,{clientVersion:e.clientVersion,username:r,accessKey:i,endpoint:n.BROWSERSTACK_SESSION_DETAILS_ENDPOINT})}},{provider:m.awsDeviceFarm,createRuntime:t=>F({clientVersion:e.clientVersion,provider:m.awsDeviceFarm,endpoint:`http://127.0.0.1/`,platform:`android`,deviceName:`AWS Device Farm device`,capabilityOverrides:$e,listArtifacts:async({provider:n,providerSessionId:r})=>await I(n,r,L({runHostCommand:e.runHostCommand,region:t.AWS_REGION??t.AWS_DEFAULT_REGION??G(r??``)})),prepareSession:async({req:n,lease:r,base:i})=>{let a=X(n,`AWS Device Farm`);V(a.flags,m.awsDeviceFarm);let o=Nt(a,`AWS Device Farm`);return await et({client:L({runHostCommand:e.runHostCommand,region:Q(a,`awsRegion`)??t.AWS_REGION??t.AWS_DEFAULT_REGION}),projectArn:Pt(a,t,`awsProjectArn`,`AGENT_DEVICE_AWS_DEVICE_FARM_PROJECT_ARN`,`AWS_DEVICE_FARM_PROJECT_ARN`),deviceArn:Pt(a,t,`awsDeviceArn`,`AGENT_DEVICE_AWS_DEVICE_FARM_DEVICE_ARN`,`AWS_DEVICE_FARM_DEVICE_ARN`),appArn:Q(a,`awsAppArn`)??t.AGENT_DEVICE_AWS_DEVICE_FARM_APP_ARN??t.AWS_DEVICE_FARM_APP_ARN,platform:o,deviceName:Q(a,`device`)??`AWS Device Farm device`,sessionName:Q(a,`providerSessionName`)??r.leaseId,interactionMode:Ft(a)})({lease:r,req:n,base:i})}}),listArtifactsFromEnv:async(t,n)=>{let r=L({runHostCommand:e.runHostCommand,region:n.AWS_REGION??n.AWS_DEFAULT_REGION??G(t)});return await I(m.awsDeviceFarm,t,r)}}]}async function jt(t){if(Mt(t.app))return t.app;let n=h.resolve(t.cwd??process.cwd(),t.app);if(!te.existsSync(n))throw new e(`INVALID_ARGS`,`BrowserStack --provider-app must be a bs:// app id, URL, or existing local app path.`,{providerApp:t.app});return await U(n,{clientVersion:t.clientVersion,username:t.username,accessKey:t.accessKey,endpoint:t.uploadEndpoint},t.signal)}function Mt(e){return e.startsWith(`bs://`)||/^https?:\/\//.test(e)}function X(t,n){if(t)return t;throw new e(`INVALID_ARGS`,`${n} lease allocation requires provider profile flags on the request.`)}function Nt(t,n){let r=t.flags?.platform;if(r===`android`||r===`ios`)return r;throw new e(`INVALID_ARGS`,`${n} requires --platform ios|android.`)}function Z(t,n,r){let i=Q(t,n);if(i)return i;throw new e(`INVALID_ARGS`,r)}function Q(e,t){let n=e.flags?.[t];return typeof n==`string`&&n.length>0?n:void 0}function $(t,n,r){let i=t[n];if(i)return i;throw new e(`INVALID_ARGS`,`${r} requires ${n} in the environment.`)}function Pt(t,n,r,i,a){let o=Q(t,r)??n[i]??n[a];if(o)return o;throw new e(`INVALID_ARGS`,`AWS Device Farm requires --${It(String(r))} or ${a}.`)}function Ft(e){let t=Q(e,`awsInteractionMode`);if(t===`INTERACTIVE`||t===`NO_VIDEO`||t===`VIDEO_ONLY`)return t}function It(e){return e.replaceAll(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}function Lt(e){let t=At(e);return{providerIds:t.map(e=>e.provider),createDefaultRuntimes:(e=process.env)=>t.map(t=>t.createRuntime(e)),listArtifactsFromEnv:async(e,n)=>{if(e.providerSessionId)return await t.find(t=>t.provider===e.provider)?.listArtifactsFromEnv(e.providerSessionId,n)},verifyConnection:async t=>await kt(t,e)}}const Rt=Lt({clientVersion:u(),runHostCommand:async(e,t)=>({stdout:(await l(e,[...t],{maxBuffer:10485760,timeoutMs:3e4})).stdout})});export{G as n,V as r,Rt as t};
1
+ import{D as e,j as t}from"./sdk-contracts.js";import{a as n,b as r}from"./sdk-device.js";import{Qt as i}from"./sdk-batch.js";import{d as a}from"./scroll-gesture.js";import{c as o}from"./sdk-remote-config.js";import"./device.js";import{o as s,s as c}from"./device-rotation.js";import{c as l}from"./exec.js";import"./command.js";import{r as u}from"./version.js";import{n as d,r as f,t as p}from"./capabilities.js";import{t as ee}from"./webdriver-source.js";import{t as m}from"./providers.js";import h from"node:path";import te from"node:fs";import g from"node:fs/promises";import{setTimeout as ne}from"node:timers/promises";function re(e,t){let n=e?.bundleId??t?.appIdentifierHint,r=e?.packageName??t?.packageNameHint;return{bundleId:n,packageName:r,appName:e?.appName,launchTarget:ae(e?.launchTarget,n,r)}}function ie(e){return e===`ios`?`xctest`:`android`}function ae(...e){return e.find(e=>e!==void 0)}function oe(e){let t=async(t,n,r,i,a)=>{let o=e.findSessionForDevice(t);if(!o)return;let s=await ce(e,o,t,n,r,i,a);return await o.client.installApp(s?.appReference??r,a),re(s,i)};return Object.freeze({fact:t=>se(e.findSessionForDevice(t)),installApp:t,installInstallablePath:async(e,n,r,i)=>await t(e,``,n,r,i),deployApp:async(e,n,r)=>_(await t(e,n.app,n.appPath,{relaunch:n.replaceExisting,appIdentifierHint:n.app,packageNameHint:n.app},r),n.app),deployMaterializedApp:async(e,n,r)=>_(await t(e,``,n.artifact.installablePath,{appIdentifierHint:n.artifact.bundleId,packageNameHint:n.artifact.packageName},r))})}function se(e){return e?p(e.capabilities,`install`)?Object.freeze({available:!0}):Object.freeze({available:!1,reason:`owner-capability-missing`,hint:f(e.capabilities,`install`)}):Object.freeze({available:!1,reason:`owner-capability-missing`,hint:`The WebDriver provider session is no longer active for this device.`})}async function ce(t,n,i,a,o,s,c){if(!p(n.capabilities,`install`))throw new e(`UNSUPPORTED_OPERATION`,f(n.capabilities,`install`),{provider:t.provider,deviceId:i.id,platform:r(i)});let l=n.prepared.uploadApp??t.uploadApp;if(l)return await l({provider:t.provider,lease:n.lease,device:i,app:a,appPath:o,options:s,signal:c})}function _(t,n){if(!t)throw new e(`UNSUPPORTED_OPERATION`,`The WebDriver provider session no longer supports app deployment.`);return{...t.bundleId?{bundleId:t.bundleId}:{},...t.packageName?{packageName:t.packageName}:{},...t.appName?{appName:t.appName}:{},...t.launchTarget??n?{launchTarget:t.launchTarget??n}:{}}}function v(e){return{provider:e.provider,providerSessionId:e.providerSessionId,status:e.artifacts.length>0?`ready`:`pending`,cloudArtifacts:e.artifacts,...e.artifacts.length>0?{}:{message:e.pendingMessage}}}function le(e){return{provider:e.provider,providerSessionId:e.providerSessionId,status:`unavailable`,cloudArtifacts:[],message:e.error instanceof Error?e.error.message:String(e.error)}}function y(e){return{"x-agent-device-client":`agent-device-cli`,"x-agent-device-version":e}}async function ue(n,r){try{await r()}catch(r){n instanceof e&&(n.details={...n.details,cleanupError:t(r)})}}function de(e,t){return typeof e==`function`?e(t):e}function b(e){return`Basic ${Buffer.from(`${e.username}:${e.accessKey}`).toString(`base64`)}`}function fe(e){let t=0;for(;t<e.length&&e.charCodeAt(t)===47;)t+=1;return t===0?e:e.slice(t)}function pe(e){let t=e.length-1;for(;t>=0&&e.charCodeAt(t)===47;)--t;return t===e.length-1?e:e.slice(0,t+1)}function me(e){if(e.pathname.endsWith(`/`))return e;let t=new URL(e);return t.pathname=`${t.pathname}/`,t}const x=`webdriver_request_timeout`;function S(t){return t instanceof e&&t.details?.reason===x}var he=class{endpoint;headers;requestPolicy;constructor(e){this.endpoint=me(new URL(e.endpoint)),this.headers={...y(e.clientVersion),...e.auth?{Authorization:b(e.auth)}:{},...e.headers},this.requestPolicy={timeoutMs:e.requestPolicy?.timeoutMs??3e4,retryAttempts:e.requestPolicy?.retryAttempts??1,retryDelayMs:e.requestPolicy?.retryDelayMs??250}}async requestValue(e,t,n,r){return await this.requestValueWithRetries(e,t,n,{retryAttempts:r?.retryAttempts??this.requestPolicy.retryAttempts,timeoutMs:r?.timeoutMs??this.requestPolicy.timeoutMs,signal:r?.signal})}async requestValueWithRetries(e,t,n,r){let i;for(let a=0;a<=r.retryAttempts;a+=1)try{return await this.requestValueOnce(e,t,n,r.timeoutMs,r.signal)}catch(e){if(i=e,!ge(e,a,r.retryAttempts,r.signal))throw e;await ne(this.requestPolicy.retryDelayMs,void 0,{signal:r.signal})}throw i}async requestValueOnce(e,t,n,r,i){let{ok:a,status:o,text:s}=await this.fetchWebDriver(e,t,n,r,i),c=s?ve(s):{};if(!a)throw ye(o,c);return _e(c)}async fetchWebDriver(e,t,n,r,i){let a=AbortSignal.timeout(r),o=i?AbortSignal.any([i,a]):a;try{let r=await fetch(new URL(fe(t),this.endpoint),{method:e,headers:{Accept:`application/json`,...n===void 0?{}:{"Content-Type":`application/json`},...this.headers},body:n===void 0?void 0:JSON.stringify(n),signal:o});return{ok:r.ok,status:r.status,text:await r.text()}}catch(n){throw a.aborted&&!i?.aborted?be(e,t,r,n):n}}};function ge(e,t,n,r){return!r?.aborted&&xe(e)&&t<n}function _e(e){if(!e||typeof e!=`object`)return e;let t=e;return`value`in t?t.value:e}function ve(t){try{return JSON.parse(t)}catch(n){throw new e(`COMMAND_FAILED`,`WebDriver response was not valid JSON.`,{text:t},n)}}function ye(t,n){let r=n&&typeof n==`object`&&`value`in n?n.value:n,i=r&&typeof r==`object`&&typeof r.message==`string`?r.message:`WebDriver request failed with HTTP ${t}.`;return new e(`COMMAND_FAILED`,i,{status:t,response:n})}function be(t,n,r,i){return new e(`COMMAND_FAILED`,`WebDriver ${t} ${n} timed out after ${r}ms.`,{reason:x,method:t,path:n,timeoutMs:r},i instanceof Error?i:void 0)}function xe(t){if(S(t))return!0;if(t instanceof e){let e=t.details?.status;return typeof e==`number`&&e>=500}return t instanceof TypeError}var Se=class{transport;sessionCreateTimeoutMs;sessionId;constructor(e){this.transport=new he(e),this.sessionCreateTimeoutMs=e.requestPolicy?.sessionCreateTimeoutMs??18e4}async createSession(e,t){let n=we(await this.requestValue(`POST`,`/session`,{capabilities:Ce(e)},{retryAttempts:0,timeoutMs:Oe(this.sessionCreateTimeoutMs,t?.deadline)}));return this.sessionId=n.sessionId,n}async deleteSession(){let e=this.requireSessionId();await this.requestValue(`DELETE`,`/session/${e}`),this.sessionId=void 0}async installApp(e,t){await this.sessionRequest(`POST`,`/appium/device/install_app`,{appPath:e},{signal:t})}async activateApp(e){try{await this.sessionRequest(`POST`,`/appium/device/activate_app`,{appId:e})}catch{await this.executeScript(`mobile: activateApp`,[{appId:e,bundleId:e}])}}async terminateApp(e){try{await this.sessionRequest(`POST`,`/appium/device/terminate_app`,{appId:e})}catch{await this.executeScript(`mobile: terminateApp`,[{appId:e,bundleId:e}])}}async performActions(e){await this.sessionRequest(`POST`,`/actions`,{actions:e})}async releaseActions(){await this.sessionRequest(`DELETE`,`/actions`,void 0,{retryAttempts:0})}async sendKeys(e){await this.sessionRequest(`POST`,`/keys`,{value:Array.from(e)})}async hideKeyboard(){await this.sessionRequest(`POST`,`/appium/device/hide_keyboard`,void 0,{retryAttempts:0})}async isKeyboardShown(e){let t;try{t=await this.sessionRequest(`GET`,`/appium/device/is_keyboard_shown`,void 0,{retryAttempts:0,...e===void 0?{}:{timeoutMs:e}})}catch(e){if(O(e))return`unsupported`;throw e}return typeof t==`boolean`?t:`unsupported`}async activeElement(e){let t=e===void 0?void 0:Date.now()+e,n;try{n=De(await this.sessionRequest(`GET`,`/element/active`,void 0,T(t)))}catch(e){if(O(e))return`unsupported`;if(D(e))return`none`;throw e}if(n===void 0)return`unsupported`;try{let e=await this.sessionRequest(`GET`,`/element/${encodeURIComponent(n)}/rect`,void 0,T(t));return{id:n,rect:C(e)}}catch(e){if(O(e))return`unsupported`;if(D(e))return`none`;throw e}}async back(){await this.sessionRequest(`POST`,`/back`)}async setRotation(e){await this.sessionRequest(`POST`,`/rotation`,{x:0,y:0,z:e})}async setOrientation(e){await this.sessionRequest(`POST`,`/orientation`,{orientation:e})}async source(t){let n=await this.sessionRequest(`GET`,`/source`,void 0,t);if(typeof n!=`string`)throw new e(`COMMAND_FAILED`,`WebDriver source response was not a string`,{valueType:typeof n});return n}async screenshot(t){let n=await this.sessionRequest(`GET`,`/screenshot`);if(typeof n!=`string`)throw new e(`COMMAND_FAILED`,`WebDriver screenshot response was not base64 text`,{valueType:typeof n});await g.writeFile(t,Buffer.from(n,`base64`))}async windowRect(){return C(await this.sessionRequest(`GET`,`/window/rect`))}async executeScript(e,t=[]){return await this.sessionRequest(`POST`,`/execute/sync`,{script:e,args:t})}async sessionRequest(e,t,n,r){let i=this.requireSessionId();return await this.requestValue(e,`/session/${i}${t}`,n,r)}requireSessionId(){if(!this.sessionId)throw new e(`SESSION_NOT_FOUND`,`WebDriver session has not been created yet.`);return this.sessionId}async requestValue(e,t,n,r){return await this.transport.requestValue(e,t,n,r)}};function C(t){if(!t||typeof t!=`object`)throw new e(`COMMAND_FAILED`,`WebDriver window rect response was empty.`);let n=t,r={x:w(n,`x`),y:w(n,`y`),width:w(n,`width`),height:w(n,`height`)};if(r.x===void 0||r.y===void 0||r.width===void 0||r.height===void 0)throw new e(`COMMAND_FAILED`,`WebDriver window rect response was invalid.`,{response:n});return r}function w(e,t){let n=e[t];return typeof n==`number`&&Number.isFinite(n)?n:void 0}function Ce(e){return`alwaysMatch`in e||`firstMatch`in e?e:{alwaysMatch:e}}function we(t){if(!t||typeof t!=`object`)throw new e(`COMMAND_FAILED`,`WebDriver create-session response was empty.`);let n=t,r=typeof n.sessionId==`string`?n.sessionId:typeof n.session_id==`string`?n.session_id:void 0;if(!r)throw new e(`COMMAND_FAILED`,`WebDriver create-session response missed sessionId.`,{response:n});return{sessionId:r,capabilities:n.capabilities&&typeof n.capabilities==`object`?n.capabilities:{}}}const Te=new Set([405,501]),Ee=new Set([`unknown command`,`unknown method`]);function De(e){if(!e||typeof e!=`object`)return;let t=e,n=t[`element-6066-11e4-a52e-4f735466cecf`]??t.ELEMENT;return typeof n==`string`&&n.length>0?n:void 0}function T(e){return e===void 0?{retryAttempts:0}:{retryAttempts:0,timeoutMs:E(e)}}function Oe(e,t){return t===void 0?e:Math.min(e,E(t))}function E(e){return Math.max(0,e-Date.now())}function D(t){return t instanceof e&&k(t).toLowerCase()===`no such element`}function O(t){if(!(t instanceof e))return!1;let n=t.details?.status;return typeof n==`number`&&Te.has(n)?!0:Ee.has(k(t).toLowerCase())}function k(e){let t=e.details?.response,n=t&&typeof t==`object`?t.value:void 0,r=n&&typeof n==`object`?n.error:void 0;return typeof r==`string`?r:``}function A(e,t){return{type:`pointer`,id:e,parameters:{pointerType:`touch`},actions:t}}async function ke(e){return j(ee(e,`android`).nodes)}function Ae(e){return j(ee(e).nodes)}function j(e){let t=e.flatMap(e=>je(e)&&Me(e.rect)?[e.rect]:[]).sort((e,t)=>t.width*t.height-e.width*e.height)[0];return t?{x:t.x,y:t.y,width:t.width,height:t.height}:void 0}function je(e){let t=e.type?.toLowerCase()??``;return e.visibleToUser!==!1&&(t.includes(`scrollview`)||t.includes(`listview`)||t.includes(`recyclerview`))}function Me(e){return!!e&&e.width>=50&&e.height>=50}async function Ne(t,n,r){let i=[];for(let e of n===`android`?[`rotation`,`orientation`]:[`orientation`,`rotation`])try{await Re(t,e,r);return}catch(t){if(!Ie(t))throw t;i.push({transport:e,error:t instanceof Error?t.message:String(t)})}throw new e(`COMMAND_FAILED`,`Could not set device orientation to ${r} on the hosted WebDriver session.`,{hint:`The provider driver rejected both orientation endpoints. Set the orientation as a session capability instead, for example connect --provider-device-orientation portrait.`,rotation:r,attempts:i})}const Pe=new Set([`unknown command`,`unknown method`]),Fe=new Set([404,405]);function Ie(t){if(!(t instanceof e)||t.code===`SESSION_NOT_FOUND`)return!1;let n=Le(t.details?.response);if(n)return Pe.has(n);let r=t.details?.status;return typeof r==`number`&&Fe.has(r)}function Le(e){if(!e||typeof e!=`object`)return``;let t=e.value;if(!t||typeof t!=`object`)return``;let n=t.error;return typeof n==`string`?n:``}async function Re(e,t,n){if(t===`rotation`){await e.setRotation(c(n));return}await e.setOrientation(s(n))}const M=1500;function ze(e){return new Promise(t=>setTimeout(t,e))}function N(t,n,r){return new e(`COMMAND_FAILED`,`fill tapped (${t}, ${n}) but ${r}`,{reason:`text_entry_focus_not_observed`,x:t,y:n,hint:`The tap most likely missed the field. Re-check the target with snapshot -i and fill the element it reports, rather than retrying the same coordinates.`})}function Be(t,n){return new e(`COMMAND_FAILED`,`fill tapped (${t}, ${n}) but this driver reports neither the focused element nor keyboard state, so the text was not sent`,{reason:`text_entry_focus_unobservable`,x:t,y:n,hint:`This provider cannot confirm a field took focus. Use press <target> followed by type <text> to enter it anyway, accepting that nothing witnesses which field receives the keys.`})}function Ve(e,t,n){return t>=e.x&&t<=e.x+e.width&&n>=e.y&&n<=e.y+e.height}function He(e){return new Ue(e.client,e.backend,e.capabilities,e.targetId)}var Ue=class{client;backend;capabilities;targetId;constructor(e,t,n,r){this.client=e,this.backend=t,this.capabilities=n,this.targetId=r}async open(e,t){if(t?.url){await this.client.executeScript(`mobile: deepLink`,[{url:t.url,package:e}]);return}let n=t?.appBundleId??e;n&&await this.client.activateApp(n)}async openDevice(){await this.client.executeScript(`mobile: activateApp`,[{}])}async close(e){e&&await this.client.terminateApp(e)}async tap(e,t){return this.requireSupport(`tap`),await this.pointerGesture(`tap`,[{type:`pointerMove`,duration:0,x:e,y:t},{type:`pointerDown`,button:0},{type:`pointerUp`,button:0}]),{backend:`webdriver`,x:e,y:t}}async doubleTap(e,t){return this.requireSupport(`doubleTap`),await this.pointerGesture(`doubleTap`,[{type:`pointerMove`,duration:0,x:e,y:t},{type:`pointerDown`,button:0},{type:`pointerUp`,button:0},{type:`pause`,duration:80},{type:`pointerDown`,button:0},{type:`pointerUp`,button:0}]),{backend:`webdriver`,x:e,y:t}}async swipe(e,t,n,r,i=400){return this.requireSupport(`swipe`),await this.pointerGesture(`swipe`,[{type:`pointerMove`,duration:0,x:e,y:t},{type:`pointerDown`,button:0},{type:`pointerMove`,duration:i,x:n,y:r},{type:`pointerUp`,button:0}]),{backend:`webdriver`,x1:e,y1:t,x2:n,y2:r,durationMs:i}}async longPress(e,t,n=600){return this.requireSupport(`longPress`),await this.pointerGesture(`longPress`,[{type:`pointerMove`,duration:0,x:e,y:t},{type:`pointerDown`,button:0},{type:`pause`,duration:n},{type:`pointerUp`,button:0}]),{backend:`webdriver`,x:e,y:t,durationMs:n}}async focus(e,t){return await this.tap(e,t)}async type(e){this.requireSupport(`type`),await this.client.sendKeys(e)}async fill(t,n,r,i){if(this.requireSupport(`fill`),r.length===0)throw new e(`UNSUPPORTED_OPERATION`,`fill with empty text (clear field) is not supported on the webdriver backend`,{hint:`Use a visible clear/reset control in the app, or fill the field with the intended replacement text directly.`});let a=await this.readTextEntryState();await this.tap(t,n);let o=await this.awaitTextEntryReadiness(a,t,n);return await this.type(r),{backend:`webdriver`,x:t,y:n,text:r,textEntryReadiness:o}}async scroll(e,t){this.requireSupport(`scroll`);let n=t?.durationMs??350;await this.client.hideKeyboard().catch(()=>void 0);let r=await this.scrollGestureFrame(),i=a({direction:e,amount:t?.amount,pixels:t?.pixels,referenceWidth:r.width,referenceHeight:r.height}),o={...i,x1:i.x1+r.x,y1:i.y1+r.y,x2:i.x2+r.x,y2:i.y2+r.y};return await this.swipe(o.x1,o.y1,o.x2,o.y2,n),{backend:`webdriver`,...o,distance:i.pixels,durationMs:n}}async gestureViewport(){return await this.scrollGestureFrame()}async performGesture(e){return this.requireSupport(Ge(e)),await this.client.performActions(e.pointers.map(e=>A(`gesture-pointer-${e.pointerId}`,We(e.samples)))),await this.client.releaseActions().catch(()=>void 0),{backend:`webdriver-w3c-actions`}}async screenshot(e,t){this.requireSupport(`screenshot`),await this.client.screenshot(e)}async snapshot(e){return this.requireSupport(`snapshot`),await this.captureSource(e?.signal)}async captureSource(e){let t=await this.readSource(e);if(this.backend===`xctest`){let{acquireWebDriverIosSnapshot:e}=await import(`./webdriver-ios-snapshot.js`);return e(t,this.targetId)}let{parseWebDriverSourceFacts:n}=await import(`./webdriver-source.js`).then(e=>e.n);return{backend:`android`,producer:`appium-source`,nodes:n(t,`android`).nodes}}async readSource(e){try{return await this.client.source(e===void 0?{}:{signal:e})}catch(e){throw S(e)?Ke(e):e}}async back(e){this.requireSupport(`back`),await this.client.back()}async home(){this.requireSupport(`home`),await this.client.executeScript(`mobile: pressButton`,[{name:`home`}])}async setOrientation(e){this.requireSupport(`orientation`),await Ne(this.client,this.backend,e)}async appSwitcher(){this.requireSupport(`appSwitcher`),await this.client.executeScript(`mobile: pressButton`,[{name:`appSwitch`}])}async tvRemote(e,t){this.unsupported(`tvRemote`)}async readClipboard(){this.requireSupport(`clipboard.read`);let e=await this.client.executeScript(`mobile: getClipboard`,[{}]);return typeof e==`string`?e:``}async writeClipboard(e){this.requireSupport(`clipboard.write`),await this.client.executeScript(`mobile: setClipboard`,[{content:e}])}async setSetting(e,t,n,r){this.unsupported(`settings`)}async readAlert(){this.unsupported(`alert`)}async awaitAlert(){this.unsupported(`alert`)}async acceptAlert(){this.unsupported(`alert`)}async dismissAlert(){this.unsupported(`alert`)}async awaitTextEntryReadiness(e,t,n){let r=e.keyboard,i=Date.now()+2e3,a=e.focusedElementId,o=await this.pollWithinBudget(i,async e=>{let r=await this.client.activeElement(e);return r===`unsupported`?`abandon`:r===`none`?`retry`:r.id!==a||Ve(r.rect,t,n)?`satisfied`:`retry`});if(o===`satisfied`)return`focused-element`;if(o===`expired`)throw N(t,n,`nothing there took text-entry focus, so the text was not sent`);if(r===`unsupported`)throw Be(t,n);if(r)throw N(t,n,`the keyboard was already up and this driver cannot report which field holds focus, so the text was not sent`);if(await this.pollWithinBudget(i,async e=>await this.client.isKeyboardShown(e)===!0?`satisfied`:`retry`)===`satisfied`)return`keyboard-shown`;throw N(t,n,`no keyboard appeared, so the text was not sent`)}async readTextEntryState(){let[e,t]=await Promise.all([this.client.isKeyboardShown(M),this.client.activeElement(M)]);return{keyboard:e,focusedElementId:t===`none`||t===`unsupported`?void 0:t.id}}async pollWithinBudget(e,t){let n=!1,r;for(;;){let i=e-Date.now();if(i<=0)break;try{let e=await t(Math.min(M,i));if(n=!0,e!==`retry`)return e}catch(e){r=e}let a=e-Date.now();if(a<=0)break;await ze(Math.min(100,a))}if(!n&&r!==void 0)throw r;return`expired`}async pointerGesture(e,t){await this.client.performActions([A(e,t)]),await this.client.releaseActions().catch(()=>void 0)}async scrollGestureFrame(){return await this.client.source().then(e=>this.backend===`xctest`?Ae(e):ke(e)).catch(()=>void 0)||await this.client.windowRect()}requireSupport(e){p(this.capabilities,e)||this.unsupported(e)}unsupported(t){throw new e(`UNSUPPORTED_OPERATION`,f(this.capabilities,t),{provider:this.capabilities.provider,platform:this.capabilities.platform,operation:t})}};function We(t){let n=t[0];if(!n)throw new e(`INVALID_ARGS`,`WebDriver gesture pointer requires samples`);let r=[{type:`pointerMove`,duration:0,x:n.point.x,y:n.point.y},{type:`pointerDown`,button:0}];for(let e=1;e<t.length;e+=1){let n=t[e-1],i=t[e];r.push({type:`pointerMove`,duration:i.offsetMs-n.offsetMs,x:i.point.x,y:i.point.y})}return r.push({type:`pointerUp`,button:0}),r}function Ge(e){if(e.topology===`single`)return`swipe`;switch(e.intent){case`pan`:case`transform`:return`transformGesture`;case`pinch`:return`pinch`;case`rotate`:return`rotateGesture`}}function Ke(t){return new e(`COMMAND_FAILED`,`The cloud driver did not finish reading the screen in its budget.`,{...t.details,hint:`A screen that never goes idle (looping video, live ticker, continuous animation) gives the driver no moment to read the UI tree. This read has the transport's own budget and does not grow with --timeout; take a screenshot, or drive the screen from refs an earlier snapshot already captured.`},t)}var qe=class{sessionsByLeaseId=new Map;ownedDeviceIds=new Set;releasedProviderSessionIdsByLeaseId=new Map;options;constructor(e){this.options=e}ownsDevice(e){return this.ownedDeviceIds.has(e.id)}findSessionForDevice(e){return[...this.sessionsByLeaseId.values()].find(t=>t.device.id===e.id)}findSessionForLease(e){return this.sessionsByLeaseId.get(e)}getInteractor(e){return this.findSessionForDevice(e)?.interactor}heartbeat(e){if(e.leaseProvider===this.options.provider&&this.sessionsByLeaseId.has(e.leaseId))return{provider:this.options.provider}}async allocate(e,t){if(e.leaseProvider!==this.options.provider)return;if(this.sessionsByLeaseId.has(e.leaseId))return this.heartbeat(e);let n=await this.prepareSession(e,t),r=new Se({clientVersion:this.options.clientVersion,endpoint:n.endpoint,auth:n.auth,headers:n.headers,requestPolicy:this.options.requestPolicy}),i=await this.createSessionWithPreparedCleanup(r,n,e,t),a=this.deviceForLease(e,n),o=n.providerSessionId??i.sessionId,s=d({provider:this.options.provider,platform:n.platform,overrides:this.options.capabilityOverrides});return this.sessionsByLeaseId.set(e.leaseId,Object.freeze({lease:e,device:a,client:r,prepared:n,capabilities:s,webDriverSessionId:i.sessionId,providerSessionId:o,interactor:He({client:r,backend:ie(n.platform),capabilities:s,targetId:a.id})})),this.ownedDeviceIds.add(a.id),{provider:this.options.provider,deviceId:a.id,sessionId:i.sessionId,providerSessionId:o,capabilities:s,...n.providerData}}async release(e){if(e.leaseProvider!==this.options.provider)return;let t=this.sessionsByLeaseId.get(e.leaseId);if(!t)return;this.sessionsByLeaseId.delete(e.leaseId),this.releasedProviderSessionIdsByLeaseId.set(e.leaseId,t.providerSessionId);let n=await this.closeSession(t),r=await this.safeListArtifacts(t);return{provider:this.options.provider,providerSessionId:t.providerSessionId,...n.cleanup,...n.warnings.length>0?{warnings:n.warnings}:{},...r?{cloudArtifacts:r}:{}}}async listCloudArtifacts(e){if(e.provider!==this.options.provider)return;let t=this.sessionsByLeaseId.get(e.leaseId??``);return t?await this.listActiveCloudArtifacts(t,e.providerSessionId):await this.listReleasedCloudArtifacts(e)}async listActiveCloudArtifacts(e,t){if(!(t&&t!==e.providerSessionId))return await this.safeListArtifacts(e)}async listReleasedCloudArtifacts(e){let t=this.releasedProviderSessionIdsByLeaseId.get(e.leaseId??``);if(!(!t||!this.options.listArtifacts)&&!(e.providerSessionId&&e.providerSessionId!==t))return await this.options.listArtifacts({provider:this.options.provider,providerSessionId:t})}async shutdown(){await Promise.allSettled([...this.sessionsByLeaseId.values()].map(async e=>await this.closeSession(e))),this.sessionsByLeaseId.clear(),this.ownedDeviceIds.clear()}async createSessionWithPreparedCleanup(e,t,n,r){try{return await e.createSession(t.webdriverCapabilities,{deadline:r?.deadline})}catch(e){let r=S(e)?Je(e,this.options.provider,n,t):e;throw await ue(r,()=>t.cleanup?.()),r}}async prepareSession(e,t){let n=this.baseSessionForLease(e);return this.options.prepareSession?await this.options.prepareSession({lease:e,req:t,base:n}):n}baseSessionForLease(e){let t=typeof this.options.webdriverCapabilities==`function`?this.options.webdriverCapabilities(e):this.options.webdriverCapabilities??{};return{provider:this.options.provider,endpoint:this.options.endpoint,platform:this.options.platform,deviceName:this.options.deviceName,auth:this.options.auth,headers:this.options.headers,webdriverCapabilities:P(this.options.platform,this.options.deviceName,t)}}deviceForLease(e,t){return{...n(t.platform),...t.platform===`ios`?{appleOs:`ios`}:{},id:t.deviceId??this.options.deviceId?.(e)??`${this.options.provider}:${t.platform}:${e.leaseId}`,name:t.deviceName,kind:`device`,target:`mobile`,booted:!0}}async closeSession(e){let n=[],r;try{await e.client.deleteSession()}catch(e){n.push({code:`WEBDRIVER_SESSION_DELETE_FAILED`,message:t(e)})}try{r=await e.prepared.cleanup?.()}catch(e){n.push({code:`PROVIDER_CLEANUP_FAILED`,message:t(e)})}return{cleanup:r,warnings:n}}async safeListArtifacts(e){let t=e.prepared.listArtifacts??this.options.listArtifacts;if(t)try{return await t({provider:this.options.provider,lease:e.lease,device:e.device,webDriverSessionId:e.webDriverSessionId,providerSessionId:e.providerSessionId})}catch(t){return le({provider:this.options.provider,providerSessionId:e.providerSessionId,error:t})}}};function P(e,t,n={}){return{platformName:e===`ios`?`iOS`:`Android`,"appium:deviceName":t,...n}}function Je(t,n,r,i){let a=t.details?.timeoutMs;return new e(`COMMAND_FAILED`,`${n} did not create the WebDriver session within ${String(a)}ms.`,{reason:`provider_session_create_timeout`,provider:n,leaseId:r.leaseId,runId:r.runId,timeoutMs:a,...i.providerSessionId?{providerSessionId:i.providerSessionId}:{},hint:`${n} may still finish creating the session after agent-device stopped waiting, and that session would keep billing until the provider reaps it. Before retrying, check ${n} for a running session created for lease ${r.leaseId} (run ${r.runId}) and stop it.`},t)}function F(e){return new Ye(e)}var Ye=class{provider;owner;leaseLifecycle;cloudArtifacts;deviceInventoryProvider;capabilities;platformRuntimeModule;sessions;deployment;constructor(e){this.provider=e.provider,this.owner=i(e.provider,e.platform),this.capabilities=d({provider:e.provider,platform:e.platform,overrides:e.capabilityOverrides}),this.sessions=new qe(e),this.deployment=oe({provider:e.provider,uploadApp:e.uploadApp,findSessionForDevice:e=>this.sessions.findSessionForDevice(e)}),this.platformRuntimeModule=Object.freeze({owner:this.owner,loadRuntime:async e=>await this.loadRuntime(e)}),this.leaseLifecycle={allocate:async(e,t)=>await this.sessions.allocate(e,t),heartbeat:async e=>this.sessions.heartbeat(e),release:async e=>await this.sessions.release(e)},this.cloudArtifacts={listCloudArtifacts:async e=>await this.sessions.listCloudArtifacts(e)},this.deviceInventoryProvider=async e=>{if(e.leaseProvider!==this.provider)return null;if(!e.leaseId)return[];let t=this.sessions.findSessionForLease(e.leaseId);return t?[t.device]:[]}}async loadRuntime(e){let{createWebDriverPlatformRuntimeOwner:t}=await import(`./platform-runtime2.js`);return t({host:e,owner:this.owner,ownsDevice:e=>this.ownsDevice(e),isSessionActive:e=>this.sessions.findSessionForDevice(e)!==void 0,deployment:this.deployment,capabilities:this.capabilities,snapshotAvailable:this.capabilities.operations.snapshot.support!==`unsupported`,screenshotAvailable:this.capabilities.operations.screenshot.support!==`unsupported`,getInteractor:e=>this.getInteractor(e)})}ownsDevice(e){return this.sessions.ownsDevice(e)}getInteractor(e){return this.sessions.getInteractor(e)}async installApp(e,t,n,r){return await this.deployment.installApp(e,t,n,r)}async installInstallablePath(e,t,n){return await this.deployment.installInstallablePath(e,t,n)}async shutdown(){await this.sessions.shutdown()}};async function I(e,t,n){return t?v({provider:e,providerSessionId:t,artifacts:(await Promise.all([n.listArtifacts(t,`FILE`),n.listArtifacts(t,`LOG`)])).flat().flatMap(n=>Ze(e,t,n)),pendingMessage:`AWS Device Farm artifacts are not ready yet.`}):void 0}function Xe(e){if(!e||typeof e!=`object`)return[];let t=e.artifacts;return Array.isArray(t)?t:[]}function Ze(e,t,n){let r=n.url;return typeof r!=`string`||r.length===0?[]:[{provider:e,providerSessionId:t,kind:Qe(n.type),name:n.name??n.type??`AWS Device Farm artifact`,url:r,providerArtifactId:n.arn,extension:n.extension,availability:`ready`,metadata:{awsType:n.type,...n.metadata?{awsMetadata:n.metadata}:{}}}]}function Qe(e){switch(e){case`VIDEO`:return`video`;case`APPIUM_SERVER_OUTPUT`:return`appium-log`;case`DEVICE_LOG`:return`device-log`;case`MESSAGE_LOG`:case`UNKNOWN`:return`automation-log`;default:return`raw`}}m.awsDeviceFarm;const $e={install:{support:`unsupported`,note:`Pass appArn when creating the remote access session; local artifact upload/install is not implemented.`},portReverse:{support:`unsupported`,note:`AWS Device Farm remote access does not expose agent-device port reverse.`},artifacts:{support:`supported`,note:`AWS Device Farm remote access exposes provider-hosted video, Appium logs, and device logs after session completion.`}};function L(e){let t=R(e);return{createRemoteAccessSession:async e=>z(await t(`create-remote-access-session`,[`--project-arn`,e.projectArn,`--device-arn`,e.deviceArn,`--name`,e.name,...e.appArn?[`--app-arn`,e.appArn]:[],...e.interactionMode?[`--interaction-mode`,e.interactionMode]:[],...e.configuration?[`--configuration`,JSON.stringify(e.configuration)]:[]])),getRemoteAccessSession:async e=>z(await t(`get-remote-access-session`,[`--arn`,e])),stopRemoteAccessSession:async e=>z(await t(`stop-remote-access-session`,[`--arn`,e])),listArtifacts:async(e,n)=>Xe(await t(`list-artifacts`,[`--arn`,e,`--type`,n]))}}function et(t){return async({lease:n,req:r,base:i})=>{let a=await t.client.createRemoteAccessSession({projectArn:t.projectArn,deviceArn:t.deviceArn,appArn:t.appArn,name:de(t.sessionName,n)??`agent-device-${n.leaseId}`,interactionMode:t.interactionMode,configuration:t.configuration}),o,s;try{if(o=await rt(a.arn,t,r),s=tt(o),!s)throw new e(`COMMAND_FAILED`,`AWS Device Farm did not expose a WebDriver endpoint.`,{sessionArn:o.arn,status:o.status})}catch(e){throw await ue(e,()=>t.client.stopRemoteAccessSession(a.arn)),e}let c=o.device?.name??t.deviceName,l=typeof t.webdriverCapabilities==`function`?t.webdriverCapabilities(n):t.webdriverCapabilities??{},u=t.platform===`android`?{"appium:autoLaunch":!1}:{};return{...i,endpoint:s,platform:t.platform,deviceName:c,webdriverCapabilities:P(t.platform,c,{...u,...l}),cleanup:async()=>(await t.client.stopRemoteAccessSession(o.arn),{awsDeviceFarmSessionArn:o.arn}),providerSessionId:o.arn,providerData:{awsDeviceFarmSessionArn:o.arn}}}}function tt(e){let t=e.endpoints&&typeof e.endpoints==`object`?Object.values(e.endpoints):[],n=[e.remoteDriverEndpoint,e.endpoint,...t,e.remoteDebugUrl,e.remoteRecordAppUrl].filter(e=>typeof e==`string`&&e.length>0).find(e=>!/^wss?:\/\//i.test(e));return n?nt(n):void 0}function nt(e){return/^https?:\/\//i.test(e)?e:`http://${e}`}async function rt(t,n,r){let i=n.pollIntervalMs??5e3,a=Date.now(),o=r?.deadline??a+(n.startupTimeoutMs??12e4),s=r?.signal,c=await n.client.getRemoteAccessSession(t);for(;Date.now()<o;){if(s?.throwIfAborted(),c.status===`RUNNING`)return c;at(c),await ne(i,void 0,{signal:s}).catch(()=>s?.throwIfAborted()),c=await n.client.getRemoteAccessSession(t)}throw new e(`COMMAND_FAILED`,`Timed out waiting for AWS Device Farm remote access.`,{sessionArn:t,status:c.status,result:c.result,timeoutMs:o-a})}const it=new Set([`ERRORED`,`STOPPED`,`COMPLETED`]);function at(t){if(!(!t.status||!it.has(t.status)))throw new e(`COMMAND_FAILED`,`AWS Device Farm remote access session did not start.`,{sessionArn:t.arn,status:t.status,result:t.result})}async function ot(t,n,r){let i=await t(n,r);try{return JSON.parse(i.stdout)}catch(t){throw new e(`COMMAND_FAILED`,`AWS Device Farm returned invalid JSON.`,void 0,t)}}function R(e){let t=e.region?[`--region`,e.region]:[],n=e.awsCommand??`aws`;return async(r,i)=>await ot(e.runHostCommand,n,[`devicefarm`,r,...t,...i,`--output`,`json`])}function z(t){if(!t||typeof t!=`object`)throw new e(`COMMAND_FAILED`,`AWS Device Farm response was not an object.`,{response:t});let n=t.remoteAccessSession;if(!n||typeof n!=`object`)throw new e(`COMMAND_FAILED`,`AWS Device Farm response missed remoteAccessSession.`,{response:t});return n}const B=[{field:`providerDeviceOrientation`,capability:`deviceOrientation`,flag:`--provider-device-orientation`,type:`enum`,enumValues:o},{field:`providerGeoLocation`,capability:`geoLocation`,flag:`--provider-geo-location`,type:`string`},{field:`providerTimezone`,capability:`timezone`,flag:`--provider-timezone`,type:`string`},{field:`providerAppiumVersion`,capability:`appiumVersion`,flag:`--provider-appium-version`,type:`string`},{field:`providerLanguage`,capability:`language`,flag:`--provider-language`,type:`string`},{field:`providerLocale`,capability:`locale`,flag:`--provider-locale`,type:`string`},{field:`providerNetworkProfile`,capability:`networkProfile`,flag:`--provider-network-profile`,type:`string`},{field:`providerCustomNetwork`,capability:`customNetwork`,flag:`--provider-custom-network`,type:`string`},{field:`providerNoResignApp`,capability:`resignApp`,flag:`--provider-no-resign-app`,type:`negated-boolean`,platform:`ios`}];function st(e,t){pt(e);let n={};for(let r of B){let i=e[r.field];i!==void 0&&i!==!1&&i!==``&&(ft(r,t),n[r.capability]=r.type!==`negated-boolean`&&i)}return n}function ct(e){return B.filter(t=>{let n=e?.[t.field];return n!==void 0&&n!==!1&&n!==``}).map(e=>e.flag)}function V(t,n){let r=ct(t);if(r.length===0)return;let i=r.length!==1;throw new e(`INVALID_ARGS`,`${r.join(`, `)} ${i?`are`:`is`} only supported by BrowserStack, not ${n}.`,{hint:`Drop ${i?`those flags`:`the flag`} or use the browserstack provider.`,provider:n,flags:r})}function lt(e){let t={};for(let n of B){let r=e?.[n.field];if(n.type===`negated-boolean`){r===!0&&(t.providerNoResignApp=!0);continue}typeof r==`string`&&r.length!==0&&ut(t,n,r)}return t}function ut(e,t,n){if(t.field===`providerDeviceOrientation`){e.providerDeviceOrientation=dt(t,n);return}t.field!==`providerNoResignApp`&&(e[t.field]=n)}function dt(t,n){let r=o.find(e=>e===n);if(r)return r;throw new e(`INVALID_ARGS`,`Invalid ${t.flag} value: ${n}.`,{hint:`Use ${o.join(`|`)}.`,flag:t.flag,capability:t.capability})}function ft(t,n){if(!(!t.platform||t.platform===n))throw new e(`INVALID_ARGS`,`${t.flag} applies to ${t.platform} sessions only, but the session platform is ${n}.`,{hint:`Drop ${t.flag} or connect with --platform ${t.platform}.`,flag:t.flag,capability:t.capability,platform:n})}function pt(t){if(!(!t.providerNetworkProfile||!t.providerCustomNetwork))throw new e(`INVALID_ARGS`,`BrowserStack accepts either a named network profile or a custom network shape, not both.`,{hint:`Pass only one of --provider-network-profile or --provider-custom-network.`,networkProfile:t.providerNetworkProfile,customNetwork:t.providerCustomNetwork})}m.browserStack;const mt={install:{support:`partial`,note:`Local app artifacts are uploaded to BrowserStack App Automate, then installed with Appium.`},portReverse:{support:`unsupported`,note:`Use BrowserStack Local for network tunneling; agent-device port reverse is not available.`},artifacts:{support:`supported`,note:`BrowserStack session details expose provider-hosted video, Appium logs, device logs, and dashboard links.`}};async function H(e,t,n){return t?v({provider:e,providerSessionId:t,artifacts:yt(e,t,await vt(t,n)),pendingMessage:`BrowserStack artifacts are not ready yet.`}):void 0}async function U(t,n,r){r?.throwIfAborted();let i=await g.readFile(t),a=new FormData;a.set(`file`,new Blob([i]),h.basename(t));let o=await fetch(n.endpoint??`https://api-cloud.browserstack.com/app-automate/upload`,{method:`POST`,headers:{...y(n.clientVersion),Authorization:b(n)},body:a,signal:r}),s=await o.json(),c=bt(s);if(!o.ok||!c)throw new e(`COMMAND_FAILED`,`BrowserStack app upload failed.`,{status:o.status,response:s});return c}function ht(e){return async({appPath:t,options:n,signal:r})=>({appReference:await U(t,e,r),bundleId:n?.appIdentifierHint,packageName:n?.packageNameHint,launchTarget:n?.appIdentifierHint??n?.packageNameHint})}function gt(e){let{"bstack:options":t,...n}=e.configured??{};return{"appium:deviceName":e.deviceName,"appium:platformVersion":e.osVersion,...e.app?{"appium:app":e.app}:{},...n,"bstack:options":{...e.projectName?{projectName:e.projectName}:{},buildName:e.buildName,sessionName:e.sessionName,...e.deviceFeatures??{},..._t(t)}}}function _t(e){return e&&typeof e==`object`&&!Array.isArray(e)?e:{}}async function vt(t,n){let r=new URL(`${pe(String(n.endpoint??`https://api-cloud.browserstack.com/app-automate/sessions`))}/${t}.json`),i=await fetch(r,{headers:{...y(n.clientVersion),Authorization:b(n)}}),a=await i.json();if(!i.ok||!a||typeof a!=`object`)throw new e(`COMMAND_FAILED`,`BrowserStack session details lookup failed.`,{status:i.status,response:a});let o=a.automation_session??a;return o&&typeof o==`object`?o:{}}function yt(e,t,n){return[W(e,t,n,`video_url`,`video`,`Session video`),W(e,t,n,`appium_logs_url`,`appium-log`,`Appium logs`),W(e,t,n,`device_logs_url`,`device-log`,`Device logs`),W(e,t,n,`browser_url`,`provider-session`,`BrowserStack dashboard`),W(e,t,n,`public_url`,`provider-session`,`Public session link`)].filter(e=>e!==void 0)}function W(e,t,n,r,i,a){let o=n[r];if(typeof o==`string`&&o.length!==0)return{provider:e,providerSessionId:t,kind:i,name:a,url:o,availability:`ready`}}function bt(e){if(!e||typeof e!=`object`)return;let t=e.app_url;return typeof t==`string`?t:void 0}function G(e){return/^arn:[^:]+:devicefarm:([^:]+):/.exec(e)?.[1]}async function xt(t,n){let r=R({runHostCommand:n,region:t.region}),[i,a,o]=await Promise.all([r(`get-project`,[`--arn`,t.projectArn]),r(`get-device`,[`--arn`,t.deviceArn]),t.appArn?r(`get-upload`,[`--arn`,t.appArn]):void 0]),s=K(i,`project`),c=K(a,`device`),l=Ct(c.platform);if(l!==t.platform)throw new e(`INVALID_ARGS`,`AWS Device Farm device "${q(c.name)??t.deviceArn}" is ${l}, not ${t.platform}.`);let u=t.appArn?St(K(o,`upload`),t):{status:`missing`,message:`No app upload is attached; AWS Device Farm does not support install after allocation. Reconnect with --aws-app-arn <arn>.`};return{provider:`aws-device-farm`,service:`AWS Device Farm`,verificationMessage:t.appArn?`Credentials, project, device, and app upload verified.`:`Credentials, project, and device verified.`,project:{name:q(s.name),reference:t.projectArn},device:{status:`verified`,name:q(c.name)??t.deviceArn,reference:t.deviceArn,platform:l,osVersion:q(c.os),availability:q(c.availability)},app:u}}function St(t,n){let r=q(t.status);if(r!==`SUCCEEDED`)throw new e(`COMMAND_FAILED`,`AWS Device Farm app upload is not ready (${r??`unknown status`}).`,{status:r,hint:`Wait for the upload to succeed or reconnect with a different --aws-app-arn.`});let i=n.platform===`android`?`ANDROID_APP`:`IOS_APP`,a=q(t.type);if(a!==i)throw new e(`INVALID_ARGS`,`AWS Device Farm app upload type is ${a??`unknown`}, expected ${i}.`);return{status:`verified`,name:q(t.name),reference:n.appArn}}function K(t,n){if(!t||typeof t!=`object`)throw new e(`COMMAND_FAILED`,`AWS Device Farm ${n} response was not an object.`);let r=t[n];if(!r||typeof r!=`object`||Array.isArray(r))throw new e(`COMMAND_FAILED`,`AWS Device Farm response missed ${n}.`);return r}function Ct(t){if(t===`ANDROID`)return`android`;if(t===`IOS`)return`ios`;throw new e(`UNSUPPORTED_PLATFORM`,`AWS Device Farm device platform is ${String(t)}.`)}function q(e){return typeof e==`string`&&e.length>0?e:void 0}async function wt(t,n){let r={username:t.username,accessKey:t.accessKey},i=Dt(await J(t.devicesEndpoint??`https://api-cloud.browserstack.com/app-automate/devices.json`,r,n)).find(e=>e.device===t.deviceName&&e.os.toLowerCase()===t.platform&&Et(e.osVersion,t.osVersion));if(!i)throw new e(`INVALID_ARGS`,`BrowserStack device "${t.deviceName}" with ${t.platform} ${t.osVersion} is not available.`,{hint:`Choose an exact device and OS version from the BrowserStack App Automate device list.`});let a=await Tt(t,r,n);return{provider:`browserstack`,service:`BrowserStack`,verificationMessage:a.status===`verified`?`Credentials, device, and uploaded app verified.`:`Credentials and device access verified; app availability is checked when the session is created.`,device:{status:`verified`,name:i.device,platform:t.platform,osVersion:i.osVersion},app:a}}async function Tt(e,t,n){let{app:r}=e;if(r.startsWith(`bs://`)){let i=Ot(await J(e.appsEndpoint??`https://api-cloud.browserstack.com/app-automate/recent_apps?limit=100`,t,n)).find(e=>e.reference===r);return i?{status:`verified`,...i}:{status:`configured`,reference:r,message:`App reference was not found in the 100 most recent uploads; BrowserStack validates it when creating the session.`}}return/^https?:\/\//i.test(r)?{status:`configured`,reference:r,message:`Public app URL configured; BrowserStack validates it when creating the session.`}:{status:`configured`,name:h.basename(r),reference:r,message:`Local app artifact is ready and will be uploaded when creating the session.`}}async function J(t,n,r){try{let i=await fetch(t,{headers:{...y(r),Authorization:b(n)},signal:AbortSignal.timeout(15e3)});if(!i.ok){let t=i.status===401||i.status===403;throw new e(t?`UNAUTHORIZED`:`COMMAND_FAILED`,`BrowserStack rejected connection verification.`,{status:i.status,hint:t?`Check BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY.`:`Retry connect or check the BrowserStack service status.`})}return await i.json()}catch(t){throw t instanceof e?t:new e(`COMMAND_FAILED`,`BrowserStack connection verification failed.`,{hint:`Check network access to api-cloud.browserstack.com and retry connect.`},t)}}function Et(e,t){let n=e=>e.replace(/(?:\.0)+$/,``);return n(e)===n(t)}function Dt(t){if(!Array.isArray(t))throw new e(`COMMAND_FAILED`,`BrowserStack device verification response was not a list.`);return t.flatMap(e=>{let t=Y(e),n=t?.os_version;return t&&typeof t.device==`string`&&typeof t.os==`string`&&(typeof n==`string`||typeof n==`number`)?[{device:t.device,os:t.os,osVersion:String(n)}]:[]})}function Ot(t){let n=Y(t);if(n&&Object.keys(n).length===0)return[];if(!Array.isArray(t))throw new e(`COMMAND_FAILED`,`BrowserStack app verification response was not a list.`);return t.flatMap(e=>{let t=Y(e);return!t||typeof t.app_url!=`string`?[]:[{reference:t.app_url,...typeof t.app_name==`string`?{name:t.app_name}:{},...typeof t.app_version==`string`?{version:t.app_version}:{}}]})}function Y(e){return e&&typeof e==`object`&&!Array.isArray(e)?e:void 0}async function kt(e,t){return e.provider===`browserstack`?await wt(e,t.clientVersion):await xt(e,t.runHostCommand)}function At(e){return[{provider:m.browserStack,createRuntime:t=>F({clientVersion:e.clientVersion,provider:m.browserStack,platform:`android`,deviceName:`BrowserStack device`,endpoint:t.BROWSERSTACK_WEBDRIVER_ENDPOINT??`https://hub-cloud.browserstack.com/wd/hub/`,capabilityOverrides:mt,listArtifacts:async({provider:n,providerSessionId:r})=>{let i=$(t,`BROWSERSTACK_USERNAME`,`BrowserStack artifact lookup`),a=$(t,`BROWSERSTACK_ACCESS_KEY`,`BrowserStack artifact lookup`);return await H(n,r,{clientVersion:e.clientVersion,username:i,accessKey:a,endpoint:t.BROWSERSTACK_SESSION_DETAILS_ENDPOINT})},prepareSession:async({req:n,lease:r,base:i})=>{let a=X(n,`BrowserStack`),o=$(t,`BROWSERSTACK_USERNAME`,`BrowserStack`),s=$(t,`BROWSERSTACK_ACCESS_KEY`,`BrowserStack`),c=Nt(a,`BrowserStack`),l=Z(a,`device`,`BrowserStack requires --device <name>.`),u=Z(a,`providerOsVersion`,`BrowserStack requires --provider-os-version <version>.`),d=await jt({clientVersion:e.clientVersion,app:Z(a,`providerApp`,`BrowserStack requires --provider-app <bs://app-id-or-local-path>.`),cwd:a.cwd,username:o,accessKey:s,uploadEndpoint:t.BROWSERSTACK_APP_UPLOAD_ENDPOINT,signal:a.signal});return{...i,platform:c,deviceName:l,auth:{username:o,accessKey:s},uploadApp:ht({clientVersion:e.clientVersion,username:o,accessKey:s,endpoint:t.BROWSERSTACK_APP_UPLOAD_ENDPOINT??`https://api-cloud.browserstack.com/app-automate/upload`}),webdriverCapabilities:gt({deviceName:l,osVersion:u,app:d,projectName:Q(a,`providerProject`),buildName:Q(a,`providerBuild`)??r.runId,sessionName:Q(a,`providerSessionName`)??r.leaseId,deviceFeatures:st(lt(a.flags),c),configured:P(c,l)})}}}),listArtifactsFromEnv:async(t,n)=>{let r=$(n,`BROWSERSTACK_USERNAME`,`BrowserStack artifact lookup`),i=$(n,`BROWSERSTACK_ACCESS_KEY`,`BrowserStack artifact lookup`);return await H(m.browserStack,t,{clientVersion:e.clientVersion,username:r,accessKey:i,endpoint:n.BROWSERSTACK_SESSION_DETAILS_ENDPOINT})}},{provider:m.awsDeviceFarm,createRuntime:t=>F({clientVersion:e.clientVersion,provider:m.awsDeviceFarm,endpoint:`http://127.0.0.1/`,platform:`android`,deviceName:`AWS Device Farm device`,capabilityOverrides:$e,listArtifacts:async({provider:n,providerSessionId:r})=>await I(n,r,L({runHostCommand:e.runHostCommand,region:t.AWS_REGION??t.AWS_DEFAULT_REGION??G(r??``)})),prepareSession:async({req:n,lease:r,base:i})=>{let a=X(n,`AWS Device Farm`);V(a.flags,m.awsDeviceFarm);let o=Nt(a,`AWS Device Farm`);return await et({client:L({runHostCommand:e.runHostCommand,region:Q(a,`awsRegion`)??t.AWS_REGION??t.AWS_DEFAULT_REGION}),projectArn:Pt(a,t,`awsProjectArn`,`AGENT_DEVICE_AWS_DEVICE_FARM_PROJECT_ARN`,`AWS_DEVICE_FARM_PROJECT_ARN`),deviceArn:Pt(a,t,`awsDeviceArn`,`AGENT_DEVICE_AWS_DEVICE_FARM_DEVICE_ARN`,`AWS_DEVICE_FARM_DEVICE_ARN`),appArn:Q(a,`awsAppArn`)??t.AGENT_DEVICE_AWS_DEVICE_FARM_APP_ARN??t.AWS_DEVICE_FARM_APP_ARN,platform:o,deviceName:Q(a,`device`)??`AWS Device Farm device`,sessionName:Q(a,`providerSessionName`)??r.leaseId,interactionMode:Ft(a)})({lease:r,req:n,base:i})}}),listArtifactsFromEnv:async(t,n)=>{let r=L({runHostCommand:e.runHostCommand,region:n.AWS_REGION??n.AWS_DEFAULT_REGION??G(t)});return await I(m.awsDeviceFarm,t,r)}}]}async function jt(t){if(Mt(t.app))return t.app;let n=h.resolve(t.cwd??process.cwd(),t.app);if(!te.existsSync(n))throw new e(`INVALID_ARGS`,`BrowserStack --provider-app must be a bs:// app id, URL, or existing local app path.`,{providerApp:t.app});return await U(n,{clientVersion:t.clientVersion,username:t.username,accessKey:t.accessKey,endpoint:t.uploadEndpoint},t.signal)}function Mt(e){return e.startsWith(`bs://`)||/^https?:\/\//.test(e)}function X(t,n){if(t)return t;throw new e(`INVALID_ARGS`,`${n} lease allocation requires provider profile flags on the request.`)}function Nt(t,n){let r=t.flags?.platform;if(r===`android`||r===`ios`)return r;throw new e(`INVALID_ARGS`,`${n} requires --platform ios|android.`)}function Z(t,n,r){let i=Q(t,n);if(i)return i;throw new e(`INVALID_ARGS`,r)}function Q(e,t){let n=e.flags?.[t];return typeof n==`string`&&n.length>0?n:void 0}function $(t,n,r){let i=t[n];if(i)return i;throw new e(`INVALID_ARGS`,`${r} requires ${n} in the environment.`)}function Pt(t,n,r,i,a){let o=Q(t,r)??n[i]??n[a];if(o)return o;throw new e(`INVALID_ARGS`,`AWS Device Farm requires --${It(String(r))} or ${a}.`)}function Ft(e){let t=Q(e,`awsInteractionMode`);if(t===`INTERACTIVE`||t===`NO_VIDEO`||t===`VIDEO_ONLY`)return t}function It(e){return e.replaceAll(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}function Lt(e){let t=At(e);return{providerIds:t.map(e=>e.provider),createDefaultRuntimes:(e=process.env)=>t.map(t=>t.createRuntime(e)),listArtifactsFromEnv:async(e,n)=>{if(e.providerSessionId)return await t.find(t=>t.provider===e.provider)?.listArtifactsFromEnv(e.providerSessionId,n)},verifyConnection:async t=>await kt(t,e)}}const Rt=Lt({clientVersion:u(),runHostCommand:async(e,t)=>({stdout:(await l(e,[...t],{maxBuffer:10485760,timeoutMs:3e4})).stdout})});export{G as n,V as r,Rt as t};