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