@monoes/monobrowse 1.0.11 → 1.0.13

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 (380) hide show
  1. package/dist/src/__tests__/adapters.test.js +5 -2
  2. package/dist/src/__tests__/adapters.test.js.map +1 -1
  3. package/dist/src/__tests__/batch-eval-parsing.test.js +4 -2
  4. package/dist/src/__tests__/batch-eval-parsing.test.js.map +1 -1
  5. package/dist/src/__tests__/box-model.test.js +9 -5
  6. package/dist/src/__tests__/box-model.test.js.map +1 -1
  7. package/dist/src/__tests__/browser-launch.test.d.ts +10 -0
  8. package/dist/src/__tests__/browser-launch.test.d.ts.map +1 -1
  9. package/dist/src/__tests__/browser-launch.test.js +17 -10
  10. package/dist/src/__tests__/browser-launch.test.js.map +1 -1
  11. package/dist/src/__tests__/cdp-client.test.js +9 -3
  12. package/dist/src/__tests__/cdp-client.test.js.map +1 -1
  13. package/dist/src/__tests__/close-browser.test.d.ts +13 -0
  14. package/dist/src/__tests__/close-browser.test.d.ts.map +1 -1
  15. package/dist/src/__tests__/close-browser.test.js +5 -5
  16. package/dist/src/__tests__/close-browser.test.js.map +1 -1
  17. package/dist/src/__tests__/console-log.test.js +17 -6
  18. package/dist/src/__tests__/console-log.test.js.map +1 -1
  19. package/dist/src/__tests__/find.test.js +26 -6
  20. package/dist/src/__tests__/find.test.js.map +1 -1
  21. package/dist/src/__tests__/frame-command.test.js +9 -3
  22. package/dist/src/__tests__/frame-command.test.js.map +1 -1
  23. package/dist/src/__tests__/open-url-navigate-error.test.js +1 -3
  24. package/dist/src/__tests__/open-url-navigate-error.test.js.map +1 -1
  25. package/dist/src/__tests__/output.test.js +1 -1
  26. package/dist/src/__tests__/output.test.js.map +1 -1
  27. package/dist/src/__tests__/profiler-heap.test.d.ts +2 -0
  28. package/dist/src/__tests__/profiler-heap.test.d.ts.map +1 -0
  29. package/dist/src/__tests__/profiler-heap.test.js +154 -0
  30. package/dist/src/__tests__/profiler-heap.test.js.map +1 -0
  31. package/dist/src/__tests__/reap-idle-browser.test.d.ts +15 -0
  32. package/dist/src/__tests__/reap-idle-browser.test.d.ts.map +1 -0
  33. package/dist/src/__tests__/reap-idle-browser.test.js +238 -0
  34. package/dist/src/__tests__/reap-idle-browser.test.js.map +1 -0
  35. package/dist/src/__tests__/ref-cache.test.js +18 -10
  36. package/dist/src/__tests__/ref-cache.test.js.map +1 -1
  37. package/dist/src/__tests__/report-a11y.test.d.ts +2 -0
  38. package/dist/src/__tests__/report-a11y.test.d.ts.map +1 -0
  39. package/dist/src/__tests__/report-a11y.test.js +147 -0
  40. package/dist/src/__tests__/report-a11y.test.js.map +1 -0
  41. package/dist/src/__tests__/report-analyze.test.d.ts +2 -0
  42. package/dist/src/__tests__/report-analyze.test.d.ts.map +1 -0
  43. package/dist/src/__tests__/report-analyze.test.js +157 -0
  44. package/dist/src/__tests__/report-analyze.test.js.map +1 -0
  45. package/dist/src/__tests__/report-budget.test.d.ts +2 -0
  46. package/dist/src/__tests__/report-budget.test.d.ts.map +1 -0
  47. package/dist/src/__tests__/report-budget.test.js +80 -0
  48. package/dist/src/__tests__/report-budget.test.js.map +1 -0
  49. package/dist/src/__tests__/report-diff.test.d.ts +2 -0
  50. package/dist/src/__tests__/report-diff.test.d.ts.map +1 -0
  51. package/dist/src/__tests__/report-diff.test.js +231 -0
  52. package/dist/src/__tests__/report-diff.test.js.map +1 -0
  53. package/dist/src/__tests__/report-evidence.test.d.ts +2 -0
  54. package/dist/src/__tests__/report-evidence.test.d.ts.map +1 -0
  55. package/dist/src/__tests__/report-evidence.test.js +214 -0
  56. package/dist/src/__tests__/report-evidence.test.js.map +1 -0
  57. package/dist/src/__tests__/report-flake.test.d.ts +2 -0
  58. package/dist/src/__tests__/report-flake.test.d.ts.map +1 -0
  59. package/dist/src/__tests__/report-flake.test.js +182 -0
  60. package/dist/src/__tests__/report-flake.test.js.map +1 -0
  61. package/dist/src/__tests__/report-history.test.d.ts +2 -0
  62. package/dist/src/__tests__/report-history.test.d.ts.map +1 -0
  63. package/dist/src/__tests__/report-history.test.js +229 -0
  64. package/dist/src/__tests__/report-history.test.js.map +1 -0
  65. package/dist/src/__tests__/report-output.test.d.ts +2 -0
  66. package/dist/src/__tests__/report-output.test.d.ts.map +1 -0
  67. package/dist/src/__tests__/report-output.test.js +169 -0
  68. package/dist/src/__tests__/report-output.test.js.map +1 -0
  69. package/dist/src/__tests__/report-png.test.d.ts +2 -0
  70. package/dist/src/__tests__/report-png.test.d.ts.map +1 -0
  71. package/dist/src/__tests__/report-png.test.js +84 -0
  72. package/dist/src/__tests__/report-png.test.js.map +1 -0
  73. package/dist/src/__tests__/report-render-extras.test.d.ts +2 -0
  74. package/dist/src/__tests__/report-render-extras.test.d.ts.map +1 -0
  75. package/dist/src/__tests__/report-render-extras.test.js +285 -0
  76. package/dist/src/__tests__/report-render-extras.test.js.map +1 -0
  77. package/dist/src/__tests__/report-render.test.d.ts +2 -0
  78. package/dist/src/__tests__/report-render.test.d.ts.map +1 -0
  79. package/dist/src/__tests__/report-render.test.js +143 -0
  80. package/dist/src/__tests__/report-render.test.js.map +1 -0
  81. package/dist/src/__tests__/report-run.test.d.ts +2 -0
  82. package/dist/src/__tests__/report-run.test.d.ts.map +1 -0
  83. package/dist/src/__tests__/report-run.test.js +234 -0
  84. package/dist/src/__tests__/report-run.test.js.map +1 -0
  85. package/dist/src/__tests__/session-state.test.d.ts +8 -0
  86. package/dist/src/__tests__/session-state.test.d.ts.map +1 -1
  87. package/dist/src/__tests__/session-state.test.js +10 -10
  88. package/dist/src/__tests__/session-state.test.js.map +1 -1
  89. package/dist/src/__tests__/snapshot.test.js +44 -14
  90. package/dist/src/__tests__/snapshot.test.js.map +1 -1
  91. package/dist/src/__tests__/storage-eval.test.js +14 -6
  92. package/dist/src/__tests__/storage-eval.test.js.map +1 -1
  93. package/dist/src/__tests__/tabs.test.js +25 -9
  94. package/dist/src/__tests__/tabs.test.js.map +1 -1
  95. package/dist/src/browser/action-builder/analyzer.d.ts +1 -1
  96. package/dist/src/browser/action-builder/analyzer.d.ts.map +1 -1
  97. package/dist/src/browser/action-builder/analyzer.js +25 -9
  98. package/dist/src/browser/action-builder/analyzer.js.map +1 -1
  99. package/dist/src/browser/action-builder/types.d.ts.map +1 -1
  100. package/dist/src/browser/actions.d.ts +1 -1
  101. package/dist/src/browser/actions.d.ts.map +1 -1
  102. package/dist/src/browser/actions.js +16 -6
  103. package/dist/src/browser/actions.js.map +1 -1
  104. package/dist/src/browser/adapters/gemini.d.ts.map +1 -1
  105. package/dist/src/browser/adapters/gemini.js.map +1 -1
  106. package/dist/src/browser/adapters/google.d.ts.map +1 -1
  107. package/dist/src/browser/adapters/google.js.map +1 -1
  108. package/dist/src/browser/adapters/index.d.ts.map +1 -1
  109. package/dist/src/browser/adapters/index.js +3 -3
  110. package/dist/src/browser/adapters/index.js.map +1 -1
  111. package/dist/src/browser/adapters/instagram.d.ts.map +1 -1
  112. package/dist/src/browser/adapters/instagram.js.map +1 -1
  113. package/dist/src/browser/adapters/linkedin.d.ts.map +1 -1
  114. package/dist/src/browser/adapters/linkedin.js.map +1 -1
  115. package/dist/src/browser/adapters/microsoft.d.ts.map +1 -1
  116. package/dist/src/browser/adapters/microsoft.js.map +1 -1
  117. package/dist/src/browser/adapters/x.d.ts.map +1 -1
  118. package/dist/src/browser/adapters/x.js.map +1 -1
  119. package/dist/src/browser/browser.d.ts +30 -0
  120. package/dist/src/browser/browser.d.ts.map +1 -1
  121. package/dist/src/browser/browser.js +122 -15
  122. package/dist/src/browser/browser.js.map +1 -1
  123. package/dist/src/browser/cdp.d.ts.map +1 -1
  124. package/dist/src/browser/cdp.js +21 -8
  125. package/dist/src/browser/cdp.js.map +1 -1
  126. package/dist/src/browser/console-log.d.ts.map +1 -1
  127. package/dist/src/browser/console-log.js +2 -2
  128. package/dist/src/browser/console-log.js.map +1 -1
  129. package/dist/src/browser/dashboard/server.d.ts.map +1 -1
  130. package/dist/src/browser/dashboard/server.js +29 -19
  131. package/dist/src/browser/dashboard/server.js.map +1 -1
  132. package/dist/src/browser/dashboard/ui.html +153 -165
  133. package/dist/src/browser/dialog.d.ts.map +1 -1
  134. package/dist/src/browser/dialog.js +3 -1
  135. package/dist/src/browser/dialog.js.map +1 -1
  136. package/dist/src/browser/emulation.d.ts.map +1 -1
  137. package/dist/src/browser/emulation.js +21 -6
  138. package/dist/src/browser/emulation.js.map +1 -1
  139. package/dist/src/browser/find.d.ts +4 -4
  140. package/dist/src/browser/find.d.ts.map +1 -1
  141. package/dist/src/browser/find.js +14 -6
  142. package/dist/src/browser/find.js.map +1 -1
  143. package/dist/src/browser/har.d.ts.map +1 -1
  144. package/dist/src/browser/har.js +14 -7
  145. package/dist/src/browser/har.js.map +1 -1
  146. package/dist/src/browser/index.d.ts +17 -16
  147. package/dist/src/browser/index.d.ts.map +1 -1
  148. package/dist/src/browser/index.js +17 -16
  149. package/dist/src/browser/index.js.map +1 -1
  150. package/dist/src/browser/network.d.ts.map +1 -1
  151. package/dist/src/browser/network.js +14 -4
  152. package/dist/src/browser/network.js.map +1 -1
  153. package/dist/src/browser/pdf.d.ts.map +1 -1
  154. package/dist/src/browser/pdf.js +3 -3
  155. package/dist/src/browser/pdf.js.map +1 -1
  156. package/dist/src/browser/profiler.d.ts.map +1 -1
  157. package/dist/src/browser/profiler.js +22 -20
  158. package/dist/src/browser/profiler.js.map +1 -1
  159. package/dist/src/browser/record.d.ts +1 -1
  160. package/dist/src/browser/record.d.ts.map +1 -1
  161. package/dist/src/browser/record.js +18 -7
  162. package/dist/src/browser/record.js.map +1 -1
  163. package/dist/src/browser/ref-cache.d.ts.map +1 -1
  164. package/dist/src/browser/ref-cache.js +9 -4
  165. package/dist/src/browser/ref-cache.js.map +1 -1
  166. package/dist/src/browser/screenshot.d.ts.map +1 -1
  167. package/dist/src/browser/screenshot.js +11 -7
  168. package/dist/src/browser/screenshot.js.map +1 -1
  169. package/dist/src/browser/session.d.ts +1 -1
  170. package/dist/src/browser/session.d.ts.map +1 -1
  171. package/dist/src/browser/session.js +27 -8
  172. package/dist/src/browser/session.js.map +1 -1
  173. package/dist/src/browser/snapshot.d.ts +1 -1
  174. package/dist/src/browser/snapshot.d.ts.map +1 -1
  175. package/dist/src/browser/snapshot.js +8 -4
  176. package/dist/src/browser/snapshot.js.map +1 -1
  177. package/dist/src/browser/storage.d.ts.map +1 -1
  178. package/dist/src/browser/storage.js.map +1 -1
  179. package/dist/src/browser/tabs.d.ts.map +1 -1
  180. package/dist/src/browser/tabs.js +9 -3
  181. package/dist/src/browser/tabs.js.map +1 -1
  182. package/dist/src/browser/trace.d.ts.map +1 -1
  183. package/dist/src/browser/trace.js +3 -3
  184. package/dist/src/browser/trace.js.map +1 -1
  185. package/dist/src/browser/types.d.ts.map +1 -1
  186. package/dist/src/browser/types.js +23 -4
  187. package/dist/src/browser/types.js.map +1 -1
  188. package/dist/src/browser/vitals.d.ts.map +1 -1
  189. package/dist/src/browser/vitals.js +1 -1
  190. package/dist/src/browser/vitals.js.map +1 -1
  191. package/dist/src/browser/wait.d.ts.map +1 -1
  192. package/dist/src/browser/wait.js +11 -5
  193. package/dist/src/browser/wait.js.map +1 -1
  194. package/dist/src/cli/action.d.ts.map +1 -1
  195. package/dist/src/cli/action.js +14 -11
  196. package/dist/src/cli/action.js.map +1 -1
  197. package/dist/src/cli/commands.d.ts.map +1 -1
  198. package/dist/src/cli/commands.js +707 -159
  199. package/dist/src/cli/commands.js.map +1 -1
  200. package/dist/src/cli/output.js +5 -5
  201. package/dist/src/cli/output.js.map +1 -1
  202. package/dist/src/cli/platform.d.ts.map +1 -1
  203. package/dist/src/cli/platform.js +15 -11
  204. package/dist/src/cli/platform.js.map +1 -1
  205. package/dist/src/cli/types.d.ts +1 -1
  206. package/dist/src/cli/types.d.ts.map +1 -1
  207. package/dist/src/cli.js +21 -9
  208. package/dist/src/cli.js.map +1 -1
  209. package/dist/src/index.d.ts +2 -2
  210. package/dist/src/index.d.ts.map +1 -1
  211. package/dist/src/index.js +2 -2
  212. package/dist/src/index.js.map +1 -1
  213. package/dist/src/report/a11y.d.ts +52 -0
  214. package/dist/src/report/a11y.d.ts.map +1 -0
  215. package/dist/src/report/a11y.js +231 -0
  216. package/dist/src/report/a11y.js.map +1 -0
  217. package/dist/src/report/analyze.d.ts +20 -0
  218. package/dist/src/report/analyze.d.ts.map +1 -0
  219. package/dist/src/report/analyze.js +136 -0
  220. package/dist/src/report/analyze.js.map +1 -0
  221. package/dist/src/report/budget.d.ts +27 -0
  222. package/dist/src/report/budget.d.ts.map +1 -0
  223. package/dist/src/report/budget.js +143 -0
  224. package/dist/src/report/budget.js.map +1 -0
  225. package/dist/src/report/collect-a11y.d.ts +25 -0
  226. package/dist/src/report/collect-a11y.d.ts.map +1 -0
  227. package/dist/src/report/collect-a11y.js +154 -0
  228. package/dist/src/report/collect-a11y.js.map +1 -0
  229. package/dist/src/report/collect.d.ts +45 -0
  230. package/dist/src/report/collect.d.ts.map +1 -0
  231. package/dist/src/report/collect.js +275 -0
  232. package/dist/src/report/collect.js.map +1 -0
  233. package/dist/src/report/evidence.d.ts +80 -0
  234. package/dist/src/report/evidence.d.ts.map +1 -0
  235. package/dist/src/report/evidence.js +279 -0
  236. package/dist/src/report/evidence.js.map +1 -0
  237. package/dist/src/report/flake.d.ts +88 -0
  238. package/dist/src/report/flake.d.ts.map +1 -0
  239. package/dist/src/report/flake.js +232 -0
  240. package/dist/src/report/flake.js.map +1 -0
  241. package/dist/src/report/history.d.ts +85 -0
  242. package/dist/src/report/history.d.ts.map +1 -0
  243. package/dist/src/report/history.js +176 -0
  244. package/dist/src/report/history.js.map +1 -0
  245. package/dist/src/report/index.d.ts +102 -0
  246. package/dist/src/report/index.d.ts.map +1 -0
  247. package/dist/src/report/index.js +216 -0
  248. package/dist/src/report/index.js.map +1 -0
  249. package/dist/src/report/pixel-diff.d.ts +30 -0
  250. package/dist/src/report/pixel-diff.d.ts.map +1 -0
  251. package/dist/src/report/pixel-diff.js +175 -0
  252. package/dist/src/report/pixel-diff.js.map +1 -0
  253. package/dist/src/report/png.d.ts +28 -0
  254. package/dist/src/report/png.d.ts.map +1 -0
  255. package/dist/src/report/png.js +259 -0
  256. package/dist/src/report/png.js.map +1 -0
  257. package/dist/src/report/render-evidence.d.ts +16 -0
  258. package/dist/src/report/render-evidence.d.ts.map +1 -0
  259. package/dist/src/report/render-evidence.js +174 -0
  260. package/dist/src/report/render-evidence.js.map +1 -0
  261. package/dist/src/report/render-trend.d.ts +16 -0
  262. package/dist/src/report/render-trend.d.ts.map +1 -0
  263. package/dist/src/report/render-trend.js +194 -0
  264. package/dist/src/report/render-trend.js.map +1 -0
  265. package/dist/src/report/render.d.ts +21 -0
  266. package/dist/src/report/render.d.ts.map +1 -0
  267. package/dist/src/report/render.js +286 -0
  268. package/dist/src/report/render.js.map +1 -0
  269. package/dist/src/report/run-diff.d.ts +18 -0
  270. package/dist/src/report/run-diff.d.ts.map +1 -0
  271. package/dist/src/report/run-diff.js +51 -0
  272. package/dist/src/report/run-diff.js.map +1 -0
  273. package/dist/src/report/structure.d.ts +41 -0
  274. package/dist/src/report/structure.d.ts.map +1 -0
  275. package/dist/src/report/structure.js +210 -0
  276. package/dist/src/report/structure.js.map +1 -0
  277. package/dist/src/report/trend.d.ts +26 -0
  278. package/dist/src/report/trend.d.ts.map +1 -0
  279. package/dist/src/report/trend.js +164 -0
  280. package/dist/src/report/trend.js.map +1 -0
  281. package/dist/src/report/types.d.ts +320 -0
  282. package/dist/src/report/types.d.ts.map +1 -0
  283. package/dist/src/report/types.js +11 -0
  284. package/dist/src/report/types.js.map +1 -0
  285. package/dist/src/report/util.d.ts +17 -0
  286. package/dist/src/report/util.d.ts.map +1 -0
  287. package/dist/src/report/util.js +45 -0
  288. package/dist/src/report/util.js.map +1 -0
  289. package/dist/tsconfig.tsbuildinfo +1 -1
  290. package/package.json +1 -1
  291. package/src/__tests__/adapters.test.ts +15 -8
  292. package/src/__tests__/batch-eval-parsing.test.ts +4 -2
  293. package/src/__tests__/box-model.test.ts +9 -5
  294. package/src/__tests__/browser-launch.test.ts +26 -15
  295. package/src/__tests__/cdp-client.test.ts +25 -9
  296. package/src/__tests__/close-browser.test.ts +11 -6
  297. package/src/__tests__/console-log.test.ts +36 -13
  298. package/src/__tests__/find.test.ts +58 -20
  299. package/src/__tests__/frame-command.test.ts +12 -6
  300. package/src/__tests__/open-url-navigate-error.test.ts +2 -4
  301. package/src/__tests__/output.test.ts +1 -1
  302. package/src/__tests__/profiler-heap.test.ts +191 -0
  303. package/src/__tests__/reap-idle-browser.test.ts +276 -0
  304. package/src/__tests__/ref-cache.test.ts +25 -12
  305. package/src/__tests__/report-a11y.test.ts +180 -0
  306. package/src/__tests__/report-analyze.test.ts +202 -0
  307. package/src/__tests__/report-budget.test.ts +92 -0
  308. package/src/__tests__/report-diff.test.ts +272 -0
  309. package/src/__tests__/report-evidence.test.ts +276 -0
  310. package/src/__tests__/report-flake.test.ts +214 -0
  311. package/src/__tests__/report-history.test.ts +293 -0
  312. package/src/__tests__/report-output.test.ts +210 -0
  313. package/src/__tests__/report-png.test.ts +95 -0
  314. package/src/__tests__/report-render-extras.test.ts +315 -0
  315. package/src/__tests__/report-render.test.ts +175 -0
  316. package/src/__tests__/report-run.test.ts +264 -0
  317. package/src/__tests__/session-state.test.ts +40 -28
  318. package/src/__tests__/snapshot.test.ts +60 -21
  319. package/src/__tests__/storage-eval.test.ts +30 -16
  320. package/src/__tests__/tabs.test.ts +26 -10
  321. package/src/browser/action-builder/analyzer.ts +39 -15
  322. package/src/browser/action-builder/types.ts +45 -8
  323. package/src/browser/actions.ts +288 -123
  324. package/src/browser/adapters/gemini.ts +7 -3
  325. package/src/browser/adapters/google.ts +5 -3
  326. package/src/browser/adapters/index.ts +5 -4
  327. package/src/browser/adapters/instagram.ts +4 -2
  328. package/src/browser/adapters/linkedin.ts +4 -2
  329. package/src/browser/adapters/microsoft.ts +9 -5
  330. package/src/browser/adapters/x.ts +7 -3
  331. package/src/browser/browser.ts +188 -42
  332. package/src/browser/cdp.ts +43 -11
  333. package/src/browser/console-log.ts +24 -7
  334. package/src/browser/dashboard/server.ts +44 -25
  335. package/src/browser/dashboard/ui.html +153 -165
  336. package/src/browser/dialog.ts +25 -8
  337. package/src/browser/emulation.ts +86 -36
  338. package/src/browser/find.ts +110 -47
  339. package/src/browser/har.ts +58 -26
  340. package/src/browser/index.ts +17 -16
  341. package/src/browser/network.ts +147 -46
  342. package/src/browser/pdf.ts +4 -4
  343. package/src/browser/profiler.ts +39 -19
  344. package/src/browser/record.ts +38 -19
  345. package/src/browser/ref-cache.ts +38 -17
  346. package/src/browser/screenshot.ts +58 -32
  347. package/src/browser/session.ts +51 -18
  348. package/src/browser/snapshot.ts +34 -20
  349. package/src/browser/storage.ts +73 -17
  350. package/src/browser/tabs.ts +29 -17
  351. package/src/browser/trace.ts +14 -10
  352. package/src/browser/types.ts +23 -4
  353. package/src/browser/vitals.ts +33 -16
  354. package/src/browser/wait.ts +47 -21
  355. package/src/cli/action.ts +52 -21
  356. package/src/cli/commands.ts +1365 -385
  357. package/src/cli/output.ts +5 -5
  358. package/src/cli/platform.ts +44 -23
  359. package/src/cli/types.ts +1 -1
  360. package/src/cli.ts +34 -18
  361. package/src/index.ts +2 -2
  362. package/src/report/a11y.ts +242 -0
  363. package/src/report/analyze.ts +181 -0
  364. package/src/report/budget.ts +155 -0
  365. package/src/report/collect-a11y.ts +200 -0
  366. package/src/report/collect.ts +408 -0
  367. package/src/report/evidence.ts +379 -0
  368. package/src/report/flake.ts +303 -0
  369. package/src/report/history.ts +219 -0
  370. package/src/report/index.ts +307 -0
  371. package/src/report/pixel-diff.ts +197 -0
  372. package/src/report/png.ts +290 -0
  373. package/src/report/render-evidence.ts +194 -0
  374. package/src/report/render-trend.ts +225 -0
  375. package/src/report/render.ts +314 -0
  376. package/src/report/run-diff.ts +63 -0
  377. package/src/report/structure.ts +212 -0
  378. package/src/report/trend.ts +189 -0
  379. package/src/report/types.ts +356 -0
  380. package/src/report/util.ts +48 -0
@@ -0,0 +1,259 @@
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
+ import { deflateSync, inflateSync } from 'node:zlib';
16
+ const SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
17
+ // ---------------------------------------------------------------------------
18
+ // CRC32 — PNG chunks carry their own checksum, and zlib does not expose one.
19
+ // ---------------------------------------------------------------------------
20
+ const CRC_TABLE = (() => {
21
+ const table = new Uint32Array(256);
22
+ for (let n = 0; n < 256; n++) {
23
+ let c = n;
24
+ for (let k = 0; k < 8; k++)
25
+ c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
26
+ table[n] = c >>> 0;
27
+ }
28
+ return table;
29
+ })();
30
+ export function crc32(buf) {
31
+ let c = 0xffffffff;
32
+ for (let i = 0; i < buf.length; i++)
33
+ c = CRC_TABLE[(c ^ buf[i]) & 0xff] ^ (c >>> 8);
34
+ return (c ^ 0xffffffff) >>> 0;
35
+ }
36
+ // ---------------------------------------------------------------------------
37
+ // Decode
38
+ // ---------------------------------------------------------------------------
39
+ const CHANNELS = { 0: 1, 2: 3, 3: 1, 4: 2, 6: 4 };
40
+ function paeth(a, b, c) {
41
+ const p = a + b - c;
42
+ const pa = Math.abs(p - a);
43
+ const pb = Math.abs(p - b);
44
+ const pc = Math.abs(p - c);
45
+ if (pa <= pb && pa <= pc)
46
+ return a;
47
+ return pb <= pc ? b : c;
48
+ }
49
+ /** Undo the per-scanline filters in place, returning the raw sample bytes. */
50
+ function unfilter(raw, width, height, bpp, stride) {
51
+ const out = Buffer.alloc(height * stride);
52
+ let pos = 0;
53
+ for (let y = 0; y < height; y++) {
54
+ const filter = raw[pos++];
55
+ const line = raw.subarray(pos, pos + stride);
56
+ pos += stride;
57
+ const cur = out.subarray(y * stride, (y + 1) * stride);
58
+ const prev = y > 0 ? out.subarray((y - 1) * stride, y * stride) : null;
59
+ for (let x = 0; x < stride; x++) {
60
+ const a = x >= bpp ? cur[x - bpp] : 0;
61
+ const b = prev ? prev[x] : 0;
62
+ const c = prev && x >= bpp ? prev[x - bpp] : 0;
63
+ const v = line[x];
64
+ switch (filter) {
65
+ case 0:
66
+ cur[x] = v;
67
+ break;
68
+ case 1:
69
+ cur[x] = (v + a) & 0xff;
70
+ break;
71
+ case 2:
72
+ cur[x] = (v + b) & 0xff;
73
+ break;
74
+ case 3:
75
+ cur[x] = (v + ((a + b) >> 1)) & 0xff;
76
+ break;
77
+ case 4:
78
+ cur[x] = (v + paeth(a, b, c)) & 0xff;
79
+ break;
80
+ default:
81
+ throw new Error(`PNG: unknown scanline filter ${filter} on row ${y}`);
82
+ }
83
+ }
84
+ }
85
+ void width;
86
+ return out;
87
+ }
88
+ function readHeader(buf, offset) {
89
+ return {
90
+ width: buf.readUInt32BE(offset),
91
+ height: buf.readUInt32BE(offset + 4),
92
+ bitDepth: buf[offset + 8],
93
+ colorType: buf[offset + 9],
94
+ interlace: buf[offset + 12],
95
+ };
96
+ }
97
+ /**
98
+ * Expand one row of decoded samples into RGBA. `step` is the byte stride of
99
+ * one sample (1 for bit depth 8, 2 for 16 — where we keep the high byte).
100
+ */
101
+ function toRgba(samples, header, palette, transparency) {
102
+ const { width, height, bitDepth, colorType } = header;
103
+ const channels = CHANNELS[colorType];
104
+ const step = bitDepth === 16 ? 2 : 1;
105
+ const stride = width * channels * step;
106
+ const out = new Uint8Array(width * height * 4);
107
+ for (let y = 0; y < height; y++) {
108
+ for (let x = 0; x < width; x++) {
109
+ const s = y * stride + x * channels * step;
110
+ const d = (y * width + x) * 4;
111
+ if (colorType === 3) {
112
+ const index = samples[s];
113
+ if (!palette || index * 3 + 2 >= palette.length) {
114
+ throw new Error(`PNG: palette index ${index} out of range`);
115
+ }
116
+ out[d] = palette[index * 3];
117
+ out[d + 1] = palette[index * 3 + 1];
118
+ out[d + 2] = palette[index * 3 + 2];
119
+ out[d + 3] = transparency && index < transparency.length ? transparency[index] : 255;
120
+ }
121
+ else if (colorType === 0) {
122
+ const g = samples[s];
123
+ out[d] = g;
124
+ out[d + 1] = g;
125
+ out[d + 2] = g;
126
+ out[d + 3] = 255;
127
+ }
128
+ else if (colorType === 4) {
129
+ const g = samples[s];
130
+ out[d] = g;
131
+ out[d + 1] = g;
132
+ out[d + 2] = g;
133
+ out[d + 3] = samples[s + step];
134
+ }
135
+ else if (colorType === 2) {
136
+ out[d] = samples[s];
137
+ out[d + 1] = samples[s + step];
138
+ out[d + 2] = samples[s + 2 * step];
139
+ out[d + 3] = 255;
140
+ }
141
+ else {
142
+ out[d] = samples[s];
143
+ out[d + 1] = samples[s + step];
144
+ out[d + 2] = samples[s + 2 * step];
145
+ out[d + 3] = samples[s + 3 * step];
146
+ }
147
+ }
148
+ }
149
+ return out;
150
+ }
151
+ export function decodePng(input) {
152
+ const buf = Buffer.from(input.buffer, input.byteOffset, input.byteLength);
153
+ if (buf.length < 8 || !buf.subarray(0, 8).equals(SIGNATURE)) {
154
+ throw new Error('PNG: not a PNG (bad signature)');
155
+ }
156
+ let header = null;
157
+ let palette = null;
158
+ let transparency = null;
159
+ const idat = [];
160
+ let pos = 8;
161
+ while (pos + 8 <= buf.length) {
162
+ const length = buf.readUInt32BE(pos);
163
+ const type = buf.toString('ascii', pos + 4, pos + 8);
164
+ const dataStart = pos + 8;
165
+ if (dataStart + length > buf.length)
166
+ throw new Error(`PNG: truncated ${type} chunk`);
167
+ if (type === 'IHDR')
168
+ header = readHeader(buf, dataStart);
169
+ else if (type === 'PLTE')
170
+ palette = buf.subarray(dataStart, dataStart + length);
171
+ else if (type === 'tRNS')
172
+ transparency = buf.subarray(dataStart, dataStart + length);
173
+ else if (type === 'IDAT')
174
+ idat.push(buf.subarray(dataStart, dataStart + length));
175
+ else if (type === 'IEND')
176
+ break;
177
+ pos = dataStart + length + 4;
178
+ }
179
+ if (!header)
180
+ throw new Error('PNG: no IHDR chunk');
181
+ if (header.interlace !== 0) {
182
+ throw new Error('PNG: interlaced (Adam7) images are not supported');
183
+ }
184
+ if (header.bitDepth !== 8 && header.bitDepth !== 16) {
185
+ throw new Error(`PNG: unsupported bit depth ${header.bitDepth} (need 8 or 16)`);
186
+ }
187
+ const channels = CHANNELS[header.colorType];
188
+ if (channels === undefined) {
189
+ throw new Error(`PNG: unsupported colour type ${header.colorType}`);
190
+ }
191
+ if (header.colorType === 3 && header.bitDepth !== 8) {
192
+ throw new Error(`PNG: palette images below bit depth 8 are not supported`);
193
+ }
194
+ if (!idat.length)
195
+ throw new Error('PNG: no IDAT data');
196
+ const sampleBytes = header.bitDepth === 16 ? 2 : 1;
197
+ const stride = header.width * channels * sampleBytes;
198
+ const bpp = Math.max(1, channels * sampleBytes);
199
+ const inflated = inflateSync(Buffer.concat(idat));
200
+ const expected = header.height * (stride + 1);
201
+ if (inflated.length < expected) {
202
+ throw new Error(`PNG: pixel data short by ${expected - inflated.length} bytes`);
203
+ }
204
+ const samples = unfilter(inflated, header.width, header.height, bpp, stride);
205
+ return {
206
+ width: header.width,
207
+ height: header.height,
208
+ data: toRgba(samples, header, palette, transparency),
209
+ };
210
+ }
211
+ // ---------------------------------------------------------------------------
212
+ // Encode
213
+ // ---------------------------------------------------------------------------
214
+ function chunk(type, data) {
215
+ const head = Buffer.alloc(8);
216
+ head.writeUInt32BE(data.length, 0);
217
+ head.write(type, 4, 'ascii');
218
+ const body = Buffer.concat([head.subarray(4), Buffer.from(data)]);
219
+ const crc = Buffer.alloc(4);
220
+ crc.writeUInt32BE(crc32(body), 0);
221
+ return Buffer.concat([head.subarray(0, 4), body, crc]);
222
+ }
223
+ /** Encode RGBA bytes as a non-interlaced, 8-bit truecolour-with-alpha PNG. */
224
+ export function encodePng(image) {
225
+ const { width, height, data } = image;
226
+ if (data.length !== width * height * 4) {
227
+ throw new Error(`PNG: encode expected ${width * height * 4} bytes for ${width}x${height}, got ${data.length}`);
228
+ }
229
+ const stride = width * 4;
230
+ const raw = Buffer.alloc(height * (stride + 1));
231
+ for (let y = 0; y < height; y++) {
232
+ raw[y * (stride + 1)] = 0; // filter: None. Simplest, and deflate still wins.
233
+ Buffer.from(data.buffer, data.byteOffset + y * stride, stride).copy(raw, y * (stride + 1) + 1);
234
+ }
235
+ const ihdr = Buffer.alloc(13);
236
+ ihdr.writeUInt32BE(width, 0);
237
+ ihdr.writeUInt32BE(height, 4);
238
+ ihdr[8] = 8; // bit depth
239
+ ihdr[9] = 6; // colour type: RGBA
240
+ ihdr[10] = 0; // compression
241
+ ihdr[11] = 0; // filter
242
+ ihdr[12] = 0; // interlace
243
+ return Buffer.concat([
244
+ SIGNATURE,
245
+ chunk('IHDR', ihdr),
246
+ chunk('IDAT', deflateSync(raw, { level: 6 })),
247
+ chunk('IEND', new Uint8Array(0)),
248
+ ]);
249
+ }
250
+ /** `data:image/png;base64,...` -> bytes. Accepts a bare base64 payload too. */
251
+ export function pngFromDataUrl(dataUrl) {
252
+ const comma = dataUrl.indexOf(',');
253
+ const payload = dataUrl.startsWith('data:') && comma >= 0 ? dataUrl.slice(comma + 1) : dataUrl;
254
+ return new Uint8Array(Buffer.from(payload, 'base64'));
255
+ }
256
+ export function pngToDataUrl(png) {
257
+ return `data:image/png;base64,${Buffer.from(png).toString('base64')}`;
258
+ }
259
+ //# sourceMappingURL=png.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"png.js","sourceRoot":"","sources":["../../../src/report/png.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Report sections for the recorded evidence timeline (RIG-11) and the flake
3
+ * analysis (RIG-14).
4
+ *
5
+ * The evidence section is written to be read the way someone triages a bug:
6
+ * a filmstrip of what the page looked like either side of the failure, then
7
+ * one time-ordered list mixing frames, console output and network failures,
8
+ * so "the error fired, then the screen went blank" is visible rather than
9
+ * inferred.
10
+ */
11
+ import type { FlakeReport } from './flake.js';
12
+ import type { Evidence } from './types.js';
13
+ export declare const EVIDENCE_STYLES: string;
14
+ export declare function renderEvidence(evidence: Evidence | undefined): string;
15
+ export declare function renderFlake(flake: FlakeReport | undefined): string;
16
+ //# sourceMappingURL=render-evidence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-evidence.d.ts","sourceRoot":"","sources":["../../../src/report/render-evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,YAAY,CAAC;AAG1D,eAAO,MAAM,eAAe,QAqBpB,CAAC;AAsDT,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAmBrE;AAwED,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,GAAG,MAAM,CAYlE"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Report sections for the recorded evidence timeline (RIG-11) and the flake
3
+ * analysis (RIG-14).
4
+ *
5
+ * The evidence section is written to be read the way someone triages a bug:
6
+ * a filmstrip of what the page looked like either side of the failure, then
7
+ * one time-ordered list mixing frames, console output and network failures,
8
+ * so "the error fired, then the screen went blank" is visible rather than
9
+ * inferred.
10
+ */
11
+ import { escapeHtml } from './util.js';
12
+ export const EVIDENCE_STYLES = `
13
+ .filmstrip{display:flex;gap:10px;overflow-x:auto;padding:4px 0 10px;margin:0 0 8px}
14
+ .filmstrip figure{flex:0 0 auto;width:180px;margin:0}
15
+ .filmstrip img{width:180px;height:auto;border-radius:6px}
16
+ .filmstrip figcaption{font-variant-numeric:tabular-nums}
17
+ .filmstrip figure.focus img{border-color:var(--fail);border-width:2px}
18
+ .timeline{list-style:none;margin:0;padding:0;border-left:2px solid var(--line);
19
+ margin-left:8px}
20
+ .timeline li{position:relative;padding:6px 0 6px 18px;font-size:13px}
21
+ .timeline li::before{content:"";position:absolute;left:-5px;top:12px;width:8px;height:8px;
22
+ border-radius:50%;background:var(--muted)}
23
+ .timeline li.error::before{background:var(--fail)}
24
+ .timeline li.warning::before{background:var(--warn)}
25
+ .timeline li.marker{font-weight:600;color:var(--fail)}
26
+ .timeline .at{display:inline-block;min-width:66px;color:var(--muted);
27
+ font-variant-numeric:tabular-nums;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
28
+ .verdict.flaky{background:var(--warn-bg);border-color:var(--warn);color:var(--warn)}
29
+ .rate{display:inline-block;min-width:72px}
30
+ .bar{display:inline-block;width:80px;height:8px;border-radius:4px;background:var(--pass);
31
+ overflow:hidden;vertical-align:middle}
32
+ .bar i{display:block;height:100%;background:var(--fail)}
33
+ `.trim();
34
+ function at(offsetMs) {
35
+ const sign = offsetMs < 0 ? '−' : '+';
36
+ const abs = Math.abs(offsetMs);
37
+ return abs >= 1000 ? `${sign}${(abs / 1000).toFixed(2)}s` : `${sign}${Math.round(abs)}ms`;
38
+ }
39
+ // ---------------------------------------------------------------------------
40
+ // Evidence
41
+ // ---------------------------------------------------------------------------
42
+ function renderFilmstrip(evidence) {
43
+ if (!evidence.frames.length)
44
+ return '';
45
+ // Mark the frame closest to the failure so the eye lands on it first.
46
+ let focusIndex = -1;
47
+ if (evidence.focusOffsetMs !== null) {
48
+ let best = Infinity;
49
+ evidence.frames.forEach((f, i) => {
50
+ const d = Math.abs(f.offsetMs - evidence.focusOffsetMs);
51
+ if (d < best) {
52
+ best = d;
53
+ focusIndex = i;
54
+ }
55
+ });
56
+ }
57
+ const figures = evidence.frames
58
+ .map((f, i) => `<figure class="${i === focusIndex ? 'focus' : ''}">
59
+ <figcaption>${escapeHtml(at(f.offsetMs))}${i === focusIndex ? ' · at failure' : ''}</figcaption>
60
+ <img alt="${escapeHtml(`Frame at ${at(f.offsetMs)}`)}" src="${escapeHtml(f.dataUrl)}">
61
+ </figure>`)
62
+ .join('');
63
+ return `<div class="filmstrip">${figures}</div>`;
64
+ }
65
+ function renderTimelineRows(timeline) {
66
+ if (!timeline.length)
67
+ return '<p class="empty">Nothing was recorded for this run.</p>';
68
+ const rows = timeline
69
+ .map((e) => {
70
+ const detail = e.detail ? ` — ${escapeHtml(e.detail)}` : '';
71
+ const frame = e.kind === 'frame' && e.frameIndex !== undefined
72
+ ? ` <span style="color:var(--muted)">#${e.frameIndex + 1}</span>`
73
+ : '';
74
+ return `<li class="${e.severity}${e.kind === 'marker' ? ' marker' : ''}">
75
+ <span class="at">${escapeHtml(at(e.offsetMs))}</span>${escapeHtml(e.label)}${frame}${detail}
76
+ </li>`;
77
+ })
78
+ .join('');
79
+ return `<ul class="timeline">${rows}</ul>`;
80
+ }
81
+ export function renderEvidence(evidence) {
82
+ if (!evidence)
83
+ return '';
84
+ const why = evidence.reason === 'budget-failure'
85
+ ? 'Recorded because this run breached its budget.'
86
+ : 'Recorded because --record was passed.';
87
+ const focus = evidence.focusOffsetMs !== null
88
+ ? ` The timeline is centred on the first failure, at ${at(evidence.focusOffsetMs)} into the run.`
89
+ : '';
90
+ const notes = evidence.notes.length
91
+ ? `<p class="note">${evidence.notes.map((n) => escapeHtml(n)).join(' ')}</p>`
92
+ : '';
93
+ return `<h2>Evidence</h2>
94
+ <p class="note">${escapeHtml(why)}${escapeHtml(focus)} Offsets are measured from the start of the run.</p>
95
+ ${renderFilmstrip(evidence)}
96
+ ${renderTimelineRows(evidence.timeline)}
97
+ ${notes}`;
98
+ }
99
+ // ---------------------------------------------------------------------------
100
+ // Flake
101
+ // ---------------------------------------------------------------------------
102
+ function rateBar(check) {
103
+ const pct = Math.round(check.flakeRate * 100);
104
+ return `<span class="bar" role="img" aria-label="${escapeHtml(`failed ${pct}% of runs`)}"><i style="width:${pct}%"></i></span>`;
105
+ }
106
+ function renderChecks(flake) {
107
+ const rows = flake.checks
108
+ // Unstable checks first: they are the reason this section exists.
109
+ .sort((a, b) => Number(a.stable) - Number(b.stable) || b.flakeRate - a.flakeRate)
110
+ .map((c) => `<tr>
111
+ <td>${escapeHtml(c.label)}</td>
112
+ <td class="num mono"><span class="rate">${c.passed} of ${c.runs} passed</span></td>
113
+ <td>${rateBar(c)}</td>
114
+ <td>${c.stable ? (c.failed ? '<span class="pill error">always fails</span>' : '<span class="pill good">stable</span>') : '<span class="pill warning">flaky</span>'}</td>
115
+ <td class="wrap mono">${escapeHtml(c.actuals.join(', '))}</td>
116
+ </tr>`)
117
+ .join('');
118
+ return `<table><thead><tr><th>Check</th><th>Outcome</th><th>Failure rate</th><th></th><th>Measured each run</th></tr></thead>
119
+ <tbody>${rows}</tbody></table>`;
120
+ }
121
+ function renderSignals(flake) {
122
+ if (!flake.signals.length) {
123
+ return '<p class="empty">No error or failed request came and went between runs.</p>';
124
+ }
125
+ const rows = flake.signals
126
+ .slice(0, 30)
127
+ .map((s) => `<tr>
128
+ <td>${escapeHtml(s.kind)}</td>
129
+ <td class="wrap">${escapeHtml(s.signature)}</td>
130
+ <td class="num mono">${s.runs} of ${s.total}</td>
131
+ </tr>`)
132
+ .join('');
133
+ return `<table><thead><tr><th>Kind</th><th>Signal</th><th>Appeared in</th></tr></thead><tbody>${rows}</tbody></table>
134
+ <p class="note">Ids, hashes and long numbers are normalised before grouping, so one intermittent error is one row rather than N.</p>`;
135
+ }
136
+ function renderMetricSpread(flake) {
137
+ if (!flake.metrics.length)
138
+ return '';
139
+ const rows = flake.metrics
140
+ .map((m) => {
141
+ const fmt = (v) => m.unit === 'score'
142
+ ? v.toFixed(3)
143
+ : v >= 1000
144
+ ? `${(v / 1000).toFixed(2)}s`
145
+ : `${Math.round(v)}ms`;
146
+ return `<tr>
147
+ <td><b>${escapeHtml(m.label)}</b></td>
148
+ <td class="num mono">${escapeHtml(fmt(m.min))} – ${escapeHtml(fmt(m.max))}</td>
149
+ <td class="num mono">${escapeHtml(fmt(m.median))}</td>
150
+ <td class="num mono">${escapeHtml(fmt(m.spread))}</td>
151
+ <td>${m.unstable ? '<span class="pill warning">varies widely</span>' : '<span class="pill good">consistent</span>'}</td>
152
+ <td class="num mono">${m.measured} of ${m.total}</td>
153
+ </tr>`;
154
+ })
155
+ .join('');
156
+ return `<h3 style="font-size:13px;color:var(--muted);margin:24px 0 8px">Metric spread</h3>
157
+ <table><thead><tr><th>Metric</th><th>Range</th><th>Median</th><th>Spread</th><th></th><th>Measured</th></tr></thead>
158
+ <tbody>${rows}</tbody></table>`;
159
+ }
160
+ export function renderFlake(flake) {
161
+ if (!flake)
162
+ return '';
163
+ return `<h2>Repeatability — ${flake.runs} runs</h2>
164
+ <section class="verdict ${flake.verdict === 'pass' ? 'pass' : flake.verdict === 'fail' ? 'fail' : 'flaky'}">
165
+ <div class="tag">${flake.verdict.toUpperCase()}</div>
166
+ <div class="line">${escapeHtml(flake.headline)}</div>
167
+ </section>
168
+ <p class="note"><b>Confidence: ${escapeHtml(flake.confidence)}.</b> ${escapeHtml(flake.confidenceNote)}</p>
169
+ ${renderChecks(flake)}
170
+ <h3 style="font-size:13px;color:var(--muted);margin:24px 0 8px">Intermittent errors and requests</h3>
171
+ ${renderSignals(flake)}
172
+ ${renderMetricSpread(flake)}`;
173
+ }
174
+ //# sourceMappingURL=render-evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-evidence.js","sourceRoot":"","sources":["../../../src/report/render-evidence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Report sections for the trend (RIG-13) and the run-to-run diff (RIG-10).
3
+ *
4
+ * Kept separate from render.ts purely for size. Same rules apply: no external
5
+ * resources, so the sparklines are hand-written inline SVG rather than a
6
+ * charting library, and the diff image is a `data:` URI.
7
+ *
8
+ * The design goal for the trend is legibility at a glance — the point of the
9
+ * feature is catching decay nobody noticed, which only works if the reader
10
+ * sees it without going looking.
11
+ */
12
+ import type { RunDiff, TrendReport } from './types.js';
13
+ export declare const TREND_STYLES: string;
14
+ export declare function renderTrend(trend: TrendReport | undefined): string;
15
+ export declare function renderDiff(diff: RunDiff | undefined): string;
16
+ //# sourceMappingURL=render-trend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-trend.d.ts","sourceRoot":"","sources":["../../../src/report/render-trend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAgC,WAAW,EAAe,MAAM,YAAY,CAAC;AAMlG,eAAO,MAAM,YAAY,QAkBjB,CAAC;AAyCT,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,GAAG,MAAM,CAyClE;AAsFD,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAmB5D"}