@enricai/barnacle 1.6.12 → 1.6.13

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.
Files changed (96) hide show
  1. package/README.md +113 -9
  2. package/dist/api/schemas/submissions.d.ts +14 -0
  3. package/dist/api/schemas/submissions.d.ts.map +1 -1
  4. package/dist/api/schemas/submissions.js +1 -0
  5. package/dist/api/schemas/submissions.js.map +1 -1
  6. package/dist/config.d.ts +33 -0
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +4 -0
  9. package/dist/config.js.map +1 -1
  10. package/dist/lib/telemetry/beacon-capture.d.ts +45 -2
  11. package/dist/lib/telemetry/beacon-capture.d.ts.map +1 -1
  12. package/dist/lib/telemetry/beacon-capture.js +36 -0
  13. package/dist/lib/telemetry/beacon-capture.js.map +1 -1
  14. package/dist/lib/telemetry/reconciliation-record.d.ts +41 -1
  15. package/dist/lib/telemetry/reconciliation-record.d.ts.map +1 -1
  16. package/dist/lib/telemetry/reconciliation-record.js +29 -2
  17. package/dist/lib/telemetry/reconciliation-record.js.map +1 -1
  18. package/dist/lib/telemetry/reconciliation-source.d.ts +7 -1
  19. package/dist/lib/telemetry/reconciliation-source.d.ts.map +1 -1
  20. package/dist/lib/telemetry/reconciliation-source.js +21 -5
  21. package/dist/lib/telemetry/reconciliation-source.js.map +1 -1
  22. package/dist/lib/telemetry/run-telemetry.d.ts +67 -0
  23. package/dist/lib/telemetry/run-telemetry.d.ts.map +1 -0
  24. package/dist/lib/telemetry/run-telemetry.js +55 -0
  25. package/dist/lib/telemetry/run-telemetry.js.map +1 -0
  26. package/dist/lib/telemetry/submission-capture.d.ts +11 -4
  27. package/dist/lib/telemetry/submission-capture.d.ts.map +1 -1
  28. package/dist/lib/telemetry/submission-capture.js +1 -0
  29. package/dist/lib/telemetry/submission-capture.js.map +1 -1
  30. package/dist/lib/telemetry/submission-reader.d.ts +11 -3
  31. package/dist/lib/telemetry/submission-reader.d.ts.map +1 -1
  32. package/dist/lib/telemetry/submission-reader.js +32 -8
  33. package/dist/lib/telemetry/submission-reader.js.map +1 -1
  34. package/dist/lib/tracking-click.d.ts.map +1 -1
  35. package/dist/lib/tracking-click.js +19 -0
  36. package/dist/lib/tracking-click.js.map +1 -1
  37. package/dist/plugins/loader.d.ts +20 -0
  38. package/dist/plugins/loader.d.ts.map +1 -1
  39. package/dist/plugins/loader.js +94 -17
  40. package/dist/plugins/loader.js.map +1 -1
  41. package/dist/scraper/deep-locator-actuate.d.ts +94 -0
  42. package/dist/scraper/deep-locator-actuate.d.ts.map +1 -0
  43. package/dist/scraper/deep-locator-actuate.js +216 -0
  44. package/dist/scraper/deep-locator-actuate.js.map +1 -0
  45. package/dist/scraper/deep-locator-candidates.d.ts +105 -18
  46. package/dist/scraper/deep-locator-candidates.d.ts.map +1 -1
  47. package/dist/scraper/deep-locator-candidates.js +238 -46
  48. package/dist/scraper/deep-locator-candidates.js.map +1 -1
  49. package/dist/scraper/deep-locator-click.d.ts +71 -0
  50. package/dist/scraper/deep-locator-click.d.ts.map +1 -0
  51. package/dist/scraper/deep-locator-click.js +71 -0
  52. package/dist/scraper/deep-locator-click.js.map +1 -0
  53. package/dist/scraper/deep-locator-fake.d.ts +344 -14
  54. package/dist/scraper/deep-locator-fake.d.ts.map +1 -1
  55. package/dist/scraper/deep-locator-fake.js +509 -7
  56. package/dist/scraper/deep-locator-fake.js.map +1 -1
  57. package/dist/scraper/deep-locator-scan.d.ts +220 -0
  58. package/dist/scraper/deep-locator-scan.d.ts.map +1 -0
  59. package/dist/scraper/deep-locator-scan.js +386 -0
  60. package/dist/scraper/deep-locator-scan.js.map +1 -0
  61. package/dist/scraper/fake-timer-advance.d.ts +47 -0
  62. package/dist/scraper/fake-timer-advance.d.ts.map +1 -0
  63. package/dist/scraper/fake-timer-advance.js +44 -0
  64. package/dist/scraper/fake-timer-advance.js.map +1 -0
  65. package/dist/scraper/flow-runner.d.ts +36 -1
  66. package/dist/scraper/flow-runner.d.ts.map +1 -1
  67. package/dist/scraper/flow-runner.js +354 -56
  68. package/dist/scraper/flow-runner.js.map +1 -1
  69. package/dist/scraper/frame-target.d.ts +28 -0
  70. package/dist/scraper/frame-target.d.ts.map +1 -1
  71. package/dist/scraper/frame-target.js +30 -0
  72. package/dist/scraper/frame-target.js.map +1 -1
  73. package/dist/scraper/session-browserbase.d.ts +13 -0
  74. package/dist/scraper/session-browserbase.d.ts.map +1 -1
  75. package/dist/scraper/session-browserbase.js +29 -0
  76. package/dist/scraper/session-browserbase.js.map +1 -1
  77. package/dist/scraper/session-ip.d.ts +69 -0
  78. package/dist/scraper/session-ip.d.ts.map +1 -0
  79. package/dist/scraper/session-ip.js +88 -0
  80. package/dist/scraper/session-ip.js.map +1 -0
  81. package/dist/scraper/session-shared.d.ts +9 -0
  82. package/dist/scraper/session-shared.d.ts.map +1 -1
  83. package/dist/scraper/session-shared.js.map +1 -1
  84. package/dist/scraper/submit-control.d.ts +14 -2
  85. package/dist/scraper/submit-control.d.ts.map +1 -1
  86. package/dist/scraper/submit-control.js +33 -2
  87. package/dist/scraper/submit-control.js.map +1 -1
  88. package/dist/scripts/recon-browser.d.ts.map +1 -1
  89. package/dist/scripts/recon-browser.js +32 -0
  90. package/dist/scripts/recon-browser.js.map +1 -1
  91. package/dist/site-plugin.d.ts +20 -0
  92. package/dist/site-plugin.d.ts.map +1 -1
  93. package/dist/testing/integration-runner.d.ts.map +1 -1
  94. package/dist/testing/integration-runner.js +6 -7
  95. package/dist/testing/integration-runner.js.map +1 -1
  96. package/package.json +1 -1
@@ -9,12 +9,31 @@
9
9
  * when the step is scoped to a child frame.
10
10
  */
11
11
  import type { Page } from "@browserbasehq/stagehand";
12
+ import { type FrameTarget } from "../scraper/frame-target";
12
13
  /** Overrides for the watchdog timeouts this module applies to every `deepLocator()` await; tests pass small values so cases don't burn wall-clock. */
13
14
  export interface DeepLocatorTimeoutOptions {
14
15
  /** Per-call watchdog timeout for `count()`/`textContent()`/`click()`. Defaults to {@link DEFAULT_DEEP_LOCATOR_CALL_TIMEOUT_MS}. */
15
16
  callTimeoutMs?: number;
16
- /** Total budget for {@link resolveDeepLocatorCandidates}'s enumeration loop. Defaults to {@link DEFAULT_DEEP_LOCATOR_ENUMERATION_BUDGET_MS}. */
17
+ /** Total budget for {@link resolveDeepLocatorCandidates}'s legacy enumeration loop. Defaults to {@link DEFAULT_DEEP_LOCATOR_ENUMERATION_BUDGET_MS}. */
17
18
  enumerationBudgetMs?: number;
19
+ /**
20
+ * Pre-resolved `FrameTarget` to scan via one batched
21
+ * `evaluate(buildScanFrameCandidatesExpr(innerSelector))` round-trip
22
+ * instead of the legacy `count()` + per-candidate `textContent()` loop.
23
+ * When omitted, a single non-polling `probeAttachedFrameTarget(page,
24
+ * frameSelector)` pass (`frame-target.ts`) is attempted internally so
25
+ * existing call sites get the batched fast path for free. Unlike a bare
26
+ * `resolveFrameTarget(page, frameSelector, { timeoutMs: 0 })` pass — which
27
+ * always loses the race against genuine CDP latency — this probe carries a
28
+ * real per-probe budget (`config.scraper.framePresenceProbeFloorMs`), so it
29
+ * can actually land against an already-attached frame under live latency.
30
+ * If the probe doesn't land a resolved child frame (not yet attached, or
31
+ * `frameSelector` is null/undefined), the legacy loop runs unchanged. A
32
+ * caller that already resolved a `FrameTarget` (e.g. `flow-runner.ts`'s
33
+ * per-step resolution) should pass it here to skip the redundant internal
34
+ * probe.
35
+ */
36
+ frameTarget?: FrameTarget;
18
37
  }
19
38
  /**
20
39
  * One candidate element `page.deepLocator()` resolved inside a scoped frame.
@@ -33,9 +52,48 @@ export interface DeepLocatorCandidate {
33
52
  index: number;
34
53
  /** `deeplocator=`-prefixed selector identifying this candidate for downstream `resolvedAction` synthesis; deliberately not `xpath=` (see {@link DeepLocatorCandidate} docs). */
35
54
  selector: string;
36
- /** Accessible text read via the delegate's `textContent()`. */
55
+ /**
56
+ * Accessible text for this candidate: the derived accessible name (see
57
+ * {@link buildScanFrameCandidatesExpr}) on the batched-scan fast path,
58
+ * or the delegate's raw `textContent()` on the legacy per-candidate
59
+ * enumeration fallback.
60
+ */
37
61
  accessibleText: string;
38
62
  }
63
+ /** One quoted phrase from an instruction, tagged with whether a negation marker (`NEGATION_MARKERS`) governs it. See {@link extractTaggedPhrases}. */
64
+ export interface TaggedPhrase {
65
+ text: string;
66
+ negated: boolean;
67
+ }
68
+ /**
69
+ * Extracts every single-quoted phrase from `instruction`, tagging each as
70
+ * negated when a negation marker (`NEGATION_MARKERS`) precedes it within the
71
+ * same sentence — flow instructions keep each "Do NOT click 'X', 'Y', ..."
72
+ * clause as one sentence listing every negated phrase, so a sentence
73
+ * boundary (`.`/`;`) between the marker and the phrase ends the negation's
74
+ * reach. Mirrors the quoted-phrase extraction convention in
75
+ * `parseSelectStep`/`parseRadioStep` (`flow-runner.ts`) — same
76
+ * `/'([^']+)'/g` shape — but here we need ALL quoted phrases plus their
77
+ * polarity, not just one option/label pair. Exported so `flow-runner.ts` can
78
+ * re-derive the exact same ranking {@link scoreCandidate} used to sort
79
+ * `deepLocatorCandidates`, to detect a tie for the top rank rather than
80
+ * duplicating this logic.
81
+ */
82
+ export declare function extractTaggedPhrases(instruction: string): TaggedPhrase[];
83
+ /**
84
+ * Scores one candidate's relevance to `instruction`'s tagged phrases, higher
85
+ * is more relevant. Mirrors `submit-control.ts`'s tiered-ranking shape:
86
+ * negative signal is checked first and wins outright (a candidate matching
87
+ * ANY negated phrase is actively demoted below "no match" — a decoy sibling
88
+ * button is worse than an unrelated structural node), then positive
89
+ * exact/substring match tiers, falling through to 0 for empty or
90
+ * unrelated text so a structural container with no accessible text can
91
+ * never outrank a candidate whose text actually matches the instruction.
92
+ * Exported so `flow-runner.ts` can detect a tie for the top rank among
93
+ * `resolveDeepLocatorCandidates`'s already-sorted output (see
94
+ * {@link extractTaggedPhrases}'s docblock).
95
+ */
96
+ export declare function scoreCandidate(accessibleText: string, phrases: TaggedPhrase[]): number;
39
97
  /**
40
98
  * Enumerates every element `page.deepLocator()` matches inside the frame
41
99
  * scoped by `frameSelector`, ranked by relevance to `instruction` (highest
@@ -50,20 +108,25 @@ export interface DeepLocatorCandidate {
50
108
  * cascading through candidate sources can move on to the next technique
51
109
  * instead of hanging the step forever.
52
110
  *
111
+ * Prefers a single batched `evaluate` round-trip over the frame
112
+ * (see {@link scanFrameCandidatesBatched}) — collapsing the O(n) per-candidate
113
+ * `textContent()` round-trips that made a dense OOPIF form (371 candidates
114
+ * measured live) unresolvable inside any reasonable budget — and falls back
115
+ * to the legacy `count()` + per-candidate loop (see
116
+ * {@link enumerateCandidatesViaLegacyLoop}) when no frame seam is available,
117
+ * the batched scan fails, or the batched scan resolves to zero candidates —
118
+ * the batched expression's light-DOM `querySelectorAll` can't see into a
119
+ * shadow root the way `page.deepLocator()` can, so a zero-length scan is
120
+ * treated as inconclusive rather than authoritative. Pass an already-resolved
121
+ * {@link DeepLocatorTimeoutOptions.frameTarget} to use the fast path without
122
+ * paying for an internal re-resolution.
123
+ *
53
124
  * Ranking exists because a hop like `"*"` matches every element inside a
54
125
  * wizard iframe (html, body, every div, ...) — DOM order alone almost always
55
126
  * puts a structural container first, not the control the step instruction
56
127
  * actually names. Pass `instruction` as `null`/`undefined` (or omit it) to
57
128
  * skip ranking and get delegate order — e.g. for pre-cascade reachability
58
129
  * probes that only care whether the frame has ANY candidates.
59
- *
60
- * `count()` and each per-candidate `textContent()` are individually bounded
61
- * by `timeoutOptions.callTimeoutMs` via {@link withWatchdog}; the enumeration
62
- * loop as a whole is additionally bounded by `timeoutOptions.enumerationBudgetMs`
63
- * so a hop with dozens of slow-but-settling elements (e.g. 65 candidates
64
- * matched against a live OOPIF) can't rack up an unbounded total cost even
65
- * when no single call hangs — the loop aborts early and returns whatever
66
- * candidates it already resolved.
67
130
  */
68
131
  export declare function resolveDeepLocatorCandidates(page: Page, frameSelector: string | null | undefined, innerSelector: string, instruction?: string | null, timeoutOptions?: DeepLocatorTimeoutOptions): Promise<DeepLocatorCandidate[]>;
69
132
  /**
@@ -71,14 +134,38 @@ export declare function resolveDeepLocatorCandidates(page: Page, frameSelector:
71
134
  * re-deriving the same hop selector `resolveDeepLocatorCandidates` used
72
135
  * rather than trusting a caller-supplied `xpath=` string, so the two stay in
73
136
  * lockstep even if a candidate's `selector` field is only ever used for
74
- * display/logging. `DeepLocatorDelegate.click()` resolves `Promise<void>` on
75
- * success and rejects on failure it never reports success via a return
76
- * value so callers must infer the outcome from whether this call throws
77
- * plus their own downstream DOM verification, not from a returned boolean.
78
- * A `click()` that exceeds `timeoutOptions.callTimeoutMs` (a wedged CDP
79
- * round-trip against a racy OOPIF frame) rejects with a `WatchdogTimeoutError`
80
- * the same as any other failure, preserving the "rejects on failure" contract
81
- * instead of hanging the caller forever.
137
+ * display/logging. Resolves on success and rejects on failure — the caller
138
+ * must infer the outcome from whether this call throws plus their own
139
+ * downstream DOM verification, not from a returned boolean.
140
+ *
141
+ * Prefers the one-round-trip {@link clickCandidateBatched} fast path when a
142
+ * frame seam is available (`timeoutOptions.frameTarget`, or one resolved
143
+ * internally the same way {@link scanFrameCandidatesBatched} does), falling
144
+ * back to the legacy `DeepLocatorDelegate.click()` — which never reports
145
+ * success via a return value, only via not rejecting — when no seam is
146
+ * available, the batched call fails/degrades, or it reports the index
147
+ * stale (`reason: "out-of-range"`). A batched `reason: "not-actionable"`
148
+ * result throws an error {@link isNodeNotActionableError} classifies, the
149
+ * same contract a real click against an unrendered node rejects with via the
150
+ * CDP `-32000 Node does not have a layout object` error, so a caller
151
+ * cascading through candidates treats both paths identically.
152
+ *
153
+ * The legacy fallback's watchdog scales with `index` (see
154
+ * {@link DEEP_LOCATOR_CLICK_INDEX_ROUND_TRIP_MS}) so a legitimately-reachable
155
+ * candidate isn't killed by a budget sized for a single round-trip. A
156
+ * `click()` that still exceeds that scaled budget (a wedged CDP round-trip
157
+ * against a racy OOPIF frame) rejects with a `WatchdogTimeoutError` the same
158
+ * as any other failure, preserving the "rejects on failure" contract instead
159
+ * of hanging the caller forever.
82
160
  */
83
161
  export declare function clickDeepLocatorCandidate(page: Page, frameSelector: string | null | undefined, innerSelector: string, index: number, timeoutOptions?: DeepLocatorTimeoutOptions): Promise<void>;
162
+ /**
163
+ * `fillDeepLocatorCandidate`/`selectDeepLocatorCandidateOption` live in
164
+ * `deep-locator-actuate.ts`, not here — that module's `writeAndVerify` wraps
165
+ * the same `buildHopSelector`/`withWatchdog` contract this file's
166
+ * `clickDeepLocatorCandidate` uses, but additionally reads the write back
167
+ * through `inputValue()` before reporting success (`verifyDomEffect` can't
168
+ * resolve a `deeplocator=` selector, so the read-back is the only
169
+ * confirmation a fill/select actually landed).
170
+ */
84
171
  //# sourceMappingURL=deep-locator-candidates.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deep-locator-candidates.d.ts","sourceRoot":"","sources":["../../src/scraper/deep-locator-candidates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AA2BrD,sJAAsJ;AACtJ,MAAM,WAAW,yBAAyB;IACxC,mIAAmI;IACnI,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gJAAgJ;IAChJ,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,oBAAoB;IACnC,kJAAkJ;IAClJ,KAAK,EAAE,MAAM,CAAC;IACd,gLAAgL;IAChL,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,cAAc,EAAE,MAAM,CAAC;CACxB;AA6ED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,IAAI,EACV,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACxC,aAAa,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,EAC3B,cAAc,GAAE,yBAA8B,GAC7C,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAoDjC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,IAAI,EACV,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACxC,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,MAAM,EACb,cAAc,GAAE,yBAA8B,GAC7C,OAAO,CAAC,IAAI,CAAC,CAOf"}
1
+ {"version":3,"file":"deep-locator-candidates.d.ts","sourceRoot":"","sources":["../../src/scraper/deep-locator-candidates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAWrD,OAAO,EAEL,KAAK,WAAW,EAEjB,MAAM,wBAAwB,CAAC;AA2BhC,sJAAsJ;AACtJ,MAAM,WAAW,yBAAyB;IACxC,mIAAmI;IACnI,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uJAAuJ;IACvJ,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;;;;;;;;;;;;OAgBG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAKD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,oBAAoB;IACnC,kJAAkJ;IAClJ,KAAK,EAAE,MAAM,CAAC;IACd,gLAAgL;IAChL,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,cAAc,EAAE,MAAM,CAAC;CACxB;AAsBD,sJAAsJ;AACtJ,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,YAAY,EAAE,CAaxE;AAOD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CAStF;AA6JD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,IAAI,EACV,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACxC,aAAa,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,EAC3B,cAAc,GAAE,yBAA8B,GAC7C,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAuCjC;AAqDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,IAAI,EACV,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACxC,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,MAAM,EACb,cAAc,GAAE,yBAA8B,GAC7C,OAAO,CAAC,IAAI,CAAC,CAwBf;AAED;;;;;;;;GAQG"}
@@ -10,10 +10,13 @@
10
10
  * when the step is scoped to a child frame.
11
11
  */
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.extractTaggedPhrases = extractTaggedPhrases;
14
+ exports.scoreCandidate = scoreCandidate;
13
15
  exports.resolveDeepLocatorCandidates = resolveDeepLocatorCandidates;
14
16
  exports.clickDeepLocatorCandidate = clickDeepLocatorCandidate;
15
17
  const errors_1 = require("../lib/errors");
16
18
  const logging_1 = require("../lib/logging");
19
+ const deep_locator_scan_1 = require("../scraper/deep-locator-scan");
17
20
  const frame_target_1 = require("../scraper/frame-target");
18
21
  const watchdog_1 = require("../scraper/watchdog");
19
22
  const logger = (0, logging_1.getLogger)({ name: "scraper/deep-locator-candidates" });
@@ -25,12 +28,16 @@ const logger = (0, logging_1.getLogger)({ name: "scraper/deep-locator-candidates
25
28
  */
26
29
  const DEFAULT_DEEP_LOCATOR_CALL_TIMEOUT_MS = 10_000;
27
30
  /**
28
- * Total wall-clock budget for {@link resolveDeepLocatorCandidates}'s
29
- * per-candidate `textContent()` enumeration loop. A hop like `"*"` can match
31
+ * Total wall-clock budget for {@link resolveDeepLocatorCandidates}'s legacy
32
+ * per-candidate `textContent()` enumeration loop the fallback path taken
33
+ * when no batched frame-scoped scan is available (see
34
+ * {@link DeepLocatorTimeoutOptions.frameTarget}). A hop like `"*"` can match
30
35
  * dozens of elements (65 observed against a live OOPIF) — each individually
31
36
  * fast but settling, not hanging — so a per-call timeout alone doesn't bound
32
37
  * the loop's total cost. Roughly half of `flow-runner.ts`'s
33
38
  * `STEP_WATCHDOG_MS` (120s), leaving headroom for the rest of the attempt.
39
+ * The batched scan path completes in one round-trip and is never gated by
40
+ * this budget.
34
41
  */
35
42
  const DEFAULT_DEEP_LOCATOR_ENUMERATION_BUDGET_MS = 60_000;
36
43
  /**
@@ -60,7 +67,10 @@ const NEGATION_MARKERS = /\b(?:do\s+not|don't|never|avoid)\b/gi;
60
67
  * reach. Mirrors the quoted-phrase extraction convention in
61
68
  * `parseSelectStep`/`parseRadioStep` (`flow-runner.ts`) — same
62
69
  * `/'([^']+)'/g` shape — but here we need ALL quoted phrases plus their
63
- * polarity, not just one option/label pair.
70
+ * polarity, not just one option/label pair. Exported so `flow-runner.ts` can
71
+ * re-derive the exact same ranking {@link scoreCandidate} used to sort
72
+ * `deepLocatorCandidates`, to detect a tie for the top rank rather than
73
+ * duplicating this logic.
64
74
  */
65
75
  function extractTaggedPhrases(instruction) {
66
76
  const negationStarts = [...instruction.matchAll(NEGATION_MARKERS)].map((m) => m.index);
@@ -88,6 +98,9 @@ function normalize(text) {
88
98
  * exact/substring match tiers, falling through to 0 for empty or
89
99
  * unrelated text so a structural container with no accessible text can
90
100
  * never outrank a candidate whose text actually matches the instruction.
101
+ * Exported so `flow-runner.ts` can detect a tie for the top rank among
102
+ * `resolveDeepLocatorCandidates`'s already-sorted output (see
103
+ * {@link extractTaggedPhrases}'s docblock).
91
104
  */
92
105
  function scoreCandidate(accessibleText, phrases) {
93
106
  const normalizedText = normalize(accessibleText);
@@ -103,6 +116,132 @@ function scoreCandidate(accessibleText, phrases) {
103
116
  return 2;
104
117
  return 0;
105
118
  }
119
+ /**
120
+ * Resolves the `FrameTarget` the batched scan should evaluate against:
121
+ * `timeoutOptions.frameTarget` when the caller already resolved one, else a
122
+ * single non-polling `probeAttachedFrameTarget(page, frameSelector)` pass
123
+ * (`frame-target.ts`) so existing call sites — which pass only a
124
+ * `frameSelector` string, not a `FrameTarget` — still get the batched fast
125
+ * path without themselves changing. Unlike a bare `resolveFrameTarget(page,
126
+ * frameSelector, { timeoutMs: 0 })` pass, the probe carries a real per-probe
127
+ * budget, so it can land against an already-attached frame under genuine CDP
128
+ * latency instead of always losing a zero-budget race. Returns `null` (never
129
+ * throws) when `frameSelector` is unset, the probe rejects (e.g. a fake
130
+ * `Page` in a legacy-path test lacking `evaluate`/`frames`), or nothing
131
+ * attaches within the probe's budget — each of those means "no frame seam
132
+ * available", and the caller degrades to the legacy per-candidate loop.
133
+ */
134
+ async function resolveScanFrameTarget(page, frameSelector, timeoutOptions) {
135
+ if (timeoutOptions.frameTarget)
136
+ return timeoutOptions.frameTarget;
137
+ if (!frameSelector)
138
+ return null;
139
+ try {
140
+ return await (0, frame_target_1.probeAttachedFrameTarget)(page, frameSelector);
141
+ }
142
+ catch {
143
+ return null;
144
+ }
145
+ }
146
+ /** Narrows a batched-scan evaluate result to {@link FrameCandidateScanResult}'s shape, guarding against a non-conforming payload (Issue #2's degrade-to-legacy-loop contract). */
147
+ function isFrameCandidateScanResult(entry) {
148
+ if (typeof entry !== "object" || entry === null)
149
+ return false;
150
+ const candidate = entry;
151
+ return (typeof candidate.index === "number" &&
152
+ typeof candidate.text === "string" &&
153
+ typeof candidate.visible === "boolean");
154
+ }
155
+ /**
156
+ * Batched-scan fast path: one `frameTarget.evaluate(buildScanFrameCandidatesExpr(innerSelector))`
157
+ * round-trip replaces the legacy `count()` + N × `nth(i).textContent()` loop.
158
+ * Returns `null` (never throws) when no frame seam is available, the
159
+ * evaluate call rejects (missing seam, thrown error, or a watchdog timeout —
160
+ * `frameTarget.evaluate` already carries its own watchdog), the resolved
161
+ * payload doesn't conform to {@link FrameCandidateScanResult}[], or the raw
162
+ * scan matched zero elements — every one of those degrades the caller to the
163
+ * legacy loop instead of losing candidates. A raw zero-match scan is treated
164
+ * as inconclusive rather than authoritative because the scan expression's
165
+ * light-DOM `querySelectorAll` can't see into a shadow root the way
166
+ * `page.deepLocator()` (used by the legacy loop) can, so it must not be
167
+ * confused with the *visibility* filter below, which legitimately produces
168
+ * an empty result when the scan *did* match elements but every one of them
169
+ * is unrendered. Filters out `visible:false` entries (Issue #2: an
170
+ * unrendered node can never be the target of a real click) before the
171
+ * caller ranks what's left, logging at `warn` when candidates are dropped
172
+ * so a frame whose every node reports unrendered doesn't silently look like
173
+ * an empty frame.
174
+ */
175
+ async function scanFrameCandidatesBatched(page, frameSelector, innerSelector, hopSelector, timeoutOptions) {
176
+ const frameTarget = await resolveScanFrameTarget(page, frameSelector, timeoutOptions);
177
+ if (!frameTarget)
178
+ return null;
179
+ let scanResults;
180
+ try {
181
+ scanResults = await frameTarget.evaluate((0, deep_locator_scan_1.buildScanFrameCandidatesExpr)(innerSelector));
182
+ }
183
+ catch (err) {
184
+ logger.warn(`deepLocator batched scan for ${hopSelector} failed, degrading to per-candidate enumeration: ${(0, errors_1.toErrorMessage)(err)}`);
185
+ return null;
186
+ }
187
+ if (!Array.isArray(scanResults) || !scanResults.every(isFrameCandidateScanResult)) {
188
+ logger.warn(`deepLocator batched scan for ${hopSelector} returned a non-conforming payload, degrading to per-candidate enumeration`);
189
+ return null;
190
+ }
191
+ if (scanResults.length === 0) {
192
+ logger.warn(`deepLocator batched scan for ${hopSelector} matched zero elements, degrading to per-candidate enumeration in case a shadow-DOM control was missed`);
193
+ return null;
194
+ }
195
+ const visibleResults = scanResults.filter((entry) => entry.visible);
196
+ if (visibleResults.length < scanResults.length) {
197
+ logger.warn(`deepLocator batched scan for ${hopSelector} dropped ${scanResults.length - visibleResults.length} unrendered candidate(s)`);
198
+ }
199
+ return visibleResults.map((entry) => ({
200
+ index: entry.index,
201
+ selector: candidateSelector(hopSelector, entry.index),
202
+ accessibleText: entry.text.trim(),
203
+ }));
204
+ }
205
+ /**
206
+ * Legacy fallback: `count()` then one `nth(index).textContent()` round-trip
207
+ * per candidate, individually bounded by `callTimeoutMs` via
208
+ * {@link withWatchdog} and collectively bounded by `enumerationBudgetMs` so a
209
+ * hop with dozens of slow-but-settling elements (e.g. 65 candidates matched
210
+ * against a live OOPIF) can't rack up an unbounded total cost even when no
211
+ * single call hangs — the loop aborts early and returns whatever candidates
212
+ * it already resolved. Never throws: a `count()`/`textContent()` failure
213
+ * (detached frame, navigated-away element) or either call exceeding its
214
+ * watchdog budget degrades to `[]`/an empty `accessibleText`.
215
+ */
216
+ async function enumerateCandidatesViaLegacyLoop(delegate, hopSelector, callTimeoutMs, enumerationBudgetMs) {
217
+ const count = await (0, watchdog_1.withWatchdog)(() => delegate.count(), {
218
+ timeoutMs: callTimeoutMs,
219
+ label: `deepLocator count() for ${hopSelector}`,
220
+ }).catch((err) => {
221
+ logger.warn(`deepLocator count() threw for ${hopSelector}: ${(0, errors_1.toErrorMessage)(err)}`);
222
+ return 0;
223
+ });
224
+ if (count === 0)
225
+ return [];
226
+ const candidates = [];
227
+ const enumerationDeadline = Date.now() + enumerationBudgetMs;
228
+ for (let index = 0; index < count; index++) {
229
+ if (Date.now() >= enumerationDeadline) {
230
+ logger.warn(`deepLocator enumeration for ${hopSelector} aborted after exceeding ${enumerationBudgetMs}ms budget at candidate ${index}/${count}`);
231
+ break;
232
+ }
233
+ const accessibleText = await (0, watchdog_1.withWatchdog)(() => delegate.nth(index).textContent(), {
234
+ timeoutMs: callTimeoutMs,
235
+ label: `deepLocator textContent() for ${hopSelector} nth=${index}`,
236
+ }).catch(() => "");
237
+ candidates.push({
238
+ index,
239
+ selector: candidateSelector(hopSelector, index),
240
+ accessibleText: accessibleText.trim(),
241
+ });
242
+ }
243
+ return candidates;
244
+ }
106
245
  /**
107
246
  * Enumerates every element `page.deepLocator()` matches inside the frame
108
247
  * scoped by `frameSelector`, ranked by relevance to `instruction` (highest
@@ -117,20 +256,25 @@ function scoreCandidate(accessibleText, phrases) {
117
256
  * cascading through candidate sources can move on to the next technique
118
257
  * instead of hanging the step forever.
119
258
  *
259
+ * Prefers a single batched `evaluate` round-trip over the frame
260
+ * (see {@link scanFrameCandidatesBatched}) — collapsing the O(n) per-candidate
261
+ * `textContent()` round-trips that made a dense OOPIF form (371 candidates
262
+ * measured live) unresolvable inside any reasonable budget — and falls back
263
+ * to the legacy `count()` + per-candidate loop (see
264
+ * {@link enumerateCandidatesViaLegacyLoop}) when no frame seam is available,
265
+ * the batched scan fails, or the batched scan resolves to zero candidates —
266
+ * the batched expression's light-DOM `querySelectorAll` can't see into a
267
+ * shadow root the way `page.deepLocator()` can, so a zero-length scan is
268
+ * treated as inconclusive rather than authoritative. Pass an already-resolved
269
+ * {@link DeepLocatorTimeoutOptions.frameTarget} to use the fast path without
270
+ * paying for an internal re-resolution.
271
+ *
120
272
  * Ranking exists because a hop like `"*"` matches every element inside a
121
273
  * wizard iframe (html, body, every div, ...) — DOM order alone almost always
122
274
  * puts a structural container first, not the control the step instruction
123
275
  * actually names. Pass `instruction` as `null`/`undefined` (or omit it) to
124
276
  * skip ranking and get delegate order — e.g. for pre-cascade reachability
125
277
  * probes that only care whether the frame has ANY candidates.
126
- *
127
- * `count()` and each per-candidate `textContent()` are individually bounded
128
- * by `timeoutOptions.callTimeoutMs` via {@link withWatchdog}; the enumeration
129
- * loop as a whole is additionally bounded by `timeoutOptions.enumerationBudgetMs`
130
- * so a hop with dozens of slow-but-settling elements (e.g. 65 candidates
131
- * matched against a live OOPIF) can't rack up an unbounded total cost even
132
- * when no single call hangs — the loop aborts early and returns whatever
133
- * candidates it already resolved.
134
278
  */
135
279
  async function resolveDeepLocatorCandidates(page, frameSelector, innerSelector, instruction, timeoutOptions = {}) {
136
280
  const callTimeoutMs = timeoutOptions.callTimeoutMs ?? DEFAULT_DEEP_LOCATOR_CALL_TIMEOUT_MS;
@@ -141,32 +285,9 @@ async function resolveDeepLocatorCandidates(page, frameSelector, innerSelector,
141
285
  logger.warn(`deepLocator() is unavailable on this page for ${hopSelector}`);
142
286
  return [];
143
287
  }
144
- const count = await (0, watchdog_1.withWatchdog)(() => delegate.count(), {
145
- timeoutMs: callTimeoutMs,
146
- label: `deepLocator count() for ${hopSelector}`,
147
- }).catch((err) => {
148
- logger.warn(`deepLocator count() threw for ${hopSelector}: ${(0, errors_1.toErrorMessage)(err)}`);
149
- return 0;
150
- });
151
- if (count === 0)
152
- return [];
153
- const candidates = [];
154
- const enumerationDeadline = Date.now() + enumerationBudgetMs;
155
- for (let index = 0; index < count; index++) {
156
- if (Date.now() >= enumerationDeadline) {
157
- logger.warn(`deepLocator enumeration for ${hopSelector} aborted after exceeding ${enumerationBudgetMs}ms budget at candidate ${index}/${count}`);
158
- break;
159
- }
160
- const accessibleText = await (0, watchdog_1.withWatchdog)(() => delegate.nth(index).textContent(), {
161
- timeoutMs: callTimeoutMs,
162
- label: `deepLocator textContent() for ${hopSelector} nth=${index}`,
163
- }).catch(() => "");
164
- candidates.push({
165
- index,
166
- selector: candidateSelector(hopSelector, index),
167
- accessibleText: accessibleText.trim(),
168
- });
169
- }
288
+ const batchedCandidates = await scanFrameCandidatesBatched(page, frameSelector, innerSelector, hopSelector, timeoutOptions);
289
+ const candidates = batchedCandidates ??
290
+ (await enumerateCandidatesViaLegacyLoop(delegate, hopSelector, callTimeoutMs, enumerationBudgetMs));
170
291
  if (!instruction)
171
292
  return candidates;
172
293
  const phrases = extractTaggedPhrases(instruction);
@@ -181,26 +302,97 @@ async function resolveDeepLocatorCandidates(page, frameSelector, innerSelector,
181
302
  .sort((a, b) => b.score - a.score || a.originalOrder - b.originalOrder)
182
303
  .map(({ candidate }) => candidate);
183
304
  }
305
+ /** Narrows a batched-click evaluate result to {@link FrameCandidateClickResult}'s shape, guarding against a non-conforming payload (the same degrade-to-legacy-loop contract {@link isFrameCandidateScanResult} enforces for the scan side). */
306
+ function isFrameCandidateClickResult(entry) {
307
+ if (typeof entry !== "object" || entry === null)
308
+ return false;
309
+ const result = entry;
310
+ if (typeof result.clicked !== "boolean")
311
+ return false;
312
+ if (result.clicked)
313
+ return true;
314
+ return result.reason === "out-of-range" || result.reason === "not-actionable";
315
+ }
316
+ /**
317
+ * Batched-click fast path: one `frameTarget.evaluate(buildClickFrameCandidateExpr(innerSelector, index))`
318
+ * round-trip replaces the legacy `nth(index).click()`, which (per
319
+ * {@link DEEP_LOCATOR_CLICK_INDEX_ROUND_TRIP_MS}'s docs) pays `index + 1`
320
+ * serial CDP round-trips through `resolveAtIndex`. Returns `null` (never
321
+ * throws) when no frame seam is available, the evaluate call rejects, or the
322
+ * resolved payload doesn't conform to {@link FrameCandidateClickResult} —
323
+ * every one of those degrades the caller to the legacy `nth(index).click()`
324
+ * path instead of losing the click, mirroring {@link scanFrameCandidatesBatched}'s
325
+ * degrade contract on the enumeration side.
326
+ */
327
+ async function clickCandidateBatched(page, frameSelector, innerSelector, index, hopSelector, timeoutOptions) {
328
+ const frameTarget = await resolveScanFrameTarget(page, frameSelector, timeoutOptions);
329
+ if (!frameTarget)
330
+ return null;
331
+ let clickResult;
332
+ try {
333
+ clickResult = await frameTarget.evaluate((0, deep_locator_scan_1.buildClickFrameCandidateExpr)(innerSelector, index));
334
+ }
335
+ catch (err) {
336
+ logger.warn(`deepLocator batched click for ${hopSelector} nth=${index} failed, degrading to delegate click: ${(0, errors_1.toErrorMessage)(err)}`);
337
+ return null;
338
+ }
339
+ if (!isFrameCandidateClickResult(clickResult)) {
340
+ logger.warn(`deepLocator batched click for ${hopSelector} nth=${index} returned a non-conforming payload, degrading to delegate click`);
341
+ return null;
342
+ }
343
+ return clickResult;
344
+ }
184
345
  /**
185
346
  * Clicks the candidate at `index` inside the frame scoped by `frameSelector`,
186
347
  * re-deriving the same hop selector `resolveDeepLocatorCandidates` used
187
348
  * rather than trusting a caller-supplied `xpath=` string, so the two stay in
188
349
  * lockstep even if a candidate's `selector` field is only ever used for
189
- * display/logging. `DeepLocatorDelegate.click()` resolves `Promise<void>` on
190
- * success and rejects on failure it never reports success via a return
191
- * value so callers must infer the outcome from whether this call throws
192
- * plus their own downstream DOM verification, not from a returned boolean.
193
- * A `click()` that exceeds `timeoutOptions.callTimeoutMs` (a wedged CDP
194
- * round-trip against a racy OOPIF frame) rejects with a `WatchdogTimeoutError`
195
- * the same as any other failure, preserving the "rejects on failure" contract
196
- * instead of hanging the caller forever.
350
+ * display/logging. Resolves on success and rejects on failure — the caller
351
+ * must infer the outcome from whether this call throws plus their own
352
+ * downstream DOM verification, not from a returned boolean.
353
+ *
354
+ * Prefers the one-round-trip {@link clickCandidateBatched} fast path when a
355
+ * frame seam is available (`timeoutOptions.frameTarget`, or one resolved
356
+ * internally the same way {@link scanFrameCandidatesBatched} does), falling
357
+ * back to the legacy `DeepLocatorDelegate.click()` — which never reports
358
+ * success via a return value, only via not rejecting — when no seam is
359
+ * available, the batched call fails/degrades, or it reports the index
360
+ * stale (`reason: "out-of-range"`). A batched `reason: "not-actionable"`
361
+ * result throws an error {@link isNodeNotActionableError} classifies, the
362
+ * same contract a real click against an unrendered node rejects with via the
363
+ * CDP `-32000 Node does not have a layout object` error, so a caller
364
+ * cascading through candidates treats both paths identically.
365
+ *
366
+ * The legacy fallback's watchdog scales with `index` (see
367
+ * {@link DEEP_LOCATOR_CLICK_INDEX_ROUND_TRIP_MS}) so a legitimately-reachable
368
+ * candidate isn't killed by a budget sized for a single round-trip. A
369
+ * `click()` that still exceeds that scaled budget (a wedged CDP round-trip
370
+ * against a racy OOPIF frame) rejects with a `WatchdogTimeoutError` the same
371
+ * as any other failure, preserving the "rejects on failure" contract instead
372
+ * of hanging the caller forever.
197
373
  */
198
374
  async function clickDeepLocatorCandidate(page, frameSelector, innerSelector, index, timeoutOptions = {}) {
199
375
  const callTimeoutMs = timeoutOptions.callTimeoutMs ?? DEFAULT_DEEP_LOCATOR_CALL_TIMEOUT_MS;
200
376
  const hopSelector = (0, frame_target_1.buildHopSelector)(frameSelector, innerSelector);
377
+ const batchedResult = await clickCandidateBatched(page, frameSelector, innerSelector, index, hopSelector, timeoutOptions);
378
+ if (batchedResult?.clicked)
379
+ return;
380
+ if (batchedResult?.reason === "not-actionable") {
381
+ throw new Error(`deepLocator batched click for ${hopSelector} nth=${index}: node does not have a layout object`);
382
+ }
383
+ const scaledCallTimeoutMs = callTimeoutMs + index * deep_locator_scan_1.DEEP_LOCATOR_CLICK_INDEX_ROUND_TRIP_MS;
201
384
  await (0, watchdog_1.withWatchdog)(() => page.deepLocator(hopSelector).nth(index).click(), {
202
- timeoutMs: callTimeoutMs,
385
+ timeoutMs: scaledCallTimeoutMs,
203
386
  label: `deepLocator click() for ${hopSelector} nth=${index}`,
204
387
  });
205
388
  }
389
+ /**
390
+ * `fillDeepLocatorCandidate`/`selectDeepLocatorCandidateOption` live in
391
+ * `deep-locator-actuate.ts`, not here — that module's `writeAndVerify` wraps
392
+ * the same `buildHopSelector`/`withWatchdog` contract this file's
393
+ * `clickDeepLocatorCandidate` uses, but additionally reads the write back
394
+ * through `inputValue()` before reporting success (`verifyDomEffect` can't
395
+ * resolve a `deeplocator=` selector, so the read-back is the only
396
+ * confirmation a fill/select actually landed).
397
+ */
206
398
  //# sourceMappingURL=deep-locator-candidates.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"deep-locator-candidates.js","sourceRoot":"","sources":["../../src/scraper/deep-locator-candidates.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deep-locator-candidates.js","sourceRoot":"","sources":["../../src/scraper/deep-locator-candidates.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;;;;AAIH,yCAA8C;AAC9C,2CAA0C;AAC1C,mEAMqC;AACrC,yDAIgC;AAChC,iDAAkD;AAElD,MAAM,MAAM,GAAG,IAAA,mBAAS,EAAC,EAAE,IAAI,EAAE,iCAAiC,EAAE,CAAC,CAAC;AAEtE;;;;;GAKG;AACH,MAAM,oCAAoC,GAAG,MAAM,CAAC;AAEpD;;;;;;;;;;;GAWG;AACH,MAAM,0CAA0C,GAAG,MAAM,CAAC;AAyD1D;;;;;;;GAOG;AACH,SAAS,iBAAiB,CAAC,WAAmB,EAAE,KAAa;IAC3D,OAAO,eAAe,WAAW,WAAW,KAAK,EAAE,CAAC;AACtD,CAAC;AAED;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG,sCAAsC,CAAC;AAQhE;;;;;;;;;;;;;GAaG;AACH,8BAAqC,WAAmB;IACtD,MAAM,cAAc,GAAG,CAAC,GAAG,WAAW,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACvF,MAAM,MAAM,GAAG,CAAC,GAAG,WAAW,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;IACvD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACtB,6FAA6F;QAC7F,MAAM,WAAW,GAAG,CAAC,CAAC,KAAM,CAAC;QAC7B,MAAM,qBAAqB,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACvF,MAAM,OAAO,GACX,qBAAqB,KAAK,SAAS;YACnC,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,qBAAqB,EAAE,WAAW,CAAC,CAAC,CAAC;QACtE,0HAA0H;QAC1H,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,iFAAiF;AACjF,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACxD,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,wBAA+B,cAAsB,EAAE,OAAuB;IAC5E,MAAM,cAAc,GAAG,SAAS,CAAC,cAAc,CAAC,CAAC;IACjD,IAAI,CAAC,cAAc;QAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAClF,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACjF,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,cAAc,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC,CAAC;IACzF,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,cAAc,CAAC;QAAE,OAAO,CAAC,CAAC;IAC1D,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IAC9F,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,KAAK,UAAU,sBAAsB,CACnC,IAAU,EACV,aAAwC,EACxC,cAAyC;IAEzC,IAAI,cAAc,CAAC,WAAW;QAAE,OAAO,cAAc,CAAC,WAAW,CAAC;IAClE,IAAI,CAAC,aAAa;QAAE,OAAO,IAAI,CAAC;IAChC,IAAI,CAAC;QACH,OAAO,MAAM,IAAA,uCAAwB,EAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,kLAAkL;AAClL,SAAS,0BAA0B,CAAC,KAAc;IAChD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,SAAS,GAAG,KAA0C,CAAC;IAC7D,OAAO,CACL,OAAO,SAAS,CAAC,KAAK,KAAK,QAAQ;QACnC,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ;QAClC,OAAO,SAAS,CAAC,OAAO,KAAK,SAAS,CACvC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,KAAK,UAAU,0BAA0B,CACvC,IAAU,EACV,aAAwC,EACxC,aAAqB,EACrB,WAAmB,EACnB,cAAyC;IAEzC,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAC,IAAI,EAAE,aAAa,EAAE,cAAc,CAAC,CAAC;IACtF,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAE9B,IAAI,WAAoB,CAAC;IACzB,IAAI,CAAC;QACH,WAAW,GAAG,MAAM,WAAW,CAAC,QAAQ,CACtC,IAAA,gDAA4B,EAAC,aAAa,CAAC,CAC5C,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CACT,gCAAgC,WAAW,oDAAoD,IAAA,uBAAc,EAAC,GAAG,CAAC,EAAE,CACrH,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,0BAA0B,CAAC,EAAE,CAAC;QAClF,MAAM,CAAC,IAAI,CACT,gCAAgC,WAAW,4EAA4E,CACxH,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,CAAC,IAAI,CACT,gCAAgC,WAAW,wGAAwG,CACpJ,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,cAAc,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACpE,IAAI,cAAc,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC;QAC/C,MAAM,CAAC,IAAI,CACT,gCAAgC,WAAW,YAAY,WAAW,CAAC,MAAM,GAAG,cAAc,CAAC,MAAM,0BAA0B,CAC5H,CAAC;IACJ,CAAC;IACD,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACpC,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,QAAQ,EAAE,iBAAiB,CAAC,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC;QACrD,cAAc,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE;KAClC,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;;;;;;;;GAUG;AACH,KAAK,UAAU,gCAAgC,CAC7C,QAA6B,EAC7B,WAAmB,EACnB,aAAqB,EACrB,mBAA2B;IAE3B,MAAM,KAAK,GAAG,MAAM,IAAA,uBAAY,EAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE;QACvD,SAAS,EAAE,aAAa;QACxB,KAAK,EAAE,2BAA2B,WAAW,EAAE;KAChD,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QACxB,MAAM,CAAC,IAAI,CAAC,iCAAiC,WAAW,KAAK,IAAA,uBAAc,EAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACpF,OAAO,CAAC,CAAC;IACX,CAAC,CAAC,CAAC;IACH,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAE3B,MAAM,UAAU,GAA2B,EAAE,CAAC;IAC9C,MAAM,mBAAmB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,mBAAmB,CAAC;IAC7D,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC;QAC3C,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,mBAAmB,EAAE,CAAC;YACtC,MAAM,CAAC,IAAI,CACT,+BAA+B,WAAW,4BAA4B,mBAAmB,0BAA0B,KAAK,IAAI,KAAK,EAAE,CACpI,CAAC;YACF,MAAM;QACR,CAAC;QACD,MAAM,cAAc,GAAG,MAAM,IAAA,uBAAY,EAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,EAAE;YACjF,SAAS,EAAE,aAAa;YACxB,KAAK,EAAE,iCAAiC,WAAW,QAAQ,KAAK,EAAE;SACnE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QACnB,UAAU,CAAC,IAAI,CAAC;YACd,KAAK;YACL,QAAQ,EAAE,iBAAiB,CAAC,WAAW,EAAE,KAAK,CAAC;YAC/C,cAAc,EAAE,cAAc,CAAC,IAAI,EAAE;SACtC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACI,KAAK,uCACV,IAAU,EACV,aAAwC,EACxC,aAAqB,EACrB,WAA2B,EAC3B,cAAc,GAA8B,EAAE;IAE9C,MAAM,aAAa,GAAG,cAAc,CAAC,aAAa,IAAI,oCAAoC,CAAC;IAC3F,MAAM,mBAAmB,GACvB,cAAc,CAAC,mBAAmB,IAAI,0CAA0C,CAAC;IACnF,MAAM,WAAW,GAAG,IAAA,+BAAgB,EAAC,aAAa,EAAE,aAAa,CAAC,CAAC;IACnE,MAAM,QAAQ,GAAG,OAAO,IAAI,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/F,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,CAAC,IAAI,CAAC,iDAAiD,WAAW,EAAE,CAAC,CAAC;QAC5E,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,iBAAiB,GAAG,MAAM,0BAA0B,CACxD,IAAI,EACJ,aAAa,EACb,aAAa,EACb,WAAW,EACX,cAAc,CACf,CAAC;IACF,MAAM,UAAU,GACd,iBAAiB;QACjB,CAAC,MAAM,gCAAgC,CACrC,QAAQ,EACR,WAAW,EACX,aAAa,EACb,mBAAmB,CACpB,CAAC,CAAC;IACL,IAAI,CAAC,WAAW;QAAE,OAAO,UAAU,CAAC;IAEpC,MAAM,OAAO,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC;IAClD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC;IAE5C,OAAO,UAAU;SACd,GAAG,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC;QAClC,SAAS;QACT,aAAa;QACb,KAAK,EAAE,cAAc,CAAC,SAAS,CAAC,cAAc,EAAE,OAAO,CAAC;KACzD,CAAC,CAAC;SACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,aAAa,CAAC;SACtE,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC;AACvC,CAAC;AAED,gPAAgP;AAChP,SAAS,2BAA2B,CAAC,KAAc;IACjD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,MAAM,GAAG,KAA2C,CAAC;IAC3D,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACtD,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAChC,OAAO,MAAM,CAAC,MAAM,KAAK,cAAc,IAAI,MAAM,CAAC,MAAM,KAAK,gBAAgB,CAAC;AAChF,CAAC;AAED;;;;;;;;;;GAUG;AACH,KAAK,UAAU,qBAAqB,CAClC,IAAU,EACV,aAAwC,EACxC,aAAqB,EACrB,KAAa,EACb,WAAmB,EACnB,cAAyC;IAEzC,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAC,IAAI,EAAE,aAAa,EAAE,cAAc,CAAC,CAAC;IACtF,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAE9B,IAAI,WAAoB,CAAC;IACzB,IAAI,CAAC;QACH,WAAW,GAAG,MAAM,WAAW,CAAC,QAAQ,CACtC,IAAA,gDAA4B,EAAC,aAAa,EAAE,KAAK,CAAC,CACnD,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CACT,iCAAiC,WAAW,QAAQ,KAAK,yCAAyC,IAAA,uBAAc,EAAC,GAAG,CAAC,EAAE,CACxH,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,2BAA2B,CAAC,WAAW,CAAC,EAAE,CAAC;QAC9C,MAAM,CAAC,IAAI,CACT,iCAAiC,WAAW,QAAQ,KAAK,iEAAiE,CAC3H,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACI,KAAK,oCACV,IAAU,EACV,aAAwC,EACxC,aAAqB,EACrB,KAAa,EACb,cAAc,GAA8B,EAAE;IAE9C,MAAM,aAAa,GAAG,cAAc,CAAC,aAAa,IAAI,oCAAoC,CAAC;IAC3F,MAAM,WAAW,GAAG,IAAA,+BAAgB,EAAC,aAAa,EAAE,aAAa,CAAC,CAAC;IAEnE,MAAM,aAAa,GAAG,MAAM,qBAAqB,CAC/C,IAAI,EACJ,aAAa,EACb,aAAa,EACb,KAAK,EACL,WAAW,EACX,cAAc,CACf,CAAC;IACF,IAAI,aAAa,EAAE,OAAO;QAAE,OAAO;IACnC,IAAI,aAAa,EAAE,MAAM,KAAK,gBAAgB,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CACb,iCAAiC,WAAW,QAAQ,KAAK,sCAAsC,CAChG,CAAC;IACJ,CAAC;IAED,MAAM,mBAAmB,GAAG,aAAa,GAAG,KAAK,GAAG,0DAAsC,CAAC;IAC3F,MAAM,IAAA,uBAAY,EAAC,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACzE,SAAS,EAAE,mBAAmB;QAC9B,KAAK,EAAE,2BAA2B,WAAW,QAAQ,KAAK,EAAE;KAC7D,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Candidate-click cascade for `deep-locator-candidates.ts`'s ranked
3
+ * `DeepLocatorCandidate[]`: `flow-runner.ts` used to click only
4
+ * `deepLocatorCandidates[0]` (see the bug report's Issue #2), so a top pick
5
+ * that turned out to be unrendered — a click rejecting with the CDP `-32000
6
+ * Node does not have a layout object` error `isNodeNotActionableError`
7
+ * classifies — scored the whole attempt as a failed click instead of trying
8
+ * the next-ranked candidate. {@link clickFirstActionableCandidate} walks the
9
+ * list instead, so a not-actionable rejection or a caller-supplied deny hit
10
+ * costs only that one candidate, not the attempt.
11
+ *
12
+ * Extracted out of `flow-runner.ts` so the walk is unit-testable against a
13
+ * stub click function — no fake `Page`, no Stagehand — and so
14
+ * `flow-runner.ts`'s own edit stays a call swap (see `bugfix-005`).
15
+ *
16
+ * NOT IMPLEMENTED: escalating to Stagehand's `Locator.sendClickEvent()` (a
17
+ * layout-free actuation) as a rescue for a candidate that's genuinely never
18
+ * going to render. The report asks for skip-and-continue, not a rescue path.
19
+ */
20
+ import type { DeepLocatorCandidate } from "../scraper/deep-locator-candidates";
21
+ /**
22
+ * Upper bound on how many candidates a single {@link clickFirstActionableCandidate}
23
+ * call will actually click. Denied candidates are skipped without a click and
24
+ * don't count against this cap — only a real `click()` invocation does — so a
25
+ * dense post-filter list (a handful of controls, per bugfix-002's visibility
26
+ * filter and bugfix-005's interactive scoping) still resolves in one or two
27
+ * attempts, while a pathological list (371 candidates, the uchealth-7
28
+ * measurement) can't spend the whole step budget clicking its way through
29
+ * every entry.
30
+ */
31
+ export declare const DEFAULT_CLICK_CANDIDATE_ATTEMPT_CAP = 5;
32
+ /**
33
+ * Attempts to click one candidate. Resolves on a successful click; rejects on
34
+ * failure — the same "no boolean return, infer from throw" contract
35
+ * `clickDeepLocatorCandidate` (`deep-locator-candidates.ts`) already uses, so
36
+ * a caller can inject that function directly (partially applied over
37
+ * `page`/`frameSelector`/`innerSelector`) without an adapter.
38
+ */
39
+ export type ClickCandidateFn = (candidate: DeepLocatorCandidate) => Promise<void>;
40
+ /** Refuses a candidate before it's clicked — e.g. `flow-runner.ts`'s `isWizardExitAction` deny-list, injected so this module stays site-agnostic. */
41
+ export type DenyCandidatePredicate = (candidate: DeepLocatorCandidate) => boolean;
42
+ export interface ClickCandidateCascadeOptions {
43
+ /** Skips a candidate without clicking it when this returns `true`. Optional — omit to click every non-not-actionable candidate in rank order. */
44
+ denyCandidate?: DenyCandidatePredicate;
45
+ /** Overrides {@link DEFAULT_CLICK_CANDIDATE_ATTEMPT_CAP}. */
46
+ attemptCap?: number;
47
+ }
48
+ /** Outcome of a {@link clickFirstActionableCandidate} walk. */
49
+ export interface ClickCandidateCascadeOutcome {
50
+ /** `true` only when a candidate's click resolved (didn't reject). */
51
+ clicked: boolean;
52
+ /** The candidate that was clicked, or `null` when the walk exhausted the list/cap without a successful click. */
53
+ candidate: DeepLocatorCandidate | null;
54
+ /** Selectors of every candidate this walk actually clicked (attempted), in attempt order — denied candidates are excluded since they were never clicked. */
55
+ triedSelectors: string[];
56
+ }
57
+ /**
58
+ * Walks `candidates` in rank order, clicking each via `click` until one
59
+ * succeeds. A candidate refused by `denyCandidate` is skipped without being
60
+ * clicked and doesn't count against `attemptCap`. A click rejection that
61
+ * {@link isNodeNotActionableError} classifies as "not actionable" (unrendered
62
+ * node) is treated as "skip this candidate, try the next"; any other
63
+ * rejection stops the walk immediately and rethrows, so a caller doesn't
64
+ * silently burn the remaining candidates on an error that had nothing to do
65
+ * with actionability (a detached frame, a wedged click's
66
+ * `WatchdogTimeoutError`). Never throws on exhaustion — an exhausted list
67
+ * (every candidate denied or not-actionable, or the cap reached) resolves to
68
+ * `{ clicked: false, candidate: null, triedSelectors }` instead.
69
+ */
70
+ export declare function clickFirstActionableCandidate(candidates: readonly DeepLocatorCandidate[], click: ClickCandidateFn, options?: ClickCandidateCascadeOptions): Promise<ClickCandidateCascadeOutcome>;
71
+ //# sourceMappingURL=deep-locator-click.d.ts.map