@reticlehq/browser 2.1.0 → 2.2.1

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 (160) hide show
  1. package/NOTICE +5 -0
  2. package/dist/actions/actions.d.ts +1 -1
  3. package/dist/actions/actions.d.ts.map +1 -1
  4. package/dist/actions/actions.js +37 -19
  5. package/dist/actions/actions.js.map +1 -1
  6. package/dist/commands/commands.d.ts +2 -0
  7. package/dist/commands/commands.d.ts.map +1 -1
  8. package/dist/commands/commands.js +20 -6
  9. package/dist/commands/commands.js.map +1 -1
  10. package/dist/dom/a11y.d.ts +17 -6
  11. package/dist/dom/a11y.d.ts.map +1 -1
  12. package/dist/dom/a11y.js +68 -32
  13. package/dist/dom/a11y.js.map +1 -1
  14. package/dist/dom/auto-anchor.d.ts +10 -10
  15. package/dist/dom/auto-anchor.js +10 -10
  16. package/dist/dom/blind-spots.d.ts +14 -0
  17. package/dist/dom/blind-spots.d.ts.map +1 -0
  18. package/dist/dom/blind-spots.js +30 -0
  19. package/dist/dom/blind-spots.js.map +1 -0
  20. package/dist/dom/chart.d.ts +93 -0
  21. package/dist/dom/chart.d.ts.map +1 -0
  22. package/dist/dom/chart.js +119 -0
  23. package/dist/dom/chart.js.map +1 -0
  24. package/dist/dom/dom-ignore.d.ts.map +1 -1
  25. package/dist/dom/dom-ignore.js +7 -2
  26. package/dist/dom/dom-ignore.js.map +1 -1
  27. package/dist/dom/query.d.ts +17 -4
  28. package/dist/dom/query.d.ts.map +1 -1
  29. package/dist/dom/query.js +185 -30
  30. package/dist/dom/query.js.map +1 -1
  31. package/dist/dom/refs.d.ts +25 -2
  32. package/dist/dom/refs.d.ts.map +1 -1
  33. package/dist/dom/refs.js +78 -3
  34. package/dist/dom/refs.js.map +1 -1
  35. package/dist/dom/snapshot.d.ts +6 -0
  36. package/dist/dom/snapshot.d.ts.map +1 -1
  37. package/dist/dom/snapshot.js +6 -1
  38. package/dist/dom/snapshot.js.map +1 -1
  39. package/dist/dom/source.d.ts +40 -0
  40. package/dist/dom/source.d.ts.map +1 -0
  41. package/dist/dom/source.js +59 -0
  42. package/dist/dom/source.js.map +1 -0
  43. package/dist/dom/theme.js +2 -2
  44. package/dist/dom/theme.js.map +1 -1
  45. package/dist/index.d.ts +6 -2
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +9 -1
  48. package/dist/index.js.map +1 -1
  49. package/dist/observers/blind-spots.d.ts +19 -0
  50. package/dist/observers/blind-spots.d.ts.map +1 -0
  51. package/dist/observers/blind-spots.js +89 -0
  52. package/dist/observers/blind-spots.js.map +1 -0
  53. package/dist/observers/console.d.ts.map +1 -1
  54. package/dist/observers/console.js +39 -6
  55. package/dist/observers/console.js.map +1 -1
  56. package/dist/observers/dom.d.ts.map +1 -1
  57. package/dist/observers/dom.js +68 -9
  58. package/dist/observers/dom.js.map +1 -1
  59. package/dist/observers/focus.d.ts +10 -0
  60. package/dist/observers/focus.d.ts.map +1 -0
  61. package/dist/observers/focus.js +49 -0
  62. package/dist/observers/focus.js.map +1 -0
  63. package/dist/observers/network-body.d.ts +19 -0
  64. package/dist/observers/network-body.d.ts.map +1 -0
  65. package/dist/observers/network-body.js +143 -0
  66. package/dist/observers/network-body.js.map +1 -0
  67. package/dist/observers/network-redact.d.ts +8 -0
  68. package/dist/observers/network-redact.d.ts.map +1 -0
  69. package/dist/observers/network-redact.js +66 -0
  70. package/dist/observers/network-redact.js.map +1 -0
  71. package/dist/observers/network.d.ts +13 -6
  72. package/dist/observers/network.d.ts.map +1 -1
  73. package/dist/observers/network.js +288 -162
  74. package/dist/observers/network.js.map +1 -1
  75. package/dist/observers/route.d.ts.map +1 -1
  76. package/dist/observers/route.js +15 -9
  77. package/dist/observers/route.js.map +1 -1
  78. package/dist/observers/scroll.d.ts.map +1 -1
  79. package/dist/observers/scroll.js +35 -8
  80. package/dist/observers/scroll.js.map +1 -1
  81. package/dist/observers/state.d.ts +20 -0
  82. package/dist/observers/state.d.ts.map +1 -0
  83. package/dist/observers/state.js +87 -0
  84. package/dist/observers/state.js.map +1 -0
  85. package/dist/observers/storage.d.ts +9 -0
  86. package/dist/observers/storage.d.ts.map +1 -1
  87. package/dist/observers/storage.js +105 -3
  88. package/dist/observers/storage.js.map +1 -1
  89. package/dist/observers/types.d.ts +15 -0
  90. package/dist/observers/types.d.ts.map +1 -1
  91. package/dist/observers/types.js +29 -1
  92. package/dist/observers/types.js.map +1 -1
  93. package/dist/patching/capture-method.d.ts +27 -0
  94. package/dist/patching/capture-method.d.ts.map +1 -0
  95. package/dist/patching/capture-method.js +37 -0
  96. package/dist/patching/capture-method.js.map +1 -0
  97. package/dist/presenter/presenter-config.d.ts +3 -3
  98. package/dist/presenter/presenter-config.d.ts.map +1 -1
  99. package/dist/presenter/presenter-config.js +3 -3
  100. package/dist/presenter/presenter-config.js.map +1 -1
  101. package/dist/presenter/presenter-controls.d.ts +1 -1
  102. package/dist/presenter/presenter-controls.d.ts.map +1 -1
  103. package/dist/presenter/presenter-controls.js +3 -3
  104. package/dist/presenter/presenter-controls.js.map +1 -1
  105. package/dist/presenter/presenter-glow.d.ts +1 -1
  106. package/dist/presenter/presenter-glow.js +1 -1
  107. package/dist/presenter/presenter-styles.d.ts +1 -1
  108. package/dist/presenter/presenter-styles.d.ts.map +1 -1
  109. package/dist/presenter/presenter-styles.js +12 -3
  110. package/dist/presenter/presenter-styles.js.map +1 -1
  111. package/dist/presenter/presenter.d.ts +4 -4
  112. package/dist/presenter/presenter.d.ts.map +1 -1
  113. package/dist/presenter/presenter.js +5 -5
  114. package/dist/presenter/presenter.js.map +1 -1
  115. package/dist/recorder/recorder.d.ts +8 -8
  116. package/dist/recorder/recorder.d.ts.map +1 -1
  117. package/dist/recorder/recorder.js +9 -9
  118. package/dist/recorder/recorder.js.map +1 -1
  119. package/dist/registry/capabilities.d.ts +2 -2
  120. package/dist/registry/capabilities.d.ts.map +1 -1
  121. package/dist/registry/capabilities.js +1 -1
  122. package/dist/registry/capabilities.js.map +1 -1
  123. package/dist/registry/domains.d.ts +1 -1
  124. package/dist/registry/domains.js +1 -1
  125. package/dist/registry/emitter.d.ts +2 -2
  126. package/dist/registry/emitter.js +2 -2
  127. package/dist/registry/store-adapters.d.ts +128 -0
  128. package/dist/registry/store-adapters.d.ts.map +1 -0
  129. package/dist/registry/store-adapters.js +135 -0
  130. package/dist/registry/store-adapters.js.map +1 -0
  131. package/dist/registry/stores.d.ts +38 -2
  132. package/dist/registry/stores.d.ts.map +1 -1
  133. package/dist/registry/stores.js +110 -8
  134. package/dist/registry/stores.js.map +1 -1
  135. package/dist/reticle.d.ts +22 -3
  136. package/dist/reticle.d.ts.map +1 -1
  137. package/dist/reticle.js +81 -14
  138. package/dist/reticle.js.map +1 -1
  139. package/dist/review/annotator.js +1 -1
  140. package/dist/review/annotator.js.map +1 -1
  141. package/dist/review/mark-anchor.d.ts.map +1 -1
  142. package/dist/review/mark-anchor.js +1 -21
  143. package/dist/review/mark-anchor.js.map +1 -1
  144. package/dist/security/serialization.d.ts +29 -3
  145. package/dist/security/serialization.d.ts.map +1 -1
  146. package/dist/security/serialization.js +169 -28
  147. package/dist/security/serialization.js.map +1 -1
  148. package/dist/timers/clock.d.ts +13 -0
  149. package/dist/timers/clock.d.ts.map +1 -1
  150. package/dist/timers/clock.js +76 -6
  151. package/dist/timers/clock.js.map +1 -1
  152. package/dist/timers/native-console.d.ts +2 -0
  153. package/dist/timers/native-console.d.ts.map +1 -0
  154. package/dist/timers/native-console.js +10 -0
  155. package/dist/timers/native-console.js.map +1 -0
  156. package/dist/transport/transport.d.ts +1 -1
  157. package/dist/transport/transport.d.ts.map +1 -1
  158. package/dist/transport/transport.js +43 -4
  159. package/dist/transport/transport.js.map +1 -1
  160. package/package.json +7 -3
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Where an element is defined in the codebase.
3
+ *
4
+ * This is the single most valuable thing Reticle can hand an agent that has to fix what Reticle just
5
+ * found. Locating the right FILE is what turns a report into an edit; without it the agent pays for a
6
+ * search loop that the instrumentation already knows the answer to.
7
+ *
8
+ * Two lookups, because the callers have very different cost budgets:
9
+ *
10
+ * sourceFromDom — reads the babel-stamped `data-reticle-source` off the nearest ancestor. One
11
+ * native upward walk, bounded by tree depth. Safe to call per element on paths
12
+ * that describe many elements at once (query results, snapshots).
13
+ * sourceFor — prefers a framework adapter's answer (which knows the component that RENDERED
14
+ * the element, not just the nearest stamped host) and falls back to the DOM. The
15
+ * adapter path walks the fiber tree, so this belongs on single-element paths
16
+ * (inspect, act, review) and not in a loop.
17
+ *
18
+ * Both report source independently of how the element is ANCHORED. Anchor answers "how do I find this
19
+ * again", source answers "where is it written" — collapsing the two once meant that adding a
20
+ * data-testid, which Reticle's own docs recommend, silently removed the source pointer.
21
+ */
22
+ import { DATA_RETICLE_SOURCE_ATTR } from '@reticlehq/core';
23
+ /** Stamped by @reticlehq/babel-plugin / @reticlehq/vite-plugin in dev as `file:line:column`. */
24
+ const SOURCE_ATTR = DATA_RETICLE_SOURCE_ATTR;
25
+ /** Parse a `data-reticle-source="file:line:column"` value into `{ file, line }` (column dropped). */
26
+ export function parseSourceAttr(value) {
27
+ if (value === null)
28
+ return undefined;
29
+ const m = /^(.*):(\d+):(\d+)$/.exec(value);
30
+ if (m === null)
31
+ return undefined;
32
+ const file = m[1];
33
+ const line = Number(m[2]);
34
+ if (file === undefined || file.length === 0 || !Number.isFinite(line))
35
+ return undefined;
36
+ return { file, line };
37
+ }
38
+ /** The nearest babel-stamped source at or above this element. Cheap enough to call in bulk. */
39
+ export function sourceFromDom(el) {
40
+ const host = el.closest(`[${SOURCE_ATTR}]`);
41
+ return host !== null ? parseSourceAttr(host.getAttribute(SOURCE_ATTR)) : undefined;
42
+ }
43
+ /** Best source for the element: the framework adapter's, else the nearest babel-stamped attribute. */
44
+ export function sourceFor(el, adapterSource) {
45
+ if (adapterSource !== undefined)
46
+ return { file: adapterSource.file, line: adapterSource.line };
47
+ return sourceFromDom(el);
48
+ }
49
+ /**
50
+ * `file:line` — the form an agent can act on directly.
51
+ *
52
+ * Deliberately a single compact string rather than an object: it costs a couple of dozen bytes on a
53
+ * descriptor that may repeat hundreds of times in one response, and every consumer of it is either
54
+ * opening an editor or printing it.
55
+ */
56
+ export function formatSource(source) {
57
+ return source === undefined ? undefined : `${source.file}:${String(source.line)}`;
58
+ }
59
+ //# sourceMappingURL=source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.js","sourceRoot":"","sources":["../../src/dom/source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAE3D,gGAAgG;AAChG,MAAM,WAAW,GAAG,wBAAwB,CAAC;AAO7C,qGAAqG;AACrG,MAAM,UAAU,eAAe,CAAC,KAAoB;IAClD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACrC,MAAM,CAAC,GAAG,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3C,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACjC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAClB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxF,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACxB,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,aAAa,CAAC,EAAW;IACvC,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,WAAW,GAAG,CAAC,CAAC;IAC5C,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACrF,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,SAAS,CACvB,EAAW,EACX,aAAyC;IAEzC,IAAI,aAAa,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,EAAE,CAAC;IAC/F,OAAO,aAAa,CAAC,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,MAAkC;IAC7D,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;AACpF,CAAC"}
package/dist/dom/theme.js CHANGED
@@ -9,7 +9,7 @@
9
9
  * the matched token name is returned when there is one — so the agent can judge, not just trust a flag.
10
10
  */
11
11
  let cached = null;
12
- /** Resolve any CSS color string to canonical computed `rgb(...)`/`rgba(...)`, or null if not a color. */
12
+ /** Resolve any CSS color string to canonical computed `rgb...)`/`rgba...)`, or null if not a color. */
13
13
  function toRgb(value) {
14
14
  if (value.length === 0)
15
15
  return null;
@@ -25,7 +25,7 @@ function toRgb(value) {
25
25
  probe.remove();
26
26
  return rgb;
27
27
  }
28
- /** Collect `--token: value` declarations from every :root/html rule across the app's stylesheets. */
28
+ /** Collect `--token: value` declarations from every:root/html rule across the app's stylesheets. */
29
29
  function collectTokens() {
30
30
  const out = {};
31
31
  for (const sheet of Array.from(document.styleSheets)) {
@@ -1 +1 @@
1
- {"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/dom/theme.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/dom/theme.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -6,8 +6,10 @@ export { SESSION_AUTO } from '@reticlehq/core';
6
6
  export { setIgnoreSelectors } from './dom/dom-ignore.js';
7
7
  export { registerAdapter, identifyComponent, readComponentState, elementHasHoverHandlers, adapterNames, } from './registry/adapters.js';
8
8
  export type { ReticleAdapter, ComponentInfo, ComponentSource } from './registry/adapters.js';
9
- export { registerStore, unregisterStore, storeNames, readStores } from './registry/stores.js';
10
- export type { StoreGetter } from './registry/stores.js';
9
+ export { registerStore, unregisterStore, storeNames, readStores, readStoresWithTruncation, } from './registry/stores.js';
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';
11
13
  export { registerCapabilities, getCapabilities, hasCapabilities } from './registry/capabilities.js';
12
14
  export type { Capabilities, CapabilitiesInput, CapabilityFlow } from './registry/capabilities.js';
13
15
  export { createReticleEmitter } from './registry/emitter.js';
@@ -16,6 +18,8 @@ export { commitAndSignal } from './registry/commit-and-signal.js';
16
18
  export { registerReticleDomain } from './registry/domains.js';
17
19
  export type { ReticleDomain } from './registry/domains.js';
18
20
  export { buildSnapshot } from './dom/snapshot.js';
21
+ export { inspectChart, canvasChartData } from './dom/chart.js';
22
+ export type { ChartReport, ChartFinding, CanvasChartData } from './dom/chart.js';
19
23
  export { matchQuery, runQuery } from './dom/query.js';
20
24
  export { executeAction, executeSequence } from './actions/actions.js';
21
25
  export { describe, getRole, getAccessibleName, getStates, isVisible } from './dom/a11y.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAQvC,eAAO,MAAM,OAAO,EAAE,OAA2D,CAAC;AAElF,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGzD,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,YAAY,GACb,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAG7F,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC9F,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGxD,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACpG,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAGlG,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,YAAY,EACV,cAAc,EACd,aAAa,EACb,2BAA2B,GAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC3F,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAQvC,eAAO,MAAM,OAAO,EAAE,OAA2D,CAAC;AAElF,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGzD,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,YAAY,GACb,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAG7F,OAAO,EACL,aAAa,EACb,eAAe,EACf,UAAU,EACV,UAAU,EACV,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAKnF,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,WAAW,EACX,SAAS,EACT,SAAS,GACV,MAAM,8BAA8B,CAAC;AACtC,YAAY,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAGlE,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACpG,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAGlG,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,YAAY,EACV,cAAc,EACd,aAAa,EACb,2BAA2B,GAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAKlD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC/D,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC3F,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC"}
package/dist/index.js CHANGED
@@ -14,7 +14,11 @@ export { setIgnoreSelectors } from './dom/dom-ignore.js';
14
14
  // Adapter API (used by @reticlehq/react and other framework adapters).
15
15
  export { registerAdapter, identifyComponent, readComponentState, elementHasHoverHandlers, adapterNames, } from './registry/adapters.js';
16
16
  // Store registry: pull live framework/store state on demand.
17
- export { registerStore, unregisterStore, storeNames, readStores } from './registry/stores.js';
17
+ export { registerStore, unregisterStore, storeNames, readStores, readStoresWithTruncation, } from './registry/stores.js';
18
+ // Adapters for state libraries that do not natively expose `{getState, subscribe}`. zustand and Redux
19
+ // need none of these; TanStack Query is the one that matters most, because a stale-cache bug fires no
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';
18
22
  // Capability registry: the app self-describes its testable surface via reticle.describe.
19
23
  export { registerCapabilities, getCapabilities, hasCapabilities } from './registry/capabilities.js';
20
24
  // SDK helpers: adopt the recommended integration patterns without boilerplate.
@@ -23,6 +27,10 @@ export { commitAndSignal } from './registry/commit-and-signal.js';
23
27
  export { registerReticleDomain } from './registry/domains.js';
24
28
  // Lower-level building blocks (useful for tests and advanced embedding).
25
29
  export { buildSnapshot } from './dom/snapshot.js';
30
+ // Chart inspection. Surfaced automatically on any element descriptor that contains faulty plot
31
+ // geometry (see ElementDescriptor.chart), and exported for direct use — canvasChartData is the only
32
+ // route to a canvas chart's data, since its pixels are not DOM.
33
+ export { inspectChart, canvasChartData } from './dom/chart.js';
26
34
  export { matchQuery, runQuery } from './dom/query.js';
27
35
  export { executeAction, executeSequence } from './actions/actions.js';
28
36
  export { describe, getRole, getAccessibleName, getStates, isVisible } from './dom/a11y.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC;;;;GAIG;AACH,MAAM,WAAW,GAAG,UAAwD,CAAC;AAC7E,MAAM,CAAC,MAAM,OAAO,GAAY,CAAC,WAAW,CAAC,iBAAiB,KAAK,IAAI,OAAO,EAAE,CAAC,CAAC;AAElF,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,qGAAqG;AACrG,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,yDAAyD;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD,uEAAuE;AACvE,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,YAAY,GACb,MAAM,wBAAwB,CAAC;AAGhC,6DAA6D;AAC7D,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAG9F,yFAAyF;AACzF,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAGpG,+EAA+E;AAC/E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAM7D,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,yEAAyE;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC3F,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAsB,MAAM,uBAAuB,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAmB,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC;;;;GAIG;AACH,MAAM,WAAW,GAAG,UAAwD,CAAC;AAC7E,MAAM,CAAC,MAAM,OAAO,GAAY,CAAC,WAAW,CAAC,iBAAiB,KAAK,IAAI,OAAO,EAAE,CAAC,CAAC;AAElF,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,qGAAqG;AACrG,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,yDAAyD;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD,uEAAuE;AACvE,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,YAAY,GACb,MAAM,wBAAwB,CAAC;AAGhC,6DAA6D;AAC7D,OAAO,EACL,aAAa,EACb,eAAe,EACf,UAAU,EACV,UAAU,EACV,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAG9B,sGAAsG;AACtG,sGAAsG;AACtG,2EAA2E;AAC3E,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,WAAW,EACX,SAAS,EACT,SAAS,GACV,MAAM,8BAA8B,CAAC;AAGtC,yFAAyF;AACzF,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAGpG,+EAA+E;AAC/E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAM7D,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,yEAAyE;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,+FAA+F;AAC/F,oGAAoG;AACpG,gEAAgE;AAChE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAE/D,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC3F,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAsB,MAAM,uBAAuB,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAmB,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { Emit, Teardown } from './types.js';
2
+ /**
3
+ * Blind-spot sensor. The SDK instruments the DOM, but a cross-origin iframe is a wall it cannot
4
+ * see through — its contents, network, and console are invisible. Left unstated, a green verdict would
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.
9
+ */
10
+ /**
11
+ * Whether a frame is cross-origin (unobservable). A same-origin frame exposes its `contentDocument`; a
12
+ * cross-origin one returns null (or THROWS a SecurityError on access). A src-less / about:blank frame is
13
+ * same-origin and simply not navigated — not a blind spot.
14
+ */
15
+ export declare function isCrossOriginFrame(frame: HTMLIFrameElement): boolean;
16
+ /** How many of the given frames are cross-origin (unobservable). */
17
+ export declare function countCrossOriginFrames(frames: readonly HTMLIFrameElement[]): number;
18
+ export declare function installBlindSpots(emit: Emit): Teardown;
19
+ //# sourceMappingURL=blind-spots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blind-spots.d.ts","sourceRoot":"","sources":["../../src/observers/blind-spots.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGjD;;;;;;;GAOG;AAEH;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAQpE;AAED,oEAAoE;AACpE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,iBAAiB,EAAE,GAAG,MAAM,CAInF;AAmBD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CAoCtD"}
@@ -0,0 +1,89 @@
1
+ import { EventType, BlindSpotKind } from '@reticlehq/core';
2
+ import { nativeClearTimeout, nativeSetTimeout } from '../timers/native-timers.js';
3
+ /**
4
+ * Blind-spot sensor. The SDK instruments the DOM, but a cross-origin iframe is a wall it cannot
5
+ * see through — its contents, network, and console are invisible. Left unstated, a green verdict would
6
+ * 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
+ */
11
+ /**
12
+ * Whether a frame is cross-origin (unobservable). A same-origin frame exposes its `contentDocument`; a
13
+ * cross-origin one returns null (or THROWS a SecurityError on access). A src-less / about:blank frame is
14
+ * same-origin and simply not navigated — not a blind spot.
15
+ */
16
+ export function isCrossOriginFrame(frame) {
17
+ const src = frame.getAttribute('src');
18
+ if (src === null || src.length === 0)
19
+ return false;
20
+ try {
21
+ return frame.contentDocument === null;
22
+ }
23
+ catch {
24
+ return true; // SecurityError on access is itself proof of cross-origin
25
+ }
26
+ }
27
+ /** How many of the given frames are cross-origin (unobservable). */
28
+ export function countCrossOriginFrames(frames) {
29
+ let count = 0;
30
+ for (const frame of frames)
31
+ if (isCrossOriginFrame(frame))
32
+ count += 1;
33
+ return count;
34
+ }
35
+ function currentCount() {
36
+ return countCrossOriginFrames(Array.from(document.querySelectorAll('iframe')));
37
+ }
38
+ /**
39
+ * Watch the page for cross-origin iframes and emit BLIND_SPOT whenever the count CHANGES (install +
40
+ * on any added/removed frame). Only the delta is emitted — never a per-mutation flood — so a static
41
+ * embed reports once. Reversible: disconnects the observer on teardown.
42
+ */
43
+ /**
44
+ * How long added/removed nodes are allowed to pile up before the frame count is re-checked.
45
+ *
46
+ * A blind spot is a coverage caveat on a verdict, not a live signal — noticing an embed a fraction of
47
+ * a second later costs nothing, while checking on every mutation costs a DOM scan per render.
48
+ */
49
+ const RECHECK_DEBOUNCE_MS = 250;
50
+ export function installBlindSpots(emit) {
51
+ let last = -1;
52
+ 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 });
59
+ }
60
+ };
61
+ report();
62
+ // Coalesce rather than gate.
63
+ //
64
+ // This used to try to skip unrelated churn by testing each added/removed node with
65
+ // `n.querySelector('iframe')` — but that is a full subtree scan per mutated node, so a React commit
66
+ // mounting a 500-node panel paid a 500-node scan to decide whether to do a document scan. The gate
67
+ // cost more than the work, and it scaled with exactly the thing a large app does most.
68
+ //
69
+ // Since report() emits only when the count CHANGES, running it late and rarely is free. One
70
+ // debounced document scan per quarter-second replaces per-node scanning, and it is also more
71
+ // correct: the old gate's `querySelector` missed an iframe added inside a subtree whose own root
72
+ // was a text or comment node.
73
+ let pending;
74
+ const observer = new MutationObserver(() => {
75
+ if (pending !== undefined)
76
+ return;
77
+ pending = nativeSetTimeout(() => {
78
+ pending = undefined;
79
+ report();
80
+ }, RECHECK_DEBOUNCE_MS);
81
+ });
82
+ observer.observe(document.documentElement, { childList: true, subtree: true });
83
+ return () => {
84
+ if (pending !== undefined)
85
+ nativeClearTimeout(pending);
86
+ observer.disconnect();
87
+ };
88
+ }
89
+ //# sourceMappingURL=blind-spots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blind-spots.js","sourceRoot":"","sources":["../../src/observers/blind-spots.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE3D,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAElF;;;;;;;GAOG;AAEH;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAwB;IACzD,MAAM,GAAG,GAAG,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACnD,IAAI,CAAC;QACH,OAAO,KAAK,CAAC,eAAe,KAAK,IAAI,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,CAAC,0DAA0D;IACzE,CAAC;AACH,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,sBAAsB,CAAC,MAAoC;IACzE,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,KAAK,IAAI,MAAM;QAAE,IAAI,kBAAkB,CAAC,KAAK,CAAC;YAAE,KAAK,IAAI,CAAC,CAAC;IACtE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY;IACnB,OAAO,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACjF,CAAC;AAED;;;;GAIG;AACH;;;;;GAKG;AACH,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC,MAAM,UAAU,iBAAiB,CAAC,IAAU;IAC1C,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;IACd,MAAM,MAAM,GAAG,GAAS,EAAE;QACxB,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;QAC7B,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO;QAC3B,IAAI,GAAG,KAAK,CAAC;QACb,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACd,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC,mBAAmB,EAAE,KAAK,EAAE,CAAC,CAAC;QACjF,CAAC;IACH,CAAC,CAAC;IACF,MAAM,EAAE,CAAC;IAET,6BAA6B;IAC7B,EAAE;IACF,mFAAmF;IACnF,oGAAoG;IACpG,mGAAmG;IACnG,uFAAuF;IACvF,EAAE;IACF,4FAA4F;IAC5F,6FAA6F;IAC7F,iGAAiG;IACjG,8BAA8B;IAC9B,IAAI,OAAwD,CAAC;IAC7D,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC,GAAG,EAAE;QACzC,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO;QAClC,OAAO,GAAG,gBAAgB,CAAC,GAAG,EAAE;YAC9B,OAAO,GAAG,SAAS,CAAC;YACpB,MAAM,EAAE,CAAC;QACX,CAAC,EAAE,mBAAmB,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IACH,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/E,OAAO,GAAG,EAAE;QACV,IAAI,OAAO,KAAK,SAAS;YAAE,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACvD,QAAQ,CAAC,UAAU,EAAE,CAAC;IACxB,CAAC,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/observers/console.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAqBjD,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CAuCnD"}
1
+ {"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/observers/console.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAyCjD,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CAqDnD"}
@@ -1,10 +1,13 @@
1
- /* eslint-disable no-console -- this module's whole purpose is to wrap console.{log,warn,error} */
2
- import { EventType } from '@reticlehq/core';
1
+ import { EventType, TRANSPORT_LIMITS } from '@reticlehq/core';
3
2
  import { safeStringify } from '../security/serialization.js';
4
3
  const METHOD_EVENT = {
5
4
  log: EventType.CONSOLE_LOG,
6
5
  warn: EventType.CONSOLE_WARN,
7
6
  error: EventType.CONSOLE_ERROR,
7
+ // info/debug are captured for the raw console channel but excluded from summaries/deviation reports
8
+ // (low signal — most apps chatter here). Lean: no stack, like log/warn.
9
+ info: EventType.CONSOLE_INFO,
10
+ debug: EventType.CONSOLE_DEBUG,
8
11
  };
9
12
  function stringifyArgs(args) {
10
13
  return args
@@ -17,39 +20,69 @@ function stringifyArgs(args) {
17
20
  })
18
21
  .join(' ');
19
22
  }
23
+ /** Stacks can be long; cap so a deep async trace never blows the event budget. */
24
+ const MAX_STACK_LEN = TRANSPORT_LIMITS.MAX_STACK_LENGTH;
25
+ function capStack(stack) {
26
+ if (stack === undefined || stack.length === 0)
27
+ return undefined;
28
+ return stack.length > MAX_STACK_LEN ? stack.slice(0, MAX_STACK_LEN) : stack;
29
+ }
30
+ /** The stack of the first Error argument, if any — the single biggest diagnosis upgrade, near-zero cost. */
31
+ function firstErrorStack(args) {
32
+ for (const arg of args) {
33
+ if (arg instanceof Error)
34
+ return capStack(arg.stack);
35
+ }
36
+ return undefined;
37
+ }
20
38
  /** Patch console.{log,warn,error} and window error events. Reversible. */
21
39
  export function installConsole(emit) {
22
- const methods = ['log', 'warn', 'error'];
40
+ const methods = ['log', 'warn', 'error', 'info', 'debug'];
23
41
  const originals = new Map();
42
+ const patched = new Map();
24
43
  for (const method of methods) {
25
44
  // Store the true original for teardown identity; call through a bound copy.
26
45
  const original = console[method];
27
46
  originals.set(method, original);
28
47
  const callOriginal = original.bind(console);
29
- console[method] = (...args) => {
30
- emit(METHOD_EVENT[method], { message: stringifyArgs(args) });
48
+ const wrapper = (...args) => {
49
+ // Only console.error carries a stack — the diagnosis case; log/warn stay lean.
50
+ const stack = method === 'error' ? firstErrorStack(args) : undefined;
51
+ emit(METHOD_EVENT[method], {
52
+ message: stringifyArgs(args),
53
+ ...(stack === undefined ? {} : { stack }),
54
+ });
31
55
  callOriginal(...args);
32
56
  };
57
+ patched.set(method, wrapper);
58
+ console[method] = wrapper;
33
59
  }
34
60
  const onError = (event) => {
61
+ const stack = capStack(event.error instanceof Error ? event.error.stack : undefined);
35
62
  emit(EventType.ERROR_UNCAUGHT, {
36
63
  message: event.message,
37
64
  source: event.filename,
38
65
  line: event.lineno,
66
+ ...(stack === undefined ? {} : { stack }),
39
67
  });
40
68
  };
41
69
  const onRejection = (event) => {
42
70
  const reason = event.reason;
71
+ const stack = capStack(reason instanceof Error ? reason.stack : undefined);
43
72
  emit(EventType.ERROR_UNCAUGHT, {
44
73
  message: reason instanceof Error ? reason.message : String(reason),
45
74
  kind: 'unhandledrejection',
75
+ ...(stack === undefined ? {} : { stack }),
46
76
  });
47
77
  };
48
78
  window.addEventListener('error', onError);
49
79
  window.addEventListener('unhandledrejection', onRejection);
50
80
  return () => {
51
81
  for (const [method, original] of originals) {
52
- console[method] = original;
82
+ // Restore only if console[method] still holds our wrapper — a logging SDK (Sentry, LogRocket)
83
+ // that wrapped console AFTER connect() must keep its instrumentation on teardown.
84
+ if (console[method] === patched.get(method))
85
+ console[method] = original;
53
86
  }
54
87
  window.removeEventListener('error', onError);
55
88
  window.removeEventListener('unhandledrejection', onRejection);
@@ -1 +1 @@
1
- {"version":3,"file":"console.js","sourceRoot":"","sources":["../../src/observers/console.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAI7D,MAAM,YAAY,GAAqC;IACrD,GAAG,EAAE,SAAS,CAAC,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAC,YAAY;IAC5B,KAAK,EAAE,SAAS,CAAC,aAAa;CAC/B,CAAC;AAEF,SAAS,aAAa,CAAC,IAAe;IACpC,OAAO,IAAI;SACR,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,YAAY,KAAK;YAAE,OAAO,CAAC,CAAC,OAAO,CAAC;QACzC,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC,CAAC;SACD,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAAC,IAAU;IACvC,MAAM,OAAO,GAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAG,IAAI,GAAG,EAA+C,CAAC;IAEzE,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,4EAA4E;QAC5E,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAiC,CAAC;QACjE,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAChC,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5C,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,IAAe,EAAQ,EAAE;YAC7C,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC7D,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC;QACxB,CAAC,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,KAAiB,EAAQ,EAAE;QAC1C,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE;YAC7B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,MAAM,EAAE,KAAK,CAAC,QAAQ;YACtB,IAAI,EAAE,KAAK,CAAC,MAAM;SACnB,CAAC,CAAC;IACL,CAAC,CAAC;IACF,MAAM,WAAW,GAAG,CAAC,KAA4B,EAAQ,EAAE;QACzD,MAAM,MAAM,GAAY,KAAK,CAAC,MAAM,CAAC;QACrC,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE;YAC7B,OAAO,EAAE,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;YAClE,IAAI,EAAE,oBAAoB;SAC3B,CAAC,CAAC;IACL,CAAC,CAAC;IACF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,CAAC,gBAAgB,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;IAE3D,OAAO,GAAG,EAAE;QACV,KAAK,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,SAAS,EAAE,CAAC;YAC3C,OAAO,CAAC,MAAM,CAAC,GAAG,QAA8B,CAAC;QACnD,CAAC;QACD,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC7C,MAAM,CAAC,mBAAmB,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;IAChE,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"console.js","sourceRoot":"","sources":["../../src/observers/console.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/observers/dom.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAwBjD,gEAAgE;AAChE,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CA0E/C"}
1
+ {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/observers/dom.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAqCjD,gEAAgE;AAChE,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CA+G/C"}
@@ -1,6 +1,19 @@
1
- import { EventType } from '@reticlehq/core';
1
+ import { EventType, TruncationChannel } from '@reticlehq/core';
2
2
  import { getAccessibleName, getRole, isVisible } from '../dom/a11y.js';
3
3
  import { refs } from '../dom/refs.js';
4
+ /**
5
+ * A STABLE identity for the region a mutation happened in. Ambient learning cannot key on the element
6
+ * ref for a churning list: every appended row is a NEW element (fresh ref) and a removed one has no ref
7
+ * at all, so per-ref counts never accumulate and the region is never recognized as ambient. The
8
+ * container persists across ticks, so its testid (or ref) is the identity that does accumulate.
9
+ */
10
+ function regionKeyOf(target) {
11
+ const el = target instanceof Element ? target : null;
12
+ if (el === null)
13
+ return undefined;
14
+ const labelled = el.closest('[data-testid]');
15
+ return labelled?.getAttribute('data-testid') ?? refs.refFor(el);
16
+ }
4
17
  import { isReticleOverlay } from '../dom/dom-ignore.js';
5
18
  const WATCHED_ATTRS = [
6
19
  'class',
@@ -12,7 +25,19 @@ const WATCHED_ATTRS = [
12
25
  'aria-selected',
13
26
  'aria-checked',
14
27
  'data-state',
28
+ // Widened: visual + resource + form-value attributes. Values are capped (they can be long).
29
+ 'style',
30
+ 'src',
31
+ 'href',
32
+ 'value',
15
33
  ];
34
+ /** Attribute/text values are capped per event — style/src can be huge and would bloat the ledger. */
35
+ const MAX_ATTR_VALUE_LEN = 120;
36
+ function capValue(value) {
37
+ if (value === null)
38
+ return undefined;
39
+ return value.length > MAX_ATTR_VALUE_LEN ? `${value.slice(0, MAX_ATTR_VALUE_LEN)}…` : value;
40
+ }
16
41
  const DIALOG_ROLES = new Set(['dialog', 'alertdialog']);
17
42
  const LIVE_ROLES = new Set(['alert', 'status']);
18
43
  /** Max meaningful added/removed nodes reported per mutation batch (backpressure). */
@@ -26,15 +51,29 @@ export function installDom(emit) {
26
51
  let added = 0;
27
52
  let removed = 0;
28
53
  let changed = 0;
54
+ // Count element nodes dropped purely because a per-batch cap was already reached. The cap is on
55
+ // MEANINGFUL events, so it is only hit after a real flood — the count is a raw over-estimate
56
+ // (it can include not-yet-inspected noise) but `dropped > 0` honestly means "this batch was capped".
57
+ let dropped = 0;
29
58
  for (const record of records) {
30
59
  if (record.type === 'attributes') {
31
60
  const target = record.target;
32
61
  if (target instanceof Element &&
33
62
  record.attributeName !== null &&
34
- changed < MAX_PER_BATCH &&
35
63
  !isReticleOverlay(target)) {
64
+ if (changed >= MAX_PER_BATCH) {
65
+ dropped += 1;
66
+ continue;
67
+ }
36
68
  changed += 1;
37
- emit(EventType.DOM_ATTR, { attr: record.attributeName, value: target.getAttribute(record.attributeName) }, refs.refFor(target));
69
+ // Old value (attributeOldValue) + capped new value — a diff, not just a reading.
70
+ const value = capValue(target.getAttribute(record.attributeName));
71
+ const old = capValue(record.oldValue);
72
+ emit(EventType.DOM_ATTR, {
73
+ attr: record.attributeName,
74
+ ...(value === undefined ? {} : { value }),
75
+ ...(old === undefined ? {} : { old }),
76
+ }, refs.refFor(target));
38
77
  }
39
78
  continue;
40
79
  }
@@ -42,16 +81,25 @@ export function installDom(emit) {
42
81
  // In-place text change inside an existing subtree (wizard steps, inline edits) —
43
82
  // childList-only would miss this.
44
83
  const parent = record.target.parentElement;
45
- if (parent !== null && changed < MAX_PER_BATCH && !isReticleOverlay(parent)) {
84
+ if (parent !== null && !isReticleOverlay(parent)) {
85
+ if (changed >= MAX_PER_BATCH) {
86
+ dropped += 1;
87
+ continue;
88
+ }
46
89
  changed += 1;
47
90
  const text = (record.target.textContent ?? '').trim().slice(0, 80);
48
- emit(EventType.DOM_TEXT, { text }, refs.refFor(parent));
91
+ const old = capValue(record.oldValue?.trim() ?? null);
92
+ emit(EventType.DOM_TEXT, { text, ...(old === undefined ? {} : { old }) }, refs.refFor(parent));
49
93
  }
50
94
  continue;
51
95
  }
52
96
  for (const node of record.addedNodes) {
53
- if (!(node instanceof Element) || added >= MAX_PER_BATCH)
97
+ if (!(node instanceof Element))
98
+ continue;
99
+ if (added >= MAX_PER_BATCH) {
100
+ dropped += 1;
54
101
  continue;
102
+ }
55
103
  if (isReticleOverlay(node))
56
104
  continue;
57
105
  const role = getRole(node);
@@ -60,7 +108,7 @@ export function installDom(emit) {
60
108
  continue;
61
109
  added += 1;
62
110
  const ref = refs.refFor(node);
63
- emit(EventType.DOM_ADDED, { role, name }, ref);
111
+ emit(EventType.DOM_ADDED, { role, name, region: regionKeyOf(record.target) }, ref);
64
112
  if (DIALOG_ROLES.has(role) ||
65
113
  LIVE_ROLES.has(role) ||
66
114
  node.getAttribute('aria-modal') === 'true') {
@@ -69,8 +117,12 @@ export function installDom(emit) {
69
117
  }
70
118
  }
71
119
  for (const node of record.removedNodes) {
72
- if (!(node instanceof Element) || removed >= MAX_PER_BATCH)
120
+ if (!(node instanceof Element))
121
+ continue;
122
+ if (removed >= MAX_PER_BATCH) {
123
+ dropped += 1;
73
124
  continue;
125
+ }
74
126
  if (isReticleOverlay(node))
75
127
  continue;
76
128
  const role = getRole(node);
@@ -78,16 +130,23 @@ export function installDom(emit) {
78
130
  if (!isMeaningful(role, name))
79
131
  continue;
80
132
  removed += 1;
81
- emit(EventType.DOM_REMOVED, { role, name });
133
+ // A removed node has no ref (it is gone), so the CONTAINER is the only stable identity — and it
134
+ // is what ambient learning needs to recognize a churning region.
135
+ emit(EventType.DOM_REMOVED, { role, name, region: regionKeyOf(record.target) });
82
136
  }
83
137
  }
138
+ // Never silent: a capped batch tells the ledger its DOM counts understate reality.
139
+ if (dropped > 0)
140
+ emit(EventType.TRUNCATED, { channel: TruncationChannel.DOM, dropped });
84
141
  });
85
142
  observer.observe(document.documentElement, {
86
143
  subtree: true,
87
144
  childList: true,
88
145
  attributes: true,
89
146
  attributeFilter: WATCHED_ATTRS,
147
+ attributeOldValue: true,
90
148
  characterData: true,
149
+ characterDataOldValue: true,
91
150
  });
92
151
  return () => {
93
152
  observer.disconnect();
@@ -1 +1 @@
1
- {"version":3,"file":"dom.js","sourceRoot":"","sources":["../../src/observers/dom.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dom.js","sourceRoot":"","sources":["../../src/observers/dom.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { Emit, Teardown } from './types.js';
2
+ /** A human-legible label for a focused element, or undefined for body/none. Pure; exported for testing. */
3
+ export declare function focusLabel(el: EventTarget | null): string | undefined;
4
+ /**
5
+ * Track element focus movement. Focus dropping to <body> after an act — a modal that closed and stranded
6
+ * focus, a button that vanished — is a real accessibility/UX regression no screenshot names. Emits
7
+ * FOCUS_CHANGE {to, from, toBody}. Reversible.
8
+ */
9
+ export declare function installFocus(emit: Emit): Teardown;
10
+ //# sourceMappingURL=focus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"focus.d.ts","sourceRoot":"","sources":["../../src/observers/focus.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEjD,2GAA2G;AAC3G,wBAAgB,UAAU,CAAC,EAAE,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAKrE;AAMD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CA+BjD"}