|
f7eb47b…
|
lmata
|
1 |
"use strict"; |
|
f7eb47b…
|
lmata
|
2 |
var __create = Object.create; |
|
f7eb47b…
|
lmata
|
3 |
var __defProp = Object.defineProperty; |
|
f7eb47b…
|
lmata
|
4 |
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; |
|
f7eb47b…
|
lmata
|
5 |
var __getOwnPropNames = Object.getOwnPropertyNames; |
|
f7eb47b…
|
lmata
|
6 |
var __getProtoOf = Object.getPrototypeOf; |
|
f7eb47b…
|
lmata
|
7 |
var __hasOwnProp = Object.prototype.hasOwnProperty; |
|
f7eb47b…
|
lmata
|
8 |
var __export = (target, all) => { |
|
f7eb47b…
|
lmata
|
9 |
for (var name in all) |
|
f7eb47b…
|
lmata
|
10 |
__defProp(target, name, { get: all[name], enumerable: true }); |
|
f7eb47b…
|
lmata
|
11 |
}; |
|
f7eb47b…
|
lmata
|
12 |
var __copyProps = (to, from, except, desc) => { |
|
f7eb47b…
|
lmata
|
13 |
if (from && typeof from === "object" || typeof from === "function") { |
|
f7eb47b…
|
lmata
|
14 |
for (let key of __getOwnPropNames(from)) |
|
f7eb47b…
|
lmata
|
15 |
if (!__hasOwnProp.call(to, key) && key !== except) |
|
f7eb47b…
|
lmata
|
16 |
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); |
|
f7eb47b…
|
lmata
|
17 |
} |
|
f7eb47b…
|
lmata
|
18 |
return to; |
|
f7eb47b…
|
lmata
|
19 |
}; |
|
f7eb47b…
|
lmata
|
20 |
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( |
|
f7eb47b…
|
lmata
|
21 |
// If the importer is in node compatibility mode or this is not an ESM |
|
f7eb47b…
|
lmata
|
22 |
// file that has been converted to a CommonJS file using a Babel- |
|
f7eb47b…
|
lmata
|
23 |
// compatible transform (i.e. "__esModule" has not been set), then set |
|
f7eb47b…
|
lmata
|
24 |
// "default" to the CommonJS "module.exports" for node compatibility. |
|
f7eb47b…
|
lmata
|
25 |
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, |
|
f7eb47b…
|
lmata
|
26 |
mod |
|
f7eb47b…
|
lmata
|
27 |
)); |
|
f7eb47b…
|
lmata
|
28 |
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); |
|
f7eb47b…
|
lmata
|
29 |
var cdpRelay_exports = {}; |
|
f7eb47b…
|
lmata
|
30 |
__export(cdpRelay_exports, { |
|
f7eb47b…
|
lmata
|
31 |
CDPRelayServer: () => CDPRelayServer |
|
f7eb47b…
|
lmata
|
32 |
}); |
|
f7eb47b…
|
lmata
|
33 |
module.exports = __toCommonJS(cdpRelay_exports); |
|
f7eb47b…
|
lmata
|
34 |
var import_child_process = require("child_process"); |
|
f7eb47b…
|
lmata
|
35 |
var import_utilsBundle = require("playwright-core/lib/utilsBundle"); |
|
f7eb47b…
|
lmata
|
36 |
var import_registry = require("playwright-core/lib/server/registry/index"); |
|
f7eb47b…
|
lmata
|
37 |
var import_utils = require("playwright-core/lib/utils"); |
|
f7eb47b…
|
lmata
|
38 |
var import_http2 = require("../sdk/http"); |
|
f7eb47b…
|
lmata
|
39 |
var import_log = require("../log"); |
|
f7eb47b…
|
lmata
|
40 |
var protocol = __toESM(require("./protocol")); |
|
f7eb47b…
|
lmata
|
41 |
const debugLogger = (0, import_utilsBundle.debug)("pw:mcp:relay"); |
|
f7eb47b…
|
lmata
|
42 |
class CDPRelayServer { |
|
f7eb47b…
|
lmata
|
43 |
constructor(server, browserChannel, userDataDir, executablePath) { |
|
f7eb47b…
|
lmata
|
44 |
this._playwrightConnection = null; |
|
f7eb47b…
|
lmata
|
45 |
this._extensionConnection = null; |
|
f7eb47b…
|
lmata
|
46 |
this._nextSessionId = 1; |
|
f7eb47b…
|
lmata
|
47 |
this._wsHost = (0, import_http2.addressToString)(server.address(), { protocol: "ws" }); |
|
f7eb47b…
|
lmata
|
48 |
this._browserChannel = browserChannel; |
|
f7eb47b…
|
lmata
|
49 |
this._userDataDir = userDataDir; |
|
f7eb47b…
|
lmata
|
50 |
this._executablePath = executablePath; |
|
f7eb47b…
|
lmata
|
51 |
const uuid = crypto.randomUUID(); |
|
f7eb47b…
|
lmata
|
52 |
this._cdpPath = `/cdp/${uuid}`; |
|
f7eb47b…
|
lmata
|
53 |
this._extensionPath = `/extension/${uuid}`; |
|
f7eb47b…
|
lmata
|
54 |
this._resetExtensionConnection(); |
|
f7eb47b…
|
lmata
|
55 |
this._wss = new import_utilsBundle.wsServer({ server }); |
|
f7eb47b…
|
lmata
|
56 |
this._wss.on("connection", this._onConnection.bind(this)); |
|
f7eb47b…
|
lmata
|
57 |
} |
|
f7eb47b…
|
lmata
|
58 |
cdpEndpoint() { |
|
f7eb47b…
|
lmata
|
59 |
return `${this._wsHost}${this._cdpPath}`; |
|
f7eb47b…
|
lmata
|
60 |
} |
|
f7eb47b…
|
lmata
|
61 |
extensionEndpoint() { |
|
f7eb47b…
|
lmata
|
62 |
return `${this._wsHost}${this._extensionPath}`; |
|
f7eb47b…
|
lmata
|
63 |
} |
|
f7eb47b…
|
lmata
|
64 |
async ensureExtensionConnectionForMCPContext(clientInfo, abortSignal, toolName) { |
|
f7eb47b…
|
lmata
|
65 |
debugLogger("Ensuring extension connection for MCP context"); |
|
f7eb47b…
|
lmata
|
66 |
if (this._extensionConnection) |
|
f7eb47b…
|
lmata
|
67 |
return; |
|
f7eb47b…
|
lmata
|
68 |
this._connectBrowser(clientInfo, toolName); |
|
f7eb47b…
|
lmata
|
69 |
debugLogger("Waiting for incoming extension connection"); |
|
f7eb47b…
|
lmata
|
70 |
await Promise.race([ |
|
f7eb47b…
|
lmata
|
71 |
this._extensionConnectionPromise, |
|
f7eb47b…
|
lmata
|
72 |
new Promise((_, reject) => setTimeout(() => { |
|
f7eb47b…
|
lmata
|
73 |
reject(new Error(`Extension connection timeout. Make sure the "Playwright MCP Bridge" extension is installed. See https://github.com/microsoft/playwright-mcp/blob/main/extension/README.md for installation instructions.`)); |
|
f7eb47b…
|
lmata
|
74 |
}, process.env.PWMCP_TEST_CONNECTION_TIMEOUT ? parseInt(process.env.PWMCP_TEST_CONNECTION_TIMEOUT, 10) : 5e3)), |
|
f7eb47b…
|
lmata
|
75 |
new Promise((_, reject) => abortSignal.addEventListener("abort", reject)) |
|
f7eb47b…
|
lmata
|
76 |
]); |
|
f7eb47b…
|
lmata
|
77 |
debugLogger("Extension connection established"); |
|
f7eb47b…
|
lmata
|
78 |
} |
|
f7eb47b…
|
lmata
|
79 |
_connectBrowser(clientInfo, toolName) { |
|
f7eb47b…
|
lmata
|
80 |
const mcpRelayEndpoint = `${this._wsHost}${this._extensionPath}`; |
|
f7eb47b…
|
lmata
|
81 |
const url = new URL("chrome-extension://jakfalbnbhgkpmoaakfflhflbfpkailf/connect.html"); |
|
f7eb47b…
|
lmata
|
82 |
url.searchParams.set("mcpRelayUrl", mcpRelayEndpoint); |
|
f7eb47b…
|
lmata
|
83 |
const client = { |
|
f7eb47b…
|
lmata
|
84 |
name: clientInfo.name, |
|
f7eb47b…
|
lmata
|
85 |
version: clientInfo.version |
|
f7eb47b…
|
lmata
|
86 |
}; |
|
f7eb47b…
|
lmata
|
87 |
url.searchParams.set("client", JSON.stringify(client)); |
|
f7eb47b…
|
lmata
|
88 |
url.searchParams.set("protocolVersion", process.env.PWMCP_TEST_PROTOCOL_VERSION ?? protocol.VERSION.toString()); |
|
f7eb47b…
|
lmata
|
89 |
if (toolName) |
|
f7eb47b…
|
lmata
|
90 |
url.searchParams.set("newTab", String(toolName === "browser_navigate")); |
|
f7eb47b…
|
lmata
|
91 |
const token = process.env.PLAYWRIGHT_MCP_EXTENSION_TOKEN; |
|
f7eb47b…
|
lmata
|
92 |
if (token) |
|
f7eb47b…
|
lmata
|
93 |
url.searchParams.set("token", token); |
|
f7eb47b…
|
lmata
|
94 |
const href = url.toString(); |
|
f7eb47b…
|
lmata
|
95 |
let executablePath = this._executablePath; |
|
f7eb47b…
|
lmata
|
96 |
if (!executablePath) { |
|
f7eb47b…
|
lmata
|
97 |
const executableInfo = import_registry.registry.findExecutable(this._browserChannel); |
|
f7eb47b…
|
lmata
|
98 |
if (!executableInfo) |
|
f7eb47b…
|
lmata
|
99 |
throw new Error(`Unsupported channel: "${this._browserChannel}"`); |
|
f7eb47b…
|
lmata
|
100 |
executablePath = executableInfo.executablePath("javascript"); |
|
f7eb47b…
|
lmata
|
101 |
if (!executablePath) |
|
f7eb47b…
|
lmata
|
102 |
throw new Error(`"${this._browserChannel}" executable not found. Make sure it is installed at a standard location.`); |
|
f7eb47b…
|
lmata
|
103 |
} |
|
f7eb47b…
|
lmata
|
104 |
const args = []; |
|
f7eb47b…
|
lmata
|
105 |
if (this._userDataDir) |
|
f7eb47b…
|
lmata
|
106 |
args.push(`--user-data-dir=${this._userDataDir}`); |
|
f7eb47b…
|
lmata
|
107 |
args.push(href); |
|
f7eb47b…
|
lmata
|
108 |
(0, import_child_process.spawn)(executablePath, args, { |
|
f7eb47b…
|
lmata
|
109 |
windowsHide: true, |
|
f7eb47b…
|
lmata
|
110 |
detached: true, |
|
f7eb47b…
|
lmata
|
111 |
shell: false, |
|
f7eb47b…
|
lmata
|
112 |
stdio: "ignore" |
|
f7eb47b…
|
lmata
|
113 |
}); |
|
f7eb47b…
|
lmata
|
114 |
} |
|
f7eb47b…
|
lmata
|
115 |
stop() { |
|
f7eb47b…
|
lmata
|
116 |
this.closeConnections("Server stopped"); |
|
f7eb47b…
|
lmata
|
117 |
this._wss.close(); |
|
f7eb47b…
|
lmata
|
118 |
} |
|
f7eb47b…
|
lmata
|
119 |
closeConnections(reason) { |
|
f7eb47b…
|
lmata
|
120 |
this._closePlaywrightConnection(reason); |
|
f7eb47b…
|
lmata
|
121 |
this._closeExtensionConnection(reason); |
|
f7eb47b…
|
lmata
|
122 |
} |
|
f7eb47b…
|
lmata
|
123 |
_onConnection(ws2, request) { |
|
f7eb47b…
|
lmata
|
124 |
const url = new URL(`http://localhost${request.url}`); |
|
f7eb47b…
|
lmata
|
125 |
debugLogger(`New connection to ${url.pathname}`); |
|
f7eb47b…
|
lmata
|
126 |
if (url.pathname === this._cdpPath) { |
|
f7eb47b…
|
lmata
|
127 |
this._handlePlaywrightConnection(ws2); |
|
f7eb47b…
|
lmata
|
128 |
} else if (url.pathname === this._extensionPath) { |
|
f7eb47b…
|
lmata
|
129 |
this._handleExtensionConnection(ws2); |
|
f7eb47b…
|
lmata
|
130 |
} else { |
|
f7eb47b…
|
lmata
|
131 |
debugLogger(`Invalid path: ${url.pathname}`); |
|
f7eb47b…
|
lmata
|
132 |
ws2.close(4004, "Invalid path"); |
|
f7eb47b…
|
lmata
|
133 |
} |
|
f7eb47b…
|
lmata
|
134 |
} |
|
f7eb47b…
|
lmata
|
135 |
_handlePlaywrightConnection(ws2) { |
|
f7eb47b…
|
lmata
|
136 |
if (this._playwrightConnection) { |
|
f7eb47b…
|
lmata
|
137 |
debugLogger("Rejecting second Playwright connection"); |
|
f7eb47b…
|
lmata
|
138 |
ws2.close(1e3, "Another CDP client already connected"); |
|
f7eb47b…
|
lmata
|
139 |
return; |
|
f7eb47b…
|
lmata
|
140 |
} |
|
f7eb47b…
|
lmata
|
141 |
this._playwrightConnection = ws2; |
|
f7eb47b…
|
lmata
|
142 |
ws2.on("message", async (data) => { |
|
f7eb47b…
|
lmata
|
143 |
try { |
|
f7eb47b…
|
lmata
|
144 |
const message = JSON.parse(data.toString()); |
|
f7eb47b…
|
lmata
|
145 |
await this._handlePlaywrightMessage(message); |
|
f7eb47b…
|
lmata
|
146 |
} catch (error) { |
|
f7eb47b…
|
lmata
|
147 |
debugLogger(`Error while handling Playwright message |
|
f7eb47b…
|
lmata
|
148 |
${data.toString()} |
|
f7eb47b…
|
lmata
|
149 |
`, error); |
|
f7eb47b…
|
lmata
|
150 |
} |
|
f7eb47b…
|
lmata
|
151 |
}); |
|
f7eb47b…
|
lmata
|
152 |
ws2.on("close", () => { |
|
f7eb47b…
|
lmata
|
153 |
if (this._playwrightConnection !== ws2) |
|
f7eb47b…
|
lmata
|
154 |
return; |
|
f7eb47b…
|
lmata
|
155 |
this._playwrightConnection = null; |
|
f7eb47b…
|
lmata
|
156 |
this._closeExtensionConnection("Playwright client disconnected"); |
|
f7eb47b…
|
lmata
|
157 |
debugLogger("Playwright WebSocket closed"); |
|
f7eb47b…
|
lmata
|
158 |
}); |
|
f7eb47b…
|
lmata
|
159 |
ws2.on("error", (error) => { |
|
f7eb47b…
|
lmata
|
160 |
debugLogger("Playwright WebSocket error:", error); |
|
f7eb47b…
|
lmata
|
161 |
}); |
|
f7eb47b…
|
lmata
|
162 |
debugLogger("Playwright MCP connected"); |
|
f7eb47b…
|
lmata
|
163 |
} |
|
f7eb47b…
|
lmata
|
164 |
_closeExtensionConnection(reason) { |
|
f7eb47b…
|
lmata
|
165 |
this._extensionConnection?.close(reason); |
|
f7eb47b…
|
lmata
|
166 |
this._extensionConnectionPromise.reject(new Error(reason)); |
|
f7eb47b…
|
lmata
|
167 |
this._resetExtensionConnection(); |
|
f7eb47b…
|
lmata
|
168 |
} |
|
f7eb47b…
|
lmata
|
169 |
_resetExtensionConnection() { |
|
f7eb47b…
|
lmata
|
170 |
this._connectedTabInfo = void 0; |
|
f7eb47b…
|
lmata
|
171 |
this._extensionConnection = null; |
|
f7eb47b…
|
lmata
|
172 |
this._extensionConnectionPromise = new import_utils.ManualPromise(); |
|
f7eb47b…
|
lmata
|
173 |
void this._extensionConnectionPromise.catch(import_log.logUnhandledError); |
|
f7eb47b…
|
lmata
|
174 |
} |
|
f7eb47b…
|
lmata
|
175 |
_closePlaywrightConnection(reason) { |
|
f7eb47b…
|
lmata
|
176 |
if (this._playwrightConnection?.readyState === import_utilsBundle.ws.OPEN) |
|
f7eb47b…
|
lmata
|
177 |
this._playwrightConnection.close(1e3, reason); |
|
f7eb47b…
|
lmata
|
178 |
this._playwrightConnection = null; |
|
f7eb47b…
|
lmata
|
179 |
} |
|
f7eb47b…
|
lmata
|
180 |
_handleExtensionConnection(ws2) { |
|
f7eb47b…
|
lmata
|
181 |
if (this._extensionConnection) { |
|
f7eb47b…
|
lmata
|
182 |
ws2.close(1e3, "Another extension connection already established"); |
|
f7eb47b…
|
lmata
|
183 |
return; |
|
f7eb47b…
|
lmata
|
184 |
} |
|
f7eb47b…
|
lmata
|
185 |
this._extensionConnection = new ExtensionConnection(ws2); |
|
f7eb47b…
|
lmata
|
186 |
this._extensionConnection.onclose = (c, reason) => { |
|
f7eb47b…
|
lmata
|
187 |
debugLogger("Extension WebSocket closed:", reason, c === this._extensionConnection); |
|
f7eb47b…
|
lmata
|
188 |
if (this._extensionConnection !== c) |
|
f7eb47b…
|
lmata
|
189 |
return; |
|
f7eb47b…
|
lmata
|
190 |
this._resetExtensionConnection(); |
|
f7eb47b…
|
lmata
|
191 |
this._closePlaywrightConnection(`Extension disconnected: ${reason}`); |
|
f7eb47b…
|
lmata
|
192 |
}; |
|
f7eb47b…
|
lmata
|
193 |
this._extensionConnection.onmessage = this._handleExtensionMessage.bind(this); |
|
f7eb47b…
|
lmata
|
194 |
this._extensionConnectionPromise.resolve(); |
|
f7eb47b…
|
lmata
|
195 |
} |
|
f7eb47b…
|
lmata
|
196 |
_handleExtensionMessage(method, params) { |
|
f7eb47b…
|
lmata
|
197 |
switch (method) { |
|
f7eb47b…
|
lmata
|
198 |
case "forwardCDPEvent": |
|
f7eb47b…
|
lmata
|
199 |
const sessionId = params.sessionId || this._connectedTabInfo?.sessionId; |
|
f7eb47b…
|
lmata
|
200 |
this._sendToPlaywright({ |
|
f7eb47b…
|
lmata
|
201 |
sessionId, |
|
f7eb47b…
|
lmata
|
202 |
method: params.method, |
|
f7eb47b…
|
lmata
|
203 |
params: params.params |
|
f7eb47b…
|
lmata
|
204 |
}); |
|
f7eb47b…
|
lmata
|
205 |
break; |
|
f7eb47b…
|
lmata
|
206 |
} |
|
f7eb47b…
|
lmata
|
207 |
} |
|
f7eb47b…
|
lmata
|
208 |
async _handlePlaywrightMessage(message) { |
|
f7eb47b…
|
lmata
|
209 |
debugLogger("\u2190 Playwright:", `${message.method} (id=${message.id})`); |
|
f7eb47b…
|
lmata
|
210 |
const { id, sessionId, method, params } = message; |
|
f7eb47b…
|
lmata
|
211 |
try { |
|
f7eb47b…
|
lmata
|
212 |
const result = await this._handleCDPCommand(method, params, sessionId); |
|
f7eb47b…
|
lmata
|
213 |
this._sendToPlaywright({ id, sessionId, result }); |
|
f7eb47b…
|
lmata
|
214 |
} catch (e) { |
|
f7eb47b…
|
lmata
|
215 |
debugLogger("Error in the extension:", e); |
|
f7eb47b…
|
lmata
|
216 |
this._sendToPlaywright({ |
|
f7eb47b…
|
lmata
|
217 |
id, |
|
f7eb47b…
|
lmata
|
218 |
sessionId, |
|
f7eb47b…
|
lmata
|
219 |
error: { message: e.message } |
|
f7eb47b…
|
lmata
|
220 |
}); |
|
f7eb47b…
|
lmata
|
221 |
} |
|
f7eb47b…
|
lmata
|
222 |
} |
|
f7eb47b…
|
lmata
|
223 |
async _handleCDPCommand(method, params, sessionId) { |
|
f7eb47b…
|
lmata
|
224 |
switch (method) { |
|
f7eb47b…
|
lmata
|
225 |
case "Browser.getVersion": { |
|
f7eb47b…
|
lmata
|
226 |
return { |
|
f7eb47b…
|
lmata
|
227 |
protocolVersion: "1.3", |
|
f7eb47b…
|
lmata
|
228 |
product: "Chrome/Extension-Bridge", |
|
f7eb47b…
|
lmata
|
229 |
userAgent: "CDP-Bridge-Server/1.0.0" |
|
f7eb47b…
|
lmata
|
230 |
}; |
|
f7eb47b…
|
lmata
|
231 |
} |
|
f7eb47b…
|
lmata
|
232 |
case "Browser.setDownloadBehavior": { |
|
f7eb47b…
|
lmata
|
233 |
return {}; |
|
f7eb47b…
|
lmata
|
234 |
} |
|
f7eb47b…
|
lmata
|
235 |
case "Target.setAutoAttach": { |
|
f7eb47b…
|
lmata
|
236 |
if (sessionId) |
|
f7eb47b…
|
lmata
|
237 |
break; |
|
f7eb47b…
|
lmata
|
238 |
const { targetInfo } = await this._extensionConnection.send("attachToTab", {}); |
|
f7eb47b…
|
lmata
|
239 |
this._connectedTabInfo = { |
|
f7eb47b…
|
lmata
|
240 |
targetInfo, |
|
f7eb47b…
|
lmata
|
241 |
sessionId: `pw-tab-${this._nextSessionId++}` |
|
f7eb47b…
|
lmata
|
242 |
}; |
|
f7eb47b…
|
lmata
|
243 |
debugLogger("Simulating auto-attach"); |
|
f7eb47b…
|
lmata
|
244 |
this._sendToPlaywright({ |
|
f7eb47b…
|
lmata
|
245 |
method: "Target.attachedToTarget", |
|
f7eb47b…
|
lmata
|
246 |
params: { |
|
f7eb47b…
|
lmata
|
247 |
sessionId: this._connectedTabInfo.sessionId, |
|
f7eb47b…
|
lmata
|
248 |
targetInfo: { |
|
f7eb47b…
|
lmata
|
249 |
...this._connectedTabInfo.targetInfo, |
|
f7eb47b…
|
lmata
|
250 |
attached: true |
|
f7eb47b…
|
lmata
|
251 |
}, |
|
f7eb47b…
|
lmata
|
252 |
waitingForDebugger: false |
|
f7eb47b…
|
lmata
|
253 |
} |
|
f7eb47b…
|
lmata
|
254 |
}); |
|
f7eb47b…
|
lmata
|
255 |
return {}; |
|
f7eb47b…
|
lmata
|
256 |
} |
|
f7eb47b…
|
lmata
|
257 |
case "Target.getTargetInfo": { |
|
f7eb47b…
|
lmata
|
258 |
return this._connectedTabInfo?.targetInfo; |
|
f7eb47b…
|
lmata
|
259 |
} |
|
f7eb47b…
|
lmata
|
260 |
} |
|
f7eb47b…
|
lmata
|
261 |
return await this._forwardToExtension(method, params, sessionId); |
|
f7eb47b…
|
lmata
|
262 |
} |
|
f7eb47b…
|
lmata
|
263 |
async _forwardToExtension(method, params, sessionId) { |
|
f7eb47b…
|
lmata
|
264 |
if (!this._extensionConnection) |
|
f7eb47b…
|
lmata
|
265 |
throw new Error("Extension not connected"); |
|
f7eb47b…
|
lmata
|
266 |
if (this._connectedTabInfo?.sessionId === sessionId) |
|
f7eb47b…
|
lmata
|
267 |
sessionId = void 0; |
|
f7eb47b…
|
lmata
|
268 |
return await this._extensionConnection.send("forwardCDPCommand", { sessionId, method, params }); |
|
f7eb47b…
|
lmata
|
269 |
} |
|
f7eb47b…
|
lmata
|
270 |
_sendToPlaywright(message) { |
|
f7eb47b…
|
lmata
|
271 |
debugLogger("\u2192 Playwright:", `${message.method ?? `response(id=${message.id})`}`); |
|
f7eb47b…
|
lmata
|
272 |
this._playwrightConnection?.send(JSON.stringify(message)); |
|
f7eb47b…
|
lmata
|
273 |
} |
|
f7eb47b…
|
lmata
|
274 |
} |
|
f7eb47b…
|
lmata
|
275 |
class ExtensionConnection { |
|
f7eb47b…
|
lmata
|
276 |
constructor(ws2) { |
|
f7eb47b…
|
lmata
|
277 |
this._callbacks = /* @__PURE__ */ new Map(); |
|
f7eb47b…
|
lmata
|
278 |
this._lastId = 0; |
|
f7eb47b…
|
lmata
|
279 |
this._ws = ws2; |
|
f7eb47b…
|
lmata
|
280 |
this._ws.on("message", this._onMessage.bind(this)); |
|
f7eb47b…
|
lmata
|
281 |
this._ws.on("close", this._onClose.bind(this)); |
|
f7eb47b…
|
lmata
|
282 |
this._ws.on("error", this._onError.bind(this)); |
|
f7eb47b…
|
lmata
|
283 |
} |
|
f7eb47b…
|
lmata
|
284 |
async send(method, params) { |
|
f7eb47b…
|
lmata
|
285 |
if (this._ws.readyState !== import_utilsBundle.ws.OPEN) |
|
f7eb47b…
|
lmata
|
286 |
throw new Error(`Unexpected WebSocket state: ${this._ws.readyState}`); |
|
f7eb47b…
|
lmata
|
287 |
const id = ++this._lastId; |
|
f7eb47b…
|
lmata
|
288 |
this._ws.send(JSON.stringify({ id, method, params })); |
|
f7eb47b…
|
lmata
|
289 |
const error = new Error(`Protocol error: ${method}`); |
|
f7eb47b…
|
lmata
|
290 |
return new Promise((resolve, reject) => { |
|
f7eb47b…
|
lmata
|
291 |
this._callbacks.set(id, { resolve, reject, error }); |
|
f7eb47b…
|
lmata
|
292 |
}); |
|
f7eb47b…
|
lmata
|
293 |
} |
|
f7eb47b…
|
lmata
|
294 |
close(message) { |
|
f7eb47b…
|
lmata
|
295 |
debugLogger("closing extension connection:", message); |
|
f7eb47b…
|
lmata
|
296 |
if (this._ws.readyState === import_utilsBundle.ws.OPEN) |
|
f7eb47b…
|
lmata
|
297 |
this._ws.close(1e3, message); |
|
f7eb47b…
|
lmata
|
298 |
} |
|
f7eb47b…
|
lmata
|
299 |
_onMessage(event) { |
|
f7eb47b…
|
lmata
|
300 |
const eventData = event.toString(); |
|
f7eb47b…
|
lmata
|
301 |
let parsedJson; |
|
f7eb47b…
|
lmata
|
302 |
try { |
|
f7eb47b…
|
lmata
|
303 |
parsedJson = JSON.parse(eventData); |
|
f7eb47b…
|
lmata
|
304 |
} catch (e) { |
|
f7eb47b…
|
lmata
|
305 |
debugLogger(`<closing ws> Closing websocket due to malformed JSON. eventData=${eventData} e=${e?.message}`); |
|
f7eb47b…
|
lmata
|
306 |
this._ws.close(); |
|
f7eb47b…
|
lmata
|
307 |
return; |
|
f7eb47b…
|
lmata
|
308 |
} |
|
f7eb47b…
|
lmata
|
309 |
try { |
|
f7eb47b…
|
lmata
|
310 |
this._handleParsedMessage(parsedJson); |
|
f7eb47b…
|
lmata
|
311 |
} catch (e) { |
|
f7eb47b…
|
lmata
|
312 |
debugLogger(`<closing ws> Closing websocket due to failed onmessage callback. eventData=${eventData} e=${e?.message}`); |
|
f7eb47b…
|
lmata
|
313 |
this._ws.close(); |
|
f7eb47b…
|
lmata
|
314 |
} |
|
f7eb47b…
|
lmata
|
315 |
} |
|
f7eb47b…
|
lmata
|
316 |
_handleParsedMessage(object) { |
|
f7eb47b…
|
lmata
|
317 |
if (object.id && this._callbacks.has(object.id)) { |
|
f7eb47b…
|
lmata
|
318 |
const callback = this._callbacks.get(object.id); |
|
f7eb47b…
|
lmata
|
319 |
this._callbacks.delete(object.id); |
|
f7eb47b…
|
lmata
|
320 |
if (object.error) { |
|
f7eb47b…
|
lmata
|
321 |
const error = callback.error; |
|
f7eb47b…
|
lmata
|
322 |
error.message = object.error; |
|
f7eb47b…
|
lmata
|
323 |
callback.reject(error); |
|
f7eb47b…
|
lmata
|
324 |
} else { |
|
f7eb47b…
|
lmata
|
325 |
callback.resolve(object.result); |
|
f7eb47b…
|
lmata
|
326 |
} |
|
f7eb47b…
|
lmata
|
327 |
} else if (object.id) { |
|
f7eb47b…
|
lmata
|
328 |
debugLogger("\u2190 Extension: unexpected response", object); |
|
f7eb47b…
|
lmata
|
329 |
} else { |
|
f7eb47b…
|
lmata
|
330 |
this.onmessage?.(object.method, object.params); |
|
f7eb47b…
|
lmata
|
331 |
} |
|
f7eb47b…
|
lmata
|
332 |
} |
|
f7eb47b…
|
lmata
|
333 |
_onClose(event) { |
|
f7eb47b…
|
lmata
|
334 |
debugLogger(`<ws closed> code=${event.code} reason=${event.reason}`); |
|
f7eb47b…
|
lmata
|
335 |
this._dispose(); |
|
f7eb47b…
|
lmata
|
336 |
this.onclose?.(this, event.reason); |
|
f7eb47b…
|
lmata
|
337 |
} |
|
f7eb47b…
|
lmata
|
338 |
_onError(event) { |
|
f7eb47b…
|
lmata
|
339 |
debugLogger(`<ws error> message=${event.message} type=${event.type} target=${event.target}`); |
|
f7eb47b…
|
lmata
|
340 |
this._dispose(); |
|
f7eb47b…
|
lmata
|
341 |
} |
|
f7eb47b…
|
lmata
|
342 |
_dispose() { |
|
f7eb47b…
|
lmata
|
343 |
for (const callback of this._callbacks.values()) |
|
f7eb47b…
|
lmata
|
344 |
callback.reject(new Error("WebSocket closed")); |
|
f7eb47b…
|
lmata
|
345 |
this._callbacks.clear(); |
|
f7eb47b…
|
lmata
|
346 |
} |
|
f7eb47b…
|
lmata
|
347 |
} |
|
f7eb47b…
|
lmata
|
348 |
// Annotate the CommonJS export names for ESM import in node: |
|
f7eb47b…
|
lmata
|
349 |
0 && (module.exports = { |
|
f7eb47b…
|
lmata
|
350 |
CDPRelayServer |
|
f7eb47b…
|
lmata
|
351 |
}); |