@jsenv/plugin-supervisor 1.4.0 → 1.4.1
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/dist/js/supervisor.js +309 -256
- package/dist/jsenv_plugin_supervisor.js +118 -139
- package/package.json +4 -4
- package/src/client/supervisor.js +332 -263
- package/src/jsenv_plugin_supervisor.js +16 -10
package/src/client/supervisor.js
CHANGED
|
@@ -160,16 +160,20 @@ window.__supervisor__ = (() => {
|
|
|
160
160
|
}
|
|
161
161
|
const scriptLoadPromise = getScriptLoadPromise(currentScriptClone);
|
|
162
162
|
parentNode.replaceChild(currentScriptClone, nodeToReplace);
|
|
163
|
-
const { detectedBy, failed,
|
|
163
|
+
const { detectedBy, failed, errorEvent } = await scriptLoadPromise;
|
|
164
164
|
if (failed) {
|
|
165
|
+
const messageDefault = `Error while loading script`;
|
|
166
|
+
const { error, message, filename, lineno, colno } = errorEvent;
|
|
165
167
|
if (detectedBy === "script_error_event") {
|
|
166
168
|
// window.error won't be dispatched for this error
|
|
167
|
-
reportErrorBackToBrowser(error);
|
|
169
|
+
reportErrorBackToBrowser(error || errorEvent);
|
|
168
170
|
}
|
|
169
|
-
fail(error, {
|
|
170
|
-
message:
|
|
171
|
+
fail(error || message || messageDefault, {
|
|
172
|
+
message: messageDefault,
|
|
171
173
|
reportedBy: "script_error_event",
|
|
172
|
-
url: urlObject.href,
|
|
174
|
+
url: filename || urlObject.href,
|
|
175
|
+
line: lineno,
|
|
176
|
+
column: colno,
|
|
173
177
|
});
|
|
174
178
|
if (detectedBy === "script_error_event") {
|
|
175
179
|
supervisor.reportException(result.exception);
|
|
@@ -222,7 +226,7 @@ window.__supervisor__ = (() => {
|
|
|
222
226
|
return result;
|
|
223
227
|
} catch (e) {
|
|
224
228
|
fail(e, {
|
|
225
|
-
message: `Error while importing module
|
|
229
|
+
message: `Error while importing module`,
|
|
226
230
|
reportedBy: "dynamic_import",
|
|
227
231
|
url: urlObject.href,
|
|
228
232
|
});
|
|
@@ -268,16 +272,21 @@ window.__supervisor__ = (() => {
|
|
|
268
272
|
const scriptLoadResultPromise =
|
|
269
273
|
getScriptLoadPromise(currentScriptClone);
|
|
270
274
|
parentNode.replaceChild(currentScriptClone, nodeToReplace);
|
|
271
|
-
const { detectedBy, failed,
|
|
275
|
+
const { detectedBy, failed, errorEvent } =
|
|
276
|
+
await scriptLoadResultPromise;
|
|
272
277
|
|
|
273
278
|
if (failed) {
|
|
279
|
+
const messageDefault = `Error while loading module`;
|
|
280
|
+
const { error, message, filename, lineno, colno } = errorEvent;
|
|
274
281
|
// if (detectedBy === "script_error_event") {
|
|
275
282
|
// reportErrorBackToBrowser(error)
|
|
276
283
|
// }
|
|
277
|
-
fail(error, {
|
|
278
|
-
message:
|
|
284
|
+
fail(error || message || messageDefault, {
|
|
285
|
+
message: messageDefault,
|
|
279
286
|
reportedBy: "script_error_event",
|
|
280
|
-
url: urlObject.href,
|
|
287
|
+
url: filename || urlObject.href,
|
|
288
|
+
line: lineno,
|
|
289
|
+
column: colno,
|
|
281
290
|
});
|
|
282
291
|
if (detectedBy === "script_error_event") {
|
|
283
292
|
supervisor.reportException(result.exception);
|
|
@@ -435,10 +444,11 @@ window.__supervisor__ = (() => {
|
|
|
435
444
|
stackSourcemapped: null,
|
|
436
445
|
stackOriginal: "", // the stack from runtime, not normalized to v8
|
|
437
446
|
stackTrace: "", // the stack trace (without error name and message)
|
|
447
|
+
stackFrames: undefined,
|
|
438
448
|
withServerUrls: {
|
|
439
449
|
message: "",
|
|
440
|
-
stackTrace: "",
|
|
441
450
|
stack: "",
|
|
451
|
+
stackTrace: "",
|
|
442
452
|
},
|
|
443
453
|
meta: null,
|
|
444
454
|
site: {
|
|
@@ -463,78 +473,154 @@ window.__supervisor__ = (() => {
|
|
|
463
473
|
exception.message = reason;
|
|
464
474
|
return;
|
|
465
475
|
}
|
|
466
|
-
if (reason
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
!isWebkitOrSafari
|
|
475
|
-
) {
|
|
476
|
-
// stackTrace formatted by V8
|
|
477
|
-
exception.stackSourcemapped = true;
|
|
478
|
-
exception.stack = error.stack;
|
|
479
|
-
exception.stackTrace = getErrorStackTrace(error);
|
|
480
|
-
} else if (error.stack) {
|
|
481
|
-
exception.stackSourcemapped = false;
|
|
482
|
-
exception.stackTrace = error.stack;
|
|
483
|
-
exception.stack = stringifyStack(exception);
|
|
484
|
-
}
|
|
476
|
+
if (typeof reason !== "object") {
|
|
477
|
+
exception.message = JSON.stringify(reason);
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
// isError can be false when reason is an ErrorEvent for instance
|
|
481
|
+
exception.isError = reason instanceof Error;
|
|
482
|
+
exception.name = reason.name || "Error";
|
|
483
|
+
exception.message = reason.message || message || "";
|
|
485
484
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
485
|
+
let stackFrames;
|
|
486
|
+
if (
|
|
487
|
+
exception.isError &&
|
|
488
|
+
Error.captureStackTrace &&
|
|
489
|
+
// captureStackTrace exists on webkit but error.stack is not v8
|
|
490
|
+
!isWebkitOrSafari
|
|
491
|
+
) {
|
|
492
|
+
// stackTrace formatted by V8
|
|
493
|
+
const { prepareStackTrace } = Error;
|
|
494
|
+
Error.prepareStackTrace = (e, callSites) => {
|
|
495
|
+
Error.prepareStackTrace = prepareStackTrace;
|
|
496
|
+
|
|
497
|
+
const getPropertiesFromEvalOrigin = (origin) => {
|
|
498
|
+
// Most eval() calls are in this format
|
|
499
|
+
const topLevelEvalMatch =
|
|
500
|
+
/^eval at ([^(]+) \((.+):(\d+):(\d+)\)$/.exec(origin);
|
|
501
|
+
if (topLevelEvalMatch) {
|
|
502
|
+
const source = topLevelEvalMatch[2];
|
|
503
|
+
const line = Number(topLevelEvalMatch[3]);
|
|
504
|
+
const column = topLevelEvalMatch[4] - 1;
|
|
505
|
+
return {
|
|
506
|
+
url: source,
|
|
507
|
+
line,
|
|
508
|
+
column,
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
// Parse nested eval() calls using recursion
|
|
512
|
+
const nestedEvalMatch = /^eval at ([^(]+) \((.+)\)$/.exec(origin);
|
|
513
|
+
if (nestedEvalMatch) {
|
|
514
|
+
return getPropertiesFromEvalOrigin(nestedEvalMatch[2]);
|
|
515
|
+
}
|
|
516
|
+
return null;
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
stackFrames = [];
|
|
520
|
+
for (const callSite of callSites) {
|
|
521
|
+
const url =
|
|
522
|
+
callSite.getFileName() || callSite.getScriptNameOrSourceURL();
|
|
523
|
+
const line = callSite.getLineNumber();
|
|
524
|
+
const column = callSite.getColumnNumber();
|
|
525
|
+
const site = resolveUrlSite({ url, line, column });
|
|
526
|
+
const stackFrame = {
|
|
527
|
+
raw: ` at ${String(callSite)}`,
|
|
528
|
+
url: site.url,
|
|
529
|
+
line: site.line,
|
|
530
|
+
column: site.column,
|
|
531
|
+
functionName: callSite.getFunctionName(),
|
|
532
|
+
isNative: callSite.isNative(),
|
|
533
|
+
isEval: callSite.isEval(),
|
|
534
|
+
isConstructor: callSite.isConstructor(),
|
|
535
|
+
isAsync: callSite.isAsync(),
|
|
536
|
+
evalSite: null,
|
|
537
|
+
};
|
|
538
|
+
if (stackFrame.isEval) {
|
|
539
|
+
const evalOrigin = stackFrame.getEvalOrigin();
|
|
540
|
+
if (evalOrigin) {
|
|
541
|
+
stackFrame.evalSite = getPropertiesFromEvalOrigin(evalOrigin);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
stackFrames.push(stackFrame);
|
|
505
545
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
546
|
+
let stackTrace = "";
|
|
547
|
+
for (const stackFrame of stackFrames) {
|
|
548
|
+
if (stackTrace) stackTrace += "\n";
|
|
549
|
+
stackTrace += stackFrame.raw;
|
|
510
550
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
551
|
+
exception.stackTrace = stackTrace;
|
|
552
|
+
|
|
553
|
+
let stack = "";
|
|
554
|
+
const name = reason.name || "Error";
|
|
555
|
+
const message = reason.message || "";
|
|
556
|
+
stack += `${name}: ${message}`;
|
|
557
|
+
if (stackTrace) {
|
|
558
|
+
stack += `\n${stackTrace}`;
|
|
514
559
|
}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
560
|
+
return stack;
|
|
561
|
+
};
|
|
562
|
+
|
|
563
|
+
exception.stackSourcemapped = true;
|
|
564
|
+
exception.stack = reason.stack;
|
|
565
|
+
if (stackFrames === undefined) {
|
|
566
|
+
// Error.prepareStackTrace not trigerred
|
|
567
|
+
// - reason is not an error
|
|
568
|
+
// - reason.stack already get
|
|
569
|
+
Error.prepareStackTrace = prepareStackTrace;
|
|
570
|
+
exception.stackTrace = getErrorStackTrace(reason);
|
|
571
|
+
} else {
|
|
572
|
+
exception.stackFrames = stackFrames;
|
|
573
|
+
const [firstCallFrame] = stackFrames;
|
|
574
|
+
if (
|
|
575
|
+
exception.site.url === null &&
|
|
576
|
+
firstCallFrame &&
|
|
577
|
+
firstCallFrame.url
|
|
578
|
+
) {
|
|
579
|
+
Object.assign(exception.site, {
|
|
580
|
+
url: firstCallFrame.url,
|
|
581
|
+
line: firstCallFrame.line,
|
|
582
|
+
column: firstCallFrame.column,
|
|
583
|
+
});
|
|
520
584
|
}
|
|
521
585
|
}
|
|
522
|
-
|
|
586
|
+
} else {
|
|
587
|
+
exception.stackSourcemapped = false;
|
|
588
|
+
exception.stackTrace = reason.stack;
|
|
589
|
+
exception.stack = stringifyStack(exception);
|
|
523
590
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
exception.
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
591
|
+
|
|
592
|
+
if (exception.site.url === null && reason.url) {
|
|
593
|
+
Object.assign(exception.site, resolveUrlSite({ url: reason.url }));
|
|
594
|
+
}
|
|
595
|
+
export_missing: {
|
|
596
|
+
// chrome
|
|
597
|
+
if (exception.message.includes("does not provide an export named")) {
|
|
598
|
+
exception.code = DYNAMIC_IMPORT_EXPORT_MISSING;
|
|
531
599
|
}
|
|
532
|
-
|
|
533
|
-
|
|
600
|
+
// firefox
|
|
601
|
+
if (
|
|
602
|
+
exception.message.startsWith("import not found:") ||
|
|
603
|
+
exception.message.startsWith("ambiguous indirect export:")
|
|
604
|
+
) {
|
|
605
|
+
exception.code = DYNAMIC_IMPORT_EXPORT_MISSING;
|
|
606
|
+
}
|
|
607
|
+
// safari
|
|
608
|
+
if (exception.message.startsWith("import binding name")) {
|
|
609
|
+
exception.code = DYNAMIC_IMPORT_EXPORT_MISSING;
|
|
610
|
+
}
|
|
611
|
+
if (exception.message.includes("Importing a module script failed")) {
|
|
612
|
+
exception.code = DYNAMIC_IMPORT_FETCH_ERROR;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
js_syntax_error: {
|
|
616
|
+
if (
|
|
617
|
+
!exception.code &&
|
|
618
|
+
exception.name === "SyntaxError" &&
|
|
619
|
+
typeof line === "number"
|
|
620
|
+
) {
|
|
621
|
+
exception.code = DYNAMIC_IMPORT_SYNTAX_ERROR;
|
|
534
622
|
}
|
|
535
|
-
return;
|
|
536
623
|
}
|
|
537
|
-
exception.message = JSON.stringify(reason);
|
|
538
624
|
};
|
|
539
625
|
writeBasicProperties();
|
|
540
626
|
|
|
@@ -549,7 +635,8 @@ window.__supervisor__ = (() => {
|
|
|
549
635
|
const fileUrlSite = resolveUrlSite({ url, line, column });
|
|
550
636
|
if (
|
|
551
637
|
fileUrlSite.isInline &&
|
|
552
|
-
exception.
|
|
638
|
+
exception.name === "SyntaxError" &&
|
|
639
|
+
exception.code !== DYNAMIC_IMPORT_EXPORT_MISSING
|
|
553
640
|
) {
|
|
554
641
|
// syntax error on inline script need line-1 for some reason
|
|
555
642
|
fileUrlSite.line = fileUrlSite.line - 1;
|
|
@@ -588,14 +675,15 @@ window.__supervisor__ = (() => {
|
|
|
588
675
|
return exception;
|
|
589
676
|
};
|
|
590
677
|
|
|
591
|
-
const stringifyStack = ({ name, message, stackTrace }) => {
|
|
592
|
-
let stack;
|
|
678
|
+
const stringifyStack = ({ codeFrame, name, message, stackTrace }) => {
|
|
679
|
+
let stack = "";
|
|
680
|
+
if (codeFrame) {
|
|
681
|
+
stack += `${codeFrame}\n`;
|
|
682
|
+
}
|
|
593
683
|
if (name && message) {
|
|
594
|
-
stack
|
|
684
|
+
stack += `${name}: ${message}`;
|
|
595
685
|
} else if (message) {
|
|
596
|
-
stack
|
|
597
|
-
} else {
|
|
598
|
-
stack = "";
|
|
686
|
+
stack += message;
|
|
599
687
|
}
|
|
600
688
|
if (stackTrace) {
|
|
601
689
|
stack += `\n${stackTrace}`;
|
|
@@ -737,153 +825,6 @@ window.__supervisor__ = (() => {
|
|
|
737
825
|
});
|
|
738
826
|
};
|
|
739
827
|
|
|
740
|
-
let formatError;
|
|
741
|
-
error_formatter: {
|
|
742
|
-
formatError = (exceptionInfo) => {
|
|
743
|
-
const errorParts = {
|
|
744
|
-
theme: "dark",
|
|
745
|
-
title: "An error occured",
|
|
746
|
-
text: "",
|
|
747
|
-
tip: "",
|
|
748
|
-
errorDetailsPromise: null,
|
|
749
|
-
};
|
|
750
|
-
const tips = [];
|
|
751
|
-
tips.push("Click outside to close.");
|
|
752
|
-
errorParts.tip = tips.join(`\n <br />\n `);
|
|
753
|
-
|
|
754
|
-
const generateClickableText = (text) => {
|
|
755
|
-
const textWithHtmlLinks = makeLinksClickable(text, {
|
|
756
|
-
createLink: ({ url, line, column }) => {
|
|
757
|
-
const urlSite = resolveUrlSite({ url, line, column });
|
|
758
|
-
if (errorBaseUrl) {
|
|
759
|
-
if (urlSite.url.startsWith(rootDirectoryUrl)) {
|
|
760
|
-
urlSite.url = `${errorBaseUrl}${urlSite.url.slice(
|
|
761
|
-
rootDirectoryUrl.length,
|
|
762
|
-
)}`;
|
|
763
|
-
} else {
|
|
764
|
-
urlSite.url = "file:///mocked_for_snapshots";
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
const urlWithLineAndColumn = stringifyUrlSite(urlSite);
|
|
768
|
-
return {
|
|
769
|
-
href:
|
|
770
|
-
urlSite.url.startsWith("file:") && openInEditor
|
|
771
|
-
? `javascript:window.fetch('/__open_in_editor__/${encodeURIComponent(
|
|
772
|
-
urlWithLineAndColumn,
|
|
773
|
-
)}')`
|
|
774
|
-
: urlSite.url,
|
|
775
|
-
text: urlWithLineAndColumn,
|
|
776
|
-
};
|
|
777
|
-
},
|
|
778
|
-
});
|
|
779
|
-
return textWithHtmlLinks;
|
|
780
|
-
};
|
|
781
|
-
|
|
782
|
-
errorParts.text = stringifyStack({
|
|
783
|
-
name: exceptionInfo.name,
|
|
784
|
-
message: exceptionInfo.message
|
|
785
|
-
? generateClickableText(exceptionInfo.message)
|
|
786
|
-
: "",
|
|
787
|
-
stackTrace: exceptionInfo.stackTrace
|
|
788
|
-
? generateClickableText(exceptionInfo.stackTrace)
|
|
789
|
-
: "",
|
|
790
|
-
});
|
|
791
|
-
if (exceptionInfo.site.url) {
|
|
792
|
-
errorParts.errorDetailsPromise = (async () => {
|
|
793
|
-
if (!serverIsJsenvDevServer) {
|
|
794
|
-
return null;
|
|
795
|
-
}
|
|
796
|
-
try {
|
|
797
|
-
if (
|
|
798
|
-
exceptionInfo.code === DYNAMIC_IMPORT_FETCH_ERROR ||
|
|
799
|
-
exceptionInfo.reportedBy === "script_error_event"
|
|
800
|
-
) {
|
|
801
|
-
const response = await window.fetch(
|
|
802
|
-
`/__get_error_cause__/${encodeURIComponent(
|
|
803
|
-
exceptionInfo.site.isInline
|
|
804
|
-
? exceptionInfo.site.originalUrl
|
|
805
|
-
: exceptionInfo.site.url,
|
|
806
|
-
)}`,
|
|
807
|
-
);
|
|
808
|
-
if (response.status !== 200) {
|
|
809
|
-
return null;
|
|
810
|
-
}
|
|
811
|
-
const causeInfo = await response.json();
|
|
812
|
-
if (!causeInfo) {
|
|
813
|
-
return null;
|
|
814
|
-
}
|
|
815
|
-
const causeText =
|
|
816
|
-
causeInfo.code === "NOT_FOUND"
|
|
817
|
-
? stringifyStack({
|
|
818
|
-
name: causeInfo.name,
|
|
819
|
-
message: generateClickableText(causeInfo.reason),
|
|
820
|
-
stackTrace: generateClickableText(causeInfo.codeFrame),
|
|
821
|
-
})
|
|
822
|
-
: stringifyStack({
|
|
823
|
-
name: causeInfo.name,
|
|
824
|
-
message: generateClickableText(causeInfo.stack),
|
|
825
|
-
stackTrace: generateClickableText(causeInfo.codeFrame),
|
|
826
|
-
});
|
|
827
|
-
return {
|
|
828
|
-
cause: causeText,
|
|
829
|
-
};
|
|
830
|
-
}
|
|
831
|
-
if (exceptionInfo.site.line !== undefined) {
|
|
832
|
-
const urlToFetch = new URL(
|
|
833
|
-
`/__get_code_frame__/${encodeURIComponent(
|
|
834
|
-
stringifyUrlSite(exceptionInfo.site),
|
|
835
|
-
)}`,
|
|
836
|
-
window.origin,
|
|
837
|
-
);
|
|
838
|
-
if (!exceptionInfo.stackSourcemapped) {
|
|
839
|
-
urlToFetch.searchParams.set("remap", "");
|
|
840
|
-
}
|
|
841
|
-
const response = await window.fetch(urlToFetch);
|
|
842
|
-
if (response.status !== 200) {
|
|
843
|
-
return null;
|
|
844
|
-
}
|
|
845
|
-
const codeFrame = await response.text();
|
|
846
|
-
return {
|
|
847
|
-
codeFrame: generateClickableText(codeFrame),
|
|
848
|
-
};
|
|
849
|
-
}
|
|
850
|
-
} catch (e) {
|
|
851
|
-
// happens if server is closed for instance
|
|
852
|
-
return null;
|
|
853
|
-
}
|
|
854
|
-
return null;
|
|
855
|
-
})();
|
|
856
|
-
}
|
|
857
|
-
return errorParts;
|
|
858
|
-
};
|
|
859
|
-
|
|
860
|
-
const makeLinksClickable = (
|
|
861
|
-
string,
|
|
862
|
-
{ createLink = ({ url }) => url },
|
|
863
|
-
) => {
|
|
864
|
-
// normalize line breaks
|
|
865
|
-
string = string.replace(/\n/g, "\n");
|
|
866
|
-
string = escapeHtml(string);
|
|
867
|
-
// render links
|
|
868
|
-
string = replaceUrls(string, ({ url, line, column }) => {
|
|
869
|
-
const { href, text } = createLink({ url, line, column });
|
|
870
|
-
return link({ href, text });
|
|
871
|
-
});
|
|
872
|
-
return string;
|
|
873
|
-
};
|
|
874
|
-
|
|
875
|
-
const escapeHtml = (string) => {
|
|
876
|
-
return string
|
|
877
|
-
.replace(/&/g, "&")
|
|
878
|
-
.replace(/</g, "<")
|
|
879
|
-
.replace(/>/g, ">")
|
|
880
|
-
.replace(/"/g, """)
|
|
881
|
-
.replace(/'/g, "'");
|
|
882
|
-
};
|
|
883
|
-
|
|
884
|
-
const link = ({ href, text = href }) => `<a href="${href}">${text}</a>`;
|
|
885
|
-
}
|
|
886
|
-
|
|
887
828
|
let displayErrorNotification;
|
|
888
829
|
error_notification: {
|
|
889
830
|
const { Notification } = window;
|
|
@@ -928,51 +869,178 @@ window.__supervisor__ = (() => {
|
|
|
928
869
|
};
|
|
929
870
|
|
|
930
871
|
class JsenvErrorOverlay extends HTMLElement {
|
|
931
|
-
constructor(
|
|
872
|
+
constructor(exception) {
|
|
932
873
|
super();
|
|
933
|
-
|
|
934
|
-
|
|
874
|
+
const root = this.attachShadow({ mode: "open" });
|
|
875
|
+
const tips = [];
|
|
876
|
+
tips.push("Click outside to close.");
|
|
877
|
+
const tip = tips.join(`\n <br />\n `);
|
|
878
|
+
root.innerHTML = `
|
|
935
879
|
<style>
|
|
936
880
|
${overlayCSS}
|
|
937
881
|
</style>
|
|
938
882
|
<div class="backdrop"></div>
|
|
939
|
-
<div class="overlay" data-theme
|
|
883
|
+
<div class="overlay" data-theme="dark">
|
|
940
884
|
<h1 class="title">
|
|
941
|
-
|
|
885
|
+
An error occured
|
|
942
886
|
</h1>
|
|
943
|
-
<pre class="text"
|
|
887
|
+
<pre class="text"></pre>
|
|
944
888
|
<div class="tip">
|
|
945
889
|
${tip}
|
|
946
890
|
</div>
|
|
947
891
|
</div>`;
|
|
948
|
-
|
|
892
|
+
root.querySelector(".backdrop").onclick = () => {
|
|
949
893
|
if (!this.parentNode) {
|
|
950
894
|
// not in document anymore
|
|
951
895
|
return;
|
|
952
896
|
}
|
|
953
|
-
|
|
897
|
+
root.querySelector(".backdrop").onclick = null;
|
|
954
898
|
this.parentNode.removeChild(this);
|
|
955
899
|
};
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
900
|
+
|
|
901
|
+
const renderException = () => {
|
|
902
|
+
const { cause = {} } = exception;
|
|
903
|
+
const { trace = {} } = cause;
|
|
904
|
+
|
|
905
|
+
root.querySelector(".text").innerHTML = stringifyStack({
|
|
906
|
+
codeFrame: trace.codeFrame
|
|
907
|
+
? generateClickableText(trace.codeFrame)
|
|
908
|
+
: "",
|
|
909
|
+
name: exception.name,
|
|
910
|
+
message: exception.message
|
|
911
|
+
? generateClickableText(exception.message)
|
|
912
|
+
: "",
|
|
913
|
+
stackTrace: exception.stackTrace
|
|
914
|
+
? generateClickableText(exception.stackTrace)
|
|
915
|
+
: "",
|
|
916
|
+
});
|
|
917
|
+
if (cause) {
|
|
918
|
+
const causeText = stringifyStack({
|
|
919
|
+
name: cause.name,
|
|
920
|
+
message: cause.reason
|
|
921
|
+
? generateClickableText(cause.reason)
|
|
922
|
+
: cause.stack
|
|
923
|
+
? generateClickableText(cause.stack)
|
|
924
|
+
: "",
|
|
925
|
+
});
|
|
926
|
+
if (causeText) {
|
|
927
|
+
const causeTextIndented = prefixRemainingLines(causeText, " ");
|
|
928
|
+
root.querySelector(".text").innerHTML +=
|
|
929
|
+
`\n [cause]: ${causeTextIndented}`;
|
|
960
930
|
}
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
931
|
+
}
|
|
932
|
+
if (
|
|
933
|
+
!exception.stackTrace &&
|
|
934
|
+
(exception.reportedBy === "script_error_event" ||
|
|
935
|
+
exception.reportedBy === "window_error_event" ||
|
|
936
|
+
exception.name === "SyntaxError" ||
|
|
937
|
+
exception.code === DYNAMIC_IMPORT_FETCH_ERROR ||
|
|
938
|
+
exception.code === DYNAMIC_IMPORT_EXPORT_MISSING ||
|
|
939
|
+
exception.code === DYNAMIC_IMPORT_SYNTAX_ERROR)
|
|
940
|
+
) {
|
|
941
|
+
let traceSite = stringifyUrlSite(trace);
|
|
942
|
+
if (traceSite) {
|
|
943
|
+
root.querySelector(".text").innerHTML +=
|
|
944
|
+
`\n at ${generateClickableText(traceSite)}`;
|
|
965
945
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
renderException();
|
|
949
|
+
if (exception.site.url && serverIsJsenvDevServer) {
|
|
950
|
+
(async () => {
|
|
951
|
+
try {
|
|
952
|
+
if (
|
|
953
|
+
exception.code === DYNAMIC_IMPORT_FETCH_ERROR ||
|
|
954
|
+
exception.reportedBy === "script_error_event"
|
|
955
|
+
) {
|
|
956
|
+
const response = await window.fetch(
|
|
957
|
+
`/__get_error_cause__/${encodeURIComponent(
|
|
958
|
+
exception.site.isInline
|
|
959
|
+
? exception.site.originalUrl
|
|
960
|
+
: exception.site.url,
|
|
961
|
+
)}`,
|
|
962
|
+
);
|
|
963
|
+
if (response.status !== 200) {
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
const causeInfo = await response.json();
|
|
967
|
+
if (!causeInfo) {
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
exception.cause = causeInfo;
|
|
971
|
+
renderException();
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
if (exception.site.line !== undefined) {
|
|
975
|
+
const urlToFetch = new URL(
|
|
976
|
+
`/__get_cause_trace__/${encodeURIComponent(
|
|
977
|
+
stringifyUrlSite(exception.site),
|
|
978
|
+
)}`,
|
|
979
|
+
window.origin,
|
|
980
|
+
);
|
|
981
|
+
if (!exception.stackSourcemapped) {
|
|
982
|
+
urlToFetch.searchParams.set("remap", "");
|
|
983
|
+
}
|
|
984
|
+
const response = await window.fetch(urlToFetch);
|
|
985
|
+
if (response.status !== 200) {
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
const causeTrace = await response.json();
|
|
989
|
+
exception.cause = {
|
|
990
|
+
trace: causeTrace,
|
|
991
|
+
};
|
|
992
|
+
renderException();
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
} catch (e) {
|
|
996
|
+
// happens if server is closed for instance
|
|
997
|
+
return;
|
|
970
998
|
}
|
|
971
|
-
});
|
|
999
|
+
})();
|
|
972
1000
|
}
|
|
973
1001
|
}
|
|
974
1002
|
}
|
|
975
|
-
|
|
1003
|
+
const generateClickableText = (text) => {
|
|
1004
|
+
const textWithHtmlLinks = makeLinksClickable(text, {
|
|
1005
|
+
createLink: ({ url, line, column }) => {
|
|
1006
|
+
const urlSite = resolveUrlSite({ url, line, column });
|
|
1007
|
+
if (errorBaseUrl) {
|
|
1008
|
+
if (urlSite.url.startsWith(rootDirectoryUrl)) {
|
|
1009
|
+
urlSite.url = `${errorBaseUrl}${urlSite.url.slice(
|
|
1010
|
+
rootDirectoryUrl.length,
|
|
1011
|
+
)}`;
|
|
1012
|
+
} else {
|
|
1013
|
+
urlSite.url = "file:///mocked_for_snapshots";
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
const urlWithLineAndColumn = stringifyUrlSite(urlSite);
|
|
1017
|
+
return {
|
|
1018
|
+
href:
|
|
1019
|
+
urlSite.url.startsWith("file:") && openInEditor
|
|
1020
|
+
? `javascript:window.fetch('/__open_in_editor__/${encodeURIComponent(
|
|
1021
|
+
urlWithLineAndColumn,
|
|
1022
|
+
)}')`
|
|
1023
|
+
: urlSite.url,
|
|
1024
|
+
text: urlWithLineAndColumn,
|
|
1025
|
+
};
|
|
1026
|
+
},
|
|
1027
|
+
});
|
|
1028
|
+
return textWithHtmlLinks;
|
|
1029
|
+
};
|
|
1030
|
+
const makeLinksClickable = (
|
|
1031
|
+
string,
|
|
1032
|
+
{ createLink = ({ url }) => url },
|
|
1033
|
+
) => {
|
|
1034
|
+
// normalize line breaks
|
|
1035
|
+
string = string.replace(/\r\n/g, "\n");
|
|
1036
|
+
string = escapeHtml(string);
|
|
1037
|
+
// render links
|
|
1038
|
+
string = replaceUrls(string, ({ url, line, column }) => {
|
|
1039
|
+
const { href, text } = createLink({ url, line, column });
|
|
1040
|
+
return link({ href, text });
|
|
1041
|
+
});
|
|
1042
|
+
return string;
|
|
1043
|
+
};
|
|
976
1044
|
const prefixRemainingLines = (text, prefix) => {
|
|
977
1045
|
const lines = text.split(/\r?\n/);
|
|
978
1046
|
const firstLine = lines.shift();
|
|
@@ -985,6 +1053,15 @@ window.__supervisor__ = (() => {
|
|
|
985
1053
|
}
|
|
986
1054
|
return result;
|
|
987
1055
|
};
|
|
1056
|
+
const escapeHtml = (string) => {
|
|
1057
|
+
return string
|
|
1058
|
+
.replace(/&/g, "&")
|
|
1059
|
+
.replace(/</g, "<")
|
|
1060
|
+
.replace(/>/g, ">")
|
|
1061
|
+
.replace(/"/g, """)
|
|
1062
|
+
.replace(/'/g, "'");
|
|
1063
|
+
};
|
|
1064
|
+
const link = ({ href, text = href }) => `<a href="${href}">${text}</a>`;
|
|
988
1065
|
|
|
989
1066
|
if (customElements && !customElements.get(JSENV_ERROR_OVERLAY_TAGNAME)) {
|
|
990
1067
|
customElements.define(JSENV_ERROR_OVERLAY_TAGNAME, JsenvErrorOverlay);
|
|
@@ -1069,17 +1146,8 @@ window.__supervisor__ = (() => {
|
|
|
1069
1146
|
|
|
1070
1147
|
supervisor.createException = createException;
|
|
1071
1148
|
supervisor.reportException = (exception) => {
|
|
1072
|
-
const { theme, title, text, tip, errorDetailsPromise } =
|
|
1073
|
-
formatError(exception);
|
|
1074
|
-
|
|
1075
1149
|
if (errorOverlay) {
|
|
1076
|
-
const removeErrorOverlay = displayJsenvErrorOverlay(
|
|
1077
|
-
theme,
|
|
1078
|
-
title,
|
|
1079
|
-
text,
|
|
1080
|
-
tip,
|
|
1081
|
-
errorDetailsPromise,
|
|
1082
|
-
});
|
|
1150
|
+
const removeErrorOverlay = displayJsenvErrorOverlay(exception);
|
|
1083
1151
|
if (window.__reloader__) {
|
|
1084
1152
|
const onchange = window.__reloader__.status.onchange;
|
|
1085
1153
|
window.__reloader__.status.onchange = () => {
|
|
@@ -1092,8 +1160,8 @@ window.__supervisor__ = (() => {
|
|
|
1092
1160
|
}
|
|
1093
1161
|
if (errorNotification) {
|
|
1094
1162
|
displayErrorNotification({
|
|
1095
|
-
title,
|
|
1096
|
-
text,
|
|
1163
|
+
title: "An error occured",
|
|
1164
|
+
text: "todo",
|
|
1097
1165
|
});
|
|
1098
1166
|
}
|
|
1099
1167
|
return exception;
|
|
@@ -1114,6 +1182,7 @@ window.__supervisor__ = (() => {
|
|
|
1114
1182
|
// when error is reported within a worker error is null
|
|
1115
1183
|
// but there is a message property on errorEvent
|
|
1116
1184
|
reportedBy: "window_error_event",
|
|
1185
|
+
message,
|
|
1117
1186
|
url: filename,
|
|
1118
1187
|
line: lineno,
|
|
1119
1188
|
column: colno,
|
|
@@ -1159,7 +1228,7 @@ window.__supervisor__ = (() => {
|
|
|
1159
1228
|
resolve({
|
|
1160
1229
|
detectedBy: "window_error_event",
|
|
1161
1230
|
failed: true,
|
|
1162
|
-
|
|
1231
|
+
errorEvent,
|
|
1163
1232
|
});
|
|
1164
1233
|
}
|
|
1165
1234
|
};
|
|
@@ -1172,7 +1241,7 @@ window.__supervisor__ = (() => {
|
|
|
1172
1241
|
resolve({
|
|
1173
1242
|
detectedBy: "script_error_event",
|
|
1174
1243
|
failed: true,
|
|
1175
|
-
|
|
1244
|
+
errorEvent,
|
|
1176
1245
|
});
|
|
1177
1246
|
});
|
|
1178
1247
|
script.addEventListener("load", () => {
|