Skip to content

Commit f7421cd

Browse files
committed
Support OOPIFs
1 parent fbfca58 commit f7421cd

File tree

1 file changed

+60
-57
lines changed

1 file changed

+60
-57
lines changed

extension/background.js

Lines changed: 60 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,33 @@ function debugLog(...args) {
1414
class TabShareExtension {
1515
constructor() {
1616
this.activeConnections = new Map(); // tabId -> connection info
17-
17+
1818
// Remove page action click handler since we now use popup
1919
chrome.tabs.onRemoved.addListener(this.onTabRemoved.bind(this));
20-
20+
2121
// Handle messages from popup
2222
chrome.runtime.onMessage.addListener(this.onMessage.bind(this));
2323
}
2424

2525
/**
2626
* Handle messages from popup
27-
* @param {any} message
28-
* @param {chrome.runtime.MessageSender} sender
29-
* @param {Function} sendResponse
27+
* @param {any} message
28+
* @param {chrome.runtime.MessageSender} sender
29+
* @param {Function} sendResponse
3030
*/
3131
onMessage(message, sender, sendResponse) {
3232
switch (message.type) {
3333
case 'getStatus':
3434
this.getStatus(message.tabId, sendResponse);
3535
return true; // Will respond asynchronously
36-
36+
3737
case 'connect':
3838
this.connectTab(message.tabId, message.bridgeUrl).then(
3939
() => sendResponse({ success: true }),
4040
(error) => sendResponse({ success: false, error: error.message })
4141
);
4242
return true; // Will respond asynchronously
43-
43+
4444
case 'disconnect':
4545
this.disconnectTab(message.tabId).then(
4646
() => sendResponse({ success: true }),
@@ -53,24 +53,24 @@ class TabShareExtension {
5353

5454
/**
5555
* Get connection status for popup
56-
* @param {number} requestedTabId
57-
* @param {Function} sendResponse
56+
* @param {number} requestedTabId
57+
* @param {Function} sendResponse
5858
*/
5959
getStatus(requestedTabId, sendResponse) {
6060
const isConnected = this.activeConnections.size > 0;
6161
let activeTabId = null;
6262
let activeTabInfo = null;
63-
63+
6464
if (isConnected) {
6565
const [tabId, connection] = this.activeConnections.entries().next().value;
6666
activeTabId = tabId;
67-
67+
6868
// Get tab info
6969
chrome.tabs.get(tabId, (tab) => {
7070
if (chrome.runtime.lastError) {
71-
sendResponse({
72-
isConnected: false,
73-
error: 'Active tab not found'
71+
sendResponse({
72+
isConnected: false,
73+
error: 'Active tab not found'
7474
});
7575
} else {
7676
sendResponse({
@@ -94,8 +94,8 @@ class TabShareExtension {
9494

9595
/**
9696
* Connect a tab to the bridge server
97-
* @param {number} tabId
98-
* @param {string} bridgeUrl
97+
* @param {number} tabId
98+
* @param {string} bridgeUrl
9999
*/
100100
async connectTab(tabId, bridgeUrl) {
101101
try {
@@ -104,15 +104,15 @@ class TabShareExtension {
104104
// Attach chrome debugger
105105
const debuggee = { tabId };
106106
await chrome.debugger.attach(debuggee, '1.3');
107-
108-
if (chrome.runtime.lastError)
107+
108+
if (chrome.runtime.lastError)
109109
throw new Error(chrome.runtime.lastError.message);
110110
const targetInfo = /** @type {any} */ (await chrome.debugger.sendCommand(debuggee, 'Target.getTargetInfo'));
111111
debugLog('Target info:', targetInfo);
112112

113113
// Connect to bridge server
114114
const socket = new WebSocket(bridgeUrl);
115-
115+
116116
const connection = {
117117
debuggee,
118118
socket,
@@ -137,36 +137,36 @@ class TabShareExtension {
137137

138138
// Set up message handling
139139
this.setupMessageHandling(connection);
140-
140+
141141
// Store connection
142142
this.activeConnections.set(tabId, connection);
143-
143+
144144
// Update UI
145145
chrome.action.setBadgeText({ tabId, text: '●' });
146146
chrome.action.setBadgeBackgroundColor({ tabId, color: '#4CAF50' });
147147
chrome.action.setTitle({ tabId, title: 'Disconnect from Playwright MCP' });
148-
148+
149149
debugLog(`Tab ${tabId} connected successfully`);
150-
150+
151151
} catch (error) {
152152
debugLog(`Failed to connect tab ${tabId}:`, error.message);
153153
await this.cleanupConnection(tabId);
154-
154+
155155
// Show error to user
156156
chrome.action.setBadgeText({ tabId, text: '!' });
157157
chrome.action.setBadgeBackgroundColor({ tabId, color: '#F44336' });
158158
chrome.action.setTitle({ tabId, title: `Connection failed: ${error.message}` });
159-
159+
160160
throw error; // Re-throw for popup to handle
161161
}
162162
}
163163

164164
/**
165165
* Set up bidirectional message handling between debugger and WebSocket
166-
* @param {Object} connection
166+
* @param {Object} connection
167167
*/
168168
setupMessageHandling(connection) {
169-
const { debuggee, socket, tabId, sessionId } = connection;
169+
const { debuggee, socket, tabId, sessionId: rootSessionId } = connection;
170170

171171
// WebSocket -> chrome.debugger
172172
socket.onmessage = async (event) => {
@@ -186,31 +186,35 @@ class TabShareExtension {
186186

187187
try {
188188
debugLog('Received from bridge:', message);
189-
189+
190+
const debuggerSession = { ...debuggee };
191+
const sessionId = message.sessionId;
192+
// Pass session id, unless it's the root session.
193+
if (sessionId && sessionId !== rootSessionId)
194+
debuggerSession.sessionId = sessionId;
195+
190196
// Forward CDP command to chrome.debugger
191-
if (message.method) {
192-
const result = await chrome.debugger.sendCommand(
193-
debuggee,
194-
message.method,
195-
message.params || {}
196-
);
197-
198-
// Send response back to bridge
199-
const response = {
200-
id: message.id,
201-
sessionId: message.sessionId,
202-
result
197+
const result = await chrome.debugger.sendCommand(
198+
debuggerSession,
199+
message.method,
200+
message.params || {}
201+
);
202+
203+
// Send response back to bridge
204+
const response = {
205+
id: message.id,
206+
sessionId,
207+
result
208+
};
209+
210+
if (chrome.runtime.lastError) {
211+
response.error = {
212+
code: -32000,
213+
message: chrome.runtime.lastError.message,
203214
};
204-
205-
if (chrome.runtime.lastError) {
206-
response.error = {
207-
code: -32000,
208-
message: chrome.runtime.lastError.message,
209-
};
210-
}
211-
212-
socket.send(JSON.stringify(response));
213215
}
216+
217+
socket.send(JSON.stringify(response));
214218
} catch (error) {
215219
debugLog('Error processing WebSocket message:', error);
216220
const response = {
@@ -228,10 +232,9 @@ class TabShareExtension {
228232
// chrome.debugger events -> WebSocket
229233
const eventListener = (source, method, params) => {
230234
if (source.tabId === tabId && socket.readyState === WebSocket.OPEN) {
231-
// There is only one session per tab, and the relay server will
232-
// has a connection info for each tab.
235+
// If the sessionId is not provided, use the root sessionId.
233236
const event = {
234-
sessionId,
237+
sessionId: source.sessionId || rootSessionId,
235238
method,
236239
params,
237240
};
@@ -268,21 +271,21 @@ class TabShareExtension {
268271

269272
/**
270273
* Disconnect a tab from the bridge
271-
* @param {number} tabId
274+
* @param {number} tabId
272275
*/
273276
async disconnectTab(tabId) {
274277
await this.cleanupConnection(tabId);
275-
278+
276279
// Update UI
277280
chrome.action.setBadgeText({ tabId, text: '' });
278281
chrome.action.setTitle({ tabId, title: 'Share tab with Playwright MCP' });
279-
282+
280283
debugLog(`Tab ${tabId} disconnected`);
281284
}
282285

283286
/**
284287
* Clean up connection resources
285-
* @param {number} tabId
288+
* @param {number} tabId
286289
*/
287290
async cleanupConnection(tabId) {
288291
const connection = this.activeConnections.get(tabId);
@@ -313,7 +316,7 @@ class TabShareExtension {
313316

314317
/**
315318
* Handle tab removal
316-
* @param {number} tabId
319+
* @param {number} tabId
317320
*/
318321
async onTabRemoved(tabId) {
319322
if (this.activeConnections.has(tabId)) {

0 commit comments

Comments
 (0)