peachsim 0.1.637 → 0.1.639
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/command-registry.ts +1 -0
- package/cli/commands/control.ts +42 -5
- package/cli/commands/inspect/core.ts +93 -24
- package/cli/commands/maestro.ts +2 -2
- package/cli/commands/serve.ts +13 -1
- package/cli/commands/swift.ts +326 -0
- 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/cli/main.ts +11 -0
- package/cli/outbound-endpoints.ts +5 -1
- 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 +88 -23
- 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 +441 -94
- 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 +89 -8
- package/dist-lib/swift-submit.mjs +78 -8
- package/dist-lib/swift.cjs +16 -33220
- package/dist-lib/vite-swift.cjs +510 -253
- package/dist-lib/vite.cjs +13 -4
- package/package.json +1 -1
- package/skills/contrast/SKILL.md +1 -0
- package/src/assetCatalogContract.ts +16 -0
- 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/metro-runtime-source.ts +15 -0
- package/src/native-seam-manifest.ts +4 -6
- package/src/swift-compile.ts +105 -9
- package/src/swift-guest.ts +51 -0
- package/src/swift-host.ts +900 -0
- package/src/swift-submit.ts +97 -6
- package/src/swift.ts +36 -8
- package/src/swiftContract.ts +52 -0
- package/src/vite-plugin-one.ts +4 -3
- package/src/vite-plugin-swift.ts +43 -755
package/dist-lib/skills.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.639 | (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",
|
|
@@ -4445,6 +4447,8 @@ var init_supported_native_packages = __esm({
|
|
|
4445
4447
|
// seam
|
|
4446
4448
|
"@metamask/native-utils",
|
|
4447
4449
|
// seam+coverage
|
|
4450
|
+
"@metamask/react-native-search-api",
|
|
4451
|
+
// seam+coverage
|
|
4448
4452
|
"@metamask/react-native-webview",
|
|
4449
4453
|
// seam
|
|
4450
4454
|
"@mhpdev/react-native-haptics",
|
|
@@ -4491,6 +4495,8 @@ var init_supported_native_packages = __esm({
|
|
|
4491
4495
|
// seam+coverage
|
|
4492
4496
|
"@react-native-community/progress-view",
|
|
4493
4497
|
// seam
|
|
4498
|
+
"@react-native-community/push-notification-ios",
|
|
4499
|
+
// seam
|
|
4494
4500
|
"@react-native-community/slider",
|
|
4495
4501
|
// coverage
|
|
4496
4502
|
"@react-native-cookies/cookies",
|
|
@@ -4590,7 +4596,7 @@ var init_supported_native_packages = __esm({
|
|
|
4590
4596
|
"appcenter-analytics",
|
|
4591
4597
|
// seam
|
|
4592
4598
|
"burnt",
|
|
4593
|
-
// coverage
|
|
4599
|
+
// seam+coverage
|
|
4594
4600
|
"customerio-reactnative",
|
|
4595
4601
|
// seam
|
|
4596
4602
|
"expo",
|
|
@@ -4803,6 +4809,8 @@ var init_supported_native_packages = __esm({
|
|
|
4803
4809
|
// coverage
|
|
4804
4810
|
"react-native-auto-skeleton",
|
|
4805
4811
|
// seam
|
|
4812
|
+
"react-native-background-fetch",
|
|
4813
|
+
// seam+coverage
|
|
4806
4814
|
"react-native-background-geolocation",
|
|
4807
4815
|
// seam
|
|
4808
4816
|
"react-native-background-timer",
|
|
@@ -4811,8 +4819,12 @@ var init_supported_native_packages = __esm({
|
|
|
4811
4819
|
// seam
|
|
4812
4820
|
"react-native-barcode-creator",
|
|
4813
4821
|
// seam
|
|
4822
|
+
"react-native-biometrics",
|
|
4823
|
+
// seam+coverage
|
|
4814
4824
|
"react-native-blasted-image",
|
|
4815
4825
|
// seam
|
|
4826
|
+
"react-native-ble-plx",
|
|
4827
|
+
// seam
|
|
4816
4828
|
"react-native-blob-util",
|
|
4817
4829
|
// coverage
|
|
4818
4830
|
"react-native-blue-crypto",
|
|
@@ -4905,6 +4917,8 @@ var init_supported_native_packages = __esm({
|
|
|
4905
4917
|
// seam
|
|
4906
4918
|
"react-native-fs",
|
|
4907
4919
|
// coverage
|
|
4920
|
+
"react-native-geolocation-service",
|
|
4921
|
+
// seam
|
|
4908
4922
|
"react-native-gesture-handler",
|
|
4909
4923
|
// preset+semantic-proof+seam+coverage
|
|
4910
4924
|
"react-native-get-device-locale",
|
|
@@ -4912,7 +4926,7 @@ var init_supported_native_packages = __esm({
|
|
|
4912
4926
|
"react-native-get-location",
|
|
4913
4927
|
// seam+coverage
|
|
4914
4928
|
"react-native-get-random-values",
|
|
4915
|
-
// coverage
|
|
4929
|
+
// seam+coverage
|
|
4916
4930
|
"react-native-google-places",
|
|
4917
4931
|
// seam
|
|
4918
4932
|
"react-native-google-play-install-referrer",
|
|
@@ -4987,8 +5001,12 @@ var init_supported_native_packages = __esm({
|
|
|
4987
5001
|
// seam+coverage
|
|
4988
5002
|
"react-native-navigation",
|
|
4989
5003
|
// seam
|
|
5004
|
+
"react-native-nfc-manager",
|
|
5005
|
+
// seam
|
|
4990
5006
|
"react-native-nitro-buffer",
|
|
4991
5007
|
// seam+coverage
|
|
5008
|
+
"react-native-nitro-cookies",
|
|
5009
|
+
// seam
|
|
4992
5010
|
"react-native-nitro-device-info",
|
|
4993
5011
|
// seam
|
|
4994
5012
|
"react-native-nitro-fetch",
|
|
@@ -5080,7 +5098,7 @@ var init_supported_native_packages = __esm({
|
|
|
5080
5098
|
"react-native-record-screen",
|
|
5081
5099
|
// seam
|
|
5082
5100
|
"react-native-restart",
|
|
5083
|
-
// coverage
|
|
5101
|
+
// seam+coverage
|
|
5084
5102
|
"react-native-restart-newarch",
|
|
5085
5103
|
// coverage
|
|
5086
5104
|
"react-native-rsa-native",
|
|
@@ -5141,6 +5159,8 @@ var init_supported_native_packages = __esm({
|
|
|
5141
5159
|
// seam
|
|
5142
5160
|
"react-native-sqlite-2",
|
|
5143
5161
|
// seam
|
|
5162
|
+
"react-native-sqlite-storage",
|
|
5163
|
+
// seam+coverage
|
|
5144
5164
|
"react-native-stallion",
|
|
5145
5165
|
// seam
|
|
5146
5166
|
"react-native-store-age-signals-native-modules",
|
|
@@ -6624,7 +6644,7 @@ var init_registry = __esm({
|
|
|
6624
6644
|
{
|
|
6625
6645
|
range: ">=0.1.0",
|
|
6626
6646
|
coverage: 0.9,
|
|
6627
|
-
note: "
|
|
6647
|
+
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
6648
|
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
6649
|
missing: "drag-to-dismiss gesture interaction on iOS toast, Android message/icon/haptic/layout customization because upstream Android Burnt ignores those fields"
|
|
6630
6650
|
}
|
|
@@ -6868,10 +6888,10 @@ var init_registry = __esm({
|
|
|
6868
6888
|
versions: [
|
|
6869
6889
|
{
|
|
6870
6890
|
range: ">=4.4.0",
|
|
6871
|
-
coverage: 0.
|
|
6872
|
-
note: "
|
|
6873
|
-
working: "
|
|
6874
|
-
missing: "
|
|
6891
|
+
coverage: 0.9,
|
|
6892
|
+
note: "native-seam: index.js runs unchanged from the bundle; only the RNBackgroundFetch module is ours, answering as TSBackgroundFetch does on the iOS simulator: configure/start/status resolve UIBackgroundRefreshStatusAvailable (2), scheduleTask rejects because BGTaskScheduler is unavailable (or the identifier is not in BGTaskSchedulerPermittedIdentifiers), and no fetch event fires, as none fires on the simulator without Xcode",
|
|
6893
|
+
working: "configure, start, stop, finish, status (promise and callback forms), scheduleTask rejection with the simulator message, the real STATUS_* and NETWORK_TYPE_* constants and NativeEventEmitter wiring",
|
|
6894
|
+
missing: "Xcode's Simulate Background Fetch has no Peach equivalent; Android mode answers as iOS (headless tasks, JobScheduler)"
|
|
6875
6895
|
}
|
|
6876
6896
|
]
|
|
6877
6897
|
},
|
|
@@ -7515,9 +7535,9 @@ var init_registry = __esm({
|
|
|
7515
7535
|
{
|
|
7516
7536
|
range: ">=5.0.0",
|
|
7517
7537
|
coverage: 0.8,
|
|
7518
|
-
note: "
|
|
7519
|
-
working: "
|
|
7520
|
-
missing: "
|
|
7538
|
+
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",
|
|
7539
|
+
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",
|
|
7540
|
+
missing: "desiredAccuracy levels (the browser fix has one accuracy), significant-change monitoring, background updates"
|
|
7521
7541
|
}
|
|
7522
7542
|
]
|
|
7523
7543
|
},
|
|
@@ -7528,9 +7548,9 @@ var init_registry = __esm({
|
|
|
7528
7548
|
{
|
|
7529
7549
|
range: ">=1.0.0",
|
|
7530
7550
|
coverage: 0.85,
|
|
7531
|
-
note: "
|
|
7532
|
-
working: "
|
|
7533
|
-
missing: "
|
|
7551
|
+
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",
|
|
7552
|
+
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",
|
|
7553
|
+
missing: "repeating calendar triggers other than daily and weekly, notification attachments, the fetch completion handler of a background push"
|
|
7534
7554
|
}
|
|
7535
7555
|
]
|
|
7536
7556
|
},
|
|
@@ -7712,9 +7732,9 @@ var init_registry = __esm({
|
|
|
7712
7732
|
{
|
|
7713
7733
|
range: ">=13.0.0",
|
|
7714
7734
|
coverage: 0.95,
|
|
7715
|
-
note:
|
|
7716
|
-
working: "
|
|
7717
|
-
missing: "
|
|
7735
|
+
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.",
|
|
7736
|
+
working: "hasHardwareAsync, isEnrolledAsync, supportedAuthenticationTypesAsync, getEnrolledLevelAsync, authenticateAsync biometric-only errors; UnavailabilityError for cancelAuthenticate on iOS",
|
|
7737
|
+
missing: "the system passcode sheet for device-fallback authentication, which settles as the sheet close button does (user_cancel)"
|
|
7718
7738
|
}
|
|
7719
7739
|
]
|
|
7720
7740
|
},
|
|
@@ -7796,19 +7816,19 @@ var init_registry = __esm({
|
|
|
7796
7816
|
usage: 3,
|
|
7797
7817
|
importance: 3,
|
|
7798
7818
|
estimate: 1,
|
|
7799
|
-
rationale: "the
|
|
7819
|
+
rationale: "the published side-effect polyfill runs unchanged over the RNGetRandomValues module"
|
|
7800
7820
|
},
|
|
7801
7821
|
{
|
|
7802
7822
|
id: "load-safe-fallback",
|
|
7803
7823
|
usage: 1,
|
|
7804
7824
|
importance: 1,
|
|
7805
7825
|
estimate: 1,
|
|
7806
|
-
rationale: "
|
|
7826
|
+
rationale: "an existing crypto.getRandomValues stays in place, as upstream leaves it"
|
|
7807
7827
|
}
|
|
7808
7828
|
],
|
|
7809
7829
|
capabilityCoverage: CAPABILITY_INVENTORY_PACKAGE_COVERAGE["react-native-get-random-values"],
|
|
7810
|
-
note: "
|
|
7811
|
-
working: "
|
|
7830
|
+
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",
|
|
7831
|
+
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
7832
|
}
|
|
7813
7833
|
]
|
|
7814
7834
|
},
|
|
@@ -7962,10 +7982,10 @@ var init_registry = __esm({
|
|
|
7962
7982
|
versions: [
|
|
7963
7983
|
{
|
|
7964
7984
|
range: ">=1.0.0",
|
|
7965
|
-
coverage: 0.
|
|
7966
|
-
note: "
|
|
7967
|
-
working: "
|
|
7968
|
-
missing: "
|
|
7985
|
+
coverage: 0.9,
|
|
7986
|
+
note: "native-seam: index.js runs unchanged from the bundle; only SearchApiManager is ours, resolving every index, delete and user-activity call as CoreSpotlight completes them on the iOS simulator",
|
|
7987
|
+
working: "indexSpotlightItem(s), deleteSpotlightItemsWithIdentifiers/InDomains, deleteAllSpotlightItems, indexAppHistoryItem, and the real event emitter wiring",
|
|
7988
|
+
missing: "Peach has no Spotlight search or Handoff, so spotlightSearchItemTapped and appHistorySearchItemTapped never fire"
|
|
7969
7989
|
}
|
|
7970
7990
|
]
|
|
7971
7991
|
},
|
|
@@ -8186,8 +8206,8 @@ var init_registry = __esm({
|
|
|
8186
8206
|
{
|
|
8187
8207
|
range: ">=0.0.1",
|
|
8188
8208
|
coverage: 1,
|
|
8189
|
-
note: "
|
|
8190
|
-
working: "restart(), Restart() (
|
|
8209
|
+
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",
|
|
8210
|
+
working: "restart(), Restart() and getReason() from the published JS"
|
|
8191
8211
|
}
|
|
8192
8212
|
]
|
|
8193
8213
|
},
|
|
@@ -8249,10 +8269,10 @@ var init_registry = __esm({
|
|
|
8249
8269
|
versions: [
|
|
8250
8270
|
{
|
|
8251
8271
|
range: ">=3.0.0",
|
|
8252
|
-
coverage: 0.
|
|
8253
|
-
note: "
|
|
8254
|
-
working: "
|
|
8255
|
-
missing: "
|
|
8272
|
+
coverage: 0.9,
|
|
8273
|
+
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",
|
|
8274
|
+
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",
|
|
8275
|
+
missing: "the system passcode sheet for allowDeviceCredentials prompts, which settle as the sheet close button does"
|
|
8256
8276
|
}
|
|
8257
8277
|
]
|
|
8258
8278
|
},
|
|
@@ -8577,9 +8597,9 @@ var init_registry = __esm({
|
|
|
8577
8597
|
{
|
|
8578
8598
|
range: ">=8.0.0",
|
|
8579
8599
|
coverage: 0.6,
|
|
8580
|
-
note: "
|
|
8581
|
-
working: "configure
|
|
8582
|
-
missing: "
|
|
8600
|
+
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)",
|
|
8601
|
+
working: "configure, localNotification, localNotificationSchedule, permissions, badge, scheduled and delivered queries and cancellation, all through the published iOS path",
|
|
8602
|
+
missing: "the Android RNPushNotification module for Android mode"
|
|
8583
8603
|
}
|
|
8584
8604
|
]
|
|
8585
8605
|
},
|
|
@@ -8970,9 +8990,9 @@ var init_registry = __esm({
|
|
|
8970
8990
|
{
|
|
8971
8991
|
range: ">=3.0.0",
|
|
8972
8992
|
coverage: 0.85,
|
|
8973
|
-
note: "
|
|
8974
|
-
working: "default createResizedImage export,
|
|
8975
|
-
missing: "
|
|
8993
|
+
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",
|
|
8994
|
+
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",
|
|
8995
|
+
missing: "EXIF metadata preservation for keepMeta, the RCTLogError red box on a failure"
|
|
8976
8996
|
}
|
|
8977
8997
|
]
|
|
8978
8998
|
},
|
|
@@ -9112,11 +9132,11 @@ var init_registry = __esm({
|
|
|
9112
9132
|
stubType: "native",
|
|
9113
9133
|
versions: [
|
|
9114
9134
|
{
|
|
9115
|
-
range: ">=1.
|
|
9135
|
+
range: ">=1.2.0",
|
|
9116
9136
|
coverage: 0.85,
|
|
9117
|
-
note: "
|
|
9118
|
-
working: "
|
|
9119
|
-
missing: "
|
|
9137
|
+
note: "native-seam: the package's JS runs unchanged from the bundle; only the NitroCookies hybrid object is ours, following NitroCookies.swift over the app's one cookie jar (shared with @react-native-cookies/cookies): HTTPCookieStorage and a separate WebKit store, the Swift domain-only matching, fractional-seconds-only expiry parsing, the 400-day expiry cap, httpOnly cookies gaining a dotted domain, and the NSError descriptions Nitro hands to JS",
|
|
9138
|
+
working: "every sync and async method: get/getSync, set/setSync, setMany/setManySync, getCookieHeader/getCookieHeaderSync, setFromResponse/setFromResponseSync, clearByName/clearByNameSync, getAll, clearAll, flush, removeSessionCookies, with useWebKit",
|
|
9139
|
+
missing: "getFromResponse makes the request but returns no cookies (a browser fetch hides Set-Cookie); the jar's iteration order for getAll and the Cookie header follows insertion, where HTTPCookieStorage orders by its own rule; the jar is not the one fetch sends"
|
|
9120
9140
|
}
|
|
9121
9141
|
]
|
|
9122
9142
|
},
|
|
@@ -9196,22 +9216,6 @@ var init_registry = __esm({
|
|
|
9196
9216
|
}
|
|
9197
9217
|
]
|
|
9198
9218
|
},
|
|
9199
|
-
"@welldone-software/why-did-you-render": {
|
|
9200
|
-
category: "Device & Platform",
|
|
9201
|
-
// pure JS (no native code), but deliberately intercepted: see the note
|
|
9202
|
-
// below. do not "restore the real package" — it patches React internals
|
|
9203
|
-
// and takes the bridged React down with it.
|
|
9204
|
-
stubType: "native",
|
|
9205
|
-
shipsNativeCode: false,
|
|
9206
|
-
versions: [
|
|
9207
|
-
{
|
|
9208
|
-
range: ">=8.0.0",
|
|
9209
|
-
coverage: 0,
|
|
9210
|
-
note: "the reference iOS simulator performs this package's behavior. Peach currently provides only this unsupported shape: intentional noop : wdyr mutates React internals and crashes sootsim's bridged React. imports and API shape receive no behavior credit",
|
|
9211
|
-
working: "default export callable as wdyr(React, opts) without error"
|
|
9212
|
-
}
|
|
9213
|
-
]
|
|
9214
|
-
},
|
|
9215
9219
|
"react-native-pure-jwt": {
|
|
9216
9220
|
category: "Auth & Payments",
|
|
9217
9221
|
stubType: "native",
|
|
@@ -9891,10 +9895,10 @@ var init_registry = __esm({
|
|
|
9891
9895
|
versions: [
|
|
9892
9896
|
{
|
|
9893
9897
|
range: ">=6.0.0",
|
|
9894
|
-
coverage: 0.
|
|
9895
|
-
note: "
|
|
9896
|
-
working: "
|
|
9897
|
-
missing: "
|
|
9898
|
+
coverage: 0.9,
|
|
9899
|
+
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",
|
|
9900
|
+
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",
|
|
9901
|
+
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
9902
|
}
|
|
9899
9903
|
]
|
|
9900
9904
|
},
|
|
@@ -11127,9 +11131,9 @@ var init_registry = __esm({
|
|
|
11127
11131
|
{
|
|
11128
11132
|
range: ">=4.0.0",
|
|
11129
11133
|
coverage: 0.85,
|
|
11130
|
-
note: "native-seam: the
|
|
11131
|
-
working: "isSupported(config) and authenticate(reason, config)
|
|
11132
|
-
missing: "
|
|
11134
|
+
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.",
|
|
11135
|
+
working: "isSupported(config) and authenticate(reason, config) through the passcodeFallback branches of TouchID.m, with the upstream TouchIDError mapping",
|
|
11136
|
+
missing: "the system passcode sheet for passcodeFallback authentication, which settles as the sheet close button does (LAErrorUserCancel)"
|
|
11133
11137
|
}
|
|
11134
11138
|
]
|
|
11135
11139
|
},
|
|
@@ -12785,7 +12789,7 @@ var init_registry = __esm({
|
|
|
12785
12789
|
coverage: 0.85,
|
|
12786
12790
|
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
12791
|
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
|
|
12792
|
+
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
12793
|
}
|
|
12790
12794
|
]
|
|
12791
12795
|
},
|
|
@@ -13286,9 +13290,9 @@ var init_registry = __esm({
|
|
|
13286
13290
|
{
|
|
13287
13291
|
range: ">=2.0.0",
|
|
13288
13292
|
coverage: 0.85,
|
|
13289
|
-
note:
|
|
13290
|
-
working: "BleManager
|
|
13291
|
-
missing: "
|
|
13293
|
+
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",
|
|
13294
|
+
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",
|
|
13295
|
+
missing: "a real Bluetooth radio, which the iOS simulator does not have either"
|
|
13292
13296
|
}
|
|
13293
13297
|
]
|
|
13294
13298
|
},
|
|
@@ -13299,9 +13303,9 @@ var init_registry = __esm({
|
|
|
13299
13303
|
{
|
|
13300
13304
|
range: ">=3.0.0",
|
|
13301
13305
|
coverage: 0.85,
|
|
13302
|
-
note:
|
|
13303
|
-
working:
|
|
13304
|
-
missing: "
|
|
13306
|
+
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",
|
|
13307
|
+
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',
|
|
13308
|
+
missing: "tag discovery (the simulator has no NFC reader); the Android NfcManager module"
|
|
13305
13309
|
}
|
|
13306
13310
|
]
|
|
13307
13311
|
},
|
|
@@ -29229,6 +29233,7 @@ var init_bridge_host = __esm({
|
|
|
29229
29233
|
// terminal 4001 code, so the client closes the abandoned window instead
|
|
29230
29234
|
// of reconnecting the zombie straight back in.
|
|
29231
29235
|
static SIM_IDLE_REAP_TTL_MS = 30 * 6e4;
|
|
29236
|
+
bindHost;
|
|
29232
29237
|
preferredPort;
|
|
29233
29238
|
portFallbackCount;
|
|
29234
29239
|
shouldWriteLockfile;
|
|
@@ -29262,6 +29267,7 @@ var init_bridge_host = __esm({
|
|
|
29262
29267
|
inflightScan = null;
|
|
29263
29268
|
static SCAN_FRESH_MS = 2e3;
|
|
29264
29269
|
constructor(opts = {}) {
|
|
29270
|
+
this.bindHost = opts.host ?? "127.0.0.1";
|
|
29265
29271
|
this.preferredPort = opts.port ?? DEFAULT_SOOTSIM_BRIDGE_PORT;
|
|
29266
29272
|
this.port = this.preferredPort;
|
|
29267
29273
|
this.shouldWriteLockfile = opts.writeLockfile === true;
|
|
@@ -29338,7 +29344,7 @@ var init_bridge_host = __esm({
|
|
|
29338
29344
|
reject(err);
|
|
29339
29345
|
};
|
|
29340
29346
|
server.once("error", onError);
|
|
29341
|
-
server.listen(port,
|
|
29347
|
+
server.listen(port, this.bindHost, () => {
|
|
29342
29348
|
if (settled) return;
|
|
29343
29349
|
const address = server.address();
|
|
29344
29350
|
if (!address || typeof address === "string") {
|
|
@@ -33485,6 +33491,57 @@ function layoutGetNativeEval(opts = {}) {
|
|
|
33485
33491
|
return elements
|
|
33486
33492
|
})()`;
|
|
33487
33493
|
}
|
|
33494
|
+
function isPeachAccessibilityTree(value) {
|
|
33495
|
+
if (!Array.isArray(value)) return false;
|
|
33496
|
+
return value.every((node) => {
|
|
33497
|
+
if (node === null || typeof node !== "object") return false;
|
|
33498
|
+
if (Reflect.get(node, "platform") !== "ios" && Reflect.get(node, "platform") !== "android")
|
|
33499
|
+
return false;
|
|
33500
|
+
if (typeof Reflect.get(node, "elementId") !== "string") return false;
|
|
33501
|
+
if (!Number.isInteger(Reflect.get(node, "nodeId"))) return false;
|
|
33502
|
+
for (const key of ["type", "role"]) {
|
|
33503
|
+
if (typeof Reflect.get(node, key) !== "string") return false;
|
|
33504
|
+
}
|
|
33505
|
+
for (const key of ["testID", "label", "hint", "value", "placeholder"]) {
|
|
33506
|
+
const field = Reflect.get(node, key);
|
|
33507
|
+
if (field !== null && typeof field !== "string") return false;
|
|
33508
|
+
}
|
|
33509
|
+
for (const key of [
|
|
33510
|
+
"isAccessibilityElement",
|
|
33511
|
+
"enabled",
|
|
33512
|
+
"selected",
|
|
33513
|
+
"checked",
|
|
33514
|
+
"clickable",
|
|
33515
|
+
"isTextInput"
|
|
33516
|
+
]) {
|
|
33517
|
+
if (typeof Reflect.get(node, key) !== "boolean") return false;
|
|
33518
|
+
}
|
|
33519
|
+
const hasFocus = Reflect.get(node, "hasFocus");
|
|
33520
|
+
if (hasFocus !== void 0 && typeof hasFocus !== "boolean") return false;
|
|
33521
|
+
const state = Reflect.get(node, "state");
|
|
33522
|
+
if (state !== null) {
|
|
33523
|
+
if (typeof state !== "object") return false;
|
|
33524
|
+
const checked = Reflect.get(state, "checked");
|
|
33525
|
+
if (typeof checked !== "boolean" && checked !== "mixed") return false;
|
|
33526
|
+
for (const key of ["disabled", "selected", "busy", "expanded"]) {
|
|
33527
|
+
if (typeof Reflect.get(state, key) !== "boolean") return false;
|
|
33528
|
+
}
|
|
33529
|
+
}
|
|
33530
|
+
const value2 = Reflect.get(node, "accessibilityValue");
|
|
33531
|
+
if (value2 !== null) {
|
|
33532
|
+
if (typeof value2 !== "object") return false;
|
|
33533
|
+
for (const key of ["min", "max", "now"]) {
|
|
33534
|
+
const field = Reflect.get(value2, key);
|
|
33535
|
+
if (field !== void 0 && (typeof field !== "number" || !Number.isFinite(field)))
|
|
33536
|
+
return false;
|
|
33537
|
+
}
|
|
33538
|
+
const text = Reflect.get(value2, "text");
|
|
33539
|
+
if (text !== void 0 && typeof text !== "string") return false;
|
|
33540
|
+
}
|
|
33541
|
+
if (!isSemanticGeometry(Reflect.get(node, "frame"))) return false;
|
|
33542
|
+
return isPeachAccessibilityTree(Reflect.get(node, "children"));
|
|
33543
|
+
});
|
|
33544
|
+
}
|
|
33488
33545
|
function waitReadyReason(status) {
|
|
33489
33546
|
if (status.bridgeError) {
|
|
33490
33547
|
if (status.bridgeError.includes(HEADLESS_TENANT_FETCH_HUNG_MARKER) || status.bridgeError.includes(PUBLIC_NO_NETWORK_MARKER)) {
|
|
@@ -34174,17 +34231,10 @@ function resolvePlaywright() {
|
|
|
34174
34231
|
const packageJsonPath = requireFromRoot.resolve(`${spec}/package.json`);
|
|
34175
34232
|
const parsed = JSON.parse((0, import_node_fs23.readFileSync)(packageJsonPath, "utf8"));
|
|
34176
34233
|
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);
|
|
34234
|
+
const corePackagePath = (0, import_node_module5.createRequire)(modulePath).resolve(
|
|
34235
|
+
"playwright-core/package.json"
|
|
34236
|
+
);
|
|
34237
|
+
const cliPath = (0, import_node_path25.join)((0, import_node_path25.dirname)(corePackagePath), "cli.js");
|
|
34188
34238
|
if (!(0, import_node_fs23.existsSync)(cliPath)) continue;
|
|
34189
34239
|
return {
|
|
34190
34240
|
spec,
|
|
@@ -34393,6 +34443,7 @@ async function launch2(opts) {
|
|
|
34393
34443
|
env: {
|
|
34394
34444
|
...playwrightEnv,
|
|
34395
34445
|
SOOTSIM_PW_MODULE: resolved.modulePath,
|
|
34446
|
+
SOOTSIM_PW_EXECUTABLE: provisioning.executablePath,
|
|
34396
34447
|
SOOTSIM_PW_URL: opts.url,
|
|
34397
34448
|
SOOTSIM_PW_BRIDGE_PORT: opts.bridgePort ? String(opts.bridgePort) : "",
|
|
34398
34449
|
SOOTSIM_PW_HEADLESS: opts.headless ?? true ? "1" : "0",
|
|
@@ -34582,6 +34633,7 @@ var init_command_registry = __esm({
|
|
|
34582
34633
|
"android",
|
|
34583
34634
|
"remote",
|
|
34584
34635
|
"preview",
|
|
34636
|
+
"swift",
|
|
34585
34637
|
"box",
|
|
34586
34638
|
"list",
|
|
34587
34639
|
"use",
|
|
@@ -35172,7 +35224,7 @@ function resolveDriverHeadless(args, driverId) {
|
|
|
35172
35224
|
function normalizeKnownTarget(target) {
|
|
35173
35225
|
return target.trim();
|
|
35174
35226
|
}
|
|
35175
|
-
async function ensureBridgeForOpen(preferredPort, explicitPort = false) {
|
|
35227
|
+
async function ensureBridgeForOpen(preferredPort, explicitPort = false, resources) {
|
|
35176
35228
|
const lock = readDaemonLockfile();
|
|
35177
35229
|
assertExplicitBridgeLock(preferredPort, explicitPort, lock);
|
|
35178
35230
|
const preferredWorld = worldForBridgePort(preferredPort);
|
|
@@ -35194,6 +35246,10 @@ async function ensureBridgeForOpen(preferredPort, explicitPort = false) {
|
|
|
35194
35246
|
}
|
|
35195
35247
|
await ensureRuntimeForOpen();
|
|
35196
35248
|
const child = spawnSootsim(["serve", "--quiet", "--port", String(preferredPort)]);
|
|
35249
|
+
if (resources) {
|
|
35250
|
+
resources.bridge = child;
|
|
35251
|
+
resources.port = preferredPort;
|
|
35252
|
+
}
|
|
35197
35253
|
let childExit = null;
|
|
35198
35254
|
child.once("exit", (code, signal) => {
|
|
35199
35255
|
childExit = String(code ?? signal ?? "unknown");
|
|
@@ -35214,6 +35270,10 @@ async function ensureBridgeForOpen(preferredPort, explicitPort = false) {
|
|
|
35214
35270
|
console.error(
|
|
35215
35271
|
` Started a local bridge on port ${selectedPort}. Run \`peach daemon install\` to keep it ready between commands.`
|
|
35216
35272
|
);
|
|
35273
|
+
if (resources) {
|
|
35274
|
+
resources.bridgeReady = true;
|
|
35275
|
+
resources.port = selectedPort;
|
|
35276
|
+
}
|
|
35217
35277
|
return selectedPort;
|
|
35218
35278
|
}
|
|
35219
35279
|
if (childExit) {
|
|
@@ -35710,6 +35770,7 @@ async function waitForSimMatchOrHostExit(wsPort, commandTimeoutMs, predicate, ho
|
|
|
35710
35770
|
const watchHost = !!hostPid && Number.isInteger(hostPid) && hostPid > 1;
|
|
35711
35771
|
const hostExited = () => watchHost && hostPid !== void 0 && !isProcessAlive2(hostPid);
|
|
35712
35772
|
for (let i = 0; i < attempts; i++) {
|
|
35773
|
+
opts.signal?.throwIfAborted();
|
|
35713
35774
|
if (hostExited()) {
|
|
35714
35775
|
return { kind: "host-exit" };
|
|
35715
35776
|
}
|
|
@@ -36142,7 +36203,14 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
36142
36203
|
parsed.wsPort = pinned.port;
|
|
36143
36204
|
}
|
|
36144
36205
|
}
|
|
36145
|
-
|
|
36206
|
+
opts.signal?.throwIfAborted();
|
|
36207
|
+
parsed.wsPort = await ensureBridgeForOpen(
|
|
36208
|
+
parsed.wsPort,
|
|
36209
|
+
parsed.explicitPort,
|
|
36210
|
+
opts.resources
|
|
36211
|
+
);
|
|
36212
|
+
if (opts.resources) opts.resources.port = parsed.wsPort;
|
|
36213
|
+
opts.signal?.throwIfAborted();
|
|
36146
36214
|
const requestedDriverId = args.find((_, i) => args[i - 1] === "--driver") || "";
|
|
36147
36215
|
if (requestedDriverId && !isDriverId(requestedDriverId)) {
|
|
36148
36216
|
console.error(
|
|
@@ -36362,7 +36430,7 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
36362
36430
|
}
|
|
36363
36431
|
const configuredBaseUrl = applyRNXConfigToUrl(baseUrl, runtimeConfig);
|
|
36364
36432
|
const openUrl2 = await buildOpenUrl(target, configuredBaseUrl, token, buildShellUrlOpts);
|
|
36365
|
-
const ownerPid = getStableOwnerPid();
|
|
36433
|
+
const ownerPid = opts.ownerPid ?? getStableOwnerPid();
|
|
36366
36434
|
if (!ownerPid) {
|
|
36367
36435
|
console.error(
|
|
36368
36436
|
" could not resolve a stable owning process; refusing unsupervised sim host"
|
|
@@ -36375,6 +36443,7 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
36375
36443
|
rnxExit(1);
|
|
36376
36444
|
}
|
|
36377
36445
|
const connectWait = resolveDriverConnectWaitOptions();
|
|
36446
|
+
opts.signal?.throwIfAborted();
|
|
36378
36447
|
const result = await driver.launch({
|
|
36379
36448
|
url: openUrl2,
|
|
36380
36449
|
// the shell serves the sim page but its WS bridge may have drifted off
|
|
@@ -36393,6 +36462,8 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
36393
36462
|
viewport: explicitViewport ?? (deviceFitBox ? { width: deviceFitBox.width + 120, height: deviceFitBox.height + 60 } : void 0),
|
|
36394
36463
|
connectTimeoutMs: connectWait.hostTimeoutMs
|
|
36395
36464
|
});
|
|
36465
|
+
if (opts.resources) opts.resources.driver = { ...result, driverId };
|
|
36466
|
+
opts.signal?.throwIfAborted();
|
|
36396
36467
|
if (!result.launched) {
|
|
36397
36468
|
console.error(` ${driver.name} driver: ${result.message}`);
|
|
36398
36469
|
rnxExit(1);
|
|
@@ -36402,7 +36473,11 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
36402
36473
|
parsed.commandTimeoutMs,
|
|
36403
36474
|
simMatchesToken,
|
|
36404
36475
|
result.pid,
|
|
36405
|
-
{
|
|
36476
|
+
{
|
|
36477
|
+
attempts: connectWait.attempts,
|
|
36478
|
+
intervalMs: connectWait.intervalMs,
|
|
36479
|
+
signal: opts.signal
|
|
36480
|
+
}
|
|
36406
36481
|
);
|
|
36407
36482
|
if (outcome.kind === "host-exit") {
|
|
36408
36483
|
printDriverDiagnosticLogTail(result);
|
|
@@ -36424,6 +36499,7 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
36424
36499
|
rnxExit(1);
|
|
36425
36500
|
}
|
|
36426
36501
|
const match = outcome.sim;
|
|
36502
|
+
if (opts.resources) opts.resources.simId = match.id;
|
|
36427
36503
|
saveCurrentSimId(match.id);
|
|
36428
36504
|
signalDriverLaunchConnected(result);
|
|
36429
36505
|
printOpenedSim(openUrl2, match, `${driver.name} driver`, quiet);
|
|
@@ -37809,9 +37885,228 @@ function assertSupportedSelector(selector) {
|
|
|
37809
37885
|
if (unsupported.length > 0) {
|
|
37810
37886
|
throw new Error(`selector ${unsupported.join(", ")} is not supported by peach yet`);
|
|
37811
37887
|
}
|
|
37812
|
-
for (const key of ["childOf", "below", "above", "leftOf", "rightOf"]) {
|
|
37888
|
+
for (const key of ["childOf", "below", "above", "leftOf", "rightOf", "containsChild"]) {
|
|
37813
37889
|
assertSupportedSelector(Reflect.get(selector, key));
|
|
37814
37890
|
}
|
|
37891
|
+
const descendants = Reflect.get(selector, "containsDescendants");
|
|
37892
|
+
if (descendants !== void 0) {
|
|
37893
|
+
if (!Array.isArray(descendants)) {
|
|
37894
|
+
throw new Error("selector containsDescendants must be a list of selectors");
|
|
37895
|
+
}
|
|
37896
|
+
for (const descendant of descendants) assertSupportedSelector(descendant);
|
|
37897
|
+
}
|
|
37898
|
+
}
|
|
37899
|
+
function needsAccessibilityProjection(selector) {
|
|
37900
|
+
if (typeof selector === "string") return false;
|
|
37901
|
+
if (ACCESSIBILITY_SELECTOR_KEYS.some((key) => selector[key] != null)) return true;
|
|
37902
|
+
return ["childOf", "below", "above", "leftOf", "rightOf"].some((key) => {
|
|
37903
|
+
const nested = Reflect.get(selector, key);
|
|
37904
|
+
return isSelectorRecord(nested) && needsAccessibilityProjection(nested);
|
|
37905
|
+
});
|
|
37906
|
+
}
|
|
37907
|
+
function accessibilityTreeNodes(tree) {
|
|
37908
|
+
const out = [];
|
|
37909
|
+
const visit = (node) => {
|
|
37910
|
+
out.push(node);
|
|
37911
|
+
for (const child of node.children) visit(child);
|
|
37912
|
+
};
|
|
37913
|
+
for (const root of tree) visit(root);
|
|
37914
|
+
return out;
|
|
37915
|
+
}
|
|
37916
|
+
function accessibilitySubtreeNodes(node) {
|
|
37917
|
+
return [node, ...node.children.flatMap(accessibilitySubtreeNodes)];
|
|
37918
|
+
}
|
|
37919
|
+
function accessibilityTextMatcher(value, kind) {
|
|
37920
|
+
const pattern = new RegExp(`^(?:${value})$`);
|
|
37921
|
+
return (candidate) => {
|
|
37922
|
+
const native = candidate ?? "";
|
|
37923
|
+
if (kind === "id")
|
|
37924
|
+
return pattern.test(native) || pattern.test(native.slice(native.lastIndexOf("/") + 1));
|
|
37925
|
+
const stripped = native.replaceAll("\n", " ");
|
|
37926
|
+
return native === value || stripped === value || pattern.test(native) || pattern.test(stripped);
|
|
37927
|
+
};
|
|
37928
|
+
}
|
|
37929
|
+
function accessibilityBounds(node) {
|
|
37930
|
+
const left = Math.trunc(node.frame.x);
|
|
37931
|
+
const top = Math.trunc(node.frame.y);
|
|
37932
|
+
return {
|
|
37933
|
+
x: left,
|
|
37934
|
+
y: top,
|
|
37935
|
+
width: Math.trunc(node.frame.x + node.frame.width) - left,
|
|
37936
|
+
height: Math.trunc(node.frame.y + node.frame.height) - top
|
|
37937
|
+
};
|
|
37938
|
+
}
|
|
37939
|
+
function accessibilityBasicFilters(selector) {
|
|
37940
|
+
const filters = [];
|
|
37941
|
+
if (selector.text != null) {
|
|
37942
|
+
const matches = accessibilityTextMatcher(selector.text, "text");
|
|
37943
|
+
filters.push(
|
|
37944
|
+
(node) => matches(node.label) || matches(node.value) || matches(node.placeholder)
|
|
37945
|
+
);
|
|
37946
|
+
}
|
|
37947
|
+
if (selector.id != null) {
|
|
37948
|
+
const matches = accessibilityTextMatcher(selector.id, "id");
|
|
37949
|
+
filters.push((node) => matches(node.testID));
|
|
37950
|
+
}
|
|
37951
|
+
if (selector.width != null || selector.height != null) {
|
|
37952
|
+
const tolerance = selector.tolerance ?? 0;
|
|
37953
|
+
filters.push((node) => {
|
|
37954
|
+
const bounds = accessibilityBounds(node);
|
|
37955
|
+
return (selector.width == null || Math.abs(bounds.width - selector.width) <= tolerance) && (selector.height == null || Math.abs(bounds.height - selector.height) <= tolerance);
|
|
37956
|
+
});
|
|
37957
|
+
}
|
|
37958
|
+
for (const trait of selector.traits ? selector.traits.split(" ") : []) {
|
|
37959
|
+
const filter = ACCESSIBILITY_TRAIT_FILTERS[trait.replaceAll("-", "_").toUpperCase()];
|
|
37960
|
+
if (!filter) throw new Error(`unknown selector trait: ${trait}`);
|
|
37961
|
+
filters.push(filter);
|
|
37962
|
+
}
|
|
37963
|
+
if (selector.enabled != null) {
|
|
37964
|
+
filters.push((node) => node.enabled === selector.enabled);
|
|
37965
|
+
}
|
|
37966
|
+
if (selector.selected != null) {
|
|
37967
|
+
filters.push((node) => node.selected === selector.selected);
|
|
37968
|
+
}
|
|
37969
|
+
if (selector.checked != null) {
|
|
37970
|
+
filters.push((node) => node.checked === selector.checked);
|
|
37971
|
+
}
|
|
37972
|
+
if (selector.focused != null) {
|
|
37973
|
+
filters.push((node) => (node.hasFocus ?? false) === selector.focused);
|
|
37974
|
+
}
|
|
37975
|
+
return filters;
|
|
37976
|
+
}
|
|
37977
|
+
function deepestMatchingAccessibilityNodes(nodes, matches) {
|
|
37978
|
+
const out = [];
|
|
37979
|
+
const included = new Set(nodes);
|
|
37980
|
+
const nested = new Set(
|
|
37981
|
+
nodes.flatMap((node) => node.children.filter((child) => included.has(child)))
|
|
37982
|
+
);
|
|
37983
|
+
for (const node of nodes.filter((node2) => !nested.has(node2))) {
|
|
37984
|
+
const children = deepestMatchingAccessibilityNodes(node.children, matches);
|
|
37985
|
+
if (children.length > 0) out.push(...children);
|
|
37986
|
+
else if (matches(node)) out.push(node);
|
|
37987
|
+
}
|
|
37988
|
+
return distinctAccessibilityNodes(out);
|
|
37989
|
+
}
|
|
37990
|
+
function distinctAccessibilityNodes(nodes) {
|
|
37991
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
37992
|
+
return nodes.filter((node) => {
|
|
37993
|
+
const key = JSON.stringify([
|
|
37994
|
+
node.testID ?? "",
|
|
37995
|
+
node.label ?? "",
|
|
37996
|
+
node.placeholder ?? "",
|
|
37997
|
+
node.value ?? "",
|
|
37998
|
+
node.enabled,
|
|
37999
|
+
node.selected,
|
|
38000
|
+
node.checked,
|
|
38001
|
+
node.clickable,
|
|
38002
|
+
node.hasFocus ?? false,
|
|
38003
|
+
accessibilityBounds(node),
|
|
38004
|
+
node.children.length
|
|
38005
|
+
]);
|
|
38006
|
+
const bucket = buckets.get(key);
|
|
38007
|
+
if (bucket?.some((other) => sameNativeAccessibilityShape(node, other))) return false;
|
|
38008
|
+
if (bucket) bucket.push(node);
|
|
38009
|
+
else buckets.set(key, [node]);
|
|
38010
|
+
return true;
|
|
38011
|
+
});
|
|
38012
|
+
}
|
|
38013
|
+
function isSelectorRecord(value) {
|
|
38014
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
38015
|
+
}
|
|
38016
|
+
function accessibilityAnchorSelector(value) {
|
|
38017
|
+
if (typeof value === "string") return { text: value };
|
|
38018
|
+
return isSelectorRecord(value) ? value : {};
|
|
38019
|
+
}
|
|
38020
|
+
function sameNativeAccessibilityShape(a, b) {
|
|
38021
|
+
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) {
|
|
38022
|
+
return false;
|
|
38023
|
+
}
|
|
38024
|
+
for (const [index, child] of a.children.entries()) {
|
|
38025
|
+
const other = b.children[index];
|
|
38026
|
+
if (!other || !sameNativeAccessibilityShape(child, other)) return false;
|
|
38027
|
+
}
|
|
38028
|
+
return true;
|
|
38029
|
+
}
|
|
38030
|
+
function accessibilitySubtreeMatches(all, node, selector) {
|
|
38031
|
+
if (filterAccessibilityNodes(all, [node], selector).length > 0) return true;
|
|
38032
|
+
return node.children.some((child) => accessibilitySubtreeMatches(all, child, selector));
|
|
38033
|
+
}
|
|
38034
|
+
function filterAccessibilityNodes(all, nodes, selector) {
|
|
38035
|
+
if (selector.childOf == null) {
|
|
38036
|
+
return filterAccessibilityNodesIn(all, nodes, selector);
|
|
38037
|
+
}
|
|
38038
|
+
const container = filterAccessibilityNodes(
|
|
38039
|
+
all,
|
|
38040
|
+
all,
|
|
38041
|
+
accessibilityAnchorSelector(selector.childOf)
|
|
38042
|
+
)[0];
|
|
38043
|
+
if (!container) return [];
|
|
38044
|
+
return filterAccessibilityNodesIn(all, accessibilitySubtreeNodes(container), selector);
|
|
38045
|
+
}
|
|
38046
|
+
function filterAccessibilityNodesIn(all, nodes, selector) {
|
|
38047
|
+
const basic = accessibilityBasicFilters(selector);
|
|
38048
|
+
let candidates = basic.length > 0 ? deepestMatchingAccessibilityNodes(
|
|
38049
|
+
nodes,
|
|
38050
|
+
(node) => basic.every((filter) => filter(node))
|
|
38051
|
+
) : [...nodes];
|
|
38052
|
+
const relativeGeometry = {
|
|
38053
|
+
below: (node, other) => accessibilityBounds(node).y > accessibilityBounds(other).y,
|
|
38054
|
+
above: (node, other) => accessibilityBounds(node).y < accessibilityBounds(other).y,
|
|
38055
|
+
leftOf: (node, other) => accessibilityBounds(node).x < accessibilityBounds(other).x,
|
|
38056
|
+
rightOf: (node, other) => accessibilityBounds(node).x > accessibilityBounds(other).x
|
|
38057
|
+
};
|
|
38058
|
+
for (const key of ["below", "above", "leftOf", "rightOf"]) {
|
|
38059
|
+
const anchor = selector[key];
|
|
38060
|
+
if (anchor == null) continue;
|
|
38061
|
+
const anchors = filterAccessibilityNodes(
|
|
38062
|
+
all,
|
|
38063
|
+
nodes,
|
|
38064
|
+
accessibilityAnchorSelector(anchor)
|
|
38065
|
+
);
|
|
38066
|
+
candidates = candidates.filter(
|
|
38067
|
+
(node) => anchors.some((other) => relativeGeometry[key](node, other))
|
|
38068
|
+
);
|
|
38069
|
+
}
|
|
38070
|
+
if (selector.containsChild != null) {
|
|
38071
|
+
const child = filterAccessibilityNodes(
|
|
38072
|
+
all,
|
|
38073
|
+
all,
|
|
38074
|
+
accessibilityAnchorSelector(selector.containsChild)
|
|
38075
|
+
)[0];
|
|
38076
|
+
candidates = child ? candidates.filter(
|
|
38077
|
+
(node) => node.children.some(
|
|
38078
|
+
(candidate) => sameNativeAccessibilityShape(candidate, child)
|
|
38079
|
+
)
|
|
38080
|
+
) : [];
|
|
38081
|
+
}
|
|
38082
|
+
if (selector.containsDescendants != null) {
|
|
38083
|
+
const descendants = selector.containsDescendants.map(accessibilityAnchorSelector);
|
|
38084
|
+
candidates = candidates.filter(
|
|
38085
|
+
(node) => descendants.every(
|
|
38086
|
+
(descendant) => node.children.some(
|
|
38087
|
+
(child) => accessibilitySubtreeMatches(all, child, descendant)
|
|
38088
|
+
)
|
|
38089
|
+
)
|
|
38090
|
+
);
|
|
38091
|
+
}
|
|
38092
|
+
candidates = distinctAccessibilityNodes(candidates);
|
|
38093
|
+
if (selector.index != null) {
|
|
38094
|
+
const index = Math.trunc(Number(selector.index));
|
|
38095
|
+
const sorted = [...candidates].sort((a, b) => {
|
|
38096
|
+
const aBounds = accessibilityBounds(a);
|
|
38097
|
+
const bBounds = accessibilityBounds(b);
|
|
38098
|
+
return aBounds.y - bBounds.y || aBounds.x - bBounds.x;
|
|
38099
|
+
});
|
|
38100
|
+
const resolved = index >= 0 ? index : sorted.length + index;
|
|
38101
|
+
if (resolved < 0 || resolved >= sorted.length) return [];
|
|
38102
|
+
const picked = sorted[resolved];
|
|
38103
|
+
return picked ? [picked] : [];
|
|
38104
|
+
}
|
|
38105
|
+
return [...candidates].sort((a, b) => Number(b.clickable) - Number(a.clickable));
|
|
38106
|
+
}
|
|
38107
|
+
function resolveAccessibilitySelector(tree, selector) {
|
|
38108
|
+
const all = accessibilityTreeNodes(tree);
|
|
38109
|
+
return filterAccessibilityNodes(all, all, selector)[0] ?? null;
|
|
37815
38110
|
}
|
|
37816
38111
|
function isObjectRecord(value) {
|
|
37817
38112
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
@@ -37920,7 +38215,7 @@ function parseFlowSteps(content) {
|
|
|
37920
38215
|
const parsed = import_yaml2.default.parse(candidate);
|
|
37921
38216
|
return Array.isArray(parsed) ? parsed : [];
|
|
37922
38217
|
}
|
|
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;
|
|
38218
|
+
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
38219
|
var init_bridge_flow_runner = __esm({
|
|
37925
38220
|
"cli/bridge-flow-runner.ts"() {
|
|
37926
38221
|
"use strict";
|
|
@@ -37987,12 +38282,21 @@ var init_bridge_flow_runner = __esm({
|
|
|
37987
38282
|
"leftOf",
|
|
37988
38283
|
"rightOf"
|
|
37989
38284
|
];
|
|
37990
|
-
UNSUPPORTED_SELECTOR_KEYS = [
|
|
38285
|
+
UNSUPPORTED_SELECTOR_KEYS = ["css"];
|
|
38286
|
+
ACCESSIBILITY_SELECTOR_KEYS = [
|
|
37991
38287
|
"containsChild",
|
|
37992
38288
|
"containsDescendants",
|
|
37993
|
-
"focused"
|
|
37994
|
-
"css"
|
|
38289
|
+
"focused"
|
|
37995
38290
|
];
|
|
38291
|
+
ACCESSIBILITY_TRAIT_FILTERS = {
|
|
38292
|
+
// IOSDriver sets attributes["text"] on every node, including empty text.
|
|
38293
|
+
TEXT: () => true,
|
|
38294
|
+
SQUARE: (node) => {
|
|
38295
|
+
const bounds = accessibilityBounds(node);
|
|
38296
|
+
return Math.abs(1 - bounds.width / bounds.height) < 0.03;
|
|
38297
|
+
},
|
|
38298
|
+
LONG_TEXT: (node) => (node.value?.length ?? 0) > 200
|
|
38299
|
+
};
|
|
37996
38300
|
MAESTRO_PERMISSION_KINDS = {
|
|
37997
38301
|
all: PERMISSION_KINDS,
|
|
37998
38302
|
bluetooth: ["bluetooth"],
|
|
@@ -38275,6 +38579,9 @@ var init_bridge_flow_runner = __esm({
|
|
|
38275
38579
|
}
|
|
38276
38580
|
async findElement(opts) {
|
|
38277
38581
|
assertSupportedSelector(opts);
|
|
38582
|
+
if (needsAccessibilityProjection(opts)) {
|
|
38583
|
+
return this.findElementAccessibilityTree(opts);
|
|
38584
|
+
}
|
|
38278
38585
|
if (opts.id != null || opts.index != null || opts.text != null && /[.*+?^$()[\]{}|\\]/.test(opts.text) || SELECTOR_FILTER_KEYS.some((key) => opts[key] != null)) {
|
|
38279
38586
|
return this.findElementScoped(opts);
|
|
38280
38587
|
}
|
|
@@ -38307,6 +38614,46 @@ var init_bridge_flow_runner = __esm({
|
|
|
38307
38614
|
}
|
|
38308
38615
|
})()`);
|
|
38309
38616
|
}
|
|
38617
|
+
// structural filters (containsChild / containsDescendants / focused) read the
|
|
38618
|
+
// engine's XCTest accessibility projection — one bridge evaluate, then the
|
|
38619
|
+
// same Orchestra.buildFilter semantics the render resolver implements, over
|
|
38620
|
+
// PeachAccessibilityNode instead of the visible semantic tree.
|
|
38621
|
+
async findElementAccessibilityTree(opts) {
|
|
38622
|
+
const tree = await this.evaluate(`(async () => {
|
|
38623
|
+
const test = window.__sootsimTest
|
|
38624
|
+
if (!test || typeof test.captureAccessibilityTree !== 'function') throw new Error('engine accessibility snapshot is unavailable')
|
|
38625
|
+
return await test.captureAccessibilityTree()
|
|
38626
|
+
})()`);
|
|
38627
|
+
if (!isPeachAccessibilityTree(tree))
|
|
38628
|
+
throw new Error("engine returned an invalid accessibility snapshot");
|
|
38629
|
+
if (tree.length === 0) return null;
|
|
38630
|
+
if (tree.some((node2) => node2.platform !== "ios"))
|
|
38631
|
+
throw new Error(
|
|
38632
|
+
"containsChild, containsDescendants and focused require the iOS accessibility hierarchy"
|
|
38633
|
+
);
|
|
38634
|
+
const node = resolveAccessibilitySelector(tree, opts);
|
|
38635
|
+
if (!node) return null;
|
|
38636
|
+
const frame = node.frame;
|
|
38637
|
+
return {
|
|
38638
|
+
nodeId: Number.isFinite(node.nodeId) ? node.nodeId : null,
|
|
38639
|
+
id: node.testID,
|
|
38640
|
+
testID: node.testID,
|
|
38641
|
+
text: node.label,
|
|
38642
|
+
accessibilityLabel: node.label,
|
|
38643
|
+
absolutePosition: { x: frame.x, y: frame.y },
|
|
38644
|
+
layout: { width: frame.width, height: frame.height },
|
|
38645
|
+
// the engine applies Maestro's integer-frame viewport filter to the
|
|
38646
|
+
// native hierarchy before this lookup; preserve the native bounds.
|
|
38647
|
+
visibleFrame: {
|
|
38648
|
+
x: frame.x,
|
|
38649
|
+
y: frame.y,
|
|
38650
|
+
width: frame.width,
|
|
38651
|
+
height: frame.height,
|
|
38652
|
+
area: frame.width * frame.height
|
|
38653
|
+
},
|
|
38654
|
+
isTextInput: node.isTextInput
|
|
38655
|
+
};
|
|
38656
|
+
}
|
|
38310
38657
|
// maestro's selector resolver (Orchestra.buildFilter over Filters.kt):
|
|
38311
38658
|
// id and text patterns, size, traits, enabled/selected, the relative
|
|
38312
38659
|
// below/above/leftOf/rightOf filters, `index:` (nth match) and `childOf:`
|
|
@@ -38669,7 +39016,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
38669
39016
|
break;
|
|
38670
39017
|
}
|
|
38671
39018
|
}
|
|
38672
|
-
const narrowed = opts.index != null || SELECTOR_FILTER_KEYS.some((key) => opts[key] != null);
|
|
39019
|
+
const narrowed = opts.index != null || SELECTOR_FILTER_KEYS.some((key) => opts[key] != null) || ACCESSIBILITY_SELECTOR_KEYS.some((key) => opts[key] != null);
|
|
38673
39020
|
const direct = element || !narrowed ? await this.activatePressTarget(opts) : null;
|
|
38674
39021
|
if (direct?.ok) {
|
|
38675
39022
|
await this.settleAfterInput();
|