Skip to content

Commit 46ef1a9

Browse files
committed
fix(extension): clean up tab sessions on close and destroy
Remove tab session entries from _tabSessions and _tabIdToSessionId when tabs are closed via Target.closeTarget or destroyed via Target.targetDestroyed events to prevent stale targets and tabId reuse.
1 parent d3e2d82 commit 46ef1a9

1 file changed

Lines changed: 35 additions & 0 deletions

File tree

packages/playwright-core/src/tools/mcp/cdpRelay.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,12 @@ export class CDPRelayServer {
254254
else
255255
sessionId = [...this._tabSessions.keys()][0];
256256
}
257+
// Clean up tab session when the target is destroyed.
258+
if (params.method === 'Target.targetDestroyed') {
259+
const destroyedSessionId = this._findSessionByTargetId(params.params?.targetId);
260+
if (destroyedSessionId)
261+
this._removeTabSession(destroyedSessionId);
262+
}
257263
this._sendToPlaywright({
258264
sessionId,
259265
method: params.method,
@@ -334,6 +340,18 @@ export class CDPRelayServer {
334340
targetInfos: [...this._tabSessions.values()].map(s => ({ ...s.targetInfo, attached: true })),
335341
};
336342
}
343+
case 'Target.closeTarget': {
344+
const targetId = params?.targetId;
345+
const tabSessionId = this._findSessionByTargetId(targetId);
346+
if (tabSessionId) {
347+
this._removeTabSession(tabSessionId);
348+
this._sendToPlaywright({
349+
method: 'Target.detachedFromTarget',
350+
params: { sessionId: tabSessionId },
351+
});
352+
}
353+
return { success: true };
354+
}
337355
case 'Target.getTargetInfo': {
338356
const tabSession = sessionId ? this._tabSessions.get(sessionId) : undefined;
339357
return (tabSession ?? [...this._tabSessions.values()][0])?.targetInfo;
@@ -342,6 +360,23 @@ export class CDPRelayServer {
342360
return await this._forwardToExtension(method, params, sessionId);
343361
}
344362

363+
private _removeTabSession(tabSessionId: string) {
364+
const session = this._tabSessions.get(tabSessionId);
365+
if (!session)
366+
return;
367+
this._tabSessions.delete(tabSessionId);
368+
if (session.tabId !== undefined)
369+
this._tabIdToSessionId.delete(session.tabId);
370+
}
371+
372+
private _findSessionByTargetId(targetId: string): string | undefined {
373+
for (const [sessionId, session] of this._tabSessions) {
374+
if (session.targetInfo?.targetId === targetId)
375+
return sessionId;
376+
}
377+
return undefined;
378+
}
379+
345380
private async _forwardToExtension(method: string, params: any, sessionId: string | undefined): Promise<any> {
346381
if (!this._extensionConnection)
347382
throw new Error('Extension not connected');

0 commit comments

Comments
 (0)