@monoes/monobrowse 1.0.12 → 1.0.14

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 (271) hide show
  1. package/dist/src/__tests__/bridge-instruments.test.d.ts +2 -0
  2. package/dist/src/__tests__/bridge-instruments.test.d.ts.map +1 -0
  3. package/dist/src/__tests__/bridge-instruments.test.js +132 -0
  4. package/dist/src/__tests__/bridge-instruments.test.js.map +1 -0
  5. package/dist/src/__tests__/bridge-transport.test.d.ts +2 -0
  6. package/dist/src/__tests__/bridge-transport.test.d.ts.map +1 -0
  7. package/dist/src/__tests__/bridge-transport.test.js +287 -0
  8. package/dist/src/__tests__/bridge-transport.test.js.map +1 -0
  9. package/dist/src/__tests__/cdp-transport.test.d.ts +2 -0
  10. package/dist/src/__tests__/cdp-transport.test.d.ts.map +1 -0
  11. package/dist/src/__tests__/cdp-transport.test.js +167 -0
  12. package/dist/src/__tests__/cdp-transport.test.js.map +1 -0
  13. package/dist/src/__tests__/profiler-heap.test.d.ts +2 -0
  14. package/dist/src/__tests__/profiler-heap.test.d.ts.map +1 -0
  15. package/dist/src/__tests__/profiler-heap.test.js +154 -0
  16. package/dist/src/__tests__/profiler-heap.test.js.map +1 -0
  17. package/dist/src/__tests__/report-a11y.test.d.ts +2 -0
  18. package/dist/src/__tests__/report-a11y.test.d.ts.map +1 -0
  19. package/dist/src/__tests__/report-a11y.test.js +147 -0
  20. package/dist/src/__tests__/report-a11y.test.js.map +1 -0
  21. package/dist/src/__tests__/report-analyze.test.d.ts +2 -0
  22. package/dist/src/__tests__/report-analyze.test.d.ts.map +1 -0
  23. package/dist/src/__tests__/report-analyze.test.js +157 -0
  24. package/dist/src/__tests__/report-analyze.test.js.map +1 -0
  25. package/dist/src/__tests__/report-budget.test.d.ts +2 -0
  26. package/dist/src/__tests__/report-budget.test.d.ts.map +1 -0
  27. package/dist/src/__tests__/report-budget.test.js +80 -0
  28. package/dist/src/__tests__/report-budget.test.js.map +1 -0
  29. package/dist/src/__tests__/report-diff.test.d.ts +2 -0
  30. package/dist/src/__tests__/report-diff.test.d.ts.map +1 -0
  31. package/dist/src/__tests__/report-diff.test.js +231 -0
  32. package/dist/src/__tests__/report-diff.test.js.map +1 -0
  33. package/dist/src/__tests__/report-evidence.test.d.ts +2 -0
  34. package/dist/src/__tests__/report-evidence.test.d.ts.map +1 -0
  35. package/dist/src/__tests__/report-evidence.test.js +214 -0
  36. package/dist/src/__tests__/report-evidence.test.js.map +1 -0
  37. package/dist/src/__tests__/report-flake.test.d.ts +2 -0
  38. package/dist/src/__tests__/report-flake.test.d.ts.map +1 -0
  39. package/dist/src/__tests__/report-flake.test.js +182 -0
  40. package/dist/src/__tests__/report-flake.test.js.map +1 -0
  41. package/dist/src/__tests__/report-history.test.d.ts +2 -0
  42. package/dist/src/__tests__/report-history.test.d.ts.map +1 -0
  43. package/dist/src/__tests__/report-history.test.js +229 -0
  44. package/dist/src/__tests__/report-history.test.js.map +1 -0
  45. package/dist/src/__tests__/report-output.test.d.ts +2 -0
  46. package/dist/src/__tests__/report-output.test.d.ts.map +1 -0
  47. package/dist/src/__tests__/report-output.test.js +169 -0
  48. package/dist/src/__tests__/report-output.test.js.map +1 -0
  49. package/dist/src/__tests__/report-png.test.d.ts +2 -0
  50. package/dist/src/__tests__/report-png.test.d.ts.map +1 -0
  51. package/dist/src/__tests__/report-png.test.js +84 -0
  52. package/dist/src/__tests__/report-png.test.js.map +1 -0
  53. package/dist/src/__tests__/report-render-extras.test.d.ts +2 -0
  54. package/dist/src/__tests__/report-render-extras.test.d.ts.map +1 -0
  55. package/dist/src/__tests__/report-render-extras.test.js +285 -0
  56. package/dist/src/__tests__/report-render-extras.test.js.map +1 -0
  57. package/dist/src/__tests__/report-render.test.d.ts +2 -0
  58. package/dist/src/__tests__/report-render.test.d.ts.map +1 -0
  59. package/dist/src/__tests__/report-render.test.js +143 -0
  60. package/dist/src/__tests__/report-render.test.js.map +1 -0
  61. package/dist/src/__tests__/report-run.test.d.ts +2 -0
  62. package/dist/src/__tests__/report-run.test.d.ts.map +1 -0
  63. package/dist/src/__tests__/report-run.test.js +234 -0
  64. package/dist/src/__tests__/report-run.test.js.map +1 -0
  65. package/dist/src/browser/bridge.d.ts +119 -0
  66. package/dist/src/browser/bridge.d.ts.map +1 -0
  67. package/dist/src/browser/bridge.js +264 -0
  68. package/dist/src/browser/bridge.js.map +1 -0
  69. package/dist/src/browser/cdp.d.ts +11 -1
  70. package/dist/src/browser/cdp.d.ts.map +1 -1
  71. package/dist/src/browser/cdp.js +60 -56
  72. package/dist/src/browser/cdp.js.map +1 -1
  73. package/dist/src/browser/index.d.ts +3 -0
  74. package/dist/src/browser/index.d.ts.map +1 -1
  75. package/dist/src/browser/index.js +3 -0
  76. package/dist/src/browser/index.js.map +1 -1
  77. package/dist/src/browser/profiler.d.ts.map +1 -1
  78. package/dist/src/browser/profiler.js +19 -22
  79. package/dist/src/browser/profiler.js.map +1 -1
  80. package/dist/src/browser/transport.d.ts +62 -0
  81. package/dist/src/browser/transport.d.ts.map +1 -0
  82. package/dist/src/browser/transport.js +65 -0
  83. package/dist/src/browser/transport.js.map +1 -0
  84. package/dist/src/cli/commander-adapter.d.ts +16 -0
  85. package/dist/src/cli/commander-adapter.d.ts.map +1 -0
  86. package/dist/src/cli/commander-adapter.js +68 -0
  87. package/dist/src/cli/commander-adapter.js.map +1 -0
  88. package/dist/src/cli/commands-context.d.ts +14 -0
  89. package/dist/src/cli/commands-context.d.ts.map +1 -0
  90. package/dist/src/cli/commands-context.js +351 -0
  91. package/dist/src/cli/commands-context.js.map +1 -0
  92. package/dist/src/cli/commands-data.d.ts +12 -0
  93. package/dist/src/cli/commands-data.d.ts.map +1 -0
  94. package/dist/src/cli/commands-data.js +246 -0
  95. package/dist/src/cli/commands-data.js.map +1 -0
  96. package/dist/src/cli/commands-element.d.ts +15 -0
  97. package/dist/src/cli/commands-element.d.ts.map +1 -0
  98. package/dist/src/cli/commands-element.js +262 -0
  99. package/dist/src/cli/commands-element.js.map +1 -0
  100. package/dist/src/cli/commands-files.d.ts +9 -0
  101. package/dist/src/cli/commands-files.d.ts.map +1 -0
  102. package/dist/src/cli/commands-files.js +207 -0
  103. package/dist/src/cli/commands-files.js.map +1 -0
  104. package/dist/src/cli/commands-input.d.ts +26 -0
  105. package/dist/src/cli/commands-input.d.ts.map +1 -0
  106. package/dist/src/cli/commands-input.js +399 -0
  107. package/dist/src/cli/commands-input.js.map +1 -0
  108. package/dist/src/cli/commands-navigate.d.ts +12 -0
  109. package/dist/src/cli/commands-navigate.d.ts.map +1 -0
  110. package/dist/src/cli/commands-navigate.js +389 -0
  111. package/dist/src/cli/commands-navigate.js.map +1 -0
  112. package/dist/src/cli/commands-page.d.ts +25 -0
  113. package/dist/src/cli/commands-page.d.ts.map +1 -0
  114. package/dist/src/cli/commands-page.js +377 -0
  115. package/dist/src/cli/commands-page.js.map +1 -0
  116. package/dist/src/cli/commands-report.d.ts +8 -0
  117. package/dist/src/cli/commands-report.d.ts.map +1 -0
  118. package/dist/src/cli/commands-report.js +256 -0
  119. package/dist/src/cli/commands-report.js.map +1 -0
  120. package/dist/src/cli/commands-script.d.ts +43 -0
  121. package/dist/src/cli/commands-script.d.ts.map +1 -0
  122. package/dist/src/cli/commands-script.js +168 -0
  123. package/dist/src/cli/commands-script.js.map +1 -0
  124. package/dist/src/cli/commands-session.d.ts +15 -0
  125. package/dist/src/cli/commands-session.d.ts.map +1 -0
  126. package/dist/src/cli/commands-session.js +357 -0
  127. package/dist/src/cli/commands-session.js.map +1 -0
  128. package/dist/src/cli/commands-trace.d.ts +12 -0
  129. package/dist/src/cli/commands-trace.d.ts.map +1 -0
  130. package/dist/src/cli/commands-trace.js +347 -0
  131. package/dist/src/cli/commands-trace.js.map +1 -0
  132. package/dist/src/cli/commands.d.ts +22 -42
  133. package/dist/src/cli/commands.d.ts.map +1 -1
  134. package/dist/src/cli/commands.js +48 -3400
  135. package/dist/src/cli/commands.js.map +1 -1
  136. package/dist/src/cli/session.d.ts +47 -0
  137. package/dist/src/cli/session.d.ts.map +1 -0
  138. package/dist/src/cli/session.js +343 -0
  139. package/dist/src/cli/session.js.map +1 -0
  140. package/dist/src/report/a11y.d.ts +52 -0
  141. package/dist/src/report/a11y.d.ts.map +1 -0
  142. package/dist/src/report/a11y.js +231 -0
  143. package/dist/src/report/a11y.js.map +1 -0
  144. package/dist/src/report/analyze.d.ts +20 -0
  145. package/dist/src/report/analyze.d.ts.map +1 -0
  146. package/dist/src/report/analyze.js +136 -0
  147. package/dist/src/report/analyze.js.map +1 -0
  148. package/dist/src/report/budget.d.ts +27 -0
  149. package/dist/src/report/budget.d.ts.map +1 -0
  150. package/dist/src/report/budget.js +143 -0
  151. package/dist/src/report/budget.js.map +1 -0
  152. package/dist/src/report/collect-a11y.d.ts +25 -0
  153. package/dist/src/report/collect-a11y.d.ts.map +1 -0
  154. package/dist/src/report/collect-a11y.js +154 -0
  155. package/dist/src/report/collect-a11y.js.map +1 -0
  156. package/dist/src/report/collect.d.ts +45 -0
  157. package/dist/src/report/collect.d.ts.map +1 -0
  158. package/dist/src/report/collect.js +275 -0
  159. package/dist/src/report/collect.js.map +1 -0
  160. package/dist/src/report/evidence.d.ts +80 -0
  161. package/dist/src/report/evidence.d.ts.map +1 -0
  162. package/dist/src/report/evidence.js +279 -0
  163. package/dist/src/report/evidence.js.map +1 -0
  164. package/dist/src/report/flake.d.ts +88 -0
  165. package/dist/src/report/flake.d.ts.map +1 -0
  166. package/dist/src/report/flake.js +232 -0
  167. package/dist/src/report/flake.js.map +1 -0
  168. package/dist/src/report/history.d.ts +85 -0
  169. package/dist/src/report/history.d.ts.map +1 -0
  170. package/dist/src/report/history.js +176 -0
  171. package/dist/src/report/history.js.map +1 -0
  172. package/dist/src/report/index.d.ts +102 -0
  173. package/dist/src/report/index.d.ts.map +1 -0
  174. package/dist/src/report/index.js +216 -0
  175. package/dist/src/report/index.js.map +1 -0
  176. package/dist/src/report/pixel-diff.d.ts +30 -0
  177. package/dist/src/report/pixel-diff.d.ts.map +1 -0
  178. package/dist/src/report/pixel-diff.js +175 -0
  179. package/dist/src/report/pixel-diff.js.map +1 -0
  180. package/dist/src/report/png.d.ts +28 -0
  181. package/dist/src/report/png.d.ts.map +1 -0
  182. package/dist/src/report/png.js +259 -0
  183. package/dist/src/report/png.js.map +1 -0
  184. package/dist/src/report/render-evidence.d.ts +16 -0
  185. package/dist/src/report/render-evidence.d.ts.map +1 -0
  186. package/dist/src/report/render-evidence.js +174 -0
  187. package/dist/src/report/render-evidence.js.map +1 -0
  188. package/dist/src/report/render-trend.d.ts +16 -0
  189. package/dist/src/report/render-trend.d.ts.map +1 -0
  190. package/dist/src/report/render-trend.js +194 -0
  191. package/dist/src/report/render-trend.js.map +1 -0
  192. package/dist/src/report/render.d.ts +21 -0
  193. package/dist/src/report/render.d.ts.map +1 -0
  194. package/dist/src/report/render.js +286 -0
  195. package/dist/src/report/render.js.map +1 -0
  196. package/dist/src/report/run-diff.d.ts +18 -0
  197. package/dist/src/report/run-diff.d.ts.map +1 -0
  198. package/dist/src/report/run-diff.js +51 -0
  199. package/dist/src/report/run-diff.js.map +1 -0
  200. package/dist/src/report/structure.d.ts +41 -0
  201. package/dist/src/report/structure.d.ts.map +1 -0
  202. package/dist/src/report/structure.js +210 -0
  203. package/dist/src/report/structure.js.map +1 -0
  204. package/dist/src/report/trend.d.ts +26 -0
  205. package/dist/src/report/trend.d.ts.map +1 -0
  206. package/dist/src/report/trend.js +164 -0
  207. package/dist/src/report/trend.js.map +1 -0
  208. package/dist/src/report/types.d.ts +320 -0
  209. package/dist/src/report/types.d.ts.map +1 -0
  210. package/dist/src/report/types.js +11 -0
  211. package/dist/src/report/types.js.map +1 -0
  212. package/dist/src/report/util.d.ts +17 -0
  213. package/dist/src/report/util.d.ts.map +1 -0
  214. package/dist/src/report/util.js +45 -0
  215. package/dist/src/report/util.js.map +1 -0
  216. package/dist/tsconfig.tsbuildinfo +1 -1
  217. package/package.json +1 -1
  218. package/src/__tests__/bridge-instruments.test.ts +180 -0
  219. package/src/__tests__/bridge-transport.test.ts +365 -0
  220. package/src/__tests__/cdp-transport.test.ts +198 -0
  221. package/src/__tests__/profiler-heap.test.ts +191 -0
  222. package/src/__tests__/report-a11y.test.ts +180 -0
  223. package/src/__tests__/report-analyze.test.ts +202 -0
  224. package/src/__tests__/report-budget.test.ts +92 -0
  225. package/src/__tests__/report-diff.test.ts +272 -0
  226. package/src/__tests__/report-evidence.test.ts +276 -0
  227. package/src/__tests__/report-flake.test.ts +214 -0
  228. package/src/__tests__/report-history.test.ts +293 -0
  229. package/src/__tests__/report-output.test.ts +210 -0
  230. package/src/__tests__/report-png.test.ts +95 -0
  231. package/src/__tests__/report-render-extras.test.ts +315 -0
  232. package/src/__tests__/report-render.test.ts +175 -0
  233. package/src/__tests__/report-run.test.ts +264 -0
  234. package/src/browser/bridge.ts +354 -0
  235. package/src/browser/cdp.ts +57 -52
  236. package/src/browser/index.ts +3 -0
  237. package/src/browser/profiler.ts +28 -21
  238. package/src/browser/transport.ts +111 -0
  239. package/src/cli/commander-adapter.ts +65 -0
  240. package/src/cli/commands-context.ts +367 -0
  241. package/src/cli/commands-data.ts +248 -0
  242. package/src/cli/commands-element.ts +305 -0
  243. package/src/cli/commands-files.ts +248 -0
  244. package/src/cli/commands-input.ts +434 -0
  245. package/src/cli/commands-navigate.ts +442 -0
  246. package/src/cli/commands-page.ts +420 -0
  247. package/src/cli/commands-report.ts +275 -0
  248. package/src/cli/commands-script.ts +183 -0
  249. package/src/cli/commands-session.ts +376 -0
  250. package/src/cli/commands-trace.ts +349 -0
  251. package/src/cli/commands.ts +101 -3677
  252. package/src/cli/session.ts +412 -0
  253. package/src/report/a11y.ts +242 -0
  254. package/src/report/analyze.ts +181 -0
  255. package/src/report/budget.ts +155 -0
  256. package/src/report/collect-a11y.ts +200 -0
  257. package/src/report/collect.ts +408 -0
  258. package/src/report/evidence.ts +379 -0
  259. package/src/report/flake.ts +303 -0
  260. package/src/report/history.ts +219 -0
  261. package/src/report/index.ts +307 -0
  262. package/src/report/pixel-diff.ts +197 -0
  263. package/src/report/png.ts +290 -0
  264. package/src/report/render-evidence.ts +194 -0
  265. package/src/report/render-trend.ts +225 -0
  266. package/src/report/render.ts +314 -0
  267. package/src/report/run-diff.ts +63 -0
  268. package/src/report/structure.ts +212 -0
  269. package/src/report/trend.ts +189 -0
  270. package/src/report/types.ts +356 -0
  271. package/src/report/util.ts +48 -0
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Budget evaluation — the step that makes "the agent tested it" mean
3
+ * something. Pure function of CaptureData + Budget, so CI behaviour is
4
+ * testable without a browser.
5
+ */
6
+ import type { Budget, BudgetFailure, CaptureData, ConsoleEntry, Report, RequestEntry, VerdictValue } from './types.js';
7
+ export declare function consoleErrors(entries: ConsoleEntry[]): ConsoleEntry[];
8
+ export declare function consoleWarnings(entries: ConsoleEntry[]): ConsoleEntry[];
9
+ export declare function failedRequests(requests: RequestEntry[]): RequestEntry[];
10
+ export interface Evaluation {
11
+ verdict: VerdictValue;
12
+ failures: BudgetFailure[];
13
+ /** Budgets that were set but could not be checked — the page never reported the metric. */
14
+ unmeasured: string[];
15
+ }
16
+ export declare function evaluateBudget(data: CaptureData, budget: Budget): Evaluation;
17
+ export declare function buildReport(data: CaptureData, budget: Budget): Report;
18
+ /** One line for a CI log / agent transcript. */
19
+ export declare function summarizeVerdict(report: Report): string;
20
+ //# sourceMappingURL=analyze.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../../src/report/analyze.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAEV,MAAM,EACN,aAAa,EACb,WAAW,EACX,YAAY,EACZ,MAAM,EACN,YAAY,EACZ,YAAY,EACb,MAAM,YAAY,CAAC;AAKpB,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,CAErE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,CAEvE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,CAEvE;AAgCD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,YAAY,CAAC;IACtB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,2FAA2F;IAC3F,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CA+E5E;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAmBrE;AAED,gDAAgD;AAChD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMvD"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Budget evaluation — the step that makes "the agent tested it" mean
3
+ * something. Pure function of CaptureData + Budget, so CI behaviour is
4
+ * testable without a browser.
5
+ */
6
+ import { countA11y } from './a11y.js';
7
+ import { budgetLabel, formatThreshold } from './budget.js';
8
+ /** How many concrete examples to quote in a failure's `detail`. */
9
+ const DETAIL_SAMPLE = 3;
10
+ export function consoleErrors(entries) {
11
+ return entries.filter((e) => e.type === 'error');
12
+ }
13
+ export function consoleWarnings(entries) {
14
+ return entries.filter((e) => e.type === 'warn' || e.type === 'warning');
15
+ }
16
+ export function failedRequests(requests) {
17
+ return requests.filter((r) => r.failed);
18
+ }
19
+ function truncate(text, max = 160) {
20
+ const flat = text.replace(/\s+/g, ' ').trim();
21
+ return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;
22
+ }
23
+ function sample(items) {
24
+ // Not `.map(truncate)`: map passes the index as the second argument, which
25
+ // would become truncate's `max` and shave every sample down to nothing.
26
+ const shown = items.slice(0, DETAIL_SAMPLE).map((item) => truncate(item));
27
+ const rest = items.length - shown.length;
28
+ return rest > 0 ? `${shown.join(' | ')} (+${rest} more)` : shown.join(' | ');
29
+ }
30
+ function describeRequest(r) {
31
+ const status = r.status !== undefined ? String(r.status) : (r.errorText ?? 'no response');
32
+ return `${status} ${r.method} ${r.url}`;
33
+ }
34
+ export function evaluateBudget(data, budget) {
35
+ const failures = [];
36
+ const unmeasured = [];
37
+ const cErrors = consoleErrors(data.console);
38
+ const failed = failedRequests(data.requests);
39
+ const a11y = countA11y(data.a11y);
40
+ const counts = [
41
+ {
42
+ key: 'maxConsoleErrors',
43
+ actual: cErrors.length,
44
+ detail: sample(cErrors.map((e) => e.text)),
45
+ },
46
+ {
47
+ key: 'maxPageErrors',
48
+ actual: data.pageErrors.length,
49
+ detail: sample(data.pageErrors.map((e) => e.text)),
50
+ },
51
+ {
52
+ key: 'maxFailedRequests',
53
+ actual: failed.length,
54
+ detail: sample(failed.map(describeRequest)),
55
+ },
56
+ {
57
+ key: 'maxA11yErrors',
58
+ actual: a11y.errors,
59
+ detail: sample(data.a11y
60
+ .filter((f) => f.impact === 'error')
61
+ .map((f) => `${f.rule} at ${f.locator}`)),
62
+ },
63
+ ];
64
+ for (const check of counts) {
65
+ const limit = budget[check.key];
66
+ if (limit === null)
67
+ continue;
68
+ if (check.actual > limit) {
69
+ failures.push({
70
+ budget: check.key,
71
+ expected: formatThreshold(check.key, limit),
72
+ actual: String(check.actual),
73
+ detail: check.detail || undefined,
74
+ });
75
+ }
76
+ }
77
+ const ms = (v) => `${Math.round(v)}ms`;
78
+ const score = (v) => v.toFixed(4).replace(/0+$/, '').replace(/\.$/, '');
79
+ const metrics = [
80
+ { key: 'lcpMs', actual: data.vitals.lcp, format: ms },
81
+ { key: 'clsScore', actual: data.vitals.cls, format: score },
82
+ { key: 'inpMs', actual: data.vitals.inp, format: ms },
83
+ { key: 'fcpMs', actual: data.vitals.fcp, format: ms },
84
+ { key: 'ttfbMs', actual: data.vitals.ttfb, format: ms },
85
+ ];
86
+ for (const metric of metrics) {
87
+ const limit = budget[metric.key];
88
+ if (limit === null)
89
+ continue;
90
+ if (metric.actual === undefined || !Number.isFinite(metric.actual)) {
91
+ // A page that never fires an LCP entry (no contentful paint, an
92
+ // observer the browser does not support, a collector that timed out)
93
+ // must not be silently graded as passing — but it is not a breach
94
+ // either. Surface it as unmeasured and let the report say so.
95
+ unmeasured.push(budgetLabel(metric.key));
96
+ continue;
97
+ }
98
+ if (metric.actual > limit) {
99
+ failures.push({
100
+ budget: metric.key,
101
+ expected: formatThreshold(metric.key, limit),
102
+ actual: metric.format(metric.actual),
103
+ });
104
+ }
105
+ }
106
+ return { verdict: failures.length > 0 ? 'fail' : 'pass', failures, unmeasured };
107
+ }
108
+ export function buildReport(data, budget) {
109
+ const evaluation = evaluateBudget(data, budget);
110
+ const a11y = countA11y(data.a11y);
111
+ return {
112
+ ...data,
113
+ budget,
114
+ verdict: evaluation.verdict,
115
+ failures: evaluation.failures,
116
+ unmeasured: evaluation.unmeasured,
117
+ counts: {
118
+ consoleErrors: consoleErrors(data.console).length,
119
+ consoleWarnings: consoleWarnings(data.console).length,
120
+ pageErrors: data.pageErrors.length,
121
+ requests: data.requests.length,
122
+ failedRequests: failedRequests(data.requests).length,
123
+ a11yErrors: a11y.errors,
124
+ a11yWarnings: a11y.warnings,
125
+ },
126
+ };
127
+ }
128
+ /** One line for a CI log / agent transcript. */
129
+ export function summarizeVerdict(report) {
130
+ if (report.verdict === 'pass') {
131
+ return `PASS — ${report.counts.requests} requests, 0 budget failures`;
132
+ }
133
+ const names = report.failures.map((f) => budgetLabel(f.budget)).join(', ');
134
+ return `FAIL — ${report.failures.length} budget failure(s): ${names}`;
135
+ }
136
+ //# sourceMappingURL=analyze.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../../src/report/analyze.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Budget parsing for `monobrowse report`.
3
+ *
4
+ * A budget is what turns "the agent looked at the page" into "the agent
5
+ * tested the page": the thresholds the run is gated on. Defaults are the
6
+ * strict ones you actually want in CI — zero errors, zero failed requests,
7
+ * Core Web Vitals at Google's "good" boundary.
8
+ */
9
+ import type { Budget } from './types.js';
10
+ export declare const DEFAULT_BUDGET: Budget;
11
+ export declare function budgetLabel(key: keyof Budget): string;
12
+ /** `2500` -> `<= 2500ms`, `0` -> `<= 0`, `0.1` -> `<= 0.1`. */
13
+ export declare function formatThreshold(key: keyof Budget, value: number): string;
14
+ /**
15
+ * Turn a parsed JSON object into a Budget, merged over the defaults.
16
+ *
17
+ * Unknown keys throw rather than being ignored: a typo'd `max_console_error`
18
+ * silently loosening a CI gate is exactly the failure mode budgets exist to
19
+ * prevent.
20
+ */
21
+ export declare function parseBudget(input: unknown, source?: string): Budget;
22
+ /**
23
+ * Resolve `--budget`. The value is either inline JSON (starts with `{`) or a
24
+ * path to a JSON file. Omitted means DEFAULT_BUDGET.
25
+ */
26
+ export declare function loadBudget(spec?: string): Promise<Budget>;
27
+ //# sourceMappingURL=budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.d.ts","sourceRoot":"","sources":["../../../src/report/budget.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,eAAO,MAAM,cAAc,EAAE,MAU5B,CAAC;AAiDF,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,MAAM,GAAG,MAAM,CAErD;AAED,+DAA+D;AAC/D,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAIxE;AAMD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,SAAW,GAAG,MAAM,CA4BrE;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA2B/D"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Budget parsing for `monobrowse report`.
3
+ *
4
+ * A budget is what turns "the agent looked at the page" into "the agent
5
+ * tested the page": the thresholds the run is gated on. Defaults are the
6
+ * strict ones you actually want in CI — zero errors, zero failed requests,
7
+ * Core Web Vitals at Google's "good" boundary.
8
+ */
9
+ import { readFile } from 'node:fs/promises';
10
+ export const DEFAULT_BUDGET = {
11
+ maxConsoleErrors: 0,
12
+ maxPageErrors: 0,
13
+ maxFailedRequests: 0,
14
+ maxA11yErrors: 0,
15
+ lcpMs: 2500,
16
+ clsScore: 0.1,
17
+ inpMs: 200,
18
+ fcpMs: null,
19
+ ttfbMs: null,
20
+ };
21
+ /** Every spelling we accept, normalized (lowercased, `_`/`-` stripped). */
22
+ const KEY_ALIASES = {
23
+ maxconsoleerrors: 'maxConsoleErrors',
24
+ consoleerrors: 'maxConsoleErrors',
25
+ maxpageerrors: 'maxPageErrors',
26
+ pageerrors: 'maxPageErrors',
27
+ maxfailedrequests: 'maxFailedRequests',
28
+ failedrequests: 'maxFailedRequests',
29
+ maxa11yerrors: 'maxA11yErrors',
30
+ a11yerrors: 'maxA11yErrors',
31
+ maxaccessibilityerrors: 'maxA11yErrors',
32
+ lcp: 'lcpMs',
33
+ lcpms: 'lcpMs',
34
+ cls: 'clsScore',
35
+ clsscore: 'clsScore',
36
+ inp: 'inpMs',
37
+ inpms: 'inpMs',
38
+ fcp: 'fcpMs',
39
+ fcpms: 'fcpMs',
40
+ ttfb: 'ttfbMs',
41
+ ttfbms: 'ttfbMs',
42
+ };
43
+ const BUDGET_UNITS = {
44
+ maxConsoleErrors: 'count',
45
+ maxPageErrors: 'count',
46
+ maxFailedRequests: 'count',
47
+ maxA11yErrors: 'count',
48
+ lcpMs: 'ms',
49
+ clsScore: 'score',
50
+ inpMs: 'ms',
51
+ fcpMs: 'ms',
52
+ ttfbMs: 'ms',
53
+ };
54
+ const BUDGET_LABELS = {
55
+ maxConsoleErrors: 'Console errors',
56
+ maxPageErrors: 'Uncaught page errors',
57
+ maxFailedRequests: 'Failed requests',
58
+ maxA11yErrors: 'Accessibility errors',
59
+ lcpMs: 'LCP (Largest Contentful Paint)',
60
+ clsScore: 'CLS (Cumulative Layout Shift)',
61
+ inpMs: 'INP (Interaction to Next Paint)',
62
+ fcpMs: 'FCP (First Contentful Paint)',
63
+ ttfbMs: 'TTFB (Time to First Byte)',
64
+ };
65
+ export function budgetLabel(key) {
66
+ return BUDGET_LABELS[key];
67
+ }
68
+ /** `2500` -> `<= 2500ms`, `0` -> `<= 0`, `0.1` -> `<= 0.1`. */
69
+ export function formatThreshold(key, value) {
70
+ const unit = BUDGET_UNITS[key];
71
+ if (unit === 'ms')
72
+ return `<= ${value}ms`;
73
+ return `<= ${value}`;
74
+ }
75
+ function normalizeKey(raw) {
76
+ return raw.toLowerCase().replace(/[_\-\s]/g, '');
77
+ }
78
+ /**
79
+ * Turn a parsed JSON object into a Budget, merged over the defaults.
80
+ *
81
+ * Unknown keys throw rather than being ignored: a typo'd `max_console_error`
82
+ * silently loosening a CI gate is exactly the failure mode budgets exist to
83
+ * prevent.
84
+ */
85
+ export function parseBudget(input, source = 'budget') {
86
+ if (input === null || typeof input !== 'object' || Array.isArray(input)) {
87
+ throw new Error(`Invalid ${source}: expected a JSON object of budget keys`);
88
+ }
89
+ const budget = { ...DEFAULT_BUDGET };
90
+ for (const [rawKey, rawValue] of Object.entries(input)) {
91
+ const key = KEY_ALIASES[normalizeKey(rawKey)];
92
+ if (!key) {
93
+ throw new Error(`Unknown budget key "${rawKey}" in ${source}. Known keys: ${Object.keys(DEFAULT_BUDGET).join(', ')}`);
94
+ }
95
+ if (rawValue === null) {
96
+ budget[key] = null;
97
+ continue;
98
+ }
99
+ if (typeof rawValue !== 'number' || !Number.isFinite(rawValue)) {
100
+ throw new Error(`Budget "${rawKey}" must be a number or null, got ${JSON.stringify(rawValue)}`);
101
+ }
102
+ if (rawValue < 0) {
103
+ throw new Error(`Budget "${rawKey}" must not be negative, got ${rawValue}`);
104
+ }
105
+ budget[key] = rawValue;
106
+ }
107
+ return budget;
108
+ }
109
+ /**
110
+ * Resolve `--budget`. The value is either inline JSON (starts with `{`) or a
111
+ * path to a JSON file. Omitted means DEFAULT_BUDGET.
112
+ */
113
+ export async function loadBudget(spec) {
114
+ if (spec === undefined || spec === '')
115
+ return { ...DEFAULT_BUDGET };
116
+ const trimmed = spec.trim();
117
+ if (trimmed.startsWith('{')) {
118
+ let parsed;
119
+ try {
120
+ parsed = JSON.parse(trimmed);
121
+ }
122
+ catch (err) {
123
+ throw new Error(`--budget is not valid JSON: ${err.message}`);
124
+ }
125
+ return parseBudget(parsed, 'inline --budget');
126
+ }
127
+ let text;
128
+ try {
129
+ text = await readFile(trimmed, 'utf8');
130
+ }
131
+ catch {
132
+ throw new Error(`Budget file not found or unreadable: ${trimmed}`);
133
+ }
134
+ let parsed;
135
+ try {
136
+ parsed = JSON.parse(text);
137
+ }
138
+ catch (err) {
139
+ throw new Error(`Budget file ${trimmed} is not valid JSON: ${err.message}`);
140
+ }
141
+ return parseBudget(parsed, trimmed);
142
+ }
143
+ //# sourceMappingURL=budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.js","sourceRoot":"","sources":["../../../src/report/budget.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The browser-facing half of the accessibility check: fetch the AX tree,
3
+ * sweep the DOM for tabindex (which the AX tree does not expose at all), and
4
+ * turn `ax-node:<id>` placeholders into real CSS selectors a human or an
5
+ * agent can act on. The rules themselves live in a11y.ts and stay pure.
6
+ */
7
+ import type { CdpClient } from '../browser/cdp.js';
8
+ import type { A11yFinding, AxNode, StructureNode } from './types.js';
9
+ /**
10
+ * Rewrites `ax-node:<id>` placeholder locators into real CSS selectors.
11
+ * Bounded: a page with 400 unlabelled buttons must not cost 400 CDP
12
+ * round-trips, and nobody reads the 400th finding anyway.
13
+ */
14
+ export declare function upgradeLocators(client: CdpClient, sessionId: string, findings: A11yFinding[], nodes: AxNode[]): Promise<A11yFinding[]>;
15
+ export interface A11yResult {
16
+ findings: A11yFinding[];
17
+ /**
18
+ * Flat signature of the same tree, for the run-to-run structural diff. It
19
+ * rides along here because the AX tree is already in hand — fetching it
20
+ * twice would double the cost of the most expensive collector.
21
+ */
22
+ structure: StructureNode[];
23
+ }
24
+ export declare function collectA11y(client: CdpClient, sessionId: string, notes: string[]): Promise<A11yResult>;
25
+ //# sourceMappingURL=collect-a11y.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collect-a11y.d.ts","sourceRoot":"","sources":["../../../src/report/collect-a11y.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAGnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAkB,aAAa,EAAE,MAAM,YAAY,CAAC;AAgGrF;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,WAAW,EAAE,EACvB,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,WAAW,EAAE,CAAC,CA2BxB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB;;;;OAIG;IACH,SAAS,EAAE,aAAa,EAAE,CAAC;CAC5B;AAED,wBAAsB,WAAW,CAC/B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,UAAU,CAAC,CAuCrB"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * The browser-facing half of the accessibility check: fetch the AX tree,
3
+ * sweep the DOM for tabindex (which the AX tree does not expose at all), and
4
+ * turn `ax-node:<id>` placeholders into real CSS selectors a human or an
5
+ * agent can act on. The rules themselves live in a11y.ts and stay pure.
6
+ */
7
+ import { evaluateJs } from '../browser/actions.js';
8
+ import { runA11yRules } from './a11y.js';
9
+ import { buildStructure } from './structure.js';
10
+ import { message, STEP_TIMEOUT_MS, withTimeout } from './util.js';
11
+ /** Most AX findings we will spend a DOM round-trip on to get a real selector. */
12
+ const MAX_LOCATOR_LOOKUPS = 60;
13
+ /** Builds a short, stable CSS selector for an element, from inside the page. */
14
+ const LOCATOR_FN = `function(){
15
+ var el = this;
16
+ if (!el || el.nodeType !== 1) return '';
17
+ var esc = function(s){ return window.CSS && CSS.escape ? CSS.escape(s) : s; };
18
+ if (el.id) return '#' + esc(el.id);
19
+ var parts = [], node = el, depth = 0;
20
+ while (node && node.nodeType === 1 && depth < 5) {
21
+ var part = node.tagName.toLowerCase();
22
+ if (node.id) { parts.unshift('#' + esc(node.id)); break; }
23
+ var parent = node.parentElement;
24
+ if (parent) {
25
+ var sibs = Array.prototype.filter.call(parent.children, function(c){ return c.tagName === node.tagName; });
26
+ if (sibs.length > 1) part += ':nth-of-type(' + (sibs.indexOf(node) + 1) + ')';
27
+ }
28
+ parts.unshift(part);
29
+ node = parent;
30
+ depth++;
31
+ }
32
+ return parts.join(' > ');
33
+ }`;
34
+ /** DOM sweep for tabindex — the AX tree does not expose it at all. */
35
+ const FOCUS_CANDIDATES_JS = `(function(){
36
+ try {
37
+ var esc = function(s){ return window.CSS && CSS.escape ? CSS.escape(s) : s; };
38
+ var loc = function(el){
39
+ if (el.id) return '#' + esc(el.id);
40
+ var parts = [], node = el, depth = 0;
41
+ while (node && node.nodeType === 1 && depth < 5) {
42
+ var part = node.tagName.toLowerCase();
43
+ if (node.id) { parts.unshift('#' + esc(node.id)); break; }
44
+ var parent = node.parentElement;
45
+ if (parent) {
46
+ var sibs = Array.prototype.filter.call(parent.children, function(c){ return c.tagName === node.tagName; });
47
+ if (sibs.length > 1) part += ':nth-of-type(' + (sibs.indexOf(node) + 1) + ')';
48
+ }
49
+ parts.unshift(part);
50
+ node = parent;
51
+ depth++;
52
+ }
53
+ return parts.join(' > ');
54
+ };
55
+ var out = [];
56
+ var els = document.querySelectorAll('[tabindex]');
57
+ for (var i = 0; i < els.length && out.length < 100; i++) {
58
+ var el = els[i];
59
+ var ti = parseInt(el.getAttribute('tabindex'), 10);
60
+ if (!(ti < 0)) continue;
61
+ var name = (el.getAttribute('aria-label') || el.getAttribute('title') || (el.textContent || '')).trim();
62
+ out.push({
63
+ tag: el.tagName.toLowerCase(),
64
+ role: (el.getAttribute('role') || '').toLowerCase(),
65
+ name: name ? name.slice(0, 120) : null,
66
+ tabindex: ti,
67
+ locator: loc(el)
68
+ });
69
+ }
70
+ return out;
71
+ } catch (e) { return []; }
72
+ })()`;
73
+ async function resolveLocator(client, sessionId, backendNodeId) {
74
+ try {
75
+ const resolved = await client.send('DOM.resolveNode', { backendNodeId }, sessionId);
76
+ const objectId = resolved.object?.objectId;
77
+ if (!objectId)
78
+ return null;
79
+ try {
80
+ const call = await client.send('Runtime.callFunctionOn', { functionDeclaration: LOCATOR_FN, objectId, returnByValue: true }, sessionId);
81
+ return call.result?.value || null;
82
+ }
83
+ finally {
84
+ await client.send('Runtime.releaseObject', { objectId }, sessionId).catch(() => { });
85
+ }
86
+ }
87
+ catch {
88
+ return null;
89
+ }
90
+ }
91
+ /**
92
+ * Rewrites `ax-node:<id>` placeholder locators into real CSS selectors.
93
+ * Bounded: a page with 400 unlabelled buttons must not cost 400 CDP
94
+ * round-trips, and nobody reads the 400th finding anyway.
95
+ */
96
+ export async function upgradeLocators(client, sessionId, findings, nodes) {
97
+ const backendByNodeId = new Map();
98
+ for (const n of nodes) {
99
+ if (n.backendDOMNodeId !== undefined)
100
+ backendByNodeId.set(String(n.nodeId), n.backendDOMNodeId);
101
+ }
102
+ let budget = MAX_LOCATOR_LOOKUPS;
103
+ const cache = new Map();
104
+ const out = [];
105
+ for (const finding of findings) {
106
+ if (!finding.locator.startsWith('ax-node:') || budget <= 0) {
107
+ out.push(finding);
108
+ continue;
109
+ }
110
+ const backendId = backendByNodeId.get(finding.locator.slice('ax-node:'.length));
111
+ if (backendId === undefined) {
112
+ out.push(finding);
113
+ continue;
114
+ }
115
+ if (!cache.has(backendId)) {
116
+ budget--;
117
+ cache.set(backendId, await resolveLocator(client, sessionId, backendId));
118
+ }
119
+ const selector = cache.get(backendId);
120
+ out.push(selector ? { ...finding, locator: selector } : finding);
121
+ }
122
+ return out;
123
+ }
124
+ export async function collectA11y(client, sessionId, notes) {
125
+ let nodes = [];
126
+ try {
127
+ const tree = await withTimeout(client.send('Accessibility.getFullAXTree', {}, sessionId), STEP_TIMEOUT_MS, 'accessibility tree');
128
+ nodes = tree.nodes ?? [];
129
+ }
130
+ catch (err) {
131
+ notes.push(`Accessibility tree unavailable: ${message(err)}`);
132
+ return { findings: [], structure: [] };
133
+ }
134
+ let focusCandidates = [];
135
+ try {
136
+ const raw = await withTimeout(evaluateJs(client, sessionId, FOCUS_CANDIDATES_JS), STEP_TIMEOUT_MS, 'tabindex sweep');
137
+ if (Array.isArray(raw))
138
+ focusCandidates = raw;
139
+ }
140
+ catch (err) {
141
+ notes.push(`Tabindex sweep skipped: ${message(err)}`);
142
+ }
143
+ const structure = buildStructure(nodes);
144
+ const findings = runA11yRules({ nodes, focusCandidates });
145
+ try {
146
+ const upgraded = await withTimeout(upgradeLocators(client, sessionId, findings, nodes), STEP_TIMEOUT_MS, 'locator resolution');
147
+ return { findings: upgraded, structure };
148
+ }
149
+ catch {
150
+ notes.push('Some accessibility locators could not be resolved to CSS selectors.');
151
+ return { findings, structure };
152
+ }
153
+ }
154
+ //# sourceMappingURL=collect-a11y.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collect-a11y.js","sourceRoot":"","sources":["../../../src/report/collect-a11y.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAElE,iFAAiF;AACjF,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAE/B,gFAAgF;AAChF,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;EAmBjB,CAAC;AAEH,sEAAsE;AACtE,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAqCvB,CAAC;AAEN,KAAK,UAAU,cAAc,CAC3B,MAAiB,EACjB,SAAiB,EACjB,aAAqB;IAErB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAChC,iBAAiB,EACjB,EAAE,aAAa,EAAE,EACjB,SAAS,CACV,CAAC;QACF,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;QAC3C,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAC5B,wBAAwB,EACxB,EAAE,mBAAmB,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,EAClE,SAAS,CACV,CAAC;YACF,OAAO,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,IAAI,CAAC;QACpC,CAAC;gBAAS,CAAC;YACT,MAAM,MAAM,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAE,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAiB,EACjB,SAAiB,EACjB,QAAuB,EACvB,KAAe;IAEf,MAAM,eAAe,GAAG,IAAI,GAAG,EAAkB,CAAC;IAClD,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC,gBAAgB,KAAK,SAAS;YAAE,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAClG,CAAC;IAED,IAAI,MAAM,GAAG,mBAAmB,CAAC;IACjC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;IAC/C,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;YAC3D,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAClB,SAAS;QACX,CAAC;QACD,MAAM,SAAS,GAAG,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QAChF,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAClB,SAAS;QACX,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1B,MAAM,EAAE,CAAC;YACT,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACtC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAYD,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAiB,EACjB,SAAiB,EACjB,KAAe;IAEf,IAAI,KAAK,GAAa,EAAE,CAAC;IACzB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,WAAW,CAC5B,MAAM,CAAC,IAAI,CAAsB,6BAA6B,EAAE,EAAE,EAAE,SAAS,CAAC,EAC9E,eAAe,EACf,oBAAoB,CACrB,CAAC;QACF,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,mCAAmC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC9D,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IACzC,CAAC;IAED,IAAI,eAAe,GAAqB,EAAE,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,WAAW,CAC3B,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,mBAAmB,CAAC,EAClD,eAAe,EACf,gBAAgB,CACjB,CAAC;QACF,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;YAAE,eAAe,GAAG,GAAuB,CAAC;IACpE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,2BAA2B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,YAAY,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,WAAW,CAChC,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,EACnD,eAAe,EACf,oBAAoB,CACrB,CAAC;QACF,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,KAAK,CAAC,IAAI,CAAC,qEAAqE,CAAC,CAAC;QAClF,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IACjC,CAAC;AACH,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Drives the browser and gathers the raw material for a report.
3
+ *
4
+ * Resilience is the design constraint: a page with no vitals, a site that
5
+ * never goes network-idle, a CSP that blocks our evaluate — each must
6
+ * degrade into a note in the report, never a hang and never a crash. Every
7
+ * collector is individually timed out and individually try/caught, and this
8
+ * function always returns a CaptureData.
9
+ */
10
+ import type { CdpClient } from '../browser/cdp.js';
11
+ import type { EvidenceRecorderOptions } from './evidence.js';
12
+ import type { CaptureData, RequestEntry } from './types.js';
13
+ export interface CollectOptions {
14
+ url: string;
15
+ /** A CSS selector to wait for, or a number of milliseconds. */
16
+ wait?: string | number;
17
+ /** Device names from `listDevices()` to add to the screenshot matrix. */
18
+ devices?: string[];
19
+ vitalsWaitMs?: number;
20
+ loadTimeoutMs?: number;
21
+ screenshotDir?: string;
22
+ fullPage?: boolean;
23
+ /** Record screencast frames for the evidence timeline (RIG-11). */
24
+ record?: boolean;
25
+ recordOptions?: EvidenceRecorderOptions;
26
+ }
27
+ interface FailureRecord {
28
+ errorText?: string;
29
+ blockedReason?: string;
30
+ canceled?: boolean;
31
+ }
32
+ export interface CapturedRequestLike {
33
+ id: string;
34
+ url: string;
35
+ method: string;
36
+ status?: number;
37
+ mimeType?: string;
38
+ startTime: number;
39
+ endTime?: number;
40
+ encodedSize?: number;
41
+ }
42
+ export declare function toRequestEntries(captured: CapturedRequestLike[], failures: Map<string, FailureRecord>, clockOffsetMs?: number): RequestEntry[];
43
+ export declare function collect(client: CdpClient, sessionId: string, options: CollectOptions): Promise<CaptureData>;
44
+ export {};
45
+ //# sourceMappingURL=collect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collect.d.ts","sourceRoot":"","sources":["../../../src/report/collect.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAmBnD,OAAO,KAAK,EAAoB,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAE/E,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAA0B,MAAM,YAAY,CAAC;AAGpF,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mEAAmE;IACnE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,uBAAuB,CAAC;CACzC;AAWD,UAAU,aAAa;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAkDD,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EACpC,aAAa,CAAC,EAAE,MAAM,GACrB,YAAY,EAAE,CAuBhB;AA2GD,wBAAsB,OAAO,CAC3B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,WAAW,CAAC,CAgJtB"}