agent-web-interface 4.2.0 → 4.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 (265) hide show
  1. package/dist/src/browser/connection-utils.d.ts +48 -0
  2. package/dist/src/browser/connection-utils.d.ts.map +1 -0
  3. package/dist/src/browser/connection-utils.js +129 -0
  4. package/dist/src/browser/connection-utils.js.map +1 -0
  5. package/dist/src/browser/index.d.ts +3 -1
  6. package/dist/src/browser/index.d.ts.map +1 -1
  7. package/dist/src/browser/index.js +2 -1
  8. package/dist/src/browser/index.js.map +1 -1
  9. package/dist/src/browser/session-manager.d.ts +1 -89
  10. package/dist/src/browser/session-manager.d.ts.map +1 -1
  11. package/dist/src/browser/session-manager.js +1 -116
  12. package/dist/src/browser/session-manager.js.map +1 -1
  13. package/dist/src/browser/session-manager.types.d.ts +90 -0
  14. package/dist/src/browser/session-manager.types.d.ts.map +1 -0
  15. package/dist/src/browser/session-manager.types.js +7 -0
  16. package/dist/src/browser/session-manager.types.js.map +1 -0
  17. package/dist/src/form/constraint-extraction.d.ts +31 -0
  18. package/dist/src/form/constraint-extraction.d.ts.map +1 -0
  19. package/dist/src/form/constraint-extraction.js +110 -0
  20. package/dist/src/form/constraint-extraction.js.map +1 -0
  21. package/dist/src/form/field-extractor.d.ts.map +1 -1
  22. package/dist/src/form/field-extractor.js +3 -444
  23. package/dist/src/form/field-extractor.js.map +1 -1
  24. package/dist/src/form/field-state-extractor.d.ts +22 -0
  25. package/dist/src/form/field-state-extractor.d.ts.map +1 -0
  26. package/dist/src/form/field-state-extractor.js +55 -0
  27. package/dist/src/form/field-state-extractor.js.map +1 -0
  28. package/dist/src/form/form-actions.d.ts +45 -0
  29. package/dist/src/form/form-actions.d.ts.map +1 -0
  30. package/dist/src/form/form-actions.js +108 -0
  31. package/dist/src/form/form-actions.js.map +1 -0
  32. package/dist/src/form/form-detector.d.ts +0 -36
  33. package/dist/src/form/form-detector.d.ts.map +1 -1
  34. package/dist/src/form/form-detector.js +11 -376
  35. package/dist/src/form/form-detector.js.map +1 -1
  36. package/dist/src/form/input-clustering.d.ts +15 -0
  37. package/dist/src/form/input-clustering.d.ts.map +1 -0
  38. package/dist/src/form/input-clustering.js +61 -0
  39. package/dist/src/form/input-clustering.js.map +1 -0
  40. package/dist/src/form/intent-inference.d.ts +28 -0
  41. package/dist/src/form/intent-inference.d.ts.map +1 -0
  42. package/dist/src/form/intent-inference.js +137 -0
  43. package/dist/src/form/intent-inference.js.map +1 -0
  44. package/dist/src/form/purpose-inference.d.ts +50 -0
  45. package/dist/src/form/purpose-inference.d.ts.map +1 -0
  46. package/dist/src/form/purpose-inference.js +313 -0
  47. package/dist/src/form/purpose-inference.js.map +1 -0
  48. package/dist/src/form/submit-detection.d.ts +36 -0
  49. package/dist/src/form/submit-detection.d.ts.map +1 -0
  50. package/dist/src/form/submit-detection.js +101 -0
  51. package/dist/src/form/submit-detection.js.map +1 -0
  52. package/dist/src/form/types.d.ts +2 -2
  53. package/dist/src/index.js +65 -48
  54. package/dist/src/index.js.map +1 -1
  55. package/dist/src/observation/observation-accumulator.d.ts +1 -1
  56. package/dist/src/observation/observation-accumulator.js +1 -1
  57. package/dist/src/observation/observer-script.d.ts +1 -1
  58. package/dist/src/observation/observer-script.d.ts.map +1 -1
  59. package/dist/src/observation/observer-script.js +129 -7
  60. package/dist/src/observation/observer-script.js.map +1 -1
  61. package/dist/src/query/disambiguation.d.ts +18 -0
  62. package/dist/src/query/disambiguation.d.ts.map +1 -0
  63. package/dist/src/query/disambiguation.js +123 -0
  64. package/dist/src/query/disambiguation.js.map +1 -0
  65. package/dist/src/query/fuzzy-match.d.ts +17 -0
  66. package/dist/src/query/fuzzy-match.d.ts.map +1 -0
  67. package/dist/src/query/fuzzy-match.js +34 -0
  68. package/dist/src/query/fuzzy-match.js.map +1 -0
  69. package/dist/src/query/index.d.ts +3 -0
  70. package/dist/src/query/index.d.ts.map +1 -1
  71. package/dist/src/query/index.js +6 -0
  72. package/dist/src/query/index.js.map +1 -1
  73. package/dist/src/query/query-engine.d.ts +0 -35
  74. package/dist/src/query/query-engine.d.ts.map +1 -1
  75. package/dist/src/query/query-engine.js +9 -309
  76. package/dist/src/query/query-engine.js.map +1 -1
  77. package/dist/src/query/scoring.d.ts +52 -0
  78. package/dist/src/query/scoring.d.ts.map +1 -0
  79. package/dist/src/query/scoring.js +162 -0
  80. package/dist/src/query/scoring.js.map +1 -0
  81. package/dist/src/server/mcp-server.d.ts.map +1 -1
  82. package/dist/src/server/mcp-server.js +29 -1
  83. package/dist/src/server/mcp-server.js.map +1 -1
  84. package/dist/src/snapshot/element-resolver.d.ts +50 -18
  85. package/dist/src/snapshot/element-resolver.d.ts.map +1 -1
  86. package/dist/src/snapshot/element-resolver.js +180 -101
  87. package/dist/src/snapshot/element-resolver.js.map +1 -1
  88. package/dist/src/snapshot/extractors/ax-extractor.d.ts +1 -1
  89. package/dist/src/snapshot/extractors/ax-extractor.d.ts.map +1 -1
  90. package/dist/src/snapshot/extractors/ax-extractor.js +4 -1
  91. package/dist/src/snapshot/extractors/ax-extractor.js.map +1 -1
  92. package/dist/src/snapshot/extractors/index.d.ts +1 -1
  93. package/dist/src/snapshot/extractors/index.d.ts.map +1 -1
  94. package/dist/src/snapshot/extractors/index.js +1 -1
  95. package/dist/src/snapshot/extractors/index.js.map +1 -1
  96. package/dist/src/snapshot/extractors/region-resolver.d.ts.map +1 -1
  97. package/dist/src/snapshot/extractors/region-resolver.js +8 -0
  98. package/dist/src/snapshot/extractors/region-resolver.js.map +1 -1
  99. package/dist/src/snapshot/extractors/types.d.ts +8 -0
  100. package/dist/src/snapshot/extractors/types.d.ts.map +1 -1
  101. package/dist/src/snapshot/extractors/types.js +16 -0
  102. package/dist/src/snapshot/extractors/types.js.map +1 -1
  103. package/dist/src/snapshot/frame-context.d.ts +68 -0
  104. package/dist/src/snapshot/frame-context.d.ts.map +1 -0
  105. package/dist/src/snapshot/frame-context.js +131 -0
  106. package/dist/src/snapshot/frame-context.js.map +1 -0
  107. package/dist/src/snapshot/heading-index.d.ts +28 -0
  108. package/dist/src/snapshot/heading-index.d.ts.map +1 -0
  109. package/dist/src/snapshot/heading-index.js +108 -0
  110. package/dist/src/snapshot/heading-index.js.map +1 -0
  111. package/dist/src/snapshot/index.d.ts +5 -3
  112. package/dist/src/snapshot/index.d.ts.map +1 -1
  113. package/dist/src/snapshot/index.js +3 -2
  114. package/dist/src/snapshot/index.js.map +1 -1
  115. package/dist/src/snapshot/kind-mapping.d.ts +30 -0
  116. package/dist/src/snapshot/kind-mapping.d.ts.map +1 -0
  117. package/dist/src/snapshot/kind-mapping.js +114 -0
  118. package/dist/src/snapshot/kind-mapping.js.map +1 -0
  119. package/dist/src/snapshot/node-filter.d.ts +31 -0
  120. package/dist/src/snapshot/node-filter.d.ts.map +1 -0
  121. package/dist/src/snapshot/node-filter.js +137 -0
  122. package/dist/src/snapshot/node-filter.js.map +1 -0
  123. package/dist/src/snapshot/node-synthesizer.d.ts +62 -0
  124. package/dist/src/snapshot/node-synthesizer.d.ts.map +1 -0
  125. package/dist/src/snapshot/node-synthesizer.js +185 -0
  126. package/dist/src/snapshot/node-synthesizer.js.map +1 -0
  127. package/dist/src/snapshot/snapshot-compiler.d.ts +2 -36
  128. package/dist/src/snapshot/snapshot-compiler.d.ts.map +1 -1
  129. package/dist/src/snapshot/snapshot-compiler.js +28 -520
  130. package/dist/src/snapshot/snapshot-compiler.js.map +1 -1
  131. package/dist/src/snapshot/snapshot.types.d.ts +7 -2
  132. package/dist/src/snapshot/snapshot.types.d.ts.map +1 -1
  133. package/dist/src/snapshot/snapshot.types.js +9 -0
  134. package/dist/src/snapshot/snapshot.types.js.map +1 -1
  135. package/dist/src/state/actionables-filter.d.ts +5 -0
  136. package/dist/src/state/actionables-filter.d.ts.map +1 -1
  137. package/dist/src/state/actionables-filter.js +22 -3
  138. package/dist/src/state/actionables-filter.js.map +1 -1
  139. package/dist/src/state/diff-engine.js +3 -3
  140. package/dist/src/state/diff-engine.js.map +1 -1
  141. package/dist/src/state/element-registry.d.ts.map +1 -1
  142. package/dist/src/state/element-registry.js +6 -4
  143. package/dist/src/state/element-registry.js.map +1 -1
  144. package/dist/src/state/hash-utils.d.ts +24 -0
  145. package/dist/src/state/hash-utils.d.ts.map +1 -0
  146. package/dist/src/state/hash-utils.js +41 -0
  147. package/dist/src/state/hash-utils.js.map +1 -0
  148. package/dist/src/state/layer-detector.d.ts.map +1 -1
  149. package/dist/src/state/layer-detector.js +15 -286
  150. package/dist/src/state/layer-detector.js.map +1 -1
  151. package/dist/src/state/layer-detectors/drawer-detector.d.ts +32 -0
  152. package/dist/src/state/layer-detectors/drawer-detector.d.ts.map +1 -0
  153. package/dist/src/state/layer-detectors/drawer-detector.js +96 -0
  154. package/dist/src/state/layer-detectors/drawer-detector.js.map +1 -0
  155. package/dist/src/state/layer-detectors/index.d.ts +10 -0
  156. package/dist/src/state/layer-detectors/index.d.ts.map +1 -0
  157. package/dist/src/state/layer-detectors/index.js +10 -0
  158. package/dist/src/state/layer-detectors/index.js.map +1 -0
  159. package/dist/src/state/layer-detectors/modal-detector.d.ts +30 -0
  160. package/dist/src/state/layer-detectors/modal-detector.d.ts.map +1 -0
  161. package/dist/src/state/layer-detectors/modal-detector.js +127 -0
  162. package/dist/src/state/layer-detectors/modal-detector.js.map +1 -0
  163. package/dist/src/state/layer-detectors/popover-detector.d.ts +20 -0
  164. package/dist/src/state/layer-detectors/popover-detector.d.ts.map +1 -0
  165. package/dist/src/state/layer-detectors/popover-detector.js +76 -0
  166. package/dist/src/state/layer-detectors/popover-detector.js.map +1 -0
  167. package/dist/src/state/layer-detectors/toast-detector.d.ts +24 -0
  168. package/dist/src/state/layer-detectors/toast-detector.d.ts.map +1 -0
  169. package/dist/src/state/layer-detectors/toast-detector.js +48 -0
  170. package/dist/src/state/layer-detectors/toast-detector.js.map +1 -0
  171. package/dist/src/state/region-mapping.d.ts +13 -0
  172. package/dist/src/state/region-mapping.d.ts.map +1 -0
  173. package/dist/src/state/region-mapping.js +25 -0
  174. package/dist/src/state/region-mapping.js.map +1 -0
  175. package/dist/src/state/state-manager.d.ts.map +1 -1
  176. package/dist/src/state/state-manager.js +8 -192
  177. package/dist/src/state/state-manager.js.map +1 -1
  178. package/dist/src/state/state-renderer.d.ts.map +1 -1
  179. package/dist/src/state/state-renderer.js +16 -2
  180. package/dist/src/state/state-renderer.js.map +1 -1
  181. package/dist/src/state/types.d.ts +8 -4
  182. package/dist/src/state/types.d.ts.map +1 -1
  183. package/dist/src/state/url-sanitization.d.ts +22 -0
  184. package/dist/src/state/url-sanitization.d.ts.map +1 -0
  185. package/dist/src/state/url-sanitization.js +60 -0
  186. package/dist/src/state/url-sanitization.js.map +1 -0
  187. package/dist/src/state/value-masking.d.ts +36 -0
  188. package/dist/src/state/value-masking.d.ts.map +1 -0
  189. package/dist/src/state/value-masking.js +86 -0
  190. package/dist/src/state/value-masking.js.map +1 -0
  191. package/dist/src/tools/action-context.d.ts +60 -0
  192. package/dist/src/tools/action-context.d.ts.map +1 -0
  193. package/dist/src/tools/action-context.js +78 -0
  194. package/dist/src/tools/action-context.js.map +1 -0
  195. package/dist/src/tools/action-stabilization.d.ts +48 -0
  196. package/dist/src/tools/action-stabilization.d.ts.map +1 -0
  197. package/dist/src/tools/action-stabilization.js +87 -0
  198. package/dist/src/tools/action-stabilization.js.map +1 -0
  199. package/dist/src/tools/browser-tools.d.ts +8 -146
  200. package/dist/src/tools/browser-tools.d.ts.map +1 -1
  201. package/dist/src/tools/browser-tools.js +13 -689
  202. package/dist/src/tools/browser-tools.js.map +1 -1
  203. package/dist/src/tools/canvas-tools.d.ts +32 -0
  204. package/dist/src/tools/canvas-tools.d.ts.map +1 -0
  205. package/dist/src/tools/canvas-tools.js +370 -0
  206. package/dist/src/tools/canvas-tools.js.map +1 -0
  207. package/dist/src/tools/effect-tracker.d.ts +25 -0
  208. package/dist/src/tools/effect-tracker.d.ts.map +1 -0
  209. package/dist/src/tools/effect-tracker.js +69 -0
  210. package/dist/src/tools/effect-tracker.js.map +1 -0
  211. package/dist/src/tools/execute-action.d.ts +1 -31
  212. package/dist/src/tools/execute-action.d.ts.map +1 -1
  213. package/dist/src/tools/execute-action.js +7 -276
  214. package/dist/src/tools/execute-action.js.map +1 -1
  215. package/dist/src/tools/form-tools.d.ts +4 -6
  216. package/dist/src/tools/form-tools.d.ts.map +1 -1
  217. package/dist/src/tools/form-tools.js +10 -42
  218. package/dist/src/tools/form-tools.js.map +1 -1
  219. package/dist/src/tools/index.d.ts +6 -4
  220. package/dist/src/tools/index.d.ts.map +1 -1
  221. package/dist/src/tools/index.js +21 -10
  222. package/dist/src/tools/index.js.map +1 -1
  223. package/dist/src/tools/interaction-tools.d.ts +46 -0
  224. package/dist/src/tools/interaction-tools.d.ts.map +1 -0
  225. package/dist/src/tools/interaction-tools.js +138 -0
  226. package/dist/src/tools/interaction-tools.js.map +1 -0
  227. package/dist/src/tools/navigation-detection.d.ts +31 -0
  228. package/dist/src/tools/navigation-detection.d.ts.map +1 -0
  229. package/dist/src/tools/navigation-detection.js +46 -0
  230. package/dist/src/tools/navigation-detection.js.map +1 -0
  231. package/dist/src/tools/navigation-tools.d.ts +57 -0
  232. package/dist/src/tools/navigation-tools.d.ts.map +1 -0
  233. package/dist/src/tools/navigation-tools.js +178 -0
  234. package/dist/src/tools/navigation-tools.js.map +1 -0
  235. package/dist/src/tools/observation-tools.d.ts +53 -0
  236. package/dist/src/tools/observation-tools.d.ts.map +1 -0
  237. package/dist/src/tools/observation-tools.js +247 -0
  238. package/dist/src/tools/observation-tools.js.map +1 -0
  239. package/dist/src/tools/response-builder.js +2 -2
  240. package/dist/src/tools/response-builder.js.map +1 -1
  241. package/dist/src/tools/stale-element-retry.d.ts +37 -0
  242. package/dist/src/tools/stale-element-retry.d.ts.map +1 -0
  243. package/dist/src/tools/stale-element-retry.js +68 -0
  244. package/dist/src/tools/stale-element-retry.js.map +1 -0
  245. package/dist/src/tools/state-manager-registry.d.ts +26 -0
  246. package/dist/src/tools/state-manager-registry.d.ts.map +1 -0
  247. package/dist/src/tools/state-manager-registry.js +39 -0
  248. package/dist/src/tools/state-manager-registry.js.map +1 -0
  249. package/dist/src/tools/tool-context.d.ts +53 -0
  250. package/dist/src/tools/tool-context.d.ts.map +1 -0
  251. package/dist/src/tools/tool-context.js +119 -0
  252. package/dist/src/tools/tool-context.js.map +1 -0
  253. package/dist/src/tools/tool-result.types.d.ts +16 -1
  254. package/dist/src/tools/tool-result.types.d.ts.map +1 -1
  255. package/dist/src/tools/tool-result.types.js +11 -0
  256. package/dist/src/tools/tool-result.types.js.map +1 -1
  257. package/dist/src/tools/tool-schemas.d.ts +358 -146
  258. package/dist/src/tools/tool-schemas.d.ts.map +1 -1
  259. package/dist/src/tools/tool-schemas.js +142 -19
  260. package/dist/src/tools/tool-schemas.js.map +1 -1
  261. package/dist/src/tools/viewport-tools.d.ts +36 -0
  262. package/dist/src/tools/viewport-tools.d.ts.map +1 -0
  263. package/dist/src/tools/viewport-tools.js +105 -0
  264. package/dist/src/tools/viewport-tools.js.map +1 -0
  265. package/package.json +1 -1
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Modal Detector
3
+ *
4
+ * Detect modal layers in the snapshot.
5
+ * Patterns: role="dialog" + aria-modal, <dialog open>, portal containers.
6
+ */
7
+ import { computeEid } from '../element-identity.js';
8
+ /**
9
+ * Detect if node is a modal layer.
10
+ *
11
+ * Patterns:
12
+ * - role="dialog" or role="alertdialog" + aria-modal="true"
13
+ * - <dialog open>
14
+ * - High z-index (>1000) with dialog role
15
+ * - React/Vue portal containers with modal content
16
+ *
17
+ * @param node - Node to check
18
+ * @returns Layer candidate or null
19
+ */
20
+ export function detectModal(node) {
21
+ const attrs = node.attributes;
22
+ const role = node.attributes?.role;
23
+ // Pattern 1: role="dialog" or role="alertdialog" + aria-modal="true"
24
+ if ((role === 'dialog' || role === 'alertdialog') && attrs?.['aria-modal'] === 'true') {
25
+ return {
26
+ type: 'modal',
27
+ rootEid: computeEid(node, 'modal'),
28
+ zIndex: node.layout.zIndex ?? 0,
29
+ isModal: true,
30
+ confidence: 1.0,
31
+ };
32
+ }
33
+ // Pattern 2: <dialog> element with open attribute
34
+ if (node.kind === 'dialog' && attrs?.open === true) {
35
+ return {
36
+ type: 'modal',
37
+ rootEid: computeEid(node, 'modal'),
38
+ zIndex: node.layout.zIndex ?? 0,
39
+ isModal: true,
40
+ confidence: 0.95,
41
+ };
42
+ }
43
+ // Pattern 3: alertdialog without aria-modal (still modal by nature)
44
+ if (role === 'alertdialog') {
45
+ return {
46
+ type: 'modal',
47
+ rootEid: computeEid(node, 'modal'),
48
+ zIndex: node.layout.zIndex ?? 0,
49
+ isModal: true,
50
+ confidence: 0.9,
51
+ };
52
+ }
53
+ // Pattern 4: High z-index dialog (>1000)
54
+ if (role === 'dialog' && (node.layout.zIndex ?? 0) > 1000) {
55
+ return {
56
+ type: 'modal',
57
+ rootEid: computeEid(node, 'modal'),
58
+ zIndex: node.layout.zIndex ?? 0,
59
+ isModal: true,
60
+ confidence: 0.8,
61
+ };
62
+ }
63
+ // Pattern 5: Portal container detection (React/Vue/Angular)
64
+ // Common portal container patterns
65
+ if (isPortalContainer(node, attrs)) {
66
+ return {
67
+ type: 'modal',
68
+ rootEid: computeEid(node, 'modal'),
69
+ zIndex: node.layout.zIndex ?? 0,
70
+ isModal: true,
71
+ confidence: 0.75,
72
+ };
73
+ }
74
+ return null;
75
+ }
76
+ /**
77
+ * Check if node is a portal container (React/Vue/Angular patterns).
78
+ *
79
+ * @param node - Node to check
80
+ * @param attrs - Node attributes
81
+ * @returns True if portal container
82
+ */
83
+ export function isPortalContainer(node, attrs) {
84
+ const zIndex = node.layout.zIndex ?? 0;
85
+ // Must have high z-index
86
+ if (zIndex < 100) {
87
+ return false;
88
+ }
89
+ // Check for common portal container attributes/classes
90
+ const className = attrs?.class ?? attrs?.className;
91
+ if (typeof className === 'string') {
92
+ const portalPatterns = [
93
+ 'modal',
94
+ 'dialog',
95
+ 'overlay',
96
+ 'portal',
97
+ 'ReactModal',
98
+ 'MuiModal',
99
+ 'chakra-modal',
100
+ 'ant-modal',
101
+ 'el-dialog', // Element UI
102
+ 'v-dialog', // Vuetify
103
+ ];
104
+ const lowerClassName = className.toLowerCase();
105
+ if (portalPatterns.some((p) => lowerClassName.includes(p.toLowerCase()))) {
106
+ return true;
107
+ }
108
+ }
109
+ // Check for data attributes indicating portal
110
+ const dataPortal = attrs?.['data-portal'];
111
+ const dataOverlay = attrs?.['data-overlay'];
112
+ const dataModal = attrs?.['data-modal'];
113
+ if (dataPortal === true || dataOverlay === true || dataModal === true) {
114
+ return true;
115
+ }
116
+ // Check for aria-hidden siblings pattern (portal often has aria-hidden on root)
117
+ // This is detected by high z-index + covering most of viewport
118
+ const bbox = node.layout.bbox;
119
+ if (bbox && zIndex > 500) {
120
+ // If element covers significant viewport area with high z-index
121
+ if (bbox.w > 200 && bbox.h > 200) {
122
+ return true;
123
+ }
124
+ }
125
+ return false;
126
+ }
127
+ //# sourceMappingURL=modal-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modal-detector.js","sourceRoot":"","sources":["../../../../src/state/layer-detectors/modal-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Popover Detector
3
+ *
4
+ * Detect popover layers in the snapshot.
5
+ * Patterns: role="menu", "listbox", "tooltip" + z-index > 100.
6
+ */
7
+ import type { ReadableNode } from '../../snapshot/snapshot.types.js';
8
+ import type { LayerCandidate } from '../types.js';
9
+ /**
10
+ * Detect if node is a popover layer.
11
+ *
12
+ * Patterns:
13
+ * - role="menu", "listbox", "tooltip", "dialog" (non-modal) + z-index > 100
14
+ * - Dropdown/popup class patterns
15
+ *
16
+ * @param node - Node to check
17
+ * @returns Layer candidate or null
18
+ */
19
+ export declare function detectPopover(node: ReadableNode): LayerCandidate | null;
20
+ //# sourceMappingURL=popover-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"popover-detector.d.ts","sourceRoot":"","sources":["../../../../src/state/layer-detectors/popover-detector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,cAAc,GAAG,IAAI,CA+DvE"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Popover Detector
3
+ *
4
+ * Detect popover layers in the snapshot.
5
+ * Patterns: role="menu", "listbox", "tooltip" + z-index > 100.
6
+ */
7
+ import { computeEid } from '../element-identity.js';
8
+ /**
9
+ * Detect if node is a popover layer.
10
+ *
11
+ * Patterns:
12
+ * - role="menu", "listbox", "tooltip", "dialog" (non-modal) + z-index > 100
13
+ * - Dropdown/popup class patterns
14
+ *
15
+ * @param node - Node to check
16
+ * @returns Layer candidate or null
17
+ */
18
+ export function detectPopover(node) {
19
+ const role = node.attributes?.role;
20
+ const zIndex = node.layout.zIndex ?? 0;
21
+ const attrs = node.attributes;
22
+ if (zIndex <= 100) {
23
+ return null;
24
+ }
25
+ // Pattern 1: Standard popover roles
26
+ const popoverRoles = ['menu', 'listbox', 'tooltip', 'tree'];
27
+ if (role && popoverRoles.includes(role)) {
28
+ return {
29
+ type: 'popover',
30
+ rootEid: computeEid(node, 'popover'),
31
+ zIndex,
32
+ isModal: false,
33
+ confidence: 0.8,
34
+ };
35
+ }
36
+ // Pattern 2: Non-modal dialog (popup)
37
+ if (role === 'dialog' && attrs?.['aria-modal'] !== 'true') {
38
+ return {
39
+ type: 'popover',
40
+ rootEid: computeEid(node, 'popover'),
41
+ zIndex,
42
+ isModal: false,
43
+ confidence: 0.6,
44
+ };
45
+ }
46
+ // Pattern 3: Common popover/dropdown class patterns
47
+ const className = attrs?.class ?? attrs?.className;
48
+ if (typeof className === 'string') {
49
+ const popoverPatterns = [
50
+ 'dropdown',
51
+ 'popover',
52
+ 'popup',
53
+ 'tooltip',
54
+ 'menu',
55
+ 'autocomplete',
56
+ 'suggestions',
57
+ 'MuiPopover',
58
+ 'MuiMenu',
59
+ 'ant-dropdown',
60
+ 'el-dropdown',
61
+ 'el-popover',
62
+ ];
63
+ const lowerClassName = className.toLowerCase();
64
+ if (popoverPatterns.some((p) => lowerClassName.includes(p.toLowerCase()))) {
65
+ return {
66
+ type: 'popover',
67
+ rootEid: computeEid(node, 'popover'),
68
+ zIndex,
69
+ isModal: false,
70
+ confidence: 0.65,
71
+ };
72
+ }
73
+ }
74
+ return null;
75
+ }
76
+ //# sourceMappingURL=popover-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"popover-detector.js","sourceRoot":"","sources":["../../../../src/state/layer-detectors/popover-detector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAAC,IAAkB;IAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC;IACnC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,UAAiD,CAAC;IAErE,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oCAAoC;IACpC,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAC5D,IAAI,IAAI,IAAI,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,OAAO;YACL,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC;YACpC,MAAM;YACN,OAAO,EAAE,KAAK;YACd,UAAU,EAAE,GAAG;SAChB,CAAC;IACJ,CAAC;IAED,sCAAsC;IACtC,IAAI,IAAI,KAAK,QAAQ,IAAI,KAAK,EAAE,CAAC,YAAY,CAAC,KAAK,MAAM,EAAE,CAAC;QAC1D,OAAO;YACL,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC;YACpC,MAAM;YACN,OAAO,EAAE,KAAK;YACd,UAAU,EAAE,GAAG;SAChB,CAAC;IACJ,CAAC;IAED,oDAAoD;IACpD,MAAM,SAAS,GAAG,KAAK,EAAE,KAAK,IAAI,KAAK,EAAE,SAAS,CAAC;IACnD,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,eAAe,GAAG;YACtB,UAAU;YACV,SAAS;YACT,OAAO;YACP,SAAS;YACT,MAAM;YACN,cAAc;YACd,aAAa;YACb,YAAY;YACZ,SAAS;YACT,cAAc;YACd,aAAa;YACb,YAAY;SACb,CAAC;QAEF,MAAM,cAAc,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;QAC/C,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC;YAC1E,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC;gBACpC,MAAM;gBACN,OAAO,EAAE,KAAK;gBACd,UAAU,EAAE,IAAI;aACjB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Toast Detector
3
+ *
4
+ * Detect toast/alert overlay layers in the snapshot.
5
+ * Toast layers are non-blocking and never become the active layer.
6
+ */
7
+ import type { ReadableNode } from '../../snapshot/snapshot.types.js';
8
+ import type { LayerCandidate } from '../types.js';
9
+ export declare const TOAST_ROLES: Set<string>;
10
+ /**
11
+ * Detect if node is a toast/alert overlay layer.
12
+ *
13
+ * Patterns:
14
+ * - role="alert" or role="status" with high z-index (non-modal)
15
+ * - Live region kinds: alert, status, log, timer, progressbar with high z-index
16
+ *
17
+ * Toast layers are non-blocking — they appear in the layer stack but never
18
+ * become the active layer.
19
+ *
20
+ * @param node - Node to check
21
+ * @returns Layer candidate or null
22
+ */
23
+ export declare function detectToast(node: ReadableNode): LayerCandidate | null;
24
+ //# sourceMappingURL=toast-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast-detector.d.ts","sourceRoot":"","sources":["../../../../src/state/layer-detectors/toast-detector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAKlD,eAAO,MAAM,WAAW,aAA+B,CAAC;AAExD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,cAAc,GAAG,IAAI,CA4BrE"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Toast Detector
3
+ *
4
+ * Detect toast/alert overlay layers in the snapshot.
5
+ * Toast layers are non-blocking and never become the active layer.
6
+ */
7
+ import { computeEid } from '../element-identity.js';
8
+ import { isLiveRegionKind } from '../actionables-filter.js';
9
+ // Roles that indicate toast-like overlays (non-modal alert/status patterns)
10
+ export const TOAST_ROLES = new Set(['alert', 'status']);
11
+ /**
12
+ * Detect if node is a toast/alert overlay layer.
13
+ *
14
+ * Patterns:
15
+ * - role="alert" or role="status" with high z-index (non-modal)
16
+ * - Live region kinds: alert, status, log, timer, progressbar with high z-index
17
+ *
18
+ * Toast layers are non-blocking — they appear in the layer stack but never
19
+ * become the active layer.
20
+ *
21
+ * @param node - Node to check
22
+ * @returns Layer candidate or null
23
+ */
24
+ export function detectToast(node) {
25
+ const role = node.attributes?.role;
26
+ const zIndex = node.layout.zIndex ?? 0;
27
+ const attrs = node.attributes;
28
+ // Must have z-index > 100 to be considered a toast overlay
29
+ if (zIndex <= 100) {
30
+ return null;
31
+ }
32
+ // Must NOT be aria-modal (those are modals/alertdialogs, not toasts)
33
+ if (attrs?.['aria-modal'] === 'true') {
34
+ return null;
35
+ }
36
+ const hasToastRole = role !== undefined && TOAST_ROLES.has(role);
37
+ if (hasToastRole || isLiveRegionKind(node.kind)) {
38
+ return {
39
+ type: 'toast',
40
+ rootEid: computeEid(node, 'toast'),
41
+ zIndex,
42
+ isModal: false,
43
+ confidence: 0.7,
44
+ };
45
+ }
46
+ return null;
47
+ }
48
+ //# sourceMappingURL=toast-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast-detector.js","sourceRoot":"","sources":["../../../../src/state/layer-detectors/toast-detector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,4EAA4E;AAC5E,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AAExD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,WAAW,CAAC,IAAkB;IAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC;IACnC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,UAAiD,CAAC;IAErE,2DAA2D;IAC3D,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,qEAAqE;IACrE,IAAI,KAAK,EAAE,CAAC,YAAY,CAAC,KAAK,MAAM,EAAE,CAAC;QACrC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,KAAK,SAAS,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAEjE,IAAI,YAAY,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,OAAO;YACL,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC;YAClC,MAAM;YACN,OAAO,EAAE,KAAK;YACd,UAAU,EAAE,GAAG;SAChB,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Region Mapping
3
+ *
4
+ * Extracts region-to-EID mappings from actionables for deduplication.
5
+ *
6
+ * @module state/region-mapping
7
+ */
8
+ import type { ActionableInfo } from './types.js';
9
+ /**
10
+ * Extract region → ordered eid list mapping from actionables.
11
+ */
12
+ export declare function extractRegionEidMapping(actionables: ActionableInfo[]): Map<string, string[]>;
13
+ //# sourceMappingURL=region-mapping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"region-mapping.d.ts","sourceRoot":"","sources":["../../../src/state/region-mapping.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAc5F"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Region Mapping
3
+ *
4
+ * Extracts region-to-EID mappings from actionables for deduplication.
5
+ *
6
+ * @module state/region-mapping
7
+ */
8
+ import { normalizeRegion } from './state-renderer.js';
9
+ /**
10
+ * Extract region → ordered eid list mapping from actionables.
11
+ */
12
+ export function extractRegionEidMapping(actionables) {
13
+ const regions = new Map();
14
+ for (const item of actionables) {
15
+ const region = normalizeRegion(item.ctx.region);
16
+ let eids = regions.get(region);
17
+ if (!eids) {
18
+ eids = [];
19
+ regions.set(region, eids);
20
+ }
21
+ eids.push(item.eid);
22
+ }
23
+ return regions;
24
+ }
25
+ //# sourceMappingURL=region-mapping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"region-mapping.js","sourceRoot":"","sources":["../../../src/state/region-mapping.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAAC,WAA6B;IACnE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE5C,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,GAAG,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC5B,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"state-manager.d.ts","sourceRoot":"","sources":["../../../src/state/state-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,+BAA+B,CAAC;AAChF,OAAO,KAAK,EACV,aAAa,EAIb,kBAAkB,EAOlB,aAAa,EACd,MAAM,YAAY,CAAC;AASpB,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AA0ExD;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,eAAe,CAAkB;IAEzC;;;;OAIG;gBACS,OAAO,EAAE;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;KACtC;IAcD;;;OAGG;IACH,kBAAkB,IAAI,eAAe;IAIrC;;;OAGG;IACH,mBAAmB,IAAI,YAAY,GAAG,IAAI;IAI1C;;;OAGG;IACH,cAAc,IAAI,MAAM;IAQxB;;;;;OAKG;IACH,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa;IAI1D;;;;;;OAMG;IACH,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,aAAa;IAkChF;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAyH1B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,eAAe;IAgBvB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA+C3B;;;OAGG;IACH,OAAO,CAAC,mCAAmC;IAuE3C;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAyC3B;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAkFzB;;OAEG;IACH,OAAO,CAAC,cAAc;CAIvB"}
1
+ {"version":3,"file":"state-manager.d.ts","sourceRoot":"","sources":["../../../src/state/state-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,+BAA+B,CAAC;AAChF,OAAO,KAAK,EACV,aAAa,EAIb,kBAAkB,EAOlB,aAAa,EACd,MAAM,YAAY,CAAC;AASpB,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAoBxD;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,eAAe,CAAkB;IAEzC;;;;OAIG;gBACS,OAAO,EAAE;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;KACtC;IAcD;;;OAGG;IACH,kBAAkB,IAAI,eAAe;IAIrC;;;OAGG;IACH,mBAAmB,IAAI,YAAY,GAAG,IAAI;IAI1C;;;OAGG;IACH,cAAc,IAAI,MAAM;IAQxB;;;;;OAKG;IACH,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa;IAI1D;;;;;;OAMG;IACH,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,aAAa;IAkChF;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAyH1B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,eAAe;IAgBvB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA+C3B;;;OAGG;IACH,OAAO,CAAC,mCAAmC;IAuE3C;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAyC3B;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAkFzB;;OAEG;IACH,OAAO,CAAC,cAAc;CAIvB"}
@@ -7,18 +7,22 @@
7
7
  * Security: Masks sensitive values (passwords, tokens) and sanitizes URLs.
8
8
  * Reliability: Includes concurrency protection and error recovery.
9
9
  */
10
- import { createHash, randomUUID } from 'crypto';
10
+ import { randomUUID } from 'crypto';
11
11
  import { computeEid, resolveEidCollision } from './element-identity.js';
12
12
  import { detectLayers } from './layer-detector.js';
13
13
  import { computeDiff } from './diff-engine.js';
14
- import { selectActionables, isInteractiveKind } from './actionables-filter.js';
14
+ import { selectActionables, isInteractiveKind, isLiveRegionKind } from './actionables-filter.js';
15
15
  import { getNodeLayer, INCLUSIVE_OVERLAY_LAYERS } from './node-layer.js';
16
16
  import { extractAtoms } from './atoms-extractor.js';
17
17
  import { linkObservationsToSnapshot } from '../observation/index.js';
18
18
  import { generateLocator } from './locator-generator.js';
19
19
  import { ElementRegistry } from './element-registry.js';
20
20
  import { validateSnapshotHealth, isErrorHealth } from '../snapshot/snapshot-health.js';
21
- import { renderStateXml, normalizeRegion } from './state-renderer.js';
21
+ import { renderStateXml } from './state-renderer.js';
22
+ import { maskValue } from './value-masking.js';
23
+ import { sanitizeUrl, sanitizeHref } from './url-sanitization.js';
24
+ import { computeDocId, computeUiHash, computeLayerHash } from './hash-utils.js';
25
+ import { extractRegionEidMapping } from './region-mapping.js';
22
26
  // ============================================================================
23
27
  // Default Configuration
24
28
  // ============================================================================
@@ -26,59 +30,6 @@ const DEFAULT_CONFIG = {
26
30
  maxActionables: 1000, // Show all elements (practically unlimited)
27
31
  };
28
32
  // ============================================================================
29
- // Security: Sensitive Field Detection
30
- // ============================================================================
31
- /**
32
- * Sensitive field name patterns (case-insensitive).
33
- * Values in these fields will be masked.
34
- */
35
- const SENSITIVE_FIELD_PATTERNS = [
36
- 'password',
37
- 'passwd',
38
- 'pass',
39
- 'secret',
40
- 'token',
41
- 'auth',
42
- 'key',
43
- 'api_key',
44
- 'apikey',
45
- 'otp',
46
- 'pin',
47
- 'cvv',
48
- 'cvc',
49
- 'ssn',
50
- 'social',
51
- 'credit',
52
- 'card',
53
- ];
54
- /**
55
- * Input types that should always be masked.
56
- */
57
- const MASKED_INPUT_TYPES = ['password'];
58
- /**
59
- * Input types with partial masking (show first/last chars).
60
- */
61
- const PARTIAL_MASK_TYPES = ['email', 'tel', 'phone'];
62
- /**
63
- * URL query parameters that are safe to keep.
64
- * All others will be stripped.
65
- */
66
- const SAFE_QUERY_PARAMS = new Set([
67
- 'page',
68
- 'p',
69
- 'sort',
70
- 'order',
71
- 'q',
72
- 'query',
73
- 'search',
74
- 'tab',
75
- 'view',
76
- 'limit',
77
- 'offset',
78
- 'lang',
79
- 'locale',
80
- ]);
81
- // ============================================================================
82
33
  // State Manager Class
83
34
  // ============================================================================
84
35
  /**
@@ -225,7 +176,7 @@ export class StateManager {
225
176
  const actionables = this.formatActionables(actionableNodes, layerResult.active, snapshot.snapshot_id);
226
177
  // Count total actionables in active layer
227
178
  const skipLayerFilter = INCLUSIVE_OVERLAY_LAYERS.has(layerResult.active);
228
- const totalInLayer = snapshot.nodes.filter((n) => isInteractiveKind(n.kind) &&
179
+ const totalInLayer = snapshot.nodes.filter((n) => (isInteractiveKind(n.kind) || isLiveRegionKind(n.kind)) &&
229
180
  n.state?.visible &&
230
181
  (skipLayerFilter || getNodeLayer(n, layerResult.active) === layerResult.active)).length;
231
182
  const counts = {
@@ -509,139 +460,4 @@ export class StateManager {
509
460
  return Math.ceil(jsonString.length / 4);
510
461
  }
511
462
  }
512
- // ============================================================================
513
- // Security: Value Masking
514
- // ============================================================================
515
- /**
516
- * Mask sensitive values in val_hint.
517
- *
518
- * Rules:
519
- * - password type: always full mask
520
- * - sensitive field names: always full mask
521
- * - email/tel: partial mask (show first/last chars)
522
- * - default: truncate to 12 chars, mask middle
523
- */
524
- function maskValue(value, inputType, label) {
525
- // Strip newlines first
526
- const cleanValue = value.replace(/[\r\n]/g, ' ').trim();
527
- if (!cleanValue)
528
- return '';
529
- // Password type: always full mask
530
- if (inputType && MASKED_INPUT_TYPES.includes(inputType.toLowerCase())) {
531
- return '••••••••';
532
- }
533
- // Check sensitive field names
534
- const lowerLabel = (label ?? '').toLowerCase();
535
- for (const pattern of SENSITIVE_FIELD_PATTERNS) {
536
- if (lowerLabel.includes(pattern)) {
537
- return '***';
538
- }
539
- }
540
- // Email/tel: partial mask
541
- if (inputType && PARTIAL_MASK_TYPES.includes(inputType.toLowerCase())) {
542
- return partialMask(cleanValue);
543
- }
544
- // Default: truncate and partial mask if long
545
- if (cleanValue.length <= 12) {
546
- return cleanValue;
547
- }
548
- return partialMask(cleanValue.substring(0, 12));
549
- }
550
- /**
551
- * Partial mask: show first 2 and last 2 chars.
552
- * Example: "example@email.com" -> "ex•••om"
553
- */
554
- function partialMask(value) {
555
- if (value.length <= 4) {
556
- return '••••';
557
- }
558
- const first = value.substring(0, 2);
559
- const last = value.substring(value.length - 2);
560
- return `${first}•••${last}`;
561
- }
562
- // ============================================================================
563
- // Security: URL Sanitization
564
- // ============================================================================
565
- /**
566
- * Sanitize URL by stripping sensitive query parameters.
567
- * Only keeps safe params like page, sort, q.
568
- */
569
- function sanitizeUrl(rawUrl) {
570
- try {
571
- const url = new URL(rawUrl);
572
- // Build new search params with only safe ones
573
- const safeParams = new URLSearchParams();
574
- for (const [key, value] of url.searchParams) {
575
- if (SAFE_QUERY_PARAMS.has(key.toLowerCase())) {
576
- safeParams.set(key, value);
577
- }
578
- }
579
- // Reconstruct URL with sanitized params
580
- url.search = safeParams.toString();
581
- return url.toString();
582
- }
583
- catch {
584
- // If URL parsing fails, return origin only
585
- return rawUrl.split('?')[0];
586
- }
587
- }
588
- /**
589
- * Sanitize href attribute (remove tokens from URLs).
590
- */
591
- function sanitizeHref(href) {
592
- // For relative URLs, return as-is
593
- if (!href.startsWith('http://') && !href.startsWith('https://')) {
594
- return href;
595
- }
596
- return sanitizeUrl(href);
597
- }
598
- // ============================================================================
599
- // Utilities
600
- // ============================================================================
601
- /**
602
- * Extract region → ordered eid list mapping from actionables.
603
- */
604
- function extractRegionEidMapping(actionables) {
605
- const regions = new Map();
606
- for (const item of actionables) {
607
- const region = normalizeRegion(item.ctx.region);
608
- let eids = regions.get(region);
609
- if (!eids) {
610
- eids = [];
611
- regions.set(region, eids);
612
- }
613
- eids.push(item.eid);
614
- }
615
- return regions;
616
- }
617
- /**
618
- * Compute document ID from snapshot.
619
- *
620
- * Uses only URL origin + pathname for navigation detection.
621
- * This ensures DOM mutations (like autocomplete suggestions appearing)
622
- * are NOT falsely detected as navigation events.
623
- *
624
- * NOTE: Previously this included a hash of the first 10 interactive node IDs,
625
- * which caused false navigation detection when typing triggered autocomplete
626
- * or other dynamic UI updates. See: https://github.com/lespaceman/agent-web-interface/issues/XXX
627
- */
628
- function computeDocId(snapshot) {
629
- const url = new URL(snapshot.url);
630
- // Only use origin + pathname for navigation detection
631
- // Query params and fragments are ignored (same page, different state)
632
- return hash(`${url.origin}:${url.pathname}`);
633
- }
634
- function computeUiHash(snapshot) {
635
- const interactiveNodeIds = snapshot.nodes
636
- .filter((n) => isInteractiveKind(n.kind) && n.state?.visible)
637
- .map((n) => computeEid(n))
638
- .join(',');
639
- return hash(interactiveNodeIds).substring(0, 6);
640
- }
641
- function computeLayerHash(stack) {
642
- return hash(stack.join(',')).substring(0, 6);
643
- }
644
- function hash(input) {
645
- return createHash('sha256').update(input).digest('hex').substring(0, 12);
646
- }
647
463
  //# sourceMappingURL=state-manager.js.map