@jobshimo/browser-link 0.35.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/agent-instructions/content.js +21 -0
  2. package/dist/agent-instructions/content.js.map +1 -1
  3. package/dist/cdp/flow.d.ts +36 -3
  4. package/dist/cdp/flow.js +54 -19
  5. package/dist/cdp/flow.js.map +1 -1
  6. package/dist/cdp/inpage/builders.d.ts +152 -20
  7. package/dist/cdp/inpage/builders.js +365 -77
  8. package/dist/cdp/inpage/builders.js.map +1 -1
  9. package/dist/cdp/inpage/observer.d.ts +50 -1
  10. package/dist/cdp/inpage/observer.js +333 -3
  11. package/dist/cdp/inpage/observer.js.map +1 -1
  12. package/dist/cdp/transport.js +91 -9
  13. package/dist/cdp/transport.js.map +1 -1
  14. package/dist/extension/background.js +92 -13
  15. package/dist/extension/background.js.map +1 -1
  16. package/dist/extension/flow.d.ts +36 -3
  17. package/dist/extension/flow.js +54 -19
  18. package/dist/extension/flow.js.map +1 -1
  19. package/dist/extension/inpage/builders.d.ts +152 -20
  20. package/dist/extension/inpage/builders.js +365 -77
  21. package/dist/extension/inpage/builders.js.map +1 -1
  22. package/dist/extension/inpage/observer.d.ts +50 -1
  23. package/dist/extension/inpage/observer.js +333 -3
  24. package/dist/extension/inpage/observer.js.map +1 -1
  25. package/dist/extension/manifest.json +1 -1
  26. package/dist/map/queries.d.ts +2 -0
  27. package/dist/map/queries.js +23 -1
  28. package/dist/map/queries.js.map +1 -1
  29. package/dist/map/tools.js +26 -4
  30. package/dist/map/tools.js.map +1 -1
  31. package/dist/tools/browser-definitions.js +89 -17
  32. package/dist/tools/browser-definitions.js.map +1 -1
  33. package/dist/tools/browser-dispatch.d.ts +19 -26
  34. package/dist/tools/browser-dispatch.js +166 -16
  35. package/dist/tools/browser-dispatch.js.map +1 -1
  36. package/dist/tools/server-instructions.js +21 -0
  37. package/dist/tools/server-instructions.js.map +1 -1
  38. package/package.json +1 -1
@@ -22,6 +22,99 @@
22
22
  */
23
23
  import { DEEP_QUERY_JS } from './deep-query.js';
24
24
  import { DOM_HELPERS_JS } from './dom-helpers.js';
25
+ import { OBSERVER_GLOBAL } from './observer.js';
26
+ /**
27
+ * In-page access to the page observer's element identity (spec v4 §5.6),
28
+ * injected verbatim into `buildSnapshotJs`, `buildFindJs` and `buildStateJs`.
29
+ * The observer global is looked up ONCE per evaluation and used only when it
30
+ * is present, not torn down, and exposes `refFor`:
31
+ * - `refOf(el)` returns the observer's `<doc_tag>:e<N>` ref for `el`, or `null`;
32
+ * - `withDocId(result)` adds `doc_id` to `result` and returns it;
33
+ * - `snapshotStore()` returns the observer when it keeps snapshot records
34
+ * (`recordSnapshot` / `getSnapshot`, used by `snapshot({ since })`), else
35
+ * `null`.
36
+ * Without the observer (injection failed, pre-observer document) all are
37
+ * no-ops, so every result is byte-identical to the pre-ref output.
38
+ */
39
+ export const PAGE_OBSERVER_JS = `
40
+ const pageObserver = (() => {
41
+ try {
42
+ const g = window[${JSON.stringify(OBSERVER_GLOBAL)}];
43
+ if (g && !g.dead && typeof g.refFor === 'function') return g;
44
+ } catch (e) {}
45
+ return null;
46
+ })();
47
+ function refOf(el) {
48
+ if (!pageObserver) return null;
49
+ try {
50
+ const ref = pageObserver.refFor(el);
51
+ return typeof ref === 'string' ? ref : null;
52
+ } catch (e) {
53
+ return null;
54
+ }
55
+ }
56
+ function withDocId(result) {
57
+ if (pageObserver && typeof pageObserver.doc_id === 'string') result.doc_id = pageObserver.doc_id;
58
+ return result;
59
+ }
60
+ function snapshotStore() {
61
+ if (
62
+ pageObserver &&
63
+ typeof pageObserver.recordSnapshot === 'function' &&
64
+ typeof pageObserver.getSnapshot === 'function'
65
+ ) {
66
+ return pageObserver;
67
+ }
68
+ return null;
69
+ }
70
+ `;
71
+ /**
72
+ * In-page action-target resolution (spec v4 §6.3), injected after
73
+ * `DEEP_QUERY_JS` and `PAGE_OBSERVER_JS` into the builders that take a
74
+ * `selector` or a `ref` (click, type, focus, element rect, `wait_for` by
75
+ * ref, `find` by ref):
76
+ * `resolveTarget(opts)` with a non-empty `opts.ref` asks the observer
77
+ * (`resolveRefDetailed`, which re-resolves a replaced node by its semantic
78
+ * key) and answers `{ ok: true, el, reresolved }`, `{ ok: false, reason:
79
+ * 'ref-stale', ref, doc_id }` or `{ ok: false, reason: 'observer-unavailable'
80
+ * }`; otherwise it resolves `opts.selector` exactly as the selector builders
81
+ * always did (`invalid-selector` checked against `document` first, then
82
+ * `deepQueryFirst`, `not-found`). Kept out of `PAGE_OBSERVER_JS` so the
83
+ * snapshot and state sources do not carry code they never call.
84
+ */
85
+ export const RESOLVE_TARGET_JS = `
86
+ function resolveTarget(opts) {
87
+ if (typeof opts.ref === 'string' && opts.ref.length > 0) {
88
+ if (!pageObserver || typeof pageObserver.resolveRefDetailed !== 'function') {
89
+ return { ok: false, reason: 'observer-unavailable' };
90
+ }
91
+ let found = null;
92
+ try {
93
+ found = pageObserver.resolveRefDetailed(opts.ref);
94
+ } catch (e) {
95
+ found = null;
96
+ }
97
+ if (!found || !found.el) return withDocId({ ok: false, reason: 'ref-stale', ref: opts.ref });
98
+ return { ok: true, el: found.el, reresolved: found.reresolved === true };
99
+ }
100
+ try {
101
+ document.querySelector(opts.selector);
102
+ } catch (e) {
103
+ return { ok: false, reason: 'invalid-selector', error: e && e.message ? e.message : String(e) };
104
+ }
105
+ const el = deepQueryFirst(opts.selector);
106
+ if (!el) return { ok: false, reason: 'not-found' };
107
+ return { ok: true, el: el, reresolved: false };
108
+ }
109
+ `;
110
+ /** JSON for the `selector` / `ref` pair, embedded as data in the built
111
+ * source; `ref` is included only when given so a selector build keeps the
112
+ * same options object as before. */
113
+ function targetJson(opts) {
114
+ return typeof opts.ref === 'string' && opts.ref.length > 0
115
+ ? { selector: opts.selector, ref: opts.ref }
116
+ : { selector: opts.selector };
117
+ }
25
118
  export function buildSnapshotJs(opts = {}) {
26
119
  const optsJson = JSON.stringify({
27
120
  withinSelector: typeof opts.within_selector === 'string' ? opts.within_selector : null,
@@ -30,23 +123,25 @@ export function buildSnapshotJs(opts = {}) {
30
123
  maxInteractive: typeof opts.max_interactive === 'number' && opts.max_interactive > 0
31
124
  ? Math.min(opts.max_interactive, 500)
32
125
  : 120,
126
+ since: typeof opts.since === 'string' ? opts.since : null,
33
127
  });
34
128
  return `
35
129
  (() => {
36
130
  ${DEEP_QUERY_JS}
37
131
  ${DOM_HELPERS_JS}
132
+ ${PAGE_OBSERVER_JS}
38
133
  const opts = ${optsJson};
39
134
  let root = document;
40
135
  let notice = '';
41
136
  if (opts.withinSelector) {
42
137
  const sub = deepQueryFirst(opts.withinSelector);
43
138
  if (!sub) {
44
- return {
139
+ return withDocId({
45
140
  title: document.title,
46
141
  url: location.href,
47
142
  interactive: [],
48
143
  notice: 'within_selector did not match any element',
49
- };
144
+ });
50
145
  }
51
146
  root = sub;
52
147
  }
@@ -89,6 +184,8 @@ export function buildSnapshotJs(opts = {}) {
89
184
  const role = el.getAttribute('role') || tag;
90
185
  const selInfo = genSelectorInfo(el);
91
186
  const entry = { tag, role, selector: selInfo.selector };
187
+ const ref = refOf(el);
188
+ if (ref) entry.ref = ref;
92
189
  if (selInfo.ambiguous) entry.ambiguous = true;
93
190
  const txt = shortText(el);
94
191
  if (txt) entry.text = txt;
@@ -108,29 +205,118 @@ export function buildSnapshotJs(opts = {}) {
108
205
  if (frame) entry.frame = frame;
109
206
  interactive.push(entry);
110
207
  });
111
- const result = {
112
- title: document.title,
113
- url: location.href,
114
- interactive: interactive.slice(0, opts.maxInteractive),
115
- };
208
+ let headings = null;
209
+ let visibleText = '';
116
210
  if (!opts.onlyInteractive) {
117
- const headings = [];
211
+ const found = [];
118
212
  deepQueryAll('h1, h2, h3', root).forEach((h) => {
119
213
  if (!isVisible(h)) return;
120
214
  if (inExcludedLandmark(h)) return;
121
215
  const t = shortText(h);
122
- if (t) headings.push({ level: h.tagName, text: t });
216
+ if (t) found.push({ level: h.tagName, text: t });
123
217
  });
124
- result.headings = headings.slice(0, 30);
218
+ headings = found.slice(0, 30);
125
219
  const textRoot = (root === document) ? (document.body || document) : root;
126
- const visibleText = (textRoot && textRoot.innerText) ? textRoot.innerText.slice(0, 4000) : '';
220
+ visibleText = (textRoot && textRoot.innerText) ? textRoot.innerText.slice(0, 4000) : '';
221
+ }
222
+ let snapshotId = null;
223
+ if (withDocId({}).doc_id && typeof pageObserver.nextSnapshotId === 'function') {
224
+ const issued = pageObserver.nextSnapshotId();
225
+ if (typeof issued === 'string') snapshotId = issued;
226
+ }
227
+ function fullResult() {
228
+ const result = {
229
+ title: document.title,
230
+ url: location.href,
231
+ interactive: interactive.slice(0, opts.maxInteractive),
232
+ };
233
+ if (headings) result.headings = headings;
127
234
  if (visibleText) result.text = visibleText;
235
+ if (notice) result.notice = notice;
236
+ withDocId(result);
237
+ if (snapshotId) result.snapshot_id = snapshotId;
238
+ return result;
128
239
  }
129
- if (notice) result.notice = notice;
130
- return result;
240
+ // Record every snapshot (with or without since) so a later call can diff
241
+ // against it. Entries are keyed by ref; the hash is the entry serialised
242
+ // without its ref, in emission order. Capped at the first 500 entries.
243
+ const store = snapshotId ? snapshotStore() : null;
244
+ // A snapshot_id is \`<doc_id>:s<N>\`: a since whose prefix (before the LAST
245
+ // ':') is not this document's doc_id, or that has no ':', came from another
246
+ // document and is never looked up.
247
+ const sinceCut = opts.since === null ? -1 : opts.since.lastIndexOf(':');
248
+ const sinceSameDoc =
249
+ sinceCut >= 0 && withDocId({}).doc_id === opts.since.slice(0, sinceCut);
250
+ const previous = store && sinceSameDoc ? store.getSnapshot(opts.since) : null;
251
+ const current = new Map();
252
+ const headingsHash = headings ? JSON.stringify(headings) : null;
253
+ const textHash = opts.onlyInteractive ? null : visibleText;
254
+ if (store) {
255
+ for (const entry of interactive) {
256
+ if (current.size >= 500) break;
257
+ if (typeof entry.ref !== 'string') continue;
258
+ const copy = {};
259
+ for (const key of Object.keys(entry)) if (key !== 'ref') copy[key] = entry[key];
260
+ current.set(entry.ref, { hash: JSON.stringify(copy), entry });
261
+ }
262
+ store.recordSnapshot(snapshotId, { entries: current, headings_hash: headingsHash, text_hash: textHash });
263
+ }
264
+ if (opts.since === null) return fullResult();
265
+ if (!store) {
266
+ const result = fullResult();
267
+ result.since = opts.since;
268
+ result.since_status = 'observer-unavailable';
269
+ return result;
270
+ }
271
+ if (!previous || !previous.entries || typeof previous.entries.get !== 'function') {
272
+ const result = fullResult();
273
+ result.since = opts.since;
274
+ result.since_status = sinceSameDoc ? 'evicted' : 'doc-changed';
275
+ return result;
276
+ }
277
+ const added = [];
278
+ const changed = [];
279
+ const removed = [];
280
+ current.forEach((item, ref) => {
281
+ const old = previous.entries.get(ref);
282
+ if (!old) added.push(item.entry);
283
+ else if (old.hash !== item.hash) changed.push(item.entry);
284
+ });
285
+ previous.entries.forEach((item, ref) => {
286
+ if (current.has(ref) || removed.length >= 500) return;
287
+ const gone = { ref, tag: item.entry.tag };
288
+ if (item.entry.text) gone.text = item.entry.text;
289
+ removed.push(gone);
290
+ });
291
+ // max_interactive applies after diffing (added first, then changed), so
292
+ // a window shift never masquerades as change.
293
+ const listed = added.concat(changed);
294
+ const kept = listed.slice(0, opts.maxInteractive);
295
+ const diff = withDocId({ title: document.title, url: location.href });
296
+ diff.snapshot_id = snapshotId;
297
+ diff.since = opts.since;
298
+ diff.added = kept.slice(0, Math.min(added.length, kept.length));
299
+ diff.removed = removed;
300
+ diff.changed = kept.slice(diff.added.length);
301
+ if (listed.length > kept.length) diff.overflow = listed.length - kept.length;
302
+ if (!opts.onlyInteractive) {
303
+ if (headingsHash !== previous.headings_hash) diff.headings = headings;
304
+ if (textHash !== previous.text_hash) diff.text = visibleText;
305
+ }
306
+ return diff;
131
307
  })()
132
308
  `;
133
309
  }
310
+ /** Only the documented key fields reach the built source, as JSON data. */
311
+ function findKeyJson(key) {
312
+ return Array.isArray(key.path)
313
+ ? {
314
+ role: key.role,
315
+ name: key.name,
316
+ path: key.path.map((step) => ({ tag: step.tag, index: step.index })),
317
+ }
318
+ : { role: key.role, name: key.name };
319
+ }
134
320
  export function buildFindJs(opts) {
135
321
  const optsJson = JSON.stringify({
136
322
  text: opts.text,
@@ -138,12 +324,98 @@ export function buildFindJs(opts) {
138
324
  exact: opts.exact === true,
139
325
  candidateLimit: 5,
140
326
  nearMissLimit: 3,
327
+ ...(typeof opts.ref === 'string' && opts.ref.length > 0 ? { ref: opts.ref } : {}),
328
+ ...(opts.key ? { key: findKeyJson(opts.key) } : {}),
141
329
  });
142
330
  return `
143
331
  (() => {
144
332
  ${DEEP_QUERY_JS}
145
333
  ${DOM_HELPERS_JS}
334
+ ${PAGE_OBSERVER_JS}
335
+ ${typeof opts.ref === 'string' && opts.ref.length > 0 ? RESOLVE_TARGET_JS : ''}
146
336
  const opts = ${optsJson};
337
+ function semanticKeyOf(el) {
338
+ if (!pageObserver || typeof pageObserver.semanticKeyFor !== 'function') return null;
339
+ try {
340
+ const key = pageObserver.semanticKeyFor(el);
341
+ return key && typeof key === 'object' ? key : null;
342
+ } catch (e) {
343
+ return null;
344
+ }
345
+ }
346
+ function singleMatch(el, ref, reresolved) {
347
+ const center = viewportCenterOf(el);
348
+ const selInfo = genSelectorInfo(el);
349
+ const result = { matched: true, selector: selInfo.selector };
350
+ if (ref) result.ref = ref;
351
+ result.coords = {
352
+ x: Math.round(center.x),
353
+ y: Math.round(center.y),
354
+ };
355
+ result.tag = el.tagName.toLowerCase();
356
+ result.text = shortText(el);
357
+ if (selInfo.ambiguous) result.ambiguous = true;
358
+ const frame = frameSelectorFor(el);
359
+ if (frame) result.frame = frame;
360
+ if (reresolved) result.reresolved = true;
361
+ const key = semanticKeyOf(el);
362
+ if (key) result.semantic_key = key;
363
+ return withDocId(result);
364
+ }
365
+ if (typeof opts.ref === 'string') {
366
+ const target = resolveTarget(opts);
367
+ if (!target.ok) {
368
+ const failure = { matched: false, reason: target.reason, ref: opts.ref };
369
+ return withDocId(failure);
370
+ }
371
+ return singleMatch(target.el, opts.ref, target.reresolved);
372
+ }
373
+ if (opts.key) {
374
+ if (!pageObserver || typeof pageObserver.semanticKeyFor !== 'function') {
375
+ return { matched: false, reason: 'observer-unavailable' };
376
+ }
377
+ const wanted = opts.key;
378
+ const candidates = [];
379
+ for (const el of deepQueryAll('*')) {
380
+ const key = semanticKeyOf(el);
381
+ if (key && key.role === wanted.role && key.name === wanted.name) {
382
+ candidates.push({ el: el, path: Array.isArray(key.path) ? key.path : [] });
383
+ }
384
+ }
385
+ const count = candidates.length;
386
+ const shared = 'key: ' + count + ' candidates share role and name; ';
387
+ let picked = null;
388
+ let error = count > 1 ? shared + 'pass path to disambiguate' : null;
389
+ if (!Array.isArray(wanted.path)) {
390
+ if (count === 1) picked = candidates[0].el;
391
+ } else {
392
+ // Same rule as the observer's re-resolution: identical tag path and
393
+ // exactly one such candidate; identical rows are refused, never guessed.
394
+ let sameTags = 0;
395
+ let only = null;
396
+ for (const c of candidates) {
397
+ if (c.path.length !== wanted.path.length) continue;
398
+ let same = true;
399
+ for (let i = 0; i < c.path.length && same; i++) {
400
+ if (c.path[i].tag !== wanted.path[i].tag) same = false;
401
+ }
402
+ if (!same) continue;
403
+ sameTags++;
404
+ only = c.el;
405
+ }
406
+ if (sameTags === 1) {
407
+ picked = only;
408
+ } else if (sameTags > 1) {
409
+ error = 'key: ' + sameTags + ' candidates share role, name and tag path';
410
+ } else if (count > 0) {
411
+ error = shared + 'none has the same tag path';
412
+ }
413
+ }
414
+ if (picked) return singleMatch(picked, refOf(picked), false);
415
+ const failure = { matched: false, reason: 'not-found' };
416
+ if (error) failure.error = error;
417
+ return withDocId(failure);
418
+ }
147
419
  const needle = opts.text.toLowerCase();
148
420
  const needleTokens = needle.split(/[^a-z0-9]+/).filter(Boolean);
149
421
  const ROLE_SELECTORS = {
@@ -203,6 +475,8 @@ export function buildFindJs(opts) {
203
475
  }
204
476
  function toNearMiss(el) {
205
477
  const entry = { text: snippetOf(el), selector: genSelector(el) };
478
+ const ref = refOf(el);
479
+ if (ref) entry.ref = ref;
206
480
  const roleAttr = el.getAttribute('role');
207
481
  if (roleAttr) entry.role = roleAttr;
208
482
  return entry;
@@ -235,60 +509,46 @@ export function buildFindJs(opts) {
235
509
  ' but none with role "' + opts.role + '"' +
236
510
  (closest ? ' — closest: ' + describeForError(closest) + ' "' + snippetOf(closest) + '"' : '');
237
511
  result.near_misses = ranked.map(toNearMiss);
238
- return result;
512
+ return withDocId(result);
239
513
  }
240
514
  const ranked = rankCandidates(broadAll);
241
515
  if (ranked.length > 0) result.near_misses = ranked.map(toNearMiss);
242
- return result;
516
+ return withDocId(result);
243
517
  }
244
518
  const ranked = rankCandidates(all);
245
519
  if (ranked.length > 0) result.near_misses = ranked.map(toNearMiss);
246
- return result;
520
+ return withDocId(result);
247
521
  }
248
522
  if (matches.length > 1) {
249
- return {
523
+ return withDocId({
250
524
  matched: false,
251
525
  reason: 'multiple-matches',
252
- candidates: matches.slice(0, opts.candidateLimit).map((el) => ({
253
- selector: genSelector(el),
254
- text: shortText(el),
255
- tag: el.tagName.toLowerCase(),
256
- })),
257
- };
526
+ candidates: matches.slice(0, opts.candidateLimit).map((el) => {
527
+ const candidate = { selector: genSelector(el) };
528
+ const ref = refOf(el);
529
+ if (ref) candidate.ref = ref;
530
+ candidate.text = shortText(el);
531
+ candidate.tag = el.tagName.toLowerCase();
532
+ return candidate;
533
+ }),
534
+ });
258
535
  }
259
536
  const el = matches[0];
260
- const center = viewportCenterOf(el);
261
- const selInfo = genSelectorInfo(el);
262
- const result = {
263
- matched: true,
264
- selector: selInfo.selector,
265
- coords: {
266
- x: Math.round(center.x),
267
- y: Math.round(center.y),
268
- },
269
- tag: el.tagName.toLowerCase(),
270
- text: shortText(el),
271
- };
272
- if (selInfo.ambiguous) result.ambiguous = true;
273
- const frame = frameSelectorFor(el);
274
- if (frame) result.frame = frame;
275
- return result;
537
+ return singleMatch(el, refOf(el), false);
276
538
  })()
277
539
  `;
278
540
  }
279
541
  export function buildClickResolveJs(opts) {
280
- const optsJson = JSON.stringify({ selector: opts.selector, force: opts.force });
542
+ const optsJson = JSON.stringify({ ...targetJson(opts), force: opts.force });
281
543
  return `
282
544
  (() => {
283
545
  ${DEEP_QUERY_JS}
546
+ ${PAGE_OBSERVER_JS}
547
+ ${RESOLVE_TARGET_JS}
284
548
  const opts = ${optsJson};
285
- try {
286
- document.querySelector(opts.selector);
287
- } catch (e) {
288
- return { ok: false, reason: 'invalid-selector', error: e && e.message ? e.message : String(e) };
289
- }
290
- const el = deepQueryFirst(opts.selector);
291
- if (!el) return { ok: false, reason: 'not-found' };
549
+ const target = resolveTarget(opts);
550
+ if (!target.ok) return target;
551
+ const el = target.el;
292
552
  const chain = frameElementChain(el);
293
553
  for (const fe of chain) {
294
554
  if (fe.scrollIntoView) fe.scrollIntoView({ block: 'center', inline: 'center' });
@@ -303,41 +563,59 @@ export function buildClickResolveJs(opts) {
303
563
  const result = { ok: true, x: center.x, y: center.y, tag };
304
564
  const hit = occlusion.allowed ? occlusion.hit : occlusion.blocker;
305
565
  if (hit) result.hit_element = hit;
566
+ if (target.reresolved) result.reresolved = true;
306
567
  return result;
307
568
  })()
308
569
  `;
309
570
  }
310
571
  export function buildTypeResolveJs(opts) {
311
- const optsJson = JSON.stringify({ selector: opts.selector });
572
+ const optsJson = JSON.stringify(targetJson(opts));
312
573
  return `
313
574
  (() => {
314
575
  ${DEEP_QUERY_JS}
576
+ ${PAGE_OBSERVER_JS}
577
+ ${RESOLVE_TARGET_JS}
315
578
  const opts = ${optsJson};
316
- try {
317
- document.querySelector(opts.selector);
318
- } catch (e) {
319
- return { ok: false, reason: 'invalid-selector', error: e && e.message ? e.message : String(e) };
320
- }
321
- const el = deepQueryFirst(opts.selector);
322
- if (!el) return { ok: false, reason: 'not-found' };
579
+ const target = resolveTarget(opts);
580
+ if (!target.ok) return target;
581
+ const el = target.el;
323
582
  el.focus();
324
583
  ${opts.clear ? "if ('value' in el) { el.value = ''; el.dispatchEvent(new Event('input', { bubbles: true })); }" : ''}
325
- return { ok: true };
584
+ return target.reresolved ? { ok: true, reresolved: true } : { ok: true };
326
585
  })()`;
327
586
  }
328
587
  export function buildFocusJs(opts) {
329
- const optsJson = JSON.stringify({ selector: opts.selector });
588
+ const optsJson = JSON.stringify(targetJson(opts));
330
589
  return `
331
590
  (() => {
332
591
  ${DEEP_QUERY_JS}
592
+ ${PAGE_OBSERVER_JS}
593
+ ${RESOLVE_TARGET_JS}
333
594
  const opts = ${optsJson};
334
- const el = deepQueryFirst(opts.selector);
335
- if (!el) return false;
336
- el.focus();
337
- return true;
595
+ const target = resolveTarget(opts);
596
+ const byRef = typeof opts.ref === 'string';
597
+ if (!target.ok) return byRef ? target : false;
598
+ target.el.focus();
599
+ if (!byRef) return true;
600
+ return target.reresolved ? { ok: true, reresolved: true } : { ok: true };
338
601
  })()`;
339
602
  }
340
- export function buildWaitForSelectorJs(selector, condition) {
603
+ export function buildWaitForSelectorJs(target, condition) {
604
+ if (typeof target !== 'string') {
605
+ const refOptsJson = JSON.stringify({ ref: target.ref, condition });
606
+ return `
607
+ (() => {
608
+ ${DEEP_QUERY_JS}
609
+ ${PAGE_OBSERVER_JS}
610
+ ${RESOLVE_TARGET_JS}
611
+ const opts = ${refOptsJson};
612
+ const target = resolveTarget(opts);
613
+ if (!target.ok && target.reason === 'observer-unavailable') return target;
614
+ const el = target.ok ? target.el : null;
615
+ ${WAIT_FOR_CONDITION_JS}
616
+ })()`;
617
+ }
618
+ const selector = target;
341
619
  const optsJson = JSON.stringify({ selector, condition });
342
620
  return `
343
621
  (() => {
@@ -345,7 +623,12 @@ export function buildWaitForSelectorJs(selector, condition) {
345
623
  const opts = ${optsJson};
346
624
  document.querySelector(opts.selector);
347
625
  const el = deepQueryFirst(opts.selector);
348
- if (opts.condition === 'attached') return Boolean(el);
626
+ ${WAIT_FOR_CONDITION_JS}
627
+ })()`;
628
+ }
629
+ /** The condition check shared by both `wait_for` probe targets; `el` is
630
+ * the resolved element or `null`. */
631
+ const WAIT_FOR_CONDITION_JS = `if (opts.condition === 'attached') return Boolean(el);
349
632
  if (opts.condition === 'detached') return !el;
350
633
  const wantHidden = opts.condition === 'hidden';
351
634
  if (!el) return wantHidden;
@@ -354,22 +637,18 @@ export function buildWaitForSelectorJs(selector, condition) {
354
637
  if (s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0') return wantHidden;
355
638
  const r = el.getBoundingClientRect();
356
639
  const shown = r.width > 0 && r.height > 0;
357
- return wantHidden ? !shown : shown;
358
- })()`;
359
- }
640
+ return wantHidden ? !shown : shown;`;
360
641
  export function buildElementRectJs(opts) {
361
- const optsJson = JSON.stringify({ selector: opts.selector });
642
+ const optsJson = JSON.stringify(targetJson(opts));
362
643
  return `
363
644
  (() => {
364
645
  ${DEEP_QUERY_JS}
646
+ ${PAGE_OBSERVER_JS}
647
+ ${RESOLVE_TARGET_JS}
365
648
  const opts = ${optsJson};
366
- try {
367
- document.querySelector(opts.selector);
368
- } catch (e) {
369
- return { ok: false, reason: 'invalid-selector', error: e && e.message ? e.message : String(e) };
370
- }
371
- const el = deepQueryFirst(opts.selector);
372
- if (!el) return { ok: false, reason: 'not-found' };
649
+ const target = resolveTarget(opts);
650
+ if (!target.ok) return target;
651
+ const el = target.el;
373
652
  const chain = frameElementChain(el);
374
653
  // behavior 'instant' overrides CSS scroll-behavior: smooth, which would
375
654
  // leave the rect below stale while the scroll is still animating.
@@ -394,13 +673,15 @@ export function buildElementRectJs(opts) {
394
673
  scrollX = top.scrollX || 0;
395
674
  scrollY = top.scrollY || 0;
396
675
  } catch (_) {}
397
- return {
676
+ const result = {
398
677
  ok: true,
399
678
  x: offsetX + rect.left + scrollX,
400
679
  y: offsetY + rect.top + scrollY,
401
680
  width: rect.width,
402
681
  height: rect.height,
403
682
  };
683
+ if (target.reresolved) result.reresolved = true;
684
+ return result;
404
685
  })()`;
405
686
  }
406
687
  export function buildSettleJs(opts) {
@@ -569,12 +850,16 @@ export function buildExpectProbeJs(opts) {
569
850
  * `focused` beyond `<body>`, no `dialogs` when none are open, and no
570
851
  * `scroll` when the page is at its default (0,0) position — token-lean by
571
852
  * construction, matching the omit-falsy convention the other builders use.
853
+ *
854
+ * With the page observer installed (see `PAGE_OBSERVER_JS`), `focused`
855
+ * carries `ref` right after `selector` and the result carries `doc_id`.
572
856
  */
573
857
  export function buildStateJs() {
574
858
  return `
575
859
  (() => {
576
860
  ${DEEP_QUERY_JS}
577
861
  ${DOM_HELPERS_JS}
862
+ ${PAGE_OBSERVER_JS}
578
863
  function deepActiveElement() {
579
864
  let el = document.activeElement;
580
865
  let guard = 0;
@@ -635,7 +920,10 @@ export function buildStateJs() {
635
920
  const active = deepActiveElement();
636
921
  if (active && active !== document.body && active.tagName) {
637
922
  const selInfo = genSelectorInfo(active);
638
- const focused = { selector: selInfo.selector, tag: active.tagName.toLowerCase() };
923
+ const focused = { selector: selInfo.selector };
924
+ const ref = refOf(active);
925
+ if (ref) focused.ref = ref;
926
+ focused.tag = active.tagName.toLowerCase();
639
927
  if (selInfo.ambiguous) focused.ambiguous = true;
640
928
  result.focused = focused;
641
929
  }
@@ -655,7 +943,7 @@ export function buildStateJs() {
655
943
  const scrollY = Math.round(window.scrollY);
656
944
  if (scrollX !== 0 || scrollY !== 0) result.scroll = { x: scrollX, y: scrollY };
657
945
 
658
- return result;
946
+ return withDocId(result);
659
947
  })()
660
948
  `;
661
949
  }
@@ -1 +1 @@
1
- {"version":3,"file":"builders.js","sourceRoot":"","sources":["../../../src/cdp/inpage/builders.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"builders.js","sourceRoot":"","sources":["../../../src/cdp/inpage/builders.ts"],"names":[],"mappings":"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"}