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.
- package/LICENSE +21 -0
- package/README.md +280 -0
- package/dist/causal/builder.d.ts +34 -0
- package/dist/causal/builder.d.ts.map +1 -0
- package/dist/causal/builder.js +132 -0
- package/dist/causal/builder.js.map +1 -0
- package/dist/causal/index.d.ts +11 -0
- package/dist/causal/index.d.ts.map +1 -0
- package/dist/causal/index.js +10 -0
- package/dist/causal/index.js.map +1 -0
- package/dist/causal/rules/js.d.ts +49 -0
- package/dist/causal/rules/js.d.ts.map +1 -0
- package/dist/causal/rules/js.js +209 -0
- package/dist/causal/rules/js.js.map +1 -0
- package/dist/causal/rules/layout.d.ts +39 -0
- package/dist/causal/rules/layout.d.ts.map +1 -0
- package/dist/causal/rules/layout.js +169 -0
- package/dist/causal/rules/layout.js.map +1 -0
- package/dist/causal/rules/lcp.d.ts +49 -0
- package/dist/causal/rules/lcp.d.ts.map +1 -0
- package/dist/causal/rules/lcp.js +250 -0
- package/dist/causal/rules/lcp.js.map +1 -0
- package/dist/causal/rules/network.d.ts +39 -0
- package/dist/causal/rules/network.d.ts.map +1 -0
- package/dist/causal/rules/network.js +140 -0
- package/dist/causal/rules/network.js.map +1 -0
- package/dist/causal/types.d.ts +142 -0
- package/dist/causal/types.d.ts.map +1 -0
- package/dist/causal/types.js +88 -0
- package/dist/causal/types.js.map +1 -0
- package/dist/cli/analyze.d.ts +33 -0
- package/dist/cli/analyze.d.ts.map +1 -0
- package/dist/cli/analyze.js +137 -0
- package/dist/cli/analyze.js.map +1 -0
- package/dist/cli/collect.d.ts +28 -0
- package/dist/cli/collect.d.ts.map +1 -0
- package/dist/cli/collect.js +125 -0
- package/dist/cli/collect.js.map +1 -0
- package/dist/cli/extract.d.ts +31 -0
- package/dist/cli/extract.d.ts.map +1 -0
- package/dist/cli/extract.js +135 -0
- package/dist/cli/extract.js.map +1 -0
- package/dist/cli/mcp.d.ts +14 -0
- package/dist/cli/mcp.d.ts.map +1 -0
- package/dist/cli/mcp.js +53 -0
- package/dist/cli/mcp.js.map +1 -0
- package/dist/cli/normalize.d.ts +58 -0
- package/dist/cli/normalize.d.ts.map +1 -0
- package/dist/cli/normalize.js +179 -0
- package/dist/cli/normalize.js.map +1 -0
- package/dist/cli/report.d.ts +33 -0
- package/dist/cli/report.d.ts.map +1 -0
- package/dist/cli/report.js +137 -0
- package/dist/cli/report.js.map +1 -0
- package/dist/cli/run.d.ts +49 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +243 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/collect/buffer-monitor.d.ts +25 -0
- package/dist/collect/buffer-monitor.d.ts.map +1 -0
- package/dist/collect/buffer-monitor.js +69 -0
- package/dist/collect/buffer-monitor.js.map +1 -0
- package/dist/collect/console.d.ts +25 -0
- package/dist/collect/console.d.ts.map +1 -0
- package/dist/collect/console.js +82 -0
- package/dist/collect/console.js.map +1 -0
- package/dist/collect/coverage.d.ts +26 -0
- package/dist/collect/coverage.d.ts.map +1 -0
- package/dist/collect/coverage.js +99 -0
- package/dist/collect/coverage.js.map +1 -0
- package/dist/collect/dom.d.ts +37 -0
- package/dist/collect/dom.d.ts.map +1 -0
- package/dist/collect/dom.js +118 -0
- package/dist/collect/dom.js.map +1 -0
- package/dist/collect/lighthouse.d.ts +41 -0
- package/dist/collect/lighthouse.d.ts.map +1 -0
- package/dist/collect/lighthouse.js +111 -0
- package/dist/collect/lighthouse.js.map +1 -0
- package/dist/collect/network.d.ts +32 -0
- package/dist/collect/network.d.ts.map +1 -0
- package/dist/collect/network.js +236 -0
- package/dist/collect/network.js.map +1 -0
- package/dist/collect/orchestrator.d.ts +23 -0
- package/dist/collect/orchestrator.d.ts.map +1 -0
- package/dist/collect/orchestrator.js +350 -0
- package/dist/collect/orchestrator.js.map +1 -0
- package/dist/collect/performance.d.ts +28 -0
- package/dist/collect/performance.d.ts.map +1 -0
- package/dist/collect/performance.js +108 -0
- package/dist/collect/performance.js.map +1 -0
- package/dist/collect/runtime.d.ts +26 -0
- package/dist/collect/runtime.d.ts.map +1 -0
- package/dist/collect/runtime.js +81 -0
- package/dist/collect/runtime.js.map +1 -0
- package/dist/collect/session.d.ts +58 -0
- package/dist/collect/session.d.ts.map +1 -0
- package/dist/collect/session.js +162 -0
- package/dist/collect/session.js.map +1 -0
- package/dist/collect/trace.d.ts +40 -0
- package/dist/collect/trace.d.ts.map +1 -0
- package/dist/collect/trace.js +127 -0
- package/dist/collect/trace.js.map +1 -0
- package/dist/collect/types.d.ts +317 -0
- package/dist/collect/types.d.ts.map +1 -0
- package/dist/collect/types.js +12 -0
- package/dist/collect/types.js.map +1 -0
- package/dist/distill/insights.d.ts +67 -0
- package/dist/distill/insights.d.ts.map +1 -0
- package/dist/distill/insights.js +317 -0
- package/dist/distill/insights.js.map +1 -0
- package/dist/distill/summaries.d.ts +71 -0
- package/dist/distill/summaries.d.ts.map +1 -0
- package/dist/distill/summaries.js +165 -0
- package/dist/distill/summaries.js.map +1 -0
- package/dist/extract/critical-path.d.ts +17 -0
- package/dist/extract/critical-path.d.ts.map +1 -0
- package/dist/extract/critical-path.js +95 -0
- package/dist/extract/critical-path.js.map +1 -0
- package/dist/extract/index.d.ts +16 -0
- package/dist/extract/index.d.ts.map +1 -0
- package/dist/extract/index.js +32 -0
- package/dist/extract/index.js.map +1 -0
- package/dist/extract/js-hotspots.d.ts +15 -0
- package/dist/extract/js-hotspots.d.ts.map +1 -0
- package/dist/extract/js-hotspots.js +22 -0
- package/dist/extract/js-hotspots.js.map +1 -0
- package/dist/extract/layout-shifts.d.ts +19 -0
- package/dist/extract/layout-shifts.d.ts.map +1 -0
- package/dist/extract/layout-shifts.js +47 -0
- package/dist/extract/layout-shifts.js.map +1 -0
- package/dist/extract/lcp-breakdown.d.ts +19 -0
- package/dist/extract/lcp-breakdown.d.ts.map +1 -0
- package/dist/extract/lcp-breakdown.js +110 -0
- package/dist/extract/lcp-breakdown.js.map +1 -0
- package/dist/extract/main-thread.d.ts +16 -0
- package/dist/extract/main-thread.d.ts.map +1 -0
- package/dist/extract/main-thread.js +41 -0
- package/dist/extract/main-thread.js.map +1 -0
- package/dist/extract/render-blocking.d.ts +16 -0
- package/dist/extract/render-blocking.d.ts.map +1 -0
- package/dist/extract/render-blocking.js +79 -0
- package/dist/extract/render-blocking.js.map +1 -0
- package/dist/extract/third-party.d.ts +15 -0
- package/dist/extract/third-party.d.ts.map +1 -0
- package/dist/extract/third-party.js +127 -0
- package/dist/extract/third-party.js.map +1 -0
- package/dist/extract/types.d.ts +183 -0
- package/dist/extract/types.d.ts.map +1 -0
- package/dist/extract/types.js +118 -0
- package/dist/extract/types.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +188 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/handlers.d.ts +72 -0
- package/dist/mcp/handlers.d.ts.map +1 -0
- package/dist/mcp/handlers.js +285 -0
- package/dist/mcp/handlers.js.map +1 -0
- package/dist/mcp/progress.d.ts +37 -0
- package/dist/mcp/progress.d.ts.map +1 -0
- package/dist/mcp/progress.js +51 -0
- package/dist/mcp/progress.js.map +1 -0
- package/dist/mcp/prompts.d.ts +57 -0
- package/dist/mcp/prompts.d.ts.map +1 -0
- package/dist/mcp/prompts.js +225 -0
- package/dist/mcp/prompts.js.map +1 -0
- package/dist/mcp/resources.d.ts +48 -0
- package/dist/mcp/resources.d.ts.map +1 -0
- package/dist/mcp/resources.js +149 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/server.d.ts +34 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +452 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/types.d.ts +47 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +67 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/normalize/clock.d.ts +40 -0
- package/dist/normalize/clock.d.ts.map +1 -0
- package/dist/normalize/clock.js +96 -0
- package/dist/normalize/clock.js.map +1 -0
- package/dist/normalize/dom-ir.d.ts +16 -0
- package/dist/normalize/dom-ir.d.ts.map +1 -0
- package/dist/normalize/dom-ir.js +48 -0
- package/dist/normalize/dom-ir.js.map +1 -0
- package/dist/normalize/index.d.ts +23 -0
- package/dist/normalize/index.d.ts.map +1 -0
- package/dist/normalize/index.js +118 -0
- package/dist/normalize/index.js.map +1 -0
- package/dist/normalize/lighthouse-insights.d.ts +27 -0
- package/dist/normalize/lighthouse-insights.d.ts.map +1 -0
- package/dist/normalize/lighthouse-insights.js +318 -0
- package/dist/normalize/lighthouse-insights.js.map +1 -0
- package/dist/normalize/lighthouse-ir.d.ts +25 -0
- package/dist/normalize/lighthouse-ir.d.ts.map +1 -0
- package/dist/normalize/lighthouse-ir.js +151 -0
- package/dist/normalize/lighthouse-ir.js.map +1 -0
- package/dist/normalize/network-ir.d.ts +23 -0
- package/dist/normalize/network-ir.d.ts.map +1 -0
- package/dist/normalize/network-ir.js +180 -0
- package/dist/normalize/network-ir.js.map +1 -0
- package/dist/normalize/runtime-ir.d.ts +18 -0
- package/dist/normalize/runtime-ir.d.ts.map +1 -0
- package/dist/normalize/runtime-ir.js +114 -0
- package/dist/normalize/runtime-ir.js.map +1 -0
- package/dist/normalize/trace-ir.d.ts +20 -0
- package/dist/normalize/trace-ir.d.ts.map +1 -0
- package/dist/normalize/trace-ir.js +224 -0
- package/dist/normalize/trace-ir.js.map +1 -0
- package/dist/normalize/types.d.ts +536 -0
- package/dist/normalize/types.d.ts.map +1 -0
- package/dist/normalize/types.js +242 -0
- package/dist/normalize/types.js.map +1 -0
- package/dist/output/manifest.d.ts +44 -0
- package/dist/output/manifest.d.ts.map +1 -0
- package/dist/output/manifest.js +232 -0
- package/dist/output/manifest.js.map +1 -0
- package/dist/output/toon.d.ts +19 -0
- package/dist/output/toon.d.ts.map +1 -0
- package/dist/output/toon.js +22 -0
- package/dist/output/toon.js.map +1 -0
- package/dist/output/writer.d.ts +31 -0
- package/dist/output/writer.d.ts.map +1 -0
- package/dist/output/writer.js +51 -0
- package/dist/output/writer.js.map +1 -0
- package/dist/report/analyzer.d.ts +29 -0
- package/dist/report/analyzer.d.ts.map +1 -0
- package/dist/report/analyzer.js +330 -0
- package/dist/report/analyzer.js.map +1 -0
- package/dist/report/index.d.ts +13 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/index.js +12 -0
- package/dist/report/index.js.map +1 -0
- package/dist/report/markdown.d.ts +21 -0
- package/dist/report/markdown.d.ts.map +1 -0
- package/dist/report/markdown.js +182 -0
- package/dist/report/markdown.js.map +1 -0
- package/dist/report/remediations.d.ts +42 -0
- package/dist/report/remediations.d.ts.map +1 -0
- package/dist/report/remediations.js +179 -0
- package/dist/report/remediations.js.map +1 -0
- package/dist/report/scorer.d.ts +35 -0
- package/dist/report/scorer.d.ts.map +1 -0
- package/dist/report/scorer.js +72 -0
- package/dist/report/scorer.js.map +1 -0
- package/dist/report/types.d.ts +201 -0
- package/dist/report/types.d.ts.map +1 -0
- package/dist/report/types.js +149 -0
- package/dist/report/types.js.map +1 -0
- package/dist/shared/fs-utils.d.ts +12 -0
- package/dist/shared/fs-utils.d.ts.map +1 -0
- package/dist/shared/fs-utils.js +44 -0
- package/dist/shared/fs-utils.js.map +1 -0
- package/dist/shared/types.d.ts +69 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +18 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/shared/utils.d.ts +6 -0
- package/dist/shared/utils.d.ts.map +1 -0
- package/dist/shared/utils.js +9 -0
- package/dist/shared/utils.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CDP session manager.
|
|
3
|
+
*
|
|
4
|
+
* Launches a headless Chromium instance via Playwright and establishes a
|
|
5
|
+
* raw CDP session for sending Chrome DevTools Protocol commands.
|
|
6
|
+
*/
|
|
7
|
+
import { type Browser, type BrowserContext, type Page, type CDPSession, type BrowserServer } from 'playwright';
|
|
8
|
+
/** The result of launching a browser and creating a CDP session */
|
|
9
|
+
export interface BrowserSession {
|
|
10
|
+
/** The Playwright Browser instance */
|
|
11
|
+
browser: Browser;
|
|
12
|
+
/** The BrowserContext (isolated session) */
|
|
13
|
+
context: BrowserContext;
|
|
14
|
+
/** The Page that was opened */
|
|
15
|
+
page: Page;
|
|
16
|
+
/** Raw CDP session bound to the page */
|
|
17
|
+
cdp: CDPSession;
|
|
18
|
+
/** CDP debugging port for connecting external tools (e.g. Lighthouse) */
|
|
19
|
+
cdpPort?: number;
|
|
20
|
+
/** Browser server instance (when using launchServer) */
|
|
21
|
+
browserServer?: BrowserServer;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Launch a headless Chromium instance, create a new page, and establish a
|
|
25
|
+
* raw CDP session.
|
|
26
|
+
*
|
|
27
|
+
* @param timeoutMs - Timeout for browser launch (default: 30_000)
|
|
28
|
+
* @returns A BrowserSession with browser, context, page, and CDP session
|
|
29
|
+
*/
|
|
30
|
+
export declare function launchBrowser(timeoutMs?: number): Promise<BrowserSession>;
|
|
31
|
+
/**
|
|
32
|
+
* Safely close a browser instance.
|
|
33
|
+
* Logs but does not propagate any errors during cleanup.
|
|
34
|
+
*
|
|
35
|
+
* @param browser - The Browser instance to close
|
|
36
|
+
*/
|
|
37
|
+
export declare function closeBrowser(browser: Browser): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Launch a headless Chromium instance with an exposed CDP debugging port.
|
|
40
|
+
*
|
|
41
|
+
* Unlike the basic `launchBrowser()`, this starts Chrome with
|
|
42
|
+
* `--remote-debugging-port` so external tools (e.g. Lighthouse) can
|
|
43
|
+
* connect directly via the Chrome DevTools Protocol without going
|
|
44
|
+
* through Playwright. Playwright itself still uses its normal pipe.
|
|
45
|
+
*
|
|
46
|
+
* @param timeoutMs - Timeout for browser launch (default: 30_000)
|
|
47
|
+
* @param deviceName - Optional device name for emulation (e.g. "iPhone 13", "Pixel 7")
|
|
48
|
+
* @returns A BrowserSession with cdpPort, browser, page, and CDP session
|
|
49
|
+
*/
|
|
50
|
+
export declare function launchBrowserServer(timeoutMs?: number, deviceName?: string): Promise<BrowserSession>;
|
|
51
|
+
/**
|
|
52
|
+
* Safely close a BrowserServer and its underlying Chrome process.
|
|
53
|
+
* Logs but does not propagate any errors during cleanup.
|
|
54
|
+
*
|
|
55
|
+
* @param browserServer - The BrowserServer to close
|
|
56
|
+
*/
|
|
57
|
+
export declare function closeBrowserServer(browserServer: BrowserServer): Promise<void>;
|
|
58
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/collect/session.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAqB,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,IAAI,EAAE,KAAK,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAGlI,mEAAmE;AACnE,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,4CAA4C;IAC5C,OAAO,EAAE,cAAc,CAAC;IACxB,+BAA+B;IAC/B,IAAI,EAAE,IAAI,CAAC;IACX,wCAAwC;IACxC,GAAG,EAAE,UAAU,CAAC;IAChB,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wDAAwD;IACxD,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,SAAS,SAAS,GAAG,OAAO,CAAC,cAAc,CAAC,CAqC/E;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAOlE;AAqBD;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CAAC,SAAS,SAAS,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CA2D1G;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,aAAa,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAMpF"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CDP session manager.
|
|
3
|
+
*
|
|
4
|
+
* Launches a headless Chromium instance via Playwright and establishes a
|
|
5
|
+
* raw CDP session for sending Chrome DevTools Protocol commands.
|
|
6
|
+
*/
|
|
7
|
+
import { createServer as createTcpServer } from 'net';
|
|
8
|
+
import { chromium, devices } from 'playwright';
|
|
9
|
+
import ow from 'ow';
|
|
10
|
+
/**
|
|
11
|
+
* Launch a headless Chromium instance, create a new page, and establish a
|
|
12
|
+
* raw CDP session.
|
|
13
|
+
*
|
|
14
|
+
* @param timeoutMs - Timeout for browser launch (default: 30_000)
|
|
15
|
+
* @returns A BrowserSession with browser, context, page, and CDP session
|
|
16
|
+
*/
|
|
17
|
+
export async function launchBrowser(timeoutMs = 30_000) {
|
|
18
|
+
ow(timeoutMs, 'timeoutMs', ow.number.positive);
|
|
19
|
+
const browser = await chromium.launch({
|
|
20
|
+
headless: true,
|
|
21
|
+
args: [
|
|
22
|
+
'--no-sandbox',
|
|
23
|
+
'--disable-setuid-sandbox',
|
|
24
|
+
'--disable-dev-shm-usage',
|
|
25
|
+
'--disable-gpu',
|
|
26
|
+
'--disable-background-networking',
|
|
27
|
+
],
|
|
28
|
+
timeout: timeoutMs,
|
|
29
|
+
});
|
|
30
|
+
try {
|
|
31
|
+
const context = await browser.newContext({
|
|
32
|
+
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
|
|
33
|
+
ignoreHTTPSErrors: false,
|
|
34
|
+
});
|
|
35
|
+
const page = await context.newPage();
|
|
36
|
+
// Set a generous navigation timeout
|
|
37
|
+
page.setDefaultNavigationTimeout(60_000);
|
|
38
|
+
page.setDefaultTimeout(60_000);
|
|
39
|
+
// Establish raw CDP session
|
|
40
|
+
const cdp = await context.newCDPSession(page);
|
|
41
|
+
return { browser, context, page, cdp };
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
// Clean up the browser if context/page creation fails
|
|
45
|
+
await browser.close().catch(() => { });
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Safely close a browser instance.
|
|
51
|
+
* Logs but does not propagate any errors during cleanup.
|
|
52
|
+
*
|
|
53
|
+
* @param browser - The Browser instance to close
|
|
54
|
+
*/
|
|
55
|
+
export async function closeBrowser(browser) {
|
|
56
|
+
ow(browser, 'browser', ow.object);
|
|
57
|
+
try {
|
|
58
|
+
await browser.close();
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
console.error(`[session] Error closing browser: ${error}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Find a free TCP port on localhost.
|
|
66
|
+
* Used to pick a port for Chrome's `--remote-debugging-port` flag.
|
|
67
|
+
*/
|
|
68
|
+
function findFreePort() {
|
|
69
|
+
return new Promise((resolve, reject) => {
|
|
70
|
+
const server = createTcpServer();
|
|
71
|
+
server.once('error', reject);
|
|
72
|
+
server.listen(0, '127.0.0.1', () => {
|
|
73
|
+
const address = server.address();
|
|
74
|
+
if (address && typeof address === 'object') {
|
|
75
|
+
server.close(() => resolve(address.port));
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
server.close(() => reject(new Error('Could not determine free port')));
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Launch a headless Chromium instance with an exposed CDP debugging port.
|
|
85
|
+
*
|
|
86
|
+
* Unlike the basic `launchBrowser()`, this starts Chrome with
|
|
87
|
+
* `--remote-debugging-port` so external tools (e.g. Lighthouse) can
|
|
88
|
+
* connect directly via the Chrome DevTools Protocol without going
|
|
89
|
+
* through Playwright. Playwright itself still uses its normal pipe.
|
|
90
|
+
*
|
|
91
|
+
* @param timeoutMs - Timeout for browser launch (default: 30_000)
|
|
92
|
+
* @param deviceName - Optional device name for emulation (e.g. "iPhone 13", "Pixel 7")
|
|
93
|
+
* @returns A BrowserSession with cdpPort, browser, page, and CDP session
|
|
94
|
+
*/
|
|
95
|
+
export async function launchBrowserServer(timeoutMs = 30_000, deviceName) {
|
|
96
|
+
ow(timeoutMs, 'timeoutMs', ow.number.positive);
|
|
97
|
+
// Pick a free port for Chrome's CDP debugging server
|
|
98
|
+
const cdpPort = await findFreePort();
|
|
99
|
+
// Launch Chrome with --remote-debugging-port so Lighthouse can connect
|
|
100
|
+
// via raw HTTP CDP (not just Playwright's internal pipe).
|
|
101
|
+
const browser = await chromium.launch({
|
|
102
|
+
headless: true,
|
|
103
|
+
args: [
|
|
104
|
+
'--no-sandbox',
|
|
105
|
+
'--disable-setuid-sandbox',
|
|
106
|
+
'--disable-dev-shm-usage',
|
|
107
|
+
'--disable-gpu',
|
|
108
|
+
'--disable-background-networking',
|
|
109
|
+
`--remote-debugging-port=${cdpPort}`,
|
|
110
|
+
],
|
|
111
|
+
timeout: timeoutMs,
|
|
112
|
+
});
|
|
113
|
+
try {
|
|
114
|
+
let context;
|
|
115
|
+
if (deviceName && deviceName.length > 0) {
|
|
116
|
+
const device = devices[deviceName];
|
|
117
|
+
if (device) {
|
|
118
|
+
context = await browser.newContext({
|
|
119
|
+
...device,
|
|
120
|
+
ignoreHTTPSErrors: false,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
console.error(`[session] Unknown device "${deviceName}", falling back to desktop`);
|
|
125
|
+
context = await browser.newContext({
|
|
126
|
+
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
|
|
127
|
+
ignoreHTTPSErrors: false,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
context = await browser.newContext({
|
|
133
|
+
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
|
|
134
|
+
ignoreHTTPSErrors: false,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
const page = await context.newPage();
|
|
138
|
+
page.setDefaultNavigationTimeout(60_000);
|
|
139
|
+
page.setDefaultTimeout(60_000);
|
|
140
|
+
const cdp = await context.newCDPSession(page);
|
|
141
|
+
return { browser, context, page, cdp, cdpPort };
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
await browser.close().catch(() => { });
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Safely close a BrowserServer and its underlying Chrome process.
|
|
150
|
+
* Logs but does not propagate any errors during cleanup.
|
|
151
|
+
*
|
|
152
|
+
* @param browserServer - The BrowserServer to close
|
|
153
|
+
*/
|
|
154
|
+
export async function closeBrowserServer(browserServer) {
|
|
155
|
+
try {
|
|
156
|
+
await browserServer.close();
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
console.error(`[session] Error closing browser server: ${error}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/collect/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TraceCollector — captures Chrome trace events via the Tracing CDP domain.
|
|
3
|
+
*
|
|
4
|
+
* Sends `Tracing.start` with a comprehensive set of categories, buffers
|
|
5
|
+
* events delivered via `Tracing.dataCollected`, and on `stop()` sends
|
|
6
|
+
* `Tracing.end` and waits for `Tracing.tracingComplete`.
|
|
7
|
+
*
|
|
8
|
+
* Also monitors `Tracing.bufferUsage` and emits warnings when the ring
|
|
9
|
+
* buffer exceeds safe thresholds. Buffer health analysis is delegated
|
|
10
|
+
* to the standalone `buffer-monitor` module.
|
|
11
|
+
*/
|
|
12
|
+
import { type CDPSession } from 'playwright';
|
|
13
|
+
import type { Collector, CollectorResult } from './types.js';
|
|
14
|
+
import type { TraceRawData, BufferUsageSample } from './types.js';
|
|
15
|
+
import type { CollectorRunOptions } from '../shared/types.js';
|
|
16
|
+
export declare class TraceCollector implements Collector {
|
|
17
|
+
readonly name = "trace";
|
|
18
|
+
private session;
|
|
19
|
+
private events;
|
|
20
|
+
private dataCollectedCount;
|
|
21
|
+
private bufferUsageSamples;
|
|
22
|
+
private tracingDone;
|
|
23
|
+
private resolveTracingComplete;
|
|
24
|
+
private tracingCompletePromise;
|
|
25
|
+
constructor();
|
|
26
|
+
/**
|
|
27
|
+
* Start tracing via the CDP Tracing domain.
|
|
28
|
+
* Registers event listeners for data collection, completion, and buffer usage.
|
|
29
|
+
*/
|
|
30
|
+
start(session: CDPSession, _options?: CollectorRunOptions): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Stop tracing, wait for completion, and return collected trace data.
|
|
33
|
+
*
|
|
34
|
+
* @returns CollectorResult with TraceRawData on success
|
|
35
|
+
*/
|
|
36
|
+
stop(): Promise<CollectorResult<TraceRawData>>;
|
|
37
|
+
/** Return collected buffer usage samples (useful for tests and monitoring) */
|
|
38
|
+
getBufferUsageSamples(): BufferUsageSample[];
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=trace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../src/collect/trace.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,YAAY,EAAc,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAkB9D,qBAAa,cAAe,YAAW,SAAS;IAC9C,QAAQ,CAAC,IAAI,WAAW;IAExB,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,kBAAkB,CAA2B;IACrD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,sBAAsB,CAAc;IAC5C,OAAO,CAAC,sBAAsB,CAAgB;;IAQ9C;;;OAGG;IACG,KAAK,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAyC/E;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;IAwCpD,8EAA8E;IAC9E,qBAAqB,IAAI,iBAAiB,EAAE;CAG7C"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TraceCollector — captures Chrome trace events via the Tracing CDP domain.
|
|
3
|
+
*
|
|
4
|
+
* Sends `Tracing.start` with a comprehensive set of categories, buffers
|
|
5
|
+
* events delivered via `Tracing.dataCollected`, and on `stop()` sends
|
|
6
|
+
* `Tracing.end` and waits for `Tracing.tracingComplete`.
|
|
7
|
+
*
|
|
8
|
+
* Also monitors `Tracing.bufferUsage` and emits warnings when the ring
|
|
9
|
+
* buffer exceeds safe thresholds. Buffer health analysis is delegated
|
|
10
|
+
* to the standalone `buffer-monitor` module.
|
|
11
|
+
*/
|
|
12
|
+
import {} from 'playwright';
|
|
13
|
+
import { checkBufferHealth, validateTraceCompleteness } from './buffer-monitor.js';
|
|
14
|
+
/** Categories requested for tracing */
|
|
15
|
+
const TRACE_CATEGORIES = [
|
|
16
|
+
'devtools.timeline',
|
|
17
|
+
'disabled-by-default-devtools.timeline',
|
|
18
|
+
'disabled-by-default-devtools.timeline.frame',
|
|
19
|
+
'blink.user_timing',
|
|
20
|
+
'loading',
|
|
21
|
+
'blink',
|
|
22
|
+
'cc',
|
|
23
|
+
'gpu',
|
|
24
|
+
'v8',
|
|
25
|
+
'disabled-by-default-v8.cpu_profiler',
|
|
26
|
+
'disabled-by-default-v8.compile',
|
|
27
|
+
];
|
|
28
|
+
export class TraceCollector {
|
|
29
|
+
name = 'trace';
|
|
30
|
+
session = null;
|
|
31
|
+
events = [];
|
|
32
|
+
dataCollectedCount = 0;
|
|
33
|
+
bufferUsageSamples = [];
|
|
34
|
+
tracingDone = false;
|
|
35
|
+
resolveTracingComplete;
|
|
36
|
+
tracingCompletePromise;
|
|
37
|
+
constructor() {
|
|
38
|
+
this.tracingCompletePromise = new Promise((resolve) => {
|
|
39
|
+
this.resolveTracingComplete = resolve;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Start tracing via the CDP Tracing domain.
|
|
44
|
+
* Registers event listeners for data collection, completion, and buffer usage.
|
|
45
|
+
*/
|
|
46
|
+
async start(session, _options) {
|
|
47
|
+
this.session = session;
|
|
48
|
+
this.events = [];
|
|
49
|
+
this.dataCollectedCount = 0;
|
|
50
|
+
this.bufferUsageSamples = [];
|
|
51
|
+
this.tracingDone = false;
|
|
52
|
+
this.tracingCompletePromise = new Promise((resolve) => {
|
|
53
|
+
this.resolveTracingComplete = resolve;
|
|
54
|
+
});
|
|
55
|
+
// Listen for batched trace events
|
|
56
|
+
session.on('Tracing.dataCollected', (event) => {
|
|
57
|
+
if (Array.isArray(event.value)) {
|
|
58
|
+
this.events.push(...event.value);
|
|
59
|
+
this.dataCollectedCount++;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
// Listen for tracing completion
|
|
63
|
+
session.on('Tracing.tracingComplete', () => {
|
|
64
|
+
this.tracingDone = true;
|
|
65
|
+
this.resolveTracingComplete();
|
|
66
|
+
});
|
|
67
|
+
// Monitor buffer usage for overflow detection
|
|
68
|
+
session.on('Tracing.bufferUsage', (event) => {
|
|
69
|
+
if (event.value !== undefined) {
|
|
70
|
+
this.bufferUsageSamples.push({
|
|
71
|
+
value: event.value,
|
|
72
|
+
timestamp: Date.now(),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
// Send Tracing.start — categories is a comma-separated string per CDP spec
|
|
77
|
+
await session.send('Tracing.start', {
|
|
78
|
+
categories: [...TRACE_CATEGORIES].join(','),
|
|
79
|
+
transferMode: 'ReportEvents',
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Stop tracing, wait for completion, and return collected trace data.
|
|
84
|
+
*
|
|
85
|
+
* @returns CollectorResult with TraceRawData on success
|
|
86
|
+
*/
|
|
87
|
+
async stop() {
|
|
88
|
+
if (!this.session) {
|
|
89
|
+
return { ok: false, error: 'TraceCollector: session not initialized' };
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
// Send Tracing.end and wait for TracingComplete
|
|
93
|
+
await this.session.send('Tracing.end');
|
|
94
|
+
await this.tracingCompletePromise;
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
return {
|
|
98
|
+
ok: false,
|
|
99
|
+
error: `TraceCollector: failed to stop tracing — ${String(error)}`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
// Analyze buffer health via standalone module
|
|
103
|
+
const warnings = [];
|
|
104
|
+
warnings.push(...checkBufferHealth(this.bufferUsageSamples));
|
|
105
|
+
// Run completeness validation via standalone module
|
|
106
|
+
const eventNames = this.events.map((e) => e.name);
|
|
107
|
+
warnings.push(...validateTraceCompleteness(eventNames));
|
|
108
|
+
const categories = [...TRACE_CATEGORIES];
|
|
109
|
+
return {
|
|
110
|
+
ok: true,
|
|
111
|
+
data: {
|
|
112
|
+
events: this.events,
|
|
113
|
+
metadata: {
|
|
114
|
+
categories,
|
|
115
|
+
totalEvents: this.events.length,
|
|
116
|
+
dataCollectedCount: this.dataCollectedCount,
|
|
117
|
+
},
|
|
118
|
+
warnings,
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/** Return collected buffer usage samples (useful for tests and monitoring) */
|
|
123
|
+
getBufferUsageSamples() {
|
|
124
|
+
return [...this.bufferUsageSamples];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=trace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.js","sourceRoot":"","sources":["../../src/collect/trace.ts"],"names":[],"mappings":"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"}
|