( devTools: TargetUniverse, rawStackTrace: Protocol.Runtime.StackTrace, targetId: string | undefined, )
| 470 | } |
| 471 | |
| 472 | export async function createStackTrace( |
| 473 | devTools: TargetUniverse, |
| 474 | rawStackTrace: Protocol.Runtime.StackTrace, |
| 475 | targetId: string | undefined, |
| 476 | ): Promise<DevTools.StackTrace.StackTrace.StackTrace> { |
| 477 | const targetManager = devTools.universe.context.get(DevTools.TargetManager); |
| 478 | const target = targetId |
| 479 | ? targetManager.targetById(targetId) || devTools.target |
| 480 | : devTools.target; |
| 481 | const model = target.model(DevTools.DebuggerModel) as DevTools.DebuggerModel; |
| 482 | |
| 483 | // DevTools doesn't wait for source maps to attach before building a stack trace, rather it'll send |
| 484 | // an update event once a source map was attached and the stack trace retranslated. This doesn't |
| 485 | // work in the MCP case, so we'll collect all script IDs upfront and wait for any pending source map |
| 486 | // loads before creating the stack trace. We might also have to wait for Debugger.ScriptParsed events if |
| 487 | // the stack trace is created particularly early. |
| 488 | const scriptIds = new Set<Protocol.Runtime.ScriptId>(); |
| 489 | for (const frame of rawStackTrace.callFrames) { |
| 490 | scriptIds.add(frame.scriptId); |
| 491 | } |
| 492 | for ( |
| 493 | let asyncStack = rawStackTrace.parent; |
| 494 | asyncStack; |
| 495 | asyncStack = asyncStack.parent |
| 496 | ) { |
| 497 | for (const frame of asyncStack.callFrames) { |
| 498 | scriptIds.add(frame.scriptId); |
| 499 | } |
| 500 | } |
| 501 | |
| 502 | const signal = AbortSignal.timeout(1_000); |
| 503 | await Promise.all( |
| 504 | [...scriptIds].map(id => |
| 505 | waitForScript(model, id, signal) |
| 506 | .then(script => |
| 507 | model.sourceMapManager().sourceMapForClientPromise(script), |
| 508 | ) |
| 509 | .catch(), |
| 510 | ), |
| 511 | ); |
| 512 | |
| 513 | const binding = devTools.universe.context.get( |
| 514 | DevTools.DebuggerWorkspaceBinding, |
| 515 | ); |
| 516 | // DevTools uses branded types for ScriptId and others. Casting the puppeteer protocol type to the DevTools protocol type is safe. |
| 517 | return binding.createStackTraceFromProtocolRuntime( |
| 518 | rawStackTrace as Parameters< |
| 519 | DevTools.DebuggerWorkspaceBinding['createStackTraceFromProtocolRuntime'] |
| 520 | >[0], |
| 521 | target, |
| 522 | ); |
| 523 | } |
| 524 | |
| 525 | // Waits indefinitely for the script so pair it with Promise.race. |
| 526 | async function waitForScript( |
no test coverage detected