@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
@@ -11,7 +11,7 @@
11
11
  * `cdp/builders-parity.test.ts` checks the built output.
12
12
  */
13
13
  /** Bump whenever the in-page protocol (global shape, messages, methods) changes. */
14
- export declare const OBSERVER_VERSION = 1;
14
+ export declare const OBSERVER_VERSION = 3;
15
15
  /** Name of the `Runtime.addBinding` function the observer pushes messages through. */
16
16
  export declare const OBSERVER_BINDING = "__blPageObserverPush";
17
17
  /** Well-known global that holds the installed observer instance. */
@@ -31,6 +31,39 @@ export interface ObserverInstallOpts {
31
31
  * `Page.addScriptToEvaluateOnNewDocument` source and as a one-off
32
32
  * `Runtime.evaluate` expression, which evaluates to
33
33
  * `{ ok: true, installed, version, doc_id, coverage }`.
34
+ *
35
+ * The instance also owns element identity (spec v4 §5.6): `refFor(el)` issues
36
+ * `<doc_tag>:e<N>` (`doc_tag` = the first 6 characters of `doc_id`, N
37
+ * monotonic per document instance, from 1) the first time an element is seen
38
+ * and reuses it while the node lives; `resolveRef(ref)` returns the element
39
+ * while it is connected, else `null`. Refs are only valid for the document
40
+ * instance that issued them: a ref whose tag is not this instance's tag, or a
41
+ * bare `e<N>` with no tag, is `null` everywhere (resolve, re-resolve, key)
42
+ * without consulting the registries. Neither method throws.
43
+ *
44
+ * Secondary identity (spec v4 §5.6, decided by lab 10): `semanticKeyFor(el)`
45
+ * returns `{ role, name, path }` — role from the `role` attribute or a small
46
+ * implicit table, accessible-ish name (aria-label, aria-labelledby, associated
47
+ * label, text ≤ 80 chars, placeholder, title, button-like input value) and up
48
+ * to 8 `{ tag, index }` ancestor steps (1-based same-tag sibling index, a
49
+ * shadow boundary as `{ tag: '#shadow', index: 0 }`). `refFor` stores the key
50
+ * when it issues a ref. `resolveRefDetailed(ref)` returns `{ el, reresolved }`:
51
+ * the live node with `reresolved: false`, else the element with the same role,
52
+ * name and tag-only path when exactly one exists, rebinding the ref to it
53
+ * (`reresolved: true`); zero or several candidates give `null` (sibling
54
+ * indices are kept in the key as data but never pick among candidates). Candidates come from the document, every open shadow root reachable
55
+ * from it, and every root the `attachShadow` patch observed (closed ones
56
+ * included); closed roots attached before install are not reachable.
57
+ * `resolveRef(ref)` is `resolveRefDetailed(ref)?.el ?? null`. `keyForRef(ref)`
58
+ * returns a copy of the stored key or `null`. None of these throws.
59
+ * `nextSnapshotId()`
60
+ * issues `<doc_id>:s<N>` (N monotonic per document instance, from 1) for each
61
+ * `snapshot` result and returns `null` once the instance is torn down; the
62
+ * `doc_id` prefix lets a stale id from another document be rejected.
63
+ * `recordSnapshot(id, record)` keeps the last 4 snapshot records per document
64
+ * instance (oldest evicted first) for `snapshot({ since })`; `getSnapshot(id)`
65
+ * returns the record or `null` when unknown or evicted. The record is opaque
66
+ * here. Both are inert after teardown, which clears the store.
34
67
  */
35
68
  export declare function buildObserverInstallJs(opts?: ObserverInstallOpts): string;
36
69
  /**
@@ -49,6 +82,22 @@ export declare function buildObserverMarkJs(): string;
49
82
  * baseline; or `{ ok: false, reason: 'observer-unavailable' | 'doc-changed' }`.
50
83
  */
51
84
  export declare function buildObserverChangesJs(mark: number, docId?: string): string;
85
+ /**
86
+ * Build the ref-resolve expression, for tests and debugging. Evaluates to
87
+ * `{ ok: true, found: true, tag }` when `ref` names an element of the current
88
+ * document that is still connected — plus `reresolved: true` when the node was
89
+ * gone and the ref was just rebound by its semantic key —
90
+ * `{ ok: true, found: false }` when it is unknown or stale, or
91
+ * `{ ok: false, reason: 'observer-unavailable' }`.
92
+ */
93
+ export declare function buildObserverRefResolveJs(ref: string): string;
94
+ /**
95
+ * Build the semantic-key read expression. Evaluates to `{ ok: true, key }`
96
+ * with the `{ role, name, path }` stored when `ref` was issued, `{ ok: true,
97
+ * key: null }` for a ref this document instance does not know, or
98
+ * `{ ok: false, reason: 'observer-unavailable' }`.
99
+ */
100
+ export declare function buildObserverSemanticKeyJs(ref: string): string;
52
101
  /**
53
102
  * Build the teardown expression: disconnects every observer, restores the
54
103
  * `attachShadow` and `history` patches when they are still the observer's,
@@ -11,7 +11,7 @@
11
11
  * `cdp/builders-parity.test.ts` checks the built output.
12
12
  */
13
13
  /** Bump whenever the in-page protocol (global shape, messages, methods) changes. */
14
- export const OBSERVER_VERSION = 1;
14
+ export const OBSERVER_VERSION = 3;
15
15
  /** Name of the `Runtime.addBinding` function the observer pushes messages through. */
16
16
  export const OBSERVER_BINDING = '__blPageObserverPush';
17
17
  /** Well-known global that holds the installed observer instance. */
@@ -30,6 +30,39 @@ function clampInt(value, fallback, min, max) {
30
30
  * `Page.addScriptToEvaluateOnNewDocument` source and as a one-off
31
31
  * `Runtime.evaluate` expression, which evaluates to
32
32
  * `{ ok: true, installed, version, doc_id, coverage }`.
33
+ *
34
+ * The instance also owns element identity (spec v4 §5.6): `refFor(el)` issues
35
+ * `<doc_tag>:e<N>` (`doc_tag` = the first 6 characters of `doc_id`, N
36
+ * monotonic per document instance, from 1) the first time an element is seen
37
+ * and reuses it while the node lives; `resolveRef(ref)` returns the element
38
+ * while it is connected, else `null`. Refs are only valid for the document
39
+ * instance that issued them: a ref whose tag is not this instance's tag, or a
40
+ * bare `e<N>` with no tag, is `null` everywhere (resolve, re-resolve, key)
41
+ * without consulting the registries. Neither method throws.
42
+ *
43
+ * Secondary identity (spec v4 §5.6, decided by lab 10): `semanticKeyFor(el)`
44
+ * returns `{ role, name, path }` — role from the `role` attribute or a small
45
+ * implicit table, accessible-ish name (aria-label, aria-labelledby, associated
46
+ * label, text ≤ 80 chars, placeholder, title, button-like input value) and up
47
+ * to 8 `{ tag, index }` ancestor steps (1-based same-tag sibling index, a
48
+ * shadow boundary as `{ tag: '#shadow', index: 0 }`). `refFor` stores the key
49
+ * when it issues a ref. `resolveRefDetailed(ref)` returns `{ el, reresolved }`:
50
+ * the live node with `reresolved: false`, else the element with the same role,
51
+ * name and tag-only path when exactly one exists, rebinding the ref to it
52
+ * (`reresolved: true`); zero or several candidates give `null` (sibling
53
+ * indices are kept in the key as data but never pick among candidates). Candidates come from the document, every open shadow root reachable
54
+ * from it, and every root the `attachShadow` patch observed (closed ones
55
+ * included); closed roots attached before install are not reachable.
56
+ * `resolveRef(ref)` is `resolveRefDetailed(ref)?.el ?? null`. `keyForRef(ref)`
57
+ * returns a copy of the stored key or `null`. None of these throws.
58
+ * `nextSnapshotId()`
59
+ * issues `<doc_id>:s<N>` (N monotonic per document instance, from 1) for each
60
+ * `snapshot` result and returns `null` once the instance is torn down; the
61
+ * `doc_id` prefix lets a stale id from another document be rejected.
62
+ * `recordSnapshot(id, record)` keeps the last 4 snapshot records per document
63
+ * instance (oldest evicted first) for `snapshot({ since })`; `getSnapshot(id)`
64
+ * returns the record or `null` when unknown or evicted. The record is opaque
65
+ * here. Both are inert after teardown, which clears the store.
33
66
  */
34
67
  export function buildObserverInstallJs(opts = {}) {
35
68
  const optsJson = JSON.stringify({
@@ -71,6 +104,25 @@ export function buildObserverInstallJs(opts = {}) {
71
104
  };
72
105
  const observers = [];
73
106
  const observed = new WeakSet();
107
+ let refs = new WeakMap();
108
+ const refNodes = new Map();
109
+ // Semantic key captured when each ref is issued; kept while the ref lives so
110
+ // a replaced node can be found again (spec v4 §5.6 secondary identity).
111
+ const refKeys = new Map();
112
+ let refSeq = 0;
113
+ // Every ref carries the issuing document's tag, so a ref from another
114
+ // document instance (or a bare e<N>) never reaches the registries.
115
+ const refPrefix = g.doc_id.slice(0, 6) + ':e';
116
+ const ownsRef = (ref) => typeof ref === 'string' && ref.startsWith(refPrefix);
117
+ let snapshotSeq = 0;
118
+ // Last SNAPSHOT_KEEP snapshot records (opaque to the observer; the snapshot
119
+ // builder owns their shape), keyed by snapshot_id in insertion order.
120
+ const SNAPSHOT_KEEP = 4;
121
+ const snapshots = new Map();
122
+ // WeakRef keeps the registry from pinning removed nodes; the fallback only
123
+ // matters on engines without it (Chrome has it since 84).
124
+ const holdWeakly =
125
+ typeof WeakRef === 'function' ? (el) => new WeakRef(el) : (el) => ({ deref: () => el });
74
126
  const round = (n) => Math.round(n * 10) / 10;
75
127
 
76
128
  function push(message) {
@@ -189,7 +241,7 @@ export function buildObserverInstallJs(opts = {}) {
189
241
  try {
190
242
  const mo = new MutationObserver(onRecords(kind));
191
243
  mo.observe(root, { subtree: true, childList: true, attributes: true, characterData: true });
192
- observers.push({ mo: mo, kind: kind });
244
+ observers.push({ mo: mo, kind: kind, root: root });
193
245
  g.roots++;
194
246
  } catch (e) {}
195
247
  }
@@ -257,6 +309,239 @@ export function buildObserverInstallJs(opts = {}) {
257
309
 
258
310
  g.flush = flush;
259
311
 
312
+ const KEY_PATH_STEPS = 8;
313
+ const KEY_TEXT_CAP = 80;
314
+ // Elements an HTML <label> can be associated with.
315
+ const LABELABLE = ['button', 'input', 'meter', 'output', 'progress', 'select', 'textarea'];
316
+ const BUTTON_INPUT_TYPES = ['button', 'submit', 'reset'];
317
+
318
+ function tagOf(el) {
319
+ return el.localName || String(el.nodeName).toLowerCase();
320
+ }
321
+
322
+ function collapse(text) {
323
+ return String(text || '').replace(/\\s+/g, ' ').trim();
324
+ }
325
+
326
+ function inputType(el) {
327
+ return (el.getAttribute('type') || 'text').toLowerCase();
328
+ }
329
+
330
+ function roleOf(el) {
331
+ const explicit = (el.getAttribute('role') || '').trim();
332
+ if (explicit) return explicit;
333
+ const tag = tagOf(el);
334
+ if (tag === 'a' && el.hasAttribute('href')) return 'link';
335
+ if (tag === 'button' || tag === 'summary') return 'button';
336
+ if (tag === 'input') {
337
+ const type = inputType(el);
338
+ if (type === 'checkbox' || type === 'radio') return type;
339
+ if (BUTTON_INPUT_TYPES.indexOf(type) >= 0) return 'button';
340
+ return 'textbox';
341
+ }
342
+ if (tag === 'textarea') return 'textbox';
343
+ if (tag === 'select') return 'combobox';
344
+ if (el.hasAttribute('contenteditable') && el.getAttribute('contenteditable') !== 'false') return 'textbox';
345
+ return tag;
346
+ }
347
+
348
+ function labelTextOf(el, root) {
349
+ if (LABELABLE.indexOf(tagOf(el)) < 0) return '';
350
+ const id = el.getAttribute('id');
351
+ if (id && root && typeof root.querySelectorAll === 'function') {
352
+ for (const label of root.querySelectorAll('label')) {
353
+ if (label.getAttribute('for') !== id) continue;
354
+ const text = collapse(label.textContent);
355
+ if (text) return text;
356
+ }
357
+ }
358
+ const wrapping = typeof el.closest === 'function' ? el.closest('label') : null;
359
+ return wrapping ? collapse(wrapping.textContent) : '';
360
+ }
361
+
362
+ function nameOf(el) {
363
+ const ariaLabel = collapse(el.getAttribute('aria-label'));
364
+ if (ariaLabel) return ariaLabel;
365
+ const root = typeof el.getRootNode === 'function' ? el.getRootNode() : document;
366
+ const labelledBy = collapse(el.getAttribute('aria-labelledby'));
367
+ if (labelledBy && root && typeof root.getElementById === 'function') {
368
+ const parts = [];
369
+ for (const id of labelledBy.split(' ')) {
370
+ const target = root.getElementById(id);
371
+ const text = target ? collapse(target.textContent) : '';
372
+ if (text) parts.push(text);
373
+ }
374
+ if (parts.length > 0) return parts.join(' ');
375
+ }
376
+ const label = labelTextOf(el, root);
377
+ if (label) return label;
378
+ const text = collapse(el.textContent).slice(0, KEY_TEXT_CAP);
379
+ if (text) return text;
380
+ const placeholder = collapse(el.getAttribute('placeholder'));
381
+ if (placeholder) return placeholder;
382
+ const title = collapse(el.getAttribute('title'));
383
+ if (title) return title;
384
+ if (tagOf(el) === 'input' && BUTTON_INPUT_TYPES.indexOf(inputType(el)) >= 0) return collapse(el.value);
385
+ return '';
386
+ }
387
+
388
+ function sameTagIndex(el) {
389
+ const tag = el.localName;
390
+ let index = 1;
391
+ for (let s = el.previousElementSibling; s; s = s.previousElementSibling) {
392
+ if (s.localName === tag) index++;
393
+ }
394
+ return index;
395
+ }
396
+
397
+ // Unlike pathOf (descriptors, pinned settle output), this path carries the
398
+ // same-tag sibling index: role + name alone collides (spec v4 §4.6).
399
+ function keyPathOf(el) {
400
+ const steps = [];
401
+ let n = el;
402
+ while (n && steps.length < KEY_PATH_STEPS) {
403
+ if (n.nodeType === 1) {
404
+ if (n === document.documentElement) break;
405
+ steps.unshift({ tag: tagOf(n), index: sameTagIndex(n) });
406
+ n = n.parentNode;
407
+ } else if (n.nodeType === 11 && n.host) {
408
+ steps.unshift({ tag: '#shadow', index: 0 });
409
+ n = n.host;
410
+ } else {
411
+ break;
412
+ }
413
+ }
414
+ return steps;
415
+ }
416
+
417
+ function semanticKeyFor(el) {
418
+ try {
419
+ if (!el || el.nodeType !== 1) return null;
420
+ return { role: roleOf(el), name: nameOf(el), path: keyPathOf(el) };
421
+ } catch (e) {
422
+ return null;
423
+ }
424
+ }
425
+
426
+ // The document, every open shadow root reachable from it, and every root the
427
+ // attachShadow patch observed (closed ones included) whose host is connected.
428
+ function searchRoots() {
429
+ const roots = [document];
430
+ const seen = new Set(roots);
431
+ const add = (root) => {
432
+ if (!root || seen.has(root)) return;
433
+ if (root.nodeType === 11 && !(root.host && root.host.isConnected)) return;
434
+ seen.add(root);
435
+ roots.push(root);
436
+ };
437
+ for (const o of observers) add(o.root);
438
+ for (let i = 0; i < roots.length; i++) {
439
+ let all;
440
+ try { all = roots[i].querySelectorAll('*'); } catch (e) { continue; }
441
+ for (const el of all) {
442
+ if (el.shadowRoot) add(el.shadowRoot);
443
+ }
444
+ }
445
+ return roots;
446
+ }
447
+
448
+ // Same role and name and an identical tag-only path, and exactly one such
449
+ // element: identical rows are refused, never guessed, so a ref never jumps
450
+ // across rows. Sibling indices stay in the key but select nothing.
451
+ function findByKey(key) {
452
+ const last = key.path[key.path.length - 1];
453
+ if (!last) return null;
454
+ let found = null;
455
+ for (const root of searchRoots()) {
456
+ let all;
457
+ try { all = root.querySelectorAll('*'); } catch (e) { continue; }
458
+ for (const el of all) {
459
+ if (tagOf(el) !== last.tag || roleOf(el) !== key.role || nameOf(el) !== key.name) continue;
460
+ const path = keyPathOf(el);
461
+ if (path.length !== key.path.length) continue;
462
+ let same = true;
463
+ for (let i = 0; i < path.length && same; i++) {
464
+ if (path[i].tag !== key.path[i].tag) same = false;
465
+ }
466
+ if (!same) continue;
467
+ if (found) return null;
468
+ found = el;
469
+ }
470
+ }
471
+ return found;
472
+ }
473
+
474
+ g.semanticKeyFor = semanticKeyFor;
475
+
476
+ g.refFor = function (el) {
477
+ try {
478
+ if (g.dead || !el || el.nodeType !== 1) return null;
479
+ let ref = refs.get(el);
480
+ if (!ref) {
481
+ ref = refPrefix + ++refSeq;
482
+ refs.set(el, ref);
483
+ const key = semanticKeyFor(el);
484
+ if (key) refKeys.set(ref, key);
485
+ }
486
+ // Same node, same ref: re-register one pruned while it was detached.
487
+ if (!refNodes.has(ref)) refNodes.set(ref, holdWeakly(el));
488
+ return ref;
489
+ } catch (e) {
490
+ return null;
491
+ }
492
+ };
493
+
494
+ g.resolveRefDetailed = function (ref) {
495
+ try {
496
+ if (g.dead || !ownsRef(ref)) return null;
497
+ const held = refNodes.get(ref);
498
+ const old = held ? held.deref() : null;
499
+ if (old && old.isConnected) return { el: old, reresolved: false };
500
+ refNodes.delete(ref);
501
+ const key = refKeys.get(ref);
502
+ if (!key) return null;
503
+ const el = findByKey(key);
504
+ if (!el) return null;
505
+ if (old && refs.get(old) === ref) refs.delete(old);
506
+ // A node that already has its own ref keeps it for refFor; this ref
507
+ // still resolves to it through refNodes.
508
+ if (!refs.has(el)) refs.set(el, ref);
509
+ refNodes.set(ref, holdWeakly(el));
510
+ return { el: el, reresolved: true };
511
+ } catch (e) {
512
+ return null;
513
+ }
514
+ };
515
+
516
+ g.resolveRef = function (ref) {
517
+ const result = g.resolveRefDetailed(ref);
518
+ return result ? result.el : null;
519
+ };
520
+
521
+ g.keyForRef = function (ref) {
522
+ if (g.dead || !ownsRef(ref)) return null;
523
+ const key = refKeys.get(ref);
524
+ if (!key) return null;
525
+ return { role: key.role, name: key.name, path: key.path.map((s) => ({ tag: s.tag, index: s.index })) };
526
+ };
527
+
528
+ g.nextSnapshotId = function () {
529
+ if (g.dead) return null;
530
+ return g.doc_id + ':s' + ++snapshotSeq;
531
+ };
532
+ g.recordSnapshot = function (id, record) {
533
+ if (g.dead || typeof id !== 'string') return;
534
+ snapshots.delete(id);
535
+ snapshots.set(id, record);
536
+ while (snapshots.size > SNAPSHOT_KEEP) snapshots.delete(snapshots.keys().next().value);
537
+ };
538
+
539
+ g.getSnapshot = function (id) {
540
+ if (g.dead || typeof id !== 'string') return null;
541
+ const record = snapshots.get(id);
542
+ return record === undefined ? null : record;
543
+ };
544
+
260
545
  g.mark = function () {
261
546
  flush();
262
547
  const mark = g.seq;
@@ -337,6 +622,11 @@ export function buildObserverInstallJs(opts = {}) {
337
622
  window.removeEventListener('popstate', onNav);
338
623
  window.removeEventListener('hashchange', onNav);
339
624
  g.baselines.clear();
625
+ refs = new WeakMap();
626
+ refNodes.clear();
627
+ refKeys.clear();
628
+ snapshotSeq = 0;
629
+ snapshots.clear();
340
630
  if (window[opts.key] === g) {
341
631
  try { delete window[opts.key]; } catch (e) {}
342
632
  }
@@ -379,9 +669,49 @@ export function buildObserverMarkJs() {
379
669
  */
380
670
  export function buildObserverChangesJs(mark, docId) {
381
671
  const markJson = JSON.stringify(clampInt(mark, 0, 0, Number.MAX_SAFE_INTEGER));
382
- const docJson = typeof docId === 'string' && docId.length > 0 ? JSON.stringify(docId) : 'null';
672
+ const docJson = typeof docId === 'string' && docId.length > 0 ? jsStringLiteral(docId) : 'null';
383
673
  return callInstance(`g.changes(${markJson}, ${docJson})`);
384
674
  }
675
+ /**
676
+ * A string literal safe to embed in JS source. `JSON.stringify` alone leaves
677
+ * U+2028 / U+2029 (line terminators in older JS grammars) and `<` (which can
678
+ * close a surrounding `<script>`) unescaped; this escapes them as `\uXXXX`,
679
+ * which parses back to the same string.
680
+ */
681
+ function jsStringLiteral(value) {
682
+ // The two separators are written as char codes so this source file never
683
+ // carries them raw; the replacement is the six-character escape sequence.
684
+ const lineSeparator = String.fromCharCode(0x2028);
685
+ const paragraphSeparator = String.fromCharCode(0x2029);
686
+ return JSON.stringify(value)
687
+ .split(lineSeparator)
688
+ .join('\\u2028')
689
+ .split(paragraphSeparator)
690
+ .join('\\u2029')
691
+ .replace(/</g, '\\u003c');
692
+ }
693
+ /**
694
+ * Build the ref-resolve expression, for tests and debugging. Evaluates to
695
+ * `{ ok: true, found: true, tag }` when `ref` names an element of the current
696
+ * document that is still connected — plus `reresolved: true` when the node was
697
+ * gone and the ref was just rebound by its semantic key —
698
+ * `{ ok: true, found: false }` when it is unknown or stale, or
699
+ * `{ ok: false, reason: 'observer-unavailable' }`.
700
+ */
701
+ export function buildObserverRefResolveJs(ref) {
702
+ const refJson = jsStringLiteral(typeof ref === 'string' ? ref : '');
703
+ return callInstance(`((r) => { if (!r) return { ok: true, found: false }; const tag = r.el.localName || String(r.el.nodeName).toLowerCase(); return r.reresolved ? { ok: true, found: true, tag: tag, reresolved: true } : { ok: true, found: true, tag: tag }; })(g.resolveRefDetailed(${refJson}))`);
704
+ }
705
+ /**
706
+ * Build the semantic-key read expression. Evaluates to `{ ok: true, key }`
707
+ * with the `{ role, name, path }` stored when `ref` was issued, `{ ok: true,
708
+ * key: null }` for a ref this document instance does not know, or
709
+ * `{ ok: false, reason: 'observer-unavailable' }`.
710
+ */
711
+ export function buildObserverSemanticKeyJs(ref) {
712
+ const refJson = jsStringLiteral(typeof ref === 'string' ? ref : '');
713
+ return callInstance(`({ ok: true, key: g.keyForRef(${refJson}) })`);
714
+ }
385
715
  /**
386
716
  * Build the teardown expression: disconnects every observer, restores the
387
717
  * `attachShadow` and `history` patches when they are still the observer's,
@@ -1 +1 @@
1
- {"version":3,"file":"observer.js","sourceRoot":"","sources":["../../../src/cdp/inpage/observer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"observer.js","sourceRoot":"","sources":["../../../src/cdp/inpage/observer.ts"],"names":[],"mappings":"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"}