@a11y-pulse/tab-orchestrator 0.1.0 → 0.3.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/adaptor.d.ts CHANGED
@@ -31,7 +31,10 @@ export interface BrowserAdaptor {
31
31
  pressTab(): Promise<void>;
32
32
  /**
33
33
  * Screenshot a clipped region of the page. `scale` is the device scale
34
- * factor (bitmap pixels per CSS pixel).
34
+ * factor (bitmap pixels per CSS pixel), multiplied against whatever
35
+ * deviceScaleFactor the page itself currently has (Puppeteer does not
36
+ * replace it). The caller is responsible for the page being at a known
37
+ * deviceScaleFactor before invoking this.
35
38
  */
36
39
  screenshotClip(clip: Rect, scale?: number): Promise<Uint8Array>;
37
40
  /** Device scale factor for evidence screenshots stored on failure. */
@@ -76,8 +76,11 @@ export declare function focusScript(el: Element | null): void;
76
76
  */
77
77
  export declare function elementStylesScript(el: Element | null, props: string[]): StyleSnapshot;
78
78
  /**
79
- * Remove the marker attribute from all elements and blur the active element. This is a best-effort
80
- * attempt to reset state between audits.
79
+ * Remove the marker attribute from all elements, blur the active element, and
80
+ * scroll back to the top. This is a best-effort attempt to reset state between
81
+ * audits: the tab loop scrolls later elements into view as it walks the page
82
+ * (see scrollToCenterScript), and nothing else undoes that once the session
83
+ * ends.
81
84
  */
82
85
  export declare function clearMarkersScript(markerAttr: string): void;
83
86
  export type MeasureObscuringResult = {
@@ -0,0 +1,10 @@
1
+ import type { BrowserAdaptor, ElementRef } from "./adaptor";
2
+ export type CaptureScreenshotOptions = {
3
+ screenshotClipBuffer: number;
4
+ };
5
+ /**
6
+ * Screenshot the element `handle` currently refers to, clipped to its box plus
7
+ * `screenshotClipBuffer` padding. The caller owns `handle` and must dispose it
8
+ * after this promise settles.
9
+ */
10
+ export declare function captureScreenshot(adaptor: BrowserAdaptor, options: CaptureScreenshotOptions, handle: ElementRef): Promise<Uint8Array>;
package/dist/index.js CHANGED
@@ -305,6 +305,7 @@ function clearMarkersScript(markerAttr) {
305
305
  };
306
306
  clear(document);
307
307
  document.activeElement?.blur();
308
+ window.scrollTo(0, 0);
308
309
  }
309
310
  function measureObscuringScript(el, obscurerAttr) {
310
311
  const empty = {
@@ -827,6 +828,20 @@ function getSelector(root) {
827
828
  return segments.join(">");
828
829
  }
829
830
 
831
+ // src/capture-screenshot.ts
832
+ async function captureScreenshot(adaptor, options, handle) {
833
+ const { width: pageWidth, height: pageHeight } = await adaptor.evaluate(pageDimensionsScript);
834
+ const rect = await adaptor.evaluate(elementRectScript, handle);
835
+ const clip = bufferedClip(
836
+ rect,
837
+ pageWidth,
838
+ pageHeight,
839
+ options.screenshotClipBuffer
840
+ );
841
+ const scale = adaptor.screenshotClipScale ?? 1;
842
+ return adaptor.screenshotClip(clip, scale);
843
+ }
844
+
830
845
  // src/truncate-html.ts
831
846
  var DEFAULT_MAX_ATTRIBUTE_VALUE_LENGTH = 50;
832
847
  var DEFAULT_MAX_LENGTH = 300;
@@ -949,6 +964,7 @@ function createTabOrchestrator(adaptor, options = {}) {
949
964
  let settleTimer;
950
965
  let resolveSettle;
951
966
  const pairByStop = { current: null };
967
+ const screenshotByStop = { current: null };
952
968
  let activeHandle;
953
969
  let lastHasAttributed = false;
954
970
  let baselineHref = null;
@@ -980,6 +996,23 @@ function createTabOrchestrator(adaptor, options = {}) {
980
996
  activeHandle
981
997
  );
982
998
  return pairByStop.current;
999
+ },
1000
+ screenshotClip: () => {
1001
+ if (!consumer.capabilities.has("screenshot")) {
1002
+ throw new Error("Consumer did not declare screenshot");
1003
+ }
1004
+ if (!remainingHas("screenshot")) {
1005
+ throw new Error("Consumer did not declare screenshot");
1006
+ }
1007
+ if (activeHandle === void 0) {
1008
+ throw new Error("screenshot capture not implemented");
1009
+ }
1010
+ screenshotByStop.current ??= captureScreenshot(
1011
+ adaptor,
1012
+ resolved,
1013
+ activeHandle
1014
+ );
1015
+ return screenshotByStop.current;
983
1016
  }
984
1017
  });
985
1018
  const end = (reason) => {
@@ -1040,6 +1073,7 @@ function createTabOrchestrator(adaptor, options = {}) {
1040
1073
  let tabIndex = 0;
1041
1074
  while (attached.size > 0) {
1042
1075
  pairByStop.current = null;
1076
+ screenshotByStop.current = null;
1043
1077
  lastHasAttributed = false;
1044
1078
  const hasFocus = await adaptor.evaluate(() => document.hasFocus());
1045
1079
  if (!hasFocus) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/audit-scaffold.ts","../src/browser-scripts.ts","../src/clip.ts","../src/focus-style.ts","../src/get-selector.ts","../src/truncate-html.ts","../src/unfocused-pair.ts","../src/orchestrator.ts"],"sourcesContent":["import type { SessionEndReason, TabSessionHandle } from \"./types\";\n\nexport const DEFAULT_ELEMENT_LIMIT = 1024;\nexport const DEFAULT_SCREENSHOT_SETTLE_DELAY = 33; // ~2 frames at 60fps\nexport const DEFAULT_FAILED_ELEMENT_LIMIT = 0; // 0 = never finish early\nexport const DEFAULT_TIMEOUT = 0; // 0 = no timeout\n\nexport type BaseAuditOptions = {\n\t/** Max focusable elements to tab through. */\n\telementLimit?: number;\n\t/** How long to wait (ms) after each Tab for the page to settle. */\n\tscreenshotSettleDelay?: number;\n\t/** Disconnect early after this many elements fail (0 = never). */\n\tfailedElementLimit?: number;\n\t/** Return whatever's gathered so far after this many ms (0 = no timeout). */\n\ttimeout?: number;\n};\n\nexport type BaseAuditSummary = {\n\tchecked: number;\n\tpassed: number;\n\tfailed: number;\n\t/** True if the element limit was hit before tabbing finished. */\n\treachedLimit: boolean;\n\t/** True if the audit stopped early after hitting `failedElementLimit`. */\n\treachedFailedElementLimit: boolean;\n\t/**\n\t * True if the audit returned early because `timeout` elapsed. The results\n\t * are whatever had been gathered when the deadline hit.\n\t */\n\ttimedOut: boolean;\n\t/**\n\t * Why the tab session ended, or `null` when this consumer disconnected\n\t * itself (element limit, failed-element limit, or timeout).\n\t */\n\tsessionEnd: SessionEndReason | null;\n};\n\nexport type AuditSelfDisconnect = {\n\t/** True once this consumer has disconnected itself from the session. */\n\treadonly disconnectedSelf: boolean;\n\t/** Arm a timeout that calls `onTimeout` then disconnects, if `timeout` is greater than 0. */\n\tarmTimeout(\n\t\ttimeout: number,\n\t\tsession: TabSessionHandle,\n\t\tonTimeout: () => void,\n\t): void;\n\t/** Disconnect the session and record that this consumer initiated it. */\n\tdisconnect(session: TabSessionHandle): void;\n\t/** Clear any pending timeout without disconnecting. */\n\tclear(): void;\n};\n\n/**\n * Arms an optional self-disconnecting timeout and tracks whether this\n * consumer initiated its own disconnect, so `onSessionEnd` can tell that\n * apart from an external end.\n */\nexport function createAuditSelfDisconnect(): AuditSelfDisconnect {\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet disconnectedSelf = false;\n\n\tconst clear = (): void => {\n\t\tif (timer !== undefined) {\n\t\t\tclearTimeout(timer);\n\t\t\ttimer = undefined;\n\t\t}\n\t};\n\n\tconst disconnect = (session: TabSessionHandle): void => {\n\t\tdisconnectedSelf = true;\n\t\tclear();\n\t\tsession.disconnect();\n\t};\n\n\treturn {\n\t\tget disconnectedSelf() {\n\t\t\treturn disconnectedSelf;\n\t\t},\n\t\tarmTimeout(timeout, session, onTimeout) {\n\t\t\tif (timeout > 0) {\n\t\t\t\ttimer = setTimeout(() => {\n\t\t\t\t\ttimer = undefined;\n\t\t\t\t\tonTimeout();\n\t\t\t\t\tdisconnect(session);\n\t\t\t\t}, timeout);\n\t\t\t}\n\t\t},\n\t\tdisconnect,\n\t\tclear,\n\t};\n}\n","/**\n * IMPORTANT: Functions in this file are serialized and injected into the audited page, so they\n * must not reference any symbols outside their own scope. This also means they cannot share code,\n * so any common logic (like descending into shadow roots) must be duplicated.\n */\n\nimport type { Rect } from \"./adaptor\";\nimport type { StyleSnapshot } from \"./types\";\n\ntype BaselineElementEntry = {\n\tindex: number;\n\t/** Position of this element's snapshot in the payload's `styles` table. */\n\tstyleIndex: number;\n\t/** The element's page-relative rect in its unfocused (baseline) state. */\n\trect: Rect;\n};\n\n/**\n * The baseline as a table of unique style snapshots plus per-element entries referencing them.\n * Elements overwhelmingly share identical snapshots (same classes), so interning keeps the\n * serialised payload O(unique styles) instead of O(elements × style size).\n */\nexport type BaselinePayload = {\n\tstyles: StyleSnapshot[];\n\tentries: BaselineElementEntry[];\n};\n\n/**\n * Find up to `limit` focusable elements and mark them with `markerAttr` and a unique index. Then\n * return a snapshot of their styles to use as a baseline.\n */\nexport function baselineScript(\n\tprops: string[],\n\tmarkerAttr: string,\n\tlimit: number,\n): BaselinePayload {\n\t// Bound oversized computed values (data-URI background images can run to hundreds of KB)\n\t// while preserving inequality via the length and a fingerprint of the full value. Must be\n\t// byte-identical to the copy in probeActiveElementScript, or every oversized value would\n\t// \"change\" on focus and produce a false style-check pass.\n\tconst truncateValue = (value: string): string => {\n\t\tconst MAX_STYLE_VALUE_LENGTH = 512;\n\n\t\tif (value.length <= MAX_STYLE_VALUE_LENGTH) {\n\t\t\treturn value;\n\t\t}\n\n\t\tlet hash = 5381;\n\n\t\tfor (let i = 0; i < value.length; i++) {\n\t\t\thash = ((hash * 33) ^ value.charCodeAt(i)) >>> 0;\n\t\t}\n\n\t\treturn `${value.slice(0, MAX_STYLE_VALUE_LENGTH)}#len=${value.length}#h=${hash.toString(36)}`;\n\t};\n\n\tconst snapshot = (el: Element): StyleSnapshot => {\n\t\tconst read = (pseudo: string | undefined): Record<string, string> => {\n\t\t\tconst cs = getComputedStyle(el, pseudo);\n\t\t\tconst out: Record<string, string> = {};\n\n\t\t\tfor (const prop of props) {\n\t\t\t\tout[prop] = truncateValue(cs.getPropertyValue(prop));\n\t\t\t}\n\n\t\t\tif (pseudo) {\n\t\t\t\tout.content = truncateValue(cs.getPropertyValue(\"content\"));\n\t\t\t}\n\n\t\t\treturn out;\n\t\t};\n\n\t\treturn {\n\t\t\telement: read(undefined),\n\t\t\tbefore: read(\"::before\"),\n\t\t\tafter: read(\"::after\"),\n\t\t};\n\t};\n\n\tconst candidates: Element[] = [];\n\tconst focusableSelector = [\n\t\t\"a[href]\",\n\t\t\"button\",\n\t\t\"input\",\n\t\t\"select\",\n\t\t\"textarea\",\n\t\t\"[tabindex]\",\n\t\t'[contenteditable=\"\"]',\n\t\t'[contenteditable=\"true\"]',\n\t].join(\", \");\n\n\t// Collect focusable candidates in document order, descending into open shadow roots.\n\tconst collect = (root: Document | ShadowRoot): void => {\n\t\tfor (const el of Array.from(root.querySelectorAll(\"*\"))) {\n\t\t\tif (el.matches(focusableSelector)) {\n\t\t\t\tcandidates.push(el);\n\t\t\t}\n\n\t\t\tif (el.shadowRoot) {\n\t\t\t\tcollect(el.shadowRoot);\n\t\t\t}\n\t\t}\n\t};\n\n\tcollect(document);\n\n\tconst styles: StyleSnapshot[] = [];\n\tconst styleIndexByKey = new Map<string, number>();\n\tconst entries: BaselineElementEntry[] = [];\n\tlet idx = 0;\n\n\tfor (const el of candidates) {\n\t\tif (idx >= limit) {\n\t\t\tbreak;\n\t\t}\n\n\t\tif (el.hasAttribute(\"disabled\")) {\n\t\t\t// Skip disabled elements\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ((el as HTMLElement).tabIndex < 0) {\n\t\t\t// Skip elements that are focusable but not in the tab order (negative\n\t\t\t// tabindex). The audit tabs through the page, so it never lands on them,\n\t\t\t// and counting them would waste the element-limit budget.\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Skip non-visible elements so they don't consume the marker budget (e.g.\n\t\t// links inside a closed mega-menu). checkVisibility sees hiding applied by\n\t\t// ancestors, which per-element computed styles don't (`display` doesn't\n\t\t// inherit); fall back to the element's own styles where it's unavailable.\n\t\tconst visibilityCheck = el as Element & {\n\t\t\tcheckVisibility?: (options?: { checkVisibilityCSS?: boolean }) => boolean;\n\t\t};\n\n\t\tif (typeof visibilityCheck.checkVisibility === \"function\") {\n\t\t\tif (!visibilityCheck.checkVisibility({ checkVisibilityCSS: true })) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t} else {\n\t\t\tconst cs = getComputedStyle(el);\n\n\t\t\tif (cs.display === \"none\" || cs.visibility === \"hidden\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Mark before measuring: the probe reads styles and rects while the marker\n\t\t// is present, so the baseline must be captured in the same DOM state.\n\t\tel.setAttribute(markerAttr, String(idx));\n\n\t\tconst rect = el.getBoundingClientRect();\n\n\t\t// Intern the snapshot: the JSON key is deterministic because every\n\t\t// snapshot is built with the same property insertion order.\n\t\tconst snap = snapshot(el);\n\t\tconst key = JSON.stringify(snap);\n\t\tlet styleIndex = styleIndexByKey.get(key);\n\n\t\tif (styleIndex === undefined) {\n\t\t\tstyleIndex = styles.length;\n\t\t\tstyles.push(snap);\n\t\t\tstyleIndexByKey.set(key, styleIndex);\n\t\t}\n\n\t\tentries.push({\n\t\t\tindex: idx,\n\t\t\tstyleIndex,\n\t\t\trect: {\n\t\t\t\tx: rect.left + window.scrollX,\n\t\t\t\ty: rect.top + window.scrollY,\n\t\t\t\twidth: rect.width,\n\t\t\t\theight: rect.height,\n\t\t\t},\n\t\t});\n\t\tidx++;\n\t}\n\n\treturn { styles, entries };\n}\n\nexport type ActiveElementBase = {\n\tindex: number | null;\n\tisBody: boolean;\n\t/**\n\t * The focused element is an <iframe>. Tabbing into a frame passes focus into\n\t * its embedded document, but the parent's document.activeElement is the frame\n\t * element itself, so the loop uses this to skip the frame as a tab stop.\n\t */\n\tisIframe: boolean;\n\thtml: string;\n\tstyles: StyleSnapshot;\n\trect: Rect;\n};\n\n/**\n * Read the currently focused element (descending open shadow roots), returning\n * its marker index, opening-tag HTML (marker attribute stripped), focus-relevant\n * styles, and page-relative rect.\n */\nexport function probeActiveElementScript(\n\tprops: string[],\n\tmarkerAttr: string,\n): ActiveElementBase {\n\tlet el = document.activeElement;\n\n\twhile (el?.shadowRoot?.activeElement) {\n\t\tel = el.shadowRoot.activeElement;\n\t}\n\n\tif (!el || el === document.body) {\n\t\treturn {\n\t\t\tindex: null,\n\t\t\tisBody: true,\n\t\t\tisIframe: false,\n\t\t\thtml: \"\",\n\t\t\tstyles: { element: {}, before: {}, after: {} },\n\t\t\trect: { x: 0, y: 0, width: 0, height: 0 },\n\t\t};\n\t}\n\n\t// Must be byte-identical to the copy in baselineScript: snapshots from the two scripts are\n\t// compared for equality, so they have to truncate oversized values the same way.\n\tconst truncateValue = (value: string): string => {\n\t\tconst MAX_STYLE_VALUE_LENGTH = 512;\n\n\t\tif (value.length <= MAX_STYLE_VALUE_LENGTH) {\n\t\t\treturn value;\n\t\t}\n\n\t\tlet hash = 5381;\n\n\t\tfor (let i = 0; i < value.length; i++) {\n\t\t\thash = ((hash * 33) ^ value.charCodeAt(i)) >>> 0;\n\t\t}\n\n\t\treturn `${value.slice(0, MAX_STYLE_VALUE_LENGTH)}#len=${value.length}#h=${hash.toString(36)}`;\n\t};\n\n\tconst read = (pseudo: string | undefined): Record<string, string> => {\n\t\tconst cs = getComputedStyle(el as Element, pseudo);\n\t\tconst out: Record<string, string> = {};\n\n\t\tfor (const prop of props) {\n\t\t\tout[prop] = truncateValue(cs.getPropertyValue(prop));\n\t\t}\n\n\t\tif (pseudo) {\n\t\t\tout.content = truncateValue(cs.getPropertyValue(\"content\"));\n\t\t}\n\n\t\treturn out;\n\t};\n\n\tconst idxAttr = el.getAttribute(markerAttr);\n\tconst rect = el.getBoundingClientRect();\n\n\t// Shallow clone so only the opening tag is serialised, not the whole subtree;\n\t// drop the internal marker attribute so it never leaks into the snippet.\n\tconst openingTag = el.cloneNode(false) as Element;\n\topeningTag.removeAttribute(markerAttr);\n\n\treturn {\n\t\tindex: idxAttr === null ? null : Number(idxAttr),\n\t\tisBody: false,\n\t\tisIframe: el.tagName === \"IFRAME\",\n\t\thtml: openingTag.outerHTML,\n\t\tstyles: {\n\t\t\telement: read(undefined),\n\t\t\tbefore: read(\"::before\"),\n\t\t\tafter: read(\"::after\"),\n\t\t},\n\t\trect: {\n\t\t\tx: rect.left + window.scrollX,\n\t\t\ty: rect.top + window.scrollY,\n\t\t\twidth: rect.width,\n\t\t\theight: rect.height,\n\t\t},\n\t};\n}\n\nexport function activeElementHandleScript(): Element | null {\n\tlet el = document.activeElement;\n\n\twhile (el?.shadowRoot?.activeElement) {\n\t\tel = el.shadowRoot.activeElement;\n\t}\n\n\treturn el;\n}\n\nexport function pageDimensionsScript(): { width: number; height: number } {\n\treturn {\n\t\twidth: document.documentElement.scrollWidth,\n\t\theight: document.documentElement.scrollHeight,\n\t};\n}\n\nexport function elementRectScript(el: Element | null): Rect {\n\tif (!el) {\n\t\treturn { x: 0, y: 0, width: 0, height: 0 };\n\t}\n\n\tconst rect = el.getBoundingClientRect();\n\n\treturn {\n\t\tx: rect.left + window.scrollX,\n\t\ty: rect.top + window.scrollY,\n\t\twidth: rect.width,\n\t\theight: rect.height,\n\t};\n}\n\n/**\n * Whether something unrelated (e.g. a fixed cookie banner) covers the element's centre point, so\n * a screenshot of the element's box would show the covering element instead.\n */\nexport function isCenterObscuredScript(el: Element | null): boolean {\n\tif (!el) {\n\t\treturn false;\n\t}\n\n\tconst rect = el.getBoundingClientRect();\n\tconst x = Math.min(\n\t\tMath.max(rect.left + rect.width / 2, 0),\n\t\twindow.innerWidth - 1,\n\t);\n\tconst y = Math.min(\n\t\tMath.max(rect.top + rect.height / 2, 0),\n\t\twindow.innerHeight - 1,\n\t);\n\n\tlet hit = document.elementFromPoint(x, y);\n\n\t// Descend into shadow roots so a hit on a shadow host resolves to the inner element.\n\twhile (hit?.shadowRoot) {\n\t\tconst inner = hit.shadowRoot.elementFromPoint(x, y);\n\n\t\tif (!inner || inner === hit) {\n\t\t\tbreak;\n\t\t}\n\n\t\thit = inner;\n\t}\n\n\tif (!hit) {\n\t\treturn false;\n\t}\n\n\treturn hit !== el && !el.contains(hit) && !hit.contains(el);\n}\n\n/**\n * Scroll the element to the centre of the viewport, instantly so a screenshot taken immediately\n * afterwards isn't captured mid-animation.\n */\nexport function scrollToCenterScript(el: Element | null): void {\n\tel?.scrollIntoView({\n\t\tblock: \"center\",\n\t\tinline: \"nearest\",\n\t\tbehavior: \"instant\",\n\t});\n}\n\n/**\n * Blur (unfocus) an element\n */\nexport function blurScript(el: Element | null): void {\n\t(el as HTMLElement | null)?.blur();\n}\n\n/**\n * Focus an element\n */\nexport function focusScript(el: Element | null): void {\n\t(el as HTMLElement | null)?.focus({ preventScroll: true });\n}\n\n/**\n * Read focus-relevant computed styles from a given element. Unlike\n * `probeActiveElementScript`, this does not use `document.activeElement`, so it\n * still works after the node has been blurred.\n */\nexport function elementStylesScript(\n\tel: Element | null,\n\tprops: string[],\n): StyleSnapshot {\n\tif (!el) {\n\t\treturn { element: {}, before: {}, after: {} };\n\t}\n\n\t// Must be byte-identical to the copies in baselineScript and\n\t// probeActiveElementScript: snapshots from the scripts are compared for\n\t// equality, so they have to truncate oversized values the same way.\n\tconst truncateValue = (value: string): string => {\n\t\tconst MAX_STYLE_VALUE_LENGTH = 512;\n\n\t\tif (value.length <= MAX_STYLE_VALUE_LENGTH) {\n\t\t\treturn value;\n\t\t}\n\n\t\tlet hash = 5381;\n\n\t\tfor (let i = 0; i < value.length; i++) {\n\t\t\thash = ((hash * 33) ^ value.charCodeAt(i)) >>> 0;\n\t\t}\n\n\t\treturn `${value.slice(0, MAX_STYLE_VALUE_LENGTH)}#len=${value.length}#h=${hash.toString(36)}`;\n\t};\n\n\tconst read = (pseudo: string | undefined): Record<string, string> => {\n\t\tconst cs = getComputedStyle(el, pseudo);\n\t\tconst out: Record<string, string> = {};\n\n\t\tfor (const prop of props) {\n\t\t\tout[prop] = truncateValue(cs.getPropertyValue(prop));\n\t\t}\n\n\t\tif (pseudo) {\n\t\t\tout.content = truncateValue(cs.getPropertyValue(\"content\"));\n\t\t}\n\n\t\treturn out;\n\t};\n\n\treturn {\n\t\telement: read(undefined),\n\t\tbefore: read(\"::before\"),\n\t\tafter: read(\"::after\"),\n\t};\n}\n\n/**\n * Remove the marker attribute from all elements and blur the active element. This is a best-effort\n * attempt to reset state between audits.\n */\nexport function clearMarkersScript(markerAttr: string): void {\n\tconst clear = (root: Document | ShadowRoot): void => {\n\t\tfor (const el of Array.from(root.querySelectorAll(`[${markerAttr}]`))) {\n\t\t\tel.removeAttribute(markerAttr);\n\t\t}\n\n\t\t// Descend into any shadow roots to clear markers within them.\n\t\tfor (const el of Array.from(root.querySelectorAll(\"*\"))) {\n\t\t\tif (el.shadowRoot) {\n\t\t\t\tclear(el.shadowRoot);\n\t\t\t}\n\t\t}\n\t};\n\n\tclear(document);\n\n\t(document.activeElement as HTMLElement | null)?.blur();\n}\n\nexport type MeasureObscuringResult = {\n\tcoveredFraction: number;\n\tfullyObscured: boolean;\n\toffscreen: boolean;\n\topacity: \"opaque\" | \"semi-transparent\" | \"unknown\";\n\tobscuredByHtml: string | null;\n\t/** True when a covering element was marked for selector resolution. */\n\thasObscurer: boolean;\n};\n\n/**\n * Hit-test whether author-created content entirely hides the focused element.\n * Marks a single covering element with `obscurerAttr` when containment confirms\n * a full cover, so the host can resolve its selector via getSelector.\n */\nexport function measureObscuringScript(\n\tel: Element | null,\n\tobscurerAttr: string,\n): MeasureObscuringResult {\n\tconst empty: MeasureObscuringResult = {\n\t\tcoveredFraction: 0,\n\t\tfullyObscured: false,\n\t\toffscreen: false,\n\t\topacity: \"opaque\",\n\t\tobscuredByHtml: null,\n\t\thasObscurer: false,\n\t};\n\n\tif (!el) {\n\t\treturn empty;\n\t}\n\n\tfor (const marked of Array.from(\n\t\tdocument.querySelectorAll(`[${obscurerAttr}]`),\n\t)) {\n\t\tmarked.removeAttribute(obscurerAttr);\n\t}\n\n\tconst rect = el.getBoundingClientRect();\n\tconst left = Math.max(rect.left, 0);\n\tconst top = Math.max(rect.top, 0);\n\tconst right = Math.min(rect.right, window.innerWidth);\n\tconst bottom = Math.min(rect.bottom, window.innerHeight);\n\n\tif (right <= left || bottom <= top) {\n\t\treturn { ...empty, offscreen: true };\n\t}\n\n\tconst width = right - left;\n\tconst height = bottom - top;\n\tconst LARGE_ELEMENT_THRESHOLD_PX = 80;\n\n\tconst points: Array<{ x: number; y: number }> = [\n\t\t{ x: left, y: top },\n\t\t{ x: right - 0.5, y: top },\n\t\t{ x: left, y: bottom - 0.5 },\n\t\t{ x: right - 0.5, y: bottom - 0.5 },\n\t\t{ x: left + width / 2, y: top },\n\t\t{ x: left + width / 2, y: bottom - 0.5 },\n\t\t{ x: left, y: top + height / 2 },\n\t\t{ x: right - 0.5, y: top + height / 2 },\n\t\t{ x: left + width / 2, y: top + height / 2 },\n\t];\n\n\tif (\n\t\twidth > LARGE_ELEMENT_THRESHOLD_PX ||\n\t\theight > LARGE_ELEMENT_THRESHOLD_PX\n\t) {\n\t\tpoints.push(\n\t\t\t{ x: left + width * 0.25, y: top + height * 0.25 },\n\t\t\t{ x: left + width * 0.75, y: top + height * 0.25 },\n\t\t\t{ x: left + width * 0.25, y: top + height * 0.75 },\n\t\t\t{ x: left + width * 0.75, y: top + height * 0.75 },\n\t\t);\n\t}\n\n\tconst hitAt = (x: number, y: number): Element | null => {\n\t\tconst px = Math.min(Math.max(x, 0), window.innerWidth - 1);\n\t\tconst py = Math.min(Math.max(y, 0), window.innerHeight - 1);\n\t\tconst stack =\n\t\t\ttypeof document.elementsFromPoint === \"function\"\n\t\t\t\t? document.elementsFromPoint(px, py)\n\t\t\t\t: [document.elementFromPoint(px, py)].filter(Boolean);\n\n\t\tfor (let candidate of stack as Element[]) {\n\t\t\twhile (candidate?.shadowRoot) {\n\t\t\t\tconst inner = candidate.shadowRoot.elementFromPoint(px, py);\n\n\t\t\t\tif (!inner || inner === candidate) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcandidate = inner;\n\t\t\t}\n\n\t\t\tif (!candidate) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tcandidate === el ||\n\t\t\t\tel.contains(candidate) ||\n\t\t\t\tcandidate.contains(el)\n\t\t\t) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn candidate;\n\t\t}\n\n\t\treturn null;\n\t};\n\n\tlet covered = 0;\n\tconst coverCounts = new Map<Element, number>();\n\n\tfor (const point of points) {\n\t\tconst cover = hitAt(point.x, point.y);\n\n\t\tif (cover) {\n\t\t\tcovered++;\n\t\t\tcoverCounts.set(cover, (coverCounts.get(cover) ?? 0) + 1);\n\t\t}\n\t}\n\n\tconst coveredFraction = points.length === 0 ? 0 : covered / points.length;\n\n\tif (coveredFraction < 1) {\n\t\treturn {\n\t\t\t...empty,\n\t\t\tcoveredFraction,\n\t\t\tfullyObscured: false,\n\t\t};\n\t}\n\n\tlet topCover: Element | null = null;\n\tlet topCount = 0;\n\n\tfor (const [candidate, count] of coverCounts) {\n\t\tif (count > topCount) {\n\t\t\ttopCover = candidate;\n\t\t\ttopCount = count;\n\t\t}\n\t}\n\n\tif (!topCover) {\n\t\treturn {\n\t\t\t...empty,\n\t\t\tcoveredFraction: 1,\n\t\t\tfullyObscured: false,\n\t\t\topacity: \"unknown\",\n\t\t};\n\t}\n\n\tconst coverRect = topCover.getBoundingClientRect();\n\tconst containsFully =\n\t\tcoverRect.left <= rect.left &&\n\t\tcoverRect.top <= rect.top &&\n\t\tcoverRect.right >= rect.right &&\n\t\tcoverRect.bottom >= rect.bottom;\n\n\tif (!containsFully) {\n\t\t// Joint multi-element cover: cannot confirm a single opaque container.\n\t\treturn {\n\t\t\tcoveredFraction: 1,\n\t\t\tfullyObscured: true,\n\t\t\toffscreen: false,\n\t\t\topacity: \"unknown\",\n\t\t\tobscuredByHtml: null,\n\t\t\thasObscurer: false,\n\t\t};\n\t}\n\n\tconst classifyOpacity = (\n\t\tnode: Element,\n\t): \"opaque\" | \"semi-transparent\" | \"unknown\" => {\n\t\tconst cs = getComputedStyle(node);\n\t\tconst opacity = Number.parseFloat(cs.opacity);\n\n\t\tif (!Number.isFinite(opacity)) {\n\t\t\treturn \"unknown\";\n\t\t}\n\n\t\tif (opacity < 1) {\n\t\t\treturn \"semi-transparent\";\n\t\t}\n\n\t\tconst bg = cs.backgroundColor;\n\t\tconst rgba = bg.match(\n\t\t\t/rgba?\\(\\s*([\\d.]+)\\s*,\\s*([\\d.]+)\\s*,\\s*([\\d.]+)(?:\\s*,\\s*([\\d.]+))?\\s*\\)/,\n\t\t);\n\n\t\tif (rgba) {\n\t\t\tconst alpha = rgba[4] === undefined ? 1 : Number.parseFloat(rgba[4]);\n\n\t\t\tif (alpha < 1) {\n\t\t\t\treturn alpha <= 0 ? \"semi-transparent\" : \"semi-transparent\";\n\t\t\t}\n\n\t\t\treturn \"opaque\";\n\t\t}\n\n\t\tif (cs.backgroundImage && cs.backgroundImage !== \"none\") {\n\t\t\treturn \"unknown\";\n\t\t}\n\n\t\treturn \"unknown\";\n\t};\n\n\tconst opacity = classifyOpacity(topCover);\n\tconst openingTag = topCover.cloneNode(false) as Element;\n\topeningTag.removeAttribute(obscurerAttr);\n\ttopCover.setAttribute(obscurerAttr, \"1\");\n\n\treturn {\n\t\tcoveredFraction: 1,\n\t\tfullyObscured: true,\n\t\toffscreen: false,\n\t\topacity,\n\t\tobscuredByHtml: openingTag.outerHTML,\n\t\thasObscurer: true,\n\t};\n}\n\n/** Return the element marked as the obscurer, if any. */\nexport function obscurerHandleScript(): Element | null {\n\treturn document.querySelector(\"[data-a11y-obscurer]\");\n}\n\nexport function clearObscurerScript(obscurerAttr: string): void {\n\tfor (const marked of Array.from(\n\t\tdocument.querySelectorAll(`[${obscurerAttr}]`),\n\t)) {\n\t\tmarked.removeAttribute(obscurerAttr);\n\t}\n}\n\ntype ContextObserverState = {\n\tbaselineHref: string;\n\topenedWindow: boolean;\n\tsubmittedForm: boolean;\n\t/** Elements that received focusin since the last drain. */\n\tfocusIns: Element[];\n\tsoftUrlChange: boolean;\n\tinstalled: boolean;\n};\n\ndeclare global {\n\tinterface Window {\n\t\t__a11yContextObserver?: ContextObserverState;\n\t}\n}\n\n/**\n * Install once: wrap window.open (record + inert stub), capture-phase submit\n * (record + preventDefault), track focusin and soft URL changes.\n */\nexport function installContextObserverScript(): void {\n\tif (window.__a11yContextObserver?.installed) {\n\t\treturn;\n\t}\n\n\tconst state: ContextObserverState = {\n\t\tbaselineHref: location.href,\n\t\topenedWindow: false,\n\t\tsubmittedForm: false,\n\t\tfocusIns: [],\n\t\tsoftUrlChange: false,\n\t\tinstalled: true,\n\t};\n\n\twindow.__a11yContextObserver = state;\n\n\tconst originalOpen = window.open.bind(window);\n\n\twindow.open = (..._args: Parameters<typeof window.open>) => {\n\t\tstate.openedWindow = true;\n\n\t\treturn {\n\t\t\tclosed: true,\n\t\t\tclose() {},\n\t\t\tfocus() {},\n\t\t\tblur() {},\n\t\t\topener: null,\n\t\t\tlocation: { href: \"\" },\n\t\t} as unknown as Window;\n\t};\n\n\t// Keep a reference so tooling does not tree-shake the bind as unused.\n\tvoid originalOpen;\n\n\tdocument.addEventListener(\n\t\t\"submit\",\n\t\t(event) => {\n\t\t\tstate.submittedForm = true;\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\t\t},\n\t\ttrue,\n\t);\n\n\tdocument.addEventListener(\n\t\t\"focus\",\n\t\t(event) => {\n\t\t\tconst target = event.target;\n\n\t\t\t// Prefer nodeType: instanceof can be brittle across some embeddings.\n\t\t\tif (target && (target as Node).nodeType === 1) {\n\t\t\t\tstate.focusIns.push(target as Element);\n\t\t\t}\n\t\t},\n\t\ttrue,\n\t);\n\n\tconst noteSoftNav = (): void => {\n\t\tif (location.href !== state.baselineHref) {\n\t\t\tstate.softUrlChange = true;\n\t\t}\n\t};\n\n\twindow.addEventListener(\"hashchange\", noteSoftNav);\n\twindow.addEventListener(\"popstate\", noteSoftNav);\n\n\tconst wrapHistory = (method: \"pushState\" | \"replaceState\"): void => {\n\t\tconst original = history[method].bind(history);\n\n\t\thistory[method] = ((...args: Parameters<History[\"pushState\"]>) => {\n\t\t\tconst result = original(...args);\n\t\t\tnoteSoftNav();\n\n\t\t\treturn result;\n\t\t}) as History[\"pushState\"];\n\t};\n\n\twrapHistory(\"pushState\");\n\twrapHistory(\"replaceState\");\n}\n\nexport type DrainContextObserverResult = {\n\topenedWindow: boolean;\n\tsubmittedForm: boolean;\n\tfocusRemoved: boolean;\n\tredirect: \"outside\" | \"same-subtree\" | null;\n\tsoftUrlChange: boolean;\n\tnavigation: boolean;\n\tattributedHtml: string | null;\n\t/** True when an attributed element was marked for selector resolution. */\n\thasAttributed: boolean;\n};\n\n/**\n * Drain observer signals for the current tab stop and reset per-stop flags.\n * Classification of focus removal / redirection uses the post-Tab settle\n * activeElement and the focusin history from this stop only.\n */\nexport function drainContextObserverScript(\n\tmarkerAttr: string,\n): DrainContextObserverResult {\n\t// Must be a string literal inside this function: it is serialized into the page.\n\tconst attributedAttr = \"data-a11y-ctx-attr\";\n\n\tconst empty: DrainContextObserverResult = {\n\t\topenedWindow: false,\n\t\tsubmittedForm: false,\n\t\tfocusRemoved: false,\n\t\tredirect: null,\n\t\tsoftUrlChange: false,\n\t\tnavigation: false,\n\t\tattributedHtml: null,\n\t\thasAttributed: false,\n\t};\n\n\tconst state = window.__a11yContextObserver;\n\n\tif (!state) {\n\t\treturn empty;\n\t}\n\n\tfor (const marked of Array.from(\n\t\tdocument.querySelectorAll(`[${attributedAttr}]`),\n\t)) {\n\t\tmarked.removeAttribute(attributedAttr);\n\t}\n\n\tconst openedWindow = state.openedWindow;\n\tconst submittedForm = state.submittedForm;\n\tconst softUrlChange = state.softUrlChange;\n\tconst focusIns = state.focusIns.slice();\n\n\tstate.openedWindow = false;\n\tstate.submittedForm = false;\n\tstate.softUrlChange = false;\n\tstate.focusIns = [];\n\n\tlet active = document.activeElement;\n\n\twhile (active?.shadowRoot?.activeElement) {\n\t\tactive = active.shadowRoot.activeElement;\n\t}\n\n\tconst intended =\n\t\tfocusIns.find(\n\t\t\t(el) => el !== document.body && el !== document.documentElement,\n\t\t) ?? null;\n\n\tconst openingHtml = (node: Element): string => {\n\t\tconst clone = node.cloneNode(false) as Element;\n\t\tclone.removeAttribute(markerAttr);\n\t\tclone.removeAttribute(attributedAttr);\n\n\t\treturn clone.outerHTML;\n\t};\n\n\tlet focusRemoved = false;\n\tlet redirect: \"outside\" | \"same-subtree\" | null = null;\n\tlet attributedHtml: string | null = null;\n\tlet hasAttributed = false;\n\n\tconst bodyOrNone =\n\t\t!active || active === document.body || active === document.documentElement;\n\n\tif (intended && bodyOrNone) {\n\t\tfocusRemoved = true;\n\t\tattributedHtml = openingHtml(intended);\n\t\tintended.setAttribute(attributedAttr, \"1\");\n\t\thasAttributed = true;\n\t} else if (intended && active && intended !== active) {\n\t\tconst composedContains = (ancestor: Element, node: Element): boolean => {\n\t\t\tlet current: Node | null = node;\n\n\t\t\twhile (current) {\n\t\t\t\tif (current === ancestor) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tconst parent: Node | null = current.parentNode;\n\n\t\t\t\tif (parent) {\n\t\t\t\t\tcurrent = parent;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (current instanceof ShadowRoot) {\n\t\t\t\t\tcurrent = current.host;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t};\n\n\t\tconst same =\n\t\t\tcomposedContains(intended, active) || composedContains(active, intended);\n\n\t\tredirect = same ? \"same-subtree\" : \"outside\";\n\t\tattributedHtml = openingHtml(intended);\n\t\tintended.setAttribute(attributedAttr, \"1\");\n\t\thasAttributed = true;\n\t}\n\n\treturn {\n\t\topenedWindow,\n\t\tsubmittedForm,\n\t\tfocusRemoved,\n\t\tredirect,\n\t\tsoftUrlChange,\n\t\tnavigation: false,\n\t\tattributedHtml,\n\t\thasAttributed,\n\t};\n}\n\n/** Return the element marked as attributed by drainContextObserverScript (the\n * element that received a focus event this stop and then lost it), if any. */\nexport function attributedHandleScript(): Element | null {\n\treturn document.querySelector(\"[data-a11y-ctx-attr]\");\n}\n\nexport function clearAttributedScript(): void {\n\tfor (const marked of Array.from(\n\t\tdocument.querySelectorAll(\"[data-a11y-ctx-attr]\"),\n\t)) {\n\t\tmarked.removeAttribute(\"data-a11y-ctx-attr\");\n\t}\n}\n\n/**\n * Drop focusin history accumulated after drain (e.g. pixel-diff blur/refocus)\n * so the next tab stop does not mis-attribute F55 or redirects.\n */\nexport function clearContextFocusInsScript(): void {\n\tconst state = window.__a11yContextObserver;\n\n\tif (state) {\n\t\tstate.focusIns = [];\n\t\tstate.openedWindow = false;\n\t\tstate.submittedForm = false;\n\t\tstate.softUrlChange = false;\n\t}\n}\n\n/** Current location.href for navigation comparison in the host. */\nexport function locationHrefScript(): string {\n\treturn location.href;\n}\n","import type { Rect } from \"./adaptor\";\n\n/**\n * A screenshot clip framing `rect` with up to `buffer` pixels of padding on each side, shrunk\n * where the page edges leave less room. The padding allows for indicators drawn just outside\n * the element box (outlines, shadows) and for anti-aliasing.\n */\nexport function bufferedClip(\n\trect: Rect,\n\tpageWidth: number,\n\tpageHeight: number,\n\tbuffer: number,\n): Rect {\n\tconst left = Math.max(0, Math.min(buffer, rect.x));\n\tconst top = Math.max(0, Math.min(buffer, rect.y));\n\tconst right = Math.max(0, Math.min(buffer, pageWidth - rect.x - rect.width));\n\tconst bottom = Math.max(\n\t\t0,\n\t\tMath.min(buffer, pageHeight - rect.y - rect.height),\n\t);\n\n\t// Clamp to non-negative origins: an element positioned partially off the top\n\t// or left of the document has a negative page-relative rect, and Puppeteer\n\t// rejects a screenshot clip with negative x/y.\n\treturn {\n\t\tx: Math.max(0, rect.x - left),\n\t\ty: Math.max(0, rect.y - top),\n\t\twidth: rect.width + left + right,\n\t\theight: rect.height + top + bottom,\n\t};\n}\n","/**\n * Computed-style properties that are likely to draw a visible focus indicator. Layout properties\n * like margin and padding are deliberately excluded.\n */\nexport const FOCUS_STYLE_PROPERTIES = [\n\t\"background-color\",\n\t\"background-image\",\n\t\"border-bottom-color\",\n\t\"border-bottom-style\",\n\t\"border-bottom-width\",\n\t\"border-left-color\",\n\t\"border-left-style\",\n\t\"border-left-width\",\n\t\"border-right-color\",\n\t\"border-right-style\",\n\t\"border-right-width\",\n\t\"border-top-color\",\n\t\"border-top-style\",\n\t\"border-top-width\",\n\t\"box-shadow\",\n\t\"color\",\n\t\"font-weight\",\n\t\"outline-color\",\n\t\"outline-style\",\n\t\"outline-width\",\n\t\"text-decoration\",\n] as const;\n","/**\n * Build a compact, hopefully-unique selector for any given element on the page. This function is\n * serialized and run in the page context, so it must not reference any symbols outside its own\n * scope.\n *\n * Mirrors axe-core's approach: each level contributes the fewest features that discriminate the\n * element (a unique id, the rarest single class, or an :nth-of-type position), and the walk stops\n * as soon as the joined selector matches exactly one element. Selectors stay short because of\n * that early stop, not because of truncation; the length budget is only a backstop.\n */\nexport function getSelector(root: Node | null): string {\n\tconst MAX_LENGTH = 128;\n\n\tconst esc = (value: string): string =>\n\t\ttypeof CSS !== \"undefined\" && typeof CSS.escape === \"function\"\n\t\t\t? CSS.escape(value)\n\t\t\t: value;\n\n\tconst tagName = (node: Node): string =>\n\t\tnode.nodeType === 1\n\t\t\t? node.nodeName.toLowerCase()\n\t\t\t: node.nodeName.toUpperCase().replace(/^#/, \"\");\n\n\t// A querySelectorAll-capable root (Document or ShadowRoot) for the element,\n\t// used to confirm uniqueness and class rarity. Absent on the plain objects\n\t// used in the serialisation unit tests, where we trust ids and walk to the\n\t// top instead of stopping early.\n\tconst rootOf = (element: Element): ParentNode | null => {\n\t\tconst node = (\n\t\t\telement as Element & { getRootNode?: () => Node }\n\t\t).getRootNode?.();\n\n\t\treturn node && typeof (node as ParentNode).querySelectorAll === \"function\"\n\t\t\t? (node as ParentNode)\n\t\t\t: null;\n\t};\n\n\tconst matchCount = (queryRoot: ParentNode, selector: string): number => {\n\t\ttry {\n\t\t\treturn queryRoot.querySelectorAll(selector).length;\n\t\t} catch {\n\t\t\t// A selector that fails to parse can't be relied on.\n\t\t\treturn Number.POSITIVE_INFINITY;\n\t\t}\n\t};\n\n\t// A candidate feature is only usable if it actually selects this element;\n\t// an escaping or engine mismatch (e.g. CSS string escapes in an attribute\n\t// value) could otherwise produce a selector that matches nothing — or a\n\t// different element entirely.\n\tconst safeMatches = (element: Element, selector: string): boolean => {\n\t\ttry {\n\t\t\treturn typeof element.matches === \"function\" && element.matches(selector);\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t};\n\n\tconst idIsUnique = (element: Element, id: string): boolean => {\n\t\tconst queryRoot = rootOf(element);\n\n\t\treturn queryRoot === null || matchCount(queryRoot, `#${esc(id)}`) === 1;\n\t};\n\n\t// A discriminating feature for one level of the selector: its CSS text plus\n\t// a predicate telling whether a sibling would match the same feature (used\n\t// to decide if an :nth-of-type pin is still needed).\n\ttype Feature = {\n\t\tfeature: string;\n\t\tsharedBy: (sibling: Element) => boolean;\n\t};\n\n\tconst classFeature = (cls: string): Feature => ({\n\t\tfeature: `.${esc(cls)}`,\n\t\tsharedBy: (sibling) => Array.from(sibling.classList ?? []).includes(cls),\n\t});\n\n\t// The single feature that narrows the element down the most: the class or\n\t// href attribute with the fewest matches in the root. Hrefs break ties\n\t// between structurally-identical content blocks, where classes and\n\t// :nth-of-type (which only pins position within one parent) cannot. Without\n\t// a queryable root there is no rarity information, so the first class\n\t// stands in.\n\tconst rarestFeature = (\n\t\telement: Element,\n\t\tqueryRoot: ParentNode | null,\n\t): Feature | null => {\n\t\tconst classes = Array.from(element.classList).slice(0, 8);\n\n\t\tif (!queryRoot) {\n\t\t\tconst cls = classes[0];\n\n\t\t\treturn cls === undefined ? null : classFeature(cls);\n\t\t}\n\n\t\tlet best: Feature | null = null;\n\t\tlet bestCount = Number.POSITIVE_INFINITY;\n\n\t\tfor (const cls of classes) {\n\t\t\tconst candidate = classFeature(cls);\n\n\t\t\tif (!safeMatches(element, candidate.feature)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst count = matchCount(queryRoot, candidate.feature);\n\n\t\t\tif (count < bestCount) {\n\t\t\t\tbest = candidate;\n\t\t\t\tbestCount = count;\n\t\t\t}\n\n\t\t\tif (count === 1) {\n\t\t\t\treturn best;\n\t\t\t}\n\t\t}\n\n\t\tconst href =\n\t\t\ttypeof element.getAttribute === \"function\"\n\t\t\t\t? element.getAttribute(\"href\")\n\t\t\t\t: null;\n\n\t\t// Skip hrefs with characters that change meaning inside a CSS string\n\t\t// (quotes, backslashes), and query strings, which are too volatile\n\t\t// across scans to pin a selector to. Fragments (#main) stay eligible —\n\t\t// skip links make stable discriminators.\n\t\tif (href && href.length <= 100 && !/[\"\\\\?]/.test(href)) {\n\t\t\tconst feature = `[href=\"${href}\"]`;\n\n\t\t\tif (\n\t\t\t\tsafeMatches(element, feature) &&\n\t\t\t\tmatchCount(queryRoot, feature) < bestCount\n\t\t\t) {\n\t\t\t\treturn {\n\t\t\t\t\tfeature,\n\t\t\t\t\tsharedBy: (sibling) =>\n\t\t\t\t\t\ttypeof sibling.getAttribute === \"function\" &&\n\t\t\t\t\t\tsibling.getAttribute(\"href\") === href,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn best;\n\t};\n\n\t// The element's 1-based position among same-tag siblings, and whether the\n\t// chosen feature fails to discriminate it from them (so the segment needs\n\t// an :nth-of-type pin). Siblings are absent on the serialisation test\n\t// nodes — there we skip the pin.\n\tconst positionAmongSiblings = (\n\t\telement: Element,\n\t\tsharedBy: (sibling: Element) => boolean,\n\t): { nth: number; ambiguous: boolean } => {\n\t\tconst siblings = (element.parentNode as ParentNode | null)?.children;\n\n\t\tif (!siblings) {\n\t\t\treturn { nth: 0, ambiguous: false };\n\t\t}\n\n\t\tlet nth = 0;\n\t\tlet count = 0;\n\t\tlet shared = 0;\n\n\t\tfor (const sibling of Array.from(siblings)) {\n\t\t\tif (sibling.nodeName !== element.nodeName) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcount++;\n\n\t\t\tif (sibling === element) {\n\t\t\t\tnth = count;\n\t\t\t}\n\n\t\t\tif (sharedBy(sibling)) {\n\t\t\t\tshared++;\n\t\t\t}\n\t\t}\n\n\t\treturn { nth, ambiguous: shared > 1 };\n\t};\n\n\tconst segmentFor = (\n\t\telement: Element,\n\t\tqueryRoot: ParentNode | null,\n\t): { segment: string; anchored: boolean } => {\n\t\t// Only treat an id as an absolute anchor when it actually resolves to a\n\t\t// single element: pages with duplicate ids would otherwise yield a\n\t\t// selector (e.g. \"#dup>a\") that matches several elements.\n\t\tif (element.id && idIsUnique(element, element.id)) {\n\t\t\treturn { segment: `#${esc(element.id)}`, anchored: true };\n\t\t}\n\n\t\tconst feature = rarestFeature(element, queryRoot);\n\t\tlet segment = tagName(element) + (feature === null ? \"\" : feature.feature);\n\n\t\t// When same-tag siblings share the chosen feature, pin the position so the\n\t\t// segment selects exactly this element rather than all of them.\n\t\tconst { nth, ambiguous } = positionAmongSiblings(\n\t\t\telement,\n\t\t\tfeature === null ? () => true : feature.sharedBy,\n\t\t);\n\n\t\tif (ambiguous && nth > 0) {\n\t\t\tsegment += `:nth-of-type(${nth})`;\n\t\t}\n\n\t\treturn { segment, anchored: false };\n\t};\n\n\t// A minimal segment for when a level's full segment would blow the budget\n\t// (e.g. an enormous class name or a long href): just the tag, pinned by\n\t// position when same-tag siblings would make the bare tag ambiguous.\n\tconst degradedSegmentFor = (element: Element): string => {\n\t\tlet segment = tagName(element);\n\n\t\tconst { nth, ambiguous } = positionAmongSiblings(element, () => true);\n\n\t\tif (ambiguous && nth > 0) {\n\t\t\tsegment += `:nth-of-type(${nth})`;\n\t\t}\n\n\t\treturn segment;\n\t};\n\n\tconst segments: string[] = [];\n\tlet node: Node | null = root;\n\tconst queryRoot =\n\t\troot && root.nodeType === 1 ? rootOf(root as Element) : null;\n\n\ttry {\n\t\t// Walk only element nodes. Stopping at the first non-element parent (the\n\t\t// document, or a ShadowRoot when the target is inside an open shadow root)\n\t\t// keeps the selector within its tree and avoids reading `classList` off a\n\t\t// node that has none.\n\t\twhile (node && node.nodeType === 1) {\n\t\t\tconst element = node as Element;\n\t\t\tlet { segment, anchored } = segmentFor(element, queryRoot);\n\n\t\t\t// Keep within the budget (the +1 accounts for the \">\" that would join\n\t\t\t// this segment to the rest). A level whose full segment doesn't fit is\n\t\t\t// degraded to tag + position rather than discarded, so ancestor context\n\t\t\t// is never lost to one long feature.\n\t\t\tconst joinedWith = (candidate: string): number =>\n\t\t\t\tsegments.length\n\t\t\t\t\t? candidate.length + 1 + segments.join(\">\").length\n\t\t\t\t\t: candidate.length;\n\n\t\t\tif (joinedWith(segment) > MAX_LENGTH - 1) {\n\t\t\t\tsegment = degradedSegmentFor(element);\n\t\t\t\tanchored = false;\n\n\t\t\t\tif (joinedWith(segment) > MAX_LENGTH - 1) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsegments.unshift(segment);\n\n\t\t\tif (anchored) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Stop as soon as the selector already identifies a single element —\n\t\t\t// this, not truncation, is what keeps selectors short.\n\t\t\tif (queryRoot && matchCount(queryRoot, segments.join(\">\")) === 1) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tnode = element.parentNode;\n\t\t}\n\t} catch {\n\t\t// A malformed node tree must never crash the audit; return what we have.\n\t}\n\n\treturn segments.join(\">\");\n}\n","const DEFAULT_MAX_ATTRIBUTE_VALUE_LENGTH = 50;\nconst DEFAULT_MAX_LENGTH = 300;\nconst ELLIPSIS = \"...\";\n\nexport type TruncateHtmlOptions = {\n\tmaxAttributeValueLength?: number;\n\tmaxLength?: number;\n};\n\n/**\n * Given an element's outerHTML, produce a truncated version suitable for display in results. For\n * memory efficiency, pass a shallow outerHTML i.e. `Node.cloneNode(false).outerHTML`.\n */\nexport function truncateHtml(\n\thtml: string,\n\toptions: TruncateHtmlOptions = {},\n): string {\n\tif (!html) {\n\t\treturn \"\";\n\t}\n\n\tconst maxAttributeValueLength =\n\t\toptions.maxAttributeValueLength ?? DEFAULT_MAX_ATTRIBUTE_VALUE_LENGTH;\n\tconst maxLength = options.maxLength ?? DEFAULT_MAX_LENGTH;\n\n\t// Keep only the opening tag\n\tconst closingBracket = html.indexOf(\">\");\n\tconst openingTag =\n\t\tclosingBracket === -1 ? html : html.slice(0, closingBracket + 1);\n\n\t// Shorten long quoted attribute values, preserving the quote style.\n\tconst trimmed = openingTag.replace(\n\t\t/=([\"'])([\\s\\S]*?)\\1/g,\n\t\t(match, quote: string, value: string) => {\n\t\t\tif (value.length <= maxAttributeValueLength) {\n\t\t\t\treturn match;\n\t\t\t}\n\n\t\t\treturn `=${quote}${value.slice(0, maxAttributeValueLength)}${ELLIPSIS}${quote}`;\n\t\t},\n\t);\n\n\tif (trimmed.length > maxLength) {\n\t\treturn `${trimmed.slice(0, maxLength)}${ELLIPSIS}`;\n\t}\n\n\treturn trimmed;\n}\n","import type { BrowserAdaptor, ElementRef } from \"./adaptor\";\nimport {\n\tblurScript,\n\telementRectScript,\n\telementStylesScript,\n\tfocusScript,\n\tisCenterObscuredScript,\n\tpageDimensionsScript,\n\tscrollToCenterScript,\n} from \"./browser-scripts\";\nimport { bufferedClip } from \"./clip\";\nimport type { UnfocusedPair } from \"./types\";\n\nexport type CaptureUnfocusedPairOptions = {\n\tscreenshotSettleDelay: number;\n\tscreenshotClipBuffer: number;\n\tstyleProps: readonly string[];\n};\n\n/**\n * Capture focused and unfocused screenshots of the same element, plus the\n * unfocused style snapshot and clip anchors appearance needs to score later.\n *\n * The caller owns `handle` and must dispose it after this promise settles.\n */\nexport async function captureUnfocusedPair(\n\tadaptor: BrowserAdaptor,\n\toptions: CaptureUnfocusedPairOptions,\n\thandle: ElementRef,\n): Promise<UnfocusedPair> {\n\t// Tab scrolls an element just barely into view at the viewport edge, which\n\t// is exactly where fixed overlays (cookie banners, sticky footers) sit. If\n\t// something covers the element there, both screenshots would show the\n\t// overlay and no indicator could ever be detected. Centre the element in\n\t// the viewport first, then give the scroll a moment to settle.\n\tif (await adaptor.evaluate(isCenterObscuredScript, handle)) {\n\t\tawait adaptor.evaluate(scrollToCenterScript, handle);\n\n\t\tawait new Promise((resolve) =>\n\t\t\tsetTimeout(resolve, options.screenshotSettleDelay),\n\t\t);\n\t}\n\n\tconst { width: pageWidth, height: pageHeight } =\n\t\tawait adaptor.evaluate(pageDimensionsScript);\n\n\tconst focusedRect = await adaptor.evaluate(elementRectScript, handle);\n\tconst focusedClip = bufferedClip(\n\t\tfocusedRect,\n\t\tpageWidth,\n\t\tpageHeight,\n\t\toptions.screenshotClipBuffer,\n\t);\n\n\tconst scale = adaptor.screenshotClipScale ?? 1;\n\n\t// Capture the focused state first, while focus is genuine: re-focusing the\n\t// element afterwards cannot always restore it (the host of a closed shadow\n\t// root cannot push focus back inside), so the focused frame must be taken\n\t// before blurring.\n\tconst focusedScreenshot = await adaptor.screenshotClip(focusedClip, scale);\n\n\tawait adaptor.evaluate(blurScript, handle);\n\n\t// Measure the unfocused rect after blurring rather than reusing a stale\n\t// baseline rect: a :focus rule may have moved the element, and a\n\t// fixed-position element's page-relative rect changes with every scroll.\n\tconst unfocusedRect = await adaptor.evaluate(elementRectScript, handle);\n\tconst unfocusedClip = bufferedClip(\n\t\tunfocusedRect,\n\t\tpageWidth,\n\t\tpageHeight,\n\t\toptions.screenshotClipBuffer,\n\t);\n\n\tconst unfocusedScreenshot = await adaptor.screenshotClip(\n\t\tunfocusedClip,\n\t\tscale,\n\t);\n\n\tconst unfocusedStyles = await adaptor.evaluate(elementStylesScript, handle, [\n\t\t...options.styleProps,\n\t]);\n\n\t// Restore focus so the next Tab advances from this element rather than\n\t// restarting traversal. (A closed-shadow host can't be re-focused into the\n\t// root; the loop still progresses because Tab re-enters from there.)\n\tawait adaptor.evaluate(focusScript, handle);\n\n\treturn {\n\t\tfocusedScreenshot,\n\t\tunfocusedScreenshot,\n\t\tunfocusedStyles,\n\t\tfocusedRect,\n\t\tunfocusedRect,\n\t\tfocusedClip,\n\t\tunfocusedClip,\n\t\tscale,\n\t};\n}\n","import type { BrowserAdaptor, ElementRef } from \"./adaptor\";\nimport {\n\ttype ActiveElementBase,\n\tactiveElementHandleScript,\n\tattributedHandleScript,\n\tbaselineScript,\n\tclearAttributedScript,\n\tclearContextFocusInsScript,\n\tclearMarkersScript,\n\tclearObscurerScript,\n\ttype DrainContextObserverResult,\n\tdrainContextObserverScript,\n\tinstallContextObserverScript,\n\tlocationHrefScript,\n\tmeasureObscuringScript,\n\tobscurerHandleScript,\n\tprobeActiveElementScript,\n} from \"./browser-scripts\";\nimport { FOCUS_STYLE_PROPERTIES } from \"./focus-style\";\nimport { getSelector } from \"./get-selector\";\nimport { truncateHtml } from \"./truncate-html\";\nimport type {\n\tActiveElementInfo,\n\tCapability,\n\tContextChangeSignals,\n\tSessionEndReason,\n\tStyleSnapshot,\n\tTabConsumer,\n\tTabSessionHandle,\n\tTabStopSnapshot,\n\tUnfocusedPair,\n} from \"./types\";\nimport { captureUnfocusedPair } from \"./unfocused-pair\";\n\n/**\n * Whether an `evaluate()` rejection looks like the page navigated out from\n * under it (execution context destroyed) rather than an unexpected failure.\n * A full navigation is the one context-change signal the in-page observer\n * can never self-report: it destroys the JS context before it can log\n * anything, so the host has to infer it from how `evaluate()` failed.\n */\nfunction isContextDestroyedError(error: unknown): boolean {\n\tconst message = error instanceof Error ? error.message : String(error);\n\treturn /Execution context was destroyed|Target closed|frame was detached|navigat/i.test(\n\t\tmessage,\n\t);\n}\n\n/**\n * Outcome of the early, pre-isBody navigation check. `navigation: true`\n * means a full navigation was detected (via href diff or a destroyed-context\n * error) and the caller must end the session without proceeding any\n * further. Otherwise `raw` carries a drain payload already fetched while\n * resolving a soft URL change (so the later full drain can reuse it instead\n * of reading back state the first call already reset), or `null` when the\n * href was unchanged and nothing has been drained yet for this stop.\n */\ntype ContextNavigationOutcome =\n\t| { navigation: true }\n\t| { navigation: false; raw: DrainContextObserverResult | null };\n\nexport const DEFAULT_SCREENSHOT_SETTLE_DELAY = 33;\nexport const DEFAULT_SCREENSHOT_CLIP_BUFFER = 10;\nexport const DEFAULT_MARKER_LIMIT = 1024;\nexport const MARKER_ATTR = \"data-a11y-focus-idx\";\nexport const OBSCURER_ATTR = \"data-a11y-obscurer\";\nexport const OBSCURING_RECHECK_DELAY_MS = 250;\n\nexport type TabSessionOptions = {\n\tscreenshotSettleDelay?: number;\n\tscreenshotClipBuffer?: number;\n\tmarkerLimit?: number;\n\tbaselineElementLimit?: number;\n};\n\nexport type TabOrchestrator = {\n\tattach(consumer: TabConsumer): void;\n\trun(): Promise<void>;\n};\n\nexport function createTabOrchestrator(\n\tadaptor: BrowserAdaptor,\n\toptions: TabSessionOptions = {},\n): TabOrchestrator {\n\tconst consumers: TabConsumer[] = [];\n\tlet started = false;\n\tlet ran = false;\n\n\treturn {\n\t\tattach(consumer) {\n\t\t\tif (started) {\n\t\t\t\tthrow new Error(\"Cannot attach after run() has started\");\n\t\t\t}\n\t\t\tconsumers.push(consumer);\n\t\t},\n\t\tasync run() {\n\t\t\tif (ran) {\n\t\t\t\tthrow new Error(\"run() has already been called\");\n\t\t\t}\n\t\t\tran = true;\n\t\t\tstarted = true;\n\n\t\t\tif (consumers.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst attached = new Set(consumers);\n\t\t\tconst screenshotSettleDelay =\n\t\t\t\toptions.screenshotSettleDelay ?? DEFAULT_SCREENSHOT_SETTLE_DELAY;\n\t\t\tconst screenshotClipBuffer =\n\t\t\t\toptions.screenshotClipBuffer ?? DEFAULT_SCREENSHOT_CLIP_BUFFER;\n\t\t\tconst markerLimit = Math.max(\n\t\t\t\toptions.markerLimit ?? DEFAULT_MARKER_LIMIT,\n\t\t\t\toptions.baselineElementLimit ?? 0,\n\t\t\t);\n\t\t\tconst styleProps = [...FOCUS_STYLE_PROPERTIES];\n\t\t\tconst resolved = {\n\t\t\t\tscreenshotSettleDelay,\n\t\t\t\tscreenshotClipBuffer,\n\t\t\t\tstyleProps,\n\t\t\t};\n\n\t\t\tlet settleTimer: ReturnType<typeof setTimeout> | undefined;\n\t\t\tlet resolveSettle: (() => void) | undefined;\n\t\t\tconst pairByStop = { current: null as Promise<UnfocusedPair> | null };\n\t\t\tlet activeHandle: ElementRef | undefined;\n\t\t\tlet lastHasAttributed = false;\n\t\t\t// Captured when observers are installed and re-armed after every\n\t\t\t// detected soft URL change, so repeated soft navigations across stops\n\t\t\t// compare against the most recent href rather than the original load.\n\t\t\tlet baselineHref: string | null = null;\n\n\t\t\tconst remainingHas = (capability: Capability): boolean =>\n\t\t\t\t[...attached].some((c) => c.capabilities.has(capability));\n\n\t\t\t// Decided once from who is attached at session start; never re-checked,\n\t\t\t// so the observer stays installed even after every declarer disconnects\n\t\t\t// (session-lifetime setup is never uninstalled, only skipped per-stop).\n\t\t\tconst contextSignalsWanted = remainingHas(\"contextSignals\");\n\n\t\t\tconst handleFor = (consumer: TabConsumer): TabSessionHandle => ({\n\t\t\t\tdisconnect() {\n\t\t\t\t\tattached.delete(consumer);\n\t\t\t\t\tif (attached.size === 0 && settleTimer !== undefined) {\n\t\t\t\t\t\tclearTimeout(settleTimer);\n\t\t\t\t\t\tsettleTimer = undefined;\n\t\t\t\t\t\tresolveSettle?.();\n\t\t\t\t\t\tresolveSettle = undefined;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tensureUnfocusedPair: () => {\n\t\t\t\t\tif (!consumer.capabilities.has(\"unfocusedPair\")) {\n\t\t\t\t\t\tthrow new Error(\"Consumer did not declare unfocusedPair\");\n\t\t\t\t\t}\n\t\t\t\t\tif (!remainingHas(\"unfocusedPair\")) {\n\t\t\t\t\t\tthrow new Error(\"Consumer did not declare unfocusedPair\");\n\t\t\t\t\t}\n\t\t\t\t\tif (activeHandle === undefined) {\n\t\t\t\t\t\tthrow new Error(\"unfocusedPair capture not implemented\");\n\t\t\t\t\t}\n\t\t\t\t\tpairByStop.current ??= captureUnfocusedPair(\n\t\t\t\t\t\tadaptor,\n\t\t\t\t\t\tresolved,\n\t\t\t\t\t\tactiveHandle,\n\t\t\t\t\t);\n\t\t\t\t\treturn pairByStop.current;\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tconst end = (reason: SessionEndReason): void => {\n\t\t\t\tfor (const consumer of attached) {\n\t\t\t\t\tconsumer.onSessionEnd?.(reason);\n\t\t\t\t}\n\t\t\t\tattached.clear();\n\t\t\t};\n\n\t\t\t/**\n\t\t\t * Primary navigation detection layer: compares `location.href` against\n\t\t\t * `baselineHref` on every stop, since a full navigation destroys the\n\t\t\t * in-page observer's execution context before it can self-report\n\t\t\t * anything (`drainContextObserverScript`'s own `navigation` field is\n\t\t\t * always `false`). A destroyed context can also simply throw instead\n\t\t\t * of returning a changed href (e.g. the navigation completes between\n\t\t\t * the href read and the drain read), which is treated the same way.\n\t\t\t *\n\t\t\t * Must run before the caller's `isBody`/\"done tabbing\" exit check: a\n\t\t\t * freshly-navigated page's `document.activeElement` defaults to\n\t\t\t * `document.body` unless the new page autofocuses something, so\n\t\t\t * without this proactive check a silent navigation would otherwise be\n\t\t\t * misclassified as `\"completed\"`.\n\t\t\t *\n\t\t\t * Deliberately cheap on the common (non-navigating) path: it only\n\t\t\t * reads `location.href` and does not call `drainContextObserverScript`\n\t\t\t * unless the href actually changed, so a stop that ends the session\n\t\t\t * via the isBody exit right after this check still drains at most\n\t\t\t * once overall (at the later, full-mapping call site).\n\t\t\t */\n\t\t\tasync function checkContextNavigation(): Promise<ContextNavigationOutcome> {\n\t\t\t\tlet href: string;\n\t\t\t\ttry {\n\t\t\t\t\thref = await adaptor.evaluate(locationHrefScript);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!isContextDestroyedError(error)) {\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t\treturn { navigation: true };\n\t\t\t\t}\n\n\t\t\t\tif (baselineHref === null || href === baselineHref) {\n\t\t\t\t\treturn { navigation: false, raw: null };\n\t\t\t\t}\n\n\t\t\t\t// Document navigated (or soft URL change). Prefer the observer's\n\t\t\t\t// own soft-nav flag when the execution context survived;\n\t\t\t\t// otherwise treat it as a full navigation.\n\t\t\t\tlet raw: DrainContextObserverResult | null = null;\n\t\t\t\ttry {\n\t\t\t\t\traw = await adaptor.evaluate(drainContextObserverScript, MARKER_ATTR);\n\t\t\t\t} catch {\n\t\t\t\t\traw = null;\n\t\t\t\t}\n\n\t\t\t\tif (raw === null || !raw.softUrlChange) {\n\t\t\t\t\treturn { navigation: true };\n\t\t\t\t}\n\n\t\t\t\tbaselineHref = href;\n\t\t\t\treturn { navigation: false, raw };\n\t\t\t}\n\n\t\t\tlet failure: unknown;\n\t\t\ttry {\n\t\t\t\tawait adaptor.ensureFocusReporting();\n\n\t\t\t\tconst payload = await adaptor.evaluate(\n\t\t\t\t\tbaselineScript,\n\t\t\t\t\tstyleProps,\n\t\t\t\t\tMARKER_ATTR,\n\t\t\t\t\tmarkerLimit,\n\t\t\t\t);\n\t\t\t\tconst interned = new Map<number, StyleSnapshot>();\n\t\t\t\tfor (const entry of payload.entries) {\n\t\t\t\t\tconst styles = payload.styles[entry.styleIndex];\n\t\t\t\t\tif (styles !== undefined) {\n\t\t\t\t\t\tinterned.set(entry.index, styles);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (contextSignalsWanted) {\n\t\t\t\t\tbaselineHref = await adaptor.evaluate(locationHrefScript);\n\t\t\t\t\tawait adaptor.evaluate(installContextObserverScript);\n\t\t\t\t}\n\n\t\t\t\tfor (const consumer of [...attached]) {\n\t\t\t\t\tawait consumer.onSessionStart?.(handleFor(consumer));\n\t\t\t\t}\n\n\t\t\t\tconst visited = new Set<number>();\n\t\t\t\tlet tabIndex = 0;\n\n\t\t\t\twhile (attached.size > 0) {\n\t\t\t\t\tpairByStop.current = null;\n\t\t\t\t\tlastHasAttributed = false;\n\n\t\t\t\t\tconst hasFocus = await adaptor.evaluate(() => document.hasFocus());\n\t\t\t\t\tif (!hasFocus) {\n\t\t\t\t\t\tend(\"lostFocus\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tawait adaptor.pressTab();\n\t\t\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\t\t\tresolveSettle = resolve;\n\t\t\t\t\t\tsettleTimer = setTimeout(() => {\n\t\t\t\t\t\t\tsettleTimer = undefined;\n\t\t\t\t\t\t\tresolveSettle = undefined;\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t}, screenshotSettleDelay);\n\t\t\t\t\t});\n\n\t\t\t\t\tif (attached.size === 0) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet base: ActiveElementBase | null;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tbase = await adaptor.evaluate(\n\t\t\t\t\t\t\tprobeActiveElementScript,\n\t\t\t\t\t\t\tstyleProps,\n\t\t\t\t\t\t\tMARKER_ATTR,\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tremainingHas(\"contextSignals\") &&\n\t\t\t\t\t\t\tisContextDestroyedError(error)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t// Mid-flight navigation destroyed the execution context\n\t\t\t\t\t\t\t// before the probe could even run: there is no active\n\t\t\t\t\t\t\t// element to report, so end directly (mirrors the\n\t\t\t\t\t\t\t// isBody/\"done tabbing\" exit below, which also ends\n\t\t\t\t\t\t\t// without a snapshot when there is nothing to notify).\n\t\t\t\t\t\t\tend(\"navigation\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Primary navigation detection layer, run before the isBody exit:\n\t\t\t\t\t// a silently-navigated page's evaluate() calls succeed against the\n\t\t\t\t\t// new document (Puppeteer/CDP targets whichever context is live at\n\t\t\t\t\t// call time), so a hard nav can surface as an ordinary `isBody: true`\n\t\t\t\t\t// probe result with no thrown error at all.\n\t\t\t\t\tlet contextNav: ContextNavigationOutcome | null = null;\n\t\t\t\t\tif (remainingHas(\"contextSignals\")) {\n\t\t\t\t\t\tconst outcome = await checkContextNavigation();\n\t\t\t\t\t\tif (outcome.navigation) {\n\t\t\t\t\t\t\tend(\"navigation\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontextNav = outcome;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (base === null || base.isBody) {\n\t\t\t\t\t\t// Focus landed on <body>. This is normally \"done tabbing\", but it\n\t\t\t\t\t\t// is also what F55 focus-removal looks like (an element receives\n\t\t\t\t\t\t// focus and then blurs itself, e.g. `onfocus=\"this.blur()\"`): the\n\t\t\t\t\t\t// in-page observer's focusin history still attributes that stop to\n\t\t\t\t\t\t// the element that briefly held focus, even though nothing is\n\t\t\t\t\t\t// focused now. Drain before ending so that case gets one last\n\t\t\t\t\t\t// notification instead of vanishing silently.\n\t\t\t\t\t\tif (remainingHas(\"contextSignals\")) {\n\t\t\t\t\t\t\tlet raw: DrainContextObserverResult;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\traw =\n\t\t\t\t\t\t\t\t\tcontextNav?.raw ??\n\t\t\t\t\t\t\t\t\t(await adaptor.evaluate(\n\t\t\t\t\t\t\t\t\t\tdrainContextObserverScript,\n\t\t\t\t\t\t\t\t\t\tMARKER_ATTR,\n\t\t\t\t\t\t\t\t\t));\n\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\tif (!isContextDestroyedError(error)) {\n\t\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Mirrors the probe's own destroyed-context catch above:\n\t\t\t\t\t\t\t\t// there is no attributed element left to report, so end\n\t\t\t\t\t\t\t\t// directly with \"navigation\" rather than \"completed\" (a\n\t\t\t\t\t\t\t\t// navigation signal always ends the session that way).\n\t\t\t\t\t\t\t\tend(\"navigation\");\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (raw.hasAttributed) {\n\t\t\t\t\t\t\t\tconst attributedRef = await adaptor.evaluateHandle(\n\t\t\t\t\t\t\t\t\tattributedHandleScript,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tlet selector: string;\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tselector = await adaptor.evaluate(getSelector, attributedRef);\n\t\t\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\t\t\tawait adaptor.disposeRef(attributedRef);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tconst activeElement: ActiveElementInfo = {\n\t\t\t\t\t\t\t\t\tindex: null,\n\t\t\t\t\t\t\t\t\tisBody: false,\n\t\t\t\t\t\t\t\t\tisIframe: false,\n\t\t\t\t\t\t\t\t\tselector,\n\t\t\t\t\t\t\t\t\thtml: truncateHtml(raw.attributedHtml ?? \"\"),\n\t\t\t\t\t\t\t\t\tstyles: { element: {}, before: {}, after: {} },\n\t\t\t\t\t\t\t\t\trect: { x: 0, y: 0, width: 0, height: 0 },\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\tconst snapshot: TabStopSnapshot = {\n\t\t\t\t\t\t\t\t\ttabIndex: ++tabIndex,\n\t\t\t\t\t\t\t\t\tactiveElement,\n\t\t\t\t\t\t\t\t\tcontextSignals: {\n\t\t\t\t\t\t\t\t\t\tsignals: {\n\t\t\t\t\t\t\t\t\t\t\topenedWindow: raw.openedWindow,\n\t\t\t\t\t\t\t\t\t\t\tsubmittedForm: raw.submittedForm,\n\t\t\t\t\t\t\t\t\t\t\tfocusRemoved: raw.focusRemoved,\n\t\t\t\t\t\t\t\t\t\t\tredirect: raw.redirect,\n\t\t\t\t\t\t\t\t\t\t\tsoftUrlChange: raw.softUrlChange,\n\t\t\t\t\t\t\t\t\t\t\tnavigation: raw.navigation,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t// This synthetic stop has no live focused element (it\n\t\t\t\t\t\t\t\t// already blurred itself before this notification is\n\t\t\t\t\t\t\t\t// built, by definition of F55), so capabilities that\n\t\t\t\t\t\t\t\t// need one (`unfocusedPair`, `baselineStyles`,\n\t\t\t\t\t\t\t\t// `obscuring`) have nothing to meaningfully act on.\n\t\t\t\t\t\t\t\t// Only consumers that declared `contextSignals` (the\n\t\t\t\t\t\t\t\t// capability this whole synthetic-stop mechanism exists\n\t\t\t\t\t\t\t\t// to serve) are notified; unlike every other stop in\n\t\t\t\t\t\t\t\t// this file, uniform notification is wrong here because\n\t\t\t\t\t\t\t\t// there is no element for the other capabilities to\n\t\t\t\t\t\t\t\t// read from.\n\t\t\t\t\t\t\t\tconst recipients = [...attached].filter((consumer) =>\n\t\t\t\t\t\t\t\t\tconsumer.capabilities.has(\"contextSignals\"),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tfor (const consumer of recipients) {\n\t\t\t\t\t\t\t\t\t\tawait consumer.onTabStop(snapshot, handleFor(consumer));\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\t\t\t// Guaranteed even if a recipient's onTabStop throws,\n\t\t\t\t\t\t\t\t\t// so the `data-a11y-ctx-attr` DOM marker never survives\n\t\t\t\t\t\t\t\t\t// past this stop (mirrors how `disposeRef` is\n\t\t\t\t\t\t\t\t\t// guaranteed via `finally` in the main per-stop loop\n\t\t\t\t\t\t\t\t\t// below).\n\t\t\t\t\t\t\t\t\tawait adaptor.evaluate(clearAttributedScript);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tend(\"completed\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (base.isIframe) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (base.index !== null) {\n\t\t\t\t\t\tif (visited.has(base.index)) {\n\t\t\t\t\t\t\tend(\"completed\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvisited.add(base.index);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst ref = await adaptor.evaluateHandle(activeElementHandleScript);\n\t\t\t\t\tactiveHandle = ref;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst selector = await adaptor.evaluate(getSelector, ref);\n\n\t\t\t\t\t\tconst activeElement: ActiveElementInfo = {\n\t\t\t\t\t\t\t...base,\n\t\t\t\t\t\t\thtml: truncateHtml(base.html),\n\t\t\t\t\t\t\tselector,\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst snapshot: TabStopSnapshot = {\n\t\t\t\t\t\t\ttabIndex: ++tabIndex,\n\t\t\t\t\t\t\tactiveElement,\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tremainingHas(\"baselineStyles\") &&\n\t\t\t\t\t\t\tactiveElement.index !== null\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tconst baselineStyles = interned.get(activeElement.index);\n\t\t\t\t\t\t\tif (baselineStyles !== undefined) {\n\t\t\t\t\t\t\t\tsnapshot.baselineStyles = baselineStyles;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (remainingHas(\"contextSignals\")) {\n\t\t\t\t\t\t\tlet signals: ContextChangeSignals;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t// Reuse the drain already fetched above while resolving\n\t\t\t\t\t\t\t\t// a soft URL change (checkContextNavigation), if any;\n\t\t\t\t\t\t\t\t// re-draining here would read back state that call\n\t\t\t\t\t\t\t\t// already reset (focusIns, softUrlChange, etc.) and\n\t\t\t\t\t\t\t\t// silently lose whatever it was reporting. Otherwise\n\t\t\t\t\t\t\t\t// (the common case: href unchanged, nothing drained\n\t\t\t\t\t\t\t\t// yet) do the one drain this stop needs.\n\t\t\t\t\t\t\t\tconst raw =\n\t\t\t\t\t\t\t\t\tcontextNav?.raw ??\n\t\t\t\t\t\t\t\t\t(await adaptor.evaluate(\n\t\t\t\t\t\t\t\t\t\tdrainContextObserverScript,\n\t\t\t\t\t\t\t\t\t\tMARKER_ATTR,\n\t\t\t\t\t\t\t\t\t));\n\t\t\t\t\t\t\t\tsignals = {\n\t\t\t\t\t\t\t\t\topenedWindow: raw.openedWindow,\n\t\t\t\t\t\t\t\t\tsubmittedForm: raw.submittedForm,\n\t\t\t\t\t\t\t\t\tfocusRemoved: raw.focusRemoved,\n\t\t\t\t\t\t\t\t\tredirect: raw.redirect,\n\t\t\t\t\t\t\t\t\tsoftUrlChange: raw.softUrlChange,\n\t\t\t\t\t\t\t\t\tnavigation: raw.navigation,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\tlastHasAttributed = raw.hasAttributed;\n\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\tif (!isContextDestroyedError(error)) {\n\t\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// The page navigated out from under the drain call: the\n\t\t\t\t\t\t\t\t// in-page observer's own state (and any DOM markers it\n\t\t\t\t\t\t\t\t// set) went with it, so there is nothing left to report\n\t\t\t\t\t\t\t\t// besides the navigation itself.\n\t\t\t\t\t\t\t\tsignals = {\n\t\t\t\t\t\t\t\t\topenedWindow: false,\n\t\t\t\t\t\t\t\t\tsubmittedForm: false,\n\t\t\t\t\t\t\t\t\tfocusRemoved: false,\n\t\t\t\t\t\t\t\t\tredirect: null,\n\t\t\t\t\t\t\t\t\tsoftUrlChange: false,\n\t\t\t\t\t\t\t\t\tnavigation: true,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\tlastHasAttributed = false;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tsnapshot.contextSignals = { signals };\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (remainingHas(\"obscuring\")) {\n\t\t\t\t\t\t\tlet raw = await adaptor.evaluate(\n\t\t\t\t\t\t\t\tmeasureObscuringScript,\n\t\t\t\t\t\t\t\tref,\n\t\t\t\t\t\t\t\tOBSCURER_ATTR,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tif (raw.fullyObscured) {\n\t\t\t\t\t\t\t\tawait new Promise((resolve) =>\n\t\t\t\t\t\t\t\t\tsetTimeout(resolve, OBSCURING_RECHECK_DELAY_MS),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\traw = await adaptor.evaluate(\n\t\t\t\t\t\t\t\t\tmeasureObscuringScript,\n\t\t\t\t\t\t\t\t\tref,\n\t\t\t\t\t\t\t\t\tOBSCURER_ATTR,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tlet obscuredBy: { selector: string; html: string } | null = null;\n\t\t\t\t\t\t\tif (raw.hasObscurer) {\n\t\t\t\t\t\t\t\tconst obscurer =\n\t\t\t\t\t\t\t\t\tawait adaptor.evaluateHandle(obscurerHandleScript);\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst obscurerSelector = await adaptor.evaluate(\n\t\t\t\t\t\t\t\t\t\tgetSelector,\n\t\t\t\t\t\t\t\t\t\tobscurer,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tobscuredBy = {\n\t\t\t\t\t\t\t\t\t\tselector: obscurerSelector,\n\t\t\t\t\t\t\t\t\t\thtml: truncateHtml(raw.obscuredByHtml ?? \"\"),\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\t\t\tawait adaptor.disposeRef(obscurer);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tsnapshot.obscuring = {\n\t\t\t\t\t\t\t\tcoveredFraction: raw.coveredFraction,\n\t\t\t\t\t\t\t\tfullyObscured: raw.fullyObscured,\n\t\t\t\t\t\t\t\toffscreen: raw.offscreen,\n\t\t\t\t\t\t\t\topacity: raw.opacity,\n\t\t\t\t\t\t\t\tobscuredBy,\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tawait adaptor.evaluate(clearObscurerScript, OBSCURER_ATTR);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst recipients = [...attached];\n\t\t\t\t\t\tfor (const consumer of recipients) {\n\t\t\t\t\t\t\tawait consumer.onTabStop(snapshot, handleFor(consumer));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (snapshot.contextSignals?.signals.navigation) {\n\t\t\t\t\t\t\tend(\"navigation\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t} finally {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tif (pairByStop.current !== null) {\n\t\t\t\t\t\t\t\tawait pairByStop.current;\n\n\t\t\t\t\t\t\t\tif (contextSignalsWanted) {\n\t\t\t\t\t\t\t\t\t// ensureUnfocusedPair blurred and re-focused the element to\n\t\t\t\t\t\t\t\t\t// capture the unfocused screenshot; drop that noise so the\n\t\t\t\t\t\t\t\t\t// next drain doesn't misread it as a real focus-removal or\n\t\t\t\t\t\t\t\t\t// redirect.\n\t\t\t\t\t\t\t\t\tawait adaptor.evaluate(clearContextFocusInsScript);\n\n\t\t\t\t\t\t\t\t\tif (lastHasAttributed) {\n\t\t\t\t\t\t\t\t\t\tawait adaptor.evaluate(clearAttributedScript);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Capture errors already surface through the consumer that\n\t\t\t\t\t\t\t// awaited; still dispose the handle below.\n\t\t\t\t\t\t}\n\t\t\t\t\t\tactiveHandle = undefined;\n\t\t\t\t\t\tawait adaptor.disposeRef(ref);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tfailure = error;\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tawait adaptor.evaluate(clearMarkersScript, MARKER_ATTR);\n\t\t\t\t} catch {\n\t\t\t\t\t// Isolate teardown so a marker-clear throw cannot replace the loop error.\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (failure !== undefined) {\n\t\t\t\tend(\"failed\");\n\t\t\t\tthrow failure;\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":"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","names":["opacity","node","queryRoot","DEFAULT_SCREENSHOT_SETTLE_DELAY"]}
1
+ {"version":3,"sources":["../src/audit-scaffold.ts","../src/browser-scripts.ts","../src/clip.ts","../src/focus-style.ts","../src/get-selector.ts","../src/capture-screenshot.ts","../src/truncate-html.ts","../src/unfocused-pair.ts","../src/orchestrator.ts"],"sourcesContent":["import type { SessionEndReason, TabSessionHandle } from \"./types\";\n\nexport const DEFAULT_ELEMENT_LIMIT = 1024;\nexport const DEFAULT_SCREENSHOT_SETTLE_DELAY = 33; // ~2 frames at 60fps\nexport const DEFAULT_FAILED_ELEMENT_LIMIT = 0; // 0 = never finish early\nexport const DEFAULT_TIMEOUT = 0; // 0 = no timeout\n\nexport type BaseAuditOptions = {\n\t/** Max focusable elements to tab through. */\n\telementLimit?: number;\n\t/** How long to wait (ms) after each Tab for the page to settle. */\n\tscreenshotSettleDelay?: number;\n\t/** Disconnect early after this many elements fail (0 = never). */\n\tfailedElementLimit?: number;\n\t/** Return whatever's gathered so far after this many ms (0 = no timeout). */\n\ttimeout?: number;\n};\n\nexport type BaseAuditSummary = {\n\tchecked: number;\n\tpassed: number;\n\tfailed: number;\n\t/** True if the element limit was hit before tabbing finished. */\n\treachedLimit: boolean;\n\t/** True if the audit stopped early after hitting `failedElementLimit`. */\n\treachedFailedElementLimit: boolean;\n\t/**\n\t * True if the audit returned early because `timeout` elapsed. The results\n\t * are whatever had been gathered when the deadline hit.\n\t */\n\ttimedOut: boolean;\n\t/**\n\t * Why the tab session ended, or `null` when this consumer disconnected\n\t * itself (element limit, failed-element limit, or timeout).\n\t */\n\tsessionEnd: SessionEndReason | null;\n};\n\nexport type AuditSelfDisconnect = {\n\t/** True once this consumer has disconnected itself from the session. */\n\treadonly disconnectedSelf: boolean;\n\t/** Arm a timeout that calls `onTimeout` then disconnects, if `timeout` is greater than 0. */\n\tarmTimeout(\n\t\ttimeout: number,\n\t\tsession: TabSessionHandle,\n\t\tonTimeout: () => void,\n\t): void;\n\t/** Disconnect the session and record that this consumer initiated it. */\n\tdisconnect(session: TabSessionHandle): void;\n\t/** Clear any pending timeout without disconnecting. */\n\tclear(): void;\n};\n\n/**\n * Arms an optional self-disconnecting timeout and tracks whether this\n * consumer initiated its own disconnect, so `onSessionEnd` can tell that\n * apart from an external end.\n */\nexport function createAuditSelfDisconnect(): AuditSelfDisconnect {\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet disconnectedSelf = false;\n\n\tconst clear = (): void => {\n\t\tif (timer !== undefined) {\n\t\t\tclearTimeout(timer);\n\t\t\ttimer = undefined;\n\t\t}\n\t};\n\n\tconst disconnect = (session: TabSessionHandle): void => {\n\t\tdisconnectedSelf = true;\n\t\tclear();\n\t\tsession.disconnect();\n\t};\n\n\treturn {\n\t\tget disconnectedSelf() {\n\t\t\treturn disconnectedSelf;\n\t\t},\n\t\tarmTimeout(timeout, session, onTimeout) {\n\t\t\tif (timeout > 0) {\n\t\t\t\ttimer = setTimeout(() => {\n\t\t\t\t\ttimer = undefined;\n\t\t\t\t\tonTimeout();\n\t\t\t\t\tdisconnect(session);\n\t\t\t\t}, timeout);\n\t\t\t}\n\t\t},\n\t\tdisconnect,\n\t\tclear,\n\t};\n}\n","/**\n * IMPORTANT: Functions in this file are serialized and injected into the audited page, so they\n * must not reference any symbols outside their own scope. This also means they cannot share code,\n * so any common logic (like descending into shadow roots) must be duplicated.\n */\n\nimport type { Rect } from \"./adaptor\";\nimport type { StyleSnapshot } from \"./types\";\n\ntype BaselineElementEntry = {\n\tindex: number;\n\t/** Position of this element's snapshot in the payload's `styles` table. */\n\tstyleIndex: number;\n\t/** The element's page-relative rect in its unfocused (baseline) state. */\n\trect: Rect;\n};\n\n/**\n * The baseline as a table of unique style snapshots plus per-element entries referencing them.\n * Elements overwhelmingly share identical snapshots (same classes), so interning keeps the\n * serialised payload O(unique styles) instead of O(elements × style size).\n */\nexport type BaselinePayload = {\n\tstyles: StyleSnapshot[];\n\tentries: BaselineElementEntry[];\n};\n\n/**\n * Find up to `limit` focusable elements and mark them with `markerAttr` and a unique index. Then\n * return a snapshot of their styles to use as a baseline.\n */\nexport function baselineScript(\n\tprops: string[],\n\tmarkerAttr: string,\n\tlimit: number,\n): BaselinePayload {\n\t// Bound oversized computed values (data-URI background images can run to hundreds of KB)\n\t// while preserving inequality via the length and a fingerprint of the full value. Must be\n\t// byte-identical to the copy in probeActiveElementScript, or every oversized value would\n\t// \"change\" on focus and produce a false style-check pass.\n\tconst truncateValue = (value: string): string => {\n\t\tconst MAX_STYLE_VALUE_LENGTH = 512;\n\n\t\tif (value.length <= MAX_STYLE_VALUE_LENGTH) {\n\t\t\treturn value;\n\t\t}\n\n\t\tlet hash = 5381;\n\n\t\tfor (let i = 0; i < value.length; i++) {\n\t\t\thash = ((hash * 33) ^ value.charCodeAt(i)) >>> 0;\n\t\t}\n\n\t\treturn `${value.slice(0, MAX_STYLE_VALUE_LENGTH)}#len=${value.length}#h=${hash.toString(36)}`;\n\t};\n\n\tconst snapshot = (el: Element): StyleSnapshot => {\n\t\tconst read = (pseudo: string | undefined): Record<string, string> => {\n\t\t\tconst cs = getComputedStyle(el, pseudo);\n\t\t\tconst out: Record<string, string> = {};\n\n\t\t\tfor (const prop of props) {\n\t\t\t\tout[prop] = truncateValue(cs.getPropertyValue(prop));\n\t\t\t}\n\n\t\t\tif (pseudo) {\n\t\t\t\tout.content = truncateValue(cs.getPropertyValue(\"content\"));\n\t\t\t}\n\n\t\t\treturn out;\n\t\t};\n\n\t\treturn {\n\t\t\telement: read(undefined),\n\t\t\tbefore: read(\"::before\"),\n\t\t\tafter: read(\"::after\"),\n\t\t};\n\t};\n\n\tconst candidates: Element[] = [];\n\tconst focusableSelector = [\n\t\t\"a[href]\",\n\t\t\"button\",\n\t\t\"input\",\n\t\t\"select\",\n\t\t\"textarea\",\n\t\t\"[tabindex]\",\n\t\t'[contenteditable=\"\"]',\n\t\t'[contenteditable=\"true\"]',\n\t].join(\", \");\n\n\t// Collect focusable candidates in document order, descending into open shadow roots.\n\tconst collect = (root: Document | ShadowRoot): void => {\n\t\tfor (const el of Array.from(root.querySelectorAll(\"*\"))) {\n\t\t\tif (el.matches(focusableSelector)) {\n\t\t\t\tcandidates.push(el);\n\t\t\t}\n\n\t\t\tif (el.shadowRoot) {\n\t\t\t\tcollect(el.shadowRoot);\n\t\t\t}\n\t\t}\n\t};\n\n\tcollect(document);\n\n\tconst styles: StyleSnapshot[] = [];\n\tconst styleIndexByKey = new Map<string, number>();\n\tconst entries: BaselineElementEntry[] = [];\n\tlet idx = 0;\n\n\tfor (const el of candidates) {\n\t\tif (idx >= limit) {\n\t\t\tbreak;\n\t\t}\n\n\t\tif (el.hasAttribute(\"disabled\")) {\n\t\t\t// Skip disabled elements\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ((el as HTMLElement).tabIndex < 0) {\n\t\t\t// Skip elements that are focusable but not in the tab order (negative\n\t\t\t// tabindex). The audit tabs through the page, so it never lands on them,\n\t\t\t// and counting them would waste the element-limit budget.\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Skip non-visible elements so they don't consume the marker budget (e.g.\n\t\t// links inside a closed mega-menu). checkVisibility sees hiding applied by\n\t\t// ancestors, which per-element computed styles don't (`display` doesn't\n\t\t// inherit); fall back to the element's own styles where it's unavailable.\n\t\tconst visibilityCheck = el as Element & {\n\t\t\tcheckVisibility?: (options?: { checkVisibilityCSS?: boolean }) => boolean;\n\t\t};\n\n\t\tif (typeof visibilityCheck.checkVisibility === \"function\") {\n\t\t\tif (!visibilityCheck.checkVisibility({ checkVisibilityCSS: true })) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t} else {\n\t\t\tconst cs = getComputedStyle(el);\n\n\t\t\tif (cs.display === \"none\" || cs.visibility === \"hidden\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Mark before measuring: the probe reads styles and rects while the marker\n\t\t// is present, so the baseline must be captured in the same DOM state.\n\t\tel.setAttribute(markerAttr, String(idx));\n\n\t\tconst rect = el.getBoundingClientRect();\n\n\t\t// Intern the snapshot: the JSON key is deterministic because every\n\t\t// snapshot is built with the same property insertion order.\n\t\tconst snap = snapshot(el);\n\t\tconst key = JSON.stringify(snap);\n\t\tlet styleIndex = styleIndexByKey.get(key);\n\n\t\tif (styleIndex === undefined) {\n\t\t\tstyleIndex = styles.length;\n\t\t\tstyles.push(snap);\n\t\t\tstyleIndexByKey.set(key, styleIndex);\n\t\t}\n\n\t\tentries.push({\n\t\t\tindex: idx,\n\t\t\tstyleIndex,\n\t\t\trect: {\n\t\t\t\tx: rect.left + window.scrollX,\n\t\t\t\ty: rect.top + window.scrollY,\n\t\t\t\twidth: rect.width,\n\t\t\t\theight: rect.height,\n\t\t\t},\n\t\t});\n\t\tidx++;\n\t}\n\n\treturn { styles, entries };\n}\n\nexport type ActiveElementBase = {\n\tindex: number | null;\n\tisBody: boolean;\n\t/**\n\t * The focused element is an <iframe>. Tabbing into a frame passes focus into\n\t * its embedded document, but the parent's document.activeElement is the frame\n\t * element itself, so the loop uses this to skip the frame as a tab stop.\n\t */\n\tisIframe: boolean;\n\thtml: string;\n\tstyles: StyleSnapshot;\n\trect: Rect;\n};\n\n/**\n * Read the currently focused element (descending open shadow roots), returning\n * its marker index, opening-tag HTML (marker attribute stripped), focus-relevant\n * styles, and page-relative rect.\n */\nexport function probeActiveElementScript(\n\tprops: string[],\n\tmarkerAttr: string,\n): ActiveElementBase {\n\tlet el = document.activeElement;\n\n\twhile (el?.shadowRoot?.activeElement) {\n\t\tel = el.shadowRoot.activeElement;\n\t}\n\n\tif (!el || el === document.body) {\n\t\treturn {\n\t\t\tindex: null,\n\t\t\tisBody: true,\n\t\t\tisIframe: false,\n\t\t\thtml: \"\",\n\t\t\tstyles: { element: {}, before: {}, after: {} },\n\t\t\trect: { x: 0, y: 0, width: 0, height: 0 },\n\t\t};\n\t}\n\n\t// Must be byte-identical to the copy in baselineScript: snapshots from the two scripts are\n\t// compared for equality, so they have to truncate oversized values the same way.\n\tconst truncateValue = (value: string): string => {\n\t\tconst MAX_STYLE_VALUE_LENGTH = 512;\n\n\t\tif (value.length <= MAX_STYLE_VALUE_LENGTH) {\n\t\t\treturn value;\n\t\t}\n\n\t\tlet hash = 5381;\n\n\t\tfor (let i = 0; i < value.length; i++) {\n\t\t\thash = ((hash * 33) ^ value.charCodeAt(i)) >>> 0;\n\t\t}\n\n\t\treturn `${value.slice(0, MAX_STYLE_VALUE_LENGTH)}#len=${value.length}#h=${hash.toString(36)}`;\n\t};\n\n\tconst read = (pseudo: string | undefined): Record<string, string> => {\n\t\tconst cs = getComputedStyle(el as Element, pseudo);\n\t\tconst out: Record<string, string> = {};\n\n\t\tfor (const prop of props) {\n\t\t\tout[prop] = truncateValue(cs.getPropertyValue(prop));\n\t\t}\n\n\t\tif (pseudo) {\n\t\t\tout.content = truncateValue(cs.getPropertyValue(\"content\"));\n\t\t}\n\n\t\treturn out;\n\t};\n\n\tconst idxAttr = el.getAttribute(markerAttr);\n\tconst rect = el.getBoundingClientRect();\n\n\t// Shallow clone so only the opening tag is serialised, not the whole subtree;\n\t// drop the internal marker attribute so it never leaks into the snippet.\n\tconst openingTag = el.cloneNode(false) as Element;\n\topeningTag.removeAttribute(markerAttr);\n\n\treturn {\n\t\tindex: idxAttr === null ? null : Number(idxAttr),\n\t\tisBody: false,\n\t\tisIframe: el.tagName === \"IFRAME\",\n\t\thtml: openingTag.outerHTML,\n\t\tstyles: {\n\t\t\telement: read(undefined),\n\t\t\tbefore: read(\"::before\"),\n\t\t\tafter: read(\"::after\"),\n\t\t},\n\t\trect: {\n\t\t\tx: rect.left + window.scrollX,\n\t\t\ty: rect.top + window.scrollY,\n\t\t\twidth: rect.width,\n\t\t\theight: rect.height,\n\t\t},\n\t};\n}\n\nexport function activeElementHandleScript(): Element | null {\n\tlet el = document.activeElement;\n\n\twhile (el?.shadowRoot?.activeElement) {\n\t\tel = el.shadowRoot.activeElement;\n\t}\n\n\treturn el;\n}\n\nexport function pageDimensionsScript(): { width: number; height: number } {\n\treturn {\n\t\twidth: document.documentElement.scrollWidth,\n\t\theight: document.documentElement.scrollHeight,\n\t};\n}\n\nexport function elementRectScript(el: Element | null): Rect {\n\tif (!el) {\n\t\treturn { x: 0, y: 0, width: 0, height: 0 };\n\t}\n\n\tconst rect = el.getBoundingClientRect();\n\n\treturn {\n\t\tx: rect.left + window.scrollX,\n\t\ty: rect.top + window.scrollY,\n\t\twidth: rect.width,\n\t\theight: rect.height,\n\t};\n}\n\n/**\n * Whether something unrelated (e.g. a fixed cookie banner) covers the element's centre point, so\n * a screenshot of the element's box would show the covering element instead.\n */\nexport function isCenterObscuredScript(el: Element | null): boolean {\n\tif (!el) {\n\t\treturn false;\n\t}\n\n\tconst rect = el.getBoundingClientRect();\n\tconst x = Math.min(\n\t\tMath.max(rect.left + rect.width / 2, 0),\n\t\twindow.innerWidth - 1,\n\t);\n\tconst y = Math.min(\n\t\tMath.max(rect.top + rect.height / 2, 0),\n\t\twindow.innerHeight - 1,\n\t);\n\n\tlet hit = document.elementFromPoint(x, y);\n\n\t// Descend into shadow roots so a hit on a shadow host resolves to the inner element.\n\twhile (hit?.shadowRoot) {\n\t\tconst inner = hit.shadowRoot.elementFromPoint(x, y);\n\n\t\tif (!inner || inner === hit) {\n\t\t\tbreak;\n\t\t}\n\n\t\thit = inner;\n\t}\n\n\tif (!hit) {\n\t\treturn false;\n\t}\n\n\treturn hit !== el && !el.contains(hit) && !hit.contains(el);\n}\n\n/**\n * Scroll the element to the centre of the viewport, instantly so a screenshot taken immediately\n * afterwards isn't captured mid-animation.\n */\nexport function scrollToCenterScript(el: Element | null): void {\n\tel?.scrollIntoView({\n\t\tblock: \"center\",\n\t\tinline: \"nearest\",\n\t\tbehavior: \"instant\",\n\t});\n}\n\n/**\n * Blur (unfocus) an element\n */\nexport function blurScript(el: Element | null): void {\n\t(el as HTMLElement | null)?.blur();\n}\n\n/**\n * Focus an element\n */\nexport function focusScript(el: Element | null): void {\n\t(el as HTMLElement | null)?.focus({ preventScroll: true });\n}\n\n/**\n * Read focus-relevant computed styles from a given element. Unlike\n * `probeActiveElementScript`, this does not use `document.activeElement`, so it\n * still works after the node has been blurred.\n */\nexport function elementStylesScript(\n\tel: Element | null,\n\tprops: string[],\n): StyleSnapshot {\n\tif (!el) {\n\t\treturn { element: {}, before: {}, after: {} };\n\t}\n\n\t// Must be byte-identical to the copies in baselineScript and\n\t// probeActiveElementScript: snapshots from the scripts are compared for\n\t// equality, so they have to truncate oversized values the same way.\n\tconst truncateValue = (value: string): string => {\n\t\tconst MAX_STYLE_VALUE_LENGTH = 512;\n\n\t\tif (value.length <= MAX_STYLE_VALUE_LENGTH) {\n\t\t\treturn value;\n\t\t}\n\n\t\tlet hash = 5381;\n\n\t\tfor (let i = 0; i < value.length; i++) {\n\t\t\thash = ((hash * 33) ^ value.charCodeAt(i)) >>> 0;\n\t\t}\n\n\t\treturn `${value.slice(0, MAX_STYLE_VALUE_LENGTH)}#len=${value.length}#h=${hash.toString(36)}`;\n\t};\n\n\tconst read = (pseudo: string | undefined): Record<string, string> => {\n\t\tconst cs = getComputedStyle(el, pseudo);\n\t\tconst out: Record<string, string> = {};\n\n\t\tfor (const prop of props) {\n\t\t\tout[prop] = truncateValue(cs.getPropertyValue(prop));\n\t\t}\n\n\t\tif (pseudo) {\n\t\t\tout.content = truncateValue(cs.getPropertyValue(\"content\"));\n\t\t}\n\n\t\treturn out;\n\t};\n\n\treturn {\n\t\telement: read(undefined),\n\t\tbefore: read(\"::before\"),\n\t\tafter: read(\"::after\"),\n\t};\n}\n\n/**\n * Remove the marker attribute from all elements, blur the active element, and\n * scroll back to the top. This is a best-effort attempt to reset state between\n * audits: the tab loop scrolls later elements into view as it walks the page\n * (see scrollToCenterScript), and nothing else undoes that once the session\n * ends.\n */\nexport function clearMarkersScript(markerAttr: string): void {\n\tconst clear = (root: Document | ShadowRoot): void => {\n\t\tfor (const el of Array.from(root.querySelectorAll(`[${markerAttr}]`))) {\n\t\t\tel.removeAttribute(markerAttr);\n\t\t}\n\n\t\t// Descend into any shadow roots to clear markers within them.\n\t\tfor (const el of Array.from(root.querySelectorAll(\"*\"))) {\n\t\t\tif (el.shadowRoot) {\n\t\t\t\tclear(el.shadowRoot);\n\t\t\t}\n\t\t}\n\t};\n\n\tclear(document);\n\n\t(document.activeElement as HTMLElement | null)?.blur();\n\n\twindow.scrollTo(0, 0);\n}\n\nexport type MeasureObscuringResult = {\n\tcoveredFraction: number;\n\tfullyObscured: boolean;\n\toffscreen: boolean;\n\topacity: \"opaque\" | \"semi-transparent\" | \"unknown\";\n\tobscuredByHtml: string | null;\n\t/** True when a covering element was marked for selector resolution. */\n\thasObscurer: boolean;\n};\n\n/**\n * Hit-test whether author-created content entirely hides the focused element.\n * Marks a single covering element with `obscurerAttr` when containment confirms\n * a full cover, so the host can resolve its selector via getSelector.\n */\nexport function measureObscuringScript(\n\tel: Element | null,\n\tobscurerAttr: string,\n): MeasureObscuringResult {\n\tconst empty: MeasureObscuringResult = {\n\t\tcoveredFraction: 0,\n\t\tfullyObscured: false,\n\t\toffscreen: false,\n\t\topacity: \"opaque\",\n\t\tobscuredByHtml: null,\n\t\thasObscurer: false,\n\t};\n\n\tif (!el) {\n\t\treturn empty;\n\t}\n\n\tfor (const marked of Array.from(\n\t\tdocument.querySelectorAll(`[${obscurerAttr}]`),\n\t)) {\n\t\tmarked.removeAttribute(obscurerAttr);\n\t}\n\n\tconst rect = el.getBoundingClientRect();\n\tconst left = Math.max(rect.left, 0);\n\tconst top = Math.max(rect.top, 0);\n\tconst right = Math.min(rect.right, window.innerWidth);\n\tconst bottom = Math.min(rect.bottom, window.innerHeight);\n\n\tif (right <= left || bottom <= top) {\n\t\treturn { ...empty, offscreen: true };\n\t}\n\n\tconst width = right - left;\n\tconst height = bottom - top;\n\tconst LARGE_ELEMENT_THRESHOLD_PX = 80;\n\n\tconst points: Array<{ x: number; y: number }> = [\n\t\t{ x: left, y: top },\n\t\t{ x: right - 0.5, y: top },\n\t\t{ x: left, y: bottom - 0.5 },\n\t\t{ x: right - 0.5, y: bottom - 0.5 },\n\t\t{ x: left + width / 2, y: top },\n\t\t{ x: left + width / 2, y: bottom - 0.5 },\n\t\t{ x: left, y: top + height / 2 },\n\t\t{ x: right - 0.5, y: top + height / 2 },\n\t\t{ x: left + width / 2, y: top + height / 2 },\n\t];\n\n\tif (\n\t\twidth > LARGE_ELEMENT_THRESHOLD_PX ||\n\t\theight > LARGE_ELEMENT_THRESHOLD_PX\n\t) {\n\t\tpoints.push(\n\t\t\t{ x: left + width * 0.25, y: top + height * 0.25 },\n\t\t\t{ x: left + width * 0.75, y: top + height * 0.25 },\n\t\t\t{ x: left + width * 0.25, y: top + height * 0.75 },\n\t\t\t{ x: left + width * 0.75, y: top + height * 0.75 },\n\t\t);\n\t}\n\n\tconst hitAt = (x: number, y: number): Element | null => {\n\t\tconst px = Math.min(Math.max(x, 0), window.innerWidth - 1);\n\t\tconst py = Math.min(Math.max(y, 0), window.innerHeight - 1);\n\t\tconst stack =\n\t\t\ttypeof document.elementsFromPoint === \"function\"\n\t\t\t\t? document.elementsFromPoint(px, py)\n\t\t\t\t: [document.elementFromPoint(px, py)].filter(Boolean);\n\n\t\tfor (let candidate of stack as Element[]) {\n\t\t\twhile (candidate?.shadowRoot) {\n\t\t\t\tconst inner = candidate.shadowRoot.elementFromPoint(px, py);\n\n\t\t\t\tif (!inner || inner === candidate) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcandidate = inner;\n\t\t\t}\n\n\t\t\tif (!candidate) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tcandidate === el ||\n\t\t\t\tel.contains(candidate) ||\n\t\t\t\tcandidate.contains(el)\n\t\t\t) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn candidate;\n\t\t}\n\n\t\treturn null;\n\t};\n\n\tlet covered = 0;\n\tconst coverCounts = new Map<Element, number>();\n\n\tfor (const point of points) {\n\t\tconst cover = hitAt(point.x, point.y);\n\n\t\tif (cover) {\n\t\t\tcovered++;\n\t\t\tcoverCounts.set(cover, (coverCounts.get(cover) ?? 0) + 1);\n\t\t}\n\t}\n\n\tconst coveredFraction = points.length === 0 ? 0 : covered / points.length;\n\n\tif (coveredFraction < 1) {\n\t\treturn {\n\t\t\t...empty,\n\t\t\tcoveredFraction,\n\t\t\tfullyObscured: false,\n\t\t};\n\t}\n\n\tlet topCover: Element | null = null;\n\tlet topCount = 0;\n\n\tfor (const [candidate, count] of coverCounts) {\n\t\tif (count > topCount) {\n\t\t\ttopCover = candidate;\n\t\t\ttopCount = count;\n\t\t}\n\t}\n\n\tif (!topCover) {\n\t\treturn {\n\t\t\t...empty,\n\t\t\tcoveredFraction: 1,\n\t\t\tfullyObscured: false,\n\t\t\topacity: \"unknown\",\n\t\t};\n\t}\n\n\tconst coverRect = topCover.getBoundingClientRect();\n\tconst containsFully =\n\t\tcoverRect.left <= rect.left &&\n\t\tcoverRect.top <= rect.top &&\n\t\tcoverRect.right >= rect.right &&\n\t\tcoverRect.bottom >= rect.bottom;\n\n\tif (!containsFully) {\n\t\t// Joint multi-element cover: cannot confirm a single opaque container.\n\t\treturn {\n\t\t\tcoveredFraction: 1,\n\t\t\tfullyObscured: true,\n\t\t\toffscreen: false,\n\t\t\topacity: \"unknown\",\n\t\t\tobscuredByHtml: null,\n\t\t\thasObscurer: false,\n\t\t};\n\t}\n\n\tconst classifyOpacity = (\n\t\tnode: Element,\n\t): \"opaque\" | \"semi-transparent\" | \"unknown\" => {\n\t\tconst cs = getComputedStyle(node);\n\t\tconst opacity = Number.parseFloat(cs.opacity);\n\n\t\tif (!Number.isFinite(opacity)) {\n\t\t\treturn \"unknown\";\n\t\t}\n\n\t\tif (opacity < 1) {\n\t\t\treturn \"semi-transparent\";\n\t\t}\n\n\t\tconst bg = cs.backgroundColor;\n\t\tconst rgba = bg.match(\n\t\t\t/rgba?\\(\\s*([\\d.]+)\\s*,\\s*([\\d.]+)\\s*,\\s*([\\d.]+)(?:\\s*,\\s*([\\d.]+))?\\s*\\)/,\n\t\t);\n\n\t\tif (rgba) {\n\t\t\tconst alpha = rgba[4] === undefined ? 1 : Number.parseFloat(rgba[4]);\n\n\t\t\tif (alpha < 1) {\n\t\t\t\treturn alpha <= 0 ? \"semi-transparent\" : \"semi-transparent\";\n\t\t\t}\n\n\t\t\treturn \"opaque\";\n\t\t}\n\n\t\tif (cs.backgroundImage && cs.backgroundImage !== \"none\") {\n\t\t\treturn \"unknown\";\n\t\t}\n\n\t\treturn \"unknown\";\n\t};\n\n\tconst opacity = classifyOpacity(topCover);\n\tconst openingTag = topCover.cloneNode(false) as Element;\n\topeningTag.removeAttribute(obscurerAttr);\n\ttopCover.setAttribute(obscurerAttr, \"1\");\n\n\treturn {\n\t\tcoveredFraction: 1,\n\t\tfullyObscured: true,\n\t\toffscreen: false,\n\t\topacity,\n\t\tobscuredByHtml: openingTag.outerHTML,\n\t\thasObscurer: true,\n\t};\n}\n\n/** Return the element marked as the obscurer, if any. */\nexport function obscurerHandleScript(): Element | null {\n\treturn document.querySelector(\"[data-a11y-obscurer]\");\n}\n\nexport function clearObscurerScript(obscurerAttr: string): void {\n\tfor (const marked of Array.from(\n\t\tdocument.querySelectorAll(`[${obscurerAttr}]`),\n\t)) {\n\t\tmarked.removeAttribute(obscurerAttr);\n\t}\n}\n\ntype ContextObserverState = {\n\tbaselineHref: string;\n\topenedWindow: boolean;\n\tsubmittedForm: boolean;\n\t/** Elements that received focusin since the last drain. */\n\tfocusIns: Element[];\n\tsoftUrlChange: boolean;\n\tinstalled: boolean;\n};\n\ndeclare global {\n\tinterface Window {\n\t\t__a11yContextObserver?: ContextObserverState;\n\t}\n}\n\n/**\n * Install once: wrap window.open (record + inert stub), capture-phase submit\n * (record + preventDefault), track focusin and soft URL changes.\n */\nexport function installContextObserverScript(): void {\n\tif (window.__a11yContextObserver?.installed) {\n\t\treturn;\n\t}\n\n\tconst state: ContextObserverState = {\n\t\tbaselineHref: location.href,\n\t\topenedWindow: false,\n\t\tsubmittedForm: false,\n\t\tfocusIns: [],\n\t\tsoftUrlChange: false,\n\t\tinstalled: true,\n\t};\n\n\twindow.__a11yContextObserver = state;\n\n\tconst originalOpen = window.open.bind(window);\n\n\twindow.open = (..._args: Parameters<typeof window.open>) => {\n\t\tstate.openedWindow = true;\n\n\t\treturn {\n\t\t\tclosed: true,\n\t\t\tclose() {},\n\t\t\tfocus() {},\n\t\t\tblur() {},\n\t\t\topener: null,\n\t\t\tlocation: { href: \"\" },\n\t\t} as unknown as Window;\n\t};\n\n\t// Keep a reference so tooling does not tree-shake the bind as unused.\n\tvoid originalOpen;\n\n\tdocument.addEventListener(\n\t\t\"submit\",\n\t\t(event) => {\n\t\t\tstate.submittedForm = true;\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\t\t},\n\t\ttrue,\n\t);\n\n\tdocument.addEventListener(\n\t\t\"focus\",\n\t\t(event) => {\n\t\t\tconst target = event.target;\n\n\t\t\t// Prefer nodeType: instanceof can be brittle across some embeddings.\n\t\t\tif (target && (target as Node).nodeType === 1) {\n\t\t\t\tstate.focusIns.push(target as Element);\n\t\t\t}\n\t\t},\n\t\ttrue,\n\t);\n\n\tconst noteSoftNav = (): void => {\n\t\tif (location.href !== state.baselineHref) {\n\t\t\tstate.softUrlChange = true;\n\t\t}\n\t};\n\n\twindow.addEventListener(\"hashchange\", noteSoftNav);\n\twindow.addEventListener(\"popstate\", noteSoftNav);\n\n\tconst wrapHistory = (method: \"pushState\" | \"replaceState\"): void => {\n\t\tconst original = history[method].bind(history);\n\n\t\thistory[method] = ((...args: Parameters<History[\"pushState\"]>) => {\n\t\t\tconst result = original(...args);\n\t\t\tnoteSoftNav();\n\n\t\t\treturn result;\n\t\t}) as History[\"pushState\"];\n\t};\n\n\twrapHistory(\"pushState\");\n\twrapHistory(\"replaceState\");\n}\n\nexport type DrainContextObserverResult = {\n\topenedWindow: boolean;\n\tsubmittedForm: boolean;\n\tfocusRemoved: boolean;\n\tredirect: \"outside\" | \"same-subtree\" | null;\n\tsoftUrlChange: boolean;\n\tnavigation: boolean;\n\tattributedHtml: string | null;\n\t/** True when an attributed element was marked for selector resolution. */\n\thasAttributed: boolean;\n};\n\n/**\n * Drain observer signals for the current tab stop and reset per-stop flags.\n * Classification of focus removal / redirection uses the post-Tab settle\n * activeElement and the focusin history from this stop only.\n */\nexport function drainContextObserverScript(\n\tmarkerAttr: string,\n): DrainContextObserverResult {\n\t// Must be a string literal inside this function: it is serialized into the page.\n\tconst attributedAttr = \"data-a11y-ctx-attr\";\n\n\tconst empty: DrainContextObserverResult = {\n\t\topenedWindow: false,\n\t\tsubmittedForm: false,\n\t\tfocusRemoved: false,\n\t\tredirect: null,\n\t\tsoftUrlChange: false,\n\t\tnavigation: false,\n\t\tattributedHtml: null,\n\t\thasAttributed: false,\n\t};\n\n\tconst state = window.__a11yContextObserver;\n\n\tif (!state) {\n\t\treturn empty;\n\t}\n\n\tfor (const marked of Array.from(\n\t\tdocument.querySelectorAll(`[${attributedAttr}]`),\n\t)) {\n\t\tmarked.removeAttribute(attributedAttr);\n\t}\n\n\tconst openedWindow = state.openedWindow;\n\tconst submittedForm = state.submittedForm;\n\tconst softUrlChange = state.softUrlChange;\n\tconst focusIns = state.focusIns.slice();\n\n\tstate.openedWindow = false;\n\tstate.submittedForm = false;\n\tstate.softUrlChange = false;\n\tstate.focusIns = [];\n\n\tlet active = document.activeElement;\n\n\twhile (active?.shadowRoot?.activeElement) {\n\t\tactive = active.shadowRoot.activeElement;\n\t}\n\n\tconst intended =\n\t\tfocusIns.find(\n\t\t\t(el) => el !== document.body && el !== document.documentElement,\n\t\t) ?? null;\n\n\tconst openingHtml = (node: Element): string => {\n\t\tconst clone = node.cloneNode(false) as Element;\n\t\tclone.removeAttribute(markerAttr);\n\t\tclone.removeAttribute(attributedAttr);\n\n\t\treturn clone.outerHTML;\n\t};\n\n\tlet focusRemoved = false;\n\tlet redirect: \"outside\" | \"same-subtree\" | null = null;\n\tlet attributedHtml: string | null = null;\n\tlet hasAttributed = false;\n\n\tconst bodyOrNone =\n\t\t!active || active === document.body || active === document.documentElement;\n\n\tif (intended && bodyOrNone) {\n\t\tfocusRemoved = true;\n\t\tattributedHtml = openingHtml(intended);\n\t\tintended.setAttribute(attributedAttr, \"1\");\n\t\thasAttributed = true;\n\t} else if (intended && active && intended !== active) {\n\t\tconst composedContains = (ancestor: Element, node: Element): boolean => {\n\t\t\tlet current: Node | null = node;\n\n\t\t\twhile (current) {\n\t\t\t\tif (current === ancestor) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tconst parent: Node | null = current.parentNode;\n\n\t\t\t\tif (parent) {\n\t\t\t\t\tcurrent = parent;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (current instanceof ShadowRoot) {\n\t\t\t\t\tcurrent = current.host;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t};\n\n\t\tconst same =\n\t\t\tcomposedContains(intended, active) || composedContains(active, intended);\n\n\t\tredirect = same ? \"same-subtree\" : \"outside\";\n\t\tattributedHtml = openingHtml(intended);\n\t\tintended.setAttribute(attributedAttr, \"1\");\n\t\thasAttributed = true;\n\t}\n\n\treturn {\n\t\topenedWindow,\n\t\tsubmittedForm,\n\t\tfocusRemoved,\n\t\tredirect,\n\t\tsoftUrlChange,\n\t\tnavigation: false,\n\t\tattributedHtml,\n\t\thasAttributed,\n\t};\n}\n\n/** Return the element marked as attributed by drainContextObserverScript (the\n * element that received a focus event this stop and then lost it), if any. */\nexport function attributedHandleScript(): Element | null {\n\treturn document.querySelector(\"[data-a11y-ctx-attr]\");\n}\n\nexport function clearAttributedScript(): void {\n\tfor (const marked of Array.from(\n\t\tdocument.querySelectorAll(\"[data-a11y-ctx-attr]\"),\n\t)) {\n\t\tmarked.removeAttribute(\"data-a11y-ctx-attr\");\n\t}\n}\n\n/**\n * Drop focusin history accumulated after drain (e.g. pixel-diff blur/refocus)\n * so the next tab stop does not mis-attribute F55 or redirects.\n */\nexport function clearContextFocusInsScript(): void {\n\tconst state = window.__a11yContextObserver;\n\n\tif (state) {\n\t\tstate.focusIns = [];\n\t\tstate.openedWindow = false;\n\t\tstate.submittedForm = false;\n\t\tstate.softUrlChange = false;\n\t}\n}\n\n/** Current location.href for navigation comparison in the host. */\nexport function locationHrefScript(): string {\n\treturn location.href;\n}\n","import type { Rect } from \"./adaptor\";\n\n/**\n * A screenshot clip framing `rect` with up to `buffer` pixels of padding on each side, shrunk\n * where the page edges leave less room. The padding allows for indicators drawn just outside\n * the element box (outlines, shadows) and for anti-aliasing.\n */\nexport function bufferedClip(\n\trect: Rect,\n\tpageWidth: number,\n\tpageHeight: number,\n\tbuffer: number,\n): Rect {\n\tconst left = Math.max(0, Math.min(buffer, rect.x));\n\tconst top = Math.max(0, Math.min(buffer, rect.y));\n\tconst right = Math.max(0, Math.min(buffer, pageWidth - rect.x - rect.width));\n\tconst bottom = Math.max(\n\t\t0,\n\t\tMath.min(buffer, pageHeight - rect.y - rect.height),\n\t);\n\n\t// Clamp to non-negative origins: an element positioned partially off the top\n\t// or left of the document has a negative page-relative rect, and Puppeteer\n\t// rejects a screenshot clip with negative x/y.\n\treturn {\n\t\tx: Math.max(0, rect.x - left),\n\t\ty: Math.max(0, rect.y - top),\n\t\twidth: rect.width + left + right,\n\t\theight: rect.height + top + bottom,\n\t};\n}\n","/**\n * Computed-style properties that are likely to draw a visible focus indicator. Layout properties\n * like margin and padding are deliberately excluded.\n */\nexport const FOCUS_STYLE_PROPERTIES = [\n\t\"background-color\",\n\t\"background-image\",\n\t\"border-bottom-color\",\n\t\"border-bottom-style\",\n\t\"border-bottom-width\",\n\t\"border-left-color\",\n\t\"border-left-style\",\n\t\"border-left-width\",\n\t\"border-right-color\",\n\t\"border-right-style\",\n\t\"border-right-width\",\n\t\"border-top-color\",\n\t\"border-top-style\",\n\t\"border-top-width\",\n\t\"box-shadow\",\n\t\"color\",\n\t\"font-weight\",\n\t\"outline-color\",\n\t\"outline-style\",\n\t\"outline-width\",\n\t\"text-decoration\",\n] as const;\n","/**\n * Build a compact, hopefully-unique selector for any given element on the page. This function is\n * serialized and run in the page context, so it must not reference any symbols outside its own\n * scope.\n *\n * Mirrors axe-core's approach: each level contributes the fewest features that discriminate the\n * element (a unique id, the rarest single class, or an :nth-of-type position), and the walk stops\n * as soon as the joined selector matches exactly one element. Selectors stay short because of\n * that early stop, not because of truncation; the length budget is only a backstop.\n */\nexport function getSelector(root: Node | null): string {\n\tconst MAX_LENGTH = 128;\n\n\tconst esc = (value: string): string =>\n\t\ttypeof CSS !== \"undefined\" && typeof CSS.escape === \"function\"\n\t\t\t? CSS.escape(value)\n\t\t\t: value;\n\n\tconst tagName = (node: Node): string =>\n\t\tnode.nodeType === 1\n\t\t\t? node.nodeName.toLowerCase()\n\t\t\t: node.nodeName.toUpperCase().replace(/^#/, \"\");\n\n\t// A querySelectorAll-capable root (Document or ShadowRoot) for the element,\n\t// used to confirm uniqueness and class rarity. Absent on the plain objects\n\t// used in the serialisation unit tests, where we trust ids and walk to the\n\t// top instead of stopping early.\n\tconst rootOf = (element: Element): ParentNode | null => {\n\t\tconst node = (\n\t\t\telement as Element & { getRootNode?: () => Node }\n\t\t).getRootNode?.();\n\n\t\treturn node && typeof (node as ParentNode).querySelectorAll === \"function\"\n\t\t\t? (node as ParentNode)\n\t\t\t: null;\n\t};\n\n\tconst matchCount = (queryRoot: ParentNode, selector: string): number => {\n\t\ttry {\n\t\t\treturn queryRoot.querySelectorAll(selector).length;\n\t\t} catch {\n\t\t\t// A selector that fails to parse can't be relied on.\n\t\t\treturn Number.POSITIVE_INFINITY;\n\t\t}\n\t};\n\n\t// A candidate feature is only usable if it actually selects this element;\n\t// an escaping or engine mismatch (e.g. CSS string escapes in an attribute\n\t// value) could otherwise produce a selector that matches nothing — or a\n\t// different element entirely.\n\tconst safeMatches = (element: Element, selector: string): boolean => {\n\t\ttry {\n\t\t\treturn typeof element.matches === \"function\" && element.matches(selector);\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t};\n\n\tconst idIsUnique = (element: Element, id: string): boolean => {\n\t\tconst queryRoot = rootOf(element);\n\n\t\treturn queryRoot === null || matchCount(queryRoot, `#${esc(id)}`) === 1;\n\t};\n\n\t// A discriminating feature for one level of the selector: its CSS text plus\n\t// a predicate telling whether a sibling would match the same feature (used\n\t// to decide if an :nth-of-type pin is still needed).\n\ttype Feature = {\n\t\tfeature: string;\n\t\tsharedBy: (sibling: Element) => boolean;\n\t};\n\n\tconst classFeature = (cls: string): Feature => ({\n\t\tfeature: `.${esc(cls)}`,\n\t\tsharedBy: (sibling) => Array.from(sibling.classList ?? []).includes(cls),\n\t});\n\n\t// The single feature that narrows the element down the most: the class or\n\t// href attribute with the fewest matches in the root. Hrefs break ties\n\t// between structurally-identical content blocks, where classes and\n\t// :nth-of-type (which only pins position within one parent) cannot. Without\n\t// a queryable root there is no rarity information, so the first class\n\t// stands in.\n\tconst rarestFeature = (\n\t\telement: Element,\n\t\tqueryRoot: ParentNode | null,\n\t): Feature | null => {\n\t\tconst classes = Array.from(element.classList).slice(0, 8);\n\n\t\tif (!queryRoot) {\n\t\t\tconst cls = classes[0];\n\n\t\t\treturn cls === undefined ? null : classFeature(cls);\n\t\t}\n\n\t\tlet best: Feature | null = null;\n\t\tlet bestCount = Number.POSITIVE_INFINITY;\n\n\t\tfor (const cls of classes) {\n\t\t\tconst candidate = classFeature(cls);\n\n\t\t\tif (!safeMatches(element, candidate.feature)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst count = matchCount(queryRoot, candidate.feature);\n\n\t\t\tif (count < bestCount) {\n\t\t\t\tbest = candidate;\n\t\t\t\tbestCount = count;\n\t\t\t}\n\n\t\t\tif (count === 1) {\n\t\t\t\treturn best;\n\t\t\t}\n\t\t}\n\n\t\tconst href =\n\t\t\ttypeof element.getAttribute === \"function\"\n\t\t\t\t? element.getAttribute(\"href\")\n\t\t\t\t: null;\n\n\t\t// Skip hrefs with characters that change meaning inside a CSS string\n\t\t// (quotes, backslashes), and query strings, which are too volatile\n\t\t// across scans to pin a selector to. Fragments (#main) stay eligible —\n\t\t// skip links make stable discriminators.\n\t\tif (href && href.length <= 100 && !/[\"\\\\?]/.test(href)) {\n\t\t\tconst feature = `[href=\"${href}\"]`;\n\n\t\t\tif (\n\t\t\t\tsafeMatches(element, feature) &&\n\t\t\t\tmatchCount(queryRoot, feature) < bestCount\n\t\t\t) {\n\t\t\t\treturn {\n\t\t\t\t\tfeature,\n\t\t\t\t\tsharedBy: (sibling) =>\n\t\t\t\t\t\ttypeof sibling.getAttribute === \"function\" &&\n\t\t\t\t\t\tsibling.getAttribute(\"href\") === href,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn best;\n\t};\n\n\t// The element's 1-based position among same-tag siblings, and whether the\n\t// chosen feature fails to discriminate it from them (so the segment needs\n\t// an :nth-of-type pin). Siblings are absent on the serialisation test\n\t// nodes — there we skip the pin.\n\tconst positionAmongSiblings = (\n\t\telement: Element,\n\t\tsharedBy: (sibling: Element) => boolean,\n\t): { nth: number; ambiguous: boolean } => {\n\t\tconst siblings = (element.parentNode as ParentNode | null)?.children;\n\n\t\tif (!siblings) {\n\t\t\treturn { nth: 0, ambiguous: false };\n\t\t}\n\n\t\tlet nth = 0;\n\t\tlet count = 0;\n\t\tlet shared = 0;\n\n\t\tfor (const sibling of Array.from(siblings)) {\n\t\t\tif (sibling.nodeName !== element.nodeName) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcount++;\n\n\t\t\tif (sibling === element) {\n\t\t\t\tnth = count;\n\t\t\t}\n\n\t\t\tif (sharedBy(sibling)) {\n\t\t\t\tshared++;\n\t\t\t}\n\t\t}\n\n\t\treturn { nth, ambiguous: shared > 1 };\n\t};\n\n\tconst segmentFor = (\n\t\telement: Element,\n\t\tqueryRoot: ParentNode | null,\n\t): { segment: string; anchored: boolean } => {\n\t\t// Only treat an id as an absolute anchor when it actually resolves to a\n\t\t// single element: pages with duplicate ids would otherwise yield a\n\t\t// selector (e.g. \"#dup>a\") that matches several elements.\n\t\tif (element.id && idIsUnique(element, element.id)) {\n\t\t\treturn { segment: `#${esc(element.id)}`, anchored: true };\n\t\t}\n\n\t\tconst feature = rarestFeature(element, queryRoot);\n\t\tlet segment = tagName(element) + (feature === null ? \"\" : feature.feature);\n\n\t\t// When same-tag siblings share the chosen feature, pin the position so the\n\t\t// segment selects exactly this element rather than all of them.\n\t\tconst { nth, ambiguous } = positionAmongSiblings(\n\t\t\telement,\n\t\t\tfeature === null ? () => true : feature.sharedBy,\n\t\t);\n\n\t\tif (ambiguous && nth > 0) {\n\t\t\tsegment += `:nth-of-type(${nth})`;\n\t\t}\n\n\t\treturn { segment, anchored: false };\n\t};\n\n\t// A minimal segment for when a level's full segment would blow the budget\n\t// (e.g. an enormous class name or a long href): just the tag, pinned by\n\t// position when same-tag siblings would make the bare tag ambiguous.\n\tconst degradedSegmentFor = (element: Element): string => {\n\t\tlet segment = tagName(element);\n\n\t\tconst { nth, ambiguous } = positionAmongSiblings(element, () => true);\n\n\t\tif (ambiguous && nth > 0) {\n\t\t\tsegment += `:nth-of-type(${nth})`;\n\t\t}\n\n\t\treturn segment;\n\t};\n\n\tconst segments: string[] = [];\n\tlet node: Node | null = root;\n\tconst queryRoot =\n\t\troot && root.nodeType === 1 ? rootOf(root as Element) : null;\n\n\ttry {\n\t\t// Walk only element nodes. Stopping at the first non-element parent (the\n\t\t// document, or a ShadowRoot when the target is inside an open shadow root)\n\t\t// keeps the selector within its tree and avoids reading `classList` off a\n\t\t// node that has none.\n\t\twhile (node && node.nodeType === 1) {\n\t\t\tconst element = node as Element;\n\t\t\tlet { segment, anchored } = segmentFor(element, queryRoot);\n\n\t\t\t// Keep within the budget (the +1 accounts for the \">\" that would join\n\t\t\t// this segment to the rest). A level whose full segment doesn't fit is\n\t\t\t// degraded to tag + position rather than discarded, so ancestor context\n\t\t\t// is never lost to one long feature.\n\t\t\tconst joinedWith = (candidate: string): number =>\n\t\t\t\tsegments.length\n\t\t\t\t\t? candidate.length + 1 + segments.join(\">\").length\n\t\t\t\t\t: candidate.length;\n\n\t\t\tif (joinedWith(segment) > MAX_LENGTH - 1) {\n\t\t\t\tsegment = degradedSegmentFor(element);\n\t\t\t\tanchored = false;\n\n\t\t\t\tif (joinedWith(segment) > MAX_LENGTH - 1) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsegments.unshift(segment);\n\n\t\t\tif (anchored) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Stop as soon as the selector already identifies a single element —\n\t\t\t// this, not truncation, is what keeps selectors short.\n\t\t\tif (queryRoot && matchCount(queryRoot, segments.join(\">\")) === 1) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tnode = element.parentNode;\n\t\t}\n\t} catch {\n\t\t// A malformed node tree must never crash the audit; return what we have.\n\t}\n\n\treturn segments.join(\">\");\n}\n","import type { BrowserAdaptor, ElementRef } from \"./adaptor\";\nimport { elementRectScript, pageDimensionsScript } from \"./browser-scripts\";\nimport { bufferedClip } from \"./clip\";\n\nexport type CaptureScreenshotOptions = {\n\tscreenshotClipBuffer: number;\n};\n\n/**\n * Screenshot the element `handle` currently refers to, clipped to its box plus\n * `screenshotClipBuffer` padding. The caller owns `handle` and must dispose it\n * after this promise settles.\n */\nexport async function captureScreenshot(\n\tadaptor: BrowserAdaptor,\n\toptions: CaptureScreenshotOptions,\n\thandle: ElementRef,\n): Promise<Uint8Array> {\n\tconst { width: pageWidth, height: pageHeight } =\n\t\tawait adaptor.evaluate(pageDimensionsScript);\n\tconst rect = await adaptor.evaluate(elementRectScript, handle);\n\tconst clip = bufferedClip(\n\t\trect,\n\t\tpageWidth,\n\t\tpageHeight,\n\t\toptions.screenshotClipBuffer,\n\t);\n\tconst scale = adaptor.screenshotClipScale ?? 1;\n\n\treturn adaptor.screenshotClip(clip, scale);\n}\n","const DEFAULT_MAX_ATTRIBUTE_VALUE_LENGTH = 50;\nconst DEFAULT_MAX_LENGTH = 300;\nconst ELLIPSIS = \"...\";\n\nexport type TruncateHtmlOptions = {\n\tmaxAttributeValueLength?: number;\n\tmaxLength?: number;\n};\n\n/**\n * Given an element's outerHTML, produce a truncated version suitable for display in results. For\n * memory efficiency, pass a shallow outerHTML i.e. `Node.cloneNode(false).outerHTML`.\n */\nexport function truncateHtml(\n\thtml: string,\n\toptions: TruncateHtmlOptions = {},\n): string {\n\tif (!html) {\n\t\treturn \"\";\n\t}\n\n\tconst maxAttributeValueLength =\n\t\toptions.maxAttributeValueLength ?? DEFAULT_MAX_ATTRIBUTE_VALUE_LENGTH;\n\tconst maxLength = options.maxLength ?? DEFAULT_MAX_LENGTH;\n\n\t// Keep only the opening tag\n\tconst closingBracket = html.indexOf(\">\");\n\tconst openingTag =\n\t\tclosingBracket === -1 ? html : html.slice(0, closingBracket + 1);\n\n\t// Shorten long quoted attribute values, preserving the quote style.\n\tconst trimmed = openingTag.replace(\n\t\t/=([\"'])([\\s\\S]*?)\\1/g,\n\t\t(match, quote: string, value: string) => {\n\t\t\tif (value.length <= maxAttributeValueLength) {\n\t\t\t\treturn match;\n\t\t\t}\n\n\t\t\treturn `=${quote}${value.slice(0, maxAttributeValueLength)}${ELLIPSIS}${quote}`;\n\t\t},\n\t);\n\n\tif (trimmed.length > maxLength) {\n\t\treturn `${trimmed.slice(0, maxLength)}${ELLIPSIS}`;\n\t}\n\n\treturn trimmed;\n}\n","import type { BrowserAdaptor, ElementRef } from \"./adaptor\";\nimport {\n\tblurScript,\n\telementRectScript,\n\telementStylesScript,\n\tfocusScript,\n\tisCenterObscuredScript,\n\tpageDimensionsScript,\n\tscrollToCenterScript,\n} from \"./browser-scripts\";\nimport { bufferedClip } from \"./clip\";\nimport type { UnfocusedPair } from \"./types\";\n\nexport type CaptureUnfocusedPairOptions = {\n\tscreenshotSettleDelay: number;\n\tscreenshotClipBuffer: number;\n\tstyleProps: readonly string[];\n};\n\n/**\n * Capture focused and unfocused screenshots of the same element, plus the\n * unfocused style snapshot and clip anchors appearance needs to score later.\n *\n * The caller owns `handle` and must dispose it after this promise settles.\n */\nexport async function captureUnfocusedPair(\n\tadaptor: BrowserAdaptor,\n\toptions: CaptureUnfocusedPairOptions,\n\thandle: ElementRef,\n): Promise<UnfocusedPair> {\n\t// Tab scrolls an element just barely into view at the viewport edge, which\n\t// is exactly where fixed overlays (cookie banners, sticky footers) sit. If\n\t// something covers the element there, both screenshots would show the\n\t// overlay and no indicator could ever be detected. Centre the element in\n\t// the viewport first, then give the scroll a moment to settle.\n\tif (await adaptor.evaluate(isCenterObscuredScript, handle)) {\n\t\tawait adaptor.evaluate(scrollToCenterScript, handle);\n\n\t\tawait new Promise((resolve) =>\n\t\t\tsetTimeout(resolve, options.screenshotSettleDelay),\n\t\t);\n\t}\n\n\tconst { width: pageWidth, height: pageHeight } =\n\t\tawait adaptor.evaluate(pageDimensionsScript);\n\n\tconst focusedRect = await adaptor.evaluate(elementRectScript, handle);\n\tconst focusedClip = bufferedClip(\n\t\tfocusedRect,\n\t\tpageWidth,\n\t\tpageHeight,\n\t\toptions.screenshotClipBuffer,\n\t);\n\n\tconst scale = adaptor.screenshotClipScale ?? 1;\n\n\t// Capture the focused state first, while focus is genuine: re-focusing the\n\t// element afterwards cannot always restore it (the host of a closed shadow\n\t// root cannot push focus back inside), so the focused frame must be taken\n\t// before blurring.\n\tconst focusedScreenshot = await adaptor.screenshotClip(focusedClip, scale);\n\n\tawait adaptor.evaluate(blurScript, handle);\n\n\t// Measure the unfocused rect after blurring rather than reusing a stale\n\t// baseline rect: a :focus rule may have moved the element, and a\n\t// fixed-position element's page-relative rect changes with every scroll.\n\tconst unfocusedRect = await adaptor.evaluate(elementRectScript, handle);\n\tconst unfocusedClip = bufferedClip(\n\t\tunfocusedRect,\n\t\tpageWidth,\n\t\tpageHeight,\n\t\toptions.screenshotClipBuffer,\n\t);\n\n\tconst unfocusedScreenshot = await adaptor.screenshotClip(\n\t\tunfocusedClip,\n\t\tscale,\n\t);\n\n\tconst unfocusedStyles = await adaptor.evaluate(elementStylesScript, handle, [\n\t\t...options.styleProps,\n\t]);\n\n\t// Restore focus so the next Tab advances from this element rather than\n\t// restarting traversal. (A closed-shadow host can't be re-focused into the\n\t// root; the loop still progresses because Tab re-enters from there.)\n\tawait adaptor.evaluate(focusScript, handle);\n\n\treturn {\n\t\tfocusedScreenshot,\n\t\tunfocusedScreenshot,\n\t\tunfocusedStyles,\n\t\tfocusedRect,\n\t\tunfocusedRect,\n\t\tfocusedClip,\n\t\tunfocusedClip,\n\t\tscale,\n\t};\n}\n","import type { BrowserAdaptor, ElementRef } from \"./adaptor\";\nimport {\n\ttype ActiveElementBase,\n\tactiveElementHandleScript,\n\tattributedHandleScript,\n\tbaselineScript,\n\tclearAttributedScript,\n\tclearContextFocusInsScript,\n\tclearMarkersScript,\n\tclearObscurerScript,\n\ttype DrainContextObserverResult,\n\tdrainContextObserverScript,\n\tinstallContextObserverScript,\n\tlocationHrefScript,\n\tmeasureObscuringScript,\n\tobscurerHandleScript,\n\tprobeActiveElementScript,\n} from \"./browser-scripts\";\nimport { captureScreenshot } from \"./capture-screenshot\";\nimport { FOCUS_STYLE_PROPERTIES } from \"./focus-style\";\nimport { getSelector } from \"./get-selector\";\nimport { truncateHtml } from \"./truncate-html\";\nimport type {\n\tActiveElementInfo,\n\tCapability,\n\tContextChangeSignals,\n\tSessionEndReason,\n\tStyleSnapshot,\n\tTabConsumer,\n\tTabSessionHandle,\n\tTabStopSnapshot,\n\tUnfocusedPair,\n} from \"./types\";\nimport { captureUnfocusedPair } from \"./unfocused-pair\";\n\n/**\n * Whether an `evaluate()` rejection looks like the page navigated out from\n * under it (execution context destroyed) rather than an unexpected failure.\n * A full navigation is the one context-change signal the in-page observer\n * can never self-report: it destroys the JS context before it can log\n * anything, so the host has to infer it from how `evaluate()` failed.\n */\nfunction isContextDestroyedError(error: unknown): boolean {\n\tconst message = error instanceof Error ? error.message : String(error);\n\n\treturn /Execution context was destroyed|Target closed|frame was detached|navigat/i.test(\n\t\tmessage,\n\t);\n}\n\n/**\n * Outcome of the early, pre-isBody navigation check. `navigation: true`\n * means a full navigation was detected (via href diff or a destroyed-context\n * error) and the caller must end the session without proceeding any\n * further. Otherwise `raw` carries a drain payload already fetched while\n * resolving a soft URL change (so the later full drain can reuse it instead\n * of reading back state the first call already reset), or `null` when the\n * href was unchanged and nothing has been drained yet for this stop.\n */\ntype ContextNavigationOutcome =\n\t| { navigation: true }\n\t| { navigation: false; raw: DrainContextObserverResult | null };\n\nexport const DEFAULT_SCREENSHOT_SETTLE_DELAY = 33;\nexport const DEFAULT_SCREENSHOT_CLIP_BUFFER = 10;\nexport const DEFAULT_MARKER_LIMIT = 1024;\nexport const MARKER_ATTR = \"data-a11y-focus-idx\";\nexport const OBSCURER_ATTR = \"data-a11y-obscurer\";\nexport const OBSCURING_RECHECK_DELAY_MS = 250;\n\nexport type TabSessionOptions = {\n\tscreenshotSettleDelay?: number;\n\tscreenshotClipBuffer?: number;\n\tmarkerLimit?: number;\n\tbaselineElementLimit?: number;\n};\n\nexport type TabOrchestrator = {\n\tattach(consumer: TabConsumer): void;\n\trun(): Promise<void>;\n};\n\nexport function createTabOrchestrator(\n\tadaptor: BrowserAdaptor,\n\toptions: TabSessionOptions = {},\n): TabOrchestrator {\n\tconst consumers: TabConsumer[] = [];\n\tlet started = false;\n\tlet ran = false;\n\n\treturn {\n\t\tattach(consumer) {\n\t\t\tif (started) {\n\t\t\t\tthrow new Error(\"Cannot attach after run() has started\");\n\t\t\t}\n\n\t\t\tconsumers.push(consumer);\n\t\t},\n\t\tasync run() {\n\t\t\tif (ran) {\n\t\t\t\tthrow new Error(\"run() has already been called\");\n\t\t\t}\n\n\t\t\tran = true;\n\t\t\tstarted = true;\n\n\t\t\tif (consumers.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst attached = new Set(consumers);\n\t\t\tconst screenshotSettleDelay =\n\t\t\t\toptions.screenshotSettleDelay ?? DEFAULT_SCREENSHOT_SETTLE_DELAY;\n\t\t\tconst screenshotClipBuffer =\n\t\t\t\toptions.screenshotClipBuffer ?? DEFAULT_SCREENSHOT_CLIP_BUFFER;\n\t\t\tconst markerLimit = Math.max(\n\t\t\t\toptions.markerLimit ?? DEFAULT_MARKER_LIMIT,\n\t\t\t\toptions.baselineElementLimit ?? 0,\n\t\t\t);\n\t\t\tconst styleProps = [...FOCUS_STYLE_PROPERTIES];\n\t\t\tconst resolved = {\n\t\t\t\tscreenshotSettleDelay,\n\t\t\t\tscreenshotClipBuffer,\n\t\t\t\tstyleProps,\n\t\t\t};\n\n\t\t\tlet settleTimer: ReturnType<typeof setTimeout> | undefined;\n\t\t\tlet resolveSettle: (() => void) | undefined;\n\t\t\tconst pairByStop = { current: null as Promise<UnfocusedPair> | null };\n\t\t\tconst screenshotByStop = { current: null as Promise<Uint8Array> | null };\n\t\t\tlet activeHandle: ElementRef | undefined;\n\t\t\tlet lastHasAttributed = false;\n\t\t\t// Captured when observers are installed and re-armed after every\n\t\t\t// detected soft URL change, so repeated soft navigations across stops\n\t\t\t// compare against the most recent href rather than the original load.\n\t\t\tlet baselineHref: string | null = null;\n\n\t\t\tconst remainingHas = (capability: Capability): boolean =>\n\t\t\t\t[...attached].some((c) => c.capabilities.has(capability));\n\n\t\t\t// Decided once from who is attached at session start; never re-checked,\n\t\t\t// so the observer stays installed even after every declarer disconnects\n\t\t\t// (session-lifetime setup is never uninstalled, only skipped per-stop).\n\t\t\tconst contextSignalsWanted = remainingHas(\"contextSignals\");\n\n\t\t\tconst handleFor = (consumer: TabConsumer): TabSessionHandle => ({\n\t\t\t\tdisconnect() {\n\t\t\t\t\tattached.delete(consumer);\n\n\t\t\t\t\tif (attached.size === 0 && settleTimer !== undefined) {\n\t\t\t\t\t\tclearTimeout(settleTimer);\n\t\t\t\t\t\tsettleTimer = undefined;\n\t\t\t\t\t\tresolveSettle?.();\n\t\t\t\t\t\tresolveSettle = undefined;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tensureUnfocusedPair: () => {\n\t\t\t\t\tif (!consumer.capabilities.has(\"unfocusedPair\")) {\n\t\t\t\t\t\tthrow new Error(\"Consumer did not declare unfocusedPair\");\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!remainingHas(\"unfocusedPair\")) {\n\t\t\t\t\t\tthrow new Error(\"Consumer did not declare unfocusedPair\");\n\t\t\t\t\t}\n\n\t\t\t\t\tif (activeHandle === undefined) {\n\t\t\t\t\t\tthrow new Error(\"unfocusedPair capture not implemented\");\n\t\t\t\t\t}\n\n\t\t\t\t\tpairByStop.current ??= captureUnfocusedPair(\n\t\t\t\t\t\tadaptor,\n\t\t\t\t\t\tresolved,\n\t\t\t\t\t\tactiveHandle,\n\t\t\t\t\t);\n\n\t\t\t\t\treturn pairByStop.current;\n\t\t\t\t},\n\t\t\t\tscreenshotClip: () => {\n\t\t\t\t\tif (!consumer.capabilities.has(\"screenshot\")) {\n\t\t\t\t\t\tthrow new Error(\"Consumer did not declare screenshot\");\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!remainingHas(\"screenshot\")) {\n\t\t\t\t\t\tthrow new Error(\"Consumer did not declare screenshot\");\n\t\t\t\t\t}\n\n\t\t\t\t\tif (activeHandle === undefined) {\n\t\t\t\t\t\tthrow new Error(\"screenshot capture not implemented\");\n\t\t\t\t\t}\n\n\t\t\t\t\tscreenshotByStop.current ??= captureScreenshot(\n\t\t\t\t\t\tadaptor,\n\t\t\t\t\t\tresolved,\n\t\t\t\t\t\tactiveHandle,\n\t\t\t\t\t);\n\n\t\t\t\t\treturn screenshotByStop.current;\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tconst end = (reason: SessionEndReason): void => {\n\t\t\t\tfor (const consumer of attached) {\n\t\t\t\t\tconsumer.onSessionEnd?.(reason);\n\t\t\t\t}\n\n\t\t\t\tattached.clear();\n\t\t\t};\n\n\t\t\t/**\n\t\t\t * Primary navigation detection layer: compares `location.href` against\n\t\t\t * `baselineHref` on every stop, since a full navigation destroys the\n\t\t\t * in-page observer's execution context before it can self-report\n\t\t\t * anything (`drainContextObserverScript`'s own `navigation` field is\n\t\t\t * always `false`). A destroyed context can also simply throw instead\n\t\t\t * of returning a changed href (e.g. the navigation completes between\n\t\t\t * the href read and the drain read), which is treated the same way.\n\t\t\t *\n\t\t\t * Must run before the caller's `isBody`/\"done tabbing\" exit check: a\n\t\t\t * freshly-navigated page's `document.activeElement` defaults to\n\t\t\t * `document.body` unless the new page autofocuses something, so\n\t\t\t * without this proactive check a silent navigation would otherwise be\n\t\t\t * misclassified as `\"completed\"`.\n\t\t\t *\n\t\t\t * Deliberately cheap on the common (non-navigating) path: it only\n\t\t\t * reads `location.href` and does not call `drainContextObserverScript`\n\t\t\t * unless the href actually changed, so a stop that ends the session\n\t\t\t * via the isBody exit right after this check still drains at most\n\t\t\t * once overall (at the later, full-mapping call site).\n\t\t\t */\n\t\t\tasync function checkContextNavigation(): Promise<ContextNavigationOutcome> {\n\t\t\t\tlet href: string;\n\n\t\t\t\ttry {\n\t\t\t\t\thref = await adaptor.evaluate(locationHrefScript);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!isContextDestroyedError(error)) {\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn { navigation: true };\n\t\t\t\t}\n\n\t\t\t\tif (baselineHref === null || href === baselineHref) {\n\t\t\t\t\treturn { navigation: false, raw: null };\n\t\t\t\t}\n\n\t\t\t\t// Document navigated (or soft URL change). Prefer the observer's\n\t\t\t\t// own soft-nav flag when the execution context survived;\n\t\t\t\t// otherwise treat it as a full navigation.\n\t\t\t\tlet raw: DrainContextObserverResult | null = null;\n\n\t\t\t\ttry {\n\t\t\t\t\traw = await adaptor.evaluate(drainContextObserverScript, MARKER_ATTR);\n\t\t\t\t} catch {\n\t\t\t\t\traw = null;\n\t\t\t\t}\n\n\t\t\t\tif (raw === null || !raw.softUrlChange) {\n\t\t\t\t\treturn { navigation: true };\n\t\t\t\t}\n\n\t\t\t\tbaselineHref = href;\n\n\t\t\t\treturn { navigation: false, raw };\n\t\t\t}\n\n\t\t\tlet failure: unknown;\n\n\t\t\ttry {\n\t\t\t\tawait adaptor.ensureFocusReporting();\n\n\t\t\t\tconst payload = await adaptor.evaluate(\n\t\t\t\t\tbaselineScript,\n\t\t\t\t\tstyleProps,\n\t\t\t\t\tMARKER_ATTR,\n\t\t\t\t\tmarkerLimit,\n\t\t\t\t);\n\t\t\t\tconst interned = new Map<number, StyleSnapshot>();\n\n\t\t\t\tfor (const entry of payload.entries) {\n\t\t\t\t\tconst styles = payload.styles[entry.styleIndex];\n\n\t\t\t\t\tif (styles !== undefined) {\n\t\t\t\t\t\tinterned.set(entry.index, styles);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (contextSignalsWanted) {\n\t\t\t\t\tbaselineHref = await adaptor.evaluate(locationHrefScript);\n\t\t\t\t\tawait adaptor.evaluate(installContextObserverScript);\n\t\t\t\t}\n\n\t\t\t\tfor (const consumer of [...attached]) {\n\t\t\t\t\tawait consumer.onSessionStart?.(handleFor(consumer));\n\t\t\t\t}\n\n\t\t\t\tconst visited = new Set<number>();\n\t\t\t\tlet tabIndex = 0;\n\n\t\t\t\twhile (attached.size > 0) {\n\t\t\t\t\tpairByStop.current = null;\n\t\t\t\t\tscreenshotByStop.current = null;\n\t\t\t\t\tlastHasAttributed = false;\n\n\t\t\t\t\tconst hasFocus = await adaptor.evaluate(() => document.hasFocus());\n\n\t\t\t\t\tif (!hasFocus) {\n\t\t\t\t\t\tend(\"lostFocus\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tawait adaptor.pressTab();\n\t\t\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\t\t\tresolveSettle = resolve;\n\t\t\t\t\t\tsettleTimer = setTimeout(() => {\n\t\t\t\t\t\t\tsettleTimer = undefined;\n\t\t\t\t\t\t\tresolveSettle = undefined;\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t}, screenshotSettleDelay);\n\t\t\t\t\t});\n\n\t\t\t\t\tif (attached.size === 0) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet base: ActiveElementBase | null;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tbase = await adaptor.evaluate(\n\t\t\t\t\t\t\tprobeActiveElementScript,\n\t\t\t\t\t\t\tstyleProps,\n\t\t\t\t\t\t\tMARKER_ATTR,\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tremainingHas(\"contextSignals\") &&\n\t\t\t\t\t\t\tisContextDestroyedError(error)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t// Mid-flight navigation destroyed the execution context\n\t\t\t\t\t\t\t// before the probe could even run: there is no active\n\t\t\t\t\t\t\t// element to report, so end directly (mirrors the\n\t\t\t\t\t\t\t// isBody/\"done tabbing\" exit below, which also ends\n\t\t\t\t\t\t\t// without a snapshot when there is nothing to notify).\n\t\t\t\t\t\t\tend(\"navigation\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Primary navigation detection layer, run before the isBody exit:\n\t\t\t\t\t// a silently-navigated page's evaluate() calls succeed against the\n\t\t\t\t\t// new document (Puppeteer/CDP targets whichever context is live at\n\t\t\t\t\t// call time), so a hard nav can surface as an ordinary `isBody: true`\n\t\t\t\t\t// probe result with no thrown error at all.\n\t\t\t\t\tlet contextNav: ContextNavigationOutcome | null = null;\n\n\t\t\t\t\tif (remainingHas(\"contextSignals\")) {\n\t\t\t\t\t\tconst outcome = await checkContextNavigation();\n\n\t\t\t\t\t\tif (outcome.navigation) {\n\t\t\t\t\t\t\tend(\"navigation\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcontextNav = outcome;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (base === null || base.isBody) {\n\t\t\t\t\t\t// Focus landed on <body>. This is normally \"done tabbing\", but it\n\t\t\t\t\t\t// is also what F55 focus-removal looks like (an element receives\n\t\t\t\t\t\t// focus and then blurs itself, e.g. `onfocus=\"this.blur()\"`): the\n\t\t\t\t\t\t// in-page observer's focusin history still attributes that stop to\n\t\t\t\t\t\t// the element that briefly held focus, even though nothing is\n\t\t\t\t\t\t// focused now. Drain before ending so that case gets one last\n\t\t\t\t\t\t// notification instead of vanishing silently.\n\t\t\t\t\t\tif (remainingHas(\"contextSignals\")) {\n\t\t\t\t\t\t\tlet raw: DrainContextObserverResult;\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\traw =\n\t\t\t\t\t\t\t\t\tcontextNav?.raw ??\n\t\t\t\t\t\t\t\t\t(await adaptor.evaluate(\n\t\t\t\t\t\t\t\t\t\tdrainContextObserverScript,\n\t\t\t\t\t\t\t\t\t\tMARKER_ATTR,\n\t\t\t\t\t\t\t\t\t));\n\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\tif (!isContextDestroyedError(error)) {\n\t\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Mirrors the probe's own destroyed-context catch above:\n\t\t\t\t\t\t\t\t// there is no attributed element left to report, so end\n\t\t\t\t\t\t\t\t// directly with \"navigation\" rather than \"completed\" (a\n\t\t\t\t\t\t\t\t// navigation signal always ends the session that way).\n\t\t\t\t\t\t\t\tend(\"navigation\");\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (raw.hasAttributed) {\n\t\t\t\t\t\t\t\tconst attributedRef = await adaptor.evaluateHandle(\n\t\t\t\t\t\t\t\t\tattributedHandleScript,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tlet selector: string;\n\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tselector = await adaptor.evaluate(getSelector, attributedRef);\n\t\t\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\t\t\tawait adaptor.disposeRef(attributedRef);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tconst activeElement: ActiveElementInfo = {\n\t\t\t\t\t\t\t\t\tindex: null,\n\t\t\t\t\t\t\t\t\tisBody: false,\n\t\t\t\t\t\t\t\t\tisIframe: false,\n\t\t\t\t\t\t\t\t\tselector,\n\t\t\t\t\t\t\t\t\thtml: truncateHtml(raw.attributedHtml ?? \"\"),\n\t\t\t\t\t\t\t\t\tstyles: { element: {}, before: {}, after: {} },\n\t\t\t\t\t\t\t\t\trect: { x: 0, y: 0, width: 0, height: 0 },\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\tconst snapshot: TabStopSnapshot = {\n\t\t\t\t\t\t\t\t\ttabIndex: ++tabIndex,\n\t\t\t\t\t\t\t\t\tactiveElement,\n\t\t\t\t\t\t\t\t\tcontextSignals: {\n\t\t\t\t\t\t\t\t\t\tsignals: {\n\t\t\t\t\t\t\t\t\t\t\topenedWindow: raw.openedWindow,\n\t\t\t\t\t\t\t\t\t\t\tsubmittedForm: raw.submittedForm,\n\t\t\t\t\t\t\t\t\t\t\tfocusRemoved: raw.focusRemoved,\n\t\t\t\t\t\t\t\t\t\t\tredirect: raw.redirect,\n\t\t\t\t\t\t\t\t\t\t\tsoftUrlChange: raw.softUrlChange,\n\t\t\t\t\t\t\t\t\t\t\tnavigation: raw.navigation,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t// This synthetic stop has no live focused element (it\n\t\t\t\t\t\t\t\t// already blurred itself before this notification is\n\t\t\t\t\t\t\t\t// built, by definition of F55), so capabilities that\n\t\t\t\t\t\t\t\t// need one (`unfocusedPair`, `baselineStyles`,\n\t\t\t\t\t\t\t\t// `obscuring`) have nothing to meaningfully act on.\n\t\t\t\t\t\t\t\t// Only consumers that declared `contextSignals` (the\n\t\t\t\t\t\t\t\t// capability this whole synthetic-stop mechanism exists\n\t\t\t\t\t\t\t\t// to serve) are notified; unlike every other stop in\n\t\t\t\t\t\t\t\t// this file, uniform notification is wrong here because\n\t\t\t\t\t\t\t\t// there is no element for the other capabilities to\n\t\t\t\t\t\t\t\t// read from.\n\t\t\t\t\t\t\t\tconst recipients = [...attached].filter((consumer) =>\n\t\t\t\t\t\t\t\t\tconsumer.capabilities.has(\"contextSignals\"),\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tfor (const consumer of recipients) {\n\t\t\t\t\t\t\t\t\t\tawait consumer.onTabStop(snapshot, handleFor(consumer));\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\t\t\t// Guaranteed even if a recipient's onTabStop throws,\n\t\t\t\t\t\t\t\t\t// so the `data-a11y-ctx-attr` DOM marker never survives\n\t\t\t\t\t\t\t\t\t// past this stop (mirrors how `disposeRef` is\n\t\t\t\t\t\t\t\t\t// guaranteed via `finally` in the main per-stop loop\n\t\t\t\t\t\t\t\t\t// below).\n\t\t\t\t\t\t\t\t\tawait adaptor.evaluate(clearAttributedScript);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tend(\"completed\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (base.isIframe) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (base.index !== null) {\n\t\t\t\t\t\tif (visited.has(base.index)) {\n\t\t\t\t\t\t\tend(\"completed\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvisited.add(base.index);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst ref = await adaptor.evaluateHandle(activeElementHandleScript);\n\t\t\t\t\tactiveHandle = ref;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst selector = await adaptor.evaluate(getSelector, ref);\n\n\t\t\t\t\t\tconst activeElement: ActiveElementInfo = {\n\t\t\t\t\t\t\t...base,\n\t\t\t\t\t\t\thtml: truncateHtml(base.html),\n\t\t\t\t\t\t\tselector,\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst snapshot: TabStopSnapshot = {\n\t\t\t\t\t\t\ttabIndex: ++tabIndex,\n\t\t\t\t\t\t\tactiveElement,\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tremainingHas(\"baselineStyles\") &&\n\t\t\t\t\t\t\tactiveElement.index !== null\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tconst baselineStyles = interned.get(activeElement.index);\n\n\t\t\t\t\t\t\tif (baselineStyles !== undefined) {\n\t\t\t\t\t\t\t\tsnapshot.baselineStyles = baselineStyles;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (remainingHas(\"contextSignals\")) {\n\t\t\t\t\t\t\tlet signals: ContextChangeSignals;\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t// Reuse the drain already fetched above while resolving\n\t\t\t\t\t\t\t\t// a soft URL change (checkContextNavigation), if any;\n\t\t\t\t\t\t\t\t// re-draining here would read back state that call\n\t\t\t\t\t\t\t\t// already reset (focusIns, softUrlChange, etc.) and\n\t\t\t\t\t\t\t\t// silently lose whatever it was reporting. Otherwise\n\t\t\t\t\t\t\t\t// (the common case: href unchanged, nothing drained\n\t\t\t\t\t\t\t\t// yet) do the one drain this stop needs.\n\t\t\t\t\t\t\t\tconst raw =\n\t\t\t\t\t\t\t\t\tcontextNav?.raw ??\n\t\t\t\t\t\t\t\t\t(await adaptor.evaluate(\n\t\t\t\t\t\t\t\t\t\tdrainContextObserverScript,\n\t\t\t\t\t\t\t\t\t\tMARKER_ATTR,\n\t\t\t\t\t\t\t\t\t));\n\t\t\t\t\t\t\t\tsignals = {\n\t\t\t\t\t\t\t\t\topenedWindow: raw.openedWindow,\n\t\t\t\t\t\t\t\t\tsubmittedForm: raw.submittedForm,\n\t\t\t\t\t\t\t\t\tfocusRemoved: raw.focusRemoved,\n\t\t\t\t\t\t\t\t\tredirect: raw.redirect,\n\t\t\t\t\t\t\t\t\tsoftUrlChange: raw.softUrlChange,\n\t\t\t\t\t\t\t\t\tnavigation: raw.navigation,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\tlastHasAttributed = raw.hasAttributed;\n\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\tif (!isContextDestroyedError(error)) {\n\t\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// The page navigated out from under the drain call: the\n\t\t\t\t\t\t\t\t// in-page observer's own state (and any DOM markers it\n\t\t\t\t\t\t\t\t// set) went with it, so there is nothing left to report\n\t\t\t\t\t\t\t\t// besides the navigation itself.\n\t\t\t\t\t\t\t\tsignals = {\n\t\t\t\t\t\t\t\t\topenedWindow: false,\n\t\t\t\t\t\t\t\t\tsubmittedForm: false,\n\t\t\t\t\t\t\t\t\tfocusRemoved: false,\n\t\t\t\t\t\t\t\t\tredirect: null,\n\t\t\t\t\t\t\t\t\tsoftUrlChange: false,\n\t\t\t\t\t\t\t\t\tnavigation: true,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\tlastHasAttributed = false;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tsnapshot.contextSignals = { signals };\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (remainingHas(\"obscuring\")) {\n\t\t\t\t\t\t\tlet raw = await adaptor.evaluate(\n\t\t\t\t\t\t\t\tmeasureObscuringScript,\n\t\t\t\t\t\t\t\tref,\n\t\t\t\t\t\t\t\tOBSCURER_ATTR,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tif (raw.fullyObscured) {\n\t\t\t\t\t\t\t\tawait new Promise((resolve) =>\n\t\t\t\t\t\t\t\t\tsetTimeout(resolve, OBSCURING_RECHECK_DELAY_MS),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\traw = await adaptor.evaluate(\n\t\t\t\t\t\t\t\t\tmeasureObscuringScript,\n\t\t\t\t\t\t\t\t\tref,\n\t\t\t\t\t\t\t\t\tOBSCURER_ATTR,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tlet obscuredBy: { selector: string; html: string } | null = null;\n\n\t\t\t\t\t\t\tif (raw.hasObscurer) {\n\t\t\t\t\t\t\t\tconst obscurer =\n\t\t\t\t\t\t\t\t\tawait adaptor.evaluateHandle(obscurerHandleScript);\n\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst obscurerSelector = await adaptor.evaluate(\n\t\t\t\t\t\t\t\t\t\tgetSelector,\n\t\t\t\t\t\t\t\t\t\tobscurer,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tobscuredBy = {\n\t\t\t\t\t\t\t\t\t\tselector: obscurerSelector,\n\t\t\t\t\t\t\t\t\t\thtml: truncateHtml(raw.obscuredByHtml ?? \"\"),\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\t\t\tawait adaptor.disposeRef(obscurer);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tsnapshot.obscuring = {\n\t\t\t\t\t\t\t\tcoveredFraction: raw.coveredFraction,\n\t\t\t\t\t\t\t\tfullyObscured: raw.fullyObscured,\n\t\t\t\t\t\t\t\toffscreen: raw.offscreen,\n\t\t\t\t\t\t\t\topacity: raw.opacity,\n\t\t\t\t\t\t\t\tobscuredBy,\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tawait adaptor.evaluate(clearObscurerScript, OBSCURER_ATTR);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst recipients = [...attached];\n\n\t\t\t\t\t\tfor (const consumer of recipients) {\n\t\t\t\t\t\t\tawait consumer.onTabStop(snapshot, handleFor(consumer));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (snapshot.contextSignals?.signals.navigation) {\n\t\t\t\t\t\t\tend(\"navigation\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t} finally {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tif (pairByStop.current !== null) {\n\t\t\t\t\t\t\t\tawait pairByStop.current;\n\n\t\t\t\t\t\t\t\tif (contextSignalsWanted) {\n\t\t\t\t\t\t\t\t\t// ensureUnfocusedPair blurred and re-focused the element to\n\t\t\t\t\t\t\t\t\t// capture the unfocused screenshot; drop that noise so the\n\t\t\t\t\t\t\t\t\t// next drain doesn't misread it as a real focus-removal or\n\t\t\t\t\t\t\t\t\t// redirect.\n\t\t\t\t\t\t\t\t\tawait adaptor.evaluate(clearContextFocusInsScript);\n\n\t\t\t\t\t\t\t\t\tif (lastHasAttributed) {\n\t\t\t\t\t\t\t\t\t\tawait adaptor.evaluate(clearAttributedScript);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Capture errors already surface through the consumer that\n\t\t\t\t\t\t\t// awaited; still dispose the handle below.\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tactiveHandle = undefined;\n\t\t\t\t\t\tawait adaptor.disposeRef(ref);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tfailure = error;\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tawait adaptor.evaluate(clearMarkersScript, MARKER_ATTR);\n\t\t\t\t} catch {\n\t\t\t\t\t// Isolate teardown so a marker-clear throw cannot replace the loop error.\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (failure !== undefined) {\n\t\t\t\tend(\"failed\");\n\t\t\t\tthrow failure;\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":"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","names":["opacity","node","queryRoot","DEFAULT_SCREENSHOT_SETTLE_DELAY"]}
package/dist/types.d.ts CHANGED
@@ -13,7 +13,7 @@ export type ActiveElementInfo = {
13
13
  styles: StyleSnapshot;
14
14
  rect: Rect;
15
15
  };
16
- export type Capability = "baselineStyles" | "contextSignals" | "obscuring" | "unfocusedPair";
16
+ export type Capability = "baselineStyles" | "contextSignals" | "obscuring" | "screenshot" | "unfocusedPair";
17
17
  export type SessionEndReason = "completed" | "lostFocus" | "navigation" | "failed";
18
18
  export type UnfocusedPair = {
19
19
  focusedScreenshot: Uint8Array;
@@ -56,6 +56,12 @@ export type ObscuredMeasurement = {
56
56
  export type TabSessionHandle = {
57
57
  disconnect(): void;
58
58
  ensureUnfocusedPair(): Promise<UnfocusedPair>;
59
+ /**
60
+ * Screenshot the currently focused element, clipped and padded. Requires the
61
+ * `screenshot` capability. Cached per stop, so multiple consumers calling
62
+ * this on the same stop only trigger one capture.
63
+ */
64
+ screenshotClip(): Promise<Uint8Array>;
59
65
  };
60
66
  export type TabConsumer = {
61
67
  readonly capabilities: ReadonlySet<Capability>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a11y-pulse/tab-orchestrator",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Shared Tab-session runner for A11y Pulse keyboard audits.",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE.md",