@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
@@ -8,6 +8,99 @@
8
8
  */
9
9
  import { DEEP_QUERY_JS } from './deep-query.js';
10
10
  import { DOM_HELPERS_JS } from './dom-helpers.js';
11
+ import { OBSERVER_GLOBAL } from './observer.js';
12
+ /**
13
+ * In-page access to the page observer's element identity (spec v4 §5.6),
14
+ * injected verbatim into `buildSnapshotJs`, `buildFindJs` and `buildStateJs`.
15
+ * The observer global is looked up ONCE per evaluation and used only when it
16
+ * is present, not torn down, and exposes `refFor`:
17
+ * - `refOf(el)` returns the observer's `<doc_tag>:e<N>` ref for `el`, or `null`;
18
+ * - `withDocId(result)` adds `doc_id` to `result` and returns it;
19
+ * - `snapshotStore()` returns the observer when it keeps snapshot records
20
+ * (`recordSnapshot` / `getSnapshot`, used by `snapshot({ since })`), else
21
+ * `null`.
22
+ * Without the observer (injection failed, pre-observer document) all are
23
+ * no-ops, so every result is byte-identical to the pre-ref output.
24
+ */
25
+ export const PAGE_OBSERVER_JS = `
26
+ const pageObserver = (() => {
27
+ try {
28
+ const g = window[${JSON.stringify(OBSERVER_GLOBAL)}];
29
+ if (g && !g.dead && typeof g.refFor === 'function') return g;
30
+ } catch (e) {}
31
+ return null;
32
+ })();
33
+ function refOf(el) {
34
+ if (!pageObserver) return null;
35
+ try {
36
+ const ref = pageObserver.refFor(el);
37
+ return typeof ref === 'string' ? ref : null;
38
+ } catch (e) {
39
+ return null;
40
+ }
41
+ }
42
+ function withDocId(result) {
43
+ if (pageObserver && typeof pageObserver.doc_id === 'string') result.doc_id = pageObserver.doc_id;
44
+ return result;
45
+ }
46
+ function snapshotStore() {
47
+ if (
48
+ pageObserver &&
49
+ typeof pageObserver.recordSnapshot === 'function' &&
50
+ typeof pageObserver.getSnapshot === 'function'
51
+ ) {
52
+ return pageObserver;
53
+ }
54
+ return null;
55
+ }
56
+ `;
57
+ /**
58
+ * In-page action-target resolution (spec v4 §6.3), injected after
59
+ * `DEEP_QUERY_JS` and `PAGE_OBSERVER_JS` into the builders that take a
60
+ * `selector` or a `ref` (click, type, focus, element rect, `wait_for` by
61
+ * ref, `find` by ref):
62
+ * `resolveTarget(opts)` with a non-empty `opts.ref` asks the observer
63
+ * (`resolveRefDetailed`, which re-resolves a replaced node by its semantic
64
+ * key) and answers `{ ok: true, el, reresolved }`, `{ ok: false, reason:
65
+ * 'ref-stale', ref, doc_id }` or `{ ok: false, reason: 'observer-unavailable'
66
+ * }`; otherwise it resolves `opts.selector` exactly as the selector builders
67
+ * always did (`invalid-selector` checked against `document` first, then
68
+ * `deepQueryFirst`, `not-found`). Kept out of `PAGE_OBSERVER_JS` so the
69
+ * snapshot and state sources do not carry code they never call.
70
+ */
71
+ export const RESOLVE_TARGET_JS = `
72
+ function resolveTarget(opts) {
73
+ if (typeof opts.ref === 'string' && opts.ref.length > 0) {
74
+ if (!pageObserver || typeof pageObserver.resolveRefDetailed !== 'function') {
75
+ return { ok: false, reason: 'observer-unavailable' };
76
+ }
77
+ let found = null;
78
+ try {
79
+ found = pageObserver.resolveRefDetailed(opts.ref);
80
+ } catch (e) {
81
+ found = null;
82
+ }
83
+ if (!found || !found.el) return withDocId({ ok: false, reason: 'ref-stale', ref: opts.ref });
84
+ return { ok: true, el: found.el, reresolved: found.reresolved === true };
85
+ }
86
+ try {
87
+ document.querySelector(opts.selector);
88
+ } catch (e) {
89
+ return { ok: false, reason: 'invalid-selector', error: e && e.message ? e.message : String(e) };
90
+ }
91
+ const el = deepQueryFirst(opts.selector);
92
+ if (!el) return { ok: false, reason: 'not-found' };
93
+ return { ok: true, el: el, reresolved: false };
94
+ }
95
+ `;
96
+ /** JSON for the `selector` / `ref` pair, embedded as data in the built
97
+ * source; `ref` is included only when given so a selector build keeps the
98
+ * same options object as before. */
99
+ function targetJson(opts) {
100
+ return typeof opts.ref === 'string' && opts.ref.length > 0
101
+ ? { selector: opts.selector, ref: opts.ref }
102
+ : { selector: opts.selector };
103
+ }
11
104
  export function buildSnapshotJs(opts = {}) {
12
105
  const optsJson = JSON.stringify({
13
106
  withinSelector: typeof opts.within_selector === 'string' ? opts.within_selector : null,
@@ -16,23 +109,25 @@ export function buildSnapshotJs(opts = {}) {
16
109
  maxInteractive: typeof opts.max_interactive === 'number' && opts.max_interactive > 0
17
110
  ? Math.min(opts.max_interactive, 500)
18
111
  : 120,
112
+ since: typeof opts.since === 'string' ? opts.since : null,
19
113
  });
20
114
  return `
21
115
  (() => {
22
116
  ${DEEP_QUERY_JS}
23
117
  ${DOM_HELPERS_JS}
118
+ ${PAGE_OBSERVER_JS}
24
119
  const opts = ${optsJson};
25
120
  let root = document;
26
121
  let notice = '';
27
122
  if (opts.withinSelector) {
28
123
  const sub = deepQueryFirst(opts.withinSelector);
29
124
  if (!sub) {
30
- return {
125
+ return withDocId({
31
126
  title: document.title,
32
127
  url: location.href,
33
128
  interactive: [],
34
129
  notice: 'within_selector did not match any element',
35
- };
130
+ });
36
131
  }
37
132
  root = sub;
38
133
  }
@@ -75,6 +170,8 @@ export function buildSnapshotJs(opts = {}) {
75
170
  const role = el.getAttribute('role') || tag;
76
171
  const selInfo = genSelectorInfo(el);
77
172
  const entry = { tag, role, selector: selInfo.selector };
173
+ const ref = refOf(el);
174
+ if (ref) entry.ref = ref;
78
175
  if (selInfo.ambiguous) entry.ambiguous = true;
79
176
  const txt = shortText(el);
80
177
  if (txt) entry.text = txt;
@@ -94,29 +191,118 @@ export function buildSnapshotJs(opts = {}) {
94
191
  if (frame) entry.frame = frame;
95
192
  interactive.push(entry);
96
193
  });
97
- const result = {
98
- title: document.title,
99
- url: location.href,
100
- interactive: interactive.slice(0, opts.maxInteractive),
101
- };
194
+ let headings = null;
195
+ let visibleText = '';
102
196
  if (!opts.onlyInteractive) {
103
- const headings = [];
197
+ const found = [];
104
198
  deepQueryAll('h1, h2, h3', root).forEach((h) => {
105
199
  if (!isVisible(h)) return;
106
200
  if (inExcludedLandmark(h)) return;
107
201
  const t = shortText(h);
108
- if (t) headings.push({ level: h.tagName, text: t });
202
+ if (t) found.push({ level: h.tagName, text: t });
109
203
  });
110
- result.headings = headings.slice(0, 30);
204
+ headings = found.slice(0, 30);
111
205
  const textRoot = (root === document) ? (document.body || document) : root;
112
- const visibleText = (textRoot && textRoot.innerText) ? textRoot.innerText.slice(0, 4000) : '';
206
+ visibleText = (textRoot && textRoot.innerText) ? textRoot.innerText.slice(0, 4000) : '';
207
+ }
208
+ let snapshotId = null;
209
+ if (withDocId({}).doc_id && typeof pageObserver.nextSnapshotId === 'function') {
210
+ const issued = pageObserver.nextSnapshotId();
211
+ if (typeof issued === 'string') snapshotId = issued;
212
+ }
213
+ function fullResult() {
214
+ const result = {
215
+ title: document.title,
216
+ url: location.href,
217
+ interactive: interactive.slice(0, opts.maxInteractive),
218
+ };
219
+ if (headings) result.headings = headings;
113
220
  if (visibleText) result.text = visibleText;
221
+ if (notice) result.notice = notice;
222
+ withDocId(result);
223
+ if (snapshotId) result.snapshot_id = snapshotId;
224
+ return result;
114
225
  }
115
- if (notice) result.notice = notice;
116
- return result;
226
+ // Record every snapshot (with or without since) so a later call can diff
227
+ // against it. Entries are keyed by ref; the hash is the entry serialised
228
+ // without its ref, in emission order. Capped at the first 500 entries.
229
+ const store = snapshotId ? snapshotStore() : null;
230
+ // A snapshot_id is \`<doc_id>:s<N>\`: a since whose prefix (before the LAST
231
+ // ':') is not this document's doc_id, or that has no ':', came from another
232
+ // document and is never looked up.
233
+ const sinceCut = opts.since === null ? -1 : opts.since.lastIndexOf(':');
234
+ const sinceSameDoc =
235
+ sinceCut >= 0 && withDocId({}).doc_id === opts.since.slice(0, sinceCut);
236
+ const previous = store && sinceSameDoc ? store.getSnapshot(opts.since) : null;
237
+ const current = new Map();
238
+ const headingsHash = headings ? JSON.stringify(headings) : null;
239
+ const textHash = opts.onlyInteractive ? null : visibleText;
240
+ if (store) {
241
+ for (const entry of interactive) {
242
+ if (current.size >= 500) break;
243
+ if (typeof entry.ref !== 'string') continue;
244
+ const copy = {};
245
+ for (const key of Object.keys(entry)) if (key !== 'ref') copy[key] = entry[key];
246
+ current.set(entry.ref, { hash: JSON.stringify(copy), entry });
247
+ }
248
+ store.recordSnapshot(snapshotId, { entries: current, headings_hash: headingsHash, text_hash: textHash });
249
+ }
250
+ if (opts.since === null) return fullResult();
251
+ if (!store) {
252
+ const result = fullResult();
253
+ result.since = opts.since;
254
+ result.since_status = 'observer-unavailable';
255
+ return result;
256
+ }
257
+ if (!previous || !previous.entries || typeof previous.entries.get !== 'function') {
258
+ const result = fullResult();
259
+ result.since = opts.since;
260
+ result.since_status = sinceSameDoc ? 'evicted' : 'doc-changed';
261
+ return result;
262
+ }
263
+ const added = [];
264
+ const changed = [];
265
+ const removed = [];
266
+ current.forEach((item, ref) => {
267
+ const old = previous.entries.get(ref);
268
+ if (!old) added.push(item.entry);
269
+ else if (old.hash !== item.hash) changed.push(item.entry);
270
+ });
271
+ previous.entries.forEach((item, ref) => {
272
+ if (current.has(ref) || removed.length >= 500) return;
273
+ const gone = { ref, tag: item.entry.tag };
274
+ if (item.entry.text) gone.text = item.entry.text;
275
+ removed.push(gone);
276
+ });
277
+ // max_interactive applies after diffing (added first, then changed), so
278
+ // a window shift never masquerades as change.
279
+ const listed = added.concat(changed);
280
+ const kept = listed.slice(0, opts.maxInteractive);
281
+ const diff = withDocId({ title: document.title, url: location.href });
282
+ diff.snapshot_id = snapshotId;
283
+ diff.since = opts.since;
284
+ diff.added = kept.slice(0, Math.min(added.length, kept.length));
285
+ diff.removed = removed;
286
+ diff.changed = kept.slice(diff.added.length);
287
+ if (listed.length > kept.length) diff.overflow = listed.length - kept.length;
288
+ if (!opts.onlyInteractive) {
289
+ if (headingsHash !== previous.headings_hash) diff.headings = headings;
290
+ if (textHash !== previous.text_hash) diff.text = visibleText;
291
+ }
292
+ return diff;
117
293
  })()
118
294
  `;
119
295
  }
296
+ /** Only the documented key fields reach the built source, as JSON data. */
297
+ function findKeyJson(key) {
298
+ return Array.isArray(key.path)
299
+ ? {
300
+ role: key.role,
301
+ name: key.name,
302
+ path: key.path.map((step) => ({ tag: step.tag, index: step.index })),
303
+ }
304
+ : { role: key.role, name: key.name };
305
+ }
120
306
  export function buildFindJs(opts) {
121
307
  const optsJson = JSON.stringify({
122
308
  text: opts.text,
@@ -124,12 +310,98 @@ export function buildFindJs(opts) {
124
310
  exact: opts.exact === true,
125
311
  candidateLimit: 5,
126
312
  nearMissLimit: 3,
313
+ ...(typeof opts.ref === 'string' && opts.ref.length > 0 ? { ref: opts.ref } : {}),
314
+ ...(opts.key ? { key: findKeyJson(opts.key) } : {}),
127
315
  });
128
316
  return `
129
317
  (() => {
130
318
  ${DEEP_QUERY_JS}
131
319
  ${DOM_HELPERS_JS}
320
+ ${PAGE_OBSERVER_JS}
321
+ ${typeof opts.ref === 'string' && opts.ref.length > 0 ? RESOLVE_TARGET_JS : ''}
132
322
  const opts = ${optsJson};
323
+ function semanticKeyOf(el) {
324
+ if (!pageObserver || typeof pageObserver.semanticKeyFor !== 'function') return null;
325
+ try {
326
+ const key = pageObserver.semanticKeyFor(el);
327
+ return key && typeof key === 'object' ? key : null;
328
+ } catch (e) {
329
+ return null;
330
+ }
331
+ }
332
+ function singleMatch(el, ref, reresolved) {
333
+ const center = viewportCenterOf(el);
334
+ const selInfo = genSelectorInfo(el);
335
+ const result = { matched: true, selector: selInfo.selector };
336
+ if (ref) result.ref = ref;
337
+ result.coords = {
338
+ x: Math.round(center.x),
339
+ y: Math.round(center.y),
340
+ };
341
+ result.tag = el.tagName.toLowerCase();
342
+ result.text = shortText(el);
343
+ if (selInfo.ambiguous) result.ambiguous = true;
344
+ const frame = frameSelectorFor(el);
345
+ if (frame) result.frame = frame;
346
+ if (reresolved) result.reresolved = true;
347
+ const key = semanticKeyOf(el);
348
+ if (key) result.semantic_key = key;
349
+ return withDocId(result);
350
+ }
351
+ if (typeof opts.ref === 'string') {
352
+ const target = resolveTarget(opts);
353
+ if (!target.ok) {
354
+ const failure = { matched: false, reason: target.reason, ref: opts.ref };
355
+ return withDocId(failure);
356
+ }
357
+ return singleMatch(target.el, opts.ref, target.reresolved);
358
+ }
359
+ if (opts.key) {
360
+ if (!pageObserver || typeof pageObserver.semanticKeyFor !== 'function') {
361
+ return { matched: false, reason: 'observer-unavailable' };
362
+ }
363
+ const wanted = opts.key;
364
+ const candidates = [];
365
+ for (const el of deepQueryAll('*')) {
366
+ const key = semanticKeyOf(el);
367
+ if (key && key.role === wanted.role && key.name === wanted.name) {
368
+ candidates.push({ el: el, path: Array.isArray(key.path) ? key.path : [] });
369
+ }
370
+ }
371
+ const count = candidates.length;
372
+ const shared = 'key: ' + count + ' candidates share role and name; ';
373
+ let picked = null;
374
+ let error = count > 1 ? shared + 'pass path to disambiguate' : null;
375
+ if (!Array.isArray(wanted.path)) {
376
+ if (count === 1) picked = candidates[0].el;
377
+ } else {
378
+ // Same rule as the observer's re-resolution: identical tag path and
379
+ // exactly one such candidate; identical rows are refused, never guessed.
380
+ let sameTags = 0;
381
+ let only = null;
382
+ for (const c of candidates) {
383
+ if (c.path.length !== wanted.path.length) continue;
384
+ let same = true;
385
+ for (let i = 0; i < c.path.length && same; i++) {
386
+ if (c.path[i].tag !== wanted.path[i].tag) same = false;
387
+ }
388
+ if (!same) continue;
389
+ sameTags++;
390
+ only = c.el;
391
+ }
392
+ if (sameTags === 1) {
393
+ picked = only;
394
+ } else if (sameTags > 1) {
395
+ error = 'key: ' + sameTags + ' candidates share role, name and tag path';
396
+ } else if (count > 0) {
397
+ error = shared + 'none has the same tag path';
398
+ }
399
+ }
400
+ if (picked) return singleMatch(picked, refOf(picked), false);
401
+ const failure = { matched: false, reason: 'not-found' };
402
+ if (error) failure.error = error;
403
+ return withDocId(failure);
404
+ }
133
405
  const needle = opts.text.toLowerCase();
134
406
  const needleTokens = needle.split(/[^a-z0-9]+/).filter(Boolean);
135
407
  const ROLE_SELECTORS = {
@@ -189,6 +461,8 @@ export function buildFindJs(opts) {
189
461
  }
190
462
  function toNearMiss(el) {
191
463
  const entry = { text: snippetOf(el), selector: genSelector(el) };
464
+ const ref = refOf(el);
465
+ if (ref) entry.ref = ref;
192
466
  const roleAttr = el.getAttribute('role');
193
467
  if (roleAttr) entry.role = roleAttr;
194
468
  return entry;
@@ -221,60 +495,46 @@ export function buildFindJs(opts) {
221
495
  ' but none with role "' + opts.role + '"' +
222
496
  (closest ? ' — closest: ' + describeForError(closest) + ' "' + snippetOf(closest) + '"' : '');
223
497
  result.near_misses = ranked.map(toNearMiss);
224
- return result;
498
+ return withDocId(result);
225
499
  }
226
500
  const ranked = rankCandidates(broadAll);
227
501
  if (ranked.length > 0) result.near_misses = ranked.map(toNearMiss);
228
- return result;
502
+ return withDocId(result);
229
503
  }
230
504
  const ranked = rankCandidates(all);
231
505
  if (ranked.length > 0) result.near_misses = ranked.map(toNearMiss);
232
- return result;
506
+ return withDocId(result);
233
507
  }
234
508
  if (matches.length > 1) {
235
- return {
509
+ return withDocId({
236
510
  matched: false,
237
511
  reason: 'multiple-matches',
238
- candidates: matches.slice(0, opts.candidateLimit).map((el) => ({
239
- selector: genSelector(el),
240
- text: shortText(el),
241
- tag: el.tagName.toLowerCase(),
242
- })),
243
- };
512
+ candidates: matches.slice(0, opts.candidateLimit).map((el) => {
513
+ const candidate = { selector: genSelector(el) };
514
+ const ref = refOf(el);
515
+ if (ref) candidate.ref = ref;
516
+ candidate.text = shortText(el);
517
+ candidate.tag = el.tagName.toLowerCase();
518
+ return candidate;
519
+ }),
520
+ });
244
521
  }
245
522
  const el = matches[0];
246
- const center = viewportCenterOf(el);
247
- const selInfo = genSelectorInfo(el);
248
- const result = {
249
- matched: true,
250
- selector: selInfo.selector,
251
- coords: {
252
- x: Math.round(center.x),
253
- y: Math.round(center.y),
254
- },
255
- tag: el.tagName.toLowerCase(),
256
- text: shortText(el),
257
- };
258
- if (selInfo.ambiguous) result.ambiguous = true;
259
- const frame = frameSelectorFor(el);
260
- if (frame) result.frame = frame;
261
- return result;
523
+ return singleMatch(el, refOf(el), false);
262
524
  })()
263
525
  `;
264
526
  }
265
527
  export function buildClickResolveJs(opts) {
266
- const optsJson = JSON.stringify({ selector: opts.selector, force: opts.force });
528
+ const optsJson = JSON.stringify({ ...targetJson(opts), force: opts.force });
267
529
  return `
268
530
  (() => {
269
531
  ${DEEP_QUERY_JS}
532
+ ${PAGE_OBSERVER_JS}
533
+ ${RESOLVE_TARGET_JS}
270
534
  const opts = ${optsJson};
271
- try {
272
- document.querySelector(opts.selector);
273
- } catch (e) {
274
- return { ok: false, reason: 'invalid-selector', error: e && e.message ? e.message : String(e) };
275
- }
276
- const el = deepQueryFirst(opts.selector);
277
- if (!el) return { ok: false, reason: 'not-found' };
535
+ const target = resolveTarget(opts);
536
+ if (!target.ok) return target;
537
+ const el = target.el;
278
538
  const chain = frameElementChain(el);
279
539
  for (const fe of chain) {
280
540
  if (fe.scrollIntoView) fe.scrollIntoView({ block: 'center', inline: 'center' });
@@ -289,41 +549,59 @@ export function buildClickResolveJs(opts) {
289
549
  const result = { ok: true, x: center.x, y: center.y, tag };
290
550
  const hit = occlusion.allowed ? occlusion.hit : occlusion.blocker;
291
551
  if (hit) result.hit_element = hit;
552
+ if (target.reresolved) result.reresolved = true;
292
553
  return result;
293
554
  })()
294
555
  `;
295
556
  }
296
557
  export function buildTypeResolveJs(opts) {
297
- const optsJson = JSON.stringify({ selector: opts.selector });
558
+ const optsJson = JSON.stringify(targetJson(opts));
298
559
  return `
299
560
  (() => {
300
561
  ${DEEP_QUERY_JS}
562
+ ${PAGE_OBSERVER_JS}
563
+ ${RESOLVE_TARGET_JS}
301
564
  const opts = ${optsJson};
302
- try {
303
- document.querySelector(opts.selector);
304
- } catch (e) {
305
- return { ok: false, reason: 'invalid-selector', error: e && e.message ? e.message : String(e) };
306
- }
307
- const el = deepQueryFirst(opts.selector);
308
- if (!el) return { ok: false, reason: 'not-found' };
565
+ const target = resolveTarget(opts);
566
+ if (!target.ok) return target;
567
+ const el = target.el;
309
568
  el.focus();
310
569
  ${opts.clear ? "if ('value' in el) { el.value = ''; el.dispatchEvent(new Event('input', { bubbles: true })); }" : ''}
311
- return { ok: true };
570
+ return target.reresolved ? { ok: true, reresolved: true } : { ok: true };
312
571
  })()`;
313
572
  }
314
573
  export function buildFocusJs(opts) {
315
- const optsJson = JSON.stringify({ selector: opts.selector });
574
+ const optsJson = JSON.stringify(targetJson(opts));
316
575
  return `
317
576
  (() => {
318
577
  ${DEEP_QUERY_JS}
578
+ ${PAGE_OBSERVER_JS}
579
+ ${RESOLVE_TARGET_JS}
319
580
  const opts = ${optsJson};
320
- const el = deepQueryFirst(opts.selector);
321
- if (!el) return false;
322
- el.focus();
323
- return true;
581
+ const target = resolveTarget(opts);
582
+ const byRef = typeof opts.ref === 'string';
583
+ if (!target.ok) return byRef ? target : false;
584
+ target.el.focus();
585
+ if (!byRef) return true;
586
+ return target.reresolved ? { ok: true, reresolved: true } : { ok: true };
324
587
  })()`;
325
588
  }
326
- export function buildWaitForSelectorJs(selector, condition) {
589
+ export function buildWaitForSelectorJs(target, condition) {
590
+ if (typeof target !== 'string') {
591
+ const refOptsJson = JSON.stringify({ ref: target.ref, condition });
592
+ return `
593
+ (() => {
594
+ ${DEEP_QUERY_JS}
595
+ ${PAGE_OBSERVER_JS}
596
+ ${RESOLVE_TARGET_JS}
597
+ const opts = ${refOptsJson};
598
+ const target = resolveTarget(opts);
599
+ if (!target.ok && target.reason === 'observer-unavailable') return target;
600
+ const el = target.ok ? target.el : null;
601
+ ${WAIT_FOR_CONDITION_JS}
602
+ })()`;
603
+ }
604
+ const selector = target;
327
605
  const optsJson = JSON.stringify({ selector, condition });
328
606
  return `
329
607
  (() => {
@@ -331,7 +609,12 @@ export function buildWaitForSelectorJs(selector, condition) {
331
609
  const opts = ${optsJson};
332
610
  document.querySelector(opts.selector);
333
611
  const el = deepQueryFirst(opts.selector);
334
- if (opts.condition === 'attached') return Boolean(el);
612
+ ${WAIT_FOR_CONDITION_JS}
613
+ })()`;
614
+ }
615
+ /** The condition check shared by both `wait_for` probe targets; `el` is
616
+ * the resolved element or `null`. */
617
+ const WAIT_FOR_CONDITION_JS = `if (opts.condition === 'attached') return Boolean(el);
335
618
  if (opts.condition === 'detached') return !el;
336
619
  const wantHidden = opts.condition === 'hidden';
337
620
  if (!el) return wantHidden;
@@ -340,22 +623,18 @@ export function buildWaitForSelectorJs(selector, condition) {
340
623
  if (s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0') return wantHidden;
341
624
  const r = el.getBoundingClientRect();
342
625
  const shown = r.width > 0 && r.height > 0;
343
- return wantHidden ? !shown : shown;
344
- })()`;
345
- }
626
+ return wantHidden ? !shown : shown;`;
346
627
  export function buildElementRectJs(opts) {
347
- const optsJson = JSON.stringify({ selector: opts.selector });
628
+ const optsJson = JSON.stringify(targetJson(opts));
348
629
  return `
349
630
  (() => {
350
631
  ${DEEP_QUERY_JS}
632
+ ${PAGE_OBSERVER_JS}
633
+ ${RESOLVE_TARGET_JS}
351
634
  const opts = ${optsJson};
352
- try {
353
- document.querySelector(opts.selector);
354
- } catch (e) {
355
- return { ok: false, reason: 'invalid-selector', error: e && e.message ? e.message : String(e) };
356
- }
357
- const el = deepQueryFirst(opts.selector);
358
- if (!el) return { ok: false, reason: 'not-found' };
635
+ const target = resolveTarget(opts);
636
+ if (!target.ok) return target;
637
+ const el = target.el;
359
638
  const chain = frameElementChain(el);
360
639
  // behavior 'instant' overrides CSS scroll-behavior: smooth, which would
361
640
  // leave the rect below stale while the scroll is still animating.
@@ -380,13 +659,15 @@ export function buildElementRectJs(opts) {
380
659
  scrollX = top.scrollX || 0;
381
660
  scrollY = top.scrollY || 0;
382
661
  } catch (_) {}
383
- return {
662
+ const result = {
384
663
  ok: true,
385
664
  x: offsetX + rect.left + scrollX,
386
665
  y: offsetY + rect.top + scrollY,
387
666
  width: rect.width,
388
667
  height: rect.height,
389
668
  };
669
+ if (target.reresolved) result.reresolved = true;
670
+ return result;
390
671
  })()`;
391
672
  }
392
673
  export function buildDragProbeJs(opts) {
@@ -623,12 +904,16 @@ export function buildExpectProbeJs(opts) {
623
904
  * `focused` beyond `<body>`, no `dialogs` when none are open, and no
624
905
  * `scroll` when the page is at its default (0,0) position — token-lean by
625
906
  * construction, matching the omit-falsy convention the other builders use.
907
+ *
908
+ * With the page observer installed (see `PAGE_OBSERVER_JS`), `focused`
909
+ * carries `ref` right after `selector` and the result carries `doc_id`.
626
910
  */
627
911
  export function buildStateJs() {
628
912
  return `
629
913
  (() => {
630
914
  ${DEEP_QUERY_JS}
631
915
  ${DOM_HELPERS_JS}
916
+ ${PAGE_OBSERVER_JS}
632
917
  function deepActiveElement() {
633
918
  let el = document.activeElement;
634
919
  let guard = 0;
@@ -689,7 +974,10 @@ export function buildStateJs() {
689
974
  const active = deepActiveElement();
690
975
  if (active && active !== document.body && active.tagName) {
691
976
  const selInfo = genSelectorInfo(active);
692
- const focused = { selector: selInfo.selector, tag: active.tagName.toLowerCase() };
977
+ const focused = { selector: selInfo.selector };
978
+ const ref = refOf(active);
979
+ if (ref) focused.ref = ref;
980
+ focused.tag = active.tagName.toLowerCase();
693
981
  if (selInfo.ambiguous) focused.ambiguous = true;
694
982
  result.focused = focused;
695
983
  }
@@ -709,7 +997,7 @@ export function buildStateJs() {
709
997
  const scrollY = Math.round(window.scrollY);
710
998
  if (scrollX !== 0 || scrollY !== 0) result.scroll = { x: scrollX, y: scrollY };
711
999
 
712
- return result;
1000
+ return withDocId(result);
713
1001
  })()
714
1002
  `;
715
1003
  }
@@ -1 +1 @@
1
- {"version":3,"file":"builders.js","sourceRoot":"","sources":["../../src/inpage/builders.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"builders.js","sourceRoot":"","sources":["../../src/inpage/builders.ts"],"names":[],"mappings":"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"}