@jobshimo/browser-link 0.34.1 → 0.36.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.
- package/dist/agent-instructions/content.js +19 -6
- package/dist/agent-instructions/content.js.map +1 -1
- package/dist/bridge/events.d.ts +1 -1
- package/dist/bridge/events.js +8 -1
- package/dist/bridge/events.js.map +1 -1
- package/dist/bridge/ws-bridge.d.ts +17 -0
- package/dist/bridge/ws-bridge.js +34 -0
- package/dist/bridge/ws-bridge.js.map +1 -1
- package/dist/cdp/inpage/builders.d.ts +70 -3
- package/dist/cdp/inpage/builders.js +197 -36
- package/dist/cdp/inpage/builders.js.map +1 -1
- package/dist/cdp/inpage/observer.d.ts +77 -0
- package/dist/cdp/inpage/observer.js +509 -0
- package/dist/cdp/inpage/observer.js.map +1 -0
- package/dist/cdp/observer-host.d.ts +137 -0
- package/dist/cdp/observer-host.js +188 -0
- package/dist/cdp/observer-host.js.map +1 -0
- package/dist/cdp/transport.js +161 -25
- package/dist/cdp/transport.js.map +1 -1
- package/dist/extension/background.js +183 -33
- package/dist/extension/background.js.map +1 -1
- package/dist/extension/inpage/builders.d.ts +70 -3
- package/dist/extension/inpage/builders.js +196 -35
- package/dist/extension/inpage/builders.js.map +1 -1
- package/dist/extension/inpage/observer.d.ts +88 -0
- package/dist/extension/inpage/observer.js +520 -0
- package/dist/extension/inpage/observer.js.map +1 -0
- package/dist/extension/manifest.json +1 -1
- package/dist/extension/observer-host.d.ts +84 -0
- package/dist/extension/observer-host.js +172 -0
- package/dist/extension/observer-host.js.map +1 -0
- package/dist/tools/browser-definitions.js +16 -6
- package/dist/tools/browser-definitions.js.map +1 -1
- package/dist/tools/browser-dispatch.js +14 -2
- package/dist/tools/browser-dispatch.js.map +1 -1
- package/dist/tools/server-instructions.js +19 -5
- package/dist/tools/server-instructions.js.map +1 -1
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* DELIBERATELY A SUBSET: only the builders `cdp/transport.ts` needs for
|
|
7
7
|
* cdp-direct's v1 supported tool set (snapshot, find, click, type, press,
|
|
8
|
-
* state, plus the shared settle wait) are copied. `buildDragProbeJs` /
|
|
8
|
+
* state, wait_for, plus the shared settle wait) are copied. `buildDragProbeJs` /
|
|
9
9
|
* `DragProbeOpts` are NOT copied — `browser.drag` is explicitly out of
|
|
10
10
|
* v1 scope for cdp-direct (see the README's cdp-direct tool-support table
|
|
11
11
|
* and `cdp/transport.ts`'s `CDP_TOOL_SUPPORT`). If drag is ever added to
|
|
@@ -22,6 +22,52 @@
|
|
|
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 `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
|
+
`;
|
|
25
71
|
export function buildSnapshotJs(opts = {}) {
|
|
26
72
|
const optsJson = JSON.stringify({
|
|
27
73
|
withinSelector: typeof opts.within_selector === 'string' ? opts.within_selector : null,
|
|
@@ -30,23 +76,25 @@ export function buildSnapshotJs(opts = {}) {
|
|
|
30
76
|
maxInteractive: typeof opts.max_interactive === 'number' && opts.max_interactive > 0
|
|
31
77
|
? Math.min(opts.max_interactive, 500)
|
|
32
78
|
: 120,
|
|
79
|
+
since: typeof opts.since === 'string' ? opts.since : null,
|
|
33
80
|
});
|
|
34
81
|
return `
|
|
35
82
|
(() => {
|
|
36
83
|
${DEEP_QUERY_JS}
|
|
37
84
|
${DOM_HELPERS_JS}
|
|
85
|
+
${PAGE_OBSERVER_JS}
|
|
38
86
|
const opts = ${optsJson};
|
|
39
87
|
let root = document;
|
|
40
88
|
let notice = '';
|
|
41
89
|
if (opts.withinSelector) {
|
|
42
90
|
const sub = deepQueryFirst(opts.withinSelector);
|
|
43
91
|
if (!sub) {
|
|
44
|
-
return {
|
|
92
|
+
return withDocId({
|
|
45
93
|
title: document.title,
|
|
46
94
|
url: location.href,
|
|
47
95
|
interactive: [],
|
|
48
96
|
notice: 'within_selector did not match any element',
|
|
49
|
-
};
|
|
97
|
+
});
|
|
50
98
|
}
|
|
51
99
|
root = sub;
|
|
52
100
|
}
|
|
@@ -89,6 +137,8 @@ export function buildSnapshotJs(opts = {}) {
|
|
|
89
137
|
const role = el.getAttribute('role') || tag;
|
|
90
138
|
const selInfo = genSelectorInfo(el);
|
|
91
139
|
const entry = { tag, role, selector: selInfo.selector };
|
|
140
|
+
const ref = refOf(el);
|
|
141
|
+
if (ref) entry.ref = ref;
|
|
92
142
|
if (selInfo.ambiguous) entry.ambiguous = true;
|
|
93
143
|
const txt = shortText(el);
|
|
94
144
|
if (txt) entry.text = txt;
|
|
@@ -108,26 +158,105 @@ export function buildSnapshotJs(opts = {}) {
|
|
|
108
158
|
if (frame) entry.frame = frame;
|
|
109
159
|
interactive.push(entry);
|
|
110
160
|
});
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
url: location.href,
|
|
114
|
-
interactive: interactive.slice(0, opts.maxInteractive),
|
|
115
|
-
};
|
|
161
|
+
let headings = null;
|
|
162
|
+
let visibleText = '';
|
|
116
163
|
if (!opts.onlyInteractive) {
|
|
117
|
-
const
|
|
164
|
+
const found = [];
|
|
118
165
|
deepQueryAll('h1, h2, h3', root).forEach((h) => {
|
|
119
166
|
if (!isVisible(h)) return;
|
|
120
167
|
if (inExcludedLandmark(h)) return;
|
|
121
168
|
const t = shortText(h);
|
|
122
|
-
if (t)
|
|
169
|
+
if (t) found.push({ level: h.tagName, text: t });
|
|
123
170
|
});
|
|
124
|
-
|
|
171
|
+
headings = found.slice(0, 30);
|
|
125
172
|
const textRoot = (root === document) ? (document.body || document) : root;
|
|
126
|
-
|
|
173
|
+
visibleText = (textRoot && textRoot.innerText) ? textRoot.innerText.slice(0, 4000) : '';
|
|
174
|
+
}
|
|
175
|
+
let snapshotId = null;
|
|
176
|
+
if (withDocId({}).doc_id && typeof pageObserver.nextSnapshotId === 'function') {
|
|
177
|
+
const issued = pageObserver.nextSnapshotId();
|
|
178
|
+
if (typeof issued === 'string') snapshotId = issued;
|
|
179
|
+
}
|
|
180
|
+
function fullResult() {
|
|
181
|
+
const result = {
|
|
182
|
+
title: document.title,
|
|
183
|
+
url: location.href,
|
|
184
|
+
interactive: interactive.slice(0, opts.maxInteractive),
|
|
185
|
+
};
|
|
186
|
+
if (headings) result.headings = headings;
|
|
127
187
|
if (visibleText) result.text = visibleText;
|
|
188
|
+
if (notice) result.notice = notice;
|
|
189
|
+
withDocId(result);
|
|
190
|
+
if (snapshotId) result.snapshot_id = snapshotId;
|
|
191
|
+
return result;
|
|
128
192
|
}
|
|
129
|
-
|
|
130
|
-
|
|
193
|
+
// Record every snapshot (with or without since) so a later call can diff
|
|
194
|
+
// against it. Entries are keyed by ref; the hash is the entry serialised
|
|
195
|
+
// without its ref, in emission order. Capped at the first 500 entries.
|
|
196
|
+
const store = snapshotId ? snapshotStore() : null;
|
|
197
|
+
// A snapshot_id is \`<doc_id>:s<N>\`: a since whose prefix (before the LAST
|
|
198
|
+
// ':') is not this document's doc_id, or that has no ':', came from another
|
|
199
|
+
// document and is never looked up.
|
|
200
|
+
const sinceCut = opts.since === null ? -1 : opts.since.lastIndexOf(':');
|
|
201
|
+
const sinceSameDoc =
|
|
202
|
+
sinceCut >= 0 && withDocId({}).doc_id === opts.since.slice(0, sinceCut);
|
|
203
|
+
const previous = store && sinceSameDoc ? store.getSnapshot(opts.since) : null;
|
|
204
|
+
const current = new Map();
|
|
205
|
+
const headingsHash = headings ? JSON.stringify(headings) : null;
|
|
206
|
+
const textHash = opts.onlyInteractive ? null : visibleText;
|
|
207
|
+
if (store) {
|
|
208
|
+
for (const entry of interactive) {
|
|
209
|
+
if (current.size >= 500) break;
|
|
210
|
+
if (typeof entry.ref !== 'string') continue;
|
|
211
|
+
const copy = {};
|
|
212
|
+
for (const key of Object.keys(entry)) if (key !== 'ref') copy[key] = entry[key];
|
|
213
|
+
current.set(entry.ref, { hash: JSON.stringify(copy), entry });
|
|
214
|
+
}
|
|
215
|
+
store.recordSnapshot(snapshotId, { entries: current, headings_hash: headingsHash, text_hash: textHash });
|
|
216
|
+
}
|
|
217
|
+
if (opts.since === null) return fullResult();
|
|
218
|
+
if (!store) {
|
|
219
|
+
const result = fullResult();
|
|
220
|
+
result.since = opts.since;
|
|
221
|
+
result.since_status = 'observer-unavailable';
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
if (!previous || !previous.entries || typeof previous.entries.get !== 'function') {
|
|
225
|
+
const result = fullResult();
|
|
226
|
+
result.since = opts.since;
|
|
227
|
+
result.since_status = sinceSameDoc ? 'evicted' : 'doc-changed';
|
|
228
|
+
return result;
|
|
229
|
+
}
|
|
230
|
+
const added = [];
|
|
231
|
+
const changed = [];
|
|
232
|
+
const removed = [];
|
|
233
|
+
current.forEach((item, ref) => {
|
|
234
|
+
const old = previous.entries.get(ref);
|
|
235
|
+
if (!old) added.push(item.entry);
|
|
236
|
+
else if (old.hash !== item.hash) changed.push(item.entry);
|
|
237
|
+
});
|
|
238
|
+
previous.entries.forEach((item, ref) => {
|
|
239
|
+
if (current.has(ref) || removed.length >= 500) return;
|
|
240
|
+
const gone = { ref, tag: item.entry.tag };
|
|
241
|
+
if (item.entry.text) gone.text = item.entry.text;
|
|
242
|
+
removed.push(gone);
|
|
243
|
+
});
|
|
244
|
+
// max_interactive applies after diffing (added first, then changed), so
|
|
245
|
+
// a window shift never masquerades as change.
|
|
246
|
+
const listed = added.concat(changed);
|
|
247
|
+
const kept = listed.slice(0, opts.maxInteractive);
|
|
248
|
+
const diff = withDocId({ title: document.title, url: location.href });
|
|
249
|
+
diff.snapshot_id = snapshotId;
|
|
250
|
+
diff.since = opts.since;
|
|
251
|
+
diff.added = kept.slice(0, Math.min(added.length, kept.length));
|
|
252
|
+
diff.removed = removed;
|
|
253
|
+
diff.changed = kept.slice(diff.added.length);
|
|
254
|
+
if (listed.length > kept.length) diff.overflow = listed.length - kept.length;
|
|
255
|
+
if (!opts.onlyInteractive) {
|
|
256
|
+
if (headingsHash !== previous.headings_hash) diff.headings = headings;
|
|
257
|
+
if (textHash !== previous.text_hash) diff.text = visibleText;
|
|
258
|
+
}
|
|
259
|
+
return diff;
|
|
131
260
|
})()
|
|
132
261
|
`;
|
|
133
262
|
}
|
|
@@ -143,6 +272,7 @@ export function buildFindJs(opts) {
|
|
|
143
272
|
(() => {
|
|
144
273
|
${DEEP_QUERY_JS}
|
|
145
274
|
${DOM_HELPERS_JS}
|
|
275
|
+
${PAGE_OBSERVER_JS}
|
|
146
276
|
const opts = ${optsJson};
|
|
147
277
|
const needle = opts.text.toLowerCase();
|
|
148
278
|
const needleTokens = needle.split(/[^a-z0-9]+/).filter(Boolean);
|
|
@@ -203,6 +333,8 @@ export function buildFindJs(opts) {
|
|
|
203
333
|
}
|
|
204
334
|
function toNearMiss(el) {
|
|
205
335
|
const entry = { text: snippetOf(el), selector: genSelector(el) };
|
|
336
|
+
const ref = refOf(el);
|
|
337
|
+
if (ref) entry.ref = ref;
|
|
206
338
|
const roleAttr = el.getAttribute('role');
|
|
207
339
|
if (roleAttr) entry.role = roleAttr;
|
|
208
340
|
return entry;
|
|
@@ -235,44 +367,46 @@ export function buildFindJs(opts) {
|
|
|
235
367
|
' but none with role "' + opts.role + '"' +
|
|
236
368
|
(closest ? ' — closest: ' + describeForError(closest) + ' "' + snippetOf(closest) + '"' : '');
|
|
237
369
|
result.near_misses = ranked.map(toNearMiss);
|
|
238
|
-
return result;
|
|
370
|
+
return withDocId(result);
|
|
239
371
|
}
|
|
240
372
|
const ranked = rankCandidates(broadAll);
|
|
241
373
|
if (ranked.length > 0) result.near_misses = ranked.map(toNearMiss);
|
|
242
|
-
return result;
|
|
374
|
+
return withDocId(result);
|
|
243
375
|
}
|
|
244
376
|
const ranked = rankCandidates(all);
|
|
245
377
|
if (ranked.length > 0) result.near_misses = ranked.map(toNearMiss);
|
|
246
|
-
return result;
|
|
378
|
+
return withDocId(result);
|
|
247
379
|
}
|
|
248
380
|
if (matches.length > 1) {
|
|
249
|
-
return {
|
|
381
|
+
return withDocId({
|
|
250
382
|
matched: false,
|
|
251
383
|
reason: 'multiple-matches',
|
|
252
|
-
candidates: matches.slice(0, opts.candidateLimit).map((el) =>
|
|
253
|
-
selector: genSelector(el)
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
384
|
+
candidates: matches.slice(0, opts.candidateLimit).map((el) => {
|
|
385
|
+
const candidate = { selector: genSelector(el) };
|
|
386
|
+
const ref = refOf(el);
|
|
387
|
+
if (ref) candidate.ref = ref;
|
|
388
|
+
candidate.text = shortText(el);
|
|
389
|
+
candidate.tag = el.tagName.toLowerCase();
|
|
390
|
+
return candidate;
|
|
391
|
+
}),
|
|
392
|
+
});
|
|
258
393
|
}
|
|
259
394
|
const el = matches[0];
|
|
260
395
|
const center = viewportCenterOf(el);
|
|
261
396
|
const selInfo = genSelectorInfo(el);
|
|
262
|
-
const result = {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
},
|
|
269
|
-
tag: el.tagName.toLowerCase(),
|
|
270
|
-
text: shortText(el),
|
|
397
|
+
const result = { matched: true, selector: selInfo.selector };
|
|
398
|
+
const ref = refOf(el);
|
|
399
|
+
if (ref) result.ref = ref;
|
|
400
|
+
result.coords = {
|
|
401
|
+
x: Math.round(center.x),
|
|
402
|
+
y: Math.round(center.y),
|
|
271
403
|
};
|
|
404
|
+
result.tag = el.tagName.toLowerCase();
|
|
405
|
+
result.text = shortText(el);
|
|
272
406
|
if (selInfo.ambiguous) result.ambiguous = true;
|
|
273
407
|
const frame = frameSelectorFor(el);
|
|
274
408
|
if (frame) result.frame = frame;
|
|
275
|
-
return result;
|
|
409
|
+
return withDocId(result);
|
|
276
410
|
})()
|
|
277
411
|
`;
|
|
278
412
|
}
|
|
@@ -337,6 +471,26 @@ export function buildFocusJs(opts) {
|
|
|
337
471
|
return true;
|
|
338
472
|
})()`;
|
|
339
473
|
}
|
|
474
|
+
export function buildWaitForSelectorJs(selector, condition) {
|
|
475
|
+
const optsJson = JSON.stringify({ selector, condition });
|
|
476
|
+
return `
|
|
477
|
+
(() => {
|
|
478
|
+
${DEEP_QUERY_JS}
|
|
479
|
+
const opts = ${optsJson};
|
|
480
|
+
document.querySelector(opts.selector);
|
|
481
|
+
const el = deepQueryFirst(opts.selector);
|
|
482
|
+
if (opts.condition === 'attached') return Boolean(el);
|
|
483
|
+
if (opts.condition === 'detached') return !el;
|
|
484
|
+
const wantHidden = opts.condition === 'hidden';
|
|
485
|
+
if (!el) return wantHidden;
|
|
486
|
+
const view = (el.ownerDocument && el.ownerDocument.defaultView) || window;
|
|
487
|
+
const s = view.getComputedStyle(el);
|
|
488
|
+
if (s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0') return wantHidden;
|
|
489
|
+
const r = el.getBoundingClientRect();
|
|
490
|
+
const shown = r.width > 0 && r.height > 0;
|
|
491
|
+
return wantHidden ? !shown : shown;
|
|
492
|
+
})()`;
|
|
493
|
+
}
|
|
340
494
|
export function buildElementRectJs(opts) {
|
|
341
495
|
const optsJson = JSON.stringify({ selector: opts.selector });
|
|
342
496
|
return `
|
|
@@ -549,12 +703,16 @@ export function buildExpectProbeJs(opts) {
|
|
|
549
703
|
* `focused` beyond `<body>`, no `dialogs` when none are open, and no
|
|
550
704
|
* `scroll` when the page is at its default (0,0) position — token-lean by
|
|
551
705
|
* construction, matching the omit-falsy convention the other builders use.
|
|
706
|
+
*
|
|
707
|
+
* With the page observer installed (see `PAGE_OBSERVER_JS`), `focused`
|
|
708
|
+
* carries `ref` right after `selector` and the result carries `doc_id`.
|
|
552
709
|
*/
|
|
553
710
|
export function buildStateJs() {
|
|
554
711
|
return `
|
|
555
712
|
(() => {
|
|
556
713
|
${DEEP_QUERY_JS}
|
|
557
714
|
${DOM_HELPERS_JS}
|
|
715
|
+
${PAGE_OBSERVER_JS}
|
|
558
716
|
function deepActiveElement() {
|
|
559
717
|
let el = document.activeElement;
|
|
560
718
|
let guard = 0;
|
|
@@ -615,7 +773,10 @@ export function buildStateJs() {
|
|
|
615
773
|
const active = deepActiveElement();
|
|
616
774
|
if (active && active !== document.body && active.tagName) {
|
|
617
775
|
const selInfo = genSelectorInfo(active);
|
|
618
|
-
const focused = { selector: selInfo.selector
|
|
776
|
+
const focused = { selector: selInfo.selector };
|
|
777
|
+
const ref = refOf(active);
|
|
778
|
+
if (ref) focused.ref = ref;
|
|
779
|
+
focused.tag = active.tagName.toLowerCase();
|
|
619
780
|
if (selInfo.ambiguous) focused.ambiguous = true;
|
|
620
781
|
result.focused = focused;
|
|
621
782
|
}
|
|
@@ -635,7 +796,7 @@ export function buildStateJs() {
|
|
|
635
796
|
const scrollY = Math.round(window.scrollY);
|
|
636
797
|
if (scrollX !== 0 || scrollY !== 0) result.scroll = { x: scrollX, y: scrollY };
|
|
637
798
|
|
|
638
|
-
return result;
|
|
799
|
+
return withDocId(result);
|
|
639
800
|
})()
|
|
640
801
|
`;
|
|
641
802
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builders.js","sourceRoot":"","sources":["../../../src/cdp/inpage/builders.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"builders.js","sourceRoot":"","sources":["../../../src/cdp/inpage/builders.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Independent copy of `packages/extension/src/inpage/observer.ts` — see
|
|
3
|
+
* `./deep-query.ts`'s header comment for why this is a verbatim duplicate
|
|
4
|
+
* rather than a cross-package import.
|
|
5
|
+
*
|
|
6
|
+
* The page observer: a persistent, coalescing MutationObserver that runs in
|
|
7
|
+
* the page's MAIN world (spec v4 §5.1–§5.3). cdp-direct installs it with the
|
|
8
|
+
* same `Runtime.addBinding` + `Page.addScriptToEvaluateOnNewDocument` pair as
|
|
9
|
+
* the extension. Everything below this header must stay byte-identical to the
|
|
10
|
+
* extension original — `cdp/drift.test.ts` enforces it and
|
|
11
|
+
* `cdp/builders-parity.test.ts` checks the built output.
|
|
12
|
+
*/
|
|
13
|
+
/** Bump whenever the in-page protocol (global shape, messages, methods) changes. */
|
|
14
|
+
export declare const OBSERVER_VERSION = 2;
|
|
15
|
+
/** Name of the `Runtime.addBinding` function the observer pushes messages through. */
|
|
16
|
+
export declare const OBSERVER_BINDING = "__blPageObserverPush";
|
|
17
|
+
/** Well-known global that holds the installed observer instance. */
|
|
18
|
+
export declare const OBSERVER_GLOBAL = "__blPageObserver";
|
|
19
|
+
export interface ObserverInstallOpts {
|
|
20
|
+
/** Binding name to push through; defaults to `OBSERVER_BINDING`. */
|
|
21
|
+
binding?: string;
|
|
22
|
+
/** Instance version; defaults to `OBSERVER_VERSION`. */
|
|
23
|
+
version?: number;
|
|
24
|
+
/** Max target descriptors per summary (default 20, clamped to 1..100). */
|
|
25
|
+
descriptor_cap?: number;
|
|
26
|
+
/** Summaries kept for mark/changes read-back (default 64, clamped to 1..1024). */
|
|
27
|
+
ring_size?: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build the observer install source. Valid both as a
|
|
31
|
+
* `Page.addScriptToEvaluateOnNewDocument` source and as a one-off
|
|
32
|
+
* `Runtime.evaluate` expression, which evaluates to
|
|
33
|
+
* `{ ok: true, installed, version, doc_id, coverage }`.
|
|
34
|
+
*
|
|
35
|
+
* The instance also owns element identity (spec v4 §5.6): `refFor(el)` issues
|
|
36
|
+
* `e<N>` (monotonic per document instance, from `e1`) the first time an
|
|
37
|
+
* element is seen and reuses it while the node lives; `resolveRef(ref)`
|
|
38
|
+
* returns the element while it is connected, else `null`. Refs are only valid
|
|
39
|
+
* for the `doc_id` that issued them. Neither method throws. `nextSnapshotId()`
|
|
40
|
+
* issues `<doc_id>:s<N>` (N monotonic per document instance, from 1) for each
|
|
41
|
+
* `snapshot` result and returns `null` once the instance is torn down; the
|
|
42
|
+
* `doc_id` prefix lets a stale id from another document be rejected.
|
|
43
|
+
* `recordSnapshot(id, record)` keeps the last 4 snapshot records per document
|
|
44
|
+
* instance (oldest evicted first) for `snapshot({ since })`; `getSnapshot(id)`
|
|
45
|
+
* returns the record or `null` when unknown or evicted. The record is opaque
|
|
46
|
+
* here. Both are inert after teardown, which clears the store.
|
|
47
|
+
*/
|
|
48
|
+
export declare function buildObserverInstallJs(opts?: ObserverInstallOpts): string;
|
|
49
|
+
/**
|
|
50
|
+
* Build the action-mark expression. Forces a flush (including records still
|
|
51
|
+
* queued in the observers) so the mark is exact, then baselines URL and focus.
|
|
52
|
+
* Evaluates to `{ ok: true, doc_id, mark, url, has_focus_baseline: true }` or
|
|
53
|
+
* `{ ok: false, reason: 'observer-unavailable' }`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function buildObserverMarkJs(): string;
|
|
56
|
+
/**
|
|
57
|
+
* Build the "changes since mark" expression. Forces a flush, then aggregates
|
|
58
|
+
* the ring summaries with `seq > mark`. `docId`, when given, must match the
|
|
59
|
+
* current document. Evaluates to the aggregated changes (see
|
|
60
|
+
* `SettleChanges` in `@browser-link/shared`) plus `ok`, `doc_id`, `since`,
|
|
61
|
+
* and `url_changed` / `focus_moved` only when they differ from the mark's
|
|
62
|
+
* baseline; or `{ ok: false, reason: 'observer-unavailable' | 'doc-changed' }`.
|
|
63
|
+
*/
|
|
64
|
+
export declare function buildObserverChangesJs(mark: number, docId?: string): string;
|
|
65
|
+
/**
|
|
66
|
+
* Build the ref-resolve expression, for tests and debugging. Evaluates to
|
|
67
|
+
* `{ ok: true, found: true, tag }` when `ref` names an element of the current
|
|
68
|
+
* document that is still connected, `{ ok: true, found: false }` when it is
|
|
69
|
+
* unknown or stale, or `{ ok: false, reason: 'observer-unavailable' }`.
|
|
70
|
+
*/
|
|
71
|
+
export declare function buildObserverRefResolveJs(ref: string): string;
|
|
72
|
+
/**
|
|
73
|
+
* Build the teardown expression: disconnects every observer, restores the
|
|
74
|
+
* `attachShadow` and `history` patches when they are still the observer's,
|
|
75
|
+
* and removes the global. Idempotent; evaluates to `{ ok: true, removed }`.
|
|
76
|
+
*/
|
|
77
|
+
export declare function buildObserverTeardownJs(): string;
|