@monoes/monobrowse 1.0.9 → 1.0.12
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/README.md +1 -1
- package/dist/src/__tests__/adapters.test.js +5 -2
- package/dist/src/__tests__/adapters.test.js.map +1 -1
- package/dist/src/__tests__/batch-eval-parsing.test.js +4 -2
- package/dist/src/__tests__/batch-eval-parsing.test.js.map +1 -1
- package/dist/src/__tests__/box-model.test.js +9 -5
- package/dist/src/__tests__/box-model.test.js.map +1 -1
- package/dist/src/__tests__/browser-launch.test.d.ts +10 -0
- package/dist/src/__tests__/browser-launch.test.d.ts.map +1 -1
- package/dist/src/__tests__/browser-launch.test.js +17 -10
- package/dist/src/__tests__/browser-launch.test.js.map +1 -1
- package/dist/src/__tests__/cdp-client.test.js +9 -3
- package/dist/src/__tests__/cdp-client.test.js.map +1 -1
- package/dist/src/__tests__/close-browser.test.d.ts +13 -0
- package/dist/src/__tests__/close-browser.test.d.ts.map +1 -1
- package/dist/src/__tests__/close-browser.test.js +40 -26
- package/dist/src/__tests__/close-browser.test.js.map +1 -1
- package/dist/src/__tests__/console-log.test.js +17 -6
- package/dist/src/__tests__/console-log.test.js.map +1 -1
- package/dist/src/__tests__/find.test.js +26 -6
- package/dist/src/__tests__/find.test.js.map +1 -1
- package/dist/src/__tests__/frame-command.test.js +9 -3
- package/dist/src/__tests__/frame-command.test.js.map +1 -1
- package/dist/src/__tests__/open-url-navigate-error.test.js +1 -3
- package/dist/src/__tests__/open-url-navigate-error.test.js.map +1 -1
- package/dist/src/__tests__/output.test.js +1 -1
- package/dist/src/__tests__/output.test.js.map +1 -1
- package/dist/src/__tests__/reap-idle-browser.test.d.ts +15 -0
- package/dist/src/__tests__/reap-idle-browser.test.d.ts.map +1 -0
- package/dist/src/__tests__/reap-idle-browser.test.js +238 -0
- package/dist/src/__tests__/reap-idle-browser.test.js.map +1 -0
- package/dist/src/__tests__/ref-cache.test.js +18 -10
- package/dist/src/__tests__/ref-cache.test.js.map +1 -1
- package/dist/src/__tests__/session-state.test.d.ts +8 -0
- package/dist/src/__tests__/session-state.test.d.ts.map +1 -1
- package/dist/src/__tests__/session-state.test.js +10 -10
- package/dist/src/__tests__/session-state.test.js.map +1 -1
- package/dist/src/__tests__/snapshot.test.js +45 -15
- package/dist/src/__tests__/snapshot.test.js.map +1 -1
- package/dist/src/__tests__/storage-eval.test.js +14 -6
- package/dist/src/__tests__/storage-eval.test.js.map +1 -1
- package/dist/src/__tests__/tabs.test.js +25 -9
- package/dist/src/__tests__/tabs.test.js.map +1 -1
- package/dist/src/browser/action-builder/analyzer.d.ts +1 -1
- package/dist/src/browser/action-builder/analyzer.d.ts.map +1 -1
- package/dist/src/browser/action-builder/analyzer.js +25 -9
- package/dist/src/browser/action-builder/analyzer.js.map +1 -1
- package/dist/src/browser/action-builder/types.d.ts.map +1 -1
- package/dist/src/browser/actions.d.ts +1 -1
- package/dist/src/browser/actions.d.ts.map +1 -1
- package/dist/src/browser/actions.js +16 -6
- package/dist/src/browser/actions.js.map +1 -1
- package/dist/src/browser/adapters/gemini.d.ts.map +1 -1
- package/dist/src/browser/adapters/gemini.js.map +1 -1
- package/dist/src/browser/adapters/google.d.ts.map +1 -1
- package/dist/src/browser/adapters/google.js.map +1 -1
- package/dist/src/browser/adapters/index.d.ts.map +1 -1
- package/dist/src/browser/adapters/index.js +3 -3
- package/dist/src/browser/adapters/index.js.map +1 -1
- package/dist/src/browser/adapters/instagram.d.ts.map +1 -1
- package/dist/src/browser/adapters/instagram.js.map +1 -1
- package/dist/src/browser/adapters/linkedin.d.ts.map +1 -1
- package/dist/src/browser/adapters/linkedin.js.map +1 -1
- package/dist/src/browser/adapters/microsoft.d.ts.map +1 -1
- package/dist/src/browser/adapters/microsoft.js.map +1 -1
- package/dist/src/browser/adapters/x.d.ts.map +1 -1
- package/dist/src/browser/adapters/x.js.map +1 -1
- package/dist/src/browser/browser.d.ts +30 -0
- package/dist/src/browser/browser.d.ts.map +1 -1
- package/dist/src/browser/browser.js +122 -15
- package/dist/src/browser/browser.js.map +1 -1
- package/dist/src/browser/cdp.d.ts.map +1 -1
- package/dist/src/browser/cdp.js +21 -8
- package/dist/src/browser/cdp.js.map +1 -1
- package/dist/src/browser/console-log.d.ts.map +1 -1
- package/dist/src/browser/console-log.js +2 -2
- package/dist/src/browser/console-log.js.map +1 -1
- package/dist/src/browser/dashboard/server.d.ts.map +1 -1
- package/dist/src/browser/dashboard/server.js +29 -19
- package/dist/src/browser/dashboard/server.js.map +1 -1
- package/dist/src/browser/dashboard/ui.html +153 -165
- package/dist/src/browser/dialog.d.ts.map +1 -1
- package/dist/src/browser/dialog.js +3 -1
- package/dist/src/browser/dialog.js.map +1 -1
- package/dist/src/browser/emulation.d.ts.map +1 -1
- package/dist/src/browser/emulation.js +21 -6
- package/dist/src/browser/emulation.js.map +1 -1
- package/dist/src/browser/find.d.ts +4 -4
- package/dist/src/browser/find.d.ts.map +1 -1
- package/dist/src/browser/find.js +14 -6
- package/dist/src/browser/find.js.map +1 -1
- package/dist/src/browser/har.d.ts.map +1 -1
- package/dist/src/browser/har.js +14 -7
- package/dist/src/browser/har.js.map +1 -1
- package/dist/src/browser/index.d.ts +16 -16
- package/dist/src/browser/index.d.ts.map +1 -1
- package/dist/src/browser/index.js +16 -16
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/browser/network.d.ts.map +1 -1
- package/dist/src/browser/network.js +14 -4
- package/dist/src/browser/network.js.map +1 -1
- package/dist/src/browser/pdf.d.ts.map +1 -1
- package/dist/src/browser/pdf.js +3 -3
- package/dist/src/browser/pdf.js.map +1 -1
- package/dist/src/browser/profiler.d.ts.map +1 -1
- package/dist/src/browser/profiler.js +10 -5
- package/dist/src/browser/profiler.js.map +1 -1
- package/dist/src/browser/record.d.ts +1 -1
- package/dist/src/browser/record.d.ts.map +1 -1
- package/dist/src/browser/record.js +18 -7
- package/dist/src/browser/record.js.map +1 -1
- package/dist/src/browser/ref-cache.d.ts.map +1 -1
- package/dist/src/browser/ref-cache.js +9 -4
- package/dist/src/browser/ref-cache.js.map +1 -1
- package/dist/src/browser/screenshot.d.ts.map +1 -1
- package/dist/src/browser/screenshot.js +11 -7
- package/dist/src/browser/screenshot.js.map +1 -1
- package/dist/src/browser/session.d.ts +1 -1
- package/dist/src/browser/session.d.ts.map +1 -1
- package/dist/src/browser/session.js +27 -8
- package/dist/src/browser/session.js.map +1 -1
- package/dist/src/browser/snapshot.d.ts +1 -1
- package/dist/src/browser/snapshot.d.ts.map +1 -1
- package/dist/src/browser/snapshot.js +8 -4
- package/dist/src/browser/snapshot.js.map +1 -1
- package/dist/src/browser/storage.d.ts.map +1 -1
- package/dist/src/browser/storage.js.map +1 -1
- package/dist/src/browser/tabs.d.ts.map +1 -1
- package/dist/src/browser/tabs.js +9 -3
- package/dist/src/browser/tabs.js.map +1 -1
- package/dist/src/browser/trace.d.ts.map +1 -1
- package/dist/src/browser/trace.js +3 -3
- package/dist/src/browser/trace.js.map +1 -1
- package/dist/src/browser/types.d.ts.map +1 -1
- package/dist/src/browser/types.js +23 -4
- package/dist/src/browser/types.js.map +1 -1
- package/dist/src/browser/vitals.d.ts.map +1 -1
- package/dist/src/browser/vitals.js +1 -1
- package/dist/src/browser/vitals.js.map +1 -1
- package/dist/src/browser/wait.d.ts.map +1 -1
- package/dist/src/browser/wait.js +11 -5
- package/dist/src/browser/wait.js.map +1 -1
- package/dist/src/cli/action.d.ts.map +1 -1
- package/dist/src/cli/action.js +14 -11
- package/dist/src/cli/action.js.map +1 -1
- package/dist/src/cli/commands.d.ts.map +1 -1
- package/dist/src/cli/commands.js +453 -159
- package/dist/src/cli/commands.js.map +1 -1
- package/dist/src/cli/output.js +5 -5
- package/dist/src/cli/output.js.map +1 -1
- package/dist/src/cli/platform.d.ts.map +1 -1
- package/dist/src/cli/platform.js +15 -11
- package/dist/src/cli/platform.js.map +1 -1
- package/dist/src/cli/types.d.ts +1 -1
- package/dist/src/cli/types.d.ts.map +1 -1
- package/dist/src/cli.js +21 -9
- package/dist/src/cli.js.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/__tests__/adapters.test.ts +15 -8
- package/src/__tests__/batch-eval-parsing.test.ts +4 -2
- package/src/__tests__/box-model.test.ts +9 -5
- package/src/__tests__/browser-launch.test.ts +26 -15
- package/src/__tests__/cdp-client.test.ts +25 -9
- package/src/__tests__/close-browser.test.ts +49 -26
- package/src/__tests__/console-log.test.ts +36 -13
- package/src/__tests__/find.test.ts +58 -20
- package/src/__tests__/frame-command.test.ts +12 -6
- package/src/__tests__/open-url-navigate-error.test.ts +2 -4
- package/src/__tests__/output.test.ts +1 -1
- package/src/__tests__/reap-idle-browser.test.ts +276 -0
- package/src/__tests__/ref-cache.test.ts +25 -12
- package/src/__tests__/session-state.test.ts +40 -28
- package/src/__tests__/snapshot.test.ts +61 -22
- package/src/__tests__/storage-eval.test.ts +30 -16
- package/src/__tests__/tabs.test.ts +26 -10
- package/src/browser/action-builder/analyzer.ts +39 -15
- package/src/browser/action-builder/types.ts +45 -8
- package/src/browser/actions.ts +288 -123
- package/src/browser/adapters/gemini.ts +7 -3
- package/src/browser/adapters/google.ts +5 -3
- package/src/browser/adapters/index.ts +5 -4
- package/src/browser/adapters/instagram.ts +4 -2
- package/src/browser/adapters/linkedin.ts +4 -2
- package/src/browser/adapters/microsoft.ts +9 -5
- package/src/browser/adapters/x.ts +7 -3
- package/src/browser/browser.ts +188 -42
- package/src/browser/cdp.ts +43 -11
- package/src/browser/console-log.ts +24 -7
- package/src/browser/dashboard/server.ts +44 -25
- package/src/browser/dashboard/ui.html +153 -165
- package/src/browser/dialog.ts +25 -8
- package/src/browser/emulation.ts +86 -36
- package/src/browser/find.ts +110 -47
- package/src/browser/har.ts +58 -26
- package/src/browser/index.ts +16 -16
- package/src/browser/network.ts +147 -46
- package/src/browser/pdf.ts +4 -4
- package/src/browser/profiler.ts +23 -10
- package/src/browser/record.ts +38 -19
- package/src/browser/ref-cache.ts +38 -17
- package/src/browser/screenshot.ts +58 -32
- package/src/browser/session.ts +51 -18
- package/src/browser/snapshot.ts +34 -20
- package/src/browser/storage.ts +73 -17
- package/src/browser/tabs.ts +29 -17
- package/src/browser/trace.ts +14 -10
- package/src/browser/types.ts +23 -4
- package/src/browser/vitals.ts +33 -16
- package/src/browser/wait.ts +47 -21
- package/src/cli/action.ts +52 -21
- package/src/cli/commands.ts +1093 -385
- package/src/cli/output.ts +5 -5
- package/src/cli/platform.ts +44 -23
- package/src/cli/types.ts +1 -1
- package/src/cli.ts +34 -18
- package/src/index.ts +2 -2
package/src/browser/index.ts
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
export * from './types.js';
|
|
2
|
-
export * from './cdp.js';
|
|
3
|
-
export * from './browser.js';
|
|
4
|
-
export * from './snapshot.js';
|
|
5
1
|
export * from './actions.js';
|
|
6
|
-
export * from './
|
|
7
|
-
export * from './
|
|
8
|
-
export * from './
|
|
9
|
-
export * from './session.js';
|
|
10
|
-
export * from './tabs.js';
|
|
11
|
-
export * from './dialog.js';
|
|
2
|
+
export * from './batch.js';
|
|
3
|
+
export * from './browser.js';
|
|
4
|
+
export * from './cdp.js';
|
|
12
5
|
export * from './console-log.js';
|
|
13
|
-
export * from './
|
|
6
|
+
export * from './dialog.js';
|
|
7
|
+
export * from './emulation.js';
|
|
14
8
|
export * from './find.js';
|
|
9
|
+
export * from './har.js';
|
|
10
|
+
export * from './network.js';
|
|
15
11
|
export * from './pdf.js';
|
|
16
|
-
export * from './
|
|
17
|
-
export * from './batch.js';
|
|
12
|
+
export * from './profiler.js';
|
|
18
13
|
export * from './record.js';
|
|
14
|
+
export * from './ref-cache.js';
|
|
15
|
+
export * from './screenshot.js';
|
|
16
|
+
export * from './session.js';
|
|
17
|
+
export * from './snapshot.js';
|
|
18
|
+
export * from './storage.js';
|
|
19
|
+
export * from './tabs.js';
|
|
19
20
|
export * from './trace.js';
|
|
20
|
-
export * from './
|
|
21
|
+
export * from './types.js';
|
|
21
22
|
export * from './vitals.js';
|
|
22
|
-
export * from './
|
|
23
|
-
export * from './ref-cache.js';
|
|
23
|
+
export * from './wait.js';
|
package/src/browser/network.ts
CHANGED
|
@@ -2,7 +2,11 @@ import type { CdpClient } from './cdp.js';
|
|
|
2
2
|
import type { CdpCookie, NetworkRoute } from './types.js';
|
|
3
3
|
|
|
4
4
|
export async function getCookies(client: CdpClient, sessionId: string): Promise<CdpCookie[]> {
|
|
5
|
-
const result = await client.send<{ cookies: CdpCookie[] }>(
|
|
5
|
+
const result = await client.send<{ cookies: CdpCookie[] }>(
|
|
6
|
+
'Network.getAllCookies',
|
|
7
|
+
{},
|
|
8
|
+
sessionId,
|
|
9
|
+
);
|
|
6
10
|
return result.cookies ?? [];
|
|
7
11
|
}
|
|
8
12
|
|
|
@@ -12,12 +16,24 @@ export async function getCookies(client: CdpClient, sessionId: string): Promise<
|
|
|
12
16
|
* profile. Used for session save/export so we don't leak session tokens for
|
|
13
17
|
* unrelated domains the user happens to be logged into.
|
|
14
18
|
*/
|
|
15
|
-
export async function getCookiesForUrls(
|
|
16
|
-
|
|
19
|
+
export async function getCookiesForUrls(
|
|
20
|
+
client: CdpClient,
|
|
21
|
+
sessionId: string,
|
|
22
|
+
urls: string[],
|
|
23
|
+
): Promise<CdpCookie[]> {
|
|
24
|
+
const result = await client.send<{ cookies: CdpCookie[] }>(
|
|
25
|
+
'Network.getCookies',
|
|
26
|
+
{ urls },
|
|
27
|
+
sessionId,
|
|
28
|
+
);
|
|
17
29
|
return result.cookies ?? [];
|
|
18
30
|
}
|
|
19
31
|
|
|
20
|
-
export async function setCookies(
|
|
32
|
+
export async function setCookies(
|
|
33
|
+
client: CdpClient,
|
|
34
|
+
sessionId: string,
|
|
35
|
+
cookies: CdpCookie[],
|
|
36
|
+
): Promise<void> {
|
|
21
37
|
await client.send('Network.setCookies', { cookies }, sessionId);
|
|
22
38
|
}
|
|
23
39
|
|
|
@@ -28,15 +44,19 @@ export async function clearCookies(client: CdpClient, sessionId: string): Promis
|
|
|
28
44
|
export async function setExtraHeaders(
|
|
29
45
|
client: CdpClient,
|
|
30
46
|
sessionId: string,
|
|
31
|
-
headers: Record<string, string
|
|
47
|
+
headers: Record<string, string>,
|
|
32
48
|
): Promise<void> {
|
|
33
49
|
await client.send('Network.setExtraHTTPHeaders', { headers }, sessionId);
|
|
34
50
|
}
|
|
35
51
|
|
|
36
52
|
export async function enableInterception(client: CdpClient, sessionId: string): Promise<void> {
|
|
37
|
-
await client.send(
|
|
38
|
-
|
|
39
|
-
|
|
53
|
+
await client.send(
|
|
54
|
+
'Fetch.enable',
|
|
55
|
+
{
|
|
56
|
+
patterns: [{ requestStage: 'Request' }],
|
|
57
|
+
},
|
|
58
|
+
sessionId,
|
|
59
|
+
);
|
|
40
60
|
}
|
|
41
61
|
|
|
42
62
|
const _routeListeners = new Map<string, () => void>();
|
|
@@ -44,11 +64,14 @@ const _routeListeners = new Map<string, () => void>();
|
|
|
44
64
|
export async function setupRoutes(
|
|
45
65
|
client: CdpClient,
|
|
46
66
|
sessionId: string,
|
|
47
|
-
routes: NetworkRoute[]
|
|
67
|
+
routes: NetworkRoute[],
|
|
48
68
|
): Promise<void> {
|
|
49
69
|
// Remove previous route listener for this session before registering a new one
|
|
50
70
|
const prevOff = _routeListeners.get(sessionId);
|
|
51
|
-
if (prevOff) {
|
|
71
|
+
if (prevOff) {
|
|
72
|
+
prevOff();
|
|
73
|
+
_routeListeners.delete(sessionId);
|
|
74
|
+
}
|
|
52
75
|
|
|
53
76
|
if (routes.length === 0) {
|
|
54
77
|
await client.send('Fetch.disable', {}, sessionId).catch(() => {});
|
|
@@ -77,14 +100,21 @@ export async function setupRoutes(
|
|
|
77
100
|
await client.send('Fetch.failRequest', { requestId, errorReason: 'Failed' }, sessionId);
|
|
78
101
|
break;
|
|
79
102
|
case 'fulfill':
|
|
80
|
-
await client.send(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
103
|
+
await client.send(
|
|
104
|
+
'Fetch.fulfillRequest',
|
|
105
|
+
{
|
|
106
|
+
requestId,
|
|
107
|
+
responseCode: matchedRoute.response?.status ?? 200,
|
|
108
|
+
responseHeaders: Object.entries(matchedRoute.response?.headers ?? {}).map(
|
|
109
|
+
([name, value]) => ({ name, value }),
|
|
110
|
+
),
|
|
111
|
+
body: matchedRoute.response?.body
|
|
112
|
+
? Buffer.from(matchedRoute.response.body).toString('base64')
|
|
113
|
+
: '',
|
|
114
|
+
},
|
|
115
|
+
sessionId,
|
|
116
|
+
);
|
|
86
117
|
break;
|
|
87
|
-
case 'continue':
|
|
88
118
|
default:
|
|
89
119
|
await client.send('Fetch.continueRequest', { requestId }, sessionId);
|
|
90
120
|
break;
|
|
@@ -96,15 +126,29 @@ export async function setupRoutes(
|
|
|
96
126
|
});
|
|
97
127
|
_routeListeners.set(sessionId, off);
|
|
98
128
|
|
|
99
|
-
await client.send(
|
|
100
|
-
|
|
101
|
-
|
|
129
|
+
await client.send(
|
|
130
|
+
'Fetch.enable',
|
|
131
|
+
{
|
|
132
|
+
patterns: routes.map((r) => ({
|
|
133
|
+
urlPattern: globToFetchPattern(r.pattern),
|
|
134
|
+
requestStage: 'Request',
|
|
135
|
+
})),
|
|
136
|
+
},
|
|
137
|
+
sessionId,
|
|
138
|
+
);
|
|
102
139
|
}
|
|
103
140
|
|
|
104
141
|
type CapturedRequest = {
|
|
105
|
-
id: string;
|
|
106
|
-
|
|
107
|
-
|
|
142
|
+
id: string;
|
|
143
|
+
url: string;
|
|
144
|
+
method: string;
|
|
145
|
+
status?: number;
|
|
146
|
+
mimeType?: string;
|
|
147
|
+
requestHeaders?: Record<string, string>;
|
|
148
|
+
responseHeaders?: Record<string, string>;
|
|
149
|
+
startTime: number;
|
|
150
|
+
endTime?: number;
|
|
151
|
+
encodedSize?: number;
|
|
108
152
|
};
|
|
109
153
|
|
|
110
154
|
const _capturedRequests = new Map<string, Map<string, CapturedRequest>>();
|
|
@@ -121,29 +165,53 @@ export function startRequestCapture(client: CdpClient, sessionId: string): void
|
|
|
121
165
|
|
|
122
166
|
const offReq = client.on('Network.requestWillBeSent', (params, sid) => {
|
|
123
167
|
if (sid !== sessionId) return;
|
|
124
|
-
const p = params as {
|
|
125
|
-
|
|
168
|
+
const p = params as {
|
|
169
|
+
requestId: string;
|
|
170
|
+
request: { url: string; method: string; headers: Record<string, string> };
|
|
171
|
+
timestamp: number;
|
|
172
|
+
};
|
|
173
|
+
idx().set(p.requestId, {
|
|
174
|
+
id: p.requestId,
|
|
175
|
+
url: p.request.url,
|
|
176
|
+
method: p.request.method,
|
|
177
|
+
requestHeaders: p.request.headers,
|
|
178
|
+
startTime: p.timestamp * 1000,
|
|
179
|
+
});
|
|
126
180
|
});
|
|
127
181
|
|
|
128
182
|
const offResp = client.on('Network.responseReceived', (params, sid) => {
|
|
129
183
|
if (sid !== sessionId) return;
|
|
130
|
-
const p = params as {
|
|
184
|
+
const p = params as {
|
|
185
|
+
requestId: string;
|
|
186
|
+
response: { status: number; mimeType: string; headers: Record<string, string> };
|
|
187
|
+
timestamp: number;
|
|
188
|
+
};
|
|
131
189
|
const entry = idx().get(p.requestId);
|
|
132
|
-
if (entry) {
|
|
190
|
+
if (entry) {
|
|
191
|
+
entry.status = p.response.status;
|
|
192
|
+
entry.mimeType = p.response.mimeType;
|
|
193
|
+
entry.responseHeaders = p.response.headers;
|
|
194
|
+
entry.endTime = p.timestamp * 1000;
|
|
195
|
+
}
|
|
133
196
|
});
|
|
134
197
|
|
|
135
198
|
const offFinished = client.on('Network.loadingFinished', (params, sid) => {
|
|
136
199
|
if (sid !== sessionId) return;
|
|
137
200
|
const p = params as { requestId: string; encodedDataLength: number; timestamp: number };
|
|
138
201
|
const entry = idx().get(p.requestId);
|
|
139
|
-
if (entry) {
|
|
202
|
+
if (entry) {
|
|
203
|
+
entry.encodedSize = p.encodedDataLength;
|
|
204
|
+
entry.endTime = p.timestamp * 1000;
|
|
205
|
+
}
|
|
140
206
|
});
|
|
141
207
|
|
|
142
208
|
const offFailed = client.on('Network.loadingFailed', (params, sid) => {
|
|
143
209
|
if (sid !== sessionId) return;
|
|
144
210
|
const p = params as { requestId: string; timestamp: number };
|
|
145
211
|
const entry = idx().get(p.requestId);
|
|
146
|
-
if (entry) {
|
|
212
|
+
if (entry) {
|
|
213
|
+
entry.endTime = p.timestamp * 1000;
|
|
214
|
+
}
|
|
147
215
|
});
|
|
148
216
|
|
|
149
217
|
_captureListeners.set(sessionId, [offReq, offResp, offFinished, offFailed]);
|
|
@@ -151,7 +219,10 @@ export function startRequestCapture(client: CdpClient, sessionId: string): void
|
|
|
151
219
|
|
|
152
220
|
export function stopRequestCapture(sessionId: string): void {
|
|
153
221
|
const offs = _captureListeners.get(sessionId);
|
|
154
|
-
if (offs) {
|
|
222
|
+
if (offs) {
|
|
223
|
+
for (const off of offs) off();
|
|
224
|
+
_captureListeners.delete(sessionId);
|
|
225
|
+
}
|
|
155
226
|
_capturedRequests.delete(sessionId);
|
|
156
227
|
}
|
|
157
228
|
|
|
@@ -165,20 +236,36 @@ export function clearCapturedRequests(sessionId: string): void {
|
|
|
165
236
|
|
|
166
237
|
export async function disableInterception(client: CdpClient, sessionId: string): Promise<void> {
|
|
167
238
|
const prevOff = _routeListeners.get(sessionId);
|
|
168
|
-
if (prevOff) {
|
|
239
|
+
if (prevOff) {
|
|
240
|
+
prevOff();
|
|
241
|
+
_routeListeners.delete(sessionId);
|
|
242
|
+
}
|
|
169
243
|
await client.send('Fetch.disable', {}, sessionId);
|
|
170
244
|
}
|
|
171
245
|
|
|
172
246
|
export function teardownRouteInterception(sessionId: string): void {
|
|
173
247
|
const prevOff = _routeListeners.get(sessionId);
|
|
174
|
-
if (prevOff) {
|
|
248
|
+
if (prevOff) {
|
|
249
|
+
prevOff();
|
|
250
|
+
_routeListeners.delete(sessionId);
|
|
251
|
+
}
|
|
175
252
|
}
|
|
176
253
|
|
|
177
|
-
export async function getLocalStorage(
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
254
|
+
export async function getLocalStorage(
|
|
255
|
+
client: CdpClient,
|
|
256
|
+
sessionId: string,
|
|
257
|
+
): Promise<Record<string, string>> {
|
|
258
|
+
const result = await client.send<{
|
|
259
|
+
result: { value?: string };
|
|
260
|
+
exceptionDetails?: { text: string; exception?: { description?: string } };
|
|
261
|
+
}>(
|
|
262
|
+
'Runtime.evaluate',
|
|
263
|
+
{
|
|
264
|
+
expression: 'JSON.stringify(Object.fromEntries(Object.entries(localStorage)))',
|
|
265
|
+
returnByValue: true,
|
|
266
|
+
},
|
|
267
|
+
sessionId,
|
|
268
|
+
);
|
|
182
269
|
if (result.exceptionDetails) return {};
|
|
183
270
|
try {
|
|
184
271
|
return JSON.parse(result.result?.value ?? '{}');
|
|
@@ -190,7 +277,7 @@ export async function getLocalStorage(client: CdpClient, sessionId: string): Pro
|
|
|
190
277
|
export async function setLocalStorage(
|
|
191
278
|
client: CdpClient,
|
|
192
279
|
sessionId: string,
|
|
193
|
-
data: Record<string, string
|
|
280
|
+
data: Record<string, string>,
|
|
194
281
|
): Promise<void> {
|
|
195
282
|
const script = Object.entries(data)
|
|
196
283
|
.map(([k, v]) => `localStorage.setItem(${JSON.stringify(k)}, ${JSON.stringify(v)})`)
|
|
@@ -201,16 +288,28 @@ export async function setLocalStorage(
|
|
|
201
288
|
exceptionDetails?: { text: string; exception?: { description?: string } };
|
|
202
289
|
}>('Runtime.evaluate', { expression: script, returnByValue: true }, sessionId);
|
|
203
290
|
if (result.exceptionDetails) {
|
|
204
|
-
throw new Error(
|
|
291
|
+
throw new Error(
|
|
292
|
+
`setLocalStorage failed: ${result.exceptionDetails.exception?.description ?? result.exceptionDetails.text}`,
|
|
293
|
+
);
|
|
205
294
|
}
|
|
206
295
|
}
|
|
207
296
|
}
|
|
208
297
|
|
|
209
|
-
export async function getSessionStorage(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
298
|
+
export async function getSessionStorage(
|
|
299
|
+
client: CdpClient,
|
|
300
|
+
sessionId: string,
|
|
301
|
+
): Promise<Record<string, string>> {
|
|
302
|
+
const result = await client.send<{
|
|
303
|
+
result: { value?: string };
|
|
304
|
+
exceptionDetails?: { text: string; exception?: { description?: string } };
|
|
305
|
+
}>(
|
|
306
|
+
'Runtime.evaluate',
|
|
307
|
+
{
|
|
308
|
+
expression: 'JSON.stringify(Object.fromEntries(Object.entries(sessionStorage)))',
|
|
309
|
+
returnByValue: true,
|
|
310
|
+
},
|
|
311
|
+
sessionId,
|
|
312
|
+
);
|
|
214
313
|
if (result.exceptionDetails) return {};
|
|
215
314
|
try {
|
|
216
315
|
return JSON.parse(result.result?.value ?? '{}');
|
|
@@ -222,7 +321,7 @@ export async function getSessionStorage(client: CdpClient, sessionId: string): P
|
|
|
222
321
|
export async function setSessionStorage(
|
|
223
322
|
client: CdpClient,
|
|
224
323
|
sessionId: string,
|
|
225
|
-
data: Record<string, string
|
|
324
|
+
data: Record<string, string>,
|
|
226
325
|
): Promise<void> {
|
|
227
326
|
const script = Object.entries(data)
|
|
228
327
|
.map(([k, v]) => `sessionStorage.setItem(${JSON.stringify(k)}, ${JSON.stringify(v)})`)
|
|
@@ -233,7 +332,9 @@ export async function setSessionStorage(
|
|
|
233
332
|
exceptionDetails?: { text: string; exception?: { description?: string } };
|
|
234
333
|
}>('Runtime.evaluate', { expression: script, returnByValue: true }, sessionId);
|
|
235
334
|
if (result.exceptionDetails) {
|
|
236
|
-
throw new Error(
|
|
335
|
+
throw new Error(
|
|
336
|
+
`setSessionStorage failed: ${result.exceptionDetails.exception?.description ?? result.exceptionDetails.text}`,
|
|
337
|
+
);
|
|
237
338
|
}
|
|
238
339
|
}
|
|
239
340
|
}
|
package/src/browser/pdf.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
1
4
|
import type { CdpClient } from './cdp.js';
|
|
2
|
-
import { writeFile } from 'fs/promises';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
import { tmpdir } from 'os';
|
|
5
5
|
|
|
6
6
|
export interface PdfOptions {
|
|
7
7
|
path?: string;
|
|
@@ -19,7 +19,7 @@ export interface PdfOptions {
|
|
|
19
19
|
export async function capturePdf(
|
|
20
20
|
client: CdpClient,
|
|
21
21
|
sessionId: string,
|
|
22
|
-
options: PdfOptions = {}
|
|
22
|
+
options: PdfOptions = {},
|
|
23
23
|
): Promise<string> {
|
|
24
24
|
const params: Record<string, unknown> = {
|
|
25
25
|
landscape: options.landscape ?? false,
|
package/src/browser/profiler.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
1
4
|
import type { CdpClient } from './cdp.js';
|
|
2
|
-
import { writeFile } from 'fs/promises';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
import { tmpdir } from 'os';
|
|
5
5
|
|
|
6
6
|
export interface ProfilerOptions {
|
|
7
7
|
path?: string;
|
|
@@ -14,14 +14,18 @@ const _heapSessions = new Set<string>();
|
|
|
14
14
|
export async function startCpuProfile(
|
|
15
15
|
client: CdpClient,
|
|
16
16
|
sessionId: string,
|
|
17
|
-
options: ProfilerOptions = {}
|
|
17
|
+
options: ProfilerOptions = {},
|
|
18
18
|
): Promise<void> {
|
|
19
19
|
if (_sessions.has(sessionId)) {
|
|
20
20
|
throw new Error('CPU profiler already running for this session');
|
|
21
21
|
}
|
|
22
22
|
await client.send('Profiler.enable', {}, sessionId);
|
|
23
23
|
if (options.samplingInterval !== undefined) {
|
|
24
|
-
await client.send(
|
|
24
|
+
await client.send(
|
|
25
|
+
'Profiler.setSamplingInterval',
|
|
26
|
+
{ interval: options.samplingInterval },
|
|
27
|
+
sessionId,
|
|
28
|
+
);
|
|
25
29
|
}
|
|
26
30
|
await client.send('Profiler.start', {}, sessionId);
|
|
27
31
|
_sessions.add(sessionId);
|
|
@@ -30,7 +34,7 @@ export async function startCpuProfile(
|
|
|
30
34
|
export async function stopCpuProfile(
|
|
31
35
|
client: CdpClient,
|
|
32
36
|
sessionId: string,
|
|
33
|
-
outputPath?: string
|
|
37
|
+
outputPath?: string,
|
|
34
38
|
): Promise<string> {
|
|
35
39
|
if (!_sessions.has(sessionId)) {
|
|
36
40
|
throw new Error('No active CPU profiler for this session');
|
|
@@ -57,7 +61,7 @@ export function isProfilingActive(sessionId: string): boolean {
|
|
|
57
61
|
export async function startHeapSnapshot(
|
|
58
62
|
client: CdpClient,
|
|
59
63
|
sessionId: string,
|
|
60
|
-
outputPath?: string
|
|
64
|
+
outputPath?: string,
|
|
61
65
|
): Promise<string> {
|
|
62
66
|
if (_heapSessions.has(sessionId)) {
|
|
63
67
|
throw new Error('Heap snapshot already in progress for this session');
|
|
@@ -79,10 +83,19 @@ export async function startHeapSnapshot(
|
|
|
79
83
|
}, 120_000);
|
|
80
84
|
const off2 = client.on('HeapProfiler.reportHeapSnapshotProgress', (params, sid) => {
|
|
81
85
|
if (sid !== sessionId) return;
|
|
82
|
-
if (params.finished) {
|
|
86
|
+
if (params.finished) {
|
|
87
|
+
clearTimeout(timeoutHandle);
|
|
88
|
+
off2();
|
|
89
|
+
resolve();
|
|
90
|
+
}
|
|
83
91
|
});
|
|
84
|
-
client
|
|
85
|
-
.
|
|
92
|
+
client
|
|
93
|
+
.send('HeapProfiler.takeHeapSnapshot', { reportProgress: true }, sessionId)
|
|
94
|
+
.catch((err) => {
|
|
95
|
+
clearTimeout(timeoutHandle);
|
|
96
|
+
off2();
|
|
97
|
+
reject(err);
|
|
98
|
+
});
|
|
86
99
|
});
|
|
87
100
|
} finally {
|
|
88
101
|
off();
|
package/src/browser/record.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
1
4
|
import type { CdpClient } from './cdp.js';
|
|
2
|
-
import { writeFile } from 'fs/promises';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
import { tmpdir } from 'os';
|
|
5
5
|
|
|
6
6
|
export interface RecordOptions {
|
|
7
7
|
path?: string;
|
|
@@ -34,7 +34,7 @@ const _sessions = new Map<string, RecordingState>();
|
|
|
34
34
|
export async function startRecording(
|
|
35
35
|
client: CdpClient,
|
|
36
36
|
sessionId: string,
|
|
37
|
-
options: RecordOptions = {}
|
|
37
|
+
options: RecordOptions = {},
|
|
38
38
|
): Promise<void> {
|
|
39
39
|
const existing = _sessions.get(sessionId);
|
|
40
40
|
if (existing && !existing.autoStopped) {
|
|
@@ -48,7 +48,12 @@ export async function startRecording(
|
|
|
48
48
|
_sessions.delete(sessionId);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
const state: RecordingState = {
|
|
51
|
+
const state: RecordingState = {
|
|
52
|
+
frames: [],
|
|
53
|
+
offScreencast: null,
|
|
54
|
+
totalBytes: 0,
|
|
55
|
+
autoStopped: false,
|
|
56
|
+
};
|
|
52
57
|
_sessions.set(sessionId, state);
|
|
53
58
|
|
|
54
59
|
state.offScreencast = client.on('Page.screencastFrame', async (params, sid) => {
|
|
@@ -63,22 +68,28 @@ export async function startRecording(
|
|
|
63
68
|
// eslint-disable-next-line no-console
|
|
64
69
|
console.error(
|
|
65
70
|
`[monobrowse] Screen recording auto-stopped: reached ${Math.round(MAX_SCREENCAST_BYTES / (1024 * 1024))}MB ` +
|
|
66
|
-
|
|
71
|
+
`of buffered frame data (${state.frames.length} frames). Call "record stop" to save what was captured.`,
|
|
67
72
|
);
|
|
68
73
|
await client.send('Page.stopScreencast', {}, sessionId).catch(() => {});
|
|
69
74
|
}
|
|
70
75
|
}
|
|
71
|
-
await client
|
|
76
|
+
await client
|
|
77
|
+
.send('Page.screencastFrameAck', { sessionId: frameSessionId }, sessionId)
|
|
78
|
+
.catch(() => {});
|
|
72
79
|
});
|
|
73
80
|
|
|
74
81
|
try {
|
|
75
|
-
await client.send(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
await client.send(
|
|
83
|
+
'Page.startScreencast',
|
|
84
|
+
{
|
|
85
|
+
format: options.format ?? 'jpeg',
|
|
86
|
+
quality: options.quality ?? 80,
|
|
87
|
+
everyNthFrame: options.everyNthFrame ?? 1,
|
|
88
|
+
...(options.maxWidth ? { maxWidth: options.maxWidth } : {}),
|
|
89
|
+
...(options.maxHeight ? { maxHeight: options.maxHeight } : {}),
|
|
90
|
+
},
|
|
91
|
+
sessionId,
|
|
92
|
+
);
|
|
82
93
|
} catch (err) {
|
|
83
94
|
state.offScreencast?.();
|
|
84
95
|
_sessions.delete(sessionId);
|
|
@@ -89,7 +100,7 @@ export async function startRecording(
|
|
|
89
100
|
export async function stopRecording(
|
|
90
101
|
client: CdpClient,
|
|
91
102
|
sessionId: string,
|
|
92
|
-
outputPath?: string
|
|
103
|
+
outputPath?: string,
|
|
93
104
|
): Promise<string> {
|
|
94
105
|
const state = _sessions.get(sessionId);
|
|
95
106
|
if (!state) throw new Error('No active recording for this session');
|
|
@@ -110,16 +121,24 @@ export async function stopRecording(
|
|
|
110
121
|
return path;
|
|
111
122
|
}
|
|
112
123
|
|
|
113
|
-
export function getRecordingStatus(sessionId: string): {
|
|
124
|
+
export function getRecordingStatus(sessionId: string): {
|
|
125
|
+
recording: boolean;
|
|
126
|
+
frames: number;
|
|
127
|
+
autoStopped: boolean;
|
|
128
|
+
} {
|
|
114
129
|
const state = _sessions.get(sessionId);
|
|
115
|
-
return {
|
|
130
|
+
return {
|
|
131
|
+
recording: !!state && !state.autoStopped,
|
|
132
|
+
frames: state?.frames.length ?? 0,
|
|
133
|
+
autoStopped: state?.autoStopped ?? false,
|
|
134
|
+
};
|
|
116
135
|
}
|
|
117
136
|
|
|
118
137
|
export async function saveFrameAsPng(
|
|
119
|
-
|
|
138
|
+
_client: CdpClient,
|
|
120
139
|
sessionId: string,
|
|
121
140
|
frameIndex: number,
|
|
122
|
-
outputPath: string
|
|
141
|
+
outputPath: string,
|
|
123
142
|
): Promise<void> {
|
|
124
143
|
const state = _sessions.get(sessionId);
|
|
125
144
|
if (!state || frameIndex >= state.frames.length) {
|
package/src/browser/ref-cache.ts
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
* The full AX-tree text/dump is intentionally NOT persisted — only the
|
|
11
11
|
* per-ref index, to keep the file small.
|
|
12
12
|
*/
|
|
13
|
-
import {
|
|
14
|
-
import { join } from 'path';
|
|
13
|
+
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
15
|
import type { ElementRef } from './types.js';
|
|
16
16
|
|
|
17
17
|
const CACHE_DIR = join(process.cwd(), '.monomind', 'monobrowse');
|
|
@@ -40,7 +40,7 @@ export interface RefCacheEntry {
|
|
|
40
40
|
export async function saveRefCache(
|
|
41
41
|
targetId: string,
|
|
42
42
|
url: string,
|
|
43
|
-
refs: Map<string, ElementRef
|
|
43
|
+
refs: Map<string, ElementRef>,
|
|
44
44
|
): Promise<void> {
|
|
45
45
|
try {
|
|
46
46
|
await mkdir(CACHE_DIR, { recursive: true });
|
|
@@ -99,7 +99,7 @@ export async function clearRefCache(): Promise<void> {
|
|
|
99
99
|
*/
|
|
100
100
|
export async function saveActivePort(
|
|
101
101
|
port: number,
|
|
102
|
-
opts?: { launched?: boolean; pid?: number; userDataDir?: string }
|
|
102
|
+
opts?: { launched?: boolean; pid?: number; userDataDir?: string },
|
|
103
103
|
): Promise<void> {
|
|
104
104
|
try {
|
|
105
105
|
await mkdir(CACHE_DIR, { recursive: true });
|
|
@@ -113,13 +113,16 @@ export async function saveActivePort(
|
|
|
113
113
|
// and kill the Chrome this one launched. Without this, closeBrowser()'s
|
|
114
114
|
// PID-kill fallback can never fire outside the launching process, since
|
|
115
115
|
// the in-memory launchedPids Map (browser.ts) is empty there.
|
|
116
|
-
await writeFile(
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
116
|
+
await writeFile(
|
|
117
|
+
PORT_FILE,
|
|
118
|
+
JSON.stringify({
|
|
119
|
+
port,
|
|
120
|
+
launched: opts?.launched !== false,
|
|
121
|
+
pid: opts?.pid,
|
|
122
|
+
userDataDir: opts?.userDataDir,
|
|
123
|
+
savedAt: Date.now(),
|
|
124
|
+
}),
|
|
125
|
+
);
|
|
123
126
|
} catch {
|
|
124
127
|
// Best-effort — persistence failure just means the next process falls
|
|
125
128
|
// back to the hardcoded default port, matching prior behavior.
|
|
@@ -142,17 +145,35 @@ export async function loadActivePort(): Promise<number | null> {
|
|
|
142
145
|
}
|
|
143
146
|
|
|
144
147
|
/** Load the persisted active port with its provenance flag, PID, user-data-dir, and save timestamp. */
|
|
145
|
-
export async function loadActivePortInfo(): Promise<
|
|
146
|
-
|
|
147
|
-
|
|
148
|
+
export async function loadActivePortInfo(): Promise<{
|
|
149
|
+
port: number;
|
|
150
|
+
launched: boolean;
|
|
151
|
+
pid?: number;
|
|
152
|
+
userDataDir?: string;
|
|
153
|
+
savedAt?: number;
|
|
154
|
+
} | null> {
|
|
148
155
|
try {
|
|
149
156
|
const raw = await readFile(PORT_FILE, 'utf8');
|
|
150
|
-
const data = JSON.parse(raw) as {
|
|
151
|
-
|
|
157
|
+
const data = JSON.parse(raw) as {
|
|
158
|
+
port?: unknown;
|
|
159
|
+
launched?: unknown;
|
|
160
|
+
pid?: unknown;
|
|
161
|
+
userDataDir?: unknown;
|
|
162
|
+
savedAt?: unknown;
|
|
163
|
+
};
|
|
164
|
+
if (
|
|
165
|
+
typeof data.port === 'number' &&
|
|
166
|
+
Number.isInteger(data.port) &&
|
|
167
|
+
data.port >= 1024 &&
|
|
168
|
+
data.port <= 65535
|
|
169
|
+
) {
|
|
152
170
|
return {
|
|
153
171
|
port: data.port,
|
|
154
172
|
launched: data.launched !== false,
|
|
155
|
-
pid:
|
|
173
|
+
pid:
|
|
174
|
+
typeof data.pid === 'number' && Number.isInteger(data.pid) && data.pid > 0
|
|
175
|
+
? data.pid
|
|
176
|
+
: undefined,
|
|
156
177
|
userDataDir: typeof data.userDataDir === 'string' ? data.userDataDir : undefined,
|
|
157
178
|
savedAt: typeof data.savedAt === 'number' ? data.savedAt : undefined,
|
|
158
179
|
};
|