@posiwise/common-services 0.1.91 → 0.1.93
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.
|
@@ -36,6 +36,16 @@ class ScriptLoaderService {
|
|
|
36
36
|
this.document = document;
|
|
37
37
|
this._scripts = {};
|
|
38
38
|
}
|
|
39
|
+
getCspNonce() {
|
|
40
|
+
// Prefer explicit global set by server-side renderer
|
|
41
|
+
const w = globalThis;
|
|
42
|
+
if (w?.__cspNonce)
|
|
43
|
+
return w.__cspNonce;
|
|
44
|
+
// Fallback: try to read nonce from any existing script tag
|
|
45
|
+
const anyScript = this.document.querySelector('script[nonce]');
|
|
46
|
+
const n = anyScript?.nonce || anyScript?.getAttribute('nonce') || undefined;
|
|
47
|
+
return n || undefined;
|
|
48
|
+
}
|
|
39
49
|
load(tag, ...scripts) {
|
|
40
50
|
scripts.forEach((src) => {
|
|
41
51
|
if (!this._scripts[src]) {
|
|
@@ -73,6 +83,9 @@ class ScriptLoaderService {
|
|
|
73
83
|
const scriptTag = document.createElement('script');
|
|
74
84
|
scriptTag.type = 'text/javascript';
|
|
75
85
|
scriptTag.src = this._scripts[src].src;
|
|
86
|
+
const nonce = this.getCspNonce();
|
|
87
|
+
if (nonce)
|
|
88
|
+
scriptTag.nonce = nonce;
|
|
76
89
|
scriptTag.onload = () => {
|
|
77
90
|
this._scripts[src].loaded = true;
|
|
78
91
|
resolve({ src, loaded: true });
|
|
@@ -2806,6 +2819,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
|
|
|
2806
2819
|
|
|
2807
2820
|
class SentryErrorHandler {
|
|
2808
2821
|
static { this.sentryInitialized = false; }
|
|
2822
|
+
static { this.unhandledRejectionListenerAttached = false; }
|
|
2809
2823
|
constructor(appConfigService) {
|
|
2810
2824
|
this.appConfigService = appConfigService;
|
|
2811
2825
|
}
|
|
@@ -2820,16 +2834,15 @@ class SentryErrorHandler {
|
|
|
2820
2834
|
if (env?.integrations?.sentry_config) {
|
|
2821
2835
|
init({ ...config, ...env.integrations.sentry_config });
|
|
2822
2836
|
SentryErrorHandler.sentryInitialized = true;
|
|
2823
|
-
// Add a global listener for unhandled promise rejections
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2837
|
+
// Add a global listener for unhandled promise rejections (once)
|
|
2838
|
+
if (!SentryErrorHandler.unhandledRejectionListenerAttached) {
|
|
2839
|
+
window.addEventListener('unhandledrejection', (event) => {
|
|
2840
|
+
this.handlePromiseRejection(event);
|
|
2841
|
+
});
|
|
2842
|
+
SentryErrorHandler.unhandledRejectionListenerAttached = true;
|
|
2843
|
+
}
|
|
2827
2844
|
}
|
|
2828
2845
|
});
|
|
2829
|
-
// Add a global listener for unhandled promise rejections
|
|
2830
|
-
window.addEventListener('unhandledrejection', (event) => {
|
|
2831
|
-
this.handlePromiseRejection(event);
|
|
2832
|
-
});
|
|
2833
2846
|
}
|
|
2834
2847
|
async getSentryConfigAsync() {
|
|
2835
2848
|
return new Promise(resolve => {
|
|
@@ -2842,18 +2855,23 @@ class SentryErrorHandler {
|
|
|
2842
2855
|
// The previous integration (`BrowserTracing` + `routingInstrumentation`) was part of
|
|
2843
2856
|
// the legacy `@sentry/angular-ivy` API and isn't available in `@sentry/angular` v10.
|
|
2844
2857
|
beforeSend(event, hint) {
|
|
2858
|
+
const initialExceptionValuesLength = Array.isArray(event?.exception?.values)
|
|
2859
|
+
? event.exception.values.length
|
|
2860
|
+
: undefined;
|
|
2861
|
+
const safeIncludes = (val, needle) => typeof val === 'string' && val.includes(needle);
|
|
2845
2862
|
// Check if the event is of type CloseEvent and ignore it
|
|
2846
2863
|
if (event?.exception?.values) {
|
|
2847
2864
|
event.exception.values = event.exception.values.filter(value => {
|
|
2848
2865
|
// Update the condition based on the actual structure of the event
|
|
2849
|
-
return !(value.type === 'CloseEvent' ||
|
|
2866
|
+
return !(value.type === 'CloseEvent' ||
|
|
2867
|
+
safeIncludes(value.value, 'CloseEvent'));
|
|
2850
2868
|
});
|
|
2851
2869
|
}
|
|
2852
2870
|
if (event?.exception?.values) {
|
|
2853
2871
|
event.exception.values = event.exception.values.filter(value => {
|
|
2854
2872
|
// Check for the specific error message and ignore it
|
|
2855
2873
|
return !(value.type === 'Error' &&
|
|
2856
|
-
value.value
|
|
2874
|
+
safeIncludes(value.value, 'ResizeObserver loop completed'));
|
|
2857
2875
|
});
|
|
2858
2876
|
}
|
|
2859
2877
|
// originates from vendor.js file
|
|
@@ -2870,21 +2888,21 @@ class SentryErrorHandler {
|
|
|
2870
2888
|
if (event?.exception?.values) {
|
|
2871
2889
|
event.exception.values = event.exception.values.filter(value => {
|
|
2872
2890
|
return !(value.type === 'ChunkLoadError' ||
|
|
2873
|
-
value.value
|
|
2891
|
+
safeIncludes(value.value, 'ChunkLoadError: Loading chunk'));
|
|
2874
2892
|
});
|
|
2875
2893
|
}
|
|
2876
2894
|
// Check if the event is a script loading error and ignore it
|
|
2877
2895
|
if (event?.exception?.values) {
|
|
2878
2896
|
event.exception.values = event.exception.values.filter(value => {
|
|
2879
2897
|
return !(value.type === 'Error' &&
|
|
2880
|
-
value.value
|
|
2898
|
+
safeIncludes(value.value, 'Could not load "util"'));
|
|
2881
2899
|
});
|
|
2882
2900
|
}
|
|
2883
2901
|
// Check if the event is a timeout error and ignore it
|
|
2884
2902
|
if (event?.exception?.values) {
|
|
2885
2903
|
event.exception.values = event.exception.values.filter(value => {
|
|
2886
2904
|
return !(value.type === 'Error' &&
|
|
2887
|
-
value.value
|
|
2905
|
+
safeIncludes(value.value, 'Error loading plotly.js library from'));
|
|
2888
2906
|
});
|
|
2889
2907
|
}
|
|
2890
2908
|
// Check if the event is related to cross-origin frame access
|
|
@@ -2898,16 +2916,6 @@ class SentryErrorHandler {
|
|
|
2898
2916
|
return null;
|
|
2899
2917
|
}
|
|
2900
2918
|
}
|
|
2901
|
-
// Check if the event has an exception and values array
|
|
2902
|
-
if (event?.exception?.values) {
|
|
2903
|
-
// Filter out events generated by TryCatch and GlobalHandlers
|
|
2904
|
-
event.exception.values = event.exception.values.filter(value => {
|
|
2905
|
-
const mechanism = value.mechanism;
|
|
2906
|
-
return !(mechanism &&
|
|
2907
|
-
(mechanism.type === 'TryCatch' ||
|
|
2908
|
-
mechanism.type === 'GlobalHandlers'));
|
|
2909
|
-
});
|
|
2910
|
-
}
|
|
2911
2919
|
// Check if it's a non-error exception
|
|
2912
2920
|
const isNonErrorException = event?.exception?.values?.[0]?.value?.startsWith('Non-Error exception captured') ??
|
|
2913
2921
|
hint?.originalException?.message?.startsWith('Non-Error exception captured');
|
|
@@ -2915,6 +2923,14 @@ class SentryErrorHandler {
|
|
|
2915
2923
|
// We want to ignore those kinds of errors
|
|
2916
2924
|
return null;
|
|
2917
2925
|
}
|
|
2926
|
+
// If we started with exception values but filtered them all out, drop the event.
|
|
2927
|
+
// Otherwise Sentry will group it as an "unlabeled event" and spam the issue stream.
|
|
2928
|
+
if (typeof initialExceptionValuesLength === 'number' &&
|
|
2929
|
+
initialExceptionValuesLength > 0 &&
|
|
2930
|
+
Array.isArray(event?.exception?.values) &&
|
|
2931
|
+
event.exception.values.length === 0) {
|
|
2932
|
+
return null;
|
|
2933
|
+
}
|
|
2918
2934
|
return event;
|
|
2919
2935
|
},
|
|
2920
2936
|
denyUrls: [/drift.*\.js/i, /analytics.*\.js/i, /polyfills.*\.js/i, /vendor.*\.js/i],
|