( devTools: TargetUniverse, rawStackTrace: Protocol.Runtime.StackTrace, targetId: string | undefined, )
| 401 | } |
| 402 | |
| 403 | export async function createStackTrace( |
| 404 | devTools: TargetUniverse, |
| 405 | rawStackTrace: Protocol.Runtime.StackTrace, |
| 406 | targetId: string | undefined, |
| 407 | ): Promise<DevTools.StackTrace.StackTrace.StackTrace> { |
| 408 | const targetManager = devTools.universe.context.get(DevTools.TargetManager); |
| 409 | const target = targetId |
| 410 | ? targetManager.targetById(targetId) || devTools.target |
| 411 | : devTools.target; |
| 412 | const model = target.model(DevTools.DebuggerModel) as DevTools.DebuggerModel; |
| 413 | |
| 414 | // DevTools doesn't wait for source maps to attach before building a stack trace, rather it'll send |
| 415 | // an update event once a source map was attached and the stack trace retranslated. This doesn't |
| 416 | // work in the MCP case, so we'll collect all script IDs upfront and wait for any pending source map |
| 417 | // loads before creating the stack trace. We might also have to wait for Debugger.ScriptParsed events if |
| 418 | // the stack trace is created particularly early. |
| 419 | const scriptIds = new Set<Protocol.Runtime.ScriptId>(); |
| 420 | for (const frame of rawStackTrace.callFrames) { |
| 421 | scriptIds.add(frame.scriptId); |
| 422 | } |
| 423 | for ( |
| 424 | let asyncStack = rawStackTrace.parent; |
| 425 | asyncStack; |
| 426 | asyncStack = asyncStack.parent |
| 427 | ) { |
| 428 | for (const frame of asyncStack.callFrames) { |
| 429 | scriptIds.add(frame.scriptId); |
| 430 | } |
| 431 | } |
| 432 | |
| 433 | const signal = AbortSignal.timeout(1_000); |
| 434 | await Promise.all( |
| 435 | [...scriptIds].map(id => |
| 436 | waitForScript(model, id, signal) |
| 437 | .then(script => |
| 438 | model.sourceMapManager().sourceMapForClientPromise(script), |
| 439 | ) |
| 440 | .catch(), |
| 441 | ), |
| 442 | ); |
| 443 | |
| 444 | const binding = devTools.universe.context.get( |
| 445 | DevTools.DebuggerWorkspaceBinding, |
| 446 | ); |
| 447 | // DevTools uses branded types for ScriptId and others. Casting the puppeteer protocol type to the DevTools protocol type is safe. |
| 448 | return binding.createStackTraceFromProtocolRuntime( |
| 449 | rawStackTrace as Parameters< |
| 450 | DevTools.DebuggerWorkspaceBinding['createStackTraceFromProtocolRuntime'] |
| 451 | >[0], |
| 452 | target, |
| 453 | ); |
| 454 | } |
| 455 | |
| 456 | // Waits indefinitely for the script so pair it with Promise.race. |
| 457 | async function waitForScript( |
no test coverage detected