@reticlehq/browser 2.2.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. package/dist/actions/actions-dom.d.ts +0 -1
  2. package/dist/actions/actions-dom.js +0 -1
  3. package/dist/actions/actions.d.ts +3 -1
  4. package/dist/actions/actions.js +55 -36
  5. package/dist/actions/scroll.d.ts +0 -1
  6. package/dist/actions/scroll.js +0 -1
  7. package/dist/actions/value-input.d.ts +33 -0
  8. package/dist/actions/value-input.js +63 -0
  9. package/dist/commands/commands.d.ts +0 -1
  10. package/dist/commands/commands.js +27 -7
  11. package/dist/connect-options.d.ts +97 -0
  12. package/dist/connect-options.js +1 -0
  13. package/dist/dom/a11y.d.ts +0 -2
  14. package/dist/dom/a11y.js +54 -24
  15. package/dist/dom/auto-anchor.d.ts +0 -1
  16. package/dist/dom/auto-anchor.js +0 -1
  17. package/dist/dom/blind-spots.d.ts +0 -1
  18. package/dist/dom/blind-spots.js +0 -1
  19. package/dist/dom/chart.d.ts +0 -1
  20. package/dist/dom/chart.js +0 -1
  21. package/dist/dom/desktop-capture.d.ts +36 -0
  22. package/dist/dom/desktop-capture.js +113 -0
  23. package/dist/dom/dom-ignore.d.ts +7 -1
  24. package/dist/dom/dom-ignore.js +1 -2
  25. package/dist/dom/occlusion.d.ts +0 -1
  26. package/dist/dom/occlusion.js +0 -1
  27. package/dist/dom/query.d.ts +0 -1
  28. package/dist/dom/query.js +61 -13
  29. package/dist/dom/realm.d.ts +30 -0
  30. package/dist/dom/realm.js +58 -0
  31. package/dist/dom/refs.d.ts +0 -1
  32. package/dist/dom/refs.js +0 -1
  33. package/dist/dom/shadow-registry.d.ts +40 -0
  34. package/dist/dom/shadow-registry.js +165 -0
  35. package/dist/dom/snapshot.d.ts +2 -2
  36. package/dist/dom/snapshot.js +21 -4
  37. package/dist/dom/source.d.ts +0 -1
  38. package/dist/dom/source.js +0 -1
  39. package/dist/dom/theme.d.ts +0 -1
  40. package/dist/dom/theme.js +0 -1
  41. package/dist/dom/virtualized.d.ts +19 -0
  42. package/dist/dom/virtualized.js +80 -0
  43. package/dist/index.d.ts +3 -4
  44. package/dist/index.js +2 -3
  45. package/dist/observers/animation.d.ts +0 -1
  46. package/dist/observers/animation.js +0 -1
  47. package/dist/observers/blind-spots.d.ts +16 -4
  48. package/dist/observers/blind-spots.js +65 -11
  49. package/dist/observers/console.d.ts +0 -1
  50. package/dist/observers/console.js +0 -1
  51. package/dist/observers/dom.d.ts +0 -2
  52. package/dist/observers/dom.js +67 -9
  53. package/dist/observers/download.d.ts +6 -0
  54. package/dist/observers/download.js +103 -0
  55. package/dist/observers/focus.d.ts +0 -1
  56. package/dist/observers/focus.js +0 -1
  57. package/dist/observers/frames.d.ts +12 -0
  58. package/dist/observers/frames.js +67 -0
  59. package/dist/observers/health.d.ts +0 -1
  60. package/dist/observers/health.js +30 -2
  61. package/dist/observers/install-all.d.ts +5 -0
  62. package/dist/observers/install-all.js +63 -0
  63. package/dist/observers/ipc.d.ts +22 -0
  64. package/dist/observers/ipc.js +121 -0
  65. package/dist/observers/network-body.d.ts +17 -1
  66. package/dist/observers/network-body.js +26 -1
  67. package/dist/observers/network-redact.d.ts +0 -1
  68. package/dist/observers/network-redact.js +6 -3
  69. package/dist/observers/network-stream.d.ts +23 -0
  70. package/dist/observers/network-stream.js +102 -0
  71. package/dist/observers/network.d.ts +11 -1
  72. package/dist/observers/network.js +7 -1
  73. package/dist/observers/perf.d.ts +0 -1
  74. package/dist/observers/perf.js +0 -1
  75. package/dist/observers/route.d.ts +0 -1
  76. package/dist/observers/route.js +0 -1
  77. package/dist/observers/scroll.d.ts +0 -1
  78. package/dist/observers/scroll.js +0 -1
  79. package/dist/observers/sdk-failure.d.ts +28 -0
  80. package/dist/observers/sdk-failure.js +60 -0
  81. package/dist/observers/state.d.ts +0 -1
  82. package/dist/observers/state.js +0 -1
  83. package/dist/observers/storage.d.ts +0 -1
  84. package/dist/observers/storage.js +0 -1
  85. package/dist/observers/types.d.ts +0 -1
  86. package/dist/observers/types.js +0 -1
  87. package/dist/patching/capture-method.d.ts +0 -1
  88. package/dist/patching/capture-method.js +0 -1
  89. package/dist/presenter/overlay.d.ts +0 -1
  90. package/dist/presenter/overlay.js +0 -1
  91. package/dist/presenter/presenter-config.d.ts +0 -1
  92. package/dist/presenter/presenter-config.js +0 -1
  93. package/dist/presenter/presenter-controls.d.ts +0 -1
  94. package/dist/presenter/presenter-controls.js +0 -1
  95. package/dist/presenter/presenter-effects.d.ts +0 -1
  96. package/dist/presenter/presenter-effects.js +0 -1
  97. package/dist/presenter/presenter-glow.d.ts +0 -1
  98. package/dist/presenter/presenter-glow.js +0 -1
  99. package/dist/presenter/presenter-log.d.ts +0 -1
  100. package/dist/presenter/presenter-log.js +0 -1
  101. package/dist/presenter/presenter-run-state.d.ts +0 -1
  102. package/dist/presenter/presenter-run-state.js +0 -1
  103. package/dist/presenter/presenter-styles.d.ts +0 -1
  104. package/dist/presenter/presenter-styles.js +0 -1
  105. package/dist/presenter/presenter-tally.d.ts +0 -1
  106. package/dist/presenter/presenter-tally.js +0 -1
  107. package/dist/presenter/presenter-test-helpers.d.ts +0 -1
  108. package/dist/presenter/presenter-test-helpers.js +0 -1
  109. package/dist/presenter/presenter-verbs.d.ts +0 -1
  110. package/dist/presenter/presenter-verbs.js +0 -1
  111. package/dist/presenter/presenter.d.ts +0 -1
  112. package/dist/presenter/presenter.js +0 -1
  113. package/dist/recorder/recorder-styles.d.ts +0 -1
  114. package/dist/recorder/recorder-styles.js +0 -1
  115. package/dist/recorder/recorder.d.ts +0 -1
  116. package/dist/recorder/recorder.js +0 -1
  117. package/dist/registry/adapters.d.ts +0 -1
  118. package/dist/registry/adapters.js +0 -1
  119. package/dist/registry/capabilities.d.ts +2 -1
  120. package/dist/registry/capabilities.js +16 -1
  121. package/dist/registry/commit-and-signal.d.ts +0 -1
  122. package/dist/registry/commit-and-signal.js +0 -1
  123. package/dist/registry/domains.d.ts +0 -1
  124. package/dist/registry/domains.js +0 -1
  125. package/dist/registry/emitter.d.ts +0 -1
  126. package/dist/registry/emitter.js +0 -1
  127. package/dist/registry/store-adapters.d.ts +141 -7
  128. package/dist/registry/store-adapters.js +178 -1
  129. package/dist/registry/stores.d.ts +0 -1
  130. package/dist/registry/stores.js +8 -1
  131. package/dist/reticle-presenter-helpers.d.ts +0 -1
  132. package/dist/reticle-presenter-helpers.js +0 -1
  133. package/dist/reticle.d.ts +5 -59
  134. package/dist/reticle.js +37 -33
  135. package/dist/review/annotator.d.ts +0 -1
  136. package/dist/review/annotator.js +0 -1
  137. package/dist/review/mark-anchor.d.ts +0 -1
  138. package/dist/review/mark-anchor.js +0 -1
  139. package/dist/security/serialization.d.ts +0 -1
  140. package/dist/security/serialization.js +0 -1
  141. package/dist/timers/clock.d.ts +0 -1
  142. package/dist/timers/clock.js +0 -1
  143. package/dist/timers/native-console.d.ts +0 -1
  144. package/dist/timers/native-console.js +0 -1
  145. package/dist/timers/native-timers.d.ts +0 -1
  146. package/dist/timers/native-timers.js +0 -1
  147. package/dist/transport/transport.d.ts +12 -6
  148. package/dist/transport/transport.js +107 -17
  149. package/package.json +13 -3
  150. package/dist/actions/actions-dom.d.ts.map +0 -1
  151. package/dist/actions/actions-dom.js.map +0 -1
  152. package/dist/actions/actions.d.ts.map +0 -1
  153. package/dist/actions/actions.js.map +0 -1
  154. package/dist/actions/scroll.d.ts.map +0 -1
  155. package/dist/actions/scroll.js.map +0 -1
  156. package/dist/commands/commands.d.ts.map +0 -1
  157. package/dist/commands/commands.js.map +0 -1
  158. package/dist/dom/a11y.d.ts.map +0 -1
  159. package/dist/dom/a11y.js.map +0 -1
  160. package/dist/dom/auto-anchor.d.ts.map +0 -1
  161. package/dist/dom/auto-anchor.js.map +0 -1
  162. package/dist/dom/blind-spots.d.ts.map +0 -1
  163. package/dist/dom/blind-spots.js.map +0 -1
  164. package/dist/dom/chart.d.ts.map +0 -1
  165. package/dist/dom/chart.js.map +0 -1
  166. package/dist/dom/dom-ignore.d.ts.map +0 -1
  167. package/dist/dom/dom-ignore.js.map +0 -1
  168. package/dist/dom/occlusion.d.ts.map +0 -1
  169. package/dist/dom/occlusion.js.map +0 -1
  170. package/dist/dom/query.d.ts.map +0 -1
  171. package/dist/dom/query.js.map +0 -1
  172. package/dist/dom/refs.d.ts.map +0 -1
  173. package/dist/dom/refs.js.map +0 -1
  174. package/dist/dom/snapshot.d.ts.map +0 -1
  175. package/dist/dom/snapshot.js.map +0 -1
  176. package/dist/dom/source.d.ts.map +0 -1
  177. package/dist/dom/source.js.map +0 -1
  178. package/dist/dom/theme.d.ts.map +0 -1
  179. package/dist/dom/theme.js.map +0 -1
  180. package/dist/index.d.ts.map +0 -1
  181. package/dist/index.js.map +0 -1
  182. package/dist/observers/animation.d.ts.map +0 -1
  183. package/dist/observers/animation.js.map +0 -1
  184. package/dist/observers/blind-spots.d.ts.map +0 -1
  185. package/dist/observers/blind-spots.js.map +0 -1
  186. package/dist/observers/console.d.ts.map +0 -1
  187. package/dist/observers/console.js.map +0 -1
  188. package/dist/observers/dom.d.ts.map +0 -1
  189. package/dist/observers/dom.js.map +0 -1
  190. package/dist/observers/focus.d.ts.map +0 -1
  191. package/dist/observers/focus.js.map +0 -1
  192. package/dist/observers/health.d.ts.map +0 -1
  193. package/dist/observers/health.js.map +0 -1
  194. package/dist/observers/network-body.d.ts.map +0 -1
  195. package/dist/observers/network-body.js.map +0 -1
  196. package/dist/observers/network-redact.d.ts.map +0 -1
  197. package/dist/observers/network-redact.js.map +0 -1
  198. package/dist/observers/network.d.ts.map +0 -1
  199. package/dist/observers/network.js.map +0 -1
  200. package/dist/observers/perf.d.ts.map +0 -1
  201. package/dist/observers/perf.js.map +0 -1
  202. package/dist/observers/route.d.ts.map +0 -1
  203. package/dist/observers/route.js.map +0 -1
  204. package/dist/observers/scroll.d.ts.map +0 -1
  205. package/dist/observers/scroll.js.map +0 -1
  206. package/dist/observers/state.d.ts.map +0 -1
  207. package/dist/observers/state.js.map +0 -1
  208. package/dist/observers/storage.d.ts.map +0 -1
  209. package/dist/observers/storage.js.map +0 -1
  210. package/dist/observers/types.d.ts.map +0 -1
  211. package/dist/observers/types.js.map +0 -1
  212. package/dist/patching/capture-method.d.ts.map +0 -1
  213. package/dist/patching/capture-method.js.map +0 -1
  214. package/dist/presenter/overlay.d.ts.map +0 -1
  215. package/dist/presenter/overlay.js.map +0 -1
  216. package/dist/presenter/presenter-config.d.ts.map +0 -1
  217. package/dist/presenter/presenter-config.js.map +0 -1
  218. package/dist/presenter/presenter-controls.d.ts.map +0 -1
  219. package/dist/presenter/presenter-controls.js.map +0 -1
  220. package/dist/presenter/presenter-effects.d.ts.map +0 -1
  221. package/dist/presenter/presenter-effects.js.map +0 -1
  222. package/dist/presenter/presenter-glow.d.ts.map +0 -1
  223. package/dist/presenter/presenter-glow.js.map +0 -1
  224. package/dist/presenter/presenter-log.d.ts.map +0 -1
  225. package/dist/presenter/presenter-log.js.map +0 -1
  226. package/dist/presenter/presenter-run-state.d.ts.map +0 -1
  227. package/dist/presenter/presenter-run-state.js.map +0 -1
  228. package/dist/presenter/presenter-styles.d.ts.map +0 -1
  229. package/dist/presenter/presenter-styles.js.map +0 -1
  230. package/dist/presenter/presenter-tally.d.ts.map +0 -1
  231. package/dist/presenter/presenter-tally.js.map +0 -1
  232. package/dist/presenter/presenter-test-helpers.d.ts.map +0 -1
  233. package/dist/presenter/presenter-test-helpers.js.map +0 -1
  234. package/dist/presenter/presenter-verbs.d.ts.map +0 -1
  235. package/dist/presenter/presenter-verbs.js.map +0 -1
  236. package/dist/presenter/presenter.d.ts.map +0 -1
  237. package/dist/presenter/presenter.js.map +0 -1
  238. package/dist/recorder/recorder-styles.d.ts.map +0 -1
  239. package/dist/recorder/recorder-styles.js.map +0 -1
  240. package/dist/recorder/recorder.d.ts.map +0 -1
  241. package/dist/recorder/recorder.js.map +0 -1
  242. package/dist/registry/adapters.d.ts.map +0 -1
  243. package/dist/registry/adapters.js.map +0 -1
  244. package/dist/registry/capabilities.d.ts.map +0 -1
  245. package/dist/registry/capabilities.js.map +0 -1
  246. package/dist/registry/commit-and-signal.d.ts.map +0 -1
  247. package/dist/registry/commit-and-signal.js.map +0 -1
  248. package/dist/registry/domains.d.ts.map +0 -1
  249. package/dist/registry/domains.js.map +0 -1
  250. package/dist/registry/emitter.d.ts.map +0 -1
  251. package/dist/registry/emitter.js.map +0 -1
  252. package/dist/registry/store-adapters.d.ts.map +0 -1
  253. package/dist/registry/store-adapters.js.map +0 -1
  254. package/dist/registry/stores.d.ts.map +0 -1
  255. package/dist/registry/stores.js.map +0 -1
  256. package/dist/reticle-presenter-helpers.d.ts.map +0 -1
  257. package/dist/reticle-presenter-helpers.js.map +0 -1
  258. package/dist/reticle.d.ts.map +0 -1
  259. package/dist/reticle.js.map +0 -1
  260. package/dist/review/annotator.d.ts.map +0 -1
  261. package/dist/review/annotator.js.map +0 -1
  262. package/dist/review/mark-anchor.d.ts.map +0 -1
  263. package/dist/review/mark-anchor.js.map +0 -1
  264. package/dist/security/serialization.d.ts.map +0 -1
  265. package/dist/security/serialization.js.map +0 -1
  266. package/dist/timers/clock.d.ts.map +0 -1
  267. package/dist/timers/clock.js.map +0 -1
  268. package/dist/timers/native-console.d.ts.map +0 -1
  269. package/dist/timers/native-console.js.map +0 -1
  270. package/dist/timers/native-timers.d.ts.map +0 -1
  271. package/dist/timers/native-timers.js.map +0 -1
  272. package/dist/transport/transport.d.ts.map +0 -1
  273. package/dist/transport/transport.js.map +0 -1
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Every shadow root this SDK has seen created, open or closed.
3
+ *
4
+ * Two problems are solved by the same record.
5
+ *
6
+ * **Observation.** A `MutationObserver` on `documentElement` does NOT cross a shadow boundary, so a
7
+ * click that changes text inside a web component produced an entirely empty observe window. Measured
8
+ * on a console with a shadow-DOM alert badge: the click landed, the badge changed, and `observe`
9
+ * reported zero DOM events — indistinguishable from an app that ignored the click. The DOM observer
10
+ * needs a list of roots to attach to, and no API enumerates them.
11
+ *
12
+ * **Closed roots.** `element.shadowRoot` is null forever for `mode: 'closed'`, so a closed root is
13
+ * unreadable AFTER the fact — but `attachShadow` still RETURNS it to its caller. Patching that call
14
+ * captures the root at the one instant it is exposed. This only works when the SDK is installed
15
+ * before the component upgrades, which is why hosts are tracked individually rather than assumed:
16
+ * whatever was missed is still declared as a blind spot, and only what was genuinely captured stops
17
+ * being one.
18
+ */
19
+ /**
20
+ * Bookkeeping ceiling. Weak references make the ROOTS collectable; this bounds the entries pointing
21
+ * at them, which are not. Sized far above any real page's live component count.
22
+ */
23
+ export declare const MAX_TRACKED_ROOTS = 4000;
24
+ /** Dead-entry sweeps are O(retained), so they run once per this many roots rather than per root. */
25
+ export declare const SWEEP_EVERY = 250;
26
+ /** Shadow roots captured so far. Includes closed roots when the patch was installed in time. */
27
+ export declare function capturedRoots(): readonly ShadowRoot[];
28
+ /** Whether this element's shadow root was captured — i.e. whether its contents are reachable. */
29
+ export declare function isCaptured(host: Element): boolean;
30
+ /** The captured root for a host, or null. Non-null for closed roots the patch caught in time. */
31
+ export declare function capturedRootOf(host: Element): ShadowRoot | null;
32
+ /** Run `listener` for every root captured from now on. Returns an unsubscribe. */
33
+ export declare function onShadowRoot(listener: (root: ShadowRoot) => void): () => void;
34
+ /**
35
+ * Patch `attachShadow` to record each root as it is created, and sweep the roots that already exist.
36
+ *
37
+ * The sweep can only find OPEN roots (there is no other way in), so a closed root attached before
38
+ * install stays unreachable — correctly, and it is declared as such.
39
+ */
40
+ export declare function installShadowRegistry(): () => void;
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Every shadow root this SDK has seen created, open or closed.
3
+ *
4
+ * Two problems are solved by the same record.
5
+ *
6
+ * **Observation.** A `MutationObserver` on `documentElement` does NOT cross a shadow boundary, so a
7
+ * click that changes text inside a web component produced an entirely empty observe window. Measured
8
+ * on a console with a shadow-DOM alert badge: the click landed, the badge changed, and `observe`
9
+ * reported zero DOM events — indistinguishable from an app that ignored the click. The DOM observer
10
+ * needs a list of roots to attach to, and no API enumerates them.
11
+ *
12
+ * **Closed roots.** `element.shadowRoot` is null forever for `mode: 'closed'`, so a closed root is
13
+ * unreadable AFTER the fact — but `attachShadow` still RETURNS it to its caller. Patching that call
14
+ * captures the root at the one instant it is exposed. This only works when the SDK is installed
15
+ * before the component upgrades, which is why hosts are tracked individually rather than assumed:
16
+ * whatever was missed is still declared as a blind spot, and only what was genuinely captured stops
17
+ * being one.
18
+ */
19
+ import { captureMethod } from '../patching/capture-method.js';
20
+ /**
21
+ * How many installs are live.
22
+ *
23
+ * The state below is module-level, and a dev-only SDK gets installed more than once: Vite re-runs the
24
+ * module on hot reload, so `connect()` can run again before the previous instance is torn down.
25
+ * Measured: install, subscribe, install again, tear down the SECOND one — and the FIRST instance's
26
+ * subscribers were gone, so the DOM observer silently stopped being told about new shadow roots for
27
+ * the rest of the session. Shared state must only be cleared by the last install standing.
28
+ */
29
+ let installs = 0;
30
+ /**
31
+ * Retained shadow roots, weakly.
32
+ *
33
+ * This was a strong `Set` and it never shrank. Measured: a virtualized list that renders and removes
34
+ * 5,000 web-component rows left 5,000 roots retained — each pinning its whole shadow subtree, and
35
+ * pinning its host through `root.host`, so nothing the list discarded could ever be collected. A
36
+ * design system's rows ARE web components, so the most ordinary data-heavy page is the worst case,
37
+ * and this SDK is meant to sit in a dev session all day.
38
+ *
39
+ * Same shape `RefRegistry` already uses for element handles: hold weakly, bound the bookkeeping,
40
+ * sweep the dead entries periodically rather than on every write.
41
+ */
42
+ const roots = new Set();
43
+ /**
44
+ * Membership, separately and weakly.
45
+ *
46
+ * The weak entries above are for ENUMERATION and cannot answer "have I seen this root" without
47
+ * dereferencing all of them — which turns every `attachShadow` into a scan of every root so far, and
48
+ * a 5,000-row list into 25 million comparisons. A WeakSet answers it in O(1) and retains nothing.
49
+ */
50
+ const known = new WeakSet();
51
+ const hosts = new WeakSet();
52
+ /**
53
+ * Bookkeeping ceiling. Weak references make the ROOTS collectable; this bounds the entries pointing
54
+ * at them, which are not. Sized far above any real page's live component count.
55
+ */
56
+ export const MAX_TRACKED_ROOTS = 4000;
57
+ /** Dead-entry sweeps are O(retained), so they run once per this many roots rather than per root. */
58
+ export const SWEEP_EVERY = 250;
59
+ let sinceSweep = 0;
60
+ /** Drop entries whose root has been collected, then any excess by age (Set keeps insertion order). */
61
+ function sweep() {
62
+ for (const ref of roots) {
63
+ if (ref.deref() === undefined)
64
+ roots.delete(ref);
65
+ }
66
+ while (roots.size > MAX_TRACKED_ROOTS) {
67
+ const oldest = roots.values().next();
68
+ if (oldest.done === true)
69
+ break;
70
+ roots.delete(oldest.value);
71
+ }
72
+ }
73
+ /** The live roots behind the weak entries. */
74
+ function liveRoots() {
75
+ const out = [];
76
+ for (const ref of roots) {
77
+ const root = ref.deref();
78
+ if (root !== undefined)
79
+ out.push(root);
80
+ }
81
+ return out;
82
+ }
83
+ const listeners = new Set();
84
+ function record(root, host) {
85
+ // Idempotent. A hot reload leaves one patch wrapping another, so a single `attachShadow` travels
86
+ // through both and reports twice; the initial sweep can also meet a root the patch already caught.
87
+ // Subscribers must see each root exactly once — they attach an observer per root, and counting one
88
+ // twice is how a "reported once" guarantee quietly becomes "reported per install".
89
+ if (known.has(root))
90
+ return;
91
+ known.add(root);
92
+ roots.add(new WeakRef(root));
93
+ sinceSweep += 1;
94
+ if (sinceSweep >= SWEEP_EVERY) {
95
+ sinceSweep = 0;
96
+ sweep();
97
+ }
98
+ hosts.add(host);
99
+ for (const listener of listeners)
100
+ listener(root);
101
+ }
102
+ /** Shadow roots captured so far. Includes closed roots when the patch was installed in time. */
103
+ export function capturedRoots() {
104
+ return liveRoots();
105
+ }
106
+ /** Whether this element's shadow root was captured — i.e. whether its contents are reachable. */
107
+ export function isCaptured(host) {
108
+ return hosts.has(host);
109
+ }
110
+ /** The captured root for a host, or null. Non-null for closed roots the patch caught in time. */
111
+ export function capturedRootOf(host) {
112
+ if (!hosts.has(host))
113
+ return null;
114
+ for (const root of liveRoots())
115
+ if (root.host === host)
116
+ return root;
117
+ return null;
118
+ }
119
+ /** Run `listener` for every root captured from now on. Returns an unsubscribe. */
120
+ export function onShadowRoot(listener) {
121
+ listeners.add(listener);
122
+ return () => listeners.delete(listener);
123
+ }
124
+ /**
125
+ * Patch `attachShadow` to record each root as it is created, and sweep the roots that already exist.
126
+ *
127
+ * The sweep can only find OPEN roots (there is no other way in), so a closed root attached before
128
+ * install stays unreachable — correctly, and it is declared as such.
129
+ */
130
+ export function installShadowRegistry() {
131
+ const proto = Element.prototype;
132
+ // Through captureMethod, like every other patch site here: reading a method to hold and restore it
133
+ // is the one thing `unbound-method` exists to flag, and the intention is named there once.
134
+ const original = captureMethod(proto, 'attachShadow');
135
+ if (typeof original !== 'function')
136
+ return () => undefined;
137
+ installs += 1;
138
+ const patched = function patchedAttachShadow(init) {
139
+ const root = original.call(this, init);
140
+ record(root, this);
141
+ return root;
142
+ };
143
+ proto.attachShadow = patched;
144
+ const sweep = (node) => {
145
+ for (const el of node.querySelectorAll('*')) {
146
+ const root = el.shadowRoot;
147
+ if (root === null)
148
+ continue;
149
+ record(root, el); // idempotent — a root the patch already caught is skipped inside
150
+ sweep(root);
151
+ }
152
+ };
153
+ if (document.documentElement !== null)
154
+ sweep(document.documentElement);
155
+ return () => {
156
+ // Restore only if nobody patched over us; clobbering a later patch is worse than leaving ours.
157
+ if (captureMethod(proto, 'attachShadow') === patched)
158
+ proto.attachShadow = original;
159
+ installs -= 1;
160
+ if (installs > 0)
161
+ return; // another install is still using this state
162
+ roots.clear();
163
+ listeners.clear();
164
+ };
165
+ }
@@ -2,7 +2,8 @@ import { SnapshotMode } from '@reticlehq/core';
2
2
  interface SnapshotStatus {
3
3
  route: string;
4
4
  title: string;
5
- visibleDialogs: string[];
5
+ /** Open dialogs, OMITTED when there are none — absence means "no dialog is up". */
6
+ visibleDialogs?: string[];
6
7
  }
7
8
  export interface SnapshotResult {
8
9
  tree: string;
@@ -25,4 +26,3 @@ interface SnapshotOptions {
25
26
  /** Build the semantic accessibility snapshot of the page or a subtree. */
26
27
  export declare function buildSnapshot(options?: SnapshotOptions): SnapshotResult;
27
28
  export {};
28
- //# sourceMappingURL=snapshot.d.ts.map
@@ -1,4 +1,6 @@
1
1
  import { ElementState, SnapshotMode } from '@reticlehq/core';
2
+ import { capturedRootOf } from './shadow-registry.js';
3
+ import { isFrame } from './realm.js';
2
4
  import { getAccessibleName, getRole, getStates, getValue, isVisible } from './a11y.js';
3
5
  import { refs } from './refs.js';
4
6
  import { isIgnored } from './dom-ignore.js';
@@ -93,10 +95,16 @@ function layoutSignature(style) {
93
95
  */
94
96
  function pierceChildren(parent) {
95
97
  const out = [...parent.children];
96
- const shadow = parent.shadowRoot;
98
+ // A CLOSED root reports `shadowRoot === null` forever, but the registry captured it at the moment
99
+ // `attachShadow` returned it. `query` has been able to reach that content since; the snapshot could
100
+ // not, so the two tools disagreed about what is on the page — and the snapshot is the one an agent
101
+ // reads to decide what to query for, which makes its omission the one that actually costs.
102
+ const shadow = parent.shadowRoot ?? capturedRootOf(parent);
97
103
  if (shadow !== null)
98
104
  out.push(...shadow.children);
99
- if (parent instanceof HTMLIFrameElement) {
105
+ // Realm-aware: an iframe nested INSIDE another frame's body belongs to that frame's realm, so the
106
+ // top window's constructor never matches it and nested embeds were silently never pierced.
107
+ if (isFrame(parent)) {
100
108
  try {
101
109
  const body = parent.contentDocument?.body;
102
110
  if (body !== null && body !== undefined)
@@ -156,11 +164,21 @@ function collectDialogs(root) {
156
164
  }
157
165
  return names;
158
166
  }
167
+ /**
168
+ * Status for a snapshot, with uninformative defaults OMITTED.
169
+ *
170
+ * `reticle_act` already follows this rule — "fields at their uninformative default are omitted so a
171
+ * clean action collapses to its consequence" — and snapshot did not, so every response carried
172
+ * `visibleDialogs: []` whether or not a dialog existed. An empty array is the overwhelmingly common
173
+ * case, so the field was almost pure repetition; a reader learns nothing from its presence and
174
+ * everything from it.
175
+ */
159
176
  function buildStatus(root) {
177
+ const visibleDialogs = collectDialogs(root);
160
178
  return {
161
179
  route: `${location.pathname}${location.search}${location.hash}`,
162
180
  title: document.title,
163
- visibleDialogs: collectDialogs(root),
181
+ ...(visibleDialogs.length > 0 ? { visibleDialogs } : {}),
164
182
  };
165
183
  }
166
184
  /** Build the semantic accessibility snapshot of the page or a subtree. */
@@ -195,4 +213,3 @@ export function buildSnapshot(options = {}) {
195
213
  truncated: ctx.truncated,
196
214
  };
197
215
  }
198
- //# sourceMappingURL=snapshot.js.map
@@ -37,4 +37,3 @@ export declare function sourceFor(el: Element, adapterSource: SourceLocation | u
37
37
  * opening an editor or printing it.
38
38
  */
39
39
  export declare function formatSource(source: SourceLocation | undefined): string | undefined;
40
- //# sourceMappingURL=source.d.ts.map
@@ -56,4 +56,3 @@ export function sourceFor(el, adapterSource) {
56
56
  export function formatSource(source) {
57
57
  return source === undefined ? undefined : `${source.file}:${String(source.line)}`;
58
58
  }
59
- //# sourceMappingURL=source.js.map
@@ -23,4 +23,3 @@ export declare function themeReport(cs: CSSStyleDeclaration): ThemeReport;
23
23
  /** Drop the cached palette (call if the app swaps themes at runtime). */
24
24
  export declare function resetThemeCache(): void;
25
25
  export {};
26
- //# sourceMappingURL=theme.d.ts.map
package/dist/dom/theme.js CHANGED
@@ -87,4 +87,3 @@ export function themeReport(cs) {
87
87
  export function resetThemeCache() {
88
88
  cached = null;
89
89
  }
90
- //# sourceMappingURL=theme.js.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Rows a scroll container has reserved space for but has NOT rendered.
3
+ *
4
+ * `BlindSpotKind.VIRTUALIZED_UNMOUNTED` has had a label on the server since it was defined and
5
+ * nothing ever emitted it — a declared blind spot that could not fire, shaped exactly like the most
6
+ * common data-heavy UI there is. Measured on a 10,000-row console: 29 rows in the DOM, and a verdict
7
+ * that reported full coverage. An assertion like "no shipment is held" was a claim about 29 rows,
8
+ * delivered as a claim about all of them.
9
+ *
10
+ * The detector measures EMPTY RESERVED SPACE rather than guessing from child counts. A virtualizer
11
+ * sizes its scroll area for the whole list and renders only a window, so the area above the first
12
+ * child and below the last is space the container has promised and not filled. An ordinary list —
13
+ * even one with large gaps or margins between rows — spans its own scroll height, so it measures
14
+ * zero and never reports.
15
+ */
16
+ /** How many rows a container is holding space for but has not rendered. 0 when it is not virtualized. */
17
+ export declare function unmountedRowsIn(container: HTMLElement): number;
18
+ /** Total unmounted rows across every scroll container on the page. */
19
+ export declare function countUnmountedRows(): number;
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Rows a scroll container has reserved space for but has NOT rendered.
3
+ *
4
+ * `BlindSpotKind.VIRTUALIZED_UNMOUNTED` has had a label on the server since it was defined and
5
+ * nothing ever emitted it — a declared blind spot that could not fire, shaped exactly like the most
6
+ * common data-heavy UI there is. Measured on a 10,000-row console: 29 rows in the DOM, and a verdict
7
+ * that reported full coverage. An assertion like "no shipment is held" was a claim about 29 rows,
8
+ * delivered as a claim about all of them.
9
+ *
10
+ * The detector measures EMPTY RESERVED SPACE rather than guessing from child counts. A virtualizer
11
+ * sizes its scroll area for the whole list and renders only a window, so the area above the first
12
+ * child and below the last is space the container has promised and not filled. An ordinary list —
13
+ * even one with large gaps or margins between rows — spans its own scroll height, so it measures
14
+ * zero and never reports.
15
+ */
16
+ /** Below this, the empty space is padding or a sticky header rather than a virtualized remainder. */
17
+ const UNMOUNTED_RATIO = 0.25;
18
+ /** A container has to be meaningfully scrollable before "what is not rendered" is even a question. */
19
+ const MIN_SCROLL_RATIO = 1.2;
20
+ /**
21
+ * Virtualizers usually put one full-height SPACER inside the scroller and position rows absolutely
22
+ * inside it, so the scroller's own children are just that spacer. Descend through it to reach the
23
+ * rows — without this the spacer measures as filling the container and nothing is ever detected.
24
+ */
25
+ function rowHost(container) {
26
+ let host = container;
27
+ for (let depth = 0; depth < 3; depth += 1) {
28
+ const children = Array.from(host.children).filter((c) => c instanceof HTMLElement);
29
+ const only = children.length === 1 ? children[0] : undefined;
30
+ if (only === undefined)
31
+ return host;
32
+ // A spacer is a single child that fills (or over-fills) the scroll area.
33
+ if (only.offsetHeight < host.scrollHeight * 0.9)
34
+ return host;
35
+ host = only;
36
+ }
37
+ return host;
38
+ }
39
+ /** How many rows a container is holding space for but has not rendered. 0 when it is not virtualized. */
40
+ export function unmountedRowsIn(container) {
41
+ const scrollHeight = container.scrollHeight;
42
+ const clientHeight = container.clientHeight;
43
+ if (clientHeight <= 0 || scrollHeight < clientHeight * MIN_SCROLL_RATIO)
44
+ return 0;
45
+ const host = rowHost(container);
46
+ const rows = Array.from(host.children).filter((c) => c instanceof HTMLElement);
47
+ if (rows.length < 2)
48
+ return 0;
49
+ let top = Infinity;
50
+ let bottom = 0;
51
+ let totalHeight = 0;
52
+ for (const row of rows) {
53
+ const rowTop = row.offsetTop;
54
+ const rowBottom = rowTop + row.offsetHeight;
55
+ if (rowTop < top)
56
+ top = rowTop;
57
+ if (rowBottom > bottom)
58
+ bottom = rowBottom;
59
+ totalHeight += row.offsetHeight;
60
+ }
61
+ // Space the container reserved and left empty: above the first row plus below the last.
62
+ const empty = Math.max(0, top) + Math.max(0, scrollHeight - bottom);
63
+ if (empty < scrollHeight * UNMOUNTED_RATIO)
64
+ return 0;
65
+ const averageRow = totalHeight / rows.length;
66
+ if (averageRow <= 0)
67
+ return 0;
68
+ return Math.round(empty / averageRow);
69
+ }
70
+ /** Total unmounted rows across every scroll container on the page. */
71
+ export function countUnmountedRows() {
72
+ let total = 0;
73
+ for (const element of document.querySelectorAll('*')) {
74
+ // Cheap gate first: only elements that actually scroll are worth measuring.
75
+ if (element.scrollHeight <= element.clientHeight)
76
+ continue;
77
+ total += unmountedRowsIn(element);
78
+ }
79
+ return total;
80
+ }
package/dist/index.d.ts CHANGED
@@ -8,9 +8,9 @@ export { registerAdapter, identifyComponent, readComponentState, elementHasHover
8
8
  export type { ReticleAdapter, ComponentInfo, ComponentSource } from './registry/adapters.js';
9
9
  export { registerStore, unregisterStore, storeNames, readStores, readStoresWithTruncation, } from './registry/stores.js';
10
10
  export type { StoreGetter, StoreLike, StoreSubscribe } from './registry/stores.js';
11
- export { tanstackQueryStore, jotaiStore, xstateStore, valtioStore, mobxStore, pushStore, } from './registry/store-adapters.js';
12
- export type { QuerySnapshot } from './registry/store-adapters.js';
13
- export { registerCapabilities, getCapabilities, hasCapabilities } from './registry/capabilities.js';
11
+ export { tanstackQueryStore, jotaiStore, xstateStore, valtioStore, mobxStore, recoilStore, svelteStore, piniaStore, pushStore, } from './registry/store-adapters.js';
12
+ export type { QuerySnapshot, RecoilAtomSnapshot } from './registry/store-adapters.js';
13
+ export { registerCapabilities, getCapabilities, hasCapabilities, setCapabilitiesListener, } from './registry/capabilities.js';
14
14
  export type { Capabilities, CapabilitiesInput, CapabilityFlow } from './registry/capabilities.js';
15
15
  export { createReticleEmitter } from './registry/emitter.js';
16
16
  export type { ReticleEmitter, EmitterTarget, CreateReticleEmitterOptions, } from './registry/emitter.js';
@@ -26,4 +26,3 @@ export { describe, getRole, getAccessibleName, getStates, isVisible } from './do
26
26
  export { refs, RefRegistry } from './dom/refs.js';
27
27
  export { Annotator, installAnnotator, type AnnotatorDeps } from './review/annotator.js';
28
28
  export { resolveMarkAnchor, type MarkAnchor } from './review/mark-anchor.js';
29
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -18,9 +18,9 @@ export { registerStore, unregisterStore, storeNames, readStores, readStoresWithT
18
18
  // Adapters for state libraries that do not natively expose `{getState, subscribe}`. zustand and Redux
19
19
  // need none of these; TanStack Query is the one that matters most, because a stale-cache bug fires no
20
20
  // request and renders a plausible value, so the cache is the only witness.
21
- export { tanstackQueryStore, jotaiStore, xstateStore, valtioStore, mobxStore, pushStore, } from './registry/store-adapters.js';
21
+ export { tanstackQueryStore, jotaiStore, xstateStore, valtioStore, mobxStore, recoilStore, svelteStore, piniaStore, pushStore, } from './registry/store-adapters.js';
22
22
  // Capability registry: the app self-describes its testable surface via reticle.describe.
23
- export { registerCapabilities, getCapabilities, hasCapabilities } from './registry/capabilities.js';
23
+ export { registerCapabilities, getCapabilities, hasCapabilities, setCapabilitiesListener, } from './registry/capabilities.js';
24
24
  // SDK helpers: adopt the recommended integration patterns without boilerplate.
25
25
  export { createReticleEmitter } from './registry/emitter.js';
26
26
  export { commitAndSignal } from './registry/commit-and-signal.js';
@@ -37,4 +37,3 @@ export { describe, getRole, getAccessibleName, getStates, isVisible } from './do
37
37
  export { refs, RefRegistry } from './dom/refs.js';
38
38
  export { Annotator, installAnnotator } from './review/annotator.js';
39
39
  export { resolveMarkAnchor } from './review/mark-anchor.js';
40
- //# sourceMappingURL=index.js.map
@@ -1,4 +1,3 @@
1
1
  import type { Emit, Teardown } from './types.js';
2
2
  /** Observe CSS animations + transitions and emit anim.start / anim.end. */
3
3
  export declare function installAnimation(emit: Emit): Teardown;
4
- //# sourceMappingURL=animation.d.ts.map
@@ -32,4 +32,3 @@ export function installAnimation(emit) {
32
32
  document.removeEventListener('transitionend', onTransitionEnd, true);
33
33
  };
34
34
  }
35
- //# sourceMappingURL=animation.js.map
@@ -3,10 +3,23 @@ import type { Emit, Teardown } from './types.js';
3
3
  * Blind-spot sensor. The SDK instruments the DOM, but a cross-origin iframe is a wall it cannot
4
4
  * see through — its contents, network, and console are invisible. Left unstated, a green verdict would
5
5
  * imply the whole page was verified. This detects cross-origin frames and emits a BLIND_SPOT event so the
6
- * server can mark results `coverage: partial` instead of lying by omission. Closed shadow roots and
7
- * virtualized-unmounted rows are the other kinds (detected elsewhere / by their tools); this sensor owns
8
- * the iframe case, the one that is cheaply and reliably detectable from the page.
6
+ * server can mark results `coverage: partial` instead of lying by omission. This sensor owns the three
7
+ * kinds cheaply and reliably detectable from the page: cross-origin frames, closed shadow roots, and
8
+ * virtualized-unmounted rows.
9
9
  */
10
+ /**
11
+ * Elements rendering content nobody outside them can read.
12
+ *
13
+ * `attachShadow({mode:'closed'})` makes `el.shadowRoot` null FOREVER, for every caller — Reticle,
14
+ * Playwright's accessibility snapshot, a screenshot-reading model, all of them. There is no API that
15
+ * recovers it, so the only honest behaviour is to say the region exists and is unreadable.
16
+ *
17
+ * It is not directly detectable either, so this infers it: a custom element (a dash in the tag name is
18
+ * the spec's own rule) that has NO light-DOM children and no text, yet occupies layout space, is
19
+ * painting from somewhere. Nothing else produces that combination — an empty custom element that
20
+ * renders nothing measures zero and is skipped.
21
+ */
22
+ export declare function countClosedShadowRoots(): number;
10
23
  /**
11
24
  * Whether a frame is cross-origin (unobservable). A same-origin frame exposes its `contentDocument`; a
12
25
  * cross-origin one returns null (or THROWS a SecurityError on access). A src-less / about:blank frame is
@@ -16,4 +29,3 @@ export declare function isCrossOriginFrame(frame: HTMLIFrameElement): boolean;
16
29
  /** How many of the given frames are cross-origin (unobservable). */
17
30
  export declare function countCrossOriginFrames(frames: readonly HTMLIFrameElement[]): number;
18
31
  export declare function installBlindSpots(emit: Emit): Teardown;
19
- //# sourceMappingURL=blind-spots.d.ts.map
@@ -1,13 +1,49 @@
1
1
  import { EventType, BlindSpotKind } from '@reticlehq/core';
2
+ import { countUnmountedRows } from '../dom/virtualized.js';
3
+ import { isCaptured } from '../dom/shadow-registry.js';
4
+ import { sameOriginFrameBodies } from './frames.js';
2
5
  import { nativeClearTimeout, nativeSetTimeout } from '../timers/native-timers.js';
3
6
  /**
4
7
  * Blind-spot sensor. The SDK instruments the DOM, but a cross-origin iframe is a wall it cannot
5
8
  * see through — its contents, network, and console are invisible. Left unstated, a green verdict would
6
9
  * imply the whole page was verified. This detects cross-origin frames and emits a BLIND_SPOT event so the
7
- * server can mark results `coverage: partial` instead of lying by omission. Closed shadow roots and
8
- * virtualized-unmounted rows are the other kinds (detected elsewhere / by their tools); this sensor owns
9
- * the iframe case, the one that is cheaply and reliably detectable from the page.
10
+ * server can mark results `coverage: partial` instead of lying by omission. This sensor owns the three
11
+ * kinds cheaply and reliably detectable from the page: cross-origin frames, closed shadow roots, and
12
+ * virtualized-unmounted rows.
10
13
  */
14
+ /**
15
+ * Elements rendering content nobody outside them can read.
16
+ *
17
+ * `attachShadow({mode:'closed'})` makes `el.shadowRoot` null FOREVER, for every caller — Reticle,
18
+ * Playwright's accessibility snapshot, a screenshot-reading model, all of them. There is no API that
19
+ * recovers it, so the only honest behaviour is to say the region exists and is unreadable.
20
+ *
21
+ * It is not directly detectable either, so this infers it: a custom element (a dash in the tag name is
22
+ * the spec's own rule) that has NO light-DOM children and no text, yet occupies layout space, is
23
+ * painting from somewhere. Nothing else produces that combination — an empty custom element that
24
+ * renders nothing measures zero and is skipped.
25
+ */
26
+ export function countClosedShadowRoots() {
27
+ let count = 0;
28
+ for (const el of document.querySelectorAll('*')) {
29
+ if (!el.tagName.includes('-'))
30
+ continue;
31
+ if (el.shadowRoot !== null)
32
+ continue; // open — readable, not a blind spot
33
+ // A closed root attached AFTER the SDK installed was captured from attachShadow's return value,
34
+ // so it is readable too. Only what was genuinely missed is declared.
35
+ if (isCaptured(el))
36
+ continue;
37
+ if (el.children.length > 0)
38
+ continue;
39
+ if ((el.textContent ?? '').trim().length > 0)
40
+ continue;
41
+ if (el.offsetHeight <= 0 && el.offsetWidth <= 0)
42
+ continue;
43
+ count += 1;
44
+ }
45
+ return count;
46
+ }
11
47
  /**
12
48
  * Whether a frame is cross-origin (unobservable). A same-origin frame exposes its `contentDocument`; a
13
49
  * cross-origin one returns null (or THROWS a SecurityError on access). A src-less / about:blank frame is
@@ -35,6 +71,15 @@ export function countCrossOriginFrames(frames) {
35
71
  function currentCount() {
36
72
  return countCrossOriginFrames(Array.from(document.querySelectorAll('iframe')));
37
73
  }
74
+ /**
75
+ * Same-origin frames — observed for DOM, NOT for network.
76
+ *
77
+ * Their `fetch` lives in the frame's own realm, which the top realm's patch never sees. Left
78
+ * undeclared, `settled` can read true while a frame request is still in flight.
79
+ */
80
+ function uninstrumentedFrameCount() {
81
+ return sameOriginFrameBodies(document).length;
82
+ }
38
83
  /**
39
84
  * Watch the page for cross-origin iframes and emit BLIND_SPOT whenever the count CHANGES (install +
40
85
  * on any added/removed frame). Only the delta is emitted — never a per-mutation flood — so a static
@@ -48,14 +93,24 @@ function currentCount() {
48
93
  */
49
94
  const RECHECK_DEBOUNCE_MS = 250;
50
95
  export function installBlindSpots(emit) {
51
- let last = -1;
96
+ // Every kind is counted the same way and emitted on CHANGE only, so a static embed or a steady list
97
+ // reports once instead of flooding. Virtualized rows matter most: without them an assertion over a
98
+ // 10,000-row grid is a claim about the ~29 on screen, delivered as full coverage.
99
+ const sensors = [
100
+ { kind: BlindSpotKind.CROSS_ORIGIN_IFRAME, count: currentCount },
101
+ { kind: BlindSpotKind.UNINSTRUMENTED_FRAME, count: uninstrumentedFrameCount },
102
+ { kind: BlindSpotKind.CLOSED_SHADOW_ROOT, count: countClosedShadowRoots },
103
+ { kind: BlindSpotKind.VIRTUALIZED_UNMOUNTED, count: countUnmountedRows },
104
+ ];
105
+ const last = new Map();
52
106
  const report = () => {
53
- const count = currentCount();
54
- if (count === last)
55
- return;
56
- last = count;
57
- if (count > 0) {
58
- emit(EventType.BLIND_SPOT, { kind: BlindSpotKind.CROSS_ORIGIN_IFRAME, count });
107
+ for (const sensor of sensors) {
108
+ const count = sensor.count();
109
+ if (count === last.get(sensor.kind))
110
+ continue;
111
+ last.set(sensor.kind, count);
112
+ if (count > 0)
113
+ emit(EventType.BLIND_SPOT, { kind: sensor.kind, count });
59
114
  }
60
115
  };
61
116
  report();
@@ -86,4 +141,3 @@ export function installBlindSpots(emit) {
86
141
  observer.disconnect();
87
142
  };
88
143
  }
89
- //# sourceMappingURL=blind-spots.js.map
@@ -1,4 +1,3 @@
1
1
  import type { Emit, Teardown } from './types.js';
2
2
  /** Patch console.{log,warn,error} and window error events. Reversible. */
3
3
  export declare function installConsole(emit: Emit): Teardown;
4
- //# sourceMappingURL=console.d.ts.map
@@ -88,4 +88,3 @@ export function installConsole(emit) {
88
88
  window.removeEventListener('unhandledrejection', onRejection);
89
89
  };
90
90
  }
91
- //# sourceMappingURL=console.js.map
@@ -1,4 +1,2 @@
1
1
  import type { Emit, Teardown } from './types.js';
2
- /** Observe DOM mutations and emit semantic (not raw) events. */
3
2
  export declare function installDom(emit: Emit): Teardown;
4
- //# sourceMappingURL=dom.d.ts.map