peachsim 0.1.636 → 0.1.638
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 +8 -5
- package/cli/bridge-flow-runner.ts +442 -14
- package/cli/commands/inspect/core.ts +93 -24
- package/cli/commands/maestro.ts +2 -2
- package/cli/commands/serve.ts +13 -1
- package/cli/drivers/playwright-provisioning.ts +8 -16
- package/cli/drivers/playwright-sim-host.ts +3 -0
- package/cli/drivers/playwright.ts +1 -0
- package/cli/internal-child.ts +51 -8
- 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 +3 -2
- package/dist-lib/bridge-contract-input.mjs +3 -2
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +4 -2
- 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 +76 -20
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.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/native-app-identity.cjs +1 -1
- package/dist-lib/native-app-identity.mjs +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 +78 -20
- package/dist-lib/sdk.mjs +77 -20
- package/dist-lib/skills.cjs +394 -62
- package/dist-lib/swift-compile.cjs +89 -7
- package/dist-lib/swift-compile.mjs +89 -7
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +1 -1
- package/dist-lib/swift-submit.mjs +1 -1
- package/dist-lib/swift.cjs +122 -34
- package/dist-lib/vite-swift.cjs +89 -7
- package/dist-lib/vite.cjs +1 -1
- package/package.json +1 -1
- package/src/bridge-contract-input.ts +3 -2
- package/src/bridge-contract.ts +8 -0
- package/src/host/bridge-host.ts +5 -5
- package/src/native-seam-manifest.ts +4 -6
- package/src/swift-compile.ts +105 -9
package/dist-lib/skills.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.638 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
@@ -4349,6 +4349,8 @@ var init_supported_native_packages = __esm({
|
|
|
4349
4349
|
// seam
|
|
4350
4350
|
"@bacons/apple-targets",
|
|
4351
4351
|
// seam
|
|
4352
|
+
"@bam.tech/react-native-image-resizer",
|
|
4353
|
+
// seam
|
|
4352
4354
|
"@baronha/ting",
|
|
4353
4355
|
// seam
|
|
4354
4356
|
"@bitdrift/react-native",
|
|
@@ -4491,6 +4493,8 @@ var init_supported_native_packages = __esm({
|
|
|
4491
4493
|
// seam+coverage
|
|
4492
4494
|
"@react-native-community/progress-view",
|
|
4493
4495
|
// seam
|
|
4496
|
+
"@react-native-community/push-notification-ios",
|
|
4497
|
+
// seam
|
|
4494
4498
|
"@react-native-community/slider",
|
|
4495
4499
|
// coverage
|
|
4496
4500
|
"@react-native-cookies/cookies",
|
|
@@ -4590,7 +4594,7 @@ var init_supported_native_packages = __esm({
|
|
|
4590
4594
|
"appcenter-analytics",
|
|
4591
4595
|
// seam
|
|
4592
4596
|
"burnt",
|
|
4593
|
-
// coverage
|
|
4597
|
+
// seam+coverage
|
|
4594
4598
|
"customerio-reactnative",
|
|
4595
4599
|
// seam
|
|
4596
4600
|
"expo",
|
|
@@ -4811,8 +4815,12 @@ var init_supported_native_packages = __esm({
|
|
|
4811
4815
|
// seam
|
|
4812
4816
|
"react-native-barcode-creator",
|
|
4813
4817
|
// seam
|
|
4818
|
+
"react-native-biometrics",
|
|
4819
|
+
// seam+coverage
|
|
4814
4820
|
"react-native-blasted-image",
|
|
4815
4821
|
// seam
|
|
4822
|
+
"react-native-ble-plx",
|
|
4823
|
+
// seam
|
|
4816
4824
|
"react-native-blob-util",
|
|
4817
4825
|
// coverage
|
|
4818
4826
|
"react-native-blue-crypto",
|
|
@@ -4905,6 +4913,8 @@ var init_supported_native_packages = __esm({
|
|
|
4905
4913
|
// seam
|
|
4906
4914
|
"react-native-fs",
|
|
4907
4915
|
// coverage
|
|
4916
|
+
"react-native-geolocation-service",
|
|
4917
|
+
// seam
|
|
4908
4918
|
"react-native-gesture-handler",
|
|
4909
4919
|
// preset+semantic-proof+seam+coverage
|
|
4910
4920
|
"react-native-get-device-locale",
|
|
@@ -4912,7 +4922,7 @@ var init_supported_native_packages = __esm({
|
|
|
4912
4922
|
"react-native-get-location",
|
|
4913
4923
|
// seam+coverage
|
|
4914
4924
|
"react-native-get-random-values",
|
|
4915
|
-
// coverage
|
|
4925
|
+
// seam+coverage
|
|
4916
4926
|
"react-native-google-places",
|
|
4917
4927
|
// seam
|
|
4918
4928
|
"react-native-google-play-install-referrer",
|
|
@@ -4987,6 +4997,8 @@ var init_supported_native_packages = __esm({
|
|
|
4987
4997
|
// seam+coverage
|
|
4988
4998
|
"react-native-navigation",
|
|
4989
4999
|
// seam
|
|
5000
|
+
"react-native-nfc-manager",
|
|
5001
|
+
// seam
|
|
4990
5002
|
"react-native-nitro-buffer",
|
|
4991
5003
|
// seam+coverage
|
|
4992
5004
|
"react-native-nitro-device-info",
|
|
@@ -5080,7 +5092,7 @@ var init_supported_native_packages = __esm({
|
|
|
5080
5092
|
"react-native-record-screen",
|
|
5081
5093
|
// seam
|
|
5082
5094
|
"react-native-restart",
|
|
5083
|
-
// coverage
|
|
5095
|
+
// seam+coverage
|
|
5084
5096
|
"react-native-restart-newarch",
|
|
5085
5097
|
// coverage
|
|
5086
5098
|
"react-native-rsa-native",
|
|
@@ -5141,6 +5153,8 @@ var init_supported_native_packages = __esm({
|
|
|
5141
5153
|
// seam
|
|
5142
5154
|
"react-native-sqlite-2",
|
|
5143
5155
|
// seam
|
|
5156
|
+
"react-native-sqlite-storage",
|
|
5157
|
+
// seam+coverage
|
|
5144
5158
|
"react-native-stallion",
|
|
5145
5159
|
// seam
|
|
5146
5160
|
"react-native-store-age-signals-native-modules",
|
|
@@ -6624,7 +6638,7 @@ var init_registry = __esm({
|
|
|
6624
6638
|
{
|
|
6625
6639
|
range: ">=0.1.0",
|
|
6626
6640
|
coverage: 0.9,
|
|
6627
|
-
note: "
|
|
6641
|
+
note: "real upstream package \u2014 not intercepted. native side via the Burnt expo module (native-seams/burnt.ts), mirroring ios/BurntModule.swift over the shell-drawn SPIndicatorView and SPAlertView; on Android the package itself calls ToastAndroid",
|
|
6628
6642
|
working: "iOS toast (title, message, preset: done/error/none/custom, duration, haptic, from, layout), iOS alert (preset: heart/done/error/none/spinner/custom, shouldDismissByTap), Android toast/title-only alert fallback via ToastAndroid.showWithGravityAndOffset, dismissAllAlerts, IconParams, all type exports",
|
|
6629
6643
|
missing: "drag-to-dismiss gesture interaction on iOS toast, Android message/icon/haptic/layout customization because upstream Android Burnt ignores those fields"
|
|
6630
6644
|
}
|
|
@@ -7515,9 +7529,9 @@ var init_registry = __esm({
|
|
|
7515
7529
|
{
|
|
7516
7530
|
range: ">=5.0.0",
|
|
7517
7531
|
coverage: 0.8,
|
|
7518
|
-
note: "
|
|
7519
|
-
working: "
|
|
7520
|
-
missing: "
|
|
7532
|
+
note: "real upstream package \u2014 not intercepted. native side via the RNFusedLocation module (native-seams/react-native-geolocation-service.ts), mirroring ios/RNFusedLocation.swift over the browser geolocation fix",
|
|
7533
|
+
working: "Geolocation.native.js runs unchanged: requestAuthorization statuses, getCurrentPosition with the native timeout timer and maximumAge cache, watchPosition with the 100 m default distanceFilter, CLLocation-shaped coords (-1 for unknown course, speed and vertical accuracy), and buildError codes and messages",
|
|
7534
|
+
missing: "desiredAccuracy levels (the browser fix has one accuracy), significant-change monitoring, background updates"
|
|
7521
7535
|
}
|
|
7522
7536
|
]
|
|
7523
7537
|
},
|
|
@@ -7528,9 +7542,9 @@ var init_registry = __esm({
|
|
|
7528
7542
|
{
|
|
7529
7543
|
range: ">=1.0.0",
|
|
7530
7544
|
coverage: 0.85,
|
|
7531
|
-
note: "
|
|
7532
|
-
working: "
|
|
7533
|
-
missing: "
|
|
7545
|
+
note: "real upstream package, not intercepted. native side via the RNCPushNotificationIOS module (native-seams/react-native-push-notification-ios.ts) following RNCPushNotificationIOS.m and RCTConvert+Notification.m over the engine notification bus: the permission prompt, delivery, banners, badge and pending requests",
|
|
7546
|
+
working: "requestPermissions/checkPermissions with UNNotificationSettings, the register event with the simulator token, addNotificationRequest with calendar triggers, the deprecated UILocalNotification calls, pending and delivered queries and removal, badge, categories, localNotification on a tap and notification for a dispatched push",
|
|
7547
|
+
missing: "repeating calendar triggers other than daily and weekly, notification attachments, the fetch completion handler of a background push"
|
|
7534
7548
|
}
|
|
7535
7549
|
]
|
|
7536
7550
|
},
|
|
@@ -7712,9 +7726,9 @@ var init_registry = __esm({
|
|
|
7712
7726
|
{
|
|
7713
7727
|
range: ">=13.0.0",
|
|
7714
7728
|
coverage: 0.95,
|
|
7715
|
-
note:
|
|
7716
|
-
working: "
|
|
7717
|
-
missing: "
|
|
7729
|
+
note: "native-seam: the published LocalAuthentication.js runs from the bundle over the ExpoLocalAuthentication module, following LocalAuthenticationModule.swift as an installed app on the iOS Simulator sees it (Face ID with no enrolled identity, a passcode set): hasHardwareAsync true, isEnrolledAsync false, supportedAuthenticationTypesAsync [FACIAL_RECOGNITION], getEnrolledLevelAsync SECRET, authenticateAsync not_enrolled with disableDeviceFallback. cancelAuthenticate is absent, as on iOS.",
|
|
7730
|
+
working: "hasHardwareAsync, isEnrolledAsync, supportedAuthenticationTypesAsync, getEnrolledLevelAsync, authenticateAsync biometric-only errors; UnavailabilityError for cancelAuthenticate on iOS",
|
|
7731
|
+
missing: "the system passcode sheet for device-fallback authentication, which settles as the sheet close button does (user_cancel)"
|
|
7718
7732
|
}
|
|
7719
7733
|
]
|
|
7720
7734
|
},
|
|
@@ -7796,19 +7810,19 @@ var init_registry = __esm({
|
|
|
7796
7810
|
usage: 3,
|
|
7797
7811
|
importance: 3,
|
|
7798
7812
|
estimate: 1,
|
|
7799
|
-
rationale: "the
|
|
7813
|
+
rationale: "the published side-effect polyfill runs unchanged over the RNGetRandomValues module"
|
|
7800
7814
|
},
|
|
7801
7815
|
{
|
|
7802
7816
|
id: "load-safe-fallback",
|
|
7803
7817
|
usage: 1,
|
|
7804
7818
|
importance: 1,
|
|
7805
7819
|
estimate: 1,
|
|
7806
|
-
rationale: "
|
|
7820
|
+
rationale: "an existing crypto.getRandomValues stays in place, as upstream leaves it"
|
|
7807
7821
|
}
|
|
7808
7822
|
],
|
|
7809
7823
|
capabilityCoverage: CAPABILITY_INVENTORY_PACKAGE_COVERAGE["react-native-get-random-values"],
|
|
7810
|
-
note: "
|
|
7811
|
-
working: "
|
|
7824
|
+
note: "real upstream package \u2014 not intercepted. native side via the RNGetRandomValues module (native-seams/react-native-get-random-values.ts), mirroring ios/RNGetRandomValues.mm",
|
|
7825
|
+
working: "index.js runs unchanged: it installs crypto.getRandomValues over the synchronous getRandomBase64 (SecRandomCopyBytes) when the global is missing, and leaves an existing one in place"
|
|
7812
7826
|
}
|
|
7813
7827
|
]
|
|
7814
7828
|
},
|
|
@@ -8186,8 +8200,8 @@ var init_registry = __esm({
|
|
|
8186
8200
|
{
|
|
8187
8201
|
range: ">=0.0.1",
|
|
8188
8202
|
coverage: 1,
|
|
8189
|
-
note: "
|
|
8190
|
-
working: "restart(), Restart() (
|
|
8203
|
+
note: "real upstream package, not intercepted. native side via the RNRestart module (native-seams/react-native-restart.ts) following ios/Restart.mm: the reason outlives the reload and the reload is the one DevSettings.reload performs",
|
|
8204
|
+
working: "restart(), Restart() and getReason() from the published JS"
|
|
8191
8205
|
}
|
|
8192
8206
|
]
|
|
8193
8207
|
},
|
|
@@ -8249,10 +8263,10 @@ var init_registry = __esm({
|
|
|
8249
8263
|
versions: [
|
|
8250
8264
|
{
|
|
8251
8265
|
range: ">=3.0.0",
|
|
8252
|
-
coverage: 0.
|
|
8253
|
-
note: "
|
|
8254
|
-
working: "
|
|
8255
|
-
missing: "
|
|
8266
|
+
coverage: 0.9,
|
|
8267
|
+
note: "real upstream package, not intercepted. native side via the ReactNativeBiometrics module (native-seams/react-native-biometrics.ts) following ios/ReactNativeBiometrics.m as the iOS Simulator answers it: Face ID with no enrolled identity, a passcode set, and a software RSA key that signs without a prompt",
|
|
8268
|
+
working: "isSensorAvailable (LAError -7 for biometrics, FaceID with device credentials), createKeys with an spki public key, createSignature (RSA PKCS#1 v1.5 SHA-256), biometricKeysExist, deleteKeys, simplePrompt rejecting biometric_error",
|
|
8269
|
+
missing: "the system passcode sheet for allowDeviceCredentials prompts, which settle as the sheet close button does"
|
|
8256
8270
|
}
|
|
8257
8271
|
]
|
|
8258
8272
|
},
|
|
@@ -8577,9 +8591,9 @@ var init_registry = __esm({
|
|
|
8577
8591
|
{
|
|
8578
8592
|
range: ">=8.0.0",
|
|
8579
8593
|
coverage: 0.6,
|
|
8580
|
-
note: "
|
|
8581
|
-
working: "configure
|
|
8582
|
-
missing: "
|
|
8594
|
+
note: "real upstream package, not intercepted. on iOS its JS runs over @react-native-community/push-notification-ios, whose RNCPushNotificationIOS module is the native side (native-seams/react-native-push-notification-ios.ts)",
|
|
8595
|
+
working: "configure, localNotification, localNotificationSchedule, permissions, badge, scheduled and delivered queries and cancellation, all through the published iOS path",
|
|
8596
|
+
missing: "the Android RNPushNotification module for Android mode"
|
|
8583
8597
|
}
|
|
8584
8598
|
]
|
|
8585
8599
|
},
|
|
@@ -8970,9 +8984,9 @@ var init_registry = __esm({
|
|
|
8970
8984
|
{
|
|
8971
8985
|
range: ">=3.0.0",
|
|
8972
8986
|
coverage: 0.85,
|
|
8973
|
-
note: "
|
|
8974
|
-
working: "default createResizedImage export,
|
|
8975
|
-
missing: "
|
|
8987
|
+
note: "real upstream package, not intercepted. native side via the ImageResizer module (native-seams/bam-react-native-image-resizer.ts) following ios/ImageResizer.mm: the RCTImageLoader contain decode, rotation, scaling, and a JPEG or PNG written to Caches/<UUID> or Documents/<outputPath> in the app file store",
|
|
8988
|
+
working: "default createResizedImage export, contain/cover/stretch sizing over the loader thumbnail, onlyScaleDown, 90-degree rotation, the file written to the app container with path/uri/name/size, WEBP failing to save as on iOS",
|
|
8989
|
+
missing: "EXIF metadata preservation for keepMeta, the RCTLogError red box on a failure"
|
|
8976
8990
|
}
|
|
8977
8991
|
]
|
|
8978
8992
|
},
|
|
@@ -9891,10 +9905,10 @@ var init_registry = __esm({
|
|
|
9891
9905
|
versions: [
|
|
9892
9906
|
{
|
|
9893
9907
|
range: ">=6.0.0",
|
|
9894
|
-
coverage: 0.
|
|
9895
|
-
note: "
|
|
9896
|
-
working: "
|
|
9897
|
-
missing: "
|
|
9908
|
+
coverage: 0.9,
|
|
9909
|
+
note: "native-seam: sqlite.core.js runs unchanged from the bundle; only NativeModules.SQLite is ours, following platforms/ios/SQLite.m over the shared bedrock-sqlite WASM engine (tenant-scoped memfs IDB, so a reopened database keeps its rows). connections keyed by name, rowsAffected from the total_changes() delta, insertId whenever the connection has changed rows, WebSQL error codes from the primary sqlite code, BLOB columns as base64, the regexp() function, WAL journal mode, and the background batch reply after the calling turn",
|
|
9910
|
+
working: "open (default/Documents/Library locations), close, delete, attach, echoStringValue, executeSqlBatch/backgroundExecuteSqlBatch, executeSql/backgroundExecuteSql; everything in sqlite.core.js above them (openDatabase, transaction/readTransaction, executeSql, sqlBatch, enablePromise) is the real package",
|
|
9911
|
+
missing: "integral JS numbers bind as integers (iOS binds every bridged number as a double, so 5 into a TEXT column reads 5.0 there); createFromLocation copies nothing (no app-bundle www/ or sandbox asset exists); a multi-statement string errors where iOS silently runs only the first statement; regexp() bracket classes such as [[:alpha:]]; the Shared location (needs an AppGroupName) opens a temporary database as iOS does with a nil directory"
|
|
9898
9912
|
}
|
|
9899
9913
|
]
|
|
9900
9914
|
},
|
|
@@ -11127,9 +11141,9 @@ var init_registry = __esm({
|
|
|
11127
11141
|
{
|
|
11128
11142
|
range: ">=4.0.0",
|
|
11129
11143
|
coverage: 0.85,
|
|
11130
|
-
note: "native-seam: the
|
|
11131
|
-
working: "isSupported(config) and authenticate(reason, config)
|
|
11132
|
-
missing: "
|
|
11144
|
+
note: "native-seam: the published TouchID wrapper and error classes run from the bundle over the TouchID module, following TouchID.m as an installed app on the iOS Simulator sees it (Face ID with no enrolled identity, a passcode set): isSupported resolves FaceID through its default passcode fallback, authenticate rejects LAErrorTouchIDNotEnrolled without one.",
|
|
11145
|
+
working: "isSupported(config) and authenticate(reason, config) through the passcodeFallback branches of TouchID.m, with the upstream TouchIDError mapping",
|
|
11146
|
+
missing: "the system passcode sheet for passcodeFallback authentication, which settles as the sheet close button does (LAErrorUserCancel)"
|
|
11133
11147
|
}
|
|
11134
11148
|
]
|
|
11135
11149
|
},
|
|
@@ -12785,7 +12799,7 @@ var init_registry = __esm({
|
|
|
12785
12799
|
coverage: 0.85,
|
|
12786
12800
|
note: "native-seam: the pure-JS concurrent-lock layer (setup-open.js, type-orm.js, DBListenerManager, lock-hooks, types) runs unchanged from the bundle; only the QuickSQLite NativeModule is ours \u2014 its synchronous install() populates global.__QuickSQLiteProxy with a real bedrock-sqlite-backed proxy sharing the same WASM engine as expo-sqlite/op-sqlite/nitro-sqlite/react-native-sqlite-storage, so persistence lands in the tenant-scoped memfs IDB and survives reload. faithfully implements the PowerSync concurrent-lock model: requestLock/onLockContextIsAvailable/executeInContext/releaseLock serialized per-db over the single-threaded WASM handle (read+write contexts one-at-a-time, FIFO \u2014 exactly how one SQLite connection behaves; the native lib\u2019s extra read connections are a throughput optimization, not an observable semantic). verified end-to-end against the on-disk bedrock build: CRUD, BEGIN/COMMIT, ROLLBACK, executeBatch, lock-context serialization ordering, and close/reopen persistence.",
|
|
12787
12801
|
working: "install()/__QuickSQLiteProxy, open/close/delete, requestLock/releaseLock + onLockContextIsAvailable dispatch, executeInContext (real bedrock SQL incl. joins/params/RETURNING), executeBatch, refreshSchema, the upstream setup-open concurrent-connection object (execute, readLock/writeLock, readTransaction/writeTransaction, listener manager) running off the seam",
|
|
12788
|
-
missing: "ATTACH/DETACH across databases (a second memfs open \u2014 parked until a consumer needs it
|
|
12802
|
+
missing: "ATTACH/DETACH across databases (a second memfs open \u2014 parked until a consumer needs it), loadFile, true multi-connection parallelism (single-threaded WASM serializes \u2014 semantically equivalent for SQLite)"
|
|
12789
12803
|
}
|
|
12790
12804
|
]
|
|
12791
12805
|
},
|
|
@@ -13286,9 +13300,9 @@ var init_registry = __esm({
|
|
|
13286
13300
|
{
|
|
13287
13301
|
range: ">=2.0.0",
|
|
13288
13302
|
coverage: 0.85,
|
|
13289
|
-
note:
|
|
13290
|
-
working: "BleManager
|
|
13291
|
-
missing: "
|
|
13303
|
+
note: "real upstream package \u2014 not intercepted. native side via the BlePlx module (native-seams/react-native-ble-plx.ts), mirroring ios/BlePlx.m over MultiplatformBleAdapter 0.2.0 as the iOS simulator answers it: no Bluetooth radio, so the manager reports Unsupported",
|
|
13304
|
+
working: "BleManager runs unchanged: StateChangeEvent Unknown then Unsupported, state(), scans and connections failing with BluetoothUnsupported (BluetoothInUnknownState before the first update), every lookup rejecting with the adapter error JSON (InvalidIdentifiers, DeviceNotConnected, ServiceNotFound, CharacteristicNotFound, DescriptorNotFound, invalid base64), monitor errors as ReadEvent, enable/disable BluetoothStateChangeFailed",
|
|
13305
|
+
missing: "a real Bluetooth radio, which the iOS simulator does not have either"
|
|
13292
13306
|
}
|
|
13293
13307
|
]
|
|
13294
13308
|
},
|
|
@@ -13299,9 +13313,9 @@ var init_registry = __esm({
|
|
|
13299
13313
|
{
|
|
13300
13314
|
range: ">=3.0.0",
|
|
13301
13315
|
coverage: 0.85,
|
|
13302
|
-
note:
|
|
13303
|
-
working:
|
|
13304
|
-
missing: "
|
|
13316
|
+
note: "real upstream package, not intercepted. native side via the NfcManager module (native-seams/react-native-nfc-manager.ts) following ios/NfcManager.m as the iOS Simulator answers it: CoreNFC reports readingAvailable false and every begun session invalidates with NFCError 1",
|
|
13317
|
+
working: 'the published NfcManager, NfcTech handlers, NfcError and Ndef helpers; isSupported false, start rejecting "Not support in this device", registerTagEvent and requestTechnology sessions closing with NFCError:1 and the SessionClosed event, the not-connected answers of every tag command',
|
|
13318
|
+
missing: "tag discovery (the simulator has no NFC reader); the Android NfcManager module"
|
|
13305
13319
|
}
|
|
13306
13320
|
]
|
|
13307
13321
|
},
|
|
@@ -29229,6 +29243,7 @@ var init_bridge_host = __esm({
|
|
|
29229
29243
|
// terminal 4001 code, so the client closes the abandoned window instead
|
|
29230
29244
|
// of reconnecting the zombie straight back in.
|
|
29231
29245
|
static SIM_IDLE_REAP_TTL_MS = 30 * 6e4;
|
|
29246
|
+
bindHost;
|
|
29232
29247
|
preferredPort;
|
|
29233
29248
|
portFallbackCount;
|
|
29234
29249
|
shouldWriteLockfile;
|
|
@@ -29262,6 +29277,7 @@ var init_bridge_host = __esm({
|
|
|
29262
29277
|
inflightScan = null;
|
|
29263
29278
|
static SCAN_FRESH_MS = 2e3;
|
|
29264
29279
|
constructor(opts = {}) {
|
|
29280
|
+
this.bindHost = opts.host ?? "127.0.0.1";
|
|
29265
29281
|
this.preferredPort = opts.port ?? DEFAULT_SOOTSIM_BRIDGE_PORT;
|
|
29266
29282
|
this.port = this.preferredPort;
|
|
29267
29283
|
this.shouldWriteLockfile = opts.writeLockfile === true;
|
|
@@ -29338,7 +29354,7 @@ var init_bridge_host = __esm({
|
|
|
29338
29354
|
reject(err);
|
|
29339
29355
|
};
|
|
29340
29356
|
server.once("error", onError);
|
|
29341
|
-
server.listen(port,
|
|
29357
|
+
server.listen(port, this.bindHost, () => {
|
|
29342
29358
|
if (settled) return;
|
|
29343
29359
|
const address = server.address();
|
|
29344
29360
|
if (!address || typeof address === "string") {
|
|
@@ -33485,6 +33501,57 @@ function layoutGetNativeEval(opts = {}) {
|
|
|
33485
33501
|
return elements
|
|
33486
33502
|
})()`;
|
|
33487
33503
|
}
|
|
33504
|
+
function isPeachAccessibilityTree(value) {
|
|
33505
|
+
if (!Array.isArray(value)) return false;
|
|
33506
|
+
return value.every((node) => {
|
|
33507
|
+
if (node === null || typeof node !== "object") return false;
|
|
33508
|
+
if (Reflect.get(node, "platform") !== "ios" && Reflect.get(node, "platform") !== "android")
|
|
33509
|
+
return false;
|
|
33510
|
+
if (typeof Reflect.get(node, "elementId") !== "string") return false;
|
|
33511
|
+
if (!Number.isInteger(Reflect.get(node, "nodeId"))) return false;
|
|
33512
|
+
for (const key of ["type", "role"]) {
|
|
33513
|
+
if (typeof Reflect.get(node, key) !== "string") return false;
|
|
33514
|
+
}
|
|
33515
|
+
for (const key of ["testID", "label", "hint", "value", "placeholder"]) {
|
|
33516
|
+
const field = Reflect.get(node, key);
|
|
33517
|
+
if (field !== null && typeof field !== "string") return false;
|
|
33518
|
+
}
|
|
33519
|
+
for (const key of [
|
|
33520
|
+
"isAccessibilityElement",
|
|
33521
|
+
"enabled",
|
|
33522
|
+
"selected",
|
|
33523
|
+
"checked",
|
|
33524
|
+
"clickable",
|
|
33525
|
+
"isTextInput"
|
|
33526
|
+
]) {
|
|
33527
|
+
if (typeof Reflect.get(node, key) !== "boolean") return false;
|
|
33528
|
+
}
|
|
33529
|
+
const hasFocus = Reflect.get(node, "hasFocus");
|
|
33530
|
+
if (hasFocus !== void 0 && typeof hasFocus !== "boolean") return false;
|
|
33531
|
+
const state = Reflect.get(node, "state");
|
|
33532
|
+
if (state !== null) {
|
|
33533
|
+
if (typeof state !== "object") return false;
|
|
33534
|
+
const checked = Reflect.get(state, "checked");
|
|
33535
|
+
if (typeof checked !== "boolean" && checked !== "mixed") return false;
|
|
33536
|
+
for (const key of ["disabled", "selected", "busy", "expanded"]) {
|
|
33537
|
+
if (typeof Reflect.get(state, key) !== "boolean") return false;
|
|
33538
|
+
}
|
|
33539
|
+
}
|
|
33540
|
+
const value2 = Reflect.get(node, "accessibilityValue");
|
|
33541
|
+
if (value2 !== null) {
|
|
33542
|
+
if (typeof value2 !== "object") return false;
|
|
33543
|
+
for (const key of ["min", "max", "now"]) {
|
|
33544
|
+
const field = Reflect.get(value2, key);
|
|
33545
|
+
if (field !== void 0 && (typeof field !== "number" || !Number.isFinite(field)))
|
|
33546
|
+
return false;
|
|
33547
|
+
}
|
|
33548
|
+
const text = Reflect.get(value2, "text");
|
|
33549
|
+
if (text !== void 0 && typeof text !== "string") return false;
|
|
33550
|
+
}
|
|
33551
|
+
if (!isSemanticGeometry(Reflect.get(node, "frame"))) return false;
|
|
33552
|
+
return isPeachAccessibilityTree(Reflect.get(node, "children"));
|
|
33553
|
+
});
|
|
33554
|
+
}
|
|
33488
33555
|
function waitReadyReason(status) {
|
|
33489
33556
|
if (status.bridgeError) {
|
|
33490
33557
|
if (status.bridgeError.includes(HEADLESS_TENANT_FETCH_HUNG_MARKER) || status.bridgeError.includes(PUBLIC_NO_NETWORK_MARKER)) {
|
|
@@ -34174,17 +34241,10 @@ function resolvePlaywright() {
|
|
|
34174
34241
|
const packageJsonPath = requireFromRoot.resolve(`${spec}/package.json`);
|
|
34175
34242
|
const parsed = JSON.parse((0, import_node_fs23.readFileSync)(packageJsonPath, "utf8"));
|
|
34176
34243
|
if (!isRecord(parsed) || typeof parsed.version !== "string") continue;
|
|
34177
|
-
const
|
|
34178
|
-
|
|
34179
|
-
|
|
34180
|
-
|
|
34181
|
-
} else if (isRecord(bin)) {
|
|
34182
|
-
const named = bin.playwright ?? bin["playwright-core"];
|
|
34183
|
-
const first = Object.values(bin).find((value) => typeof value === "string");
|
|
34184
|
-
binPath = typeof named === "string" ? named : typeof first === "string" ? first : null;
|
|
34185
|
-
}
|
|
34186
|
-
if (!binPath) continue;
|
|
34187
|
-
const cliPath = (0, import_node_path25.join)((0, import_node_path25.dirname)(packageJsonPath), binPath);
|
|
34244
|
+
const corePackagePath = (0, import_node_module5.createRequire)(modulePath).resolve(
|
|
34245
|
+
"playwright-core/package.json"
|
|
34246
|
+
);
|
|
34247
|
+
const cliPath = (0, import_node_path25.join)((0, import_node_path25.dirname)(corePackagePath), "cli.js");
|
|
34188
34248
|
if (!(0, import_node_fs23.existsSync)(cliPath)) continue;
|
|
34189
34249
|
return {
|
|
34190
34250
|
spec,
|
|
@@ -34393,6 +34453,7 @@ async function launch2(opts) {
|
|
|
34393
34453
|
env: {
|
|
34394
34454
|
...playwrightEnv,
|
|
34395
34455
|
SOOTSIM_PW_MODULE: resolved.modulePath,
|
|
34456
|
+
SOOTSIM_PW_EXECUTABLE: provisioning.executablePath,
|
|
34396
34457
|
SOOTSIM_PW_URL: opts.url,
|
|
34397
34458
|
SOOTSIM_PW_BRIDGE_PORT: opts.bridgePort ? String(opts.bridgePort) : "",
|
|
34398
34459
|
SOOTSIM_PW_HEADLESS: opts.headless ?? true ? "1" : "0",
|
|
@@ -37809,9 +37870,228 @@ function assertSupportedSelector(selector) {
|
|
|
37809
37870
|
if (unsupported.length > 0) {
|
|
37810
37871
|
throw new Error(`selector ${unsupported.join(", ")} is not supported by peach yet`);
|
|
37811
37872
|
}
|
|
37812
|
-
for (const key of ["childOf", "below", "above", "leftOf", "rightOf"]) {
|
|
37873
|
+
for (const key of ["childOf", "below", "above", "leftOf", "rightOf", "containsChild"]) {
|
|
37813
37874
|
assertSupportedSelector(Reflect.get(selector, key));
|
|
37814
37875
|
}
|
|
37876
|
+
const descendants = Reflect.get(selector, "containsDescendants");
|
|
37877
|
+
if (descendants !== void 0) {
|
|
37878
|
+
if (!Array.isArray(descendants)) {
|
|
37879
|
+
throw new Error("selector containsDescendants must be a list of selectors");
|
|
37880
|
+
}
|
|
37881
|
+
for (const descendant of descendants) assertSupportedSelector(descendant);
|
|
37882
|
+
}
|
|
37883
|
+
}
|
|
37884
|
+
function needsAccessibilityProjection(selector) {
|
|
37885
|
+
if (typeof selector === "string") return false;
|
|
37886
|
+
if (ACCESSIBILITY_SELECTOR_KEYS.some((key) => selector[key] != null)) return true;
|
|
37887
|
+
return ["childOf", "below", "above", "leftOf", "rightOf"].some((key) => {
|
|
37888
|
+
const nested = Reflect.get(selector, key);
|
|
37889
|
+
return isSelectorRecord(nested) && needsAccessibilityProjection(nested);
|
|
37890
|
+
});
|
|
37891
|
+
}
|
|
37892
|
+
function accessibilityTreeNodes(tree) {
|
|
37893
|
+
const out = [];
|
|
37894
|
+
const visit = (node) => {
|
|
37895
|
+
out.push(node);
|
|
37896
|
+
for (const child of node.children) visit(child);
|
|
37897
|
+
};
|
|
37898
|
+
for (const root of tree) visit(root);
|
|
37899
|
+
return out;
|
|
37900
|
+
}
|
|
37901
|
+
function accessibilitySubtreeNodes(node) {
|
|
37902
|
+
return [node, ...node.children.flatMap(accessibilitySubtreeNodes)];
|
|
37903
|
+
}
|
|
37904
|
+
function accessibilityTextMatcher(value, kind) {
|
|
37905
|
+
const pattern = new RegExp(`^(?:${value})$`);
|
|
37906
|
+
return (candidate) => {
|
|
37907
|
+
const native = candidate ?? "";
|
|
37908
|
+
if (kind === "id")
|
|
37909
|
+
return pattern.test(native) || pattern.test(native.slice(native.lastIndexOf("/") + 1));
|
|
37910
|
+
const stripped = native.replaceAll("\n", " ");
|
|
37911
|
+
return native === value || stripped === value || pattern.test(native) || pattern.test(stripped);
|
|
37912
|
+
};
|
|
37913
|
+
}
|
|
37914
|
+
function accessibilityBounds(node) {
|
|
37915
|
+
const left = Math.trunc(node.frame.x);
|
|
37916
|
+
const top = Math.trunc(node.frame.y);
|
|
37917
|
+
return {
|
|
37918
|
+
x: left,
|
|
37919
|
+
y: top,
|
|
37920
|
+
width: Math.trunc(node.frame.x + node.frame.width) - left,
|
|
37921
|
+
height: Math.trunc(node.frame.y + node.frame.height) - top
|
|
37922
|
+
};
|
|
37923
|
+
}
|
|
37924
|
+
function accessibilityBasicFilters(selector) {
|
|
37925
|
+
const filters = [];
|
|
37926
|
+
if (selector.text != null) {
|
|
37927
|
+
const matches = accessibilityTextMatcher(selector.text, "text");
|
|
37928
|
+
filters.push(
|
|
37929
|
+
(node) => matches(node.label) || matches(node.value) || matches(node.placeholder)
|
|
37930
|
+
);
|
|
37931
|
+
}
|
|
37932
|
+
if (selector.id != null) {
|
|
37933
|
+
const matches = accessibilityTextMatcher(selector.id, "id");
|
|
37934
|
+
filters.push((node) => matches(node.testID));
|
|
37935
|
+
}
|
|
37936
|
+
if (selector.width != null || selector.height != null) {
|
|
37937
|
+
const tolerance = selector.tolerance ?? 0;
|
|
37938
|
+
filters.push((node) => {
|
|
37939
|
+
const bounds = accessibilityBounds(node);
|
|
37940
|
+
return (selector.width == null || Math.abs(bounds.width - selector.width) <= tolerance) && (selector.height == null || Math.abs(bounds.height - selector.height) <= tolerance);
|
|
37941
|
+
});
|
|
37942
|
+
}
|
|
37943
|
+
for (const trait of selector.traits ? selector.traits.split(" ") : []) {
|
|
37944
|
+
const filter = ACCESSIBILITY_TRAIT_FILTERS[trait.replaceAll("-", "_").toUpperCase()];
|
|
37945
|
+
if (!filter) throw new Error(`unknown selector trait: ${trait}`);
|
|
37946
|
+
filters.push(filter);
|
|
37947
|
+
}
|
|
37948
|
+
if (selector.enabled != null) {
|
|
37949
|
+
filters.push((node) => node.enabled === selector.enabled);
|
|
37950
|
+
}
|
|
37951
|
+
if (selector.selected != null) {
|
|
37952
|
+
filters.push((node) => node.selected === selector.selected);
|
|
37953
|
+
}
|
|
37954
|
+
if (selector.checked != null) {
|
|
37955
|
+
filters.push((node) => node.checked === selector.checked);
|
|
37956
|
+
}
|
|
37957
|
+
if (selector.focused != null) {
|
|
37958
|
+
filters.push((node) => (node.hasFocus ?? false) === selector.focused);
|
|
37959
|
+
}
|
|
37960
|
+
return filters;
|
|
37961
|
+
}
|
|
37962
|
+
function deepestMatchingAccessibilityNodes(nodes, matches) {
|
|
37963
|
+
const out = [];
|
|
37964
|
+
const included = new Set(nodes);
|
|
37965
|
+
const nested = new Set(
|
|
37966
|
+
nodes.flatMap((node) => node.children.filter((child) => included.has(child)))
|
|
37967
|
+
);
|
|
37968
|
+
for (const node of nodes.filter((node2) => !nested.has(node2))) {
|
|
37969
|
+
const children = deepestMatchingAccessibilityNodes(node.children, matches);
|
|
37970
|
+
if (children.length > 0) out.push(...children);
|
|
37971
|
+
else if (matches(node)) out.push(node);
|
|
37972
|
+
}
|
|
37973
|
+
return distinctAccessibilityNodes(out);
|
|
37974
|
+
}
|
|
37975
|
+
function distinctAccessibilityNodes(nodes) {
|
|
37976
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
37977
|
+
return nodes.filter((node) => {
|
|
37978
|
+
const key = JSON.stringify([
|
|
37979
|
+
node.testID ?? "",
|
|
37980
|
+
node.label ?? "",
|
|
37981
|
+
node.placeholder ?? "",
|
|
37982
|
+
node.value ?? "",
|
|
37983
|
+
node.enabled,
|
|
37984
|
+
node.selected,
|
|
37985
|
+
node.checked,
|
|
37986
|
+
node.clickable,
|
|
37987
|
+
node.hasFocus ?? false,
|
|
37988
|
+
accessibilityBounds(node),
|
|
37989
|
+
node.children.length
|
|
37990
|
+
]);
|
|
37991
|
+
const bucket = buckets.get(key);
|
|
37992
|
+
if (bucket?.some((other) => sameNativeAccessibilityShape(node, other))) return false;
|
|
37993
|
+
if (bucket) bucket.push(node);
|
|
37994
|
+
else buckets.set(key, [node]);
|
|
37995
|
+
return true;
|
|
37996
|
+
});
|
|
37997
|
+
}
|
|
37998
|
+
function isSelectorRecord(value) {
|
|
37999
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
38000
|
+
}
|
|
38001
|
+
function accessibilityAnchorSelector(value) {
|
|
38002
|
+
if (typeof value === "string") return { text: value };
|
|
38003
|
+
return isSelectorRecord(value) ? value : {};
|
|
38004
|
+
}
|
|
38005
|
+
function sameNativeAccessibilityShape(a, b) {
|
|
38006
|
+
if ((a.testID ?? "") !== (b.testID ?? "") || (a.label ?? "") !== (b.label ?? "") || (a.placeholder ?? "") !== (b.placeholder ?? "") || (a.value ?? "") !== (b.value ?? "") || a.enabled !== b.enabled || a.selected !== b.selected || a.checked !== b.checked || a.clickable !== b.clickable || (a.hasFocus ?? false) !== (b.hasFocus ?? false) || JSON.stringify(accessibilityBounds(a)) !== JSON.stringify(accessibilityBounds(b)) || a.children.length !== b.children.length) {
|
|
38007
|
+
return false;
|
|
38008
|
+
}
|
|
38009
|
+
for (const [index, child] of a.children.entries()) {
|
|
38010
|
+
const other = b.children[index];
|
|
38011
|
+
if (!other || !sameNativeAccessibilityShape(child, other)) return false;
|
|
38012
|
+
}
|
|
38013
|
+
return true;
|
|
38014
|
+
}
|
|
38015
|
+
function accessibilitySubtreeMatches(all, node, selector) {
|
|
38016
|
+
if (filterAccessibilityNodes(all, [node], selector).length > 0) return true;
|
|
38017
|
+
return node.children.some((child) => accessibilitySubtreeMatches(all, child, selector));
|
|
38018
|
+
}
|
|
38019
|
+
function filterAccessibilityNodes(all, nodes, selector) {
|
|
38020
|
+
if (selector.childOf == null) {
|
|
38021
|
+
return filterAccessibilityNodesIn(all, nodes, selector);
|
|
38022
|
+
}
|
|
38023
|
+
const container = filterAccessibilityNodes(
|
|
38024
|
+
all,
|
|
38025
|
+
all,
|
|
38026
|
+
accessibilityAnchorSelector(selector.childOf)
|
|
38027
|
+
)[0];
|
|
38028
|
+
if (!container) return [];
|
|
38029
|
+
return filterAccessibilityNodesIn(all, accessibilitySubtreeNodes(container), selector);
|
|
38030
|
+
}
|
|
38031
|
+
function filterAccessibilityNodesIn(all, nodes, selector) {
|
|
38032
|
+
const basic = accessibilityBasicFilters(selector);
|
|
38033
|
+
let candidates = basic.length > 0 ? deepestMatchingAccessibilityNodes(
|
|
38034
|
+
nodes,
|
|
38035
|
+
(node) => basic.every((filter) => filter(node))
|
|
38036
|
+
) : [...nodes];
|
|
38037
|
+
const relativeGeometry = {
|
|
38038
|
+
below: (node, other) => accessibilityBounds(node).y > accessibilityBounds(other).y,
|
|
38039
|
+
above: (node, other) => accessibilityBounds(node).y < accessibilityBounds(other).y,
|
|
38040
|
+
leftOf: (node, other) => accessibilityBounds(node).x < accessibilityBounds(other).x,
|
|
38041
|
+
rightOf: (node, other) => accessibilityBounds(node).x > accessibilityBounds(other).x
|
|
38042
|
+
};
|
|
38043
|
+
for (const key of ["below", "above", "leftOf", "rightOf"]) {
|
|
38044
|
+
const anchor = selector[key];
|
|
38045
|
+
if (anchor == null) continue;
|
|
38046
|
+
const anchors = filterAccessibilityNodes(
|
|
38047
|
+
all,
|
|
38048
|
+
nodes,
|
|
38049
|
+
accessibilityAnchorSelector(anchor)
|
|
38050
|
+
);
|
|
38051
|
+
candidates = candidates.filter(
|
|
38052
|
+
(node) => anchors.some((other) => relativeGeometry[key](node, other))
|
|
38053
|
+
);
|
|
38054
|
+
}
|
|
38055
|
+
if (selector.containsChild != null) {
|
|
38056
|
+
const child = filterAccessibilityNodes(
|
|
38057
|
+
all,
|
|
38058
|
+
all,
|
|
38059
|
+
accessibilityAnchorSelector(selector.containsChild)
|
|
38060
|
+
)[0];
|
|
38061
|
+
candidates = child ? candidates.filter(
|
|
38062
|
+
(node) => node.children.some(
|
|
38063
|
+
(candidate) => sameNativeAccessibilityShape(candidate, child)
|
|
38064
|
+
)
|
|
38065
|
+
) : [];
|
|
38066
|
+
}
|
|
38067
|
+
if (selector.containsDescendants != null) {
|
|
38068
|
+
const descendants = selector.containsDescendants.map(accessibilityAnchorSelector);
|
|
38069
|
+
candidates = candidates.filter(
|
|
38070
|
+
(node) => descendants.every(
|
|
38071
|
+
(descendant) => node.children.some(
|
|
38072
|
+
(child) => accessibilitySubtreeMatches(all, child, descendant)
|
|
38073
|
+
)
|
|
38074
|
+
)
|
|
38075
|
+
);
|
|
38076
|
+
}
|
|
38077
|
+
candidates = distinctAccessibilityNodes(candidates);
|
|
38078
|
+
if (selector.index != null) {
|
|
38079
|
+
const index = Math.trunc(Number(selector.index));
|
|
38080
|
+
const sorted = [...candidates].sort((a, b) => {
|
|
38081
|
+
const aBounds = accessibilityBounds(a);
|
|
38082
|
+
const bBounds = accessibilityBounds(b);
|
|
38083
|
+
return aBounds.y - bBounds.y || aBounds.x - bBounds.x;
|
|
38084
|
+
});
|
|
38085
|
+
const resolved = index >= 0 ? index : sorted.length + index;
|
|
38086
|
+
if (resolved < 0 || resolved >= sorted.length) return [];
|
|
38087
|
+
const picked = sorted[resolved];
|
|
38088
|
+
return picked ? [picked] : [];
|
|
38089
|
+
}
|
|
38090
|
+
return [...candidates].sort((a, b) => Number(b.clickable) - Number(a.clickable));
|
|
38091
|
+
}
|
|
38092
|
+
function resolveAccessibilitySelector(tree, selector) {
|
|
38093
|
+
const all = accessibilityTreeNodes(tree);
|
|
38094
|
+
return filterAccessibilityNodes(all, all, selector)[0] ?? null;
|
|
37815
38095
|
}
|
|
37816
38096
|
function isObjectRecord(value) {
|
|
37817
38097
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
@@ -37920,7 +38200,7 @@ function parseFlowSteps(content) {
|
|
|
37920
38200
|
const parsed = import_yaml2.default.parse(candidate);
|
|
37921
38201
|
return Array.isArray(parsed) ? parsed : [];
|
|
37922
38202
|
}
|
|
37923
|
-
var fs20, path20, import_devices4, import_yaml2, import_proof_frame, DEFAULT_TIMEOUT, ASSERTION_LOOKUP_MS, FLOW_TIMEOUT_SCALE, scaledTimeout, MAESTRO_SELECTOR_KEYS, SELECTOR_FILTER_KEYS, UNSUPPORTED_SELECTOR_KEYS, MAESTRO_PERMISSION_KINDS, MAESTRO_PERMISSION_STATUS, SootSimBridgeFlowRunner;
|
|
38203
|
+
var fs20, path20, import_devices4, import_yaml2, import_proof_frame, DEFAULT_TIMEOUT, ASSERTION_LOOKUP_MS, FLOW_TIMEOUT_SCALE, scaledTimeout, MAESTRO_SELECTOR_KEYS, SELECTOR_FILTER_KEYS, UNSUPPORTED_SELECTOR_KEYS, ACCESSIBILITY_SELECTOR_KEYS, ACCESSIBILITY_TRAIT_FILTERS, MAESTRO_PERMISSION_KINDS, MAESTRO_PERMISSION_STATUS, SootSimBridgeFlowRunner;
|
|
37924
38204
|
var init_bridge_flow_runner = __esm({
|
|
37925
38205
|
"cli/bridge-flow-runner.ts"() {
|
|
37926
38206
|
"use strict";
|
|
@@ -37987,12 +38267,21 @@ var init_bridge_flow_runner = __esm({
|
|
|
37987
38267
|
"leftOf",
|
|
37988
38268
|
"rightOf"
|
|
37989
38269
|
];
|
|
37990
|
-
UNSUPPORTED_SELECTOR_KEYS = [
|
|
38270
|
+
UNSUPPORTED_SELECTOR_KEYS = ["css"];
|
|
38271
|
+
ACCESSIBILITY_SELECTOR_KEYS = [
|
|
37991
38272
|
"containsChild",
|
|
37992
38273
|
"containsDescendants",
|
|
37993
|
-
"focused"
|
|
37994
|
-
"css"
|
|
38274
|
+
"focused"
|
|
37995
38275
|
];
|
|
38276
|
+
ACCESSIBILITY_TRAIT_FILTERS = {
|
|
38277
|
+
// IOSDriver sets attributes["text"] on every node, including empty text.
|
|
38278
|
+
TEXT: () => true,
|
|
38279
|
+
SQUARE: (node) => {
|
|
38280
|
+
const bounds = accessibilityBounds(node);
|
|
38281
|
+
return Math.abs(1 - bounds.width / bounds.height) < 0.03;
|
|
38282
|
+
},
|
|
38283
|
+
LONG_TEXT: (node) => (node.value?.length ?? 0) > 200
|
|
38284
|
+
};
|
|
37996
38285
|
MAESTRO_PERMISSION_KINDS = {
|
|
37997
38286
|
all: PERMISSION_KINDS,
|
|
37998
38287
|
bluetooth: ["bluetooth"],
|
|
@@ -38275,6 +38564,9 @@ var init_bridge_flow_runner = __esm({
|
|
|
38275
38564
|
}
|
|
38276
38565
|
async findElement(opts) {
|
|
38277
38566
|
assertSupportedSelector(opts);
|
|
38567
|
+
if (needsAccessibilityProjection(opts)) {
|
|
38568
|
+
return this.findElementAccessibilityTree(opts);
|
|
38569
|
+
}
|
|
38278
38570
|
if (opts.id != null || opts.index != null || opts.text != null && /[.*+?^$()[\]{}|\\]/.test(opts.text) || SELECTOR_FILTER_KEYS.some((key) => opts[key] != null)) {
|
|
38279
38571
|
return this.findElementScoped(opts);
|
|
38280
38572
|
}
|
|
@@ -38307,6 +38599,46 @@ var init_bridge_flow_runner = __esm({
|
|
|
38307
38599
|
}
|
|
38308
38600
|
})()`);
|
|
38309
38601
|
}
|
|
38602
|
+
// structural filters (containsChild / containsDescendants / focused) read the
|
|
38603
|
+
// engine's XCTest accessibility projection — one bridge evaluate, then the
|
|
38604
|
+
// same Orchestra.buildFilter semantics the render resolver implements, over
|
|
38605
|
+
// PeachAccessibilityNode instead of the visible semantic tree.
|
|
38606
|
+
async findElementAccessibilityTree(opts) {
|
|
38607
|
+
const tree = await this.evaluate(`(async () => {
|
|
38608
|
+
const test = window.__sootsimTest
|
|
38609
|
+
if (!test || typeof test.captureAccessibilityTree !== 'function') throw new Error('engine accessibility snapshot is unavailable')
|
|
38610
|
+
return await test.captureAccessibilityTree()
|
|
38611
|
+
})()`);
|
|
38612
|
+
if (!isPeachAccessibilityTree(tree))
|
|
38613
|
+
throw new Error("engine returned an invalid accessibility snapshot");
|
|
38614
|
+
if (tree.length === 0) return null;
|
|
38615
|
+
if (tree.some((node2) => node2.platform !== "ios"))
|
|
38616
|
+
throw new Error(
|
|
38617
|
+
"containsChild, containsDescendants and focused require the iOS accessibility hierarchy"
|
|
38618
|
+
);
|
|
38619
|
+
const node = resolveAccessibilitySelector(tree, opts);
|
|
38620
|
+
if (!node) return null;
|
|
38621
|
+
const frame = node.frame;
|
|
38622
|
+
return {
|
|
38623
|
+
nodeId: Number.isFinite(node.nodeId) ? node.nodeId : null,
|
|
38624
|
+
id: node.testID,
|
|
38625
|
+
testID: node.testID,
|
|
38626
|
+
text: node.label,
|
|
38627
|
+
accessibilityLabel: node.label,
|
|
38628
|
+
absolutePosition: { x: frame.x, y: frame.y },
|
|
38629
|
+
layout: { width: frame.width, height: frame.height },
|
|
38630
|
+
// the engine applies Maestro's integer-frame viewport filter to the
|
|
38631
|
+
// native hierarchy before this lookup; preserve the native bounds.
|
|
38632
|
+
visibleFrame: {
|
|
38633
|
+
x: frame.x,
|
|
38634
|
+
y: frame.y,
|
|
38635
|
+
width: frame.width,
|
|
38636
|
+
height: frame.height,
|
|
38637
|
+
area: frame.width * frame.height
|
|
38638
|
+
},
|
|
38639
|
+
isTextInput: node.isTextInput
|
|
38640
|
+
};
|
|
38641
|
+
}
|
|
38310
38642
|
// maestro's selector resolver (Orchestra.buildFilter over Filters.kt):
|
|
38311
38643
|
// id and text patterns, size, traits, enabled/selected, the relative
|
|
38312
38644
|
// below/above/leftOf/rightOf filters, `index:` (nth match) and `childOf:`
|
|
@@ -38669,7 +39001,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
38669
39001
|
break;
|
|
38670
39002
|
}
|
|
38671
39003
|
}
|
|
38672
|
-
const narrowed = opts.index != null || SELECTOR_FILTER_KEYS.some((key) => opts[key] != null);
|
|
39004
|
+
const narrowed = opts.index != null || SELECTOR_FILTER_KEYS.some((key) => opts[key] != null) || ACCESSIBILITY_SELECTOR_KEYS.some((key) => opts[key] != null);
|
|
38673
39005
|
const direct = element || !narrowed ? await this.activatePressTarget(opts) : null;
|
|
38674
39006
|
if (direct?.ok) {
|
|
38675
39007
|
await this.settleAfterInput();
|