perfgraph 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +280 -0
  3. package/dist/causal/builder.d.ts +34 -0
  4. package/dist/causal/builder.d.ts.map +1 -0
  5. package/dist/causal/builder.js +132 -0
  6. package/dist/causal/builder.js.map +1 -0
  7. package/dist/causal/index.d.ts +11 -0
  8. package/dist/causal/index.d.ts.map +1 -0
  9. package/dist/causal/index.js +10 -0
  10. package/dist/causal/index.js.map +1 -0
  11. package/dist/causal/rules/js.d.ts +49 -0
  12. package/dist/causal/rules/js.d.ts.map +1 -0
  13. package/dist/causal/rules/js.js +209 -0
  14. package/dist/causal/rules/js.js.map +1 -0
  15. package/dist/causal/rules/layout.d.ts +39 -0
  16. package/dist/causal/rules/layout.d.ts.map +1 -0
  17. package/dist/causal/rules/layout.js +169 -0
  18. package/dist/causal/rules/layout.js.map +1 -0
  19. package/dist/causal/rules/lcp.d.ts +49 -0
  20. package/dist/causal/rules/lcp.d.ts.map +1 -0
  21. package/dist/causal/rules/lcp.js +250 -0
  22. package/dist/causal/rules/lcp.js.map +1 -0
  23. package/dist/causal/rules/network.d.ts +39 -0
  24. package/dist/causal/rules/network.d.ts.map +1 -0
  25. package/dist/causal/rules/network.js +140 -0
  26. package/dist/causal/rules/network.js.map +1 -0
  27. package/dist/causal/types.d.ts +142 -0
  28. package/dist/causal/types.d.ts.map +1 -0
  29. package/dist/causal/types.js +88 -0
  30. package/dist/causal/types.js.map +1 -0
  31. package/dist/cli/analyze.d.ts +33 -0
  32. package/dist/cli/analyze.d.ts.map +1 -0
  33. package/dist/cli/analyze.js +137 -0
  34. package/dist/cli/analyze.js.map +1 -0
  35. package/dist/cli/collect.d.ts +28 -0
  36. package/dist/cli/collect.d.ts.map +1 -0
  37. package/dist/cli/collect.js +125 -0
  38. package/dist/cli/collect.js.map +1 -0
  39. package/dist/cli/extract.d.ts +31 -0
  40. package/dist/cli/extract.d.ts.map +1 -0
  41. package/dist/cli/extract.js +135 -0
  42. package/dist/cli/extract.js.map +1 -0
  43. package/dist/cli/mcp.d.ts +14 -0
  44. package/dist/cli/mcp.d.ts.map +1 -0
  45. package/dist/cli/mcp.js +53 -0
  46. package/dist/cli/mcp.js.map +1 -0
  47. package/dist/cli/normalize.d.ts +58 -0
  48. package/dist/cli/normalize.d.ts.map +1 -0
  49. package/dist/cli/normalize.js +179 -0
  50. package/dist/cli/normalize.js.map +1 -0
  51. package/dist/cli/report.d.ts +33 -0
  52. package/dist/cli/report.d.ts.map +1 -0
  53. package/dist/cli/report.js +137 -0
  54. package/dist/cli/report.js.map +1 -0
  55. package/dist/cli/run.d.ts +49 -0
  56. package/dist/cli/run.d.ts.map +1 -0
  57. package/dist/cli/run.js +243 -0
  58. package/dist/cli/run.js.map +1 -0
  59. package/dist/collect/buffer-monitor.d.ts +25 -0
  60. package/dist/collect/buffer-monitor.d.ts.map +1 -0
  61. package/dist/collect/buffer-monitor.js +69 -0
  62. package/dist/collect/buffer-monitor.js.map +1 -0
  63. package/dist/collect/console.d.ts +25 -0
  64. package/dist/collect/console.d.ts.map +1 -0
  65. package/dist/collect/console.js +82 -0
  66. package/dist/collect/console.js.map +1 -0
  67. package/dist/collect/coverage.d.ts +26 -0
  68. package/dist/collect/coverage.d.ts.map +1 -0
  69. package/dist/collect/coverage.js +99 -0
  70. package/dist/collect/coverage.js.map +1 -0
  71. package/dist/collect/dom.d.ts +37 -0
  72. package/dist/collect/dom.d.ts.map +1 -0
  73. package/dist/collect/dom.js +118 -0
  74. package/dist/collect/dom.js.map +1 -0
  75. package/dist/collect/lighthouse.d.ts +41 -0
  76. package/dist/collect/lighthouse.d.ts.map +1 -0
  77. package/dist/collect/lighthouse.js +111 -0
  78. package/dist/collect/lighthouse.js.map +1 -0
  79. package/dist/collect/network.d.ts +32 -0
  80. package/dist/collect/network.d.ts.map +1 -0
  81. package/dist/collect/network.js +236 -0
  82. package/dist/collect/network.js.map +1 -0
  83. package/dist/collect/orchestrator.d.ts +23 -0
  84. package/dist/collect/orchestrator.d.ts.map +1 -0
  85. package/dist/collect/orchestrator.js +350 -0
  86. package/dist/collect/orchestrator.js.map +1 -0
  87. package/dist/collect/performance.d.ts +28 -0
  88. package/dist/collect/performance.d.ts.map +1 -0
  89. package/dist/collect/performance.js +108 -0
  90. package/dist/collect/performance.js.map +1 -0
  91. package/dist/collect/runtime.d.ts +26 -0
  92. package/dist/collect/runtime.d.ts.map +1 -0
  93. package/dist/collect/runtime.js +81 -0
  94. package/dist/collect/runtime.js.map +1 -0
  95. package/dist/collect/session.d.ts +58 -0
  96. package/dist/collect/session.d.ts.map +1 -0
  97. package/dist/collect/session.js +162 -0
  98. package/dist/collect/session.js.map +1 -0
  99. package/dist/collect/trace.d.ts +40 -0
  100. package/dist/collect/trace.d.ts.map +1 -0
  101. package/dist/collect/trace.js +127 -0
  102. package/dist/collect/trace.js.map +1 -0
  103. package/dist/collect/types.d.ts +317 -0
  104. package/dist/collect/types.d.ts.map +1 -0
  105. package/dist/collect/types.js +12 -0
  106. package/dist/collect/types.js.map +1 -0
  107. package/dist/distill/insights.d.ts +67 -0
  108. package/dist/distill/insights.d.ts.map +1 -0
  109. package/dist/distill/insights.js +317 -0
  110. package/dist/distill/insights.js.map +1 -0
  111. package/dist/distill/summaries.d.ts +71 -0
  112. package/dist/distill/summaries.d.ts.map +1 -0
  113. package/dist/distill/summaries.js +165 -0
  114. package/dist/distill/summaries.js.map +1 -0
  115. package/dist/extract/critical-path.d.ts +17 -0
  116. package/dist/extract/critical-path.d.ts.map +1 -0
  117. package/dist/extract/critical-path.js +95 -0
  118. package/dist/extract/critical-path.js.map +1 -0
  119. package/dist/extract/index.d.ts +16 -0
  120. package/dist/extract/index.d.ts.map +1 -0
  121. package/dist/extract/index.js +32 -0
  122. package/dist/extract/index.js.map +1 -0
  123. package/dist/extract/js-hotspots.d.ts +15 -0
  124. package/dist/extract/js-hotspots.d.ts.map +1 -0
  125. package/dist/extract/js-hotspots.js +22 -0
  126. package/dist/extract/js-hotspots.js.map +1 -0
  127. package/dist/extract/layout-shifts.d.ts +19 -0
  128. package/dist/extract/layout-shifts.d.ts.map +1 -0
  129. package/dist/extract/layout-shifts.js +47 -0
  130. package/dist/extract/layout-shifts.js.map +1 -0
  131. package/dist/extract/lcp-breakdown.d.ts +19 -0
  132. package/dist/extract/lcp-breakdown.d.ts.map +1 -0
  133. package/dist/extract/lcp-breakdown.js +110 -0
  134. package/dist/extract/lcp-breakdown.js.map +1 -0
  135. package/dist/extract/main-thread.d.ts +16 -0
  136. package/dist/extract/main-thread.d.ts.map +1 -0
  137. package/dist/extract/main-thread.js +41 -0
  138. package/dist/extract/main-thread.js.map +1 -0
  139. package/dist/extract/render-blocking.d.ts +16 -0
  140. package/dist/extract/render-blocking.d.ts.map +1 -0
  141. package/dist/extract/render-blocking.js +79 -0
  142. package/dist/extract/render-blocking.js.map +1 -0
  143. package/dist/extract/third-party.d.ts +15 -0
  144. package/dist/extract/third-party.d.ts.map +1 -0
  145. package/dist/extract/third-party.js +127 -0
  146. package/dist/extract/third-party.js.map +1 -0
  147. package/dist/extract/types.d.ts +183 -0
  148. package/dist/extract/types.d.ts.map +1 -0
  149. package/dist/extract/types.js +118 -0
  150. package/dist/extract/types.js.map +1 -0
  151. package/dist/index.d.ts +20 -0
  152. package/dist/index.d.ts.map +1 -0
  153. package/dist/index.js +188 -0
  154. package/dist/index.js.map +1 -0
  155. package/dist/mcp/handlers.d.ts +72 -0
  156. package/dist/mcp/handlers.d.ts.map +1 -0
  157. package/dist/mcp/handlers.js +285 -0
  158. package/dist/mcp/handlers.js.map +1 -0
  159. package/dist/mcp/progress.d.ts +37 -0
  160. package/dist/mcp/progress.d.ts.map +1 -0
  161. package/dist/mcp/progress.js +51 -0
  162. package/dist/mcp/progress.js.map +1 -0
  163. package/dist/mcp/prompts.d.ts +57 -0
  164. package/dist/mcp/prompts.d.ts.map +1 -0
  165. package/dist/mcp/prompts.js +225 -0
  166. package/dist/mcp/prompts.js.map +1 -0
  167. package/dist/mcp/resources.d.ts +48 -0
  168. package/dist/mcp/resources.d.ts.map +1 -0
  169. package/dist/mcp/resources.js +149 -0
  170. package/dist/mcp/resources.js.map +1 -0
  171. package/dist/mcp/server.d.ts +34 -0
  172. package/dist/mcp/server.d.ts.map +1 -0
  173. package/dist/mcp/server.js +452 -0
  174. package/dist/mcp/server.js.map +1 -0
  175. package/dist/mcp/types.d.ts +47 -0
  176. package/dist/mcp/types.d.ts.map +1 -0
  177. package/dist/mcp/types.js +67 -0
  178. package/dist/mcp/types.js.map +1 -0
  179. package/dist/normalize/clock.d.ts +40 -0
  180. package/dist/normalize/clock.d.ts.map +1 -0
  181. package/dist/normalize/clock.js +96 -0
  182. package/dist/normalize/clock.js.map +1 -0
  183. package/dist/normalize/dom-ir.d.ts +16 -0
  184. package/dist/normalize/dom-ir.d.ts.map +1 -0
  185. package/dist/normalize/dom-ir.js +48 -0
  186. package/dist/normalize/dom-ir.js.map +1 -0
  187. package/dist/normalize/index.d.ts +23 -0
  188. package/dist/normalize/index.d.ts.map +1 -0
  189. package/dist/normalize/index.js +118 -0
  190. package/dist/normalize/index.js.map +1 -0
  191. package/dist/normalize/lighthouse-insights.d.ts +27 -0
  192. package/dist/normalize/lighthouse-insights.d.ts.map +1 -0
  193. package/dist/normalize/lighthouse-insights.js +318 -0
  194. package/dist/normalize/lighthouse-insights.js.map +1 -0
  195. package/dist/normalize/lighthouse-ir.d.ts +25 -0
  196. package/dist/normalize/lighthouse-ir.d.ts.map +1 -0
  197. package/dist/normalize/lighthouse-ir.js +151 -0
  198. package/dist/normalize/lighthouse-ir.js.map +1 -0
  199. package/dist/normalize/network-ir.d.ts +23 -0
  200. package/dist/normalize/network-ir.d.ts.map +1 -0
  201. package/dist/normalize/network-ir.js +180 -0
  202. package/dist/normalize/network-ir.js.map +1 -0
  203. package/dist/normalize/runtime-ir.d.ts +18 -0
  204. package/dist/normalize/runtime-ir.d.ts.map +1 -0
  205. package/dist/normalize/runtime-ir.js +114 -0
  206. package/dist/normalize/runtime-ir.js.map +1 -0
  207. package/dist/normalize/trace-ir.d.ts +20 -0
  208. package/dist/normalize/trace-ir.d.ts.map +1 -0
  209. package/dist/normalize/trace-ir.js +224 -0
  210. package/dist/normalize/trace-ir.js.map +1 -0
  211. package/dist/normalize/types.d.ts +536 -0
  212. package/dist/normalize/types.d.ts.map +1 -0
  213. package/dist/normalize/types.js +242 -0
  214. package/dist/normalize/types.js.map +1 -0
  215. package/dist/output/manifest.d.ts +44 -0
  216. package/dist/output/manifest.d.ts.map +1 -0
  217. package/dist/output/manifest.js +232 -0
  218. package/dist/output/manifest.js.map +1 -0
  219. package/dist/output/toon.d.ts +19 -0
  220. package/dist/output/toon.d.ts.map +1 -0
  221. package/dist/output/toon.js +22 -0
  222. package/dist/output/toon.js.map +1 -0
  223. package/dist/output/writer.d.ts +31 -0
  224. package/dist/output/writer.d.ts.map +1 -0
  225. package/dist/output/writer.js +51 -0
  226. package/dist/output/writer.js.map +1 -0
  227. package/dist/report/analyzer.d.ts +29 -0
  228. package/dist/report/analyzer.d.ts.map +1 -0
  229. package/dist/report/analyzer.js +330 -0
  230. package/dist/report/analyzer.js.map +1 -0
  231. package/dist/report/index.d.ts +13 -0
  232. package/dist/report/index.d.ts.map +1 -0
  233. package/dist/report/index.js +12 -0
  234. package/dist/report/index.js.map +1 -0
  235. package/dist/report/markdown.d.ts +21 -0
  236. package/dist/report/markdown.d.ts.map +1 -0
  237. package/dist/report/markdown.js +182 -0
  238. package/dist/report/markdown.js.map +1 -0
  239. package/dist/report/remediations.d.ts +42 -0
  240. package/dist/report/remediations.d.ts.map +1 -0
  241. package/dist/report/remediations.js +179 -0
  242. package/dist/report/remediations.js.map +1 -0
  243. package/dist/report/scorer.d.ts +35 -0
  244. package/dist/report/scorer.d.ts.map +1 -0
  245. package/dist/report/scorer.js +72 -0
  246. package/dist/report/scorer.js.map +1 -0
  247. package/dist/report/types.d.ts +201 -0
  248. package/dist/report/types.d.ts.map +1 -0
  249. package/dist/report/types.js +149 -0
  250. package/dist/report/types.js.map +1 -0
  251. package/dist/shared/fs-utils.d.ts +12 -0
  252. package/dist/shared/fs-utils.d.ts.map +1 -0
  253. package/dist/shared/fs-utils.js +44 -0
  254. package/dist/shared/fs-utils.js.map +1 -0
  255. package/dist/shared/types.d.ts +69 -0
  256. package/dist/shared/types.d.ts.map +1 -0
  257. package/dist/shared/types.js +18 -0
  258. package/dist/shared/types.js.map +1 -0
  259. package/dist/shared/utils.d.ts +6 -0
  260. package/dist/shared/utils.d.ts.map +1 -0
  261. package/dist/shared/utils.js +9 -0
  262. package/dist/shared/utils.js.map +1 -0
  263. package/package.json +67 -0
@@ -0,0 +1,118 @@
1
+ /**
2
+ * DOMCollector — captures DOM structure metadata via page.evaluate().
3
+ *
4
+ * Extracts the following from the live page after navigation:
5
+ * - Total node count (elements, text nodes, comments)
6
+ * - Maximum DOM tree depth
7
+ * - Element type distribution (count per tag name)
8
+ * - Total text content length
9
+ *
10
+ * Uses page.evaluate() rather than CDP domains for lightweight introspection.
11
+ * Does NOT traverse the full DOM tree — collects aggregate stats only.
12
+ */
13
+ import {} from 'playwright';
14
+ export class DOMCollector {
15
+ page;
16
+ name = 'dom';
17
+ session = null;
18
+ /**
19
+ * @param page - Playwright Page instance used for evaluate() calls.
20
+ * The page reference is required because DOM stats are
21
+ * extracted via in-page JavaScript, not CDP commands.
22
+ */
23
+ constructor(page) {
24
+ this.page = page;
25
+ }
26
+ /**
27
+ * Start collecting DOM data.
28
+ * Currently a no-op — DOM snapshot is taken on stop() after navigation.
29
+ */
30
+ async start(session, _options) {
31
+ this.session = session;
32
+ }
33
+ /**
34
+ * Stop collecting and return DOM metadata.
35
+ * Runs page.evaluate() to extract aggregate DOM statistics.
36
+ */
37
+ async stop() {
38
+ const page = this.page;
39
+ try {
40
+ const result = await page.evaluate(() => {
41
+ let totalNodes = 0;
42
+ let maxDepth = 0;
43
+ const elementCounts = {};
44
+ /**
45
+ * Recursively walk the DOM tree counting nodes and tracking depth.
46
+ * Walks via childNodes to capture text nodes and comments too.
47
+ */
48
+ function walk(node, depth) {
49
+ // Count this node
50
+ totalNodes++;
51
+ if (depth > maxDepth)
52
+ maxDepth = depth;
53
+ // If it's an element, count its tag and recurse through children
54
+ if (node.nodeType === Node.ELEMENT_NODE) {
55
+ const el = node;
56
+ const tag = el.tagName.toLowerCase();
57
+ elementCounts[tag] = (elementCounts[tag] ?? 0) + 1;
58
+ // Recurse only through element children (children is live but
59
+ // we're reading sequentially, not mutating)
60
+ const children = el.children;
61
+ for (let i = 0; i < children.length; i++) {
62
+ walk(children[i], depth + 1);
63
+ }
64
+ }
65
+ // Count non-element children (text nodes, comments, etc.)
66
+ // These are found via childNodes but NOT recursed into since
67
+ // they cannot contain elements
68
+ if (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.DOCUMENT_NODE) {
69
+ const childNodes = node.childNodes;
70
+ for (let i = 0; i < childNodes.length; i++) {
71
+ const child = childNodes[i];
72
+ if (child.nodeType === Node.TEXT_NODE ||
73
+ child.nodeType === Node.COMMENT_NODE ||
74
+ child.nodeType === Node.CDATA_SECTION_NODE ||
75
+ child.nodeType === Node.PROCESSING_INSTRUCTION_NODE) {
76
+ totalNodes++;
77
+ }
78
+ }
79
+ }
80
+ }
81
+ // Start walking from body (document is above body/html which would
82
+ // double-count)
83
+ if (document.body) {
84
+ walk(document.body, 0);
85
+ }
86
+ const textContentLength = document.body?.textContent?.length ?? 0;
87
+ return {
88
+ totalNodes,
89
+ elementCount: elementCounts,
90
+ maxDepth,
91
+ textContentLength,
92
+ elementDistribution: elementCounts,
93
+ };
94
+ });
95
+ const distribution = result.elementDistribution;
96
+ return {
97
+ ok: true,
98
+ data: {
99
+ stats: {
100
+ totalNodes: result.totalNodes,
101
+ elementCount: Object.values(distribution).reduce((sum, n) => sum + n, 0),
102
+ maxDepth: result.maxDepth,
103
+ textContentLength: result.textContentLength,
104
+ },
105
+ elementDistribution: distribution,
106
+ warnings: [],
107
+ },
108
+ };
109
+ }
110
+ catch (error) {
111
+ return {
112
+ ok: false,
113
+ error: `DOMCollector: failed to collect DOM stats — ${String(error)}`,
114
+ };
115
+ }
116
+ }
117
+ }
118
+ //# sourceMappingURL=dom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom.js","sourceRoot":"","sources":["../../src/collect/dom.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * LighthouseCollector — runs a Lighthouse audit against the target URL.
3
+ *
4
+ * Unlike other collectors, Lighthouse manages its own browser instance via
5
+ * chrome-launcher. This collector does NOT participate in the normal CDP
6
+ * start/stop flow. Instead, call `runCollection(url)` directly from the
7
+ * orchestrator AFTER the CDP session's browser has been closed.
8
+ *
9
+ * This avoids interference between Lighthouse and CDP tracing/coverage.
10
+ */
11
+ import { type CDPSession } from 'playwright';
12
+ import type { Collector, CollectorResult, LighthouseRawData } from './types.js';
13
+ import type { CollectorRunOptions } from '../shared/types.js';
14
+ export declare class LighthouseCollector implements Collector {
15
+ readonly name = "lighthouse";
16
+ /** Categories to include in every Lighthouse run */
17
+ private readonly defaultCategories;
18
+ /**
19
+ * Start is a no-op because Lighthouse manages its own browser.
20
+ * Use runCollection() instead.
21
+ */
22
+ start(_session: CDPSession, _options?: CollectorRunOptions): Promise<void>;
23
+ /**
24
+ * Stop is a no-op because Lighthouse manages its own lifecycle.
25
+ * Use runCollection() instead.
26
+ */
27
+ stop(): Promise<CollectorResult<LighthouseRawData>>;
28
+ /**
29
+ * Execute a full Lighthouse audit.
30
+ *
31
+ * When `cdpPort` is provided, connects to an existing Chrome instance
32
+ * (e.g. the Playwright browser used for CDP collection). Otherwise
33
+ * launches its own headless Chrome instance via chrome-launcher.
34
+ *
35
+ * @param url - Target URL to audit
36
+ * @param cdpPort - Optional CDP debugging port of an existing Chrome instance
37
+ * @returns CollectorResult with full Lighthouse result
38
+ */
39
+ runCollection(url: string, cdpPort?: number): Promise<CollectorResult<LighthouseRawData>>;
40
+ }
41
+ //# sourceMappingURL=lighthouse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lighthouse.d.ts","sourceRoot":"","sources":["../../src/collect/lighthouse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,iBAAiB,EAAsB,MAAM,YAAY,CAAC;AACpG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,qBAAa,mBAAoB,YAAW,SAAS;IACnD,QAAQ,CAAC,IAAI,gBAAgB;IAE7B,oDAAoD;IACpD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAKhC;IAEF;;;OAGG;IACG,KAAK,CAAC,QAAQ,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhF;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC;IAOzD;;;;;;;;;;OAUG;IACG,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC;CA8DhG"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * LighthouseCollector — runs a Lighthouse audit against the target URL.
3
+ *
4
+ * Unlike other collectors, Lighthouse manages its own browser instance via
5
+ * chrome-launcher. This collector does NOT participate in the normal CDP
6
+ * start/stop flow. Instead, call `runCollection(url)` directly from the
7
+ * orchestrator AFTER the CDP session's browser has been closed.
8
+ *
9
+ * This avoids interference between Lighthouse and CDP tracing/coverage.
10
+ */
11
+ import {} from 'playwright';
12
+ import { launch as launchChrome } from 'chrome-launcher';
13
+ import lighthouse from 'lighthouse';
14
+ export class LighthouseCollector {
15
+ name = 'lighthouse';
16
+ /** Categories to include in every Lighthouse run */
17
+ defaultCategories = [
18
+ 'performance',
19
+ 'accessibility',
20
+ 'best-practices',
21
+ 'seo',
22
+ ];
23
+ /**
24
+ * Start is a no-op because Lighthouse manages its own browser.
25
+ * Use runCollection() instead.
26
+ */
27
+ async start(_session, _options) {
28
+ // No-op — Lighthouse manages its own browser lifecycle
29
+ }
30
+ /**
31
+ * Stop is a no-op because Lighthouse manages its own lifecycle.
32
+ * Use runCollection() instead.
33
+ */
34
+ async stop() {
35
+ return {
36
+ ok: false,
37
+ error: 'LighthouseCollector: use runCollection() instead of stop()',
38
+ };
39
+ }
40
+ /**
41
+ * Execute a full Lighthouse audit.
42
+ *
43
+ * When `cdpPort` is provided, connects to an existing Chrome instance
44
+ * (e.g. the Playwright browser used for CDP collection). Otherwise
45
+ * launches its own headless Chrome instance via chrome-launcher.
46
+ *
47
+ * @param url - Target URL to audit
48
+ * @param cdpPort - Optional CDP debugging port of an existing Chrome instance
49
+ * @returns CollectorResult with full Lighthouse result
50
+ */
51
+ async runCollection(url, cdpPort) {
52
+ let chrome = null;
53
+ try {
54
+ const flags = {
55
+ port: 0,
56
+ output: 'json',
57
+ onlyCategories: this.defaultCategories,
58
+ };
59
+ if (cdpPort !== undefined) {
60
+ // Connect to an existing browser instance (Option C — same Chrome as CDP collectors)
61
+ flags.port = cdpPort;
62
+ }
63
+ else {
64
+ // Fallback: launch a dedicated Chrome instance for Lighthouse
65
+ chrome = await launchChrome({
66
+ chromeFlags: [
67
+ '--headless',
68
+ '--no-sandbox',
69
+ '--disable-setuid-sandbox',
70
+ '--disable-gpu',
71
+ '--disable-dev-shm-usage',
72
+ ],
73
+ });
74
+ flags.port = chrome.port;
75
+ }
76
+ const result = await lighthouse(url, flags);
77
+ if (!result) {
78
+ return { ok: false, error: 'LighthouseCollector: Lighthouse returned no result' };
79
+ }
80
+ // The LHR may be a string (JSON) or already an object depending on
81
+ // the output flag. We handle both.
82
+ const lhr = typeof result.lhr === 'string' ? JSON.parse(result.lhr) : result.lhr;
83
+ return {
84
+ ok: true,
85
+ data: {
86
+ lhr,
87
+ categories: this.defaultCategories,
88
+ warnings: [],
89
+ },
90
+ };
91
+ }
92
+ catch (error) {
93
+ return {
94
+ ok: false,
95
+ error: `LighthouseCollector: ${String(error)}`,
96
+ };
97
+ }
98
+ finally {
99
+ // Always clean up the browser
100
+ if (chrome) {
101
+ try {
102
+ await chrome.kill();
103
+ }
104
+ catch {
105
+ // Best-effort cleanup
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ //# sourceMappingURL=lighthouse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lighthouse.js","sourceRoot":"","sources":["../../src/collect/lighthouse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAmB,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,MAAM,IAAI,YAAY,EAAuB,MAAM,iBAAiB,CAAC;AAC9E,OAAO,UAAU,MAAM,YAAY,CAAC;AAIpC,MAAM,OAAO,mBAAmB;IACrB,IAAI,GAAG,YAAY,CAAC;IAE7B,oDAAoD;IACnC,iBAAiB,GAAyB;QACzD,aAAa;QACb,eAAe;QACf,gBAAgB;QAChB,KAAK;KACN,CAAC;IAEF;;;OAGG;IACH,KAAK,CAAC,KAAK,CAAC,QAAoB,EAAE,QAA8B;QAC9D,uDAAuD;IACzD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI;QACR,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,4DAA4D;SACpE,CAAC;IACJ,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,aAAa,CAAC,GAAW,EAAE,OAAgB;QAC/C,IAAI,MAAM,GAA0B,IAAI,CAAC;QAEzC,IAAI,CAAC;YACH,MAAM,KAAK,GAA2E;gBACpF,IAAI,EAAE,CAAC;gBACP,MAAM,EAAE,MAAM;gBACd,cAAc,EAAE,IAAI,CAAC,iBAAiB;aACvC,CAAC;YAEF,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC1B,qFAAqF;gBACrF,KAAK,CAAC,IAAI,GAAG,OAAO,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACN,8DAA8D;gBAC9D,MAAM,GAAG,MAAM,YAAY,CAAC;oBAC1B,WAAW,EAAE;wBACX,YAAY;wBACZ,cAAc;wBACd,0BAA0B;wBAC1B,eAAe;wBACf,yBAAyB;qBAC1B;iBACF,CAAC,CAAC;gBACH,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YAC3B,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAE5C,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,oDAAoD,EAAE,CAAC;YACpF,CAAC;YAED,mEAAmE;YACnE,mCAAmC;YACnC,MAAM,GAAG,GACP,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;YAEvE,OAAO;gBACL,EAAE,EAAE,IAAI;gBACR,IAAI,EAAE;oBACJ,GAAG;oBACH,UAAU,EAAE,IAAI,CAAC,iBAAiB;oBAClC,QAAQ,EAAE,EAAE;iBACb;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,wBAAwB,MAAM,CAAC,KAAK,CAAC,EAAE;aAC/C,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,8BAA8B;YAC9B,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,CAAC;oBACH,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBACtB,CAAC;gBAAC,MAAM,CAAC;oBACP,sBAAsB;gBACxB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * NetworkCollector — captures HTTP request/response data via the CDP Network domain.
3
+ *
4
+ * Enables the Network domain and listens for:
5
+ * - Network.requestWillBeSent (request metadata + redirect tracking)
6
+ * - Network.responseReceived (response metadata + timing)
7
+ * - Network.loadingFailed (failure information)
8
+ * - Network.requestServedFromCache
9
+ *
10
+ * Correlates requests and responses by CDP requestId.
11
+ */
12
+ import { type CDPSession } from 'playwright';
13
+ import type { Collector, CollectorResult } from './types.js';
14
+ import type { NetworkRawData } from './types.js';
15
+ import type { CollectorRunOptions } from '../shared/types.js';
16
+ export declare class NetworkCollector implements Collector {
17
+ #private;
18
+ readonly name = "network";
19
+ private session;
20
+ /** Map of requestId -> entry (covers redirect chains) */
21
+ private requestMap;
22
+ /** Maintain insertion order for chronological output */
23
+ private requestOrder;
24
+ private requestCount;
25
+ private failedCount;
26
+ private startTime;
27
+ private endTime;
28
+ private collected;
29
+ start(session: CDPSession, _options?: CollectorRunOptions): Promise<void>;
30
+ stop(): Promise<CollectorResult<NetworkRawData>>;
31
+ }
32
+ //# sourceMappingURL=network.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/collect/network.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAsC,MAAM,YAAY,CAAC;AACrF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAyG9D,qBAAa,gBAAiB,YAAW,SAAS;;IAChD,QAAQ,CAAC,IAAI,aAAa;IAE1B,OAAO,CAAC,OAAO,CAA2B;IAC1C,yDAAyD;IACzD,OAAO,CAAC,UAAU,CAA0C;IAC5D,wDAAwD;IACxD,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,SAAS,CAAS;IAEpB,KAAK,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmCzE,IAAI,IAAI,OAAO,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC;CA4LvD"}
@@ -0,0 +1,236 @@
1
+ /**
2
+ * NetworkCollector — captures HTTP request/response data via the CDP Network domain.
3
+ *
4
+ * Enables the Network domain and listens for:
5
+ * - Network.requestWillBeSent (request metadata + redirect tracking)
6
+ * - Network.responseReceived (response metadata + timing)
7
+ * - Network.loadingFailed (failure information)
8
+ * - Network.requestServedFromCache
9
+ *
10
+ * Correlates requests and responses by CDP requestId.
11
+ */
12
+ import {} from 'playwright';
13
+ // ---------------------------------------------------------------------------
14
+ /**
15
+ * Validate that collected network data contains at least some expected entries.
16
+ *
17
+ * @param entries - Array of collected network request entries
18
+ * @returns Array of warning strings
19
+ */
20
+ function validateNetworkData(entries) {
21
+ const warnings = [];
22
+ if (entries.length === 0) {
23
+ warnings.push('No network requests were captured — page may not have loaded.');
24
+ }
25
+ const documentRequests = entries.filter((e) => e.type === 'Document');
26
+ if (documentRequests.length === 0) {
27
+ warnings.push('No document (main-frame) request found in network data.');
28
+ }
29
+ const failedEntries = entries.filter((e) => e.failed);
30
+ if (failedEntries.length > 0) {
31
+ const failedUrls = failedEntries.map((e) => e.url).slice(0, 5);
32
+ warnings.push(`${failedEntries.length} network request(s) failed. First failures: ${failedUrls.join(', ')}`);
33
+ }
34
+ return warnings;
35
+ }
36
+ export class NetworkCollector {
37
+ name = 'network';
38
+ session = null;
39
+ /** Map of requestId -> entry (covers redirect chains) */
40
+ requestMap = new Map();
41
+ /** Maintain insertion order for chronological output */
42
+ requestOrder = [];
43
+ requestCount = 0;
44
+ failedCount = 0;
45
+ startTime = 0;
46
+ endTime = 0;
47
+ collected = false;
48
+ async start(session, _options) {
49
+ this.session = session;
50
+ this.requestMap.clear();
51
+ this.requestOrder = [];
52
+ this.requestCount = 0;
53
+ this.failedCount = 0;
54
+ this.startTime = 0;
55
+ this.endTime = 0;
56
+ this.collected = false;
57
+ // Register CDP event listeners (cast to unknown to bypass strict typed overloads)
58
+ session.on('Network.requestWillBeSent', this.#onRequestWillBeSent.bind(this));
59
+ session.on('Network.responseReceived', this.#onResponseReceived.bind(this));
60
+ session.on('Network.loadingFailed', this.#onLoadingFailed.bind(this));
61
+ session.on('Network.requestServedFromCache', this.#onRequestServedFromCache.bind(this));
62
+ // Enable the Network domain
63
+ await session.send('Network.enable', {
64
+ maxTotalBufferSize: 10_000_000,
65
+ maxResourceBufferSize: 5_000_000,
66
+ });
67
+ }
68
+ async stop() {
69
+ this.collected = true;
70
+ if (!this.session) {
71
+ return { ok: false, error: 'NetworkCollector: session not initialized' };
72
+ }
73
+ const warnings = [];
74
+ try {
75
+ // Disable the Network domain to stop receiving events
76
+ await this.session.send('Network.disable');
77
+ }
78
+ catch (error) {
79
+ warnings.push(`NetworkCollector: error disabling Network domain — ${String(error)}`);
80
+ }
81
+ // Build ordered array of entries
82
+ const requests = [];
83
+ for (const id of this.requestOrder) {
84
+ const entry = this.requestMap.get(id);
85
+ if (entry) {
86
+ requests.push(entry);
87
+ }
88
+ }
89
+ // Calculate metadata
90
+ const totalRequests = requests.length;
91
+ const totalFailed = requests.filter((r) => r.failed).length;
92
+ // Collect total bytes from completed responses
93
+ let totalBytes = 0;
94
+ for (const r of requests) {
95
+ if (r.response) {
96
+ totalBytes += r.response.encodedDataLength;
97
+ }
98
+ }
99
+ // Run completeness validation
100
+ const validationWarnings = validateNetworkData(requests);
101
+ warnings.push(...validationWarnings);
102
+ return {
103
+ ok: true,
104
+ data: {
105
+ requests,
106
+ metadata: {
107
+ totalRequests,
108
+ totalFailed,
109
+ totalBytes,
110
+ startTime: this.startTime,
111
+ endTime: this.endTime,
112
+ },
113
+ warnings,
114
+ },
115
+ };
116
+ }
117
+ /**
118
+ * Handle Network.requestWillBeSent — captures request metadata.
119
+ * The CDP payload nests url/method/headers inside `request`.
120
+ * For redirects, updates the existing entry and stores redirect info.
121
+ */
122
+ #onRequestWillBeSent(raw) {
123
+ const { requestId, request: req, type, timestamp, wallTime, initiator, redirectResponse } = raw;
124
+ if (this.startTime === 0 || timestamp < this.startTime) {
125
+ this.startTime = timestamp;
126
+ }
127
+ this.endTime = Math.max(this.endTime, timestamp);
128
+ // Check if this is a new request or part of a redirect chain
129
+ const existing = this.requestMap.get(requestId);
130
+ if (existing) {
131
+ // This is a redirect — save the redirect response and update entry
132
+ if (redirectResponse) {
133
+ existing.redirectChain = existing.redirectChain ?? [];
134
+ existing.redirectChain.push({
135
+ url: redirectResponse.url,
136
+ status: redirectResponse.status,
137
+ statusText: redirectResponse.statusText,
138
+ headers: redirectResponse.headers,
139
+ timing: redirectResponse.timing,
140
+ encodedDataLength: redirectResponse.encodedDataLength,
141
+ });
142
+ }
143
+ // Update the entry with final request data
144
+ existing.url = req.url;
145
+ existing.method = req.method;
146
+ existing.type = type ?? existing.type;
147
+ existing.timestamp = timestamp;
148
+ existing.wallTime = wallTime ?? existing.wallTime;
149
+ existing.request = {
150
+ headers: req.headers,
151
+ postData: req.postData,
152
+ initialPriority: req.initialPriority,
153
+ referrerPolicy: req.referrerPolicy,
154
+ };
155
+ if (initiator) {
156
+ existing.initiator = initiator;
157
+ }
158
+ }
159
+ else {
160
+ // New request
161
+ const entry = {
162
+ requestId,
163
+ url: req.url,
164
+ method: req.method,
165
+ type,
166
+ request: {
167
+ headers: req.headers,
168
+ postData: req.postData,
169
+ initialPriority: req.initialPriority,
170
+ referrerPolicy: req.referrerPolicy,
171
+ },
172
+ timestamp,
173
+ wallTime,
174
+ initiator: initiator,
175
+ };
176
+ this.requestMap.set(requestId, entry);
177
+ this.requestOrder.push(requestId);
178
+ this.requestCount++;
179
+ }
180
+ }
181
+ /**
182
+ * Handle Network.responseReceived — captures response metadata.
183
+ */
184
+ #onResponseReceived(raw) {
185
+ const { requestId, type, response: res } = raw;
186
+ const entry = this.requestMap.get(requestId);
187
+ if (!entry) {
188
+ return; // May happen if request started before Network.enable
189
+ }
190
+ // Update type from response (more reliable than requestWillBeSent's type)
191
+ entry.type = type ?? entry.type;
192
+ // Fill in response data
193
+ entry.response = {
194
+ status: res.status,
195
+ statusText: res.statusText,
196
+ headers: res.headers,
197
+ mimeType: res.mimeType,
198
+ timing: res.timing,
199
+ fromDiskCache: res.fromDiskCache,
200
+ fromServiceWorker: res.fromServiceWorker,
201
+ encodedDataLength: res.encodedDataLength,
202
+ responseTime: res.responseTime,
203
+ protocol: res.protocol,
204
+ remoteIPAddress: res.remoteIPAddress,
205
+ remotePort: res.remotePort,
206
+ };
207
+ }
208
+ /**
209
+ * Handle Network.loadingFailed — captures failure information.
210
+ */
211
+ #onLoadingFailed(raw) {
212
+ const { requestId, type, errorText, canceled, blockedReason, timestamp } = raw;
213
+ const entry = this.requestMap.get(requestId);
214
+ if (!entry) {
215
+ return;
216
+ }
217
+ entry.failed = true;
218
+ entry.errorText = errorText;
219
+ entry.canceled = canceled;
220
+ entry.blockedReason = blockedReason;
221
+ entry.type = type ?? entry.type;
222
+ this.failedCount++;
223
+ this.endTime = Math.max(this.endTime, timestamp);
224
+ }
225
+ /**
226
+ * Handle Network.requestServedFromCache — marks cache-served requests.
227
+ */
228
+ #onRequestServedFromCache(raw) {
229
+ const entry = this.requestMap.get(raw.requestId);
230
+ if (!entry) {
231
+ return;
232
+ }
233
+ entry.fromCache = true;
234
+ }
235
+ }
236
+ //# sourceMappingURL=network.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/collect/network.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Collector orchestrator.
3
+ *
4
+ * Coordinates the full collection lifecycle for a single run:
5
+ * 1. Validate URL
6
+ * 2. Launch browser + create CDP session
7
+ * 3. Run each active collector in the correct order
8
+ * 4. Write results to the output directory
9
+ * 5. Clean up browser
10
+ * 6. Run Lighthouse audit (separate browser, after CDP session closes)
11
+ *
12
+ * Designed for multi-run support: `run()` wraps `runOnce()`.
13
+ */
14
+ import type { CollectorRunOptions, RunResult } from '../shared/types.js';
15
+ /**
16
+ * Run one or more collection runs against the given URL.
17
+ *
18
+ * @param url - Target URL to collect data from
19
+ * @param partialOptions - Partial options (merged with defaults)
20
+ * @returns Array of RunResult — one per run
21
+ */
22
+ export declare function run(url: string, partialOptions?: Partial<CollectorRunOptions>): Promise<RunResult[]>;
23
+ //# sourceMappingURL=orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/collect/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAqTzE;;;;;;GAMG;AACH,wBAAsB,GAAG,CACvB,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAC5C,OAAO,CAAC,SAAS,EAAE,CAAC,CA8EtB"}