| | import type { |
| | OriginalStackFrameResponse, |
| | OriginalStackFrameResponseResult, |
| | OriginalStackFramesRequest, |
| | StackFrame, |
| | } from '../server/shared' |
| | import { |
| | isWebpackInternalResource, |
| | formatFrameSourceFile, |
| | } from './webpack-module-path' |
| |
|
| | export type { StackFrame } |
| |
|
| | interface ResolvedOriginalStackFrame extends OriginalStackFrameResponse { |
| | error: false |
| | reason: null |
| | external: boolean |
| | ignored: boolean |
| | sourceStackFrame: StackFrame |
| | } |
| |
|
| | interface RejectedOriginalStackFrame extends OriginalStackFrameResponse { |
| | error: true |
| | reason: string |
| | external: boolean |
| | ignored: boolean |
| | sourceStackFrame: StackFrame |
| | } |
| |
|
| | export type OriginalStackFrame = |
| | | ResolvedOriginalStackFrame |
| | | RejectedOriginalStackFrame |
| |
|
| | function getOriginalStackFrame( |
| | source: StackFrame, |
| | response: OriginalStackFrameResponseResult |
| | ): Promise<OriginalStackFrame> { |
| | async function _getOriginalStackFrame(): Promise<ResolvedOriginalStackFrame> { |
| | if (response.status === 'rejected') { |
| | throw new Error(response.reason) |
| | } |
| |
|
| | const body: OriginalStackFrameResponse = response.value |
| |
|
| | return { |
| | error: false, |
| | reason: null, |
| | external: false, |
| | sourceStackFrame: source, |
| | originalStackFrame: body.originalStackFrame, |
| | originalCodeFrame: body.originalCodeFrame || null, |
| | ignored: body.originalStackFrame?.ignored || false, |
| | } |
| | } |
| |
|
| | |
| | if (source.file === 'file://' || source.file?.match(/https?:\/\//)) { |
| | return Promise.resolve({ |
| | error: false, |
| | reason: null, |
| | external: true, |
| | sourceStackFrame: source, |
| | originalStackFrame: null, |
| | originalCodeFrame: null, |
| | ignored: true, |
| | }) |
| | } |
| |
|
| | return _getOriginalStackFrame().catch( |
| | (err: Error): RejectedOriginalStackFrame => ({ |
| | error: true, |
| | reason: err?.message ?? err?.toString() ?? 'Unknown Error', |
| | external: false, |
| | sourceStackFrame: source, |
| | originalStackFrame: null, |
| | originalCodeFrame: null, |
| | ignored: false, |
| | }) |
| | ) |
| | } |
| |
|
| | export async function getOriginalStackFrames( |
| | frames: readonly StackFrame[], |
| | type: 'server' | 'edge-server' | null, |
| | isAppDir: boolean |
| | ): Promise<readonly OriginalStackFrame[]> { |
| | const req: OriginalStackFramesRequest = { |
| | frames, |
| | isServer: type === 'server', |
| | isEdgeServer: type === 'edge-server', |
| | isAppDirectory: isAppDir, |
| | } |
| |
|
| | let res: Response | undefined = undefined |
| | let reason: string | undefined = undefined |
| | try { |
| | res = await fetch('/__nextjs_original-stack-frames', { |
| | method: 'POST', |
| | body: JSON.stringify(req), |
| | }) |
| | } catch (e) { |
| | reason = e + '' |
| | } |
| |
|
| | |
| | |
| | |
| | if (res && res.ok && res.status !== 204) { |
| | const data = await res.json() |
| | return Promise.all( |
| | frames.map((frame, index) => getOriginalStackFrame(frame, data[index])) |
| | ) |
| | } else { |
| | if (res) { |
| | reason = await res.text() |
| | } |
| | } |
| | return Promise.all( |
| | frames.map((frame) => |
| | getOriginalStackFrame(frame, { |
| | status: 'rejected', |
| | reason: `Failed to fetch the original stack frames ${reason ? `: ${reason}` : ''}`, |
| | }) |
| | ) |
| | ) |
| | } |
| |
|
| | export function getFrameSource(frame: StackFrame): string { |
| | if (!frame.file) return '' |
| |
|
| | const isWebpackFrame = isWebpackInternalResource(frame.file) |
| |
|
| | let str = '' |
| | |
| | if (isWebpackFrame) { |
| | str = formatFrameSourceFile(frame.file) |
| | } else { |
| | try { |
| | const u = new URL(frame.file) |
| |
|
| | let parsedPath = '' |
| | |
| | if (globalThis.location?.origin !== u.origin) { |
| | |
| | |
| | if (u.origin === 'null') { |
| | parsedPath += u.protocol |
| | } else { |
| | parsedPath += u.origin |
| | } |
| | } |
| |
|
| | |
| | |
| | parsedPath += u.pathname |
| | str = formatFrameSourceFile(parsedPath) |
| | } catch { |
| | str = formatFrameSourceFile(frame.file) |
| | } |
| | } |
| |
|
| | if (!isWebpackInternalResource(frame.file) && frame.line1 != null) { |
| | |
| | |
| | if (str && frame.file !== '<anonymous>') { |
| | if (frame.column1 != null) { |
| | str += ` (${frame.line1}:${frame.column1})` |
| | } else { |
| | str += ` (${frame.line1})` |
| | } |
| | } |
| | } |
| | return str |
| | } |
| |
|