Skip to content

Commit 31f4a68

Browse files
authored
Add JS bride handlers (#38)
1 parent 85ee3c8 commit 31f4a68

2 files changed

Lines changed: 95 additions & 2 deletions

File tree

‎bin/lib/handlers.js‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,14 @@ class InteractionHandler extends BaseHandler {
513513
});
514514
await this.executeWithRegistry(registry, method);
515515
}
516+
517+
async handleTouchscreen(command, method) {
518+
const page = this.validateResource(this.pages, command.pageId, 'Page');
519+
const registry = CommandRegistry.create({
520+
tap: () => page.touchscreen.tap(command.x, command.y)
521+
});
522+
await this.executeWithRegistry(registry, method);
523+
}
516524
}
517525

518526
class FrameHandler extends BaseHandler {

‎bin/playwright-server.js‎

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ class PlaywrightServer extends BaseHandler {
2020
this.dialogs = new Map();
2121
this.elementHandles = new Map();
2222
this.contextThrottling = new Map();
23-
this.counters = { browser: 0, context: 0, page: 0, response: 0, route: 0, element: 0 };
23+
this.servers = new Map();
24+
this.counters = { browser: 0, context: 0, page: 0, response: 0, route: 0, element: 0, server: 0 };
2425
}
2526

2627
initHandlers() {
@@ -67,6 +68,9 @@ class PlaywrightServer extends BaseHandler {
6768
response: () => this.handleResponse(command, actionMethod),
6869
mouse: () => this.interactionHandler.handleMouse(command, actionMethod),
6970
keyboard: () => this.interactionHandler.handleKeyboard(command, actionMethod),
71+
touchscreen: () => this.interactionHandler.handleTouchscreen(command, actionMethod),
72+
frame: () => this.frameHandler.handle(command, actionMethod),
73+
browserServer: () => this.handleBrowserServer(command, actionMethod)
7074
frame: () => this.frameHandler.handle(command, actionMethod),
7175
selectors: () => this.selectorsHandler.handle(command, actionMethod)
7276
});
@@ -77,9 +81,13 @@ class PlaywrightServer extends BaseHandler {
7781

7882
const directRegistry = CommandRegistry.create({
7983
launch: () => this.launchBrowser(command),
84+
// Attach to existing browser servers/endpoints
85+
connect: () => this.connect(command),
86+
connectOverCDP: () => this.connectOverCDP(command),
8087
newContext: () => this.newContext(command),
8188
close: () => this.closeBrowser(command),
82-
exit: () => this.exit()
89+
exit: () => this.exit(),
90+
launchServer: () => this.launchServer(command)
8391
});
8492

8593
return await ErrorHandler.safeExecute(() => this.executeWithRegistry(directRegistry, command.action), { action: command.action });
@@ -241,6 +249,83 @@ class PlaywrightServer extends BaseHandler {
241249
}
242250
}
243251

252+
async handleBrowserServer(command, method) {
253+
const server = this.servers.get(command.serverId);
254+
if (!server) throw new Error(`Unknown BrowserServer: ${command.serverId}`);
255+
const registry = CommandRegistry.create({
256+
close: async () => { await server.close(); this.servers.delete(command.serverId); },
257+
kill: async () => { try { await server.kill(); } finally { this.servers.delete(command.serverId); } }
258+
});
259+
logger.info(`BROWSER_SERVER ${method.toUpperCase()}`, { serverId: command.serverId });
260+
return await ErrorHandler.safeExecute(() => this.executeWithRegistry(registry, method), { method, serverId: command.serverId });
261+
}
262+
263+
async launchServer(command) {
264+
try {
265+
const browserType = this.getBrowserType(command.browser);
266+
const launchOptions = this.buildLaunchOptions(command);
267+
const server = await browserType.launchServer(launchOptions);
268+
const serverId = this.generateId('server');
269+
this.servers.set(serverId, server);
270+
271+
// Auto-cleanup on server close and notify
272+
try {
273+
server.on?.('close', () => {
274+
if (this.servers.has(serverId)) this.servers.delete(serverId);
275+
try { sendFramedResponse({ objectId: serverId, event: 'close', params: {} }); } catch {}
276+
});
277+
} catch {}
278+
279+
const wsEndpoint = server.wsEndpoint();
280+
let pid = null;
281+
try { pid = server.process() ? server.process().pid : null; } catch {}
282+
return { serverId, wsEndpoint, pid };
283+
} catch (error) {
284+
logger.error('launchServer error', { message: error.message });
285+
throw error;
286+
}
287+
}
288+
289+
// Attach to an existing BrowserServer (WebSocket endpoint)
290+
async connect(command) {
291+
try {
292+
const { browser, wsEndpoint, options } = command;
293+
if (!wsEndpoint || typeof wsEndpoint !== 'string') throw new Error('connect requires a wsEndpoint string');
294+
const browserType = this.getBrowserType(browser);
295+
const attached = await browserType.connect(wsEndpoint, options || {});
296+
const browserId = this.generateId('browser');
297+
this.browsers.set(browserId, attached);
298+
// Create a fresh context to align with launch return shape
299+
const context = await attached.newContext();
300+
const contextId = this.generateId('context');
301+
this.contexts.set(contextId, { context, browserId, id: contextId });
302+
return { browserId, defaultContextId: contextId, version: attached.version() };
303+
} catch (error) {
304+
logger.error('connect error', { message: error.message });
305+
throw error;
306+
}
307+
}
308+
309+
// Attach over CDP (Chromium only)
310+
async connectOverCDP(command) {
311+
try {
312+
const { endpointURL, options, browser } = command;
313+
if (!endpointURL || typeof endpointURL !== 'string') throw new Error('connectOverCDP requires an endpointURL string');
314+
const browserName = browser || 'chromium';
315+
if (browserName !== 'chromium') throw new Error('connectOverCDP is only supported for chromium');
316+
const attached = await chromium.connectOverCDP(endpointURL, options || {});
317+
const browserId = this.generateId('browser');
318+
this.browsers.set(browserId, attached);
319+
const context = await attached.newContext();
320+
const contextId = this.generateId('context');
321+
this.contexts.set(contextId, { context, browserId, id: contextId });
322+
return { browserId, defaultContextId: contextId, version: attached.version() };
323+
} catch (error) {
324+
logger.error('connectOverCDP error', { message: error.message });
325+
throw error;
326+
}
327+
}
328+
244329
async exit() {
245330
logger.info('Shutting down server');
246331
for (const browser of this.browsers.values()) {

0 commit comments

Comments
 (0)