rnxsim 0.1.366 → 0.1.368
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -2
- package/cli/bin.ts +18 -0
- package/cli/bridge-flow-runner.ts +14 -151
- package/cli/commands/assert.ts +1 -1
- package/cli/commands/box/checkout-plane.ts +126 -0
- package/cli/commands/box/rnx-command.ts +68 -0
- package/cli/commands/box.ts +200 -0
- package/cli/commands/control.ts +12 -32
- package/cli/commands/do-chain.ts +412 -0
- package/cli/commands/flow.ts +0 -10
- package/cli/commands/inspect/core.ts +302 -725
- package/cli/commands/inspect/describe.ts +3 -76
- package/cli/commands/inspect/find.ts +3 -6
- package/cli/commands/inspect/get-layout.ts +14 -1
- package/cli/commands/inspect/resolve-target.ts +41 -47
- package/cli/commands/inspect/shared.ts +28 -123
- package/cli/commands/inspect/tree.ts +6 -15
- package/cli/commands/inspect/wait-ready.ts +2 -2
- package/cli/commands/inspect/wait-selector.ts +4 -8
- package/cli/commands/inspect.ts +23 -17
- package/cli/commands/install-desktop.ts +44 -7
- package/cli/commands/maestro-generate.ts +0 -2
- package/cli/commands/platform.ts +68 -0
- package/cli/commands/state.ts +5 -2
- package/cli/outbound-endpoints.ts +6 -1
- package/cli/parse-args.ts +13 -2
- package/cli/ws-bridge.ts +30 -2
- package/detox/index.ts +34 -17
- package/dist-cli/bin.js +5 -5
- package/dist-cli/chunks/{agent-SO6IOPRK.js → agent-GXCQMYV4.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-PMYCB2KO.js → agent-wrapper-Y3PQAL6I.js} +2 -2
- package/dist-cli/chunks/{app-fonts-LULQGFY7.js → app-fonts-MDD3W4VN.js} +2 -2
- package/dist-cli/chunks/{assert-WGNCD4ZU.js → assert-BSRQBRH7.js} +3 -3
- package/dist-cli/chunks/{auth-G7CCHH3M.js → auth-SLPHDPCF.js} +2 -2
- package/dist-cli/chunks/{beta-N4LXL5TO.js → beta-R4IZ5SWO.js} +2 -2
- package/dist-cli/chunks/box-2NQYYY3B.js +1709 -0
- package/dist-cli/chunks/{camera-4JHCYBQS.js → camera-ER66WWAX.js} +2 -2
- package/dist-cli/chunks/chunk-2YK5J2D2.js +24 -0
- package/dist-cli/chunks/{chunk-I6KIM6PN.js → chunk-3MPFC3DS.js} +1 -1
- package/dist-cli/chunks/{chunk-77ZHQJZR.js → chunk-3S2J6IVC.js} +2 -2
- package/dist-cli/chunks/chunk-3XMEIZEV.js +4 -0
- package/dist-cli/chunks/chunk-42TLK75A.js +497 -0
- package/dist-cli/chunks/{chunk-OW5XHAA4.js → chunk-4FLQYRGN.js} +1 -1
- package/dist-cli/chunks/{chunk-EFR5DVNP.js → chunk-4VA2ISWX.js} +1 -1
- package/dist-cli/chunks/chunk-57LITN73.js +7 -0
- package/dist-cli/chunks/{chunk-EQK5MJCU.js → chunk-7B22IPSC.js} +2 -2
- package/dist-cli/chunks/{chunk-EGAGZHO6.js → chunk-7V3S2DY2.js} +1 -1
- package/dist-cli/chunks/{chunk-IZKHOM37.js → chunk-AUPJX4KI.js} +1 -1
- package/dist-cli/chunks/{chunk-2S7BKUP2.js → chunk-BWJOLJOK.js} +2 -2
- package/dist-cli/chunks/{chunk-CN6XYYEA.js → chunk-CKNNO6ZG.js} +27 -27
- package/dist-cli/chunks/{chunk-MGDSJZ37.js → chunk-DJSPNOF6.js} +2 -2
- package/dist-cli/chunks/{chunk-YXXKSL6R.js → chunk-E6XYIIJK.js} +1 -1
- package/dist-cli/chunks/{chunk-ONORMKWX.js → chunk-ECXDCED5.js} +2 -2
- package/dist-cli/chunks/chunk-EHA65UVJ.js +5 -0
- package/dist-cli/chunks/chunk-ESVUVW3R.js +32 -0
- package/dist-cli/chunks/{chunk-XJU2QIRY.js → chunk-FDAFSRQE.js} +2 -2
- package/dist-cli/chunks/{chunk-NM2L2QV4.js → chunk-FSPZY4AI.js} +2 -2
- package/dist-cli/chunks/chunk-FVODUDPS.js +4 -0
- package/dist-cli/chunks/{chunk-H23KWIKA.js → chunk-GFWUIGGY.js} +2 -2
- package/dist-cli/chunks/{chunk-CTG7HBCA.js → chunk-GS5VUDCF.js} +1 -1
- package/dist-cli/chunks/{chunk-ORWP2E7R.js → chunk-GXHCJRKE.js} +2 -2
- package/dist-cli/chunks/{chunk-TTASWLKM.js → chunk-HKQXGCQT.js} +1 -1
- package/dist-cli/chunks/{chunk-5OK3LCEJ.js → chunk-IXRVFQMT.js} +2 -2
- package/dist-cli/chunks/{chunk-TIAEYO6I.js → chunk-JFGW75UL.js} +2 -2
- package/dist-cli/chunks/{chunk-RYIMSKDO.js → chunk-JHYXRORU.js} +2 -2
- package/dist-cli/chunks/chunk-LAKWOJ5Y.js +5 -0
- package/dist-cli/chunks/{chunk-GAJQSITE.js → chunk-LPAOOJIW.js} +1 -1
- package/dist-cli/chunks/chunk-M7COA4BE.js +312 -0
- package/dist-cli/chunks/{chunk-6PL2CCGP.js → chunk-MCO7V4VN.js} +2 -2
- package/dist-cli/chunks/{chunk-YGMEDJKJ.js → chunk-MGOAQHMO.js} +2 -2
- package/dist-cli/chunks/chunk-NERY6HGZ.js +4 -0
- package/dist-cli/chunks/chunk-NGWUGNPV.js +4 -0
- package/dist-cli/chunks/{chunk-ZMJ75EDG.js → chunk-NPSPWMBO.js} +2 -2
- package/dist-cli/chunks/{chunk-2UXU53MG.js → chunk-OXCDE3DD.js} +1 -1
- package/dist-cli/chunks/{chunk-ZLVRYXZ7.js → chunk-OZJMWTGA.js} +1 -1
- package/dist-cli/chunks/{chunk-HT6GFZOZ.js → chunk-PNBQBBG5.js} +1 -1
- package/dist-cli/chunks/{chunk-JHXETDVC.js → chunk-Q65KH25G.js} +1 -1
- package/dist-cli/chunks/{chunk-NQFJOCSF.js → chunk-QKOY7UW5.js} +2 -2
- package/dist-cli/chunks/{chunk-5DAIA77C.js → chunk-QMVBWZH2.js} +2 -2
- package/dist-cli/chunks/chunk-RRALQ4WM.js +38 -0
- package/dist-cli/chunks/{chunk-GXAB52K7.js → chunk-SHMLYTNH.js} +2 -2
- package/dist-cli/chunks/chunk-SSUPPM6K.js +130 -0
- package/dist-cli/chunks/chunk-T2MGLXY5.js +27 -0
- package/dist-cli/chunks/{chunk-ZJIS3CTW.js → chunk-T4ZZ26A2.js} +2 -2
- package/dist-cli/chunks/{chunk-YCCCPFWT.js → chunk-TC6DNQL6.js} +2 -2
- package/dist-cli/chunks/chunk-TE645QCO.js +423 -0
- package/dist-cli/chunks/{chunk-UCHW7ZHR.js → chunk-TOE5O6JE.js} +2 -2
- package/dist-cli/chunks/{chunk-N3UC7HIX.js → chunk-TPIPKXJL.js} +1 -1
- package/dist-cli/chunks/chunk-UBH2BWCY.js +4 -0
- package/dist-cli/chunks/{chunk-AFV32WZT.js → chunk-UXROQPIN.js} +3 -3
- package/dist-cli/chunks/{chunk-SA6XVI55.js → chunk-WF2CRNYF.js} +1 -1
- package/dist-cli/chunks/chunk-WFAFAGMG.js +4 -0
- package/dist-cli/chunks/{chunk-A5FXX5PJ.js → chunk-WJQB6AXZ.js} +1 -1
- package/dist-cli/chunks/{chunk-5NMCF5VF.js → chunk-WVVAYLWZ.js} +1 -1
- package/dist-cli/chunks/chunk-WXRDFUR7.js +4 -0
- package/dist-cli/chunks/{chunk-M3BNCF7E.js → chunk-X5MXQB3L.js} +2 -2
- package/dist-cli/chunks/{chunk-LN3RNW6X.js → chunk-YSHJ3LMQ.js} +2 -2
- package/dist-cli/chunks/{chunk-34IQM22N.js → chunk-YYPTSF6W.js} +15 -15
- package/dist-cli/chunks/{cleanup-KRIATKFH.js → cleanup-WHGLBAJ2.js} +2 -2
- package/dist-cli/chunks/cli-version-DMXIXBIM.js +4 -0
- package/dist-cli/chunks/{compat-6PTQ3QEA.js → compat-MGBKGYGQ.js} +2 -2
- package/dist-cli/chunks/{config-ETGDUANO.js → config-TRDOMP4T.js} +2 -2
- package/dist-cli/chunks/connect-N4FV3DDV.js +4 -0
- package/dist-cli/chunks/control-5GRBZVYK.js +4 -0
- package/dist-cli/chunks/daemon-MBT5E3ZC.js +4 -0
- package/dist-cli/chunks/{debug-WIIB6ZKC.js → debug-AHEK43AJ.js} +3 -3
- package/dist-cli/chunks/{desktop-TD7Q5LNB.js → desktop-LDRIXOVV.js} +3 -3
- package/dist-cli/chunks/{detox-7GNR33VM.js → detox-6HAKYISO.js} +2 -2
- package/dist-cli/chunks/{device-QOR3PGUF.js → device-QM3S7OVU.js} +2 -2
- package/dist-cli/chunks/{diagnose-RRCBLP6E.js → diagnose-WDP3CVIX.js} +2 -2
- package/dist-cli/chunks/{disk-cleanup-MJUGJPXT.js → disk-cleanup-JRT5MKFW.js} +2 -2
- package/dist-cli/chunks/do-chain-7FDMO56C.js +5 -0
- package/dist-cli/chunks/drivers-AJL2EVXH.js +4 -0
- package/dist-cli/chunks/env-YIBOMB24.js +4 -0
- package/dist-cli/chunks/{film-D7Y64LID.js → film-R3EQADMG.js} +3 -3
- package/dist-cli/chunks/flow-BDAA6BWL.js +4 -0
- package/dist-cli/chunks/help-5EJD6LJF.js +4 -0
- package/dist-cli/chunks/{hidden-runtime-alias-JGURVR2Z.js → hidden-runtime-alias-6M4UERRQ.js} +2 -2
- package/dist-cli/chunks/{home-paths-4ICFIGXO.js → home-paths-QJNOHZJO.js} +2 -2
- package/dist-cli/chunks/inspect-S3LR3R2A.js +4 -0
- package/dist-cli/chunks/install-desktop-GXE6K7BJ.js +4 -0
- package/dist-cli/chunks/{login-RU33QR2G.js → login-ISWDW4WU.js} +2 -2
- package/dist-cli/chunks/{logout-2IUG3Y5J.js → logout-VNJX2IEW.js} +2 -2
- package/dist-cli/chunks/{maestro-2MXTGG7I.js → maestro-SQS2OS2D.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-2PYIFGLR.js → maestro-generate-GWVPISG5.js} +5 -5
- package/dist-cli/chunks/{mode-3DAPG3HF.js → mode-3URDGBZB.js} +2 -2
- package/dist-cli/chunks/{optional-demo-registry-BWSDJF2Z.js → optional-demo-registry-L3LRBQHG.js} +2 -2
- package/dist-cli/chunks/{perf-2TKPWB4N.js → perf-XLPC4UKR.js} +2 -2
- package/dist-cli/chunks/{permissions-5CSMHYNA.js → permissions-QRHWVMDP.js} +2 -2
- package/dist-cli/chunks/platform-F47URZNB.js +6 -0
- package/dist-cli/chunks/privacy-BF23T67T.js +4 -0
- package/dist-cli/chunks/{record-I2HJCFP3.js → record-2DN3OUE5.js} +3 -3
- package/dist-cli/chunks/{report-issue-A4FZWBOC.js → report-issue-D3BQPSLU.js} +2 -2
- package/dist-cli/chunks/reset-T5CNZ7D3.js +4 -0
- package/dist-cli/chunks/resolve-target-KAAS274S.js +4 -0
- package/dist-cli/chunks/runtime-AQJDBR3X.js +4 -0
- package/dist-cli/chunks/{screenshot-command-UFW5BFHP.js → screenshot-command-RK7IJHVK.js} +3 -3
- package/dist-cli/chunks/{screenshot-layers-5BIAL4YN.js → screenshot-layers-DP2QKSMN.js} +2 -2
- package/dist-cli/chunks/{screenshots-capture-EHYS3BV2.js → screenshots-capture-MA7P3FUT.js} +2 -2
- package/dist-cli/chunks/{serve-O4FDM3AC.js → serve-UBXNGLNP.js} +3 -3
- package/dist-cli/chunks/setup-GH7OW4GC.js +4 -0
- package/dist-cli/chunks/sim-client-VTKFEDJX.js +4 -0
- package/dist-cli/chunks/{skills-ZK55SY32.js → skills-HPK25R4B.js} +2 -2
- package/dist-cli/chunks/state-273XJPUE.js +14 -0
- package/dist-cli/chunks/{storage-WP33ISEM.js → storage-RTDFWIY7.js} +2 -2
- package/dist-cli/chunks/store-DLKNNM4L.js +4 -0
- package/dist-cli/chunks/telemetry-7CWDXEOO.js +4 -0
- package/dist-cli/chunks/{timeline-DKGW5S4I.js → timeline-IF2PGK7C.js} +2 -2
- package/dist-cli/chunks/{upgrade-LL7G4B7G.js → upgrade-R74NVHKG.js} +2 -2
- package/dist-cli/chunks/upload-3JFFVCZ4.js +4 -0
- package/dist-cli/chunks/{version-YLWR5G4F.js → version-RTFCYQZ7.js} +2 -2
- package/dist-cli/chunks/{web-QELZ4CP6.js → web-35SSKBRU.js} +2 -2
- package/dist-cli/chunks/welcome-N5V352SE.js +5 -0
- package/dist-cli/chunks/{what-happened-MIOMZWM5.js → what-happened-WXTP6EPR.js} +2 -2
- package/dist-cli/chunks/ws-bridge-JXQUAWFA.js +4 -0
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +336 -0
- package/dist-lib/bridge-contract-input.mjs +303 -0
- package/dist-lib/bridge-contract.cjs +29 -1
- package/dist-lib/bridge-contract.mjs +19 -0
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +32 -18
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +5 -1
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +214 -594
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +273 -657
- package/dist-lib/sdk.mjs +271 -652
- package/dist-lib/skills.cjs +190 -287
- package/dist-lib/vite.cjs +1 -1
- package/package.json +9 -6
- package/skills/contrast/SKILL.md +3 -0
- package/skills/rnx-debug/SKILL.md +8 -0
- package/skills/rnx-test/SKILL.md +21 -0
- package/src/bridge-contract-input.ts +359 -0
- package/src/bridge-contract.ts +121 -1
- package/src/host/bridge-host.ts +7 -12
- package/src/index.ts +7 -0
- package/src/sim-client.ts +12 -3
- package/dist-cli/chunks/chunk-3X6IBUBX.js +0 -38
- package/dist-cli/chunks/chunk-7B37IZBN.js +0 -15
- package/dist-cli/chunks/chunk-DMPF2D24.js +0 -4
- package/dist-cli/chunks/chunk-DW37EVX5.js +0 -767
- package/dist-cli/chunks/chunk-DWFIH7CB.js +0 -32
- package/dist-cli/chunks/chunk-GUI3PDH2.js +0 -27
- package/dist-cli/chunks/chunk-KLF3K6ZZ.js +0 -4
- package/dist-cli/chunks/chunk-M5QCGLXR.js +0 -944
- package/dist-cli/chunks/chunk-M6SKQGAN.js +0 -5
- package/dist-cli/chunks/chunk-NAYLPOC5.js +0 -24
- package/dist-cli/chunks/chunk-VIND4SP3.js +0 -124
- package/dist-cli/chunks/chunk-XXNLYR64.js +0 -5
- package/dist-cli/chunks/chunk-ZFM24DOX.js +0 -4
- package/dist-cli/chunks/cli-version-SYGNHGFR.js +0 -4
- package/dist-cli/chunks/control-RBTNOLQM.js +0 -4
- package/dist-cli/chunks/daemon-N3SC5DK6.js +0 -4
- package/dist-cli/chunks/drivers-W6E3BZH4.js +0 -4
- package/dist-cli/chunks/flow-7QAE2V5Y.js +0 -4
- package/dist-cli/chunks/help-NLD6KWVG.js +0 -4
- package/dist-cli/chunks/inspect-C347BG52.js +0 -4
- package/dist-cli/chunks/install-desktop-YR6TWZYK.js +0 -4
- package/dist-cli/chunks/privacy-PWWC2BXO.js +0 -4
- package/dist-cli/chunks/reset-Y3PBPFYA.js +0 -4
- package/dist-cli/chunks/runtime-IC6NVVGA.js +0 -4
- package/dist-cli/chunks/setup-Y4QGSJBM.js +0 -4
- package/dist-cli/chunks/state-KFLAZNEY.js +0 -14
- package/dist-cli/chunks/store-VEE22CAY.js +0 -4
- package/dist-cli/chunks/telemetry-PZV4BISJ.js +0 -4
- package/dist-cli/chunks/upload-Y4C3YZDK.js +0 -4
- package/dist-cli/chunks/welcome-ZPKA5PZJ.js +0 -5
- package/dist-lib/mcp.cjs +0 -673
- package/dist-lib/mcp.mjs +0 -641
- package/src/mcp.ts +0 -791
|
@@ -1,767 +0,0 @@
|
|
|
1
|
-
/*! rnx v0.1.366 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import { createRequire as __sootsimCreateRequire } from 'node:module'
|
|
3
|
-
var require = __sootsimCreateRequire(import.meta.url)
|
|
4
|
-
function Q(t,e){let r=["--max-ms","--maxMs","--maxms","--max_ms"];for(let n of r){let o=t.indexOf(n);if(o>=0&&t[o+1]){let s=Number(t[o+1]);if(Number.isFinite(s))return Math.max(100,s)}}return e}var P=new Set(["tap","double-tap","tap-text","tap-id","long-press","touch"]);function N(t){return typeof t=="string"&&P.has(t)}async function M(t){return await t.send({type:"evaluate",code:"window.__sootsimEngineState?.inspectActive === true"})===!0}async function X(t,e){if(!N(e))return!1;try{return await M(t)}catch{return!1}}async function Z(t){let e=await t.send({type:"evaluate",code:"(async () => await window.__sootsimTest.getNodeCount())()"});return{nodes:typeof e=="number"?e:0}}async function ee(t,e=5,r){let n=r?.format?`, ${JSON.stringify(r)}`:"",o=await t.send({type:"evaluate",code:`(async () => await window.__sootsimTest.dumpTree(${e}${n}))()`});if(r?.format==="boxes"&&typeof o=="string")try{return{depth:e,tree:JSON.parse(o)}}catch{return{depth:e,tree:o}}return{depth:e,tree:o}}async function te(t){let e=await t.send({type:"evaluate",code:"window.location.href"});return{url:typeof e=="string"?e:""}}async function ne(t,e){let r=e.maxDepth??12,n=`(async () => {
|
|
5
|
-
const t = window.__sootsimTest
|
|
6
|
-
const mainShell = window.SootSim?.bridges?.mainShell
|
|
7
|
-
const kb = window.__sootsimKeyboard
|
|
8
|
-
if (!t) return { error: 'no test bridge' }
|
|
9
|
-
|
|
10
|
-
let shell = null
|
|
11
|
-
try {
|
|
12
|
-
shell = typeof mainShell?.getState === 'function' ? await mainShell.getState() : null
|
|
13
|
-
} catch {}
|
|
14
|
-
|
|
15
|
-
const opts = ${JSON.stringify(e)}
|
|
16
|
-
const needsRecursiveDump =
|
|
17
|
-
opts.verbose || opts.subtreeRoot || opts.includeOccluded || opts.maxDepth != null
|
|
18
|
-
const globToRegex = (glob) => {
|
|
19
|
-
const escaped = String(glob).replace(/[.+^$(){}|[\\]\\\\]/g, '\\\\$&')
|
|
20
|
-
const body = escaped.replace(/\\*/g, '.*').replace(/\\?/g, '.')
|
|
21
|
-
return new RegExp('^' + body + '$', 'i')
|
|
22
|
-
}
|
|
23
|
-
// clipping a describe line is a DISPLAY decision. opts.fullText (set by
|
|
24
|
-
// \`describe --json\`) keeps the real string, so a bundle-eval stack or a
|
|
25
|
-
// red-box message reaches the caller whole instead of ending in an
|
|
26
|
-
// ellipsis nothing downstream can undo.
|
|
27
|
-
const clipForDisplay = (value, max) => {
|
|
28
|
-
const text = typeof value === 'string' ? value.replace(/\\s+/g, ' ').trim() : ''
|
|
29
|
-
if (opts.fullText || text.length <= max) return text
|
|
30
|
-
return text.slice(0, max - 1).trimEnd() + '\u2026'
|
|
31
|
-
}
|
|
32
|
-
const formatInspectableTree = async () => {
|
|
33
|
-
if (typeof t.listInspectable !== 'function') return null
|
|
34
|
-
const list = await t.listInspectable({})
|
|
35
|
-
if (!Array.isArray(list)) return null
|
|
36
|
-
const filter = typeof opts.filter === 'string' ? opts.filter.toLowerCase() : ''
|
|
37
|
-
const testIdRegex = opts.testIdLike ? globToRegex(opts.testIdLike) : null
|
|
38
|
-
const onlyRegex = opts.onlyGlob ? globToRegex(opts.onlyGlob) : null
|
|
39
|
-
const lines = []
|
|
40
|
-
let matched = 0
|
|
41
|
-
for (const node of list) {
|
|
42
|
-
const testID = node?.testID || node?.testId || ''
|
|
43
|
-
const role = node?.role || ''
|
|
44
|
-
const label = node?.accessibilityLabel || node?.label || ''
|
|
45
|
-
const text = node?.text || ''
|
|
46
|
-
if (testIdRegex && !testIdRegex.test(testID)) continue
|
|
47
|
-
const joined = [role, label, text, testID].filter(Boolean).join(' ')
|
|
48
|
-
if (onlyRegex && !onlyRegex.test(joined)) continue
|
|
49
|
-
if (filter && !joined.toLowerCase().includes(filter)) continue
|
|
50
|
-
matched++
|
|
51
|
-
|
|
52
|
-
const type = String(node?.type || 'node').toLowerCase()
|
|
53
|
-
const handlers = Array.isArray(node?.handlers) ? node.handlers : []
|
|
54
|
-
const parts = []
|
|
55
|
-
if (role) parts.push('[' + role + ']')
|
|
56
|
-
else if (handlers.length > 0) parts.push('[tap]')
|
|
57
|
-
else parts.push('<' + type + '>')
|
|
58
|
-
const visibleText = clipForDisplay(text, 50)
|
|
59
|
-
if (visibleText) parts.push(JSON.stringify(visibleText))
|
|
60
|
-
if (testID) parts.push('#' + testID)
|
|
61
|
-
if (label && label !== text) {
|
|
62
|
-
parts.push('label=' + JSON.stringify(clipForDisplay(label, 50)))
|
|
63
|
-
}
|
|
64
|
-
if (!opts.hideXy) {
|
|
65
|
-
const abs = node?.absolute || {}
|
|
66
|
-
const layout = node?.layout || {}
|
|
67
|
-
const x = Math.round(Number(abs.x) || 0)
|
|
68
|
-
const y = Math.round(Number(abs.y) || 0)
|
|
69
|
-
const w = Math.round(Number(layout.width) || 0)
|
|
70
|
-
const h = Math.round(Number(layout.height) || 0)
|
|
71
|
-
parts.push('@(' + x + ',' + y + ') ' + w + 'x' + h)
|
|
72
|
-
}
|
|
73
|
-
if (handlers.length > 0) parts.push('(tap)')
|
|
74
|
-
lines.push(' ' + parts.join(' '))
|
|
75
|
-
}
|
|
76
|
-
return { tree: lines.join('\\n'), matched }
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
let tree = ''
|
|
80
|
-
const compactResult = needsRecursiveDump ? null : await formatInspectableTree()
|
|
81
|
-
if (compactResult) {
|
|
82
|
-
tree = compactResult.tree
|
|
83
|
-
} else {
|
|
84
|
-
tree = await t.dumpTree(${r}, opts)
|
|
85
|
-
}
|
|
86
|
-
const nodeCount = (await t.getNodeCount?.()) || 0
|
|
87
|
-
const keyboard = kb && typeof kb.getLayout === 'function' ? kb.getLayout() : null
|
|
88
|
-
return { tree, shell, nodeCount, keyboard }
|
|
89
|
-
})()`;return await t.send({type:"evaluate",code:n})??{}}function D(t){let e=t.fontSize>=18||t.fontSize>=14&&(t.fontWeight??400)>=700?3:4.5,{normal:r,background:n}=t;if(r.width<=0||r.height<=0||r.width!==n.width||r.height!==n.height)return{ratio:null,required:e,reason:"capture dimensions do not match"};let o=Math.max(0,Math.floor(t.box.x)),s=Math.max(0,Math.floor(t.box.y)),i=Math.min(r.width,Math.ceil(t.box.x+t.box.w)),d=Math.min(r.height,Math.ceil(t.box.y+t.box.h));if(i<=o||d<=s)return{ratio:null,required:e,reason:"text is outside the captured frame"};let p=l=>{let u=l/255;return u<=.04045?u/12.92:Math.pow((u+.055)/1.055,2.4)},g=(l,u)=>{let c=.2126*p(l[0])+.7152*p(l[1])+.0722*p(l[2]),v=.2126*p(u[0])+.7152*p(u[1])+.0722*p(u[2]);return(Math.max(c,v)+.05)/(Math.min(c,v)+.05)},a=l=>`#${l.slice(0,3).map(u=>Math.round(u).toString(16).padStart(2,"0")).join("")}`,h=(i-o)*(d-s),y=Math.max(1,Math.floor(Math.sqrt(h/12e3))),b=(l,u)=>(u*r.width+l)*4,x=l=>Math.max(Math.abs(r.data[l]-n.data[l]),Math.abs(r.data[l+1]-n.data[l+1]),Math.abs(r.data[l+2]-n.data[l+2])),f=0,m=null,w=null;for(let l=s;l<d;l+=y)for(let u=o;u<i;u+=y){let c=b(u,l);if(n.data[c+3]<250)continue;let v=[n.data[c],n.data[c+1],n.data[c+2]];w??=v;let E=x(c);E<=f||(f=E,m=[r.data[c],r.data[c+1],r.data[c+2]])}let S=1/0,I=null,T=null,k=(l,u)=>{let c=g(l,u);c>=S||(S=c,I=l,T=u)};if(f>=2&&m)for(let l=s;l<d;l+=y)for(let u=o;u<i;u+=y){let c=b(u,l);n.data[c+3]<250||x(c)<2||k(m,[n.data[c],n.data[c+1],n.data[c+2]])}else w&&k(w,w);return!I||!T||!Number.isFinite(S)?{ratio:null,required:e,reason:"could not isolate opaque rendered text pixels"}:{ratio:Math.round(S*100)/100,required:e,foreground:a(I),background:a(T)}}function A(t={}){let e=t.styling===!0,r=t.filter?.trim().toLowerCase()??"";return`(async () => {
|
|
90
|
-
const t = window.__sootsimTest
|
|
91
|
-
if (!t || typeof t.listInspectable !== 'function') return []
|
|
92
|
-
const list = await t.listInspectable({})
|
|
93
|
-
if (!Array.isArray(list)) return []
|
|
94
|
-
const includeStyle = ${JSON.stringify(e)}
|
|
95
|
-
const scoreContrast = ${D.toString()}
|
|
96
|
-
// narrows by ELEMENT, not by style field: fewer rows, full detail on each.
|
|
97
|
-
const filter = ${JSON.stringify(r)}
|
|
98
|
-
const matchesFilter = (n, text) => {
|
|
99
|
-
if (!filter) return true
|
|
100
|
-
const fields = [text, n.testID || n.testId, n.accessibilityRole || n.role, n.type]
|
|
101
|
-
return fields.some((f) => typeof f === 'string' && f.toLowerCase().includes(filter))
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0)
|
|
105
|
-
const round = (v) => Math.round(num(v))
|
|
106
|
-
|
|
107
|
-
// borderRadius can be authored as a string ("12px") or split per-corner;
|
|
108
|
-
// prefer the uniform borderRadius, else the largest corner radius present.
|
|
109
|
-
const radiusOf = (style) => {
|
|
110
|
-
if (!style) return 0
|
|
111
|
-
const keys = ['borderRadius','borderTopLeftRadius','borderTopRightRadius','borderBottomLeftRadius','borderBottomRightRadius']
|
|
112
|
-
let max = 0
|
|
113
|
-
for (const k of keys) {
|
|
114
|
-
const raw = style[k]
|
|
115
|
-
const n = typeof raw === 'number' ? raw : (typeof raw === 'string' ? parseFloat(raw) : NaN)
|
|
116
|
-
if (Number.isFinite(n)) max = Math.max(max, n)
|
|
117
|
-
}
|
|
118
|
-
return Math.round(max)
|
|
119
|
-
}
|
|
120
|
-
const fontSizeOf = (style) => {
|
|
121
|
-
if (!style) return 0
|
|
122
|
-
const raw = style.fontSize
|
|
123
|
-
const n = typeof raw === 'number' ? raw : (typeof raw === 'string' ? parseFloat(raw) : NaN)
|
|
124
|
-
return Number.isFinite(n) ? Math.round(n) : 0
|
|
125
|
-
}
|
|
126
|
-
// styling extractors \u2014 omit boring defaults so the agent only sees notable
|
|
127
|
-
// styling (low opacity, struck text, clipping, a real border/color).
|
|
128
|
-
const colorStr = (v) => {
|
|
129
|
-
if (v == null) return undefined
|
|
130
|
-
const s = String(v).split(' ').join('')
|
|
131
|
-
return s && s !== 'transparent' && s !== 'rgba(0,0,0,0)' ? s : undefined
|
|
132
|
-
}
|
|
133
|
-
const opacityOf = (style) => {
|
|
134
|
-
const o = style && style.opacity
|
|
135
|
-
const n = typeof o === 'number' ? o : (typeof o === 'string' ? parseFloat(o) : NaN)
|
|
136
|
-
return Number.isFinite(n) && n < 1 ? Math.round(n * 100) / 100 : undefined
|
|
137
|
-
}
|
|
138
|
-
const weightOf = (style) => {
|
|
139
|
-
const w = style && style.fontWeight
|
|
140
|
-
const n = w === 'bold' ? 700 : (typeof w === 'number' ? w : (typeof w === 'string' ? parseInt(w, 10) : NaN))
|
|
141
|
-
return Number.isFinite(n) && n >= 600 ? n : undefined
|
|
142
|
-
}
|
|
143
|
-
const decoOf = (style) => {
|
|
144
|
-
const d = style && (style.textDecorationLine || style.textDecoration)
|
|
145
|
-
return d && d !== 'none' && d !== 'normal' ? String(d).split(' ')[0] : undefined
|
|
146
|
-
}
|
|
147
|
-
const overflowOf = (style) => (style && style.overflow === 'hidden' ? 'hidden' : undefined)
|
|
148
|
-
const borderWOf = (style) => {
|
|
149
|
-
if (!style) return undefined
|
|
150
|
-
const keys = ['borderWidth','borderTopWidth','borderBottomWidth','borderLeftWidth','borderRightWidth']
|
|
151
|
-
let max = 0
|
|
152
|
-
for (const k of keys) {
|
|
153
|
-
const r = style[k]
|
|
154
|
-
const n = typeof r === 'number' ? r : (typeof r === 'string' ? parseFloat(r) : NaN)
|
|
155
|
-
if (Number.isFinite(n)) max = Math.max(max, n)
|
|
156
|
-
}
|
|
157
|
-
return max > 0 ? Math.round(max) : undefined
|
|
158
|
-
}
|
|
159
|
-
// only meaningful alongside a real border width, so it is resolved by the
|
|
160
|
-
// caller below rather than on its own.
|
|
161
|
-
const borderColorOf = (style) => {
|
|
162
|
-
if (!style) return undefined
|
|
163
|
-
const keys = ['borderColor','borderTopColor','borderBottomColor','borderLeftColor','borderRightColor']
|
|
164
|
-
for (const k of keys) {
|
|
165
|
-
const c = colorStr(style[k])
|
|
166
|
-
if (c) return c
|
|
167
|
-
}
|
|
168
|
-
return undefined
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const isVisible = (n) => {
|
|
172
|
-
const layout = n && n.layout
|
|
173
|
-
if (!layout || layout.width <= 0 || layout.height <= 0) return false
|
|
174
|
-
const abs = (n && (n.absolute || n.absolutePosition)) || null
|
|
175
|
-
if (!abs) return true
|
|
176
|
-
const device = (n && n.device) || {}
|
|
177
|
-
const screenW = Number(device.width) || window.innerWidth || 0
|
|
178
|
-
const screenH = Number(device.height) || window.innerHeight || 0
|
|
179
|
-
if (!screenW || !screenH) return true
|
|
180
|
-
return abs.x + layout.width > 0 && abs.y + layout.height > 0 && abs.x < screenW && abs.y < screenH
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const elements = list.filter(isVisible).filter((n) => {
|
|
184
|
-
const t = typeof n.text === 'string' && n.text.trim() ? n.text.trim() : undefined
|
|
185
|
-
return matchesFilter(n, t)
|
|
186
|
-
}).map((n) => {
|
|
187
|
-
const layout = n.layout || { x: 0, y: 0, width: 0, height: 0 }
|
|
188
|
-
const abs = n.absolute || n.absolutePosition || { x: layout.x, y: layout.y }
|
|
189
|
-
const text = typeof n.text === 'string' && n.text.trim() ? n.text.trim() : undefined
|
|
190
|
-
const base = {
|
|
191
|
-
...(typeof n.nodeId === 'number'
|
|
192
|
-
? {
|
|
193
|
-
nodeId: n.nodeId,
|
|
194
|
-
ancestorIds: Array.isArray(n.ancestors)
|
|
195
|
-
? n.ancestors.map((ancestor) => ancestor && ancestor.nodeId).filter((id) => typeof id === 'number')
|
|
196
|
-
: [],
|
|
197
|
-
}
|
|
198
|
-
: {}),
|
|
199
|
-
testID: n.testID || n.testId || undefined,
|
|
200
|
-
role: n.accessibilityRole || n.role || undefined,
|
|
201
|
-
type: typeof n.type === 'string' ? n.type : 'node',
|
|
202
|
-
text,
|
|
203
|
-
box: { x: round(abs.x), y: round(abs.y), w: round(layout.width), h: round(layout.height) },
|
|
204
|
-
borderRadius: 0,
|
|
205
|
-
padding: { t: 0, r: 0, b: 0, l: 0 },
|
|
206
|
-
fontSize: 0,
|
|
207
|
-
}
|
|
208
|
-
if (!includeStyle) return base
|
|
209
|
-
// computedStyle has the resolved values; style is the curated subset \u2014
|
|
210
|
-
// fall back across both so radius/fontSize survive either shape.
|
|
211
|
-
const style = Object.assign({}, n.style || {}, n.computedStyle || {})
|
|
212
|
-
const pad = (n.boxModel && n.boxModel.padding) || {}
|
|
213
|
-
const borderWidth = borderWOf(style)
|
|
214
|
-
return {
|
|
215
|
-
...base,
|
|
216
|
-
borderRadius: radiusOf(style),
|
|
217
|
-
padding: { t: round(pad.top), r: round(pad.right), b: round(pad.bottom), l: round(pad.left) },
|
|
218
|
-
fontSize: text ? (fontSizeOf(style) || 14) : 0,
|
|
219
|
-
color: text ? colorStr(style.color) : undefined,
|
|
220
|
-
bg: colorStr(style.backgroundColor),
|
|
221
|
-
opacity: opacityOf(style),
|
|
222
|
-
fontWeight: weightOf(style),
|
|
223
|
-
textDecoration: decoOf(style),
|
|
224
|
-
overflow: overflowOf(style),
|
|
225
|
-
borderWidth,
|
|
226
|
-
borderColor: borderWidth ? borderColorOf(style) : undefined,
|
|
227
|
-
}
|
|
228
|
-
})
|
|
229
|
-
const textElements = elements.filter((element) => element.text && element.fontSize > 0)
|
|
230
|
-
if (!includeStyle || textElements.length === 0) return elements
|
|
231
|
-
|
|
232
|
-
const screenshot = window.SootSim && window.SootSim.bridges && window.SootSim.bridges.screenshot
|
|
233
|
-
if (typeof screenshot !== 'function') {
|
|
234
|
-
throw new Error('styled native layout requires the rnx capture bridge')
|
|
235
|
-
}
|
|
236
|
-
const device = list.find((node) => node && node.device)?.device || {}
|
|
237
|
-
const width = Math.round(Number(device.width) || window.innerWidth || 0)
|
|
238
|
-
const height = Math.round(Number(device.height) || window.innerHeight || 0)
|
|
239
|
-
if (!width || !height) throw new Error('native layout has no capture dimensions')
|
|
240
|
-
const capture = async (suppressText) => {
|
|
241
|
-
const dataUrl = await screenshot({
|
|
242
|
-
format: 'png',
|
|
243
|
-
outputWidth: width,
|
|
244
|
-
outputHeight: height,
|
|
245
|
-
...(suppressText ? { suppressText: true } : {}),
|
|
246
|
-
})
|
|
247
|
-
const image = await new Promise((resolve, reject) => {
|
|
248
|
-
const next = new Image()
|
|
249
|
-
next.onload = () => resolve(next)
|
|
250
|
-
next.onerror = () => reject(new Error('could not decode native layout pixels'))
|
|
251
|
-
next.src = dataUrl
|
|
252
|
-
})
|
|
253
|
-
const canvas = document.createElement('canvas')
|
|
254
|
-
canvas.width = image.naturalWidth
|
|
255
|
-
canvas.height = image.naturalHeight
|
|
256
|
-
const context = canvas.getContext('2d', { willReadFrequently: true })
|
|
257
|
-
if (!context) throw new Error('could not read native layout pixels')
|
|
258
|
-
context.drawImage(image, 0, 0)
|
|
259
|
-
return context.getImageData(0, 0, canvas.width, canvas.height)
|
|
260
|
-
}
|
|
261
|
-
const normal = await capture(false)
|
|
262
|
-
const background = await capture(true)
|
|
263
|
-
for (const element of textElements) {
|
|
264
|
-
element.contrast = scoreContrast({
|
|
265
|
-
normal,
|
|
266
|
-
background,
|
|
267
|
-
box: element.box,
|
|
268
|
-
fontSize: element.fontSize,
|
|
269
|
-
fontWeight: element.fontWeight,
|
|
270
|
-
})
|
|
271
|
-
}
|
|
272
|
-
return elements
|
|
273
|
-
})()`}var re=A();async function oe(t,e={}){let r=await t.send({type:"evaluate",code:A(e)});return Array.isArray(r)?r:[]}function se(t,e){return t.length===0?" no visible elements found":t.map(n=>{let s=[n.testID?`#${n.testID}`:n.selector?n.selector:n.role?`[${n.role}]`:`<${n.type}>`,`@(${n.box.x},${n.box.y})`,`${n.box.w}x${n.box.h}`];n.borderRadius>0&&s.push(`radius:${n.borderRadius}`);let i=n.padding;if(i.t||i.r||i.b||i.l){let d=i.t===i.r&&i.r===i.b&&i.b===i.l;s.push(d?`pad:${i.t}`:`pad:${i.t},${i.r},${i.b},${i.l}`)}if(n.fontSize>0&&s.push(`font:${n.fontSize}`),e?.styling){if(n.fontWeight&&s.push(`weight:${n.fontWeight}`),n.color&&s.push(`color:${n.color}`),n.bg&&s.push(`bg:${n.bg}`),n.contrast){let d=n.contrast.ratio==null?`?/${n.contrast.required}`:`${n.contrast.ratio}/${n.contrast.required}${n.contrast.ratio<n.contrast.required?" FAIL":""}`;s.push(`contrast:${d}`),n.contrast.background&&s.push(`on:${n.contrast.background}`)}n.opacity!=null&&s.push(`opacity:${n.opacity}`),n.textDecoration&&s.push(`deco:${n.textDecoration}`),n.overflow&&s.push(`overflow:${n.overflow}`),n.borderWidth&&s.push(n.borderColor?`border:${n.borderWidth}/${n.borderColor}`:`border:${n.borderWidth}`)}if(n.text){let d=n.text.length>40?`${n.text.slice(0,39)}\u2026`:n.text;s.push(`"${d}"`)}return` ${s.join(" ")}`}).join(`
|
|
274
|
-
`)}var C=`(async () => {
|
|
275
|
-
const t = window.__sootsimTest
|
|
276
|
-
if (!t) return []
|
|
277
|
-
|
|
278
|
-
const readLayout = (n) => n?.layout || null
|
|
279
|
-
const readAbs = (n) => n?.absolutePosition || n?.absolute || null
|
|
280
|
-
const readRole = (n) => n?.accessibilityRole || n?.role || null
|
|
281
|
-
const readLabel = (n) => n?.accessibilityLabel || n?.label || n?.text || null
|
|
282
|
-
const readHint = (n) => n?.accessibilityHint || n?.hint || null
|
|
283
|
-
const readState = (n) => n?.accessibilityState || n?.state || null
|
|
284
|
-
const readTestId = (n) => n?.testID || n?.testId || null
|
|
285
|
-
const readType = (n) => typeof n?.type === 'string' ? n.type.toLowerCase() : n?.type
|
|
286
|
-
const readPressable = (n) => {
|
|
287
|
-
if (n?.pressable) return true
|
|
288
|
-
const handlers = Array.isArray(n?.handlers) ? n.handlers : []
|
|
289
|
-
const role = readRole(n)
|
|
290
|
-
return handlers.length > 0 || role === 'button' || role === 'link' || role === 'tab'
|
|
291
|
-
}
|
|
292
|
-
const isTextInput = (n) => n?.isTextInput === true
|
|
293
|
-
const isTextNode = (n) => readType(n) === 'text'
|
|
294
|
-
const isVisibleTarget = (n) => {
|
|
295
|
-
const layout = readLayout(n)
|
|
296
|
-
if (!layout || layout.width <= 0 || layout.height <= 0) return false
|
|
297
|
-
const abs = readAbs(n)
|
|
298
|
-
if (!abs) return true
|
|
299
|
-
const device = n?.device || {}
|
|
300
|
-
const screenW = Number(device.width) || window.innerWidth || 0
|
|
301
|
-
const screenH = Number(device.height) || window.innerHeight || 0
|
|
302
|
-
return (
|
|
303
|
-
abs.x + layout.width > 0 &&
|
|
304
|
-
abs.y + layout.height > 0 &&
|
|
305
|
-
abs.x < screenW &&
|
|
306
|
-
abs.y < screenH
|
|
307
|
-
)
|
|
308
|
-
}
|
|
309
|
-
const hasAccessibleSignal = (n) => {
|
|
310
|
-
const role = readRole(n)
|
|
311
|
-
const label = readLabel(n)
|
|
312
|
-
const hint = readHint(n)
|
|
313
|
-
if (role) return true
|
|
314
|
-
if (hint) return true
|
|
315
|
-
if (isTextInput(n)) return true
|
|
316
|
-
if (readPressable(n)) return true
|
|
317
|
-
if (isTextNode(n) && n?.text) return true
|
|
318
|
-
if (typeof label === 'string' && label.length <= 30 && label !== n?.text) return true
|
|
319
|
-
return false
|
|
320
|
-
}
|
|
321
|
-
const normalize = (n) => {
|
|
322
|
-
const layout = readLayout(n)
|
|
323
|
-
const abs = readAbs(n)
|
|
324
|
-
const role = readRole(n) || (readPressable(n) ? 'button' : isTextInput(n) ? 'textfield' : isTextNode(n) ? 'statictext' : 'none')
|
|
325
|
-
return {
|
|
326
|
-
role,
|
|
327
|
-
label: readLabel(n),
|
|
328
|
-
hint: readHint(n),
|
|
329
|
-
state: readState(n),
|
|
330
|
-
testID: readTestId(n),
|
|
331
|
-
position: abs ? { x: Math.round(abs.x), y: Math.round(abs.y) } : null,
|
|
332
|
-
size: layout ? { w: Math.round(layout.width), h: Math.round(layout.height) } : null,
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
if (typeof t.listInspectable === 'function') {
|
|
337
|
-
const list = await t.listInspectable({})
|
|
338
|
-
if (Array.isArray(list)) {
|
|
339
|
-
return list.filter(n => isVisibleTarget(n) && hasAccessibleSignal(n)).map(normalize)
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
const all = await t.queryAll({ pruneHidden: true })
|
|
344
|
-
return all
|
|
345
|
-
.filter(n => isVisibleTarget(n) && hasAccessibleSignal(n))
|
|
346
|
-
.map(normalize)
|
|
347
|
-
})()`;async function ae(t){let e=await t.send({type:"evaluate",code:C});return Array.isArray(e)?e:[]}var R=`
|
|
348
|
-
const fromInspectable = async () => {
|
|
349
|
-
if (typeof t.listInspectable !== 'function') return null
|
|
350
|
-
const list = await t.listInspectable({})
|
|
351
|
-
if (!Array.isArray(list)) return null
|
|
352
|
-
return list.map((n) => {
|
|
353
|
-
const role = n.accessibilityRole ?? n.role
|
|
354
|
-
const label = n.accessibilityLabel ?? n.label
|
|
355
|
-
const layout = n.layout
|
|
356
|
-
const absolutePosition = n.absolutePosition ?? n.absolute
|
|
357
|
-
const screenW = Number(n.device?.width) || window.innerWidth || 0
|
|
358
|
-
const screenH = Number(n.device?.height) || window.innerHeight || 0
|
|
359
|
-
const visibleFrame = layout && absolutePosition
|
|
360
|
-
? {
|
|
361
|
-
x: Math.max(0, absolutePosition.x),
|
|
362
|
-
y: Math.max(0, absolutePosition.y),
|
|
363
|
-
width: Math.max(
|
|
364
|
-
0,
|
|
365
|
-
Math.min(screenW, absolutePosition.x + layout.width) -
|
|
366
|
-
Math.max(0, absolutePosition.x),
|
|
367
|
-
),
|
|
368
|
-
height: Math.max(
|
|
369
|
-
0,
|
|
370
|
-
Math.min(screenH, absolutePosition.y + layout.height) -
|
|
371
|
-
Math.max(0, absolutePosition.y),
|
|
372
|
-
),
|
|
373
|
-
}
|
|
374
|
-
: null
|
|
375
|
-
const handlers = Array.isArray(n.handlers) ? n.handlers : []
|
|
376
|
-
const pressable =
|
|
377
|
-
handlers.length > 0 ||
|
|
378
|
-
role === 'button' ||
|
|
379
|
-
role === 'link' ||
|
|
380
|
-
role === 'tab'
|
|
381
|
-
return {
|
|
382
|
-
type: typeof n.type === 'string' ? n.type.toLowerCase() : n.type,
|
|
383
|
-
id: n.id ?? n.nodeId,
|
|
384
|
-
nodeId: n.nodeId,
|
|
385
|
-
testID: n.testID ?? n.testId,
|
|
386
|
-
text: n.text,
|
|
387
|
-
layout,
|
|
388
|
-
absolutePosition,
|
|
389
|
-
visibleFrame,
|
|
390
|
-
style: n.computedStyle ?? n.style ?? {},
|
|
391
|
-
childCount: n.childCount ?? 0,
|
|
392
|
-
pressed: n.pressed ?? false,
|
|
393
|
-
pressable,
|
|
394
|
-
isTextInput: n.isTextInput ?? false,
|
|
395
|
-
accessible: n.accessible ?? true,
|
|
396
|
-
accessibilityLabel: label,
|
|
397
|
-
accessibilityRole: role,
|
|
398
|
-
accessibilityHint: n.accessibilityHint,
|
|
399
|
-
accessibilityState: n.accessibilityState,
|
|
400
|
-
accessibilityValue: n.accessibilityValue,
|
|
401
|
-
}
|
|
402
|
-
})
|
|
403
|
-
}
|
|
404
|
-
const isVisibleTarget = (n) => {
|
|
405
|
-
if (!n?.layout) return false
|
|
406
|
-
const frame = n.visibleFrame
|
|
407
|
-
if (frame) return frame.width > 0 && frame.height > 0
|
|
408
|
-
const abs = n.absolutePosition
|
|
409
|
-
if (!abs) return n.layout.width > 0 && n.layout.height > 0
|
|
410
|
-
const screenW = window.innerWidth || 0
|
|
411
|
-
const screenH = window.innerHeight || 0
|
|
412
|
-
return (
|
|
413
|
-
abs.x + n.layout.width > 0 &&
|
|
414
|
-
abs.y + n.layout.height > 0 &&
|
|
415
|
-
abs.x < screenW &&
|
|
416
|
-
abs.y < screenH
|
|
417
|
-
)
|
|
418
|
-
}
|
|
419
|
-
`;function O(t){return t.testId?{mode:"testid",code:`(async () => {
|
|
420
|
-
const t = window.__sootsimTest
|
|
421
|
-
if (!t) return null
|
|
422
|
-
return (await t.findByTestId(${JSON.stringify(t.testId)})) || (await t.findById(${JSON.stringify(t.testId)}))
|
|
423
|
-
})()`}:t.role?{mode:"role",code:`(async () => {
|
|
424
|
-
const t = window.__sootsimTest
|
|
425
|
-
if (!t) return []
|
|
426
|
-
return await t.queryAll({ hasRole: ${JSON.stringify(t.role)}, pruneHidden: true })
|
|
427
|
-
})()`}:t.type?{mode:"type",code:`(async () => {
|
|
428
|
-
const t = window.__sootsimTest
|
|
429
|
-
if (!t) return []
|
|
430
|
-
return await t.queryAll({ type: ${JSON.stringify(t.type)}, pruneHidden: true })
|
|
431
|
-
})()`}:t.pressable?{mode:"pressable",code:`(async () => {
|
|
432
|
-
const t = window.__sootsimTest
|
|
433
|
-
if (!t) return []
|
|
434
|
-
${R}
|
|
435
|
-
const inspectable = await fromInspectable()
|
|
436
|
-
if (inspectable) return inspectable.filter(n => n.pressable && isVisibleTarget(n))
|
|
437
|
-
const all = await t.queryAll({ pruneHidden: true })
|
|
438
|
-
return all.filter(n => n.pressable && isVisibleTarget(n))
|
|
439
|
-
})()`}:t.interactive?{mode:"interactive-targets",code:`(async () => {
|
|
440
|
-
const t = window.__sootsimTest
|
|
441
|
-
if (!t) return []
|
|
442
|
-
${R}
|
|
443
|
-
const inspectable = await fromInspectable()
|
|
444
|
-
if (inspectable) {
|
|
445
|
-
return inspectable.filter(n => n.pressable && isVisibleTarget(n))
|
|
446
|
-
}
|
|
447
|
-
const all = await t.queryAll({ pruneHidden: true })
|
|
448
|
-
return all.filter(n => n.pressable && isVisibleTarget(n))
|
|
449
|
-
})()`}:t.visible?{mode:"visible",code:`(async () => {
|
|
450
|
-
const t = window.__sootsimTest
|
|
451
|
-
if (!t) return []
|
|
452
|
-
const all = await t.queryAll({ pruneHidden: true })
|
|
453
|
-
return all.filter(n => n.layout && n.layout.width > 0 && n.layout.height > 0)
|
|
454
|
-
})()`}:t.text?{mode:"text",code:`(async () => {
|
|
455
|
-
const t = window.__sootsimTest
|
|
456
|
-
if (!t) return null
|
|
457
|
-
return await t.findByText(${JSON.stringify(t.text)})
|
|
458
|
-
})()`}:null}async function ie(t,e){let r=O(e);if(!r)return null;let n=await t.send({type:"evaluate",code:r.code});return{mode:r.mode,result:n}}function le(t){return[...t].sort((e,r)=>$(r)-$(e))}function $(t){let e=0;t.testID&&(e+=100),typeof t.text=="string"&&t.text.trim().length>0&&(e+=60),typeof t.accessibilityLabel=="string"&&t.accessibilityLabel.trim().length>0&&(e+=30),t.accessibilityRole&&(e+=15);let r=t.layout?.width??0,n=t.layout?.height??0,o=r*n;return o>=400&&o<=6e4?e+=25:o>6e4&&(e-=20),(t.absolutePosition?.y??0)<0&&(e-=30),e}function ue(t){if(t.testID)return`rnx do tap-id ${_(t.testID)}`;let e=typeof t.text=="string"?t.text.trim():"";if(e.length>0&&e.length<=80)return`rnx do tap-text ${_(e)}`;let r=Math.round(((t.absolutePosition?.x??0)+(t.layout?.width??0)/2)*10)/10,n=Math.round(((t.absolutePosition?.y??0)+(t.layout?.height??0)/2)*10)/10;return`rnx do tap ${r} ${n}`}function _(t){return/^[A-Za-z0-9_./@:-]+$/.test(t)?t:`'${t.replace(/'/g,"'\\''")}'`}var F=`(async () => {
|
|
459
|
-
const t = window.__sootsimTest
|
|
460
|
-
let nodes = 0
|
|
461
|
-
try { nodes = (await t?.getNodeCount?.()) || 0 } catch {}
|
|
462
|
-
let targets = 0
|
|
463
|
-
let liveFrameActive = false
|
|
464
|
-
let liveFrameChannels = 0
|
|
465
|
-
let liveFramePublishes = 0
|
|
466
|
-
let loadingText = ''
|
|
467
|
-
const cleanText = (value) =>
|
|
468
|
-
typeof value === 'string' ? value.replace(/\\s+/g, ' ').trim() : ''
|
|
469
|
-
const loadingSignal = (value) => {
|
|
470
|
-
const text = cleanText(value)
|
|
471
|
-
if (!text) return ''
|
|
472
|
-
return /^(opening app\\b|looking for your app\\b|building bundle\\b|preparing rnx runtime\\b|loading native bundle\\b|loading rnx stubs\\b|loading bundle loader\\b|loading native stubs\\b|loading compat bridge\\b|loading react-native shim\\b|loading react bridge\\b|loading reconciler\\b|loading replacement modules\\b|injecting rnx modules\\b|warming sqlite engine\\b|capturing root component\\b|reloading app\\b|loading(?:[.!\u2026]*)?$|connecting(?:[.!\u2026]*)?$)/i.test(text)
|
|
473
|
-
? text
|
|
474
|
-
: ''
|
|
475
|
-
}
|
|
476
|
-
try {
|
|
477
|
-
const loading = window.__sootsimConnectRNLoading
|
|
478
|
-
if (loading && loading.active === true) {
|
|
479
|
-
loadingText = [loading.title, loading.detail].map(cleanText).filter(Boolean).join(' ')
|
|
480
|
-
}
|
|
481
|
-
} catch {}
|
|
482
|
-
try {
|
|
483
|
-
if (typeof t?.listInspectable === 'function') {
|
|
484
|
-
const list = await t.listInspectable({})
|
|
485
|
-
if (Array.isArray(list)) {
|
|
486
|
-
const screenW = window.innerWidth || 0
|
|
487
|
-
const screenH = window.innerHeight || 0
|
|
488
|
-
const isVisible = (n) => {
|
|
489
|
-
const layout = n?.layout
|
|
490
|
-
if (!layout || layout.width <= 0 || layout.height <= 0) return false
|
|
491
|
-
const abs = n?.absolutePosition || n?.absolute
|
|
492
|
-
if (!abs) return true
|
|
493
|
-
const device = n?.device || {}
|
|
494
|
-
const w = Number(device.width) || screenW
|
|
495
|
-
const h = Number(device.height) || screenH
|
|
496
|
-
return (
|
|
497
|
-
abs.x + layout.width > 0 &&
|
|
498
|
-
abs.y + layout.height > 0 &&
|
|
499
|
-
abs.x < w &&
|
|
500
|
-
abs.y < h
|
|
501
|
-
)
|
|
502
|
-
}
|
|
503
|
-
const hasContentSignal = (n) => {
|
|
504
|
-
const role = n?.accessibilityRole || n?.role
|
|
505
|
-
const label = cleanText(n?.accessibilityLabel || n?.label)
|
|
506
|
-
const handlers = Array.isArray(n?.handlers) ? n.handlers : []
|
|
507
|
-
const text = cleanText(n?.text)
|
|
508
|
-
const testID = cleanText(n?.testID || n?.testId)
|
|
509
|
-
const loading = loadingSignal(text) || loadingSignal(label) || loadingSignal(testID)
|
|
510
|
-
if (!loadingText && loading) {
|
|
511
|
-
loadingText = loading
|
|
512
|
-
}
|
|
513
|
-
if (handlers.length > 0) return true
|
|
514
|
-
if (role) return true
|
|
515
|
-
if (n?.isTextInput) return true
|
|
516
|
-
if (text) return true
|
|
517
|
-
if (label) return true
|
|
518
|
-
if (testID && !/^splash|loading/i.test(testID)) return true
|
|
519
|
-
return false
|
|
520
|
-
}
|
|
521
|
-
targets = list.filter(n => isVisible(n) && hasContentSignal(n)).length
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
} catch {}
|
|
525
|
-
try {
|
|
526
|
-
const stats = await t?.getImageLoaderStats?.()
|
|
527
|
-
const presentation = stats?.liveFramePresentation
|
|
528
|
-
liveFrameChannels = Number(presentation?.activeChannels) || 0
|
|
529
|
-
liveFramePublishes = Number(presentation?.publishes) || 0
|
|
530
|
-
const previous = window.__sootsimWaitReadyLiveFramePublishes
|
|
531
|
-
liveFrameActive =
|
|
532
|
-
liveFrameChannels > 0 &&
|
|
533
|
-
typeof previous === 'number' &&
|
|
534
|
-
liveFramePublishes > previous
|
|
535
|
-
window.__sootsimWaitReadyLiveFramePublishes = liveFramePublishes
|
|
536
|
-
} catch {}
|
|
537
|
-
let externalReady = null
|
|
538
|
-
let externalStatus = ''
|
|
539
|
-
let externalError = ''
|
|
540
|
-
let suppressedEntryError = ''
|
|
541
|
-
try {
|
|
542
|
-
const getExternalAppState = t?.getExternalAppState
|
|
543
|
-
const external = typeof getExternalAppState === 'function'
|
|
544
|
-
? await Promise.race([
|
|
545
|
-
getExternalAppState(),
|
|
546
|
-
new Promise((resolve) => setTimeout(
|
|
547
|
-
() => resolve({
|
|
548
|
-
state: {
|
|
549
|
-
ready: false,
|
|
550
|
-
loading: true,
|
|
551
|
-
status: 'waiting for tenant worker...',
|
|
552
|
-
},
|
|
553
|
-
}),
|
|
554
|
-
1000,
|
|
555
|
-
)),
|
|
556
|
-
])
|
|
557
|
-
: null
|
|
558
|
-
const state = external?.state
|
|
559
|
-
if (state && typeof state === 'object') {
|
|
560
|
-
externalReady = state.ready === true
|
|
561
|
-
if (typeof state.status === 'string') externalStatus = state.status
|
|
562
|
-
if (typeof state.error === 'string') externalError = state.error
|
|
563
|
-
}
|
|
564
|
-
if (!externalError && Array.isArray(external?.entryErrors)) {
|
|
565
|
-
// suppressed-and-continued entry errors (bundle-loader's patched __r
|
|
566
|
-
// swallows entry throws and moves on) must NOT gate readiness \u2014 the
|
|
567
|
-
// app frequently runs fine after one (e.g. metro's "Unknown named
|
|
568
|
-
// module" probing noise). they surface separately as a diagnostic
|
|
569
|
-
// for the timeout path.
|
|
570
|
-
const isReal = (item) => item && typeof item.message === 'string' && item.message.trim()
|
|
571
|
-
const fatal = external.entryErrors.find((item) => isReal(item) && item.suppressed !== true)
|
|
572
|
-
if (fatal) externalError = fatal.message
|
|
573
|
-
const suppressed = external.entryErrors.find((item) => isReal(item) && item.suppressed === true)
|
|
574
|
-
if (suppressed) suppressedEntryError = suppressed.message
|
|
575
|
-
}
|
|
576
|
-
// once the app has errored its last status ("injecting sootsim
|
|
577
|
-
// modules...") is stale \u2014 reporting it makes a dead app read as one that
|
|
578
|
-
// is still booting.
|
|
579
|
-
if (externalError) loadingText = ''
|
|
580
|
-
else if (externalReady === false && externalStatus) loadingText = externalStatus
|
|
581
|
-
} catch {}
|
|
582
|
-
let errors = 0
|
|
583
|
-
try { errors = window.__sootsimConsole?.count?.()?.errors ?? 0 } catch {}
|
|
584
|
-
return {
|
|
585
|
-
flag: (window).__sootsimExternalAppReady,
|
|
586
|
-
at: (window).__sootsimExternalAppReadyAt || 0,
|
|
587
|
-
nodes,
|
|
588
|
-
targets,
|
|
589
|
-
liveFrameActive,
|
|
590
|
-
liveFrameChannels,
|
|
591
|
-
liveFramePublishes,
|
|
592
|
-
errors,
|
|
593
|
-
loadingText,
|
|
594
|
-
externalReady,
|
|
595
|
-
externalStatus,
|
|
596
|
-
externalError,
|
|
597
|
-
suppressedEntryError,
|
|
598
|
-
}
|
|
599
|
-
})()`,W=100,H=750,B=2e3,z=150;function j(t){return t.liveFrameActive||t.targets>0||t.nodes>=W}function J(t){return t.liveFrameActive||t.targets>0}function ce(t){if(t.bridgeError)return`sim unreachable: ${t.bridgeError} \u2014 the target tab is closed or no sim is connected (check \`rnx list\`, reopen with \`rnx open\`)`;let e=t.externalError?`guest app errored: ${t.externalError}`:t.loadingText?`still showing "${t.loadingText}"`:t.externalReady===!1?"guest app is still loading":t.flag!==!0&&t.targets>0?"native content is rendered but the ready signal has not settled":t.flag!==!0?"guest app has not emitted sootsim:externalAppReady":t.targets<=0?"ready flag emitted but no visible app content is inspectable yet":"node tree is still changing";return!t.externalError&&t.suppressedEntryError?`${e} (suppressed entry error: ${t.suppressedEntryError})`:e}async function de(t,e=2e4,r={}){let n=Date.now(),o=n+e,s=r.progressIntervalMs??B,i=n+s,d=-1,p=n,g="",a={flag:void 0,at:0,nodes:0,targets:0,liveFrameActive:!1,liveFrameChannels:0,liveFramePublishes:0,errors:0,loadingText:"",externalReady:null,externalStatus:"",externalError:"",suppressedEntryError:""};for(;Date.now()<o;){try{a=await t.send({type:"evaluate",code:F})??a,g=""}catch(m){if(g=m instanceof Error?m.message:String(m),g.startsWith("multiple sims are connected:")||g.startsWith("saved sim "))throw m}let y=Date.now(),b={ready:!1,elapsedMs:y-n,nodes:a.nodes,targets:a.targets,liveFrameActive:a.liveFrameActive,liveFrameChannels:a.liveFrameChannels,liveFramePublishes:a.liveFramePublishes,flag:a.flag,loadingText:a.loadingText,externalReady:a.externalReady,externalStatus:a.externalStatus,externalError:a.externalError,suppressedEntryError:a.suppressedEntryError,errors:a.errors,bridgeError:g};a.nodes!==d&&(d=a.nodes,p=y);let x=a.flag===!0&&j(a),f=a.flag!==!0&&J(a);if((x||f)&&a.externalReady!==!1&&!a.externalError&&!a.loadingText&&y-p>=H)return{...b,ready:!0};if(a.externalError)return b;if(r.onProgress&&s>0&&y>=i){r.onProgress(b);do i+=s;while(y>=i)}await new Promise(m=>setTimeout(m,z))}let h={ready:!1,elapsedMs:Date.now()-n,nodes:a.nodes,targets:a.targets,liveFrameActive:a.liveFrameActive,liveFrameChannels:a.liveFrameChannels,liveFramePublishes:a.liveFramePublishes,flag:a.flag,loadingText:a.loadingText,externalReady:a.externalReady,externalStatus:a.externalStatus,externalError:a.externalError,suppressedEntryError:a.suppressedEntryError,errors:a.errors,bridgeError:g};return r.onProgress&&s>0&&Date.now()>=i&&r.onProgress(h),h}async function pe(t,e,r=5e3,n={}){let o=n.gone===!0;return await t.send({type:"evaluate",code:`(async () => {
|
|
600
|
-
const start = Date.now()
|
|
601
|
-
const deadline = start + ${r}
|
|
602
|
-
const gone = ${o}
|
|
603
|
-
const ID = ${JSON.stringify(e)}
|
|
604
|
-
const present = (node) => !!(node && node.layout && node.layout.width > 0 && node.layout.height > 0)
|
|
605
|
-
const find = async () => {
|
|
606
|
-
const t = window.__sootsimTest
|
|
607
|
-
if (!t) return undefined // bridge not ready \u2014 indeterminate, not "gone"
|
|
608
|
-
try {
|
|
609
|
-
// gone-mode confirms a gate/screen LEFT \u2014 it only needs structural
|
|
610
|
-
// existence + layout, NOT the full-tree occlusion pass (pruneHidden).
|
|
611
|
-
// that pass (computeOccludedInspectNodeIds) walks the whole tree and
|
|
612
|
-
// does O(n\xB2)-ish rect-occlusion testing EVERY poll; on a large
|
|
613
|
-
// post-login app tree it costs seconds per poll, so --gone can never
|
|
614
|
-
// get two clean "absent" polls inside budget and falsely reports the
|
|
615
|
-
// gate as still blocked \u2014 the root cause of the 3pc PR-preview outage.
|
|
616
|
-
// presence-mode keeps pruneHidden so "appeared" still means
|
|
617
|
-
// visibly-reachable. a departed gate is unmounted or zero-sized, so the
|
|
618
|
-
// cheap structural+layout check is correct here and ~O(n) cheap.
|
|
619
|
-
const matches = await t.queryAll?.(gone ? { hasId: ID } : { hasId: ID, pruneHidden: true })
|
|
620
|
-
if (!Array.isArray(matches)) return undefined
|
|
621
|
-
return matches.find(present) || null
|
|
622
|
-
} catch {
|
|
623
|
-
return undefined
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
let goneStreak = 0
|
|
627
|
-
while (Date.now() < deadline) {
|
|
628
|
-
const node = await find()
|
|
629
|
-
if (gone) {
|
|
630
|
-
if (node === null) {
|
|
631
|
-
goneStreak += 1
|
|
632
|
-
if (goneStreak >= 2) return { found: true, elapsed: Date.now() - start }
|
|
633
|
-
} else {
|
|
634
|
-
goneStreak = 0
|
|
635
|
-
}
|
|
636
|
-
} else if (present(node)) {
|
|
637
|
-
return { found: true, node, elapsed: Date.now() - start }
|
|
638
|
-
}
|
|
639
|
-
await new Promise((r) => setTimeout(r, 80))
|
|
640
|
-
}
|
|
641
|
-
return { found: false, elapsed: Date.now() - start }
|
|
642
|
-
})()`},{timeoutMs:r+1e3})??{found:!1,elapsed:r}}function L(t,e){return`(() => {
|
|
643
|
-
const out = []
|
|
644
|
-
const seen = new Set()
|
|
645
|
-
const norm = (s) => (typeof s === 'string' ? s : (() => { try { return JSON.stringify(s) } catch { return String(s) } })())
|
|
646
|
-
const key = (ts, args) => Math.round((ts || 0) / 250) + '|' + (Array.isArray(args) ? args.map(norm).join(' ') : norm(args))
|
|
647
|
-
const push = (e) => {
|
|
648
|
-
if (!e) return
|
|
649
|
-
const ts = typeof e.timestamp === 'number' ? e.timestamp : (typeof e.ts === 'number' ? e.ts : 0)
|
|
650
|
-
const k = key(ts, e.args)
|
|
651
|
-
if (seen.has(k)) return
|
|
652
|
-
seen.add(k)
|
|
653
|
-
out.push({ timestamp: ts, args: Array.isArray(e.args) ? e.args : [e.args], stack: e.stack || undefined, source: e.source || undefined })
|
|
654
|
-
}
|
|
655
|
-
// page-realm ws-bridge buffer first (richest stacks for page-origin errors)
|
|
656
|
-
try { for (const e of (window.__sootsimConsole?.${t==="error"?"getErrors":"getWarnings"}(${e}) || [])) push(e) } catch {}
|
|
657
|
-
// engine observability store \u2014 the always-on render-worker / forwarded path
|
|
658
|
-
try {
|
|
659
|
-
const obs = window.__sootsimObservability
|
|
660
|
-
const snap = obs && obs.logs && typeof obs.logs.getSnapshot === 'function' ? obs.logs.getSnapshot() : []
|
|
661
|
-
for (const e of snap) if (e && e.level === ${JSON.stringify(t)}) push(e)
|
|
662
|
-
} catch {}
|
|
663
|
-
return out.sort((a, b) => (a.timestamp || 0) - (b.timestamp || 0)).slice(-${e})
|
|
664
|
-
})()`}async function ye(t,e=20){let r=await t.send({type:"evaluate",code:L("error",e)});return Array.isArray(r)?r:[]}async function me(t,e=20){let r=await t.send({type:"evaluate",code:L("warn",e)});return Array.isArray(r)?r:[]}var ge=`(() => {
|
|
665
|
-
const norm = (s) => (typeof s === 'string' ? s : (() => { try { return JSON.stringify(s) } catch { return String(s) } })())
|
|
666
|
-
const key = (lvl, ts, args) => lvl + '|' + Math.round((ts || 0) / 250) + '|' + (Array.isArray(args) ? args.map(norm).join(' ') : norm(args))
|
|
667
|
-
const seen = new Set()
|
|
668
|
-
let errors = 0
|
|
669
|
-
let warnings = 0
|
|
670
|
-
const add = (lvl, ts, args) => {
|
|
671
|
-
if (lvl !== 'error' && lvl !== 'warn') return
|
|
672
|
-
const k = key(lvl, ts, args)
|
|
673
|
-
if (seen.has(k)) return
|
|
674
|
-
seen.add(k)
|
|
675
|
-
if (lvl === 'error') errors++
|
|
676
|
-
else warnings++
|
|
677
|
-
}
|
|
678
|
-
try {
|
|
679
|
-
const c = window.__sootsimConsole
|
|
680
|
-
for (const e of (c?.getErrors?.(200) || [])) add('error', e?.timestamp ?? e?.ts, e?.args)
|
|
681
|
-
for (const e of (c?.getWarnings?.(200) || [])) add('warn', e?.timestamp ?? e?.ts, e?.args)
|
|
682
|
-
} catch {}
|
|
683
|
-
try {
|
|
684
|
-
const obs = window.__sootsimObservability
|
|
685
|
-
const snap = obs && obs.logs && typeof obs.logs.getSnapshot === 'function' ? obs.logs.getSnapshot() : []
|
|
686
|
-
for (const e of snap) if (e) add(e.level, e.ts, e.args)
|
|
687
|
-
} catch {}
|
|
688
|
-
return { errors, warnings, total: errors + warnings }
|
|
689
|
-
})()`;async function be(t){await t.send({type:"evaluate",code:'window.__sootsimConsole?.clear(); window.__sootsimObservability?.logs?.clear?.(); "cleared"'})}async function fe(t,e={}){let r=e.limit??20,n=e.failed===!1?"getRequests":"getFailedRequests",o=await t.send({type:"call",path:`__sootsimTest.${n}`,args:[r]});return Array.isArray(o)?o:[]}async function he(t){await t.send({type:"call",path:"__sootsimTest.clearRequests",args:[]})}async function xe(t){let e=await t.send({type:"evaluate",code:`(() => {
|
|
690
|
-
const obs = window.__sootsimObservability;
|
|
691
|
-
if (!obs) return { ok: false };
|
|
692
|
-
return { ok: true, entries: obs.logs.getSnapshot() };
|
|
693
|
-
})()`});return!e||!e.ok?[]:e.entries??[]}async function we(t){await t.send({type:"evaluate",code:'window.__sootsimObservability?.logs.clear(); "cleared"'})}function K(t,e){if(t.source===e.source||t.level!==e.level||Math.abs(t.ts-e.ts)>1e3||t.args.length!==e.args.length)return!1;let r=new Set([t.source,e.source]);return!r.has("sootsim-worker")||!r.has("render-worker")&&!r.has("forwarded-render-worker")?!1:t.args.every((n,o)=>n===e.args[o])}function Se(t,e={}){let r=[];for(let n of t)r.some(o=>K(o,n))||r.push(n);if(e.showInternal||(r=r.filter(n=>{let o=n.args[0];return!(typeof o=="string"&&o.startsWith("[rnx]"))})),e.level&&(r=r.filter(n=>e.level.has(n.level))),e.filter){let n=e.filter.toLowerCase();r=r.filter(o=>o.args.join(" ").toLowerCase().includes(n))}return r}async function ve(t,e){return await t.send({type:"call",path:"SootSim.bridges.timeline.summary",args:[e]})}async function V(t,e){return await t.send({type:"call",path:"SootSim.bridges.timeline.recent",args:[e]})}async function Ie(t){let e;try{e=(await V(t,{kinds:["alert","actionsheet"],limit:80})).events}catch{return[]}let r=new Map;for(let s of e)r.set(s.kind,s);let n=[],o=(s,i)=>{let d=r.get(s);if(!d||!d.data||typeof d.data!="object")return;let p=d.data;p.phase==="show"&&n.push({label:i,title:typeof p.title=="string"?p.title:null})};return o("alert","Alert"),o("actionsheet","ActionSheet"),n}async function Te(t,e,r){await t.send({type:"call",path:"SootSim.bridges.timeline.cursorAdvance",args:[e,r]})}async function ke(t){return await t.send({type:"evaluate",code:`(() => {
|
|
694
|
-
const kb = window.__sootsimKeyboard
|
|
695
|
-
if (!kb || typeof kb.getLayout !== 'function') {
|
|
696
|
-
return { error: 'keyboard bridge getLayout() not available' }
|
|
697
|
-
}
|
|
698
|
-
return kb.getLayout()
|
|
699
|
-
})()`})??{error:"keyboard bridge returned no result"}}function q(t){let e=t instanceof Error?t.message:String(t);return e.includes("call target not found: SootSim.bridges.mainShell")||e.includes("test bridge unavailable before app-in-worker boot")}async function Y(t,e=0){let r=Date.now()+Math.max(0,e);for(;;)try{return await t.send({type:"call",path:"SootSim.bridges.mainShell.getState",args:[]})}catch(n){if(!q(n)||Date.now()>=r)throw n;await new Promise(o=>setTimeout(o,50))}}async function Ee(t){let e=await t.send({type:"evaluate",code:`(async () => {
|
|
700
|
-
const test = window.__sootsimTest
|
|
701
|
-
const kb = window.__sootsimKeyboard
|
|
702
|
-
const navSnap =
|
|
703
|
-
test && typeof test.getNavigationSnapshot === 'function'
|
|
704
|
-
? await test.getNavigationSnapshot()
|
|
705
|
-
: null
|
|
706
|
-
const route =
|
|
707
|
-
test && typeof test.getRouteInfo === 'function'
|
|
708
|
-
? await test.getRouteInfo()
|
|
709
|
-
: null
|
|
710
|
-
const keyboard =
|
|
711
|
-
kb && typeof kb.getLayout === 'function'
|
|
712
|
-
? (() => {
|
|
713
|
-
const layout = kb.getLayout()
|
|
714
|
-
return layout ? {
|
|
715
|
-
visible: layout.visible,
|
|
716
|
-
mode: layout.mode,
|
|
717
|
-
spec: layout.spec
|
|
718
|
-
? {
|
|
719
|
-
keyboardType: layout.spec.keyboardType,
|
|
720
|
-
returnKeyType: layout.spec.returnKeyType,
|
|
721
|
-
}
|
|
722
|
-
: null,
|
|
723
|
-
} : null
|
|
724
|
-
})()
|
|
725
|
-
: null
|
|
726
|
-
return { nav: navSnap, route, keyboard }
|
|
727
|
-
})()`});return{shell:await Y(t,500).catch(()=>null),nav:e?.nav??null,route:e?.route??null,keyboard:e?.keyboard??null}}async function Re(t){return t.send({type:"evaluate",code:"window.__sootsimDebug.status()"})}async function $e(t){return t.send({type:"evaluate",code:"window.__sootsimDebug.flags()"})}async function _e(t,e){return t.send({type:"evaluate",code:`window.__sootsimTest.debugFind(${JSON.stringify(e)})`})}async function Ae(t,e,r=50){let n=e&&e!=="all"?`window.__sootsimDebug.recent(${JSON.stringify(e)}, ${r})`:`window.__sootsimDebug.recent(undefined, ${r})`;return t.send({type:"evaluate",code:n})}async function Le(t,e,r){let n=r.length>0?r.map(o=>JSON.stringify(o)).join(", "):e==="disable"?"'all'":"";return t.send({type:"evaluate",code:`window.__sootsimDebug.${e}(${n})`})}async function Pe(t){return await t.send({type:"evaluate",code:`(async () => {
|
|
728
|
-
const host = window.__sootsimRenderHost
|
|
729
|
-
const stats = host?.queryStats ? await host.queryStats() : null
|
|
730
|
-
const shellRaw = window.__sootsimShellMemory
|
|
731
|
-
? await window.__sootsimShellMemory()
|
|
732
|
-
: null
|
|
733
|
-
const shell = shellRaw && !shellRaw.error ? shellRaw : null
|
|
734
|
-
// the compositor paints home + app:one + app:two, so every app-surface
|
|
735
|
-
// picture and raster image is counted here and nowhere else.
|
|
736
|
-
let compositor = null
|
|
737
|
-
try {
|
|
738
|
-
const cs = await window.__sootsimCompositor?.getStats?.(false, true)
|
|
739
|
-
compositor = cs?.memory ?? null
|
|
740
|
-
} catch {}
|
|
741
|
-
const normalize = (m) =>
|
|
742
|
-
m
|
|
743
|
-
? {
|
|
744
|
-
nodesRegistered: m.nodesRegistered ?? null,
|
|
745
|
-
nodesDetached: m.nodesDetached ?? null,
|
|
746
|
-
detachedTypes: m.detachedTypes ?? null,
|
|
747
|
-
objects: m.objects ?? null,
|
|
748
|
-
activeNativeAnimations: m.activeNativeAnimations ?? null,
|
|
749
|
-
imageLoader: m.imageLoader ?? null,
|
|
750
|
-
workerHeap: m.workerHeap ?? null,
|
|
751
|
-
wasmHeapBytes: m.wasmHeapBytes ?? null,
|
|
752
|
-
}
|
|
753
|
-
: null
|
|
754
|
-
const hostMem = performance.memory
|
|
755
|
-
? {
|
|
756
|
-
usedJSHeapSize: performance.memory.usedJSHeapSize,
|
|
757
|
-
totalJSHeapSize: performance.memory.totalJSHeapSize,
|
|
758
|
-
jsHeapSizeLimit: performance.memory.jsHeapSizeLimit,
|
|
759
|
-
}
|
|
760
|
-
: null
|
|
761
|
-
return {
|
|
762
|
-
tenant: normalize(stats?.memory),
|
|
763
|
-
shell: normalize(shell),
|
|
764
|
-
compositor: normalize(compositor),
|
|
765
|
-
hostHeap: hostMem,
|
|
766
|
-
}
|
|
767
|
-
})()`})??{tenant:null,shell:null,compositor:null,hostHeap:null}}function Ne(t){if(t.total===0)return"nothing recorded";let e=[],r=["error","warning","console","fetch","toast","alert","actionsheet","picker","notification","screen","route","keyboard","app-launch","shell","scroll","gesture","text-input","react-commit","animation","reanimated"],n=new Set;for(let o of r){let s=t.byKind[o];s&&(e.push(`${s} ${o}${s===1?"":"s"}`),n.add(o))}for(let[o,s]of Object.entries(t.byKind))!n.has(o)&&s&&e.push(`${s} ${o}${s===1?"":"s"}`);return e.join(" \xB7 ")}var Me=new Set(["react-commit","layout","scroll"]);function U(t,e){if(e===null)return new Date(t).toLocaleTimeString();let r=(t-e)/1e3;return`${r>=0?"+":""}${r.toFixed(2)}s`}function G(t,e){switch(t){case"app-launch":return e.phase==="launch"?`launch ${e.appName??e.toAppId??""}`:`dismiss ${e.appName??e.fromAppId??""} \u2192 ${e.toAppId??""}`;case"toast":return`"${e.text??""}"${e.durationMs?` (${e.durationMs}ms)`:""}`;case"keyboard":return`${e.phase??"?"}${e.heightPx?` h=${e.heightPx}`:""}${e.mode?` ${e.mode}`:""}`;case"screen":return`${e.phase??"?"} ${e.name??e.activeName??""}`;case"flow-step":return`${e.status??"?"} ${e.stepName??"step"}${e.durationMs?` ${e.durationMs}ms`:""}`;case"route":return`${e.phase??"?"} ${e.path??e.pathname??""}`;case"alert":case"actionsheet":case"picker":return`${e.phase??"?"} ${e.title??e.message??""}`;case"notification":return`${e.title??""}${e.body?` \u2014 ${e.body}`:""}`;case"fetch":return`${e.method??"GET"} ${e.url??""}${e.status?` -> ${e.status}`:""}`;case"console":case"console-log":return`${e.level??"log"}: ${(e.message??"").toString().slice(0,120)}`;case"shell":return`${e.event??e.type??e.phase??""}`;case"scroll":return`${e.phase??"?"} ${e.target??""}`;case"gesture":return`${e.phase??"?"} ${e.type??""}`;case"text-input":return`${e.phase??"?"}${e.value!==void 0?` "${String(e.value).slice(0,40)}"`:""}`;case"layout":return`${e.kind??"?"} ${e.testID??e.type??""}${e.skipped?` skipped:${e.reason??"unknown"}`:""}`;case"react-commit":{let r=e.slowest;return`${e.fiberCount??"?"} fibers ${e.durationMs??"?"}ms${r?.displayName?` \xB7 ${r.displayName} ${r.durationMs??"?"}ms`:""}`}case"frame":return`${e.totalMs??"?"}ms${e.renderMs?` \xB7 render ${e.renderMs}ms`:""}${e.layoutMs?` \xB7 layout ${e.layoutMs}ms`:""}${e.copyMs?` \xB7 copy ${e.copyMs}ms`:""}`;case"reanimated":case"animation":return`${e.kind??""} ${e.target??""}${e.durationMs?` ${e.durationMs}ms`:""}`}return""}function De(t,e){let r=U(t.t,e).padStart(8),n=t.context.padEnd(6),o=`[${t.kind}]`.padEnd(15),s=t.data,i=s&&typeof s=="object"?G(t.kind,s):"";return` ${r} ${n} ${o} ${i}`}export{Q as a,X as b,Z as c,ee as d,te as e,ne as f,oe as g,se as h,ae as i,ie as j,le as k,ue as l,F as m,H as n,z as o,j as p,J as q,ce as r,de as s,pe as t,ye as u,me as v,ge as w,be as x,fe as y,he as z,xe as A,we as B,Se as C,ve as D,V as E,Ie as F,Te as G,ke as H,q as I,Y as J,Ee as K,Re as L,$e as M,_e as N,Ae as O,Le as P,Pe as Q,Ne as R,Me as S,De as T};
|