execbro 2.3.0 → 2.5.0
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/build/__tests__/helpers/fake-cdp-server.d.ts +0 -12
- package/build/__tests__/helpers/fake-cdp-server.d.ts.map +1 -1
- package/build/__tests__/helpers/fake-cdp-server.js +0 -22
- package/build/__tests__/helpers/fake-cdp-server.js.map +1 -1
- package/build/__tests__/helpers/tap-test-helpers.d.ts +0 -23
- package/build/__tests__/helpers/tap-test-helpers.d.ts.map +1 -1
- package/build/__tests__/helpers/tap-test-helpers.js +2 -29
- package/build/__tests__/helpers/tap-test-helpers.js.map +1 -1
- package/build/__tests__/integration/auto-reconnect.test.js +4 -14
- package/build/__tests__/integration/auto-reconnect.test.js.map +1 -1
- package/build/__tests__/integration/connection-health.test.js +1 -10
- package/build/__tests__/integration/connection-health.test.js.map +1 -1
- package/build/__tests__/integration/execute-in-app.test.js +1 -11
- package/build/__tests__/integration/execute-in-app.test.js.map +1 -1
- package/build/__tests__/integration/native-logs.test.js +0 -5
- package/build/__tests__/integration/native-logs.test.js.map +1 -1
- package/build/__tests__/integration/per-call-timeout.test.js +1 -5
- package/build/__tests__/integration/per-call-timeout.test.js.map +1 -1
- package/build/__tests__/integration/socket-close-midflight.test.js +2 -12
- package/build/__tests__/integration/socket-close-midflight.test.js.map +1 -1
- package/build/__tests__/integration/stale-target-probe.test.js +2 -17
- package/build/__tests__/integration/stale-target-probe.test.js.map +1 -1
- package/build/__tests__/integration/tap-strategies.test.js +2 -36
- package/build/__tests__/integration/tap-strategies.test.js.map +1 -1
- package/build/__tests__/integration/text-input.test.js +0 -39
- package/build/__tests__/integration/text-input.test.js.map +1 -1
- package/build/__tests__/integration/tools.test.js +1 -7
- package/build/__tests__/integration/tools.test.js.map +1 -1
- package/build/__tests__/setup.js +0 -2
- package/build/__tests__/setup.js.map +1 -1
- package/build/__tests__/unit/androidEmulatorAvds.test.js +0 -10
- package/build/__tests__/unit/androidEmulatorAvds.test.js.map +1 -1
- package/build/__tests__/unit/appContext.test.js +0 -2
- package/build/__tests__/unit/appContext.test.js.map +1 -1
- package/build/__tests__/unit/appRequest.test.js +0 -3
- package/build/__tests__/unit/appRequest.test.js.map +1 -1
- package/build/__tests__/unit/buildToken.test.js +0 -6
- package/build/__tests__/unit/buildToken.test.js.map +1 -1
- package/build/__tests__/unit/burst.test.js +0 -1
- package/build/__tests__/unit/burst.test.js.map +1 -1
- package/build/__tests__/unit/clearLogsNative.test.js +0 -8
- package/build/__tests__/unit/clearLogsNative.test.js.map +1 -1
- package/build/__tests__/unit/componentFormatNaming.test.js +0 -13
- package/build/__tests__/unit/componentFormatNaming.test.js.map +1 -1
- package/build/__tests__/unit/componentSource.test.js +0 -4
- package/build/__tests__/unit/componentSource.test.js.map +1 -1
- package/build/__tests__/unit/componentSourceResolve.test.js +0 -1
- package/build/__tests__/unit/componentSourceResolve.test.js.map +1 -1
- package/build/__tests__/unit/contextWiring.test.js +0 -3
- package/build/__tests__/unit/contextWiring.test.js.map +1 -1
- package/build/__tests__/unit/coordinateMiss.test.js +0 -16
- package/build/__tests__/unit/coordinateMiss.test.js.map +1 -1
- package/build/__tests__/unit/deviceDiscovery.test.js +0 -4
- package/build/__tests__/unit/deviceDiscovery.test.js.map +1 -1
- package/build/__tests__/unit/deviceResolution.test.js +0 -2
- package/build/__tests__/unit/deviceResolution.test.js.map +1 -1
- package/build/__tests__/unit/deviceResolver.test.js +0 -1
- package/build/__tests__/unit/deviceResolver.test.js.map +1 -1
- package/build/__tests__/unit/deviceResolverStaleRetry.test.js +0 -8
- package/build/__tests__/unit/deviceResolverStaleRetry.test.js.map +1 -1
- package/build/__tests__/unit/epochRender.test.js +0 -3
- package/build/__tests__/unit/epochRender.test.js.map +1 -1
- package/build/__tests__/unit/errorCategorization.test.js +0 -18
- package/build/__tests__/unit/errorCategorization.test.js.map +1 -1
- package/build/__tests__/unit/exec.test.js +0 -1
- package/build/__tests__/unit/exec.test.js.map +1 -1
- package/build/__tests__/unit/executor.test.js +0 -15
- package/build/__tests__/unit/executor.test.js.map +1 -1
- package/build/__tests__/unit/findElementTreeReuse.test.js +0 -12
- package/build/__tests__/unit/findElementTreeReuse.test.js.map +1 -1
- package/build/__tests__/unit/fingerprint.test.js +0 -4
- package/build/__tests__/unit/fingerprint.test.js.map +1 -1
- package/build/__tests__/unit/focusedInputTools.test.js +0 -4
- package/build/__tests__/unit/focusedInputTools.test.js.map +1 -1
- package/build/__tests__/unit/getLogsEmptyContract.test.js +0 -30
- package/build/__tests__/unit/getLogsEmptyContract.test.js.map +1 -1
- package/build/__tests__/unit/getLogsNativeSource.test.js +0 -22
- package/build/__tests__/unit/getLogsNativeSource.test.js.map +1 -1
- package/build/__tests__/unit/graphqlOperation.test.d.ts +2 -0
- package/build/__tests__/unit/graphqlOperation.test.d.ts.map +1 -0
- package/build/__tests__/unit/graphqlOperation.test.js +107 -0
- package/build/__tests__/unit/graphqlOperation.test.js.map +1 -0
- package/build/__tests__/unit/inputTarget.test.js +0 -16
- package/build/__tests__/unit/inputTarget.test.js.map +1 -1
- package/build/__tests__/unit/inputTextTool.test.js +0 -3
- package/build/__tests__/unit/inputTextTool.test.js.map +1 -1
- package/build/__tests__/unit/jsLogEvents.test.js +0 -3
- package/build/__tests__/unit/jsLogEvents.test.js.map +1 -1
- package/build/__tests__/unit/keyboardMetrics.test.js +0 -2
- package/build/__tests__/unit/keyboardMetrics.test.js.map +1 -1
- package/build/__tests__/unit/keyboardRaise.test.js +0 -2
- package/build/__tests__/unit/keyboardRaise.test.js.map +1 -1
- package/build/__tests__/unit/licenseGrace.test.js +1 -4
- package/build/__tests__/unit/licenseGrace.test.js.map +1 -1
- package/build/__tests__/unit/logEventFormat.test.js +0 -27
- package/build/__tests__/unit/logEventFormat.test.js.map +1 -1
- package/build/__tests__/unit/logEvents.test.js +1 -5
- package/build/__tests__/unit/logEvents.test.js.map +1 -1
- package/build/__tests__/unit/logGrouping.test.js +0 -2
- package/build/__tests__/unit/logGrouping.test.js.map +1 -1
- package/build/__tests__/unit/logOwnership.test.js +0 -11
- package/build/__tests__/unit/logOwnership.test.js.map +1 -1
- package/build/__tests__/unit/logRelevance.test.js +0 -6
- package/build/__tests__/unit/logRelevance.test.js.map +1 -1
- package/build/__tests__/unit/logSourceAndroid.test.js +0 -4
- package/build/__tests__/unit/logSourceAndroid.test.js.map +1 -1
- package/build/__tests__/unit/logSourceIos.test.js +0 -5
- package/build/__tests__/unit/logSourceIos.test.js.map +1 -1
- package/build/__tests__/unit/logs.test.js +0 -1
- package/build/__tests__/unit/logs.test.js.map +1 -1
- package/build/__tests__/unit/measureComponentTools.test.js +0 -1
- package/build/__tests__/unit/measureComponentTools.test.js.map +1 -1
- package/build/__tests__/unit/metro.test.js +0 -2
- package/build/__tests__/unit/metro.test.js.map +1 -1
- package/build/__tests__/unit/nativeInputValue.test.js +0 -4
- package/build/__tests__/unit/nativeInputValue.test.js.map +1 -1
- package/build/__tests__/unit/nativeLogs.test.js +1 -23
- package/build/__tests__/unit/nativeLogs.test.js.map +1 -1
- package/build/__tests__/unit/navigateVerify.test.js +0 -6
- package/build/__tests__/unit/navigateVerify.test.js.map +1 -1
- package/build/__tests__/unit/navigation.test.js +0 -5
- package/build/__tests__/unit/navigation.test.js.map +1 -1
- package/build/__tests__/unit/networkInterceptor.test.js +0 -2
- package/build/__tests__/unit/networkInterceptor.test.js.map +1 -1
- package/build/__tests__/unit/overlayGuard.test.d.ts +2 -0
- package/build/__tests__/unit/overlayGuard.test.d.ts.map +1 -0
- package/build/__tests__/unit/overlayGuard.test.js +123 -0
- package/build/__tests__/unit/overlayGuard.test.js.map +1 -0
- package/build/__tests__/unit/pendingExecutions.test.js +0 -6
- package/build/__tests__/unit/pendingExecutions.test.js.map +1 -1
- package/build/__tests__/unit/probe.test.js +0 -1
- package/build/__tests__/unit/probe.test.js.map +1 -1
- package/build/__tests__/unit/projectMemory.test.js +6 -7
- package/build/__tests__/unit/projectMemory.test.js.map +1 -1
- package/build/__tests__/unit/projectStore.test.js +2 -2
- package/build/__tests__/unit/projectStore.test.js.map +1 -1
- package/build/__tests__/unit/reloadAppAutoConnect.test.js +0 -9
- package/build/__tests__/unit/reloadAppAutoConnect.test.js.map +1 -1
- package/build/__tests__/unit/rnGlobalsBootstrap.test.js +3 -3
- package/build/__tests__/unit/rnGlobalsBootstrap.test.js.map +1 -1
- package/build/__tests__/unit/routeHistory.test.d.ts +2 -0
- package/build/__tests__/unit/routeHistory.test.d.ts.map +1 -0
- package/build/__tests__/unit/routeHistory.test.js +136 -0
- package/build/__tests__/unit/routeHistory.test.js.map +1 -0
- package/build/__tests__/unit/screenSpace.test.js +30 -13
- package/build/__tests__/unit/screenSpace.test.js.map +1 -1
- package/build/__tests__/unit/screenState.test.js +3 -6
- package/build/__tests__/unit/screenState.test.js.map +1 -1
- package/build/__tests__/unit/screenStateInputValue.test.js +0 -7
- package/build/__tests__/unit/screenStateInputValue.test.js.map +1 -1
- package/build/__tests__/unit/screenStateKeyboard.test.js +0 -1
- package/build/__tests__/unit/screenStateKeyboard.test.js.map +1 -1
- package/build/__tests__/unit/screenshot-diff.test.js +0 -6
- package/build/__tests__/unit/screenshot-diff.test.js.map +1 -1
- package/build/__tests__/unit/sdkMirrorPoller.test.js +0 -8
- package/build/__tests__/unit/sdkMirrorPoller.test.js.map +1 -1
- package/build/__tests__/unit/settleAndDiff.test.js +0 -11
- package/build/__tests__/unit/settleAndDiff.test.js.map +1 -1
- package/build/__tests__/unit/signedVerdict.test.js +0 -5
- package/build/__tests__/unit/signedVerdict.test.js.map +1 -1
- package/build/__tests__/unit/swipeDirection.test.js +6 -9
- package/build/__tests__/unit/swipeDirection.test.js.map +1 -1
- package/build/__tests__/unit/symbolicate.test.js +0 -1
- package/build/__tests__/unit/symbolicate.test.js.map +1 -1
- package/build/__tests__/unit/tap.test.js +2 -40
- package/build/__tests__/unit/tap.test.js.map +1 -1
- package/build/__tests__/unit/textEntry.test.js +0 -27
- package/build/__tests__/unit/textEntry.test.js.map +1 -1
- package/build/__tests__/unit/toolDescriptions.test.js +0 -40
- package/build/__tests__/unit/toolDescriptions.test.js.map +1 -1
- package/build/__tests__/unit/toolsJson.test.js +0 -10
- package/build/__tests__/unit/toolsJson.test.js.map +1 -1
- package/build/__tests__/unit/transportClassify.test.js +0 -20
- package/build/__tests__/unit/transportClassify.test.js.map +1 -1
- package/build/__tests__/unit/truncate.test.js +0 -5
- package/build/__tests__/unit/truncate.test.js.map +1 -1
- package/build/__tests__/unit/usageCache.test.js +0 -3
- package/build/__tests__/unit/usageCache.test.js.map +1 -1
- package/build/__tests__/unit/usageGate.test.js +1 -1
- package/build/__tests__/unit/usageGate.test.js.map +1 -1
- package/build/__tests__/unit/visibility.test.js +0 -8
- package/build/__tests__/unit/visibility.test.js.map +1 -1
- package/build/__tests__/unit/waitForMeasurements.test.js +2 -7
- package/build/__tests__/unit/waitForMeasurements.test.js.map +1 -1
- package/build/bin.js +0 -18
- package/build/bin.js.map +1 -1
- package/build/core/android.d.ts +0 -120
- package/build/core/android.d.ts.map +1 -1
- package/build/core/android.js +4 -259
- package/build/core/android.js.map +1 -1
- package/build/core/appContext.d.ts +0 -50
- package/build/core/appContext.d.ts.map +1 -1
- package/build/core/appContext.js +0 -50
- package/build/core/appContext.js.map +1 -1
- package/build/core/appDetection.d.ts +0 -16
- package/build/core/appDetection.d.ts.map +1 -1
- package/build/core/appDetection.js +0 -36
- package/build/core/appDetection.js.map +1 -1
- package/build/core/appRequest.d.ts +0 -12
- package/build/core/appRequest.d.ts.map +1 -1
- package/build/core/appRequest.js +0 -15
- package/build/core/appRequest.js.map +1 -1
- package/build/core/bufferConfig.d.ts +0 -2
- package/build/core/bufferConfig.d.ts.map +1 -1
- package/build/core/bufferConfig.js +0 -2
- package/build/core/bufferConfig.js.map +1 -1
- package/build/core/bundle.js +0 -40
- package/build/core/bundle.js.map +1 -1
- package/build/core/componentSearch.d.ts +0 -19
- package/build/core/componentSearch.d.ts.map +1 -1
- package/build/core/componentSearch.js +1 -22
- package/build/core/componentSearch.js.map +1 -1
- package/build/core/componentSource.d.ts +0 -21
- package/build/core/componentSource.d.ts.map +1 -1
- package/build/core/componentSource.js +0 -27
- package/build/core/componentSource.js.map +1 -1
- package/build/core/componentTree.js +0 -12
- package/build/core/componentTree.js.map +1 -1
- package/build/core/config.d.ts +0 -8
- package/build/core/config.d.ts.map +1 -1
- package/build/core/config.js +0 -10
- package/build/core/config.js.map +1 -1
- package/build/core/connection.d.ts +0 -76
- package/build/core/connection.d.ts.map +1 -1
- package/build/core/connection.js +15 -340
- package/build/core/connection.js.map +1 -1
- package/build/core/connectionState.d.ts +0 -78
- package/build/core/connectionState.d.ts.map +1 -1
- package/build/core/connectionState.js +4 -92
- package/build/core/connectionState.js.map +1 -1
- package/build/core/debugGlobals.js +0 -68
- package/build/core/debugGlobals.js.map +1 -1
- package/build/core/deviceDiscovery.d.ts +0 -5
- package/build/core/deviceDiscovery.d.ts.map +1 -1
- package/build/core/deviceDiscovery.js +0 -12
- package/build/core/deviceDiscovery.js.map +1 -1
- package/build/core/deviceResolver.d.ts +0 -10
- package/build/core/deviceResolver.d.ts.map +1 -1
- package/build/core/deviceResolver.js +0 -54
- package/build/core/deviceResolver.js.map +1 -1
- package/build/core/epochRender.d.ts +0 -12
- package/build/core/epochRender.d.ts.map +1 -1
- package/build/core/epochRender.js +0 -12
- package/build/core/epochRender.js.map +1 -1
- package/build/core/errorScreenParser.d.ts +0 -21
- package/build/core/errorScreenParser.d.ts.map +1 -1
- package/build/core/errorScreenParser.js +0 -50
- package/build/core/errorScreenParser.js.map +1 -1
- package/build/core/errors.d.ts +0 -15
- package/build/core/errors.d.ts.map +1 -1
- package/build/core/errors.js +0 -15
- package/build/core/errors.js.map +1 -1
- package/build/core/escapeNonAscii.d.ts +0 -9
- package/build/core/escapeNonAscii.d.ts.map +1 -1
- package/build/core/escapeNonAscii.js +1 -43
- package/build/core/escapeNonAscii.js.map +1 -1
- package/build/core/exec.d.ts +0 -12
- package/build/core/exec.d.ts.map +1 -1
- package/build/core/exec.js +2 -14
- package/build/core/exec.js.map +1 -1
- package/build/core/executor.js +0 -3
- package/build/core/executor.js.map +1 -1
- package/build/core/fastRefreshRecorder.js +0 -4
- package/build/core/fastRefreshRecorder.js.map +1 -1
- package/build/core/fastRefreshTools.js +0 -3
- package/build/core/fastRefreshTools.js.map +1 -1
- package/build/core/feedback.js +0 -4
- package/build/core/feedback.js.map +1 -1
- package/build/core/graphqlOperation.d.ts +13 -0
- package/build/core/graphqlOperation.d.ts.map +1 -0
- package/build/core/graphqlOperation.js +80 -0
- package/build/core/graphqlOperation.js.map +1 -0
- package/build/core/guides.d.ts +0 -10
- package/build/core/guides.d.ts.map +1 -1
- package/build/core/guides.js +0 -10
- package/build/core/guides.js.map +1 -1
- package/build/core/iconSemantics.d.ts +0 -15
- package/build/core/iconSemantics.d.ts.map +1 -1
- package/build/core/iconSemantics.js +0 -31
- package/build/core/iconSemantics.js.map +1 -1
- package/build/core/index.js +4 -47
- package/build/core/index.js.map +1 -1
- package/build/core/injected/visibility.d.ts +0 -30
- package/build/core/injected/visibility.d.ts.map +1 -1
- package/build/core/injected/visibility.js +0 -33
- package/build/core/injected/visibility.js.map +1 -1
- package/build/core/injectedFilters.d.ts +0 -28
- package/build/core/injectedFilters.d.ts.map +1 -1
- package/build/core/injectedFilters.js +0 -28
- package/build/core/injectedFilters.js.map +1 -1
- package/build/core/inputTarget.d.ts +1 -34
- package/build/core/inputTarget.d.ts.map +1 -1
- package/build/core/inputTarget.js +0 -26
- package/build/core/inputTarget.js.map +1 -1
- package/build/core/inputTargetTools.d.ts +0 -7
- package/build/core/inputTargetTools.d.ts.map +1 -1
- package/build/core/inputTargetTools.js +0 -7
- package/build/core/inputTargetTools.js.map +1 -1
- package/build/core/inspector.d.ts +0 -33
- package/build/core/inspector.d.ts.map +1 -1
- package/build/core/inspector.js +27 -40
- package/build/core/inspector.js.map +1 -1
- package/build/core/ios.d.ts +11 -122
- package/build/core/ios.d.ts.map +1 -1
- package/build/core/ios.js +32 -299
- package/build/core/ios.js.map +1 -1
- package/build/core/jsExecute.d.ts +0 -100
- package/build/core/jsExecute.d.ts.map +1 -1
- package/build/core/jsExecute.js +0 -261
- package/build/core/jsExecute.js.map +1 -1
- package/build/core/jsLogEvents.d.ts +0 -8
- package/build/core/jsLogEvents.d.ts.map +1 -1
- package/build/core/jsLogEvents.js +0 -8
- package/build/core/jsLogEvents.js.map +1 -1
- package/build/core/keyboardMetrics.js +0 -8
- package/build/core/keyboardMetrics.js.map +1 -1
- package/build/core/keyboardRaise.d.ts +0 -8
- package/build/core/keyboardRaise.d.ts.map +1 -1
- package/build/core/keyboardRaise.js +0 -23
- package/build/core/keyboardRaise.js.map +1 -1
- package/build/core/license.d.ts +0 -4
- package/build/core/license.d.ts.map +1 -1
- package/build/core/license.js +2 -55
- package/build/core/license.js.map +1 -1
- package/build/core/logDiagnosis.d.ts +0 -34
- package/build/core/logDiagnosis.d.ts.map +1 -1
- package/build/core/logDiagnosis.js +0 -15
- package/build/core/logDiagnosis.js.map +1 -1
- package/build/core/logEventFormat.d.ts +0 -1
- package/build/core/logEventFormat.d.ts.map +1 -1
- package/build/core/logEventFormat.js +0 -30
- package/build/core/logEventFormat.js.map +1 -1
- package/build/core/logEvents.d.ts +0 -54
- package/build/core/logEvents.d.ts.map +1 -1
- package/build/core/logEvents.js +0 -37
- package/build/core/logEvents.js.map +1 -1
- package/build/core/logGrouping.d.ts +0 -9
- package/build/core/logGrouping.d.ts.map +1 -1
- package/build/core/logGrouping.js +0 -17
- package/build/core/logGrouping.js.map +1 -1
- package/build/core/logOwnership.d.ts +0 -17
- package/build/core/logOwnership.d.ts.map +1 -1
- package/build/core/logOwnership.js +0 -34
- package/build/core/logOwnership.js.map +1 -1
- package/build/core/logRelevance.d.ts +0 -8
- package/build/core/logRelevance.d.ts.map +1 -1
- package/build/core/logRelevance.js +0 -15
- package/build/core/logRelevance.js.map +1 -1
- package/build/core/logSourceAndroid.d.ts +0 -8
- package/build/core/logSourceAndroid.d.ts.map +1 -1
- package/build/core/logSourceAndroid.js +0 -11
- package/build/core/logSourceAndroid.js.map +1 -1
- package/build/core/logSourceIos.d.ts +0 -8
- package/build/core/logSourceIos.d.ts.map +1 -1
- package/build/core/logSourceIos.js +1 -24
- package/build/core/logSourceIos.js.map +1 -1
- package/build/core/logbox.d.ts +0 -30
- package/build/core/logbox.d.ts.map +1 -1
- package/build/core/logbox.js +0 -43
- package/build/core/logbox.js.map +1 -1
- package/build/core/logs.d.ts +0 -6
- package/build/core/logs.d.ts.map +1 -1
- package/build/core/logs.js +0 -19
- package/build/core/logs.js.map +1 -1
- package/build/core/metro.d.ts +0 -14
- package/build/core/metro.d.ts.map +1 -1
- package/build/core/metro.js +1 -32
- package/build/core/metro.js.map +1 -1
- package/build/core/moduleRegistry.d.ts +0 -17
- package/build/core/moduleRegistry.d.ts.map +1 -1
- package/build/core/moduleRegistry.js +0 -17
- package/build/core/moduleRegistry.js.map +1 -1
- package/build/core/nativeInputValue.d.ts +0 -29
- package/build/core/nativeInputValue.d.ts.map +1 -1
- package/build/core/nativeInputValue.js +0 -18
- package/build/core/nativeInputValue.js.map +1 -1
- package/build/core/nativeLogs.d.ts +0 -47
- package/build/core/nativeLogs.d.ts.map +1 -1
- package/build/core/nativeLogs.js +0 -82
- package/build/core/nativeLogs.js.map +1 -1
- package/build/core/nativeOnlyHints.js +0 -4
- package/build/core/nativeOnlyHints.js.map +1 -1
- package/build/core/navigate.d.ts +0 -15
- package/build/core/navigate.d.ts.map +1 -1
- package/build/core/navigate.js +0 -22
- package/build/core/navigate.js.map +1 -1
- package/build/core/navigation.d.ts +0 -60
- package/build/core/navigation.d.ts.map +1 -1
- package/build/core/navigation.js +0 -60
- package/build/core/navigation.js.map +1 -1
- package/build/core/network.d.ts +0 -5
- package/build/core/network.d.ts.map +1 -1
- package/build/core/network.js +10 -31
- package/build/core/network.js.map +1 -1
- package/build/core/networkInterceptor.d.ts +0 -19
- package/build/core/networkInterceptor.d.ts.map +1 -1
- package/build/core/networkInterceptor.js +3 -27
- package/build/core/networkInterceptor.js.map +1 -1
- package/build/core/ocr.d.ts +0 -31
- package/build/core/ocr.d.ts.map +1 -1
- package/build/core/ocr.js +1 -71
- package/build/core/ocr.js.map +1 -1
- package/build/core/paths.js +0 -1
- package/build/core/paths.js.map +1 -1
- package/build/core/posthog.js +0 -7
- package/build/core/posthog.js.map +1 -1
- package/build/core/pressables.d.ts +0 -25
- package/build/core/pressables.d.ts.map +1 -1
- package/build/core/pressables.js +0 -37
- package/build/core/pressables.js.map +1 -1
- package/build/core/probe.d.ts +0 -9
- package/build/core/probe.d.ts.map +1 -1
- package/build/core/probe.js +0 -9
- package/build/core/probe.js.map +1 -1
- package/build/core/projectMemory.d.ts +0 -2
- package/build/core/projectMemory.d.ts.map +1 -1
- package/build/core/projectMemory.js +2 -7
- package/build/core/projectMemory.js.map +1 -1
- package/build/core/projectStore.d.ts +0 -18
- package/build/core/projectStore.d.ts.map +1 -1
- package/build/core/projectStore.js +0 -19
- package/build/core/projectStore.js.map +1 -1
- package/build/core/promiseHandles.d.ts +0 -13
- package/build/core/promiseHandles.d.ts.map +1 -1
- package/build/core/promiseHandles.js +0 -25
- package/build/core/promiseHandles.js.map +1 -1
- package/build/core/register.js +0 -44
- package/build/core/register.js.map +1 -1
- package/build/core/rnGlobalsBootstrap.d.ts +0 -13
- package/build/core/rnGlobalsBootstrap.d.ts.map +1 -1
- package/build/core/rnGlobalsBootstrap.js +0 -22
- package/build/core/rnGlobalsBootstrap.js.map +1 -1
- package/build/core/routeHistory.d.ts +24 -0
- package/build/core/routeHistory.d.ts.map +1 -0
- package/build/core/routeHistory.js +186 -0
- package/build/core/routeHistory.js.map +1 -0
- package/build/core/screenLayout.d.ts +0 -11
- package/build/core/screenLayout.d.ts.map +1 -1
- package/build/core/screenLayout.js +24 -61
- package/build/core/screenLayout.js.map +1 -1
- package/build/core/screenSpace.d.ts +32 -44
- package/build/core/screenSpace.d.ts.map +1 -1
- package/build/core/screenSpace.js +80 -46
- package/build/core/screenSpace.js.map +1 -1
- package/build/core/screenSpaceDevice.d.ts +0 -8
- package/build/core/screenSpaceDevice.d.ts.map +1 -1
- package/build/core/screenSpaceDevice.js +31 -14
- package/build/core/screenSpaceDevice.js.map +1 -1
- package/build/core/screenState.d.ts +2 -74
- package/build/core/screenState.d.ts.map +1 -1
- package/build/core/screenState.js +204 -145
- package/build/core/screenState.js.map +1 -1
- package/build/core/sdkBridge.js +0 -8
- package/build/core/sdkBridge.js.map +1 -1
- package/build/core/sdkMirrorPoller.d.ts +0 -18
- package/build/core/sdkMirrorPoller.d.ts.map +1 -1
- package/build/core/sdkMirrorPoller.js +0 -47
- package/build/core/sdkMirrorPoller.js.map +1 -1
- package/build/core/selectionBuffer.d.ts +0 -6
- package/build/core/selectionBuffer.d.ts.map +1 -1
- package/build/core/selectionBuffer.js +0 -5
- package/build/core/selectionBuffer.js.map +1 -1
- package/build/core/signedVerdict.js +0 -6
- package/build/core/signedVerdict.js.map +1 -1
- package/build/core/state.d.ts +0 -31
- package/build/core/state.d.ts.map +1 -1
- package/build/core/state.js +0 -57
- package/build/core/state.js.map +1 -1
- package/build/core/symbolicate.js +0 -11
- package/build/core/symbolicate.js.map +1 -1
- package/build/core/telemetry.d.ts +0 -47
- package/build/core/telemetry.d.ts.map +1 -1
- package/build/core/telemetry.js +1 -173
- package/build/core/telemetry.js.map +1 -1
- package/build/core/textEntry.d.ts +0 -34
- package/build/core/textEntry.d.ts.map +1 -1
- package/build/core/textEntry.js +0 -73
- package/build/core/textEntry.js.map +1 -1
- package/build/core/toolHelpers.d.ts +0 -12
- package/build/core/toolHelpers.d.ts.map +1 -1
- package/build/core/toolHelpers.js +2 -47
- package/build/core/toolHelpers.js.map +1 -1
- package/build/core/truncate.d.ts +0 -17
- package/build/core/truncate.d.ts.map +1 -1
- package/build/core/truncate.js +0 -32
- package/build/core/truncate.js.map +1 -1
- package/build/core/types.d.ts +0 -6
- package/build/core/types.d.ts.map +1 -1
- package/build/core/usageCache.js +0 -12
- package/build/core/usageCache.js.map +1 -1
- package/build/index.js +0 -18
- package/build/index.js.map +1 -1
- package/build/pro/coordinateMiss.d.ts +0 -30
- package/build/pro/coordinateMiss.d.ts.map +1 -1
- package/build/pro/coordinateMiss.js +0 -17
- package/build/pro/coordinateMiss.js.map +1 -1
- package/build/pro/overlayGuard.d.ts +27 -0
- package/build/pro/overlayGuard.d.ts.map +1 -0
- package/build/pro/overlayGuard.js +103 -0
- package/build/pro/overlayGuard.js.map +1 -0
- package/build/pro/screenshot-diff.js +4 -6
- package/build/pro/screenshot-diff.js.map +1 -1
- package/build/pro/tap.d.ts +0 -55
- package/build/pro/tap.d.ts.map +1 -1
- package/build/pro/tap.js +72 -316
- package/build/pro/tap.js.map +1 -1
- package/build/pro/usageGate.js +0 -9
- package/build/pro/usageGate.js.map +1 -1
- package/build/pro/usageNotifications.js +1 -13
- package/build/pro/usageNotifications.js.map +1 -1
- package/build/pro/verifyAction.d.ts +0 -13
- package/build/pro/verifyAction.d.ts.map +1 -1
- package/build/pro/verifyAction.js +0 -45
- package/build/pro/verifyAction.js.map +1 -1
- package/build/tools/_deviceArg.d.ts +0 -35
- package/build/tools/_deviceArg.d.ts.map +1 -1
- package/build/tools/_deviceArg.js +0 -35
- package/build/tools/_deviceArg.js.map +1 -1
- package/build/tools/accountTools.js +2 -2
- package/build/tools/accountTools.js.map +1 -1
- package/build/tools/bundleTools.js +0 -16
- package/build/tools/bundleTools.js.map +1 -1
- package/build/tools/componentTools.d.ts.map +1 -1
- package/build/tools/componentTools.js +47 -53
- package/build/tools/componentTools.js.map +1 -1
- package/build/tools/connectionTools.js +1 -59
- package/build/tools/connectionTools.js.map +1 -1
- package/build/tools/deviceTools.js +0 -11
- package/build/tools/deviceTools.js.map +1 -1
- package/build/tools/executionTools.js +1 -18
- package/build/tools/executionTools.js.map +1 -1
- package/build/tools/interactionTools.d.ts +0 -10
- package/build/tools/interactionTools.d.ts.map +1 -1
- package/build/tools/interactionTools.js +0 -57
- package/build/tools/interactionTools.js.map +1 -1
- package/build/tools/logTools.d.ts +0 -13
- package/build/tools/logTools.d.ts.map +1 -1
- package/build/tools/logTools.js +2 -126
- package/build/tools/logTools.js.map +1 -1
- package/build/tools/metaTools.js +0 -10
- package/build/tools/metaTools.js.map +1 -1
- package/build/tools/networkTools.js +4 -43
- package/build/tools/networkTools.js.map +1 -1
- package/build/tools/requestTools.js +0 -5
- package/build/tools/requestTools.js.map +1 -1
- package/build/tools/screenshotTools.js +5 -111
- package/build/tools/screenshotTools.js.map +1 -1
- package/package.json +2 -2
- package/tools.json +1 -0
package/build/core/jsExecute.js
CHANGED
|
@@ -8,71 +8,37 @@ import { trackAutoReconnect } from "./telemetry.js";
|
|
|
8
8
|
import { probeCdpAlive } from "./probe.js";
|
|
9
9
|
import { buildContextPreamble } from "./appContext.js";
|
|
10
10
|
import { registerHandle } from "./promiseHandles.js";
|
|
11
|
-
// Hermes runtime compatibility: polyfill for 'global' which doesn't exist in Hermes
|
|
12
|
-
// In Hermes, globalThis is the standard way to access global scope
|
|
13
11
|
const GLOBAL_POLYFILL = `var global = typeof global !== 'undefined' ? global : globalThis;`;
|
|
14
|
-
// The preamble is static source; re-stringifying it per call would be waste.
|
|
15
12
|
let cachedContextPreamble = null;
|
|
16
|
-
/**
|
|
17
|
-
* Assemble what Hermes actually compiles: global polyfill, then the resolved
|
|
18
|
-
* app context, then the caller's expression verbatim.
|
|
19
|
-
*
|
|
20
|
-
* The caller's expression is never wrapped — PR #5 reverted blanket IIFE
|
|
21
|
-
* wrapping because it discarded return values and double-wrapped tools that
|
|
22
|
-
* build their own IIFE. Context bindings use `var` so they remain visible
|
|
23
|
-
* inside the manual-await wrapper, which emits `var __v=(<expr>);` downstream.
|
|
24
|
-
*/
|
|
25
13
|
export function buildEvaluationSource(cleanedExpression) {
|
|
26
14
|
if (cachedContextPreamble === null) {
|
|
27
15
|
cachedContextPreamble = buildContextPreamble();
|
|
28
16
|
}
|
|
29
17
|
return `${GLOBAL_POLYFILL}\n${cachedContextPreamble}\n${cleanedExpression}`;
|
|
30
18
|
}
|
|
31
|
-
/**
|
|
32
|
-
* Check if a string contains emoji or other problematic Unicode characters
|
|
33
|
-
* Hermes has issues with certain UTF-16 surrogate pairs (like emoji)
|
|
34
|
-
* @deprecated retained for backward compatibility — escapeNonAsciiInStringLiterals handles this now.
|
|
35
|
-
*/
|
|
36
19
|
export function containsProblematicUnicode(str) {
|
|
37
|
-
// Detect UTF-16 surrogate pairs (emoji and other characters outside BMP)
|
|
38
|
-
// These cause "Invalid UTF-8 code point" errors in Hermes
|
|
39
|
-
// eslint-disable-next-line no-control-regex
|
|
40
20
|
return /[\uD800-\uDFFF]/.test(str);
|
|
41
21
|
}
|
|
42
|
-
/**
|
|
43
|
-
* Strip leading comments from an expression
|
|
44
|
-
* Users often start with // comments which break the (return expr) wrapping
|
|
45
|
-
*/
|
|
46
22
|
export function stripLeadingComments(expression) {
|
|
47
23
|
let result = expression;
|
|
48
|
-
// Strip leading whitespace first
|
|
49
24
|
result = result.trimStart();
|
|
50
|
-
// Repeatedly strip leading single-line comments (// ...)
|
|
51
25
|
while (result.startsWith("//")) {
|
|
52
26
|
const newlineIndex = result.indexOf("\n");
|
|
53
27
|
if (newlineIndex === -1) {
|
|
54
|
-
// Entire expression is a comment
|
|
55
28
|
return "";
|
|
56
29
|
}
|
|
57
30
|
result = result.slice(newlineIndex + 1).trimStart();
|
|
58
31
|
}
|
|
59
|
-
// Strip leading multi-line comments (/* ... */)
|
|
60
32
|
while (result.startsWith("/*")) {
|
|
61
33
|
const endIndex = result.indexOf("*/");
|
|
62
34
|
if (endIndex === -1) {
|
|
63
|
-
// Unclosed comment
|
|
64
35
|
return result;
|
|
65
36
|
}
|
|
66
37
|
result = result.slice(endIndex + 2).trimStart();
|
|
67
38
|
}
|
|
68
39
|
return result;
|
|
69
40
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Validate and preprocess an expression before execution
|
|
72
|
-
* Returns cleaned expression or error with helpful message
|
|
73
|
-
*/
|
|
74
41
|
export function validateAndPreprocessExpression(expression) {
|
|
75
|
-
// Strip leading comments that would break the expression wrapper
|
|
76
42
|
const cleaned = stripLeadingComments(expression);
|
|
77
43
|
if (!cleaned.trim()) {
|
|
78
44
|
return {
|
|
@@ -81,8 +47,6 @@ export function validateAndPreprocessExpression(expression) {
|
|
|
81
47
|
error: "Expression is empty or contains only comments."
|
|
82
48
|
};
|
|
83
49
|
}
|
|
84
|
-
// Auto-escape non-ASCII inside string literals so the wire stays ASCII
|
|
85
|
-
// and Hermes can compile the expression.
|
|
86
50
|
const escapeResult = escapeNonAsciiInStringLiterals(cleaned);
|
|
87
51
|
if (!escapeResult.ok) {
|
|
88
52
|
return {
|
|
@@ -94,7 +58,6 @@ export function validateAndPreprocessExpression(expression) {
|
|
|
94
58
|
};
|
|
95
59
|
}
|
|
96
60
|
const escaped = escapeResult.expression;
|
|
97
|
-
// Check for top-level async/await that Hermes doesn't support in Runtime.evaluate
|
|
98
61
|
const trimmed = escaped.trim();
|
|
99
62
|
if (looksLikeTopLevelAwait(trimmed)) {
|
|
100
63
|
return {
|
|
@@ -105,25 +68,10 @@ export function validateAndPreprocessExpression(expression) {
|
|
|
105
68
|
"`global.__result = null; myAsyncFn().then(r => global.__result = r)`."
|
|
106
69
|
};
|
|
107
70
|
}
|
|
108
|
-
// NOTE: require() used to be rejected here. It now works — the injected
|
|
109
|
-
// context defines `require` over Metro's module registry (see
|
|
110
|
-
// appContext.ts / moduleRegistry.ts), which addressed the second-largest
|
|
111
|
-
// production failure class (236 events). Unresolvable names return an
|
|
112
|
-
// object carrying __eb_error rather than throwing.
|
|
113
|
-
// Check for multi-statement expressions. Runtime.evaluate compiles input as
|
|
114
|
-
// a single expression — `console.log('x'); 1+1` raises `')' expected at end
|
|
115
|
-
// of parenthesized expression`. Internal callers wrap in (function(){...})()
|
|
116
|
-
// so any `;` they use is at brace depth 1 and won't be flagged.
|
|
117
|
-
// executeWithManualAwait emits `var __v=(<expr>);`, so a depth-0 `;` breaks
|
|
118
|
-
// compilation. Rewrite into the IIFE ourselves instead of making the caller
|
|
119
|
-
// do it — this was the single largest execute_in_app failure class
|
|
120
|
-
// (125 events / 42 installations over 30d).
|
|
121
71
|
const wrapped = wrapMultiStatementInIife(trimmed);
|
|
122
72
|
if (wrapped) {
|
|
123
73
|
return { valid: true, expression: wrapped, rewritten: "iife-wrap" };
|
|
124
74
|
}
|
|
125
|
-
// More than one statement, but the last one can't yield a value — we can't
|
|
126
|
-
// synthesize a sensible `return`, so explain rather than guess.
|
|
127
75
|
if (splitTopLevelStatements(trimmed).length > 1) {
|
|
128
76
|
return {
|
|
129
77
|
valid: false,
|
|
@@ -143,10 +91,6 @@ export function validateAndPreprocessExpression(expression) {
|
|
|
143
91
|
function isIdentChar(c) {
|
|
144
92
|
return c !== undefined && /[A-Za-z0-9_$]/.test(c);
|
|
145
93
|
}
|
|
146
|
-
// Devices whose Hermes build rejects `async` function syntax in
|
|
147
|
-
// Runtime.evaluate ("Compiling JS failed: N:M:async functions are unsupported").
|
|
148
|
-
// Populated reactively on the first such failure, then used to reject
|
|
149
|
-
// pre-flight with actionable guidance instead of spending another round trip.
|
|
150
94
|
const asyncEvalUnsupported = new Set();
|
|
151
95
|
export function markAsyncEvalUnsupported(deviceKey) {
|
|
152
96
|
asyncEvalUnsupported.add(deviceKey);
|
|
@@ -154,14 +98,10 @@ export function markAsyncEvalUnsupported(deviceKey) {
|
|
|
154
98
|
export function isAsyncEvalUnsupported(deviceKey) {
|
|
155
99
|
return asyncEvalUnsupported.has(deviceKey);
|
|
156
100
|
}
|
|
157
|
-
// Test-only: async support is a per-engine property, so tests need a reset.
|
|
158
101
|
export function resetAsyncEvalSupport() {
|
|
159
102
|
asyncEvalUnsupported.clear();
|
|
160
103
|
}
|
|
161
104
|
const ASYNC_UNSUPPORTED_HERMES = /async functions are unsupported/i;
|
|
162
|
-
// Blank out string/template literal bodies and comments, preserving length and
|
|
163
|
-
// structure, so syntax probes never match on text inside a literal. Replacing
|
|
164
|
-
// rather than deleting keeps offsets stable for any future diagnostics.
|
|
165
105
|
export function maskLiteralsAndComments(src) {
|
|
166
106
|
const out = src.split("");
|
|
167
107
|
let i = 0;
|
|
@@ -206,10 +146,6 @@ export function maskLiteralsAndComments(src) {
|
|
|
206
146
|
}
|
|
207
147
|
return out.join("");
|
|
208
148
|
}
|
|
209
|
-
// `async function foo(){}` / `async () => {}` / `async x => {}`.
|
|
210
|
-
// Literals are masked first: a string containing "async (" must not be
|
|
211
|
-
// mistaken for async syntax, or we reintroduce the over-eager pre-flight
|
|
212
|
-
// rejection that f6fb8a0 removed.
|
|
213
149
|
export function looksLikeAsyncFunction(src) {
|
|
214
150
|
return /\basync\s*(function\b|\(|[A-Za-z_$][\w$]*\s*=>)/.test(maskLiteralsAndComments(src));
|
|
215
151
|
}
|
|
@@ -220,22 +156,7 @@ const ASYNC_UNSUPPORTED_GUIDANCE = "async functions are not supported by this de
|
|
|
220
156
|
"the returned Promise is resolved for you when awaitPromise is true. " +
|
|
221
157
|
"Note this is engine-dependent: some Hermes builds do compile async functions, so the same " +
|
|
222
158
|
"expression may work on another device.";
|
|
223
|
-
// Detect a bare top-level `await` in `src`. Walks char-by-char tracking string,
|
|
224
|
-
// template, comment, and bracket depth so we don't false-positive on
|
|
225
|
-
// substrings inside strings, identifiers like `awaiting`, etc.
|
|
226
|
-
//
|
|
227
|
-
// NOTE: `async function`/`async () => {}`/`(async () => {})()` are not flagged
|
|
228
|
-
// unconditionally. Support is ENGINE-DEPENDENT: some Hermes builds compile them
|
|
229
|
-
// (rejecting them outright cost ~20 legitimate calls/30d across 10
|
|
230
|
-
// installations, which is why f6fb8a0 stopped doing so), while others fail with
|
|
231
|
-
// "async functions are unsupported" — reproduced 2026-07-31 on Hermes/Expo 55
|
|
232
|
-
// (iOS) and on Android. Blanket accept and blanket reject are both wrong, so
|
|
233
|
-
// capability is learned per device from the first failure (see
|
|
234
|
-
// asyncEvalUnsupported). Only a bare top-level `await` is unconditionally a
|
|
235
|
-
// syntax error, because the wrapper emits `var __v=(<expr>);` — a non-async
|
|
236
|
-
// context.
|
|
237
159
|
function looksLikeTopLevelAwait(src) {
|
|
238
|
-
// Depth-tracked scan for a standalone `await` token at depth 0.
|
|
239
160
|
let i = 0;
|
|
240
161
|
let parens = 0;
|
|
241
162
|
let braces = 0;
|
|
@@ -314,18 +235,7 @@ function looksLikeTopLevelAwait(src) {
|
|
|
314
235
|
}
|
|
315
236
|
return false;
|
|
316
237
|
}
|
|
317
|
-
// Statement forms that cannot be the final segment of an auto-wrapped IIFE,
|
|
318
|
-
// because prefixing them with `return` is either a syntax error or drops the
|
|
319
|
-
// value the caller wanted back. `return` itself is handled separately.
|
|
320
238
|
const NON_VALUE_STATEMENT_START = /^(?:if|for|while|do|switch|try|catch|finally|throw|var|let|const|function|class|debugger|break|continue|with|else)\b|^\{/;
|
|
321
|
-
/**
|
|
322
|
-
* Rewrite a multi-statement source into the IIFE that Hermes can compile,
|
|
323
|
-
* returning `null` when the rewrite would not be safe.
|
|
324
|
-
*
|
|
325
|
-
* `stmt1; stmt2; value` becomes `(function(){ stmt1; stmt2; return value; })()`.
|
|
326
|
-
* Bails out when the final segment cannot yield a value, so those callers still
|
|
327
|
-
* get the explanatory error rather than a silently broken transform.
|
|
328
|
-
*/
|
|
329
239
|
export function wrapMultiStatementInIife(src) {
|
|
330
240
|
const segments = splitTopLevelStatements(src);
|
|
331
241
|
if (segments.length <= 1)
|
|
@@ -337,9 +247,6 @@ export function wrapMultiStatementInIife(src) {
|
|
|
337
247
|
const body = last.startsWith("return") && !isIdentChar(last[6]) ? last : `return ${last}`;
|
|
338
248
|
return `(function(){ ${[...head, body].join("; ")}; })()`;
|
|
339
249
|
}
|
|
340
|
-
// Walk `src` tracking string/template/comment and bracket depth, splitting on
|
|
341
|
-
// `;` at depth 0. Returns the trimmed top-level statements; a trailing `;` that
|
|
342
|
-
// merely terminates the final statement produces no extra segment.
|
|
343
250
|
export function splitTopLevelStatements(src) {
|
|
344
251
|
const segments = [];
|
|
345
252
|
let segmentStart = 0;
|
|
@@ -406,15 +313,8 @@ export function splitTopLevelStatements(src) {
|
|
|
406
313
|
push(src.length);
|
|
407
314
|
return segments;
|
|
408
315
|
}
|
|
409
|
-
// ============================================================================
|
|
410
|
-
// Per-call timeoutMs: clamp + defaults
|
|
411
|
-
// ============================================================================
|
|
412
316
|
export const TIMEOUT_HARD_CAP_MS = 120_000;
|
|
413
317
|
const TIMEOUT_DEFAULT_MS = 5_000;
|
|
414
|
-
// Flips true after the first successful executeInApp OR successful CDP
|
|
415
|
-
// connection in this process. Used by the auto-reconnect wrapper to distinguish
|
|
416
|
-
// "Metro/app never came up" (don't bother scanning) from a mid-session
|
|
417
|
-
// transport drop worth retrying.
|
|
418
318
|
let hasEverConnected = false;
|
|
419
319
|
export function markConnectionEstablished() {
|
|
420
320
|
hasEverConnected = true;
|
|
@@ -428,36 +328,12 @@ export function clampTimeoutMs(input) {
|
|
|
428
328
|
}
|
|
429
329
|
return { value: input };
|
|
430
330
|
}
|
|
431
|
-
// How long to wait for the disambiguating probe on a ws=OPEN timeout. Matches
|
|
432
|
-
// PROBE_TIMEOUT_MS in connection.ts, which uses the same probe to reject stale
|
|
433
|
-
// CDP targets at connect time.
|
|
434
331
|
const STALE_TARGET_PROBE_TIMEOUT_MS = 1_500;
|
|
435
|
-
/**
|
|
436
|
-
* True for the one ambiguous failure shape: our own timer fired while the
|
|
437
|
-
* socket was still OPEN.
|
|
438
|
-
*
|
|
439
|
-
* Everything else is already decided. ws=CLOSED is transport (handled in
|
|
440
|
-
* classifyTransportError); a CDP-sourced error carries its own signal. This
|
|
441
|
-
* case alone can be either a genuinely slow expression or a stale CDP target
|
|
442
|
-
* that silently swallows evaluates while the device socket keeps ponging — and
|
|
443
|
-
* only a probe can tell them apart.
|
|
444
|
-
*/
|
|
445
332
|
export function isEvalTimeoutOnLiveSocket(message, source) {
|
|
446
333
|
if (source !== "server-timer")
|
|
447
334
|
return false;
|
|
448
335
|
return /ws=OPEN/i.test(message);
|
|
449
336
|
}
|
|
450
|
-
/**
|
|
451
|
-
* Is our CDP page still listed by Metro?
|
|
452
|
-
*
|
|
453
|
-
* This is the signal that a JS-level probe cannot provide: it goes over Metro's
|
|
454
|
-
* HTTP /json, so a blocked JavaScript thread has no effect on the answer.
|
|
455
|
-
*
|
|
456
|
-
* Conservative on purpose — an empty list (Metro unreachable, momentary blip)
|
|
457
|
-
* or a missing id counts as "still there". A false "gone" costs a reconnect and
|
|
458
|
-
* a retry that RE-RUNS the caller's expression, which must never happen on a
|
|
459
|
-
* guess.
|
|
460
|
-
*/
|
|
461
337
|
export async function isTargetStillAdvertised(app, fetchTargets = fetchDevices) {
|
|
462
338
|
const id = app.deviceInfo?.id;
|
|
463
339
|
if (!id)
|
|
@@ -467,28 +343,6 @@ export async function isTargetStillAdvertised(app, fetchTargets = fetchDevices)
|
|
|
467
343
|
return true;
|
|
468
344
|
return targets.some((t) => t.id === id);
|
|
469
345
|
}
|
|
470
|
-
/**
|
|
471
|
-
* classifyTransportError plus disambiguation for the one ambiguous shape: our
|
|
472
|
-
* timer fired while the socket was still OPEN.
|
|
473
|
-
*
|
|
474
|
-
* The transport was alive (the 1s ping/pong keepalive would have killed a dead
|
|
475
|
-
* socket within ~2s), so this is one of three things:
|
|
476
|
-
*
|
|
477
|
-
* 1. a genuinely slow ASYNC expression -> probe answers -> logical
|
|
478
|
-
* 2. a genuinely slow SYNC expression -> probe silent, but the
|
|
479
|
-
* (busy loop, big serialize) page is still listed -> logical
|
|
480
|
-
* 3. a stale CDP target (app reloaded -> probe silent AND the
|
|
481
|
-
* via shake / Metro 'r') page is gone -> transport
|
|
482
|
-
*
|
|
483
|
-
* Both signals are required for case 3. The probe alone cannot separate 2 from
|
|
484
|
-
* 3 — it is itself a Runtime.evaluate, so a blocked JS thread silences it
|
|
485
|
-
* exactly like a dead context. Verified on-device: a 15s busy loop silenced the
|
|
486
|
-
* probe and was misread as stale, triggering a reconnect that re-ran the
|
|
487
|
-
* expression. Metro's target list is independent of the JS thread and settles it.
|
|
488
|
-
*
|
|
489
|
-
* `probe` and `targetStillAdvertised` are injectable so the decision is
|
|
490
|
-
* testable without a socket or a Metro server.
|
|
491
|
-
*/
|
|
492
346
|
export async function classifyWithLivenessProbe(message, source, app, probe = probeCdpAlive, targetStillAdvertised = isTargetStillAdvertised) {
|
|
493
347
|
const base = classifyTransportError(message, source);
|
|
494
348
|
if (base.kind === "transport")
|
|
@@ -500,31 +354,13 @@ export async function classifyWithLivenessProbe(message, source, app, probe = pr
|
|
|
500
354
|
const alive = await probe(app.ws, STALE_TARGET_PROBE_TIMEOUT_MS);
|
|
501
355
|
if (alive)
|
|
502
356
|
return base;
|
|
503
|
-
// Probe silent. Only a target that Metro no longer lists is truly stale;
|
|
504
|
-
// otherwise the JS thread is just busy and retrying would re-run the call.
|
|
505
357
|
if (await targetStillAdvertised(app))
|
|
506
358
|
return base;
|
|
507
359
|
return { kind: "transport", pattern: "stale_target" };
|
|
508
360
|
}
|
|
509
|
-
/**
|
|
510
|
-
* Classify an error message into transport-vs-logical for auto-reconnect routing.
|
|
511
|
-
*
|
|
512
|
-
* The `source` argument distinguishes the CDP-emitted "Expression took too long"
|
|
513
|
-
* (a stale-target signal we DO want to reconnect on) from the server-side
|
|
514
|
-
* `Promise.race` timer text (a logical "this took too long" we do NOT).
|
|
515
|
-
*/
|
|
516
361
|
export function classifyTransportError(message, source) {
|
|
517
362
|
if (!message)
|
|
518
363
|
return { kind: "logical" };
|
|
519
|
-
// A server-timer expiry is normally logical ("this expression is slow").
|
|
520
|
-
// But the timer snapshots ws state into the message, and a CLOSED socket
|
|
521
|
-
// means the call never had a live transport to answer it — that is a
|
|
522
|
-
// transport failure no matter which timer noticed. Checked before the
|
|
523
|
-
// server-timer bail-out, which otherwise swallowed it.
|
|
524
|
-
//
|
|
525
|
-
// Primarily a backstop: failPendingExecutionsForSocket now fails in-flight
|
|
526
|
-
// calls at close time, so most of these surface as "WebSocket connection is
|
|
527
|
-
// not open" instead. This covers the race where our timer fires first.
|
|
528
364
|
if (/ws=CLOSED/i.test(message))
|
|
529
365
|
return { kind: "transport", pattern: "ws_closed" };
|
|
530
366
|
if (source === "server-timer")
|
|
@@ -540,17 +376,8 @@ export function classifyTransportError(message, source) {
|
|
|
540
376
|
if (/target closed/i.test(message) || /Inspector detached/i.test(message)) {
|
|
541
377
|
return { kind: "transport", pattern: "target_closed" };
|
|
542
378
|
}
|
|
543
|
-
// NOTE: there used to be a `cdp_eval_too_long` branch here for a CDP-side
|
|
544
|
-
// "Expression took too long to evaluate". It was unreachable: the only
|
|
545
|
-
// producer of that phrase is our own timer in executeCDP, whose message
|
|
546
|
-
// always starts with "Timeout: Expression took too long" and is therefore
|
|
547
|
-
// tagged `server-timer` and handled above. Telemetry agrees — 367 such
|
|
548
|
-
// events over 90 days, none of them lacking our "Connection state:" block.
|
|
549
|
-
// Retrying is also wrong here: the 1s ping/pong keepalive terminates dead
|
|
550
|
-
// sockets within ~2s, so a still-OPEN socket had a live transport all along.
|
|
551
379
|
return { kind: "logical" };
|
|
552
380
|
}
|
|
553
|
-
// Error patterns that indicate a stale/destroyed context
|
|
554
381
|
const CONTEXT_ERROR_PATTERNS = [
|
|
555
382
|
"cannot find context",
|
|
556
383
|
"execution context was destroyed",
|
|
@@ -561,24 +388,15 @@ const CONTEXT_ERROR_PATTERNS = [
|
|
|
561
388
|
"no execution context",
|
|
562
389
|
"runningdetached"
|
|
563
390
|
];
|
|
564
|
-
/**
|
|
565
|
-
* Check if an error indicates a stale page context
|
|
566
|
-
*/
|
|
567
391
|
function isContextError(error) {
|
|
568
392
|
if (!error)
|
|
569
393
|
return false;
|
|
570
394
|
const lowerError = error.toLowerCase();
|
|
571
395
|
return CONTEXT_ERROR_PATTERNS.some((pattern) => lowerError.includes(pattern));
|
|
572
396
|
}
|
|
573
|
-
/**
|
|
574
|
-
* Simple delay helper
|
|
575
|
-
*/
|
|
576
397
|
export function delay(ms) {
|
|
577
398
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
578
399
|
}
|
|
579
|
-
/**
|
|
580
|
-
* Attempt quick reconnection to Metro
|
|
581
|
-
*/
|
|
582
400
|
async function attemptQuickReconnect(preferredPort) {
|
|
583
401
|
try {
|
|
584
402
|
const ports = await scanMetroPorts();
|
|
@@ -596,9 +414,6 @@ async function attemptQuickReconnect(preferredPort) {
|
|
|
596
414
|
return false;
|
|
597
415
|
}
|
|
598
416
|
}
|
|
599
|
-
/**
|
|
600
|
-
* Execute expression on a connected app (core implementation without retry)
|
|
601
|
-
*/
|
|
602
417
|
async function executeExpressionCore(expression, awaitPromise, timeoutMs = 10000, targetApp) {
|
|
603
418
|
const app = targetApp ?? getFirstConnectedApp();
|
|
604
419
|
if (!app) {
|
|
@@ -607,45 +422,28 @@ async function executeExpressionCore(expression, awaitPromise, timeoutMs = 10000
|
|
|
607
422
|
if (app.ws.readyState !== WebSocket.OPEN) {
|
|
608
423
|
return { success: false, error: "WebSocket connection is not open." };
|
|
609
424
|
}
|
|
610
|
-
// Validate and preprocess the expression
|
|
611
425
|
const validation = validateAndPreprocessExpression(expression);
|
|
612
426
|
if (!validation.valid) {
|
|
613
427
|
return { success: false, error: validation.error };
|
|
614
428
|
}
|
|
615
429
|
const cleanedExpression = validation.expression;
|
|
616
|
-
// This device's Hermes already told us it can't compile async functions —
|
|
617
|
-
// reject before spending a round trip on a guaranteed compiler error.
|
|
618
430
|
const deviceKey = app.deviceInfo?.deviceName || "__default__";
|
|
619
431
|
if (isAsyncEvalUnsupported(deviceKey) && looksLikeAsyncFunction(cleanedExpression)) {
|
|
620
432
|
return { success: false, error: ASYNC_UNSUPPORTED_GUIDANCE };
|
|
621
433
|
}
|
|
622
|
-
// Hermes CDP does not support awaitPromise — it serializes the Promise's
|
|
623
|
-
// internal fields (_A, _x, _y, _z) instead of waiting for resolution.
|
|
624
|
-
// When the caller wants awaitPromise, we handle it ourselves: wrap the
|
|
625
|
-
// expression to store the resolved value in a temp global, then poll.
|
|
626
434
|
const result = awaitPromise
|
|
627
435
|
? await executeWithManualAwait(app, cleanedExpression, timeoutMs)
|
|
628
436
|
: await executeCDP(app, cleanedExpression, false, timeoutMs);
|
|
629
|
-
// Learn the capability from the engine's own compiler error, and replace
|
|
630
|
-
// the raw message with something the caller can act on.
|
|
631
437
|
if (!result.success && result.error && ASYNC_UNSUPPORTED_HERMES.test(result.error)) {
|
|
632
438
|
markAsyncEvalUnsupported(deviceKey);
|
|
633
439
|
return { success: false, error: ASYNC_UNSUPPORTED_GUIDANCE };
|
|
634
440
|
}
|
|
635
441
|
return result;
|
|
636
442
|
}
|
|
637
|
-
/**
|
|
638
|
-
* Execute a CDP Runtime.evaluate call (no promise awaiting).
|
|
639
|
-
*/
|
|
640
443
|
function executeCDP(app, cleanedExpression, awaitPromise, timeoutMs) {
|
|
641
444
|
const TIMEOUT_MS = timeoutMs;
|
|
642
445
|
const currentMessageId = getNextMessageId();
|
|
643
446
|
const wrappedExpression = buildEvaluationSource(cleanedExpression);
|
|
644
|
-
// Every send funnels through here, including executeWithManualAwait's poll
|
|
645
|
-
// loop — which re-enters between sleeps and so can start on a socket that
|
|
646
|
-
// died since the previous send. ws.send() on a CLOSED socket does not
|
|
647
|
-
// throw; it simply never gets a reply, so without this the call burns its
|
|
648
|
-
// full timeout and then reports a misleading "took too long".
|
|
649
447
|
if (app.ws.readyState !== WebSocket.OPEN) {
|
|
650
448
|
return Promise.resolve({ success: false, error: "WebSocket connection is not open." });
|
|
651
449
|
}
|
|
@@ -678,8 +476,6 @@ function executeCDP(app, cleanedExpression, awaitPromise, timeoutMs) {
|
|
|
678
476
|
].join("\n");
|
|
679
477
|
resolve({ success: false, error: errorMessage });
|
|
680
478
|
}, TIMEOUT_MS);
|
|
681
|
-
// Tag with the socket so a close event can fail this call immediately
|
|
682
|
-
// rather than letting it sit until TIMEOUT_MS.
|
|
683
479
|
pendingExecutions.set(currentMessageId, { resolve, timeoutId, ws: app.ws });
|
|
684
480
|
try {
|
|
685
481
|
app.ws.send(JSON.stringify({
|
|
@@ -691,8 +487,6 @@ function executeCDP(app, cleanedExpression, awaitPromise, timeoutMs) {
|
|
|
691
487
|
awaitPromise,
|
|
692
488
|
userGesture: true,
|
|
693
489
|
generatePreview: true,
|
|
694
|
-
// Hermes-side timeout layer. Older Hermes builds ignore this — the
|
|
695
|
-
// server-side setTimeout above is the primary defense.
|
|
696
490
|
timeout: timeoutMs
|
|
697
491
|
}
|
|
698
492
|
}));
|
|
@@ -707,15 +501,8 @@ function executeCDP(app, cleanedExpression, awaitPromise, timeoutMs) {
|
|
|
707
501
|
}
|
|
708
502
|
});
|
|
709
503
|
}
|
|
710
|
-
/**
|
|
711
|
-
* Hermes workaround for awaitPromise: execute the expression, and if it
|
|
712
|
-
* returns a Promise, store the resolved/rejected value in a temp global
|
|
713
|
-
* and read it back with a small number of spaced-out retries.
|
|
714
|
-
*/
|
|
715
504
|
async function executeWithManualAwait(app, cleanedExpression, timeoutMs) {
|
|
716
505
|
const slotId = `__rn_dbg_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
717
|
-
// Wrap: run the expression, if result is thenable store resolved value in
|
|
718
|
-
// a temp global slot; otherwise store the sync value immediately.
|
|
719
506
|
const wrapperExpr = `(function(){
|
|
720
507
|
var __v=(${cleanedExpression});
|
|
721
508
|
if(__v&&typeof __v==='object'&&typeof __v.then==='function'){
|
|
@@ -724,12 +511,9 @@ __v.then(function(r){globalThis['${slotId}']={s:'ok',v:r}},function(e){globalThi
|
|
|
724
511
|
return '__awaiting__'}
|
|
725
512
|
else{return __v}})()`;
|
|
726
513
|
const initial = await executeCDP(app, wrapperExpr, false, timeoutMs);
|
|
727
|
-
// If the expression didn't return a Promise, return the result directly
|
|
728
514
|
if (!initial.success || initial.result !== "__awaiting__") {
|
|
729
515
|
return initial;
|
|
730
516
|
}
|
|
731
|
-
// Read the settled value with a few spaced-out retries (not aggressive polling).
|
|
732
|
-
// Most Promises resolve within a microtask or a single event loop tick.
|
|
733
517
|
const RETRY_DELAYS_MS = [100, 300, 600, 1000, 2000, 3000];
|
|
734
518
|
const readExpr = `(function(){var s=globalThis['${slotId}'];if(!s||s.s==='pending')return '__pending__';delete globalThis['${slotId}'];return{status:s.s,value:s.v}})()`;
|
|
735
519
|
for (const delayMs of RETRY_DELAYS_MS) {
|
|
@@ -739,8 +523,6 @@ else{return __v}})()`;
|
|
|
739
523
|
return poll;
|
|
740
524
|
if (poll.result === "__pending__")
|
|
741
525
|
continue;
|
|
742
|
-
// The poll result comes through formatRemoteObject — objects are
|
|
743
|
-
// JSON.stringified, so we need to parse it back.
|
|
744
526
|
try {
|
|
745
527
|
const parsed = typeof poll.result === "string" ? JSON.parse(poll.result) : poll.result;
|
|
746
528
|
if (parsed?.status === "err") {
|
|
@@ -760,9 +542,6 @@ else{return __v}})()`;
|
|
|
760
542
|
return poll;
|
|
761
543
|
}
|
|
762
544
|
}
|
|
763
|
-
// Budget expired. Keep the slot: the promise will very likely settle a
|
|
764
|
-
// moment from now, and deleting it here is what made 143 production results
|
|
765
|
-
// unrecoverable (43% of all execute_in_app timeouts).
|
|
766
545
|
const budgetMs = RETRY_DELAYS_MS.reduce((a, b) => a + b, 0);
|
|
767
546
|
registerHandle(app.deviceInfo?.deviceName || "__default__", slotId);
|
|
768
547
|
return {
|
|
@@ -772,19 +551,16 @@ else{return __v}})()`;
|
|
|
772
551
|
`execute_in_app({ collect: "${slotId}" }).`
|
|
773
552
|
};
|
|
774
553
|
}
|
|
775
|
-
// Execute JavaScript in the connected React Native app with retry logic
|
|
776
554
|
async function executeInAppInner(expression, awaitPromise = true, options = {}, device) {
|
|
777
555
|
const { maxRetries = 2, retryDelayMs = 1000, autoReconnect = true, timeoutMs = 10000, skipBootstrap = false } = options;
|
|
778
556
|
let lastError;
|
|
779
557
|
let preferredPort;
|
|
780
|
-
// Get preferred port from current connection if available
|
|
781
558
|
const currentApp = getConnectedAppByDevice(device);
|
|
782
559
|
if (currentApp) {
|
|
783
560
|
preferredPort = currentApp.port;
|
|
784
561
|
}
|
|
785
562
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
786
563
|
const app = getConnectedAppByDevice(device);
|
|
787
|
-
// No connection - try to reconnect if enabled
|
|
788
564
|
if (!app) {
|
|
789
565
|
if (autoReconnect && attempt < maxRetries) {
|
|
790
566
|
console.error(`[execbro] No connection, attempting reconnect (attempt ${attempt + 1}/${maxRetries})...`);
|
|
@@ -796,18 +572,15 @@ async function executeInAppInner(expression, awaitPromise = true, options = {},
|
|
|
796
572
|
}
|
|
797
573
|
return { success: false, error: "No apps connected. Run 'scan_metro' first." };
|
|
798
574
|
}
|
|
799
|
-
// WebSocket not open - try to reconnect
|
|
800
575
|
if (app.ws.readyState !== WebSocket.OPEN) {
|
|
801
576
|
if (autoReconnect && attempt < maxRetries) {
|
|
802
577
|
console.error(`[execbro] WebSocket not open, attempting reconnect (attempt ${attempt + 1}/${maxRetries})...`);
|
|
803
|
-
// Close stale connection
|
|
804
578
|
const appKey = `${app.port}-${app.deviceInfo.id}`;
|
|
805
579
|
cancelReconnectionTimer(appKey);
|
|
806
580
|
try {
|
|
807
581
|
app.ws.close();
|
|
808
582
|
}
|
|
809
583
|
catch {
|
|
810
|
-
/* ignore */
|
|
811
584
|
}
|
|
812
585
|
connectedApps.delete(appKey);
|
|
813
586
|
const reconnected = await attemptQuickReconnect(app.port);
|
|
@@ -818,12 +591,6 @@ async function executeInAppInner(expression, awaitPromise = true, options = {},
|
|
|
818
591
|
}
|
|
819
592
|
return { success: false, error: "WebSocket connection is not open." };
|
|
820
593
|
}
|
|
821
|
-
// Best-effort one-shot bootstrap of globalThis.__rn__ for this app
|
|
822
|
-
// session. Hermes does not expose closure-captured RN modules, so this
|
|
823
|
-
// fiber-walk usually sets __rn__ = null — that's fine; list_debug_globals
|
|
824
|
-
// reports the failure clearly. Wrapped in try/catch so a bootstrap
|
|
825
|
-
// failure never breaks the user's expression. skipBootstrap is set by
|
|
826
|
-
// the bootstrap itself (via ensureRnGlobalsBootstrap) to avoid recursion.
|
|
827
594
|
if (!skipBootstrap) {
|
|
828
595
|
try {
|
|
829
596
|
const { ensureRnGlobalsBootstrap } = await import("./rnGlobalsBootstrap.js");
|
|
@@ -833,25 +600,20 @@ async function executeInAppInner(expression, awaitPromise = true, options = {},
|
|
|
833
600
|
console.error("[execbro] __rn__ bootstrap dispatch failed:", e);
|
|
834
601
|
}
|
|
835
602
|
}
|
|
836
|
-
// Execute the expression
|
|
837
603
|
const result = await executeExpressionCore(expression, awaitPromise, timeoutMs, app);
|
|
838
|
-
// Success - return result
|
|
839
604
|
if (result.success) {
|
|
840
605
|
return result;
|
|
841
606
|
}
|
|
842
607
|
lastError = result.error;
|
|
843
|
-
// Check if this is a context error that might be recoverable
|
|
844
608
|
if (isContextError(result.error)) {
|
|
845
609
|
if (autoReconnect && attempt < maxRetries) {
|
|
846
610
|
console.error(`[execbro] Context error detected, attempting reconnect (attempt ${attempt + 1}/${maxRetries})...`);
|
|
847
|
-
// Close and reconnect
|
|
848
611
|
const appKey = `${app.port}-${app.deviceInfo.id}`;
|
|
849
612
|
cancelReconnectionTimer(appKey);
|
|
850
613
|
try {
|
|
851
614
|
app.ws.close();
|
|
852
615
|
}
|
|
853
616
|
catch {
|
|
854
|
-
/* ignore */
|
|
855
617
|
}
|
|
856
618
|
connectedApps.delete(appKey);
|
|
857
619
|
const reconnected = await attemptQuickReconnect(app.port);
|
|
@@ -861,7 +623,6 @@ async function executeInAppInner(expression, awaitPromise = true, options = {},
|
|
|
861
623
|
}
|
|
862
624
|
}
|
|
863
625
|
}
|
|
864
|
-
// Non-context error or no more retries - return error
|
|
865
626
|
return result;
|
|
866
627
|
}
|
|
867
628
|
return {
|
|
@@ -878,23 +639,8 @@ async function executeInAppInner(expression, awaitPromise = true, options = {},
|
|
|
878
639
|
].join("\n")
|
|
879
640
|
};
|
|
880
641
|
}
|
|
881
|
-
/**
|
|
882
|
-
* One-shot scan-and-retry wrapper on top of executeInAppInner.
|
|
883
|
-
*
|
|
884
|
-
* On first-failure, classifies the error as transport-vs-logical:
|
|
885
|
-
* - transport → call attemptQuickReconnect once, retry with autoReconnect:false
|
|
886
|
-
* to avoid recursion. Successful retries carry _meta.reconnected; surviving
|
|
887
|
-
* failures surface 'reconnected_but_still_failed'.
|
|
888
|
-
* - logical → propagate the original error unchanged.
|
|
889
|
-
*
|
|
890
|
-
* The server-side `timeoutMs` timer always classifies as logical (a too-long
|
|
891
|
-
* expression is not a transport drop), so timeoutMs hits never trigger
|
|
892
|
-
* reconnect.
|
|
893
|
-
*/
|
|
894
642
|
export async function executeInApp(expression, awaitPromise = true, options = {}, device) {
|
|
895
643
|
const toolName = options.originatingToolName ?? "unknown";
|
|
896
|
-
// Clamp timeoutMs at the boundary. Mistyped values clamp with a warning surfaced in
|
|
897
|
-
// _meta rather than reject. The default (when not supplied) keeps the historical 10000 ms.
|
|
898
644
|
const requestedTimeout = options.timeoutMs ?? 10_000;
|
|
899
645
|
const { value: clampedTimeout, clampedFrom } = clampTimeoutMs(requestedTimeout);
|
|
900
646
|
const effectiveOptions = { ...options, timeoutMs: clampedTimeout };
|
|
@@ -912,9 +658,6 @@ export async function executeInApp(expression, awaitPromise = true, options = {}
|
|
|
912
658
|
const source = first.error?.startsWith("Timeout: Expression took too long")
|
|
913
659
|
? "server-timer"
|
|
914
660
|
: "cdp";
|
|
915
|
-
// getConnectedAppByDevice throws when an explicit device name matches
|
|
916
|
-
// nothing; that failure is already reported via `first`, so fall back to
|
|
917
|
-
// "nothing to probe" rather than replacing the original error.
|
|
918
661
|
let probeApp = null;
|
|
919
662
|
try {
|
|
920
663
|
probeApp = getConnectedAppByDevice(device);
|
|
@@ -927,10 +670,6 @@ export async function executeInApp(expression, awaitPromise = true, options = {}
|
|
|
927
670
|
trackAutoReconnect("not_needed", toolName);
|
|
928
671
|
return withClampMeta(first);
|
|
929
672
|
}
|
|
930
|
-
// 'no_apps' without any prior successful exec means Metro/app simply isn't
|
|
931
|
-
// running — scanning will only re-confirm that. Return the original error
|
|
932
|
-
// so the user sees the actionable message ("Run 'scan_metro' first") instead
|
|
933
|
-
// of a misleading 'reconnect_attempted' prefix.
|
|
934
673
|
if (classification.pattern === "no_apps" && !hasEverConnected) {
|
|
935
674
|
trackAutoReconnect("not_needed", toolName);
|
|
936
675
|
return withClampMeta(first);
|