@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,102 @@
1
+ /**
2
+ * `monobrowse report <url>` — open a page, measure it, judge it against a
3
+ * budget, and leave behind one self-contained HTML file plus a sibling JSON.
4
+ *
5
+ * collect.ts (drive the browser) -> analyze.ts (a11y + budgets -> verdict)
6
+ * -> history/trend/diff (what changed since last time) -> render.ts (HTML).
7
+ * This module is the seam that wires them together and writes the two files.
8
+ */
9
+ import type { CdpClient } from '../browser/cdp.js';
10
+ import type { CollectOptions } from './collect.js';
11
+ import { type FlakeReport } from './flake.js';
12
+ import { type HistoryRun } from './history.js';
13
+ import type { Budget, Report } from './types.js';
14
+ export * from './a11y.js';
15
+ export * from './analyze.js';
16
+ export * from './budget.js';
17
+ export * from './collect.js';
18
+ export * from './collect-a11y.js';
19
+ export * from './evidence.js';
20
+ export * from './flake.js';
21
+ export * from './history.js';
22
+ export * from './pixel-diff.js';
23
+ export * from './png.js';
24
+ export * from './render.js';
25
+ export * from './run-diff.js';
26
+ export * from './structure.js';
27
+ export * from './trend.js';
28
+ export * from './types.js';
29
+ /** Prior runs a trend is charted over. Older runs stay on disk, off the chart. */
30
+ export declare const DEFAULT_TREND_WINDOW = 10;
31
+ export interface RunReportOptions extends CollectOptions {
32
+ /** Output path: a `.html` file, or a directory to drop the default name in. */
33
+ out?: string;
34
+ /** Budget file path or inline JSON. Omitted means DEFAULT_BUDGET. */
35
+ budget?: string | Budget;
36
+ cwd?: string;
37
+ /** Persist this run and compare against previous ones. Default true. */
38
+ history?: boolean;
39
+ /** Runs kept per URL. Default DEFAULT_HISTORY_MAX. */
40
+ historyMax?: number;
41
+ /** Root of the history store. Default `~/.monomind/browser-reports`. */
42
+ historyDir?: string;
43
+ /** Prior runs charted. Default DEFAULT_TREND_WINDOW. */
44
+ trendWindow?: number;
45
+ }
46
+ export interface ReportResult {
47
+ report: Report;
48
+ htmlPath: string;
49
+ jsonPath: string;
50
+ summary: string;
51
+ /** Present when the run was saved to the history store. */
52
+ historyDir?: string;
53
+ /** Present only for a `--repeat` run (RIG-14); see RepeatResult. */
54
+ flake?: FlakeReport;
55
+ }
56
+ /**
57
+ * Resolve `--out` into an absolute .html path. A path that is an existing
58
+ * directory, or that ends in a separator, gets the generated filename
59
+ * appended — `--out ./reports` should not silently produce a file called
60
+ * `reports`.
61
+ */
62
+ export declare function resolveOutPath(out: string | undefined, url: string, capturedAt: string, cwd: string): Promise<string>;
63
+ /**
64
+ * The JSON sibling drops the base64 image payloads — they are megabytes of
65
+ * noise for anything reading this programmatically, and the HTML already
66
+ * carries them inline. `path` still points at the PNG on disk. The pixel
67
+ * diff's highlight image and the evidence frames go the same way: every
68
+ * measurement survives, only the pixels are dropped.
69
+ */
70
+ export declare function toJsonReport(report: Report): Record<string, unknown>;
71
+ export declare function writeReportFiles(report: Report, htmlPath: string, extras?: {
72
+ flake?: FlakeReport;
73
+ }): Promise<{
74
+ htmlPath: string;
75
+ jsonPath: string;
76
+ }>;
77
+ /** One run: collect, judge, compare against history, write the two files. */
78
+ export declare function runReport(client: CdpClient, sessionId: string, options: RunReportOptions): Promise<ReportResult>;
79
+ export interface RepeatResult extends ReportResult {
80
+ flake: FlakeReport;
81
+ /** Every run, in order. `report` is the last of them. */
82
+ reports: Report[];
83
+ }
84
+ /**
85
+ * `--repeat N`: run the same URL N times and judge the set (RIG-14).
86
+ *
87
+ * Only the last run is written out in full — N runs' worth of inlined
88
+ * screenshots is not something anyone wants on disk — but the flake analysis
89
+ * covers all of them, and it is the flake verdict that decides the exit code.
90
+ * A check that passed three times and failed twice must not exit 0.
91
+ */
92
+ export declare function runReportRepeated(client: CdpClient, sessionId: string, options: RunReportOptions & {
93
+ repeat: number;
94
+ }): Promise<RepeatResult>;
95
+ /** `--history <url>`: the stored runs for a URL, oldest first. */
96
+ export declare function readHistory(url: string, options?: {
97
+ historyDir?: string;
98
+ }): Promise<{
99
+ dir: string;
100
+ runs: HistoryRun[];
101
+ }>;
102
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/report/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,216 @@
1
+ /**
2
+ * `monobrowse report <url>` — open a page, measure it, judge it against a
3
+ * budget, and leave behind one self-contained HTML file plus a sibling JSON.
4
+ *
5
+ * collect.ts (drive the browser) -> analyze.ts (a11y + budgets -> verdict)
6
+ * -> history/trend/diff (what changed since last time) -> render.ts (HTML).
7
+ * This module is the seam that wires them together and writes the two files.
8
+ */
9
+ import { mkdir, stat, writeFile } from 'node:fs/promises';
10
+ import { dirname, isAbsolute, join, resolve } from 'node:path';
11
+ import { buildReport, summarizeVerdict } from './analyze.js';
12
+ import { loadBudget } from './budget.js';
13
+ import { collect } from './collect.js';
14
+ import { buildEvidence } from './evidence.js';
15
+ import { analyzeFlake, summarizeFlake } from './flake.js';
16
+ import { DEFAULT_HISTORY_MAX, historyDirFor, historyRoot, listRuns, saveRun, } from './history.js';
17
+ import { renderHtml } from './render.js';
18
+ import { buildRunDiff } from './run-diff.js';
19
+ import { buildTrend } from './trend.js';
20
+ export * from './a11y.js';
21
+ export * from './analyze.js';
22
+ export * from './budget.js';
23
+ export * from './collect.js';
24
+ export * from './collect-a11y.js';
25
+ export * from './evidence.js';
26
+ export * from './flake.js';
27
+ export * from './history.js';
28
+ export * from './pixel-diff.js';
29
+ export * from './png.js';
30
+ export * from './render.js';
31
+ export * from './run-diff.js';
32
+ export * from './structure.js';
33
+ export * from './trend.js';
34
+ export * from './types.js';
35
+ /** Prior runs a trend is charted over. Older runs stay on disk, off the chart. */
36
+ export const DEFAULT_TREND_WINDOW = 10;
37
+ function slugFor(url) {
38
+ try {
39
+ const parsed = new URL(url);
40
+ const path = parsed.pathname.replace(/\/+$/, '').replace(/[^a-z0-9]+/gi, '-');
41
+ return `${parsed.hostname}${path}`.replace(/-+/g, '-').replace(/^-|-$/g, '').toLowerCase();
42
+ }
43
+ catch {
44
+ return (url
45
+ .replace(/[^a-z0-9]+/gi, '-')
46
+ .replace(/^-|-$/g, '')
47
+ .toLowerCase() || 'page');
48
+ }
49
+ }
50
+ function timestamp(iso) {
51
+ return iso.replace(/[-:]/g, '').replace(/\.\d+Z$/, 'Z');
52
+ }
53
+ /**
54
+ * Resolve `--out` into an absolute .html path. A path that is an existing
55
+ * directory, or that ends in a separator, gets the generated filename
56
+ * appended — `--out ./reports` should not silently produce a file called
57
+ * `reports`.
58
+ */
59
+ export async function resolveOutPath(out, url, capturedAt, cwd) {
60
+ const defaultName = `monobrowse-report-${slugFor(url)}-${timestamp(capturedAt)}.html`;
61
+ if (!out)
62
+ return join(cwd, defaultName);
63
+ const abs = isAbsolute(out) ? out : resolve(cwd, out);
64
+ if (/[\\/]$/.test(out))
65
+ return join(abs, defaultName);
66
+ const isDir = await stat(abs)
67
+ .then((s) => s.isDirectory())
68
+ .catch(() => false);
69
+ if (isDir)
70
+ return join(abs, defaultName);
71
+ return abs.toLowerCase().endsWith('.html') || abs.toLowerCase().endsWith('.htm')
72
+ ? abs
73
+ : `${abs}.html`;
74
+ }
75
+ /**
76
+ * The JSON sibling drops the base64 image payloads — they are megabytes of
77
+ * noise for anything reading this programmatically, and the HTML already
78
+ * carries them inline. `path` still points at the PNG on disk. The pixel
79
+ * diff's highlight image and the evidence frames go the same way: every
80
+ * measurement survives, only the pixels are dropped.
81
+ */
82
+ export function toJsonReport(report) {
83
+ const { screenshots, recording, diff, evidence, ...rest } = report;
84
+ void recording;
85
+ return {
86
+ ...rest,
87
+ screenshots: screenshots.map(({ label, width, height, path }) => ({
88
+ label,
89
+ width,
90
+ height,
91
+ path,
92
+ })),
93
+ ...(diff
94
+ ? {
95
+ diff: {
96
+ ...diff,
97
+ pixels: diff.pixels ? { ...diff.pixels, diffDataUrl: undefined } : undefined,
98
+ },
99
+ }
100
+ : {}),
101
+ ...(evidence
102
+ ? {
103
+ evidence: {
104
+ ...evidence,
105
+ frames: evidence.frames.map(({ offsetMs, bytes }) => ({ offsetMs, bytes })),
106
+ },
107
+ }
108
+ : {}),
109
+ };
110
+ }
111
+ export async function writeReportFiles(report, htmlPath, extras = {}) {
112
+ const jsonPath = `${htmlPath.replace(/\.html?$/i, '')}.json`;
113
+ await mkdir(dirname(htmlPath), { recursive: true });
114
+ await writeFile(htmlPath, renderHtml(report, extras), 'utf8');
115
+ const json = extras.flake
116
+ ? { ...toJsonReport(report), flake: extras.flake }
117
+ : toJsonReport(report);
118
+ await writeFile(jsonPath, `${JSON.stringify(json, null, 2)}\n`, 'utf8');
119
+ return { htmlPath, jsonPath };
120
+ }
121
+ /**
122
+ * Attach the trend and the diff, then persist the run.
123
+ *
124
+ * Order matters: history is read BEFORE the run is saved, so a run never
125
+ * trends or diffs against itself. A failure anywhere in here becomes a note
126
+ * on the report rather than an error — an unwritable home directory should
127
+ * cost you the trend section, not the report.
128
+ */
129
+ async function applyHistory(report, options) {
130
+ if (options.history === false)
131
+ return undefined;
132
+ const root = options.historyDir ?? historyRoot();
133
+ const dir = historyDirFor(report.url, root);
134
+ try {
135
+ const previous = await listRuns(dir);
136
+ const window = options.trendWindow ?? DEFAULT_TREND_WINDOW;
137
+ report.trend = buildTrend(report, previous.slice(-window));
138
+ report.diff = await buildRunDiff(dir, previous.at(-1), report);
139
+ await saveRun(report, { root, max: options.historyMax ?? DEFAULT_HISTORY_MAX });
140
+ return dir;
141
+ }
142
+ catch (err) {
143
+ report.notes.push(`Run history unavailable (${err.message}) — no trend or diff for this run.`);
144
+ return undefined;
145
+ }
146
+ }
147
+ /** Turn the recorder's raw frames into the evidence block, when warranted. */
148
+ function applyEvidence(report, data) {
149
+ const recording = data.recording;
150
+ if (!recording)
151
+ return;
152
+ if (report.verdict !== 'fail' && !recording.requested)
153
+ return;
154
+ report.evidence = buildEvidence({
155
+ reason: report.verdict === 'fail' ? 'budget-failure' : 'requested',
156
+ startedAtMs: recording.startedAtMs,
157
+ frames: recording.frames,
158
+ bufferDropped: recording.droppedFrames,
159
+ console: report.console,
160
+ pageErrors: report.pageErrors,
161
+ requests: report.requests,
162
+ failures: report.failures,
163
+ });
164
+ }
165
+ async function resolveBudget(options) {
166
+ return options.budget && typeof options.budget === 'object'
167
+ ? options.budget
168
+ : await loadBudget(options.budget);
169
+ }
170
+ /** One run: collect, judge, compare against history, write the two files. */
171
+ export async function runReport(client, sessionId, options) {
172
+ const budget = await resolveBudget(options);
173
+ const data = await collect(client, sessionId, options);
174
+ const report = buildReport(data, budget);
175
+ applyEvidence(report, data);
176
+ const historyDir = await applyHistory(report, options);
177
+ // Working material, not report content — and megabytes of it.
178
+ report.recording = undefined;
179
+ const htmlPath = await resolveOutPath(options.out, options.url, data.capturedAt, options.cwd ?? process.cwd());
180
+ const paths = await writeReportFiles(report, htmlPath);
181
+ return { report, ...paths, summary: summarizeVerdict(report), historyDir };
182
+ }
183
+ /**
184
+ * `--repeat N`: run the same URL N times and judge the set (RIG-14).
185
+ *
186
+ * Only the last run is written out in full — N runs' worth of inlined
187
+ * screenshots is not something anyone wants on disk — but the flake analysis
188
+ * covers all of them, and it is the flake verdict that decides the exit code.
189
+ * A check that passed three times and failed twice must not exit 0.
190
+ */
191
+ export async function runReportRepeated(client, sessionId, options) {
192
+ const times = Math.max(1, Math.floor(options.repeat));
193
+ const budget = await resolveBudget(options);
194
+ const reports = [];
195
+ for (let i = 0; i < times; i++) {
196
+ const data = await collect(client, sessionId, options);
197
+ const report = buildReport(data, budget);
198
+ applyEvidence(report, data);
199
+ report.recording = undefined;
200
+ reports.push(report);
201
+ }
202
+ const flake = analyzeFlake(reports);
203
+ const report = reports[reports.length - 1];
204
+ // Only the run we keep is persisted: writing N history entries for one
205
+ // command would let a single `--repeat 20` evict the whole trend window.
206
+ const historyDir = await applyHistory(report, options);
207
+ const htmlPath = await resolveOutPath(options.out, options.url, report.capturedAt, options.cwd ?? process.cwd());
208
+ const paths = await writeReportFiles(report, htmlPath, { flake });
209
+ return { report, reports, flake, ...paths, summary: summarizeFlake(flake), historyDir };
210
+ }
211
+ /** `--history <url>`: the stored runs for a URL, oldest first. */
212
+ export async function readHistory(url, options = {}) {
213
+ const dir = historyDirFor(url, options.historyDir ?? historyRoot());
214
+ return { dir, runs: await listRuns(dir) };
215
+ }
216
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/report/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Pixel diff between two screenshots (RIG-10), with no image dependency —
3
+ * png.ts decodes and re-encodes using node's own zlib.
4
+ *
5
+ * Two design choices worth stating:
6
+ *
7
+ * - A per-channel tolerance, not exact equality. Chrome's rasteriser is not
8
+ * bit-deterministic across runs (font hinting, GPU vs. software paths), so
9
+ * an exact compare reports 4% of every screenshot as "changed" and the
10
+ * number becomes noise nobody reads.
11
+ * - Differing dimensions are a result, not an error. A page that grew 200px
12
+ * taller is exactly the regression this is for, so we compare the
13
+ * overlapping region, count the rest as changed, and say so.
14
+ */
15
+ import type { PixelDiff } from './types.js';
16
+ export interface PixelDiffOptions {
17
+ threshold?: number;
18
+ maxPixels?: number;
19
+ /** Set false to skip building the highlight image (counts only). */
20
+ renderImage?: boolean;
21
+ }
22
+ /**
23
+ * Compare two PNGs. Never throws for image-shaped reasons — an undecodable
24
+ * screenshot produces a result carrying `note` and no counts, because a
25
+ * report that renders minus one section beats a report that fails to build.
26
+ */
27
+ export declare function pixelDiff(previousPng: Uint8Array, currentPng: Uint8Array, options?: PixelDiffOptions): PixelDiff;
28
+ /** One line for a CI log. */
29
+ export declare function summarizePixelDiff(diff: PixelDiff): string;
30
+ //# sourceMappingURL=pixel-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pixel-diff.d.ts","sourceRoot":"","sources":["../../../src/report/pixel-diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAW5C,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAwED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,WAAW,EAAE,UAAU,EACvB,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,gBAAqB,GAC7B,SAAS,CAwEX;AAED,6BAA6B;AAC7B,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAQ1D"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Pixel diff between two screenshots (RIG-10), with no image dependency —
3
+ * png.ts decodes and re-encodes using node's own zlib.
4
+ *
5
+ * Two design choices worth stating:
6
+ *
7
+ * - A per-channel tolerance, not exact equality. Chrome's rasteriser is not
8
+ * bit-deterministic across runs (font hinting, GPU vs. software paths), so
9
+ * an exact compare reports 4% of every screenshot as "changed" and the
10
+ * number becomes noise nobody reads.
11
+ * - Differing dimensions are a result, not an error. A page that grew 200px
12
+ * taller is exactly the regression this is for, so we compare the
13
+ * overlapping region, count the rest as changed, and say so.
14
+ */
15
+ import { decodePng, encodePng, pngToDataUrl } from './png.js';
16
+ /** Per-channel delta below which two pixels are "the same". */
17
+ const DEFAULT_THRESHOLD = 16;
18
+ /**
19
+ * Cap on the highlight image, in pixels. A full-page shot of a long article
20
+ * can be 1440x20000; inlining that as a data URI would add ~20MB to a report
21
+ * that is supposed to stay openable.
22
+ */
23
+ const DEFAULT_MAX_PIXELS = 1_400_000;
24
+ function changedAt(a, ai, b, bi, threshold) {
25
+ return (Math.abs(a[ai] - b[bi]) > threshold ||
26
+ Math.abs(a[ai + 1] - b[bi + 1]) > threshold ||
27
+ Math.abs(a[ai + 2] - b[bi + 2]) > threshold ||
28
+ Math.abs(a[ai + 3] - b[bi + 3]) > threshold);
29
+ }
30
+ /**
31
+ * Build the highlight image: the current screenshot faded towards white so it
32
+ * reads as context, with changed pixels painted a saturated magenta. Scaled
33
+ * down by an integer factor when the shot is large, ORing the change mask so
34
+ * a one-pixel-wide change survives the downscale instead of being averaged
35
+ * into invisibility.
36
+ */
37
+ function renderHighlight(current, mask, maxPixels) {
38
+ const { width, height, data } = current;
39
+ const scale = Math.max(1, Math.ceil(Math.sqrt((width * height) / maxPixels)));
40
+ const outW = Math.max(1, Math.ceil(width / scale));
41
+ const outH = Math.max(1, Math.ceil(height / scale));
42
+ const out = new Uint8Array(outW * outH * 4);
43
+ for (let oy = 0; oy < outH; oy++) {
44
+ for (let ox = 0; ox < outW; ox++) {
45
+ let r = 0;
46
+ let g = 0;
47
+ let b = 0;
48
+ let n = 0;
49
+ let hit = false;
50
+ for (let dy = 0; dy < scale; dy++) {
51
+ const y = oy * scale + dy;
52
+ if (y >= height)
53
+ break;
54
+ for (let dx = 0; dx < scale; dx++) {
55
+ const x = ox * scale + dx;
56
+ if (x >= width)
57
+ break;
58
+ const i = (y * width + x) * 4;
59
+ r += data[i];
60
+ g += data[i + 1];
61
+ b += data[i + 2];
62
+ n++;
63
+ if (mask[y * width + x])
64
+ hit = true;
65
+ }
66
+ }
67
+ const o = (oy * outW + ox) * 4;
68
+ if (!n) {
69
+ out[o + 3] = 255;
70
+ continue;
71
+ }
72
+ if (hit) {
73
+ out[o] = 214;
74
+ out[o + 1] = 31;
75
+ out[o + 2] = 105;
76
+ }
77
+ else {
78
+ // Fade to white: keeps the layout legible without competing with the
79
+ // magenta, and compresses far better than the original.
80
+ out[o] = Math.round(255 - (255 - r / n) * 0.28);
81
+ out[o + 1] = Math.round(255 - (255 - g / n) * 0.28);
82
+ out[o + 2] = Math.round(255 - (255 - b / n) * 0.28);
83
+ }
84
+ out[o + 3] = 255;
85
+ }
86
+ }
87
+ return { image: { width: outW, height: outH, data: out }, scale };
88
+ }
89
+ /**
90
+ * Compare two PNGs. Never throws for image-shaped reasons — an undecodable
91
+ * screenshot produces a result carrying `note` and no counts, because a
92
+ * report that renders minus one section beats a report that fails to build.
93
+ */
94
+ export function pixelDiff(previousPng, currentPng, options = {}) {
95
+ const threshold = options.threshold ?? DEFAULT_THRESHOLD;
96
+ const maxPixels = options.maxPixels ?? DEFAULT_MAX_PIXELS;
97
+ let prev;
98
+ let curr;
99
+ try {
100
+ prev = decodePng(previousPng);
101
+ curr = decodePng(currentPng);
102
+ }
103
+ catch (err) {
104
+ return {
105
+ comparable: false,
106
+ note: `Pixel diff skipped: ${err.message}`,
107
+ changedPixels: 0,
108
+ totalPixels: 0,
109
+ changedPercent: 0,
110
+ previousSize: null,
111
+ currentSize: null,
112
+ sizeChanged: false,
113
+ };
114
+ }
115
+ const overlapW = Math.min(prev.width, curr.width);
116
+ const overlapH = Math.min(prev.height, curr.height);
117
+ const sizeChanged = prev.width !== curr.width || prev.height !== curr.height;
118
+ // Denominator is the union, not the overlap: if the page doubled in height,
119
+ // "0.1% of pixels changed" would be a lie told by a small denominator.
120
+ const totalPixels = Math.max(prev.width * prev.height, curr.width * curr.height);
121
+ const mask = new Uint8Array(curr.width * curr.height);
122
+ let changed = 0;
123
+ for (let y = 0; y < curr.height; y++) {
124
+ for (let x = 0; x < curr.width; x++) {
125
+ const ci = (y * curr.width + x) * 4;
126
+ if (x >= overlapW || y >= overlapH) {
127
+ // Outside the overlap there is nothing to compare against: the pixel
128
+ // is new by definition.
129
+ mask[y * curr.width + x] = 1;
130
+ changed++;
131
+ continue;
132
+ }
133
+ const pi = (y * prev.width + x) * 4;
134
+ if (changedAt(prev.data, pi, curr.data, ci, threshold)) {
135
+ mask[y * curr.width + x] = 1;
136
+ changed++;
137
+ }
138
+ }
139
+ }
140
+ // Pixels the previous shot had and this one does not are changes too.
141
+ changed += Math.max(0, prev.width * prev.height - overlapW * overlapH);
142
+ const result = {
143
+ comparable: true,
144
+ changedPixels: changed,
145
+ totalPixels,
146
+ changedPercent: totalPixels ? (changed / totalPixels) * 100 : 0,
147
+ previousSize: { width: prev.width, height: prev.height },
148
+ currentSize: { width: curr.width, height: curr.height },
149
+ sizeChanged,
150
+ };
151
+ if (options.renderImage !== false && changed > 0) {
152
+ try {
153
+ const { image, scale } = renderHighlight(curr, mask, maxPixels);
154
+ result.diffDataUrl = pngToDataUrl(encodePng(image));
155
+ if (scale > 1)
156
+ result.scale = scale;
157
+ }
158
+ catch (err) {
159
+ result.note = `Highlight image not rendered: ${err.message}`;
160
+ }
161
+ }
162
+ return result;
163
+ }
164
+ /** One line for a CI log. */
165
+ export function summarizePixelDiff(diff) {
166
+ if (!diff.comparable)
167
+ return diff.note ?? 'pixel diff unavailable';
168
+ const pct = diff.changedPercent;
169
+ const shown = pct === 0 ? '0' : pct < 0.01 ? '<0.01' : pct.toFixed(2);
170
+ const size = diff.sizeChanged
171
+ ? ` (size ${diff.previousSize?.width}x${diff.previousSize?.height} -> ${diff.currentSize?.width}x${diff.currentSize?.height})`
172
+ : '';
173
+ return `${shown}% of pixels changed${size}`;
174
+ }
175
+ //# sourceMappingURL=pixel-diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pixel-diff.js","sourceRoot":"","sources":["../../../src/report/pixel-diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * A minimal PNG decoder and encoder built on node's own `zlib`.
3
+ *
4
+ * This exists so the pixel diff (RIG-10) can compare two screenshots without
5
+ * adding an image dependency to a package whose whole point is to be a small
6
+ * self-contained CDP client. PNG is simple enough to justify it: the format
7
+ * is a chunk list wrapping one zlib stream, and node ships the zlib.
8
+ *
9
+ * Scope is deliberately narrow — what `Page.captureScreenshot` actually
10
+ * emits. Non-interlaced, bit depth 8 (16 is accepted by taking the high
11
+ * byte), colour types 0/2/3/4/6. Anything else throws a message that names
12
+ * what it saw, so the caller can degrade to "pixel diff unavailable" instead
13
+ * of rendering a wrong picture.
14
+ */
15
+ export interface RgbaImage {
16
+ width: number;
17
+ height: number;
18
+ /** Row-major RGBA, 4 bytes per pixel, length === width * height * 4. */
19
+ data: Uint8Array;
20
+ }
21
+ export declare function crc32(buf: Uint8Array): number;
22
+ export declare function decodePng(input: Uint8Array): RgbaImage;
23
+ /** Encode RGBA bytes as a non-interlaced, 8-bit truecolour-with-alpha PNG. */
24
+ export declare function encodePng(image: RgbaImage): Buffer;
25
+ /** `data:image/png;base64,...` -> bytes. Accepts a bare base64 payload too. */
26
+ export declare function pngFromDataUrl(dataUrl: string): Uint8Array;
27
+ export declare function pngToDataUrl(png: Uint8Array): string;
28
+ //# sourceMappingURL=png.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"png.d.ts","sourceRoot":"","sources":["../../../src/report/png.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,IAAI,EAAE,UAAU,CAAC;CAClB;AAgBD,wBAAgB,KAAK,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAI7C;AAoID,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,CAwDtD;AAgBD,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CA6BlD;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAI1D;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAEpD"}