2import { difference } from 'lodash-es' 4import { SourceMapConsumer, SourceMapGenerator } from 'source-map' 6import { parse } from 'stacktrace-parser' 10// https://github.com/mifi/stacktracify/blob/master/index.js 12const getLocalSmPathForLine = (lineS: string) => { 13 // Match both _next/ (client URL) and .next/ (server filesystem path) 14 const match = lineS.match(/[_.]next\/(.+\.js)/) 16 return ptDir + `/${getAppName()}/.next/` + match[1] + '.map' 19const getSm = async (smPath: string) => { 20 return await new SourceMapConsumer(fs.readFileSync(smPath, 'utf-8')) 23let memo: SourceMapConsumer | undefined 24const getCombinedSmc = async ({mapPaths}: {mapPaths: string[]}) => { 27 const [firstPath, ...restPaths] = mapPaths 29 let generator = SourceMapGenerator.fromSourceMap(await getSm(firstPath)) 31 const smm = await getSm(path) 32 generator.applySourceMap(smm) 34 memo = await new SourceMapConsumer(generator.toString()) 38export const mapStackTrace = async ({stackA}: {stackA: string[]}) => { 40 let [header, ...lines] = stackA 42 let mapPaths: string[] = [...new Set(lines.map(getLocalSmPathForLine).filter(Boolean) as string[])] 43 const mapPathsExist = mapPaths.filter((path: string) => fs.existsSync(path)) 44 const sourceMapsNotExist = difference(mapPaths, mapPathsExist) 45 if (sourceMapsNotExist.length > 0) { 46 console.log({sourceMapsNotExist}) 48 mapPaths = mapPathsExist 50 if (mapPaths.length == 0) return stackA 52 const smc = await getCombinedSmc({mapPaths}) 54 lines = lines.map((line) => { 55 // stacktrace-parser doesn't seem to support stacktrace lines like this: 56 // index-12345678.js:1:2 a 57 const match = line.match(/^(\s+)([^\s]+:\d+:\d+)\s+([^\s]+)$/) 59 return `${match[1]}at ${match[3]} (${match[2]})` 65 const stack = parse(lines.join('\n')) 68 return stack.map((stackItem, ii) => { 69 const { methodName, lineNumber, column, file } = stackItem 72 if (lineNumber == null || lineNumber < 1) { 73 return ` at ${methodName || '[unknown]'}` 75 const pos = smc.originalPositionFor({ line: lineNumber, column: column! }); 76 if (pos && pos.line != null) { 77 return ` at ${pos.name || methodName || '[unknown]'} (${pos.source}:${pos.line}:${pos.column})` 81 'utt' + // cleanup that^ crap repl w small searchable token 85 console.log('FAILED_TO_PARSE_LINE', err) 86 return ` at FAILED_TO_PARSE_LINE`