@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
- window.addEventListener('unhandledrejection', (event) => {
2825
- this.handlePromiseRejection(event);
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' || value.value.includes('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.includes('ResizeObserver loop completed'));
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.includes('ChunkLoadError: Loading chunk'));
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.includes('Could not load "util"'));
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.includes('Error loading plotly.js library from'));
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],