agent-web-interface 4.5.0 → 4.5.1
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 +35 -34
- package/dist/src/browser/browser-session-config.d.ts.map +1 -1
- package/dist/src/browser/browser-session-config.js +1 -0
- package/dist/src/browser/browser-session-config.js.map +1 -1
- package/dist/src/browser/ensure-browser.d.ts.map +1 -1
- package/dist/src/browser/ensure-browser.js +34 -9
- package/dist/src/browser/ensure-browser.js.map +1 -1
- package/dist/src/browser/page-network-recorder.d.ts +95 -0
- package/dist/src/browser/page-network-recorder.d.ts.map +1 -0
- package/dist/src/browser/page-network-recorder.js +306 -0
- package/dist/src/browser/page-network-recorder.js.map +1 -0
- package/dist/src/browser/session-manager.d.ts.map +1 -1
- package/dist/src/browser/session-manager.js +47 -3
- package/dist/src/browser/session-manager.js.map +1 -1
- package/dist/src/server/tool-result-handler.d.ts.map +1 -1
- package/dist/src/server/tool-result-handler.js +19 -1
- package/dist/src/server/tool-result-handler.js.map +1 -1
- package/dist/src/session/session-controller.d.ts +1 -0
- package/dist/src/session/session-controller.d.ts.map +1 -1
- package/dist/src/session/session-controller.js +3 -0
- package/dist/src/session/session-controller.js.map +1 -1
- package/dist/src/tools/browser-tools.d.ts +1 -0
- package/dist/src/tools/browser-tools.d.ts.map +1 -1
- package/dist/src/tools/browser-tools.js +2 -0
- package/dist/src/tools/browser-tools.js.map +1 -1
- package/dist/src/tools/index.d.ts +2 -0
- package/dist/src/tools/index.d.ts.map +1 -1
- package/dist/src/tools/index.js +3 -0
- package/dist/src/tools/index.js.map +1 -1
- package/dist/src/tools/navigation-tools.d.ts.map +1 -1
- package/dist/src/tools/navigation-tools.js +14 -9
- package/dist/src/tools/navigation-tools.js.map +1 -1
- package/dist/src/tools/network-tools.d.ts +10 -0
- package/dist/src/tools/network-tools.d.ts.map +1 -0
- package/dist/src/tools/network-tools.js +117 -0
- package/dist/src/tools/network-tools.js.map +1 -0
- package/dist/src/tools/tool-context.types.d.ts +6 -0
- package/dist/src/tools/tool-context.types.d.ts.map +1 -1
- package/dist/src/tools/tool-registration.d.ts +1 -1
- package/dist/src/tools/tool-registration.d.ts.map +1 -1
- package/dist/src/tools/tool-registration.js +16 -1
- package/dist/src/tools/tool-registration.js.map +1 -1
- package/dist/src/tools/tool-schemas.d.ts +93 -3
- package/dist/src/tools/tool-schemas.d.ts.map +1 -1
- package/dist/src/tools/tool-schemas.js +115 -6
- package/dist/src/tools/tool-schemas.js.map +1 -1
- package/dist/vitest.config.js +1 -1
- package/dist/vitest.config.js.map +1 -1
- package/dist/vitest.integration.config.d.ts +3 -0
- package/dist/vitest.integration.config.d.ts.map +1 -0
- package/dist/vitest.integration.config.js +11 -0
- package/dist/vitest.integration.config.js.map +1 -0
- package/package.json +14 -3
package/README.md
CHANGED
|
@@ -100,8 +100,6 @@ Example workflows include:
|
|
|
100
100
|
- Handling login and consent flows
|
|
101
101
|
- Performing multi-step UI interactions with lower token usage
|
|
102
102
|
|
|
103
|
-
See the `examples/` directory for concrete agent workflows.
|
|
104
|
-
|
|
105
103
|
---
|
|
106
104
|
|
|
107
105
|
## Claude Code
|
|
@@ -110,33 +108,30 @@ See the `examples/` directory for concrete agent workflows.
|
|
|
110
108
|
# Basic (auto-launches browser)
|
|
111
109
|
claude mcp add agent-web-interface -- npx agent-web-interface@latest
|
|
112
110
|
|
|
113
|
-
# With auto-connect to your Chrome profile
|
|
114
|
-
claude mcp add agent-web-interface -- npx agent-web-interface@latest
|
|
115
|
-
|
|
116
|
-
# Headless mode
|
|
117
|
-
claude mcp add agent-web-interface -- npx agent-web-interface@latest --headless
|
|
111
|
+
# With auto-connect to your Chrome profile (set via env var)
|
|
112
|
+
claude mcp add agent-web-interface -e AWI_CDP_URL=http://localhost:9222 -- npx agent-web-interface@latest
|
|
118
113
|
```
|
|
119
114
|
|
|
120
115
|
---
|
|
121
116
|
|
|
122
117
|
## CLI Arguments
|
|
123
118
|
|
|
124
|
-
The server accepts
|
|
119
|
+
The server accepts transport-level arguments only. Browser configuration is per-session via the `navigate` tool.
|
|
125
120
|
|
|
126
|
-
| Argument
|
|
127
|
-
|
|
|
128
|
-
| `--
|
|
129
|
-
| `--
|
|
130
|
-
| `--wsEndpoint` | WebSocket endpoint to connect to existing browser | - |
|
|
131
|
-
| `--autoConnect` | Auto-connect to Chrome 144+ via DevToolsActivePort | `false` |
|
|
132
|
-
| `--isolated` | Use isolated temp profile instead of persistent | `false` |
|
|
133
|
-
| `--userDataDir` | Chrome user data directory | Platform default |
|
|
134
|
-
| `--channel` | Chrome channel (chrome, chrome-canary, chrome-beta, chrome-dev) | `chrome` |
|
|
135
|
-
| `--executablePath` | Path to Chrome executable | - |
|
|
121
|
+
| Argument | Description | Default |
|
|
122
|
+
| ------------- | --------------------------------- | ------- |
|
|
123
|
+
| `--transport` | Transport mode: `stdio` or `http` | `stdio` |
|
|
124
|
+
| `--port` | Port for HTTP transport | `3000` |
|
|
136
125
|
|
|
137
|
-
###
|
|
126
|
+
### Browser Session Configuration
|
|
138
127
|
|
|
139
|
-
|
|
128
|
+
Browser initialization is automatic on the first tool call. The `navigate` tool accepts optional parameters to configure the session:
|
|
129
|
+
|
|
130
|
+
| Parameter | Description | Default |
|
|
131
|
+
| -------------- | -------------------------------------------------- | ------- |
|
|
132
|
+
| `headless` | Run browser in headless mode | `false` |
|
|
133
|
+
| `isolated` | Use an isolated temp profile instead of persistent | `false` |
|
|
134
|
+
| `auto_connect` | Auto-connect to Chrome 144+ via DevToolsActivePort | `false` |
|
|
140
135
|
|
|
141
136
|
Examples:
|
|
142
137
|
|
|
@@ -144,14 +139,11 @@ Examples:
|
|
|
144
139
|
# Auto-launch visible browser (default)
|
|
145
140
|
npx agent-web-interface
|
|
146
141
|
|
|
147
|
-
#
|
|
148
|
-
npx agent-web-interface --
|
|
149
|
-
|
|
150
|
-
# Auto-connect to Chrome with remote debugging enabled
|
|
151
|
-
npx agent-web-interface --autoConnect
|
|
142
|
+
# HTTP transport mode
|
|
143
|
+
npx agent-web-interface --transport http --port 8080
|
|
152
144
|
|
|
153
|
-
# Connect to
|
|
154
|
-
npx agent-web-interface
|
|
145
|
+
# Connect to existing CDP endpoint via env var
|
|
146
|
+
AWI_CDP_URL=http://localhost:9222 npx agent-web-interface
|
|
155
147
|
```
|
|
156
148
|
|
|
157
149
|
---
|
|
@@ -162,14 +154,17 @@ To connect with your bookmarks, extensions, and logged-in sessions:
|
|
|
162
154
|
|
|
163
155
|
1. Navigate to `chrome://inspect/#remote-debugging` in Chrome
|
|
164
156
|
2. Enable remote debugging and allow the connection
|
|
165
|
-
3. Use
|
|
157
|
+
3. Use the `auto_connect` parameter on the `navigate` tool, or set `AWI_CDP_URL`
|
|
166
158
|
|
|
167
159
|
```json
|
|
168
160
|
{
|
|
169
161
|
"mcpServers": {
|
|
170
162
|
"agent-web-interface": {
|
|
171
163
|
"command": "npx",
|
|
172
|
-
"args": ["agent-web-interface@latest",
|
|
164
|
+
"args": ["agent-web-interface@latest"],
|
|
165
|
+
"env": {
|
|
166
|
+
"AWI_CDP_URL": "http://localhost:9222"
|
|
167
|
+
}
|
|
173
168
|
}
|
|
174
169
|
}
|
|
175
170
|
}
|
|
@@ -179,11 +174,17 @@ To connect with your bookmarks, extensions, and logged-in sessions:
|
|
|
179
174
|
|
|
180
175
|
## Environment Variables
|
|
181
176
|
|
|
182
|
-
| Variable | Description
|
|
183
|
-
| ------------------ |
|
|
184
|
-
| `
|
|
185
|
-
| `
|
|
186
|
-
| `
|
|
177
|
+
| Variable | Description | Default |
|
|
178
|
+
| ------------------ | -------------------------------------------------------- | ----------- |
|
|
179
|
+
| `AWI_CDP_URL` | CDP endpoint (http or ws) to connect to existing browser | - |
|
|
180
|
+
| `AWI_TRIM_REGIONS` | Set to `false` to disable region trimming globally | `true` |
|
|
181
|
+
| `TRANSPORT` | Transport mode override (`http`) | - |
|
|
182
|
+
| `HTTP_HOST` | Host for HTTP transport | `127.0.0.1` |
|
|
183
|
+
| `HTTP_PORT` | Port for HTTP transport | `3000` |
|
|
184
|
+
| `LOG_LEVEL` | Logging level | `info` |
|
|
185
|
+
| `CEF_BRIDGE_HOST` | CDP host for CEF bridge connection | `127.0.0.1` |
|
|
186
|
+
| `CEF_BRIDGE_PORT` | CDP port for CEF bridge connection | `9223` |
|
|
187
|
+
| `CHROME_PATH` | Path to Chrome executable (multi-tenant) | - |
|
|
187
188
|
|
|
188
189
|
---
|
|
189
190
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-session-config.d.ts","sourceRoot":"","sources":["../../../src/browser/browser-session-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,yDAAyD;IACzD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,oBAAoB,
|
|
1
|
+
{"version":3,"file":"browser-session-config.d.ts","sourceRoot":"","sources":["../../../src/browser/browser-session-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,yDAAyD;IACzD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,oBAAoB,CAM3D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-session-config.js","sourceRoot":"","sources":["../../../src/browser/browser-session-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAmBH;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,QAAQ,EAAE,KAAK;QACf,QAAQ,EAAE,KAAK;
|
|
1
|
+
{"version":3,"file":"browser-session-config.js","sourceRoot":"","sources":["../../../src/browser/browser-session-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAmBH;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,QAAQ,EAAE,KAAK;QACf,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,IAAI;KAClB,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ensure-browser.d.ts","sourceRoot":"","sources":["../../../src/browser/ensure-browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AASxE;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"ensure-browser.d.ts","sourceRoot":"","sources":["../../../src/browser/ensure-browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AASxE;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAwFf"}
|
|
@@ -38,24 +38,37 @@ export async function ensureBrowserReady(session, config) {
|
|
|
38
38
|
}
|
|
39
39
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- empty string must be falsy
|
|
40
40
|
const cdpUrl = process.env.AWI_CDP_URL?.trim() || undefined;
|
|
41
|
-
|
|
42
|
-
if (
|
|
43
|
-
logger.info('Lazy browser initialization triggered', { mode: 'connect' });
|
|
41
|
+
// Explicit CDP URL — connect only, no fallback to launch
|
|
42
|
+
if (cdpUrl) {
|
|
43
|
+
logger.info('Lazy browser initialization triggered', { mode: 'connect', cdpUrl });
|
|
44
44
|
try {
|
|
45
|
-
await session.connect({
|
|
46
|
-
endpointUrl: cdpUrl,
|
|
47
|
-
autoConnect: config.autoConnect,
|
|
48
|
-
});
|
|
45
|
+
await session.connect({ endpointUrl: cdpUrl });
|
|
49
46
|
logger.info('Browser initialized successfully', { mode: 'connect' });
|
|
50
47
|
}
|
|
51
48
|
catch (error) {
|
|
49
|
+
const msg = extractErrorMessage(error);
|
|
52
50
|
logger.error('Browser initialization failed', error instanceof Error ? error : undefined, {
|
|
53
51
|
mode: 'connect',
|
|
54
52
|
});
|
|
55
|
-
throw
|
|
53
|
+
throw new Error(`Failed to connect to CDP endpoint (${cdpUrl}): ${msg}. ` +
|
|
54
|
+
'Try removing AWI_CDP_URL to auto-connect to a running Chrome, or launch a new browser with auto_connect=false.');
|
|
56
55
|
}
|
|
57
56
|
return;
|
|
58
57
|
}
|
|
58
|
+
// Auto-connect: try connecting to an existing Chrome first, fall back to launch
|
|
59
|
+
if (config.autoConnect) {
|
|
60
|
+
logger.info('Attempting auto-connect to existing Chrome');
|
|
61
|
+
try {
|
|
62
|
+
await session.connect({ autoConnect: true });
|
|
63
|
+
logger.info('Auto-connected to existing Chrome');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
logger.info('Auto-connect failed, falling back to launch', {
|
|
68
|
+
error: extractErrorMessage(error),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
59
72
|
// Launch mode — try reconnecting to an existing browser first (persistent profiles only)
|
|
60
73
|
const profileDir = config.isolated ? undefined : DEFAULT_USER_DATA_DIR;
|
|
61
74
|
if (profileDir && (await hasPortFile(profileDir)) && (await tryReconnect(session, profileDir))) {
|
|
@@ -76,11 +89,23 @@ export async function ensureBrowserReady(session, config) {
|
|
|
76
89
|
if (profileDir && isProfileLockError(error) && (await tryReconnect(session, profileDir))) {
|
|
77
90
|
return;
|
|
78
91
|
}
|
|
92
|
+
const msg = extractErrorMessage(error);
|
|
79
93
|
logger.error('Browser initialization failed', error instanceof Error ? error : undefined, {
|
|
80
94
|
mode: 'launch',
|
|
81
95
|
headless: config.headless,
|
|
82
96
|
});
|
|
83
|
-
|
|
97
|
+
const suggestions = [];
|
|
98
|
+
if (!config.headless) {
|
|
99
|
+
suggestions.push('try headless=true if no display is available');
|
|
100
|
+
}
|
|
101
|
+
if (!config.isolated) {
|
|
102
|
+
suggestions.push('try isolated=true to use a fresh profile');
|
|
103
|
+
}
|
|
104
|
+
if (config.headless) {
|
|
105
|
+
suggestions.push('try headless=false to launch a visible browser');
|
|
106
|
+
}
|
|
107
|
+
const hint = suggestions.length > 0 ? ` Suggestions: ${suggestions.join('; ')}.` : '';
|
|
108
|
+
throw new Error(`Failed to launch browser: ${msg}.${hint}`);
|
|
84
109
|
}
|
|
85
110
|
}
|
|
86
111
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ensure-browser.js","sourceRoot":"","sources":["../../../src/browser/ensure-browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,uCAAuC,CAAC;AAElE,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;AAE3B,6FAA6F;AAC7F,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAElC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAuB,EACvB,MAA4B;IAE5B,IAAI,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;QACxB,OAAO;IACT,CAAC;IAED,MAAM,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAClD,IAAI,OAAO,CAAC,eAAe,KAAK,YAAY,IAAI,eAAe,EAAE,CAAC;QAChE,MAAM,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;QACrD,MAAM,eAAe,CAAC;QACtB,OAAO;IACT,CAAC;IAED,sGAAsG;IACtG,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"ensure-browser.js","sourceRoot":"","sources":["../../../src/browser/ensure-browser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page Network Recorder
|
|
3
|
+
*
|
|
4
|
+
* Records network request/response details per page for the
|
|
5
|
+
* list_network_calls and search_network_calls tools.
|
|
6
|
+
*
|
|
7
|
+
* Uses Puppeteer page events (request, requestfinished, requestfailed)
|
|
8
|
+
* to capture entries. Memory-bounded via a ring buffer with
|
|
9
|
+
* configurable max entries.
|
|
10
|
+
*
|
|
11
|
+
* Follows the same lifecycle pattern as PageNetworkTracker:
|
|
12
|
+
* attach() → markNavigation() → detach()
|
|
13
|
+
*/
|
|
14
|
+
import type { Page } from 'puppeteer-core';
|
|
15
|
+
export interface NetworkEntry {
|
|
16
|
+
id: number;
|
|
17
|
+
url: string;
|
|
18
|
+
method: string;
|
|
19
|
+
resource_type: string;
|
|
20
|
+
is_navigation: boolean;
|
|
21
|
+
request_headers: Record<string, string>;
|
|
22
|
+
post_data: string | null;
|
|
23
|
+
started_at: number;
|
|
24
|
+
status: number | null;
|
|
25
|
+
status_text: string | null;
|
|
26
|
+
response_headers: Record<string, string> | null;
|
|
27
|
+
mime_type: string | null;
|
|
28
|
+
duration_ms: number | null;
|
|
29
|
+
failed: boolean;
|
|
30
|
+
failure_text: string | null;
|
|
31
|
+
navigation_id: number;
|
|
32
|
+
}
|
|
33
|
+
export interface NetworkFilter {
|
|
34
|
+
url_pattern?: string;
|
|
35
|
+
url_regex?: boolean;
|
|
36
|
+
method?: string;
|
|
37
|
+
resource_type?: string;
|
|
38
|
+
status_min?: number;
|
|
39
|
+
status_max?: number;
|
|
40
|
+
failed_only?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface NetworkQueryResult {
|
|
43
|
+
entries: NetworkEntry[];
|
|
44
|
+
total: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Records network request/response details for a single page.
|
|
48
|
+
*
|
|
49
|
+
* Uses a ring buffer (fixed-size array with head pointer) for O(1)
|
|
50
|
+
* insertion and eviction instead of Array.shift().
|
|
51
|
+
*/
|
|
52
|
+
export declare class PageNetworkRecorder {
|
|
53
|
+
private buffer;
|
|
54
|
+
private head;
|
|
55
|
+
private count;
|
|
56
|
+
private nextId;
|
|
57
|
+
private navigationId;
|
|
58
|
+
private maxEntries;
|
|
59
|
+
private page;
|
|
60
|
+
private generation;
|
|
61
|
+
private currentGeneration;
|
|
62
|
+
/** Map from HTTPRequest to NetworkEntry for response correlation */
|
|
63
|
+
private pending;
|
|
64
|
+
private onRequest;
|
|
65
|
+
private onRequestFinished;
|
|
66
|
+
private onRequestFailed;
|
|
67
|
+
constructor(maxEntries?: number);
|
|
68
|
+
attach(page: Page): void;
|
|
69
|
+
detach(): void;
|
|
70
|
+
markNavigation(): void;
|
|
71
|
+
getEntries(filter?: NetworkFilter, offset?: number, limit?: number): NetworkQueryResult;
|
|
72
|
+
search(urlPattern: string, isRegex?: boolean, filter?: NetworkFilter, limit?: number): NetworkQueryResult;
|
|
73
|
+
clear(): void;
|
|
74
|
+
getStats(): {
|
|
75
|
+
total: number;
|
|
76
|
+
pending: number;
|
|
77
|
+
failed: number;
|
|
78
|
+
by_resource_type: Record<string, number>;
|
|
79
|
+
};
|
|
80
|
+
isAttached(): boolean;
|
|
81
|
+
/** Iterate entries in insertion order (oldest first). */
|
|
82
|
+
private iterEntries;
|
|
83
|
+
/** Compile a URL regex once, with a safety check for pathological patterns. */
|
|
84
|
+
private compileUrlRegex;
|
|
85
|
+
private applyFilter;
|
|
86
|
+
/** Add an entry, evicting the oldest if at capacity. O(1). */
|
|
87
|
+
private addEntry;
|
|
88
|
+
private pickHeaders;
|
|
89
|
+
private createAndAttachHandlers;
|
|
90
|
+
private removeHandlers;
|
|
91
|
+
}
|
|
92
|
+
export declare function getOrCreateRecorder(page: Page, maxEntries?: number): PageNetworkRecorder;
|
|
93
|
+
export declare function removeRecorder(page: Page): void;
|
|
94
|
+
export declare function hasRecorder(page: Page): boolean;
|
|
95
|
+
//# sourceMappingURL=page-network-recorder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-network-recorder.d.ts","sourceRoot":"","sources":["../../../src/browser/page-network-recorder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page Network Recorder
|
|
3
|
+
*
|
|
4
|
+
* Records network request/response details per page for the
|
|
5
|
+
* list_network_calls and search_network_calls tools.
|
|
6
|
+
*
|
|
7
|
+
* Uses Puppeteer page events (request, requestfinished, requestfailed)
|
|
8
|
+
* to capture entries. Memory-bounded via a ring buffer with
|
|
9
|
+
* configurable max entries.
|
|
10
|
+
*
|
|
11
|
+
* Follows the same lifecycle pattern as PageNetworkTracker:
|
|
12
|
+
* attach() → markNavigation() → detach()
|
|
13
|
+
*/
|
|
14
|
+
/** Maximum post data size to store (bytes) */
|
|
15
|
+
const MAX_POST_DATA_SIZE = 2048;
|
|
16
|
+
/** Default maximum number of entries to retain */
|
|
17
|
+
const DEFAULT_MAX_ENTRIES = 1000;
|
|
18
|
+
/** Headers worth keeping on requests */
|
|
19
|
+
const KEPT_REQUEST_HEADERS = new Set([
|
|
20
|
+
'content-type',
|
|
21
|
+
'accept',
|
|
22
|
+
'content-length',
|
|
23
|
+
'x-requested-with',
|
|
24
|
+
]);
|
|
25
|
+
/** Headers worth keeping on responses */
|
|
26
|
+
const KEPT_RESPONSE_HEADERS = new Set([
|
|
27
|
+
'content-type',
|
|
28
|
+
'content-length',
|
|
29
|
+
'cache-control',
|
|
30
|
+
'location',
|
|
31
|
+
]);
|
|
32
|
+
/**
|
|
33
|
+
* Records network request/response details for a single page.
|
|
34
|
+
*
|
|
35
|
+
* Uses a ring buffer (fixed-size array with head pointer) for O(1)
|
|
36
|
+
* insertion and eviction instead of Array.shift().
|
|
37
|
+
*/
|
|
38
|
+
export class PageNetworkRecorder {
|
|
39
|
+
// Ring buffer: fixed-size array, head points to oldest entry
|
|
40
|
+
buffer;
|
|
41
|
+
head = 0;
|
|
42
|
+
count = 0;
|
|
43
|
+
nextId = 1;
|
|
44
|
+
navigationId = 0;
|
|
45
|
+
maxEntries;
|
|
46
|
+
page = null;
|
|
47
|
+
generation = 0;
|
|
48
|
+
currentGeneration = 0;
|
|
49
|
+
/** Map from HTTPRequest to NetworkEntry for response correlation */
|
|
50
|
+
pending = new Map();
|
|
51
|
+
onRequest = null;
|
|
52
|
+
onRequestFinished = null;
|
|
53
|
+
onRequestFailed = null;
|
|
54
|
+
constructor(maxEntries = DEFAULT_MAX_ENTRIES) {
|
|
55
|
+
this.maxEntries = maxEntries;
|
|
56
|
+
this.buffer = new Array(maxEntries).fill(null);
|
|
57
|
+
}
|
|
58
|
+
attach(page) {
|
|
59
|
+
if (this.page) {
|
|
60
|
+
this.detach();
|
|
61
|
+
}
|
|
62
|
+
this.page = page;
|
|
63
|
+
this.generation++;
|
|
64
|
+
this.currentGeneration = this.generation;
|
|
65
|
+
this.createAndAttachHandlers(page);
|
|
66
|
+
}
|
|
67
|
+
detach() {
|
|
68
|
+
if (this.page) {
|
|
69
|
+
this.removeHandlers(this.page);
|
|
70
|
+
}
|
|
71
|
+
this.onRequest = null;
|
|
72
|
+
this.onRequestFinished = null;
|
|
73
|
+
this.onRequestFailed = null;
|
|
74
|
+
this.page = null;
|
|
75
|
+
this.pending.clear();
|
|
76
|
+
}
|
|
77
|
+
markNavigation() {
|
|
78
|
+
this.navigationId++;
|
|
79
|
+
this.generation++;
|
|
80
|
+
this.currentGeneration = this.generation;
|
|
81
|
+
this.pending.clear();
|
|
82
|
+
if (this.page) {
|
|
83
|
+
this.removeHandlers(this.page);
|
|
84
|
+
this.createAndAttachHandlers(this.page);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
getEntries(filter, offset = 0, limit = 25) {
|
|
88
|
+
const filtered = this.applyFilter(filter);
|
|
89
|
+
return {
|
|
90
|
+
total: filtered.length,
|
|
91
|
+
entries: filtered.slice(offset, offset + limit),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
search(urlPattern, isRegex = false, filter, limit = 25) {
|
|
95
|
+
const combinedFilter = {
|
|
96
|
+
...filter,
|
|
97
|
+
url_pattern: urlPattern,
|
|
98
|
+
url_regex: isRegex,
|
|
99
|
+
};
|
|
100
|
+
const filtered = this.applyFilter(combinedFilter);
|
|
101
|
+
return { total: filtered.length, entries: filtered.slice(0, limit) };
|
|
102
|
+
}
|
|
103
|
+
clear() {
|
|
104
|
+
this.buffer = new Array(this.maxEntries).fill(null);
|
|
105
|
+
this.head = 0;
|
|
106
|
+
this.count = 0;
|
|
107
|
+
this.pending.clear();
|
|
108
|
+
this.nextId = 1;
|
|
109
|
+
}
|
|
110
|
+
getStats() {
|
|
111
|
+
let pendingCount = 0;
|
|
112
|
+
let failedCount = 0;
|
|
113
|
+
const byType = {};
|
|
114
|
+
for (const entry of this.iterEntries()) {
|
|
115
|
+
if (entry.status === null && !entry.failed)
|
|
116
|
+
pendingCount++;
|
|
117
|
+
if (entry.failed)
|
|
118
|
+
failedCount++;
|
|
119
|
+
byType[entry.resource_type] = (byType[entry.resource_type] ?? 0) + 1;
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
total: this.count,
|
|
123
|
+
pending: pendingCount,
|
|
124
|
+
failed: failedCount,
|
|
125
|
+
by_resource_type: byType,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
isAttached() {
|
|
129
|
+
return this.page !== null;
|
|
130
|
+
}
|
|
131
|
+
// --- Private methods ---
|
|
132
|
+
/** Iterate entries in insertion order (oldest first). */
|
|
133
|
+
*iterEntries() {
|
|
134
|
+
for (let i = 0; i < this.count; i++) {
|
|
135
|
+
const idx = (this.head + i) % this.maxEntries;
|
|
136
|
+
const entry = this.buffer[idx];
|
|
137
|
+
if (entry)
|
|
138
|
+
yield entry;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/** Compile a URL regex once, with a safety check for pathological patterns. */
|
|
142
|
+
compileUrlRegex(pattern) {
|
|
143
|
+
try {
|
|
144
|
+
return new RegExp(pattern);
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
applyFilter(filter) {
|
|
151
|
+
if (!filter)
|
|
152
|
+
return Array.from(this.iterEntries());
|
|
153
|
+
// Pre-compile regex once instead of per-entry
|
|
154
|
+
let urlRegex = null;
|
|
155
|
+
if (filter.url_pattern && filter.url_regex) {
|
|
156
|
+
urlRegex = this.compileUrlRegex(filter.url_pattern);
|
|
157
|
+
}
|
|
158
|
+
const results = [];
|
|
159
|
+
for (const e of this.iterEntries()) {
|
|
160
|
+
if (filter.method && e.method.toUpperCase() !== filter.method.toUpperCase())
|
|
161
|
+
continue;
|
|
162
|
+
if (filter.resource_type && e.resource_type !== filter.resource_type)
|
|
163
|
+
continue;
|
|
164
|
+
if (filter.status_min != null && (e.status === null || e.status < filter.status_min))
|
|
165
|
+
continue;
|
|
166
|
+
if (filter.status_max != null && (e.status === null || e.status > filter.status_max))
|
|
167
|
+
continue;
|
|
168
|
+
if (filter.failed_only && !e.failed)
|
|
169
|
+
continue;
|
|
170
|
+
if (filter.url_pattern) {
|
|
171
|
+
if (urlRegex) {
|
|
172
|
+
if (!urlRegex.test(e.url))
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
else if (filter.url_regex) {
|
|
176
|
+
// Regex compilation failed — fall back to substring
|
|
177
|
+
if (!e.url.includes(filter.url_pattern))
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
if (!e.url.includes(filter.url_pattern))
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
results.push(e);
|
|
186
|
+
}
|
|
187
|
+
return results;
|
|
188
|
+
}
|
|
189
|
+
/** Add an entry, evicting the oldest if at capacity. O(1). */
|
|
190
|
+
addEntry(entry) {
|
|
191
|
+
if (this.count >= this.maxEntries) {
|
|
192
|
+
// Overwrite oldest entry at head
|
|
193
|
+
this.buffer[this.head] = entry;
|
|
194
|
+
this.head = (this.head + 1) % this.maxEntries;
|
|
195
|
+
// No need to clean up pending — evicted entries that are still pending
|
|
196
|
+
// will simply not be found in the pending Map lookup (harmless no-op)
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
const idx = (this.head + this.count) % this.maxEntries;
|
|
200
|
+
this.buffer[idx] = entry;
|
|
201
|
+
this.count++;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
pickHeaders(headers, kept) {
|
|
205
|
+
const result = {};
|
|
206
|
+
for (const key of Object.keys(headers)) {
|
|
207
|
+
if (kept.has(key.toLowerCase())) {
|
|
208
|
+
result[key.toLowerCase()] = headers[key];
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
createAndAttachHandlers(page) {
|
|
214
|
+
const gen = this.currentGeneration;
|
|
215
|
+
this.onRequest = (req) => {
|
|
216
|
+
if (this.currentGeneration !== gen)
|
|
217
|
+
return;
|
|
218
|
+
if (req.resourceType() === 'websocket')
|
|
219
|
+
return;
|
|
220
|
+
let postData = req.postData() ?? null;
|
|
221
|
+
if (postData && postData.length > MAX_POST_DATA_SIZE) {
|
|
222
|
+
postData = postData.slice(0, MAX_POST_DATA_SIZE) + '…[truncated]';
|
|
223
|
+
}
|
|
224
|
+
const entry = {
|
|
225
|
+
id: this.nextId++,
|
|
226
|
+
url: req.url(),
|
|
227
|
+
method: req.method(),
|
|
228
|
+
resource_type: req.resourceType(),
|
|
229
|
+
is_navigation: req.isNavigationRequest(),
|
|
230
|
+
request_headers: this.pickHeaders(req.headers(), KEPT_REQUEST_HEADERS),
|
|
231
|
+
post_data: postData,
|
|
232
|
+
started_at: Date.now(),
|
|
233
|
+
status: null,
|
|
234
|
+
status_text: null,
|
|
235
|
+
response_headers: null,
|
|
236
|
+
mime_type: null,
|
|
237
|
+
duration_ms: null,
|
|
238
|
+
failed: false,
|
|
239
|
+
failure_text: null,
|
|
240
|
+
navigation_id: this.navigationId,
|
|
241
|
+
};
|
|
242
|
+
this.addEntry(entry);
|
|
243
|
+
this.pending.set(req, entry);
|
|
244
|
+
};
|
|
245
|
+
this.onRequestFinished = (req) => {
|
|
246
|
+
if (this.currentGeneration !== gen)
|
|
247
|
+
return;
|
|
248
|
+
const entry = this.pending.get(req);
|
|
249
|
+
if (!entry)
|
|
250
|
+
return;
|
|
251
|
+
this.pending.delete(req);
|
|
252
|
+
const response = req.response();
|
|
253
|
+
if (response) {
|
|
254
|
+
entry.status = response.status();
|
|
255
|
+
entry.status_text = response.statusText();
|
|
256
|
+
entry.response_headers = this.pickHeaders(response.headers(), KEPT_RESPONSE_HEADERS);
|
|
257
|
+
const ct = response.headers()['content-type'];
|
|
258
|
+
entry.mime_type = ct ? ct.split(';')[0].trim() : null;
|
|
259
|
+
}
|
|
260
|
+
entry.duration_ms = Date.now() - entry.started_at;
|
|
261
|
+
};
|
|
262
|
+
this.onRequestFailed = (req) => {
|
|
263
|
+
if (this.currentGeneration !== gen)
|
|
264
|
+
return;
|
|
265
|
+
const entry = this.pending.get(req);
|
|
266
|
+
if (!entry)
|
|
267
|
+
return;
|
|
268
|
+
this.pending.delete(req);
|
|
269
|
+
entry.failed = true;
|
|
270
|
+
entry.failure_text = req.failure()?.errorText ?? null;
|
|
271
|
+
entry.duration_ms = Date.now() - entry.started_at;
|
|
272
|
+
};
|
|
273
|
+
page.on('request', this.onRequest);
|
|
274
|
+
page.on('requestfinished', this.onRequestFinished);
|
|
275
|
+
page.on('requestfailed', this.onRequestFailed);
|
|
276
|
+
}
|
|
277
|
+
removeHandlers(page) {
|
|
278
|
+
if (this.onRequest)
|
|
279
|
+
page.off('request', this.onRequest);
|
|
280
|
+
if (this.onRequestFinished)
|
|
281
|
+
page.off('requestfinished', this.onRequestFinished);
|
|
282
|
+
if (this.onRequestFailed)
|
|
283
|
+
page.off('requestfailed', this.onRequestFailed);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
// --- Global Registry ---
|
|
287
|
+
const recorders = new WeakMap();
|
|
288
|
+
export function getOrCreateRecorder(page, maxEntries) {
|
|
289
|
+
let recorder = recorders.get(page);
|
|
290
|
+
if (!recorder) {
|
|
291
|
+
recorder = new PageNetworkRecorder(maxEntries);
|
|
292
|
+
recorders.set(page, recorder);
|
|
293
|
+
}
|
|
294
|
+
return recorder;
|
|
295
|
+
}
|
|
296
|
+
export function removeRecorder(page) {
|
|
297
|
+
const recorder = recorders.get(page);
|
|
298
|
+
if (recorder) {
|
|
299
|
+
recorder.detach();
|
|
300
|
+
recorders.delete(page);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
export function hasRecorder(page) {
|
|
304
|
+
return recorders.has(page);
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=page-network-recorder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-network-recorder.js","sourceRoot":"","sources":["../../../src/browser/page-network-recorder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,8CAA8C;AAC9C,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC,kDAAkD;AAClD,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC,wCAAwC;AACxC,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,cAAc;IACd,QAAQ;IACR,gBAAgB;IAChB,kBAAkB;CACnB,CAAC,CAAC;AAEH,yCAAyC;AACzC,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC;IACpC,cAAc;IACd,gBAAgB;IAChB,eAAe;IACf,UAAU;CACX,CAAC,CAAC;AAoCH;;;;;GAKG;AACH,MAAM,OAAO,mBAAmB;IAC9B,6DAA6D;IACrD,MAAM,CAA0B;IAChC,IAAI,GAAG,CAAC,CAAC;IACT,KAAK,GAAG,CAAC,CAAC;IACV,MAAM,GAAG,CAAC,CAAC;IACX,YAAY,GAAG,CAAC,CAAC;IACjB,UAAU,CAAS;IACnB,IAAI,GAAgB,IAAI,CAAC;IACzB,UAAU,GAAG,CAAC,CAAC;IACf,iBAAiB,GAAG,CAAC,CAAC;IAE9B,oEAAoE;IAC5D,OAAO,GAAG,IAAI,GAAG,EAA6B,CAAC;IAE/C,SAAS,GAAwC,IAAI,CAAC;IACtD,iBAAiB,GAAwC,IAAI,CAAC;IAC9D,eAAe,GAAwC,IAAI,CAAC;IAEpE,YAAY,UAAU,GAAG,mBAAmB;QAC1C,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,IAAI,KAAK,CAAsB,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,CAAC,IAAU;QACf,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,CAAC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,UAAU,CAAC;QAEzC,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC;QAED,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;QAC9B,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED,cAAc;QACZ,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,UAAU,CAAC;QACzC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAErB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,UAAU,CAAC,MAAsB,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG,EAAE;QACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC1C,OAAO;YACL,KAAK,EAAE,QAAQ,CAAC,MAAM;YACtB,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC;SAChD,CAAC;IACJ,CAAC;IAED,MAAM,CACJ,UAAkB,EAClB,OAAO,GAAG,KAAK,EACf,MAAsB,EACtB,KAAK,GAAG,EAAE;QAEV,MAAM,cAAc,GAAkB;YACpC,GAAG,MAAM;YACT,WAAW,EAAE,UAAU;YACvB,SAAS,EAAE,OAAO;SACnB,CAAC;QACF,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;QAClD,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;IACvE,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,IAAI,KAAK,CAAsB,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzE,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAClB,CAAC;IAED,QAAQ;QAMN,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,MAAM,MAAM,GAA2B,EAAE,CAAC;QAE1C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACvC,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM;gBAAE,YAAY,EAAE,CAAC;YAC3D,IAAI,KAAK,CAAC,MAAM;gBAAE,WAAW,EAAE,CAAC;YAChC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACvE,CAAC;QAED,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,YAAY;YACrB,MAAM,EAAE,WAAW;YACnB,gBAAgB,EAAE,MAAM;SACzB,CAAC;IACJ,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC;IAC5B,CAAC;IAED,0BAA0B;IAE1B,yDAAyD;IACjD,CAAC,WAAW;QAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;YAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,KAAK;gBAAE,MAAM,KAAK,CAAC;QACzB,CAAC;IACH,CAAC;IAED,+EAA+E;IACvE,eAAe,CAAC,OAAe;QACrC,IAAI,CAAC;YACH,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAEO,WAAW,CAAC,MAAsB;QACxC,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAEnD,8CAA8C;QAC9C,IAAI,QAAQ,GAAkB,IAAI,CAAC;QACnC,IAAI,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YAC3C,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACtD,CAAC;QAED,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACnC,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE;gBAAE,SAAS;YACtF,IAAI,MAAM,CAAC,aAAa,IAAI,CAAC,CAAC,aAAa,KAAK,MAAM,CAAC,aAAa;gBAAE,SAAS;YAC/E,IAAI,MAAM,CAAC,UAAU,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC;gBAClF,SAAS;YACX,IAAI,MAAM,CAAC,UAAU,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC;gBAClF,SAAS;YACX,IAAI,MAAM,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,MAAM;gBAAE,SAAS;YAC9C,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;gBACvB,IAAI,QAAQ,EAAE,CAAC;oBACb,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;wBAAE,SAAS;gBACtC,CAAC;qBAAM,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;oBAC5B,oDAAoD;oBACpD,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC;wBAAE,SAAS;gBACpD,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC;wBAAE,SAAS;gBACpD,CAAC;YACH,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,8DAA8D;IACtD,QAAQ,CAAC,KAAmB;QAClC,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAClC,iCAAiC;YACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;YAC/B,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;YAC9C,uEAAuE;YACvE,sEAAsE;QACxE,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;YACvD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YACzB,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC;IACH,CAAC;IAEO,WAAW,CAAC,OAA+B,EAAE,IAAiB;QACpE,MAAM,MAAM,GAA2B,EAAE,CAAC;QAC1C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACvC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;gBAChC,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,uBAAuB,CAAC,IAAU;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,CAAC;QAEnC,IAAI,CAAC,SAAS,GAAG,CAAC,GAAgB,EAAE,EAAE;YACpC,IAAI,IAAI,CAAC,iBAAiB,KAAK,GAAG;gBAAE,OAAO;YAC3C,IAAI,GAAG,CAAC,YAAY,EAAE,KAAK,WAAW;gBAAE,OAAO;YAE/C,IAAI,QAAQ,GAAG,GAAG,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC;YACtC,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,kBAAkB,EAAE,CAAC;gBACrD,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,kBAAkB,CAAC,GAAG,cAAc,CAAC;YACpE,CAAC;YAED,MAAM,KAAK,GAAiB;gBAC1B,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE;gBACjB,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE;gBACd,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE;gBACpB,aAAa,EAAE,GAAG,CAAC,YAAY,EAAE;gBACjC,aAAa,EAAE,GAAG,CAAC,mBAAmB,EAAE;gBACxC,eAAe,EAAE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,oBAAoB,CAAC;gBACtE,SAAS,EAAE,QAAQ;gBACnB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;gBACtB,MAAM,EAAE,IAAI;gBACZ,WAAW,EAAE,IAAI;gBACjB,gBAAgB,EAAE,IAAI;gBACtB,SAAS,EAAE,IAAI;gBACf,WAAW,EAAE,IAAI;gBACjB,MAAM,EAAE,KAAK;gBACb,YAAY,EAAE,IAAI;gBAClB,aAAa,EAAE,IAAI,CAAC,YAAY;aACjC,CAAC;YAEF,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YACrB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC,CAAC;QAEF,IAAI,CAAC,iBAAiB,GAAG,CAAC,GAAgB,EAAE,EAAE;YAC5C,IAAI,IAAI,CAAC,iBAAiB,KAAK,GAAG;gBAAE,OAAO;YAE3C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACpC,IAAI,CAAC,KAAK;gBAAE,OAAO;YACnB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAEzB,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;YAChC,IAAI,QAAQ,EAAE,CAAC;gBACb,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;gBACjC,KAAK,CAAC,WAAW,GAAG,QAAQ,CAAC,UAAU,EAAE,CAAC;gBAC1C,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,qBAAqB,CAAC,CAAC;gBACrF,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,cAAc,CAAC,CAAC;gBAC9C,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YACxD,CAAC;YACD,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC;QACpD,CAAC,CAAC;QAEF,IAAI,CAAC,eAAe,GAAG,CAAC,GAAgB,EAAE,EAAE;YAC1C,IAAI,IAAI,CAAC,iBAAiB,KAAK,GAAG;gBAAE,OAAO;YAE3C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACpC,IAAI,CAAC,KAAK;gBAAE,OAAO;YACnB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAEzB,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;YACpB,KAAK,CAAC,YAAY,GAAG,GAAG,CAAC,OAAO,EAAE,EAAE,SAAS,IAAI,IAAI,CAAC;YACtD,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC;QACpD,CAAC,CAAC;QAEF,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACnC,IAAI,CAAC,EAAE,CAAC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACnD,IAAI,CAAC,EAAE,CAAC,eAAe,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;IACjD,CAAC;IAEO,cAAc,CAAC,IAAU;QAC/B,IAAI,IAAI,CAAC,SAAS;YAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACxD,IAAI,IAAI,CAAC,iBAAiB;YAAE,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAChF,IAAI,IAAI,CAAC,eAAe;YAAE,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;IAC5E,CAAC;CACF;AAED,0BAA0B;AAE1B,MAAM,SAAS,GAAG,IAAI,OAAO,EAA6B,CAAC;AAE3D,MAAM,UAAU,mBAAmB,CAAC,IAAU,EAAE,UAAmB;IACjE,IAAI,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,QAAQ,GAAG,IAAI,mBAAmB,CAAC,UAAU,CAAC,CAAC;QAC/C,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAU;IACvC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,QAAQ,EAAE,CAAC;QACb,QAAQ,CAAC,MAAM,EAAE,CAAC;QAClB,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAU;IACpC,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC"}
|