@watchforge/browser 0.1.12 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/stacktrace.js +98 -26
package/package.json
CHANGED
package/src/stacktrace.js
CHANGED
|
@@ -538,6 +538,37 @@ async function fetchBrowserSourceMap(absPath) {
|
|
|
538
538
|
}
|
|
539
539
|
}
|
|
540
540
|
|
|
541
|
+
function parseDataSourceMap(sourceMappingUrl) {
|
|
542
|
+
if (!sourceMappingUrl?.startsWith("data:")) return null;
|
|
543
|
+
|
|
544
|
+
try {
|
|
545
|
+
const commaIndex = sourceMappingUrl.indexOf(",");
|
|
546
|
+
if (commaIndex === -1) return null;
|
|
547
|
+
|
|
548
|
+
const metadata = sourceMappingUrl.slice(0, commaIndex);
|
|
549
|
+
const payload = sourceMappingUrl.slice(commaIndex + 1);
|
|
550
|
+
const json = metadata.includes(";base64")
|
|
551
|
+
? decodeURIComponent(escape(atob(payload)))
|
|
552
|
+
: decodeURIComponent(payload);
|
|
553
|
+
return JSON.parse(json);
|
|
554
|
+
} catch {
|
|
555
|
+
return null;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
function findInlineSourceMap(sourceText) {
|
|
560
|
+
if (!sourceText || typeof sourceText !== "string") return null;
|
|
561
|
+
|
|
562
|
+
const sourceMapPattern = /\/\/# sourceMappingURL=([^\s"'\\)]+)/g;
|
|
563
|
+
let match;
|
|
564
|
+
while ((match = sourceMapPattern.exec(sourceText))) {
|
|
565
|
+
const sourceMap = parseDataSourceMap(match[1]);
|
|
566
|
+
if (sourceMap) return sourceMap;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
return null;
|
|
570
|
+
}
|
|
571
|
+
|
|
541
572
|
async function findSourceMapForFrame(frame) {
|
|
542
573
|
const wanted = normalizeSourcePath(frame.abs_path || frame.module);
|
|
543
574
|
const scriptUrls = [];
|
|
@@ -582,16 +613,31 @@ async function findSourceMapForFrame(frame) {
|
|
|
582
613
|
return null;
|
|
583
614
|
}
|
|
584
615
|
|
|
585
|
-
async function
|
|
586
|
-
const resolved = await findSourceMapForFrame(frame);
|
|
587
|
-
if (!resolved) return false;
|
|
588
|
-
|
|
589
|
-
const { sourceMap } = resolved;
|
|
590
|
-
|
|
616
|
+
async function applySourceMapToFrame(frame, sourceMap) {
|
|
591
617
|
try {
|
|
592
618
|
const SourceMapConsumer = await getSourceMapConsumer();
|
|
593
619
|
if (!SourceMapConsumer) return false;
|
|
594
620
|
|
|
621
|
+
const sources = Array.isArray(sourceMap.sources) ? sourceMap.sources : [];
|
|
622
|
+
const contents = Array.isArray(sourceMap.sourcesContent)
|
|
623
|
+
? sourceMap.sourcesContent
|
|
624
|
+
: [];
|
|
625
|
+
const matchedSourceIndex = sources.findIndex((candidate) =>
|
|
626
|
+
sourceMatchesFrame(candidate, frame.abs_path || frame.module || frame.raw_abs_path)
|
|
627
|
+
);
|
|
628
|
+
|
|
629
|
+
if (matchedSourceIndex >= 0 && contents[matchedSourceIndex]) {
|
|
630
|
+
const source = sources[matchedSourceIndex];
|
|
631
|
+
const sourceLines = contents[matchedSourceIndex].split("\n");
|
|
632
|
+
const originalLine = frame.lineno;
|
|
633
|
+
if (originalLine && originalLine <= sourceLines.length) {
|
|
634
|
+
frame.abs_path = source;
|
|
635
|
+
frame.filename = normalizeSourcePath(source).split("/").pop() || frame.filename;
|
|
636
|
+
applySourceContext(frame, sourceLines, originalLine);
|
|
637
|
+
if (frame.context_line) return true;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
595
641
|
const consumer = await new SourceMapConsumer(sourceMap);
|
|
596
642
|
let source = null;
|
|
597
643
|
let lineno = frame.lineno;
|
|
@@ -639,28 +685,49 @@ async function enrichFrameWithSourceMap(frame) {
|
|
|
639
685
|
}
|
|
640
686
|
}
|
|
641
687
|
|
|
642
|
-
function
|
|
643
|
-
const
|
|
644
|
-
|
|
645
|
-
Object.values(globalObject).find(
|
|
646
|
-
(value) =>
|
|
647
|
-
Array.isArray(value) &&
|
|
648
|
-
value.some((item) => Array.isArray(item) && item.length >= 2)
|
|
649
|
-
) || [];
|
|
688
|
+
async function enrichFrameWithSourceMap(frame) {
|
|
689
|
+
const resolved = await findSourceMapForFrame(frame);
|
|
690
|
+
if (!resolved) return false;
|
|
650
691
|
|
|
692
|
+
return applySourceMapToFrame(frame, resolved.sourceMap);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
function getWebpackChunkGlobals(globalObject) {
|
|
696
|
+
return Object.entries(globalObject)
|
|
697
|
+
.filter(([, value]) => Array.isArray(value))
|
|
698
|
+
.sort(([nameA], [nameB]) => {
|
|
699
|
+
const score = (name) => (name.startsWith("webpackChunk") ? 0 : 1);
|
|
700
|
+
return score(nameA) - score(nameB);
|
|
701
|
+
})
|
|
702
|
+
.map(([, value]) => value);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
function getWebpackFrameArtifacts(frame) {
|
|
706
|
+
const globalObject = typeof globalThis !== "undefined" ? globalThis : window;
|
|
651
707
|
const framePath = normalizeSourcePath(
|
|
652
708
|
frame.abs_path || frame.module || frame.raw_abs_path
|
|
653
709
|
);
|
|
654
|
-
if (!framePath
|
|
655
|
-
|
|
656
|
-
for (const
|
|
657
|
-
const
|
|
658
|
-
|
|
710
|
+
if (!framePath) return null;
|
|
711
|
+
|
|
712
|
+
for (const webpackChunks of getWebpackChunkGlobals(globalObject)) {
|
|
713
|
+
for (const chunk of webpackChunks) {
|
|
714
|
+
const modules = Array.isArray(chunk) ? chunk[1] : null;
|
|
715
|
+
if (!modules || typeof modules !== "object") continue;
|
|
716
|
+
|
|
717
|
+
for (const [moduleId, factory] of Object.entries(modules)) {
|
|
718
|
+
const factorySource = String(factory);
|
|
719
|
+
if (
|
|
720
|
+
!sourceMatchesFrame(moduleId, framePath) &&
|
|
721
|
+
!sourceMatchesFrame(factorySource.match(/sourceURL=([^\s"'\\)]+)/)?.[1], framePath)
|
|
722
|
+
) {
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
659
725
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
726
|
+
return {
|
|
727
|
+
lines: factorySource.includes("\n") ? factorySource.split("\n") : null,
|
|
728
|
+
sourceMap: findInlineSourceMap(factorySource),
|
|
729
|
+
};
|
|
730
|
+
}
|
|
664
731
|
}
|
|
665
732
|
}
|
|
666
733
|
|
|
@@ -670,9 +737,14 @@ function getSourceContentFromWebpackFrame(frame) {
|
|
|
670
737
|
async function enrichFrameWithBrowserSource(frame) {
|
|
671
738
|
if (!frame.in_app || !frame.lineno) return;
|
|
672
739
|
|
|
673
|
-
const
|
|
674
|
-
if (
|
|
675
|
-
|
|
740
|
+
const webpackArtifacts = getWebpackFrameArtifacts(frame);
|
|
741
|
+
if (webpackArtifacts?.sourceMap) {
|
|
742
|
+
const applied = await applySourceMapToFrame(frame, webpackArtifacts.sourceMap);
|
|
743
|
+
if (applied) return;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
if (webpackArtifacts?.lines) {
|
|
747
|
+
applySourceContext(frame, webpackArtifacts.lines, frame.lineno);
|
|
676
748
|
if (frame.context_line) return;
|
|
677
749
|
}
|
|
678
750
|
|