execbro 1.10.23 → 1.10.25
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 +2 -1
- package/build/__tests__/helpers/fake-cdp-server.d.ts +9 -0
- package/build/__tests__/helpers/fake-cdp-server.d.ts.map +1 -1
- package/build/__tests__/helpers/fake-cdp-server.js +20 -2
- package/build/__tests__/helpers/fake-cdp-server.js.map +1 -1
- package/build/__tests__/integration/connection-health.test.js +8 -1
- package/build/__tests__/integration/connection-health.test.js.map +1 -1
- package/build/__tests__/integration/socket-close-midflight.test.d.ts +2 -0
- package/build/__tests__/integration/socket-close-midflight.test.d.ts.map +1 -0
- package/build/__tests__/integration/socket-close-midflight.test.js +106 -0
- package/build/__tests__/integration/socket-close-midflight.test.js.map +1 -0
- package/build/__tests__/integration/stale-target-probe.test.d.ts +2 -0
- package/build/__tests__/integration/stale-target-probe.test.d.ts.map +1 -0
- package/build/__tests__/integration/stale-target-probe.test.js +85 -0
- package/build/__tests__/integration/stale-target-probe.test.js.map +1 -0
- package/build/__tests__/unit/componentSource.test.d.ts +2 -0
- package/build/__tests__/unit/componentSource.test.d.ts.map +1 -0
- package/build/__tests__/unit/componentSource.test.js +67 -0
- package/build/__tests__/unit/componentSource.test.js.map +1 -0
- package/build/__tests__/unit/componentSourceResolve.test.d.ts +2 -0
- package/build/__tests__/unit/componentSourceResolve.test.d.ts.map +1 -0
- package/build/__tests__/unit/componentSourceResolve.test.js +91 -0
- package/build/__tests__/unit/componentSourceResolve.test.js.map +1 -0
- package/build/__tests__/unit/deviceResolution.test.d.ts +2 -0
- package/build/__tests__/unit/deviceResolution.test.d.ts.map +1 -0
- package/build/__tests__/unit/deviceResolution.test.js +108 -0
- package/build/__tests__/unit/deviceResolution.test.js.map +1 -0
- package/build/__tests__/unit/executor.test.js +48 -12
- package/build/__tests__/unit/executor.test.js.map +1 -1
- package/build/__tests__/unit/getLogsEmptyContract.test.d.ts +2 -0
- package/build/__tests__/unit/getLogsEmptyContract.test.d.ts.map +1 -0
- package/build/__tests__/unit/getLogsEmptyContract.test.js +99 -0
- package/build/__tests__/unit/getLogsEmptyContract.test.js.map +1 -0
- package/build/__tests__/unit/inspectorHarvest.test.d.ts +2 -0
- package/build/__tests__/unit/inspectorHarvest.test.d.ts.map +1 -0
- package/build/__tests__/unit/inspectorHarvest.test.js +61 -0
- package/build/__tests__/unit/inspectorHarvest.test.js.map +1 -0
- package/build/__tests__/unit/inspectorSource.test.d.ts +2 -0
- package/build/__tests__/unit/inspectorSource.test.d.ts.map +1 -0
- package/build/__tests__/unit/inspectorSource.test.js +74 -0
- package/build/__tests__/unit/inspectorSource.test.js.map +1 -0
- package/build/__tests__/unit/logDiagnosis.test.d.ts +2 -0
- package/build/__tests__/unit/logDiagnosis.test.d.ts.map +1 -0
- package/build/__tests__/unit/logDiagnosis.test.js +81 -0
- package/build/__tests__/unit/logDiagnosis.test.js.map +1 -0
- package/build/__tests__/unit/pendingExecutions.test.d.ts +2 -0
- package/build/__tests__/unit/pendingExecutions.test.d.ts.map +1 -0
- package/build/__tests__/unit/pendingExecutions.test.js +70 -0
- package/build/__tests__/unit/pendingExecutions.test.js.map +1 -0
- package/build/__tests__/unit/reloadAppAutoConnect.test.d.ts +2 -0
- package/build/__tests__/unit/reloadAppAutoConnect.test.d.ts.map +1 -0
- package/build/__tests__/unit/reloadAppAutoConnect.test.js +63 -0
- package/build/__tests__/unit/reloadAppAutoConnect.test.js.map +1 -0
- package/build/__tests__/unit/selectionBuffer.test.d.ts +2 -0
- package/build/__tests__/unit/selectionBuffer.test.d.ts.map +1 -0
- package/build/__tests__/unit/selectionBuffer.test.js +86 -0
- package/build/__tests__/unit/selectionBuffer.test.js.map +1 -0
- package/build/__tests__/unit/selectionPoller.test.d.ts +2 -0
- package/build/__tests__/unit/selectionPoller.test.d.ts.map +1 -0
- package/build/__tests__/unit/selectionPoller.test.js +109 -0
- package/build/__tests__/unit/selectionPoller.test.js.map +1 -0
- package/build/__tests__/unit/symbolicate.test.d.ts +2 -0
- package/build/__tests__/unit/symbolicate.test.d.ts.map +1 -0
- package/build/__tests__/unit/symbolicate.test.js +154 -0
- package/build/__tests__/unit/symbolicate.test.js.map +1 -0
- package/build/__tests__/unit/transportClassify.test.js +108 -7
- package/build/__tests__/unit/transportClassify.test.js.map +1 -1
- package/build/core/componentSource.d.ts +62 -0
- package/build/core/componentSource.d.ts.map +1 -0
- package/build/core/componentSource.js +268 -0
- package/build/core/componentSource.js.map +1 -0
- package/build/core/connection.d.ts +30 -0
- package/build/core/connection.d.ts.map +1 -1
- package/build/core/connection.js +101 -28
- package/build/core/connection.js.map +1 -1
- package/build/core/debugGlobals.d.ts.map +1 -1
- package/build/core/debugGlobals.js +89 -32
- package/build/core/debugGlobals.js.map +1 -1
- package/build/core/errors.d.ts +7 -1
- package/build/core/errors.d.ts.map +1 -1
- package/build/core/errors.js +8 -1
- package/build/core/errors.js.map +1 -1
- package/build/core/guides.js +1 -1
- package/build/core/index.d.ts +4 -1
- package/build/core/index.d.ts.map +1 -1
- package/build/core/index.js +4 -1
- package/build/core/index.js.map +1 -1
- package/build/core/inspector.d.ts +24 -0
- package/build/core/inspector.d.ts.map +1 -1
- package/build/core/inspector.js +58 -0
- package/build/core/inspector.js.map +1 -1
- package/build/core/jsExecute.d.ts +76 -1
- package/build/core/jsExecute.d.ts.map +1 -1
- package/build/core/jsExecute.js +193 -32
- package/build/core/jsExecute.js.map +1 -1
- package/build/core/logDiagnosis.d.ts +65 -0
- package/build/core/logDiagnosis.d.ts.map +1 -0
- package/build/core/logDiagnosis.js +51 -0
- package/build/core/logDiagnosis.js.map +1 -0
- package/build/core/register.d.ts.map +1 -1
- package/build/core/register.js +22 -6
- package/build/core/register.js.map +1 -1
- package/build/core/selectionBuffer.d.ts +42 -0
- package/build/core/selectionBuffer.d.ts.map +1 -0
- package/build/core/selectionBuffer.js +51 -0
- package/build/core/selectionBuffer.js.map +1 -0
- package/build/core/selectionPoller.d.ts +13 -0
- package/build/core/selectionPoller.d.ts.map +1 -0
- package/build/core/selectionPoller.js +102 -0
- package/build/core/selectionPoller.js.map +1 -0
- package/build/core/state.d.ts +10 -0
- package/build/core/state.d.ts.map +1 -1
- package/build/core/state.js +21 -0
- package/build/core/state.js.map +1 -1
- package/build/core/symbolicate.d.ts +18 -0
- package/build/core/symbolicate.d.ts.map +1 -0
- package/build/core/symbolicate.js +119 -0
- package/build/core/symbolicate.js.map +1 -0
- package/build/core/types.d.ts +8 -0
- package/build/core/types.d.ts.map +1 -1
- package/build/tools/componentTools.d.ts.map +1 -1
- package/build/tools/componentTools.js +78 -9
- package/build/tools/componentTools.js.map +1 -1
- package/build/tools/connectionTools.d.ts.map +1 -1
- package/build/tools/connectionTools.js +10 -4
- package/build/tools/connectionTools.js.map +1 -1
- package/build/tools/executionTools.js +7 -7
- package/build/tools/executionTools.js.map +1 -1
- package/build/tools/interactionTools.d.ts.map +1 -1
- package/build/tools/interactionTools.js +1 -0
- package/build/tools/interactionTools.js.map +1 -1
- package/build/tools/logTools.d.ts.map +1 -1
- package/build/tools/logTools.js +77 -69
- package/build/tools/logTools.js.map +1 -1
- package/build/tools/networkTools.d.ts.map +1 -1
- package/build/tools/networkTools.js +63 -13
- package/build/tools/networkTools.js.map +1 -1
- package/build/tools/screenshotTools.d.ts.map +1 -1
- package/build/tools/screenshotTools.js +3 -0
- package/build/tools/screenshotTools.js.map +1 -1
- package/package.json +1 -1
package/build/core/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,QAAQ;AACR,cAAc,YAAY,CAAC;AAE3B,8BAA8B;AAC9B,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,EACvB,wBAAwB,EACxB,qBAAqB,EACrB,4BAA4B,EAC5B,uBAAuB,EACvB,2BAA2B,EAC3B,uBAAuB,EACvB,qBAAqB,EACrB,cAAc;AACd,0BAA0B;AAC1B,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB;AACnB,+CAA+C;AAC/C,qBAAqB,EACrB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAE9B,QAAQ;AACR,OAAO,EACL,UAAU,EACV,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAEpB,OAAO;AACP,OAAO,EACL,SAAS,EACT,cAAc,EACd,UAAU,EACV,OAAO,EACP,UAAU,EACV,aAAa,GACd,MAAM,WAAW,CAAC;AAEnB,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,UAAU;AACV,OAAO,EACL,aAAa,EACb,aAAa,EACb,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,GAChB,MAAM,cAAc,CAAC;AAEtB,QAAQ;AACR,OAAO,EACL,YAAY,EACZ,UAAU,EACV,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACpB,eAAe,GAChB,MAAM,YAAY,CAAC;AAIpB,aAAa;AACb,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,EACvB,8BAA8B,EAC9B,gCAAgC,EAChC,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,0BAA0B,EAC1B,wBAAwB,EACxB,oBAAoB,EACpB,0BAA0B,EAC1B,4BAA4B,EAC5B,6BAA6B,EAC7B,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AAOzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,kGAAkG;AAClG,OAAO,EACL,QAAQ,EACR,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAG9B,WAAW;AACX,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,SAAS;AACT,6BAA6B;AAC7B,gBAAgB,EAChB,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,cAAc,EACd,0BAA0B,EAC1B,gBAAgB,EAChB,cAAc,EACd,YAAY;AACZ,8BAA8B;AAC9B,cAAc,EACd,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,4BAA4B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,QAAQ;AACR,cAAc,YAAY,CAAC;AAE3B,8BAA8B;AAC9B,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,EACvB,wBAAwB,EACxB,qBAAqB,EACrB,4BAA4B,EAC5B,uBAAuB,EACvB,2BAA2B,EAC3B,uBAAuB,EACvB,qBAAqB,EACrB,cAAc;AACd,0BAA0B;AAC1B,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB;AACnB,+CAA+C;AAC/C,qBAAqB,EACrB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAE9B,QAAQ;AACR,OAAO,EACL,UAAU,EACV,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAEpB,OAAO;AACP,OAAO,EACL,SAAS,EACT,cAAc,EACd,UAAU,EACV,OAAO,EACP,UAAU,EACV,aAAa,GACd,MAAM,WAAW,CAAC;AAEnB,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,UAAU;AACV,OAAO,EACL,aAAa,EACb,aAAa,EACb,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,GAChB,MAAM,cAAc,CAAC;AAEtB,QAAQ;AACR,OAAO,EACL,YAAY,EACZ,UAAU,EACV,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACpB,eAAe,GAChB,MAAM,YAAY,CAAC;AAIpB,aAAa;AACb,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,EACvB,8BAA8B,EAC9B,gCAAgC,EAChC,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,0BAA0B,EAC1B,wBAAwB,EACxB,oBAAoB,EACpB,0BAA0B,EAC1B,4BAA4B,EAC5B,6BAA6B,EAC7B,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AAOzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,kGAAkG;AAClG,OAAO,EACL,QAAQ,EACR,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAG9B,WAAW;AACX,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,SAAS;AACT,6BAA6B;AAC7B,gBAAgB,EAChB,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,cAAc,EACd,0BAA0B,EAC1B,gBAAgB,EAChB,cAAc,EACd,YAAY;AACZ,8BAA8B;AAC9B,cAAc,EACd,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,4BAA4B,EAC5B,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAEvB,gBAAgB;AAChB,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB;AACnB,qBAAqB;AACrB,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,iBAAiB,EACjB,yBAAyB;AACzB,+BAA+B;AAC/B,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB;AACjB,qCAAqC;AACrC,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,cAAc,CAAC;AAYtB,qBAAqB;AACrB,OAAO;AACL,qBAAqB;AACrB,iBAAiB,EACjB,iBAAiB,EACjB,sBAAsB,EACtB,mBAAmB,EACnB,8BAA8B,EAC9B,aAAa,EACb,aAAa,EACb,YAAY,EACZ,UAAU,EACV,eAAe,EACf,gBAAgB;AAChB,+BAA+B;AAC/B,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,sBAAsB,EACtB,MAAM,EACN,aAAa,EACb,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,WAAW,EACX,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,6BAA6B,EAC7B,gBAAgB;AAChB,oDAAoD;AACpD,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAalB,8BAA8B;AAC9B,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,0BAA0B,EAC1B,6BAA6B,EAC7B,iBAAiB,EACjB,eAAe,EACf,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AAErB,sCAAsC;AACtC,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGxE,kBAAkB;AAClB,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,eAAe,EACf,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAGtB,YAAY;AACZ,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAExB,MAAM;AACN,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,UAAU,CAAC;AAGlB,wDAAwD;AACxD,OAAO,EACL,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAGhC,+BAA+B;AAC/B,OAAO,EACL,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,sBAAsB,EACtB,UAAU,EACV,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAOrB,WAAW;AACX,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,eAAe,EACf,cAAc,GACf,MAAM,eAAe,CAAC;AAEvB,0BAA0B;AAC1B,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGpE,yCAAyC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAG9D,eAAe;AACf,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ExecutionResult } from "./types.js";
|
|
2
|
+
import type { RawComponentStack } from "./componentSource.js";
|
|
2
3
|
/**
|
|
3
4
|
* Toggle the Element Inspector via DevSettings native module.
|
|
4
5
|
* This enables the inspector overlay programmatically.
|
|
@@ -52,4 +53,27 @@ export declare function inspectAtPoint(x: number, y: number, options?: {
|
|
|
52
53
|
includeFrame?: boolean;
|
|
53
54
|
device?: string;
|
|
54
55
|
}): Promise<ExecutionResult>;
|
|
56
|
+
/**
|
|
57
|
+
* Harvests raw _debugStack strings for whatever sits at (x, y). Returns an
|
|
58
|
+
* empty list rather than throwing, so callers can always fall back to the
|
|
59
|
+
* unenriched payload.
|
|
60
|
+
*/
|
|
61
|
+
export declare function harvestStacksAtPoint(x: number, y: number, device?: string): Promise<RawComponentStack[]>;
|
|
62
|
+
/** Same, but derives the point from an inspected element's frame. */
|
|
63
|
+
export declare function harvestStacksAtFrame(frame: {
|
|
64
|
+
left?: number;
|
|
65
|
+
top?: number;
|
|
66
|
+
width?: number;
|
|
67
|
+
height?: number;
|
|
68
|
+
} | null | undefined, device?: string): Promise<RawComponentStack[]>;
|
|
69
|
+
/**
|
|
70
|
+
* Attaches source location to an inspector payload. Never throws and never
|
|
71
|
+
* removes existing fields - a failure adds only a `sourceUnavailable` reason.
|
|
72
|
+
*/
|
|
73
|
+
export declare function enrichWithSource(payload: Record<string, unknown>, stacks: RawComponentStack[]): Promise<Record<string, unknown>>;
|
|
74
|
+
/** Buffered selections, newest first, each with source resolved lazily on read. */
|
|
75
|
+
export declare function getSelectionHistory(options: {
|
|
76
|
+
device?: string;
|
|
77
|
+
limit?: number;
|
|
78
|
+
}): Promise<Record<string, unknown>[]>;
|
|
55
79
|
//# sourceMappingURL=inspector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspector.d.ts","sourceRoot":"","sources":["../../src/core/inspector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"inspector.d.ts","sourceRoot":"","sources":["../../src/core/inspector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGlD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAO9D;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAqBtF;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAqCzE;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CA4ErF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,4BAA4B,CAC9C,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,MAAM,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,eAAe,CAAC,CAqN1B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,cAAc,CAChC,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,OAAO,GAAE;IACL,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACd,GACP,OAAO,CAAC,eAAe,CAAC,CAiN1B;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACtC,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,MAAM,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAc9B;AAED,qEAAqE;AACrE,wBAAsB,oBAAoB,CACtC,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,EAC1F,MAAM,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAW9B;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAClC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,MAAM,EAAE,iBAAiB,EAAE,GAC5B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAUlC;AAED,mFAAmF;AACnF,wBAAsB,mBAAmB,CAAC,OAAO,EAAE;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAiBrC"}
|
package/build/core/inspector.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { executeInApp } from "./jsExecute.js";
|
|
2
|
+
import { resolveStacksToSource, buildDebugStackHarvestExpression } from "./componentSource.js";
|
|
3
|
+
import { selectionBuffer } from "./selectionBuffer.js";
|
|
2
4
|
// ============================================================================
|
|
3
5
|
// Coordinate-Based Element Inspection (via DevTools Inspector API)
|
|
4
6
|
// ============================================================================
|
|
@@ -600,4 +602,60 @@ export async function inspectAtPoint(x, y, options = {}) {
|
|
|
600
602
|
// measure paths without letting a hung Hermes runtime stall the tool.
|
|
601
603
|
return executeInApp(expression, true, { timeoutMs: 5000, originatingToolName: "inspect_at_point" }, device);
|
|
602
604
|
}
|
|
605
|
+
/**
|
|
606
|
+
* Harvests raw _debugStack strings for whatever sits at (x, y). Returns an
|
|
607
|
+
* empty list rather than throwing, so callers can always fall back to the
|
|
608
|
+
* unenriched payload.
|
|
609
|
+
*/
|
|
610
|
+
export async function harvestStacksAtPoint(x, y, device) {
|
|
611
|
+
try {
|
|
612
|
+
const res = await executeInApp(buildDebugStackHarvestExpression(x, y), true, { timeoutMs: 5000, originatingToolName: "get_inspector_selection" }, device);
|
|
613
|
+
if (!res.success || !res.result)
|
|
614
|
+
return [];
|
|
615
|
+
const parsed = JSON.parse(res.result);
|
|
616
|
+
return parsed.stacks ?? [];
|
|
617
|
+
}
|
|
618
|
+
catch {
|
|
619
|
+
return [];
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
/** Same, but derives the point from an inspected element's frame. */
|
|
623
|
+
export async function harvestStacksAtFrame(frame, device) {
|
|
624
|
+
if (!frame ||
|
|
625
|
+
frame.left === undefined ||
|
|
626
|
+
frame.top === undefined ||
|
|
627
|
+
frame.width === undefined ||
|
|
628
|
+
frame.height === undefined) {
|
|
629
|
+
return [];
|
|
630
|
+
}
|
|
631
|
+
return harvestStacksAtPoint(frame.left + frame.width / 2, frame.top + frame.height / 2, device);
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Attaches source location to an inspector payload. Never throws and never
|
|
635
|
+
* removes existing fields - a failure adds only a `sourceUnavailable` reason.
|
|
636
|
+
*/
|
|
637
|
+
export async function enrichWithSource(payload, stacks) {
|
|
638
|
+
try {
|
|
639
|
+
const resolved = await resolveStacksToSource(stacks);
|
|
640
|
+
if (resolved.source) {
|
|
641
|
+
return { ...payload, source: resolved.source, ancestors: resolved.ancestors };
|
|
642
|
+
}
|
|
643
|
+
return { ...payload, sourceUnavailable: resolved.sourceUnavailable ?? "unknown" };
|
|
644
|
+
}
|
|
645
|
+
catch {
|
|
646
|
+
return { ...payload, sourceUnavailable: "resolution-failed" };
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
/** Buffered selections, newest first, each with source resolved lazily on read. */
|
|
650
|
+
export async function getSelectionHistory(options) {
|
|
651
|
+
const entries = selectionBuffer.list({ device: options.device, limit: options.limit ?? 10 });
|
|
652
|
+
return Promise.all(entries.map(async (entry) => enrichWithSource({
|
|
653
|
+
element: entry.element,
|
|
654
|
+
path: entry.path,
|
|
655
|
+
frame: entry.frame,
|
|
656
|
+
style: entry.style,
|
|
657
|
+
device: entry.device,
|
|
658
|
+
timestamp: entry.timestamp,
|
|
659
|
+
}, entry.stacks)));
|
|
660
|
+
}
|
|
603
661
|
//# sourceMappingURL=inspector.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspector.js","sourceRoot":"","sources":["../../src/core/inspector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"inspector.js","sourceRoot":"","sources":["../../src/core/inspector.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import WebSocket from "ws";
|
|
1
2
|
import { ExecutionResult, ExecuteOptions } from "./types.js";
|
|
3
|
+
import type { DeviceInfo } from "./types.js";
|
|
2
4
|
export interface ExpressionValidation {
|
|
3
5
|
valid: boolean;
|
|
4
6
|
expression: string;
|
|
5
7
|
error?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Set when the pre-flight rewrote the caller's source rather than rejecting
|
|
10
|
+
* it. Surfaced to the caller so an agent can see its input was transformed.
|
|
11
|
+
*/
|
|
12
|
+
rewritten?: "iife-wrap";
|
|
6
13
|
}
|
|
7
14
|
/**
|
|
8
15
|
* Check if a string contains emoji or other problematic Unicode characters
|
|
@@ -20,13 +27,81 @@ export declare function stripLeadingComments(expression: string): string;
|
|
|
20
27
|
* Returns cleaned expression or error with helpful message
|
|
21
28
|
*/
|
|
22
29
|
export declare function validateAndPreprocessExpression(expression: string): ExpressionValidation;
|
|
30
|
+
/**
|
|
31
|
+
* Rewrite a multi-statement source into the IIFE that Hermes can compile,
|
|
32
|
+
* returning `null` when the rewrite would not be safe.
|
|
33
|
+
*
|
|
34
|
+
* `stmt1; stmt2; value` becomes `(function(){ stmt1; stmt2; return value; })()`.
|
|
35
|
+
* Bails out when the final segment cannot yield a value, so those callers still
|
|
36
|
+
* get the explanatory error rather than a silently broken transform.
|
|
37
|
+
*/
|
|
38
|
+
export declare function wrapMultiStatementInIife(src: string): string | null;
|
|
39
|
+
export declare function splitTopLevelStatements(src: string): string[];
|
|
23
40
|
export declare const TIMEOUT_HARD_CAP_MS = 120000;
|
|
24
41
|
export declare function markConnectionEstablished(): void;
|
|
25
42
|
export declare function clampTimeoutMs(input: number): {
|
|
26
43
|
value: number;
|
|
27
44
|
clampedFrom?: number;
|
|
28
45
|
};
|
|
29
|
-
export type TransportPattern = "no_apps" | "ws_closed" | "target_closed" | "
|
|
46
|
+
export type TransportPattern = "no_apps" | "ws_closed" | "target_closed" | "stale_target";
|
|
47
|
+
/**
|
|
48
|
+
* True for the one ambiguous failure shape: our own timer fired while the
|
|
49
|
+
* socket was still OPEN.
|
|
50
|
+
*
|
|
51
|
+
* Everything else is already decided. ws=CLOSED is transport (handled in
|
|
52
|
+
* classifyTransportError); a CDP-sourced error carries its own signal. This
|
|
53
|
+
* case alone can be either a genuinely slow expression or a stale CDP target
|
|
54
|
+
* that silently swallows evaluates while the device socket keeps ponging — and
|
|
55
|
+
* only a probe can tell them apart.
|
|
56
|
+
*/
|
|
57
|
+
export declare function isEvalTimeoutOnLiveSocket(message: string, source: "cdp" | "server-timer" | "logical"): boolean;
|
|
58
|
+
export type ProbeTargetApp = {
|
|
59
|
+
ws: WebSocket;
|
|
60
|
+
port: number;
|
|
61
|
+
deviceInfo: {
|
|
62
|
+
id?: string;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Is our CDP page still listed by Metro?
|
|
67
|
+
*
|
|
68
|
+
* This is the signal that a JS-level probe cannot provide: it goes over Metro's
|
|
69
|
+
* HTTP /json, so a blocked JavaScript thread has no effect on the answer.
|
|
70
|
+
*
|
|
71
|
+
* Conservative on purpose — an empty list (Metro unreachable, momentary blip)
|
|
72
|
+
* or a missing id counts as "still there". A false "gone" costs a reconnect and
|
|
73
|
+
* a retry that RE-RUNS the caller's expression, which must never happen on a
|
|
74
|
+
* guess.
|
|
75
|
+
*/
|
|
76
|
+
export declare function isTargetStillAdvertised(app: {
|
|
77
|
+
port: number;
|
|
78
|
+
deviceInfo: {
|
|
79
|
+
id?: string;
|
|
80
|
+
};
|
|
81
|
+
}, fetchTargets?: (port: number) => Promise<DeviceInfo[]>): Promise<boolean>;
|
|
82
|
+
/**
|
|
83
|
+
* classifyTransportError plus disambiguation for the one ambiguous shape: our
|
|
84
|
+
* timer fired while the socket was still OPEN.
|
|
85
|
+
*
|
|
86
|
+
* The transport was alive (the 1s ping/pong keepalive would have killed a dead
|
|
87
|
+
* socket within ~2s), so this is one of three things:
|
|
88
|
+
*
|
|
89
|
+
* 1. a genuinely slow ASYNC expression -> probe answers -> logical
|
|
90
|
+
* 2. a genuinely slow SYNC expression -> probe silent, but the
|
|
91
|
+
* (busy loop, big serialize) page is still listed -> logical
|
|
92
|
+
* 3. a stale CDP target (app reloaded -> probe silent AND the
|
|
93
|
+
* via shake / Metro 'r') page is gone -> transport
|
|
94
|
+
*
|
|
95
|
+
* Both signals are required for case 3. The probe alone cannot separate 2 from
|
|
96
|
+
* 3 — it is itself a Runtime.evaluate, so a blocked JS thread silences it
|
|
97
|
+
* exactly like a dead context. Verified on-device: a 15s busy loop silenced the
|
|
98
|
+
* probe and was misread as stale, triggering a reconnect that re-ran the
|
|
99
|
+
* expression. Metro's target list is independent of the JS thread and settles it.
|
|
100
|
+
*
|
|
101
|
+
* `probe` and `targetStillAdvertised` are injectable so the decision is
|
|
102
|
+
* testable without a socket or a Metro server.
|
|
103
|
+
*/
|
|
104
|
+
export declare function classifyWithLivenessProbe(message: string, source: "cdp" | "server-timer" | "logical", app: ProbeTargetApp | null, probe?: (ws: WebSocket, timeoutMs: number) => Promise<boolean>, targetStillAdvertised?: (app: ProbeTargetApp) => Promise<boolean>): Promise<TransportClassification>;
|
|
30
105
|
export type TransportClassification = {
|
|
31
106
|
kind: "transport";
|
|
32
107
|
pattern: TransportPattern;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsExecute.d.ts","sourceRoot":"","sources":["../../src/core/jsExecute.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"jsExecute.d.ts","sourceRoot":"","sources":["../../src/core/jsExecute.ts"],"names":[],"mappings":"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"}
|
package/build/core/jsExecute.js
CHANGED
|
@@ -5,6 +5,7 @@ import { getFirstConnectedApp, getConnectedAppByDevice, connectToDevice } from "
|
|
|
5
5
|
import { fetchDevices, selectMainDevice, scanMetroPorts } from "./metro.js";
|
|
6
6
|
import { cancelReconnectionTimer } from "./connectionState.js";
|
|
7
7
|
import { trackAutoReconnect } from "./telemetry.js";
|
|
8
|
+
import { probeCdpAlive } from "./probe.js";
|
|
8
9
|
// Hermes runtime compatibility: polyfill for 'global' which doesn't exist in Hermes
|
|
9
10
|
// In Hermes, globalThis is the standard way to access global scope
|
|
10
11
|
const GLOBAL_POLYFILL = `var global = typeof global !== 'undefined' ? global : globalThis;`;
|
|
@@ -91,21 +92,39 @@ export function validateAndPreprocessExpression(expression) {
|
|
|
91
92
|
valid: false,
|
|
92
93
|
expression: escaped,
|
|
93
94
|
error: "require() is not available in Hermes Runtime.evaluate. " +
|
|
94
|
-
"Modules cannot be imported at runtime.
|
|
95
|
-
"
|
|
95
|
+
"Modules cannot be imported at runtime. " +
|
|
96
|
+
"In a Metro dev build you can reach already-loaded modules through Metro's registry: " +
|
|
97
|
+
"`(function(){ var hit=null; __r.getModules().forEach(function(m,id){ " +
|
|
98
|
+
"if(!hit && m.verboseName && m.verboseName.indexOf('react-native/index.js') !== -1) hit=id; }); " +
|
|
99
|
+
"return __r(hit).Dimensions.get('window'); })()` " +
|
|
100
|
+
"(swap the verboseName match for the module you want). " +
|
|
101
|
+
"Otherwise use list_debug_globals to discover exposed globals, or add " +
|
|
102
|
+
"`globalThis.__MY_VAR__ = myModule;` in your app code."
|
|
96
103
|
};
|
|
97
104
|
}
|
|
98
105
|
// Check for multi-statement expressions. Runtime.evaluate compiles input as
|
|
99
106
|
// a single expression — `console.log('x'); 1+1` raises `')' expected at end
|
|
100
107
|
// of parenthesized expression`. Internal callers wrap in (function(){...})()
|
|
101
108
|
// so any `;` they use is at brace depth 1 and won't be flagged.
|
|
102
|
-
|
|
109
|
+
// executeWithManualAwait emits `var __v=(<expr>);`, so a depth-0 `;` breaks
|
|
110
|
+
// compilation. Rewrite into the IIFE ourselves instead of making the caller
|
|
111
|
+
// do it — this was the single largest execute_in_app failure class
|
|
112
|
+
// (125 events / 42 installations over 30d).
|
|
113
|
+
const wrapped = wrapMultiStatementInIife(trimmed);
|
|
114
|
+
if (wrapped) {
|
|
115
|
+
return { valid: true, expression: wrapped, rewritten: "iife-wrap" };
|
|
116
|
+
}
|
|
117
|
+
// More than one statement, but the last one can't yield a value — we can't
|
|
118
|
+
// synthesize a sensible `return`, so explain rather than guess.
|
|
119
|
+
if (splitTopLevelStatements(trimmed).length > 1) {
|
|
103
120
|
return {
|
|
104
121
|
valid: false,
|
|
105
122
|
expression: escaped,
|
|
106
123
|
error: "Multi-statement expressions are not supported by Hermes Runtime.evaluate " +
|
|
107
|
-
"(compiles input as a single expression)
|
|
108
|
-
"
|
|
124
|
+
"(compiles input as a single expression), and the final statement does not " +
|
|
125
|
+
"produce a value to return. " +
|
|
126
|
+
"Wrap the body in an IIFE with an explicit result: " +
|
|
127
|
+
"`(function(){ stmt1; stmt2; return result; })()`."
|
|
109
128
|
};
|
|
110
129
|
}
|
|
111
130
|
return {
|
|
@@ -116,21 +135,19 @@ export function validateAndPreprocessExpression(expression) {
|
|
|
116
135
|
function isIdentChar(c) {
|
|
117
136
|
return c !== undefined && /[A-Za-z0-9_$]/.test(c);
|
|
118
137
|
}
|
|
119
|
-
// Detect top-level `await
|
|
120
|
-
// `(async ...)` IIFE forms in `src`. Walks char-by-char tracking string,
|
|
138
|
+
// Detect a bare top-level `await` in `src`. Walks char-by-char tracking string,
|
|
121
139
|
// template, comment, and bracket depth so we don't false-positive on
|
|
122
140
|
// substrings inside strings, identifiers like `awaiting`, etc.
|
|
141
|
+
//
|
|
142
|
+
// NOTE: `async function`/`async () => {}`/`(async () => {})()` are deliberately
|
|
143
|
+
// NOT flagged. Hermes compiles them (they are expressions), the manual-await
|
|
144
|
+
// wrapper in executeWithManualAwait resolves the Promise they return, and
|
|
145
|
+
// telemetry showed this pre-flight rejecting ~20 legitimate calls/30d across 10
|
|
146
|
+
// installations. Verified on-device (iOS 26 sim, Hermes): an async arrow with an
|
|
147
|
+
// internal `await` evaluates correctly. Only a bare top-level `await` is a real
|
|
148
|
+
// syntax error, because the wrapper emits `var __v=(<expr>);` — a non-async
|
|
149
|
+
// context.
|
|
123
150
|
function looksLikeTopLevelAwait(src) {
|
|
124
|
-
// Cheap prefix checks for async-function / async-arrow / async-IIFE forms.
|
|
125
|
-
// Whitespace-tolerant on `async <keyword>` / `async (`.
|
|
126
|
-
const asyncPrefix = /^async\s*(?:function\b|\()/;
|
|
127
|
-
if (asyncPrefix.test(src))
|
|
128
|
-
return true;
|
|
129
|
-
// `(async () => ...)()` or `(async(...)...)` — match `(async` followed by
|
|
130
|
-
// a non-identifier char (so `(asyncFoo` doesn't trigger).
|
|
131
|
-
const parenAsync = /^\(\s*async(?:\s|\()/;
|
|
132
|
-
if (parenAsync.test(src))
|
|
133
|
-
return true;
|
|
134
151
|
// Depth-tracked scan for a standalone `await` token at depth 0.
|
|
135
152
|
let i = 0;
|
|
136
153
|
let parens = 0;
|
|
@@ -210,10 +227,40 @@ function looksLikeTopLevelAwait(src) {
|
|
|
210
227
|
}
|
|
211
228
|
return false;
|
|
212
229
|
}
|
|
213
|
-
//
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
|
|
230
|
+
// Statement forms that cannot be the final segment of an auto-wrapped IIFE,
|
|
231
|
+
// because prefixing them with `return` is either a syntax error or drops the
|
|
232
|
+
// value the caller wanted back. `return` itself is handled separately.
|
|
233
|
+
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|^\{/;
|
|
234
|
+
/**
|
|
235
|
+
* Rewrite a multi-statement source into the IIFE that Hermes can compile,
|
|
236
|
+
* returning `null` when the rewrite would not be safe.
|
|
237
|
+
*
|
|
238
|
+
* `stmt1; stmt2; value` becomes `(function(){ stmt1; stmt2; return value; })()`.
|
|
239
|
+
* Bails out when the final segment cannot yield a value, so those callers still
|
|
240
|
+
* get the explanatory error rather than a silently broken transform.
|
|
241
|
+
*/
|
|
242
|
+
export function wrapMultiStatementInIife(src) {
|
|
243
|
+
const segments = splitTopLevelStatements(src);
|
|
244
|
+
if (segments.length <= 1)
|
|
245
|
+
return null;
|
|
246
|
+
const last = segments[segments.length - 1];
|
|
247
|
+
if (NON_VALUE_STATEMENT_START.test(last))
|
|
248
|
+
return null;
|
|
249
|
+
const head = segments.slice(0, -1);
|
|
250
|
+
const body = last.startsWith("return") && !isIdentChar(last[6]) ? last : `return ${last}`;
|
|
251
|
+
return `(function(){ ${[...head, body].join("; ")}; })()`;
|
|
252
|
+
}
|
|
253
|
+
// Walk `src` tracking string/template/comment and bracket depth, splitting on
|
|
254
|
+
// `;` at depth 0. Returns the trimmed top-level statements; a trailing `;` that
|
|
255
|
+
// merely terminates the final statement produces no extra segment.
|
|
256
|
+
export function splitTopLevelStatements(src) {
|
|
257
|
+
const segments = [];
|
|
258
|
+
let segmentStart = 0;
|
|
259
|
+
const push = (end) => {
|
|
260
|
+
const seg = src.slice(segmentStart, end).trim();
|
|
261
|
+
if (seg.length > 0)
|
|
262
|
+
segments.push(seg);
|
|
263
|
+
};
|
|
217
264
|
let i = 0;
|
|
218
265
|
let parens = 0;
|
|
219
266
|
let braces = 0;
|
|
@@ -224,14 +271,14 @@ function hasTopLevelStatementSeparator(src) {
|
|
|
224
271
|
if (ch === "/" && next === "/") {
|
|
225
272
|
const nl = src.indexOf("\n", i + 2);
|
|
226
273
|
if (nl === -1)
|
|
227
|
-
|
|
274
|
+
break;
|
|
228
275
|
i = nl + 1;
|
|
229
276
|
continue;
|
|
230
277
|
}
|
|
231
278
|
if (ch === "/" && next === "*") {
|
|
232
279
|
const end = src.indexOf("*/", i + 2);
|
|
233
280
|
if (end === -1)
|
|
234
|
-
|
|
281
|
+
break;
|
|
235
282
|
i = end + 2;
|
|
236
283
|
continue;
|
|
237
284
|
}
|
|
@@ -264,13 +311,13 @@ function hasTopLevelStatementSeparator(src) {
|
|
|
264
311
|
else if (ch === "]")
|
|
265
312
|
brackets--;
|
|
266
313
|
else if (ch === ";" && parens === 0 && braces === 0 && brackets === 0) {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
return true;
|
|
314
|
+
push(i);
|
|
315
|
+
segmentStart = i + 1;
|
|
270
316
|
}
|
|
271
317
|
i++;
|
|
272
318
|
}
|
|
273
|
-
|
|
319
|
+
push(src.length);
|
|
320
|
+
return segments;
|
|
274
321
|
}
|
|
275
322
|
// ============================================================================
|
|
276
323
|
// Per-call timeoutMs: clamp + defaults
|
|
@@ -294,6 +341,84 @@ export function clampTimeoutMs(input) {
|
|
|
294
341
|
}
|
|
295
342
|
return { value: input };
|
|
296
343
|
}
|
|
344
|
+
// How long to wait for the disambiguating probe on a ws=OPEN timeout. Matches
|
|
345
|
+
// PROBE_TIMEOUT_MS in connection.ts, which uses the same probe to reject stale
|
|
346
|
+
// CDP targets at connect time.
|
|
347
|
+
const STALE_TARGET_PROBE_TIMEOUT_MS = 1_500;
|
|
348
|
+
/**
|
|
349
|
+
* True for the one ambiguous failure shape: our own timer fired while the
|
|
350
|
+
* socket was still OPEN.
|
|
351
|
+
*
|
|
352
|
+
* Everything else is already decided. ws=CLOSED is transport (handled in
|
|
353
|
+
* classifyTransportError); a CDP-sourced error carries its own signal. This
|
|
354
|
+
* case alone can be either a genuinely slow expression or a stale CDP target
|
|
355
|
+
* that silently swallows evaluates while the device socket keeps ponging — and
|
|
356
|
+
* only a probe can tell them apart.
|
|
357
|
+
*/
|
|
358
|
+
export function isEvalTimeoutOnLiveSocket(message, source) {
|
|
359
|
+
if (source !== "server-timer")
|
|
360
|
+
return false;
|
|
361
|
+
return /ws=OPEN/i.test(message);
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Is our CDP page still listed by Metro?
|
|
365
|
+
*
|
|
366
|
+
* This is the signal that a JS-level probe cannot provide: it goes over Metro's
|
|
367
|
+
* HTTP /json, so a blocked JavaScript thread has no effect on the answer.
|
|
368
|
+
*
|
|
369
|
+
* Conservative on purpose — an empty list (Metro unreachable, momentary blip)
|
|
370
|
+
* or a missing id counts as "still there". A false "gone" costs a reconnect and
|
|
371
|
+
* a retry that RE-RUNS the caller's expression, which must never happen on a
|
|
372
|
+
* guess.
|
|
373
|
+
*/
|
|
374
|
+
export async function isTargetStillAdvertised(app, fetchTargets = fetchDevices) {
|
|
375
|
+
const id = app.deviceInfo?.id;
|
|
376
|
+
if (!id)
|
|
377
|
+
return true;
|
|
378
|
+
const targets = await fetchTargets(app.port);
|
|
379
|
+
if (targets.length === 0)
|
|
380
|
+
return true;
|
|
381
|
+
return targets.some((t) => t.id === id);
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* classifyTransportError plus disambiguation for the one ambiguous shape: our
|
|
385
|
+
* timer fired while the socket was still OPEN.
|
|
386
|
+
*
|
|
387
|
+
* The transport was alive (the 1s ping/pong keepalive would have killed a dead
|
|
388
|
+
* socket within ~2s), so this is one of three things:
|
|
389
|
+
*
|
|
390
|
+
* 1. a genuinely slow ASYNC expression -> probe answers -> logical
|
|
391
|
+
* 2. a genuinely slow SYNC expression -> probe silent, but the
|
|
392
|
+
* (busy loop, big serialize) page is still listed -> logical
|
|
393
|
+
* 3. a stale CDP target (app reloaded -> probe silent AND the
|
|
394
|
+
* via shake / Metro 'r') page is gone -> transport
|
|
395
|
+
*
|
|
396
|
+
* Both signals are required for case 3. The probe alone cannot separate 2 from
|
|
397
|
+
* 3 — it is itself a Runtime.evaluate, so a blocked JS thread silences it
|
|
398
|
+
* exactly like a dead context. Verified on-device: a 15s busy loop silenced the
|
|
399
|
+
* probe and was misread as stale, triggering a reconnect that re-ran the
|
|
400
|
+
* expression. Metro's target list is independent of the JS thread and settles it.
|
|
401
|
+
*
|
|
402
|
+
* `probe` and `targetStillAdvertised` are injectable so the decision is
|
|
403
|
+
* testable without a socket or a Metro server.
|
|
404
|
+
*/
|
|
405
|
+
export async function classifyWithLivenessProbe(message, source, app, probe = probeCdpAlive, targetStillAdvertised = isTargetStillAdvertised) {
|
|
406
|
+
const base = classifyTransportError(message, source);
|
|
407
|
+
if (base.kind === "transport")
|
|
408
|
+
return base;
|
|
409
|
+
if (!isEvalTimeoutOnLiveSocket(message, source))
|
|
410
|
+
return base;
|
|
411
|
+
if (!app)
|
|
412
|
+
return base;
|
|
413
|
+
const alive = await probe(app.ws, STALE_TARGET_PROBE_TIMEOUT_MS);
|
|
414
|
+
if (alive)
|
|
415
|
+
return base;
|
|
416
|
+
// Probe silent. Only a target that Metro no longer lists is truly stale;
|
|
417
|
+
// otherwise the JS thread is just busy and retrying would re-run the call.
|
|
418
|
+
if (await targetStillAdvertised(app))
|
|
419
|
+
return base;
|
|
420
|
+
return { kind: "transport", pattern: "stale_target" };
|
|
421
|
+
}
|
|
297
422
|
/**
|
|
298
423
|
* Classify an error message into transport-vs-logical for auto-reconnect routing.
|
|
299
424
|
*
|
|
@@ -304,6 +429,17 @@ export function clampTimeoutMs(input) {
|
|
|
304
429
|
export function classifyTransportError(message, source) {
|
|
305
430
|
if (!message)
|
|
306
431
|
return { kind: "logical" };
|
|
432
|
+
// A server-timer expiry is normally logical ("this expression is slow").
|
|
433
|
+
// But the timer snapshots ws state into the message, and a CLOSED socket
|
|
434
|
+
// means the call never had a live transport to answer it — that is a
|
|
435
|
+
// transport failure no matter which timer noticed. Checked before the
|
|
436
|
+
// server-timer bail-out, which otherwise swallowed it.
|
|
437
|
+
//
|
|
438
|
+
// Primarily a backstop: failPendingExecutionsForSocket now fails in-flight
|
|
439
|
+
// calls at close time, so most of these surface as "WebSocket connection is
|
|
440
|
+
// not open" instead. This covers the race where our timer fires first.
|
|
441
|
+
if (/ws=CLOSED/i.test(message))
|
|
442
|
+
return { kind: "transport", pattern: "ws_closed" };
|
|
307
443
|
if (source === "server-timer")
|
|
308
444
|
return { kind: "logical" };
|
|
309
445
|
if (/No apps connected/i.test(message))
|
|
@@ -317,9 +453,14 @@ export function classifyTransportError(message, source) {
|
|
|
317
453
|
if (/target closed/i.test(message) || /Inspector detached/i.test(message)) {
|
|
318
454
|
return { kind: "transport", pattern: "target_closed" };
|
|
319
455
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
456
|
+
// NOTE: there used to be a `cdp_eval_too_long` branch here for a CDP-side
|
|
457
|
+
// "Expression took too long to evaluate". It was unreachable: the only
|
|
458
|
+
// producer of that phrase is our own timer in executeCDP, whose message
|
|
459
|
+
// always starts with "Timeout: Expression took too long" and is therefore
|
|
460
|
+
// tagged `server-timer` and handled above. Telemetry agrees — 367 such
|
|
461
|
+
// events over 90 days, none of them lacking our "Connection state:" block.
|
|
462
|
+
// Retrying is also wrong here: the 1s ping/pong keepalive terminates dead
|
|
463
|
+
// sockets within ~2s, so a still-OPEN socket had a live transport all along.
|
|
323
464
|
return { kind: "logical" };
|
|
324
465
|
}
|
|
325
466
|
// Error patterns that indicate a stale/destroyed context
|
|
@@ -401,6 +542,14 @@ function executeCDP(app, cleanedExpression, awaitPromise, timeoutMs) {
|
|
|
401
542
|
const TIMEOUT_MS = timeoutMs;
|
|
402
543
|
const currentMessageId = getNextMessageId();
|
|
403
544
|
const wrappedExpression = `${GLOBAL_POLYFILL} ${cleanedExpression}`;
|
|
545
|
+
// Every send funnels through here, including executeWithManualAwait's poll
|
|
546
|
+
// loop — which re-enters between sleeps and so can start on a socket that
|
|
547
|
+
// died since the previous send. ws.send() on a CLOSED socket does not
|
|
548
|
+
// throw; it simply never gets a reply, so without this the call burns its
|
|
549
|
+
// full timeout and then reports a misleading "took too long".
|
|
550
|
+
if (app.ws.readyState !== WebSocket.OPEN) {
|
|
551
|
+
return Promise.resolve({ success: false, error: "WebSocket connection is not open." });
|
|
552
|
+
}
|
|
404
553
|
return new Promise((resolve) => {
|
|
405
554
|
const timeoutId = setTimeout(() => {
|
|
406
555
|
pendingExecutions.delete(currentMessageId);
|
|
@@ -430,7 +579,9 @@ function executeCDP(app, cleanedExpression, awaitPromise, timeoutMs) {
|
|
|
430
579
|
].join("\n");
|
|
431
580
|
resolve({ success: false, error: errorMessage });
|
|
432
581
|
}, TIMEOUT_MS);
|
|
433
|
-
|
|
582
|
+
// Tag with the socket so a close event can fail this call immediately
|
|
583
|
+
// rather than letting it sit until TIMEOUT_MS.
|
|
584
|
+
pendingExecutions.set(currentMessageId, { resolve, timeoutId, ws: app.ws });
|
|
434
585
|
try {
|
|
435
586
|
app.ws.send(JSON.stringify({
|
|
436
587
|
id: currentMessageId,
|
|
@@ -654,7 +805,17 @@ export async function executeInApp(expression, awaitPromise = true, options = {}
|
|
|
654
805
|
const source = first.error?.startsWith("Timeout: Expression took too long")
|
|
655
806
|
? "server-timer"
|
|
656
807
|
: "cdp";
|
|
657
|
-
|
|
808
|
+
// getConnectedAppByDevice throws when an explicit device name matches
|
|
809
|
+
// nothing; that failure is already reported via `first`, so fall back to
|
|
810
|
+
// "nothing to probe" rather than replacing the original error.
|
|
811
|
+
let probeApp = null;
|
|
812
|
+
try {
|
|
813
|
+
probeApp = getConnectedAppByDevice(device);
|
|
814
|
+
}
|
|
815
|
+
catch {
|
|
816
|
+
probeApp = null;
|
|
817
|
+
}
|
|
818
|
+
const classification = await classifyWithLivenessProbe(first.error ?? "", source, probeApp);
|
|
658
819
|
if (classification.kind !== "transport") {
|
|
659
820
|
trackAutoReconnect("not_needed", toolName);
|
|
660
821
|
return withClampMeta(first);
|