@posiwise/common-services 0.2.12 → 0.2.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.
@@ -8,7 +8,7 @@ import { DOCUMENT, CommonModule } from '@angular/common';
8
8
  import * as i1$2 from '@angular/common/http';
9
9
  import { HttpErrorResponse, HttpHeaders } from '@angular/common/http';
10
10
  import { throwError, of, BehaviorSubject, tap, timer } from 'rxjs';
11
- import { catchError, take, switchMap, map, mergeMap, tap as tap$1, distinctUntilChanged } from 'rxjs/operators';
11
+ import { catchError, take, tap as tap$1, switchMap, map, mergeMap, distinctUntilChanged } from 'rxjs/operators';
12
12
  import { HelperService } from '@posiwise/helper-service';
13
13
  import * as i1$1 from 'ngx-toastr';
14
14
  import { getUser, SetUser, UserActionTypes, appReducers } from '@posiwise/app-store';
@@ -1108,9 +1108,12 @@ class AuthService {
1108
1108
  phonegap: true
1109
1109
  };
1110
1110
  }
1111
- // Clear all tokens securely
1112
- this.secureTokenStorage.clearTokens().subscribe();
1113
- return this.http.delete('session', options);
1111
+ // Send DELETE request with token intact, then clear tokens after response
1112
+ // Use tap to clear tokens without changing the response stream
1113
+ return this.http.delete('session', options).pipe(tap$1(() => {
1114
+ // Clear tokens AFTER logout succeeds
1115
+ this.secureTokenStorage.clearTokens().subscribe();
1116
+ }));
1114
1117
  }
1115
1118
  /**
1116
1119
  * Clear all authentication tokens
@@ -1192,7 +1195,13 @@ class AuthService {
1192
1195
  return this.userService.getUserInfo();
1193
1196
  }));
1194
1197
  sequence$.subscribe(resp => {
1195
- localStorage.setItem('name', resp.first_name);
1198
+ // Store user information in localStorage for chat widgets and other services
1199
+ const firstName = resp.first_name || '';
1200
+ const email = resp.email || '';
1201
+ const userId = resp.id?.toString() || '';
1202
+ localStorage.setItem('name', firstName);
1203
+ localStorage.setItem('userEmail', email);
1204
+ localStorage.setItem('userId', userId);
1196
1205
  this.router.navigate(['home']);
1197
1206
  if ($('.cc-dismiss').length > 0) {
1198
1207
  $('.cc-dismiss')[0].click();
@@ -2917,95 +2926,7 @@ class SentryErrorHandler {
2917
2926
  // NOTE: We intentionally do not enable Performance Tracing here.
2918
2927
  // The previous integration (`BrowserTracing` + `routingInstrumentation`) was part of
2919
2928
  // the legacy `@sentry/angular-ivy` API and isn't available in `@sentry/angular` v10.
2920
- beforeSend(event, hint) {
2921
- const initialExceptionValuesLength = Array.isArray(event?.exception?.values)
2922
- ? event.exception.values.length
2923
- : undefined;
2924
- const safeIncludes = (val, needle) => typeof val === 'string' && val.includes(needle);
2925
- // Check if the event is of type CloseEvent and ignore it
2926
- if (event?.exception?.values) {
2927
- event.exception.values = event.exception.values.filter(value => {
2928
- // Update the condition based on the actual structure of the event
2929
- return !(value.type === 'CloseEvent' ||
2930
- safeIncludes(value.value, 'CloseEvent'));
2931
- });
2932
- }
2933
- if (event?.exception?.values) {
2934
- event.exception.values = event.exception.values.filter(value => {
2935
- // Check for the specific error message and ignore it
2936
- return !(value.type === 'Error' &&
2937
- safeIncludes(value.value, 'ResizeObserver loop completed'));
2938
- });
2939
- }
2940
- // originates from vendor.js file
2941
- if (event?.exception?.values) {
2942
- const isJsonParsingError = event.exception.values.some(value => {
2943
- return (value.type === 'SyntaxError' &&
2944
- value?.value?.includes("expected ':' after property name in"));
2945
- });
2946
- if (isJsonParsingError) {
2947
- return null;
2948
- }
2949
- }
2950
- // Check if the event is a ChunkLoadError and ignore it (it could be because of poor network)
2951
- if (event?.exception?.values) {
2952
- event.exception.values = event.exception.values.filter(value => {
2953
- return !(value.type === 'ChunkLoadError' ||
2954
- safeIncludes(value.value, 'ChunkLoadError: Loading chunk'));
2955
- });
2956
- }
2957
- // Check if the event is a script loading error and ignore it
2958
- if (event?.exception?.values) {
2959
- event.exception.values = event.exception.values.filter(value => {
2960
- return !(value.type === 'Error' &&
2961
- safeIncludes(value.value, 'Could not load "util"'));
2962
- });
2963
- }
2964
- // Check if the event is a timeout error and ignore it
2965
- if (event?.exception?.values) {
2966
- event.exception.values = event.exception.values.filter(value => {
2967
- return !(value.type === 'Error' &&
2968
- safeIncludes(value.value, 'Error loading plotly.js library from'));
2969
- });
2970
- }
2971
- // Check if the event is related to cross-origin frame access
2972
- if (event?.exception?.values) {
2973
- const isCrossOriginFrameError = event.exception.values.some(value => {
2974
- return (value.type === 'SecurityError' &&
2975
- value?.value?.includes("Failed to read a named property 'navigator' from 'Window': Blocked a frame with origin"));
2976
- });
2977
- if (isCrossOriginFrameError) {
2978
- // Exclude cross-origin frame errors from being reported to Sentry
2979
- return null;
2980
- }
2981
- }
2982
- // Check if it's a non-error exception
2983
- const isNonErrorException = event?.exception?.values?.[0]?.value?.startsWith('Non-Error exception captured') ??
2984
- hint?.originalException?.message?.startsWith('Non-Error exception captured');
2985
- if (isNonErrorException) {
2986
- // We want to ignore those kinds of errors
2987
- return null;
2988
- }
2989
- // Filter out Edge browser (145.0.0+) synthetic isTrusted events
2990
- // These events spam Sentry as "unlabeled events"
2991
- const isEdge = /Edg\//.test(navigator.userAgent);
2992
- if (isEdge && hint?.originalException) {
2993
- const originalException = hint.originalException;
2994
- if (originalException && typeof originalException === 'object' && originalException['isTrusted'] === true) {
2995
- // Block Edge synthetic browser events from being sent to Sentry
2996
- return null;
2997
- }
2998
- }
2999
- // If we started with exception values but filtered them all out, drop the event.
3000
- // Otherwise Sentry will group it as an "unlabeled event" and spam the issue stream.
3001
- if (typeof initialExceptionValuesLength === 'number' &&
3002
- initialExceptionValuesLength > 0 &&
3003
- Array.isArray(event?.exception?.values) &&
3004
- event.exception.values.length === 0) {
3005
- return null;
3006
- }
3007
- return event;
3008
- },
2929
+ beforeSend: (event, hint) => SentryErrorHandler.beforeSendFilter(event, hint),
3009
2930
  denyUrls: [/drift.*\.js/i, /analytics.*\.js/i, /polyfills.*\.js/i, /vendor.*\.js/i],
3010
2931
  environment,
3011
2932
  // We ignore Server Errors. We have to define here since Angular
@@ -3188,15 +3109,41 @@ class SentryErrorHandler {
3188
3109
  return 'string_error';
3189
3110
  }
3190
3111
  if (error && typeof error === 'object') {
3112
+ return this.classifyObjectError(error);
3113
+ }
3114
+ return 'unknown';
3115
+ }
3116
+ /**
3117
+ * Classifies object-type errors
3118
+ */
3119
+ classifyObjectError(error) {
3120
+ if (typeof error === 'object' && error !== null) {
3191
3121
  if ('isTrusted' in error) {
3192
3122
  return 'browser_event';
3193
3123
  }
3194
3124
  if ('type' in error) {
3195
- return `event_${error.type}`.toLowerCase();
3125
+ return this.classifyErrorByType(error);
3196
3126
  }
3197
- return 'object_error';
3198
3127
  }
3199
- return 'unknown';
3128
+ return 'object_error';
3129
+ }
3130
+ /**
3131
+ * Determines error type classification based on the 'type' property
3132
+ */
3133
+ classifyErrorByType(error) {
3134
+ const typedError = error;
3135
+ const rawType = typedError['type'];
3136
+ let errorType;
3137
+ if (typeof rawType === 'string') {
3138
+ errorType = rawType;
3139
+ }
3140
+ else if (rawType != null) {
3141
+ errorType = JSON.stringify(rawType);
3142
+ }
3143
+ else {
3144
+ errorType = 'unknown';
3145
+ }
3146
+ return `event_${errorType}`.toLowerCase();
3200
3147
  }
3201
3148
  isEdgeSyntheticEvent(error) {
3202
3149
  // Check if running in Edge browser
@@ -3256,6 +3203,102 @@ class SentryErrorHandler {
3256
3203
  const enhancedError = new Error(enhancedErrorMessage);
3257
3204
  captureException(enhancedError);
3258
3205
  }
3206
+ /**
3207
+ * Filters Sentry events before sending — extracted from beforeSend config
3208
+ * to reduce cognitive complexity (S3776).
3209
+ *
3210
+ * Drops or filters exception values for known noisy/irrelevant error types:
3211
+ * CloseEvent, ResizeObserver, JSON parsing, ChunkLoadError, script loading,
3212
+ * plotly timeout, cross-origin frame, non-error exceptions, and Edge synthetic events.
3213
+ */
3214
+ static beforeSendFilter(event, hint) {
3215
+ const initialExceptionValuesLength = Array.isArray(event?.exception?.values)
3216
+ ? event.exception.values.length
3217
+ : undefined;
3218
+ // Apply all exception-value filters in a single pass
3219
+ if (event?.exception?.values) {
3220
+ event.exception.values = SentryErrorHandler.filterExceptionValues(event.exception.values);
3221
+ }
3222
+ // Check for early-return (drop) conditions
3223
+ const dropReason = SentryErrorHandler.shouldDropEvent(event, hint);
3224
+ if (dropReason) {
3225
+ return null;
3226
+ }
3227
+ // If we started with exception values but filtered them all out, drop the event.
3228
+ if (typeof initialExceptionValuesLength === 'number' &&
3229
+ initialExceptionValuesLength > 0 &&
3230
+ Array.isArray(event?.exception?.values) &&
3231
+ event.exception.values.length === 0) {
3232
+ return null;
3233
+ }
3234
+ return event;
3235
+ }
3236
+ /**
3237
+ * Filters out known noisy exception values in a single pass.
3238
+ */
3239
+ static filterExceptionValues(values) {
3240
+ const safeIncludes = (val, needle) => typeof val === 'string' && val.includes(needle);
3241
+ return values.filter(value => {
3242
+ // CloseEvent
3243
+ if (value.type === 'CloseEvent' || safeIncludes(value.value, 'CloseEvent')) {
3244
+ return false;
3245
+ }
3246
+ // ResizeObserver loop completed
3247
+ if (value.type === 'Error' &&
3248
+ safeIncludes(value.value, 'ResizeObserver loop completed')) {
3249
+ return false;
3250
+ }
3251
+ // ChunkLoadError
3252
+ if (value.type === 'ChunkLoadError' ||
3253
+ safeIncludes(value.value, 'ChunkLoadError: Loading chunk')) {
3254
+ return false;
3255
+ }
3256
+ // Script loading error
3257
+ if (value.type === 'Error' && safeIncludes(value.value, 'Could not load "util"')) {
3258
+ return false;
3259
+ }
3260
+ // Plotly timeout error
3261
+ if (value.type === 'Error' &&
3262
+ safeIncludes(value.value, 'Error loading plotly.js library from')) {
3263
+ return false;
3264
+ }
3265
+ return true;
3266
+ });
3267
+ }
3268
+ /**
3269
+ * Determines whether the entire event should be dropped (return truthy to drop).
3270
+ */
3271
+ static shouldDropEvent(event, hint) {
3272
+ // JSON parsing error from vendor.js
3273
+ const hasJsonParsingError = event?.exception?.values?.some(value => value.type === 'SyntaxError' &&
3274
+ value?.value?.includes("expected ':' after property name in"));
3275
+ if (hasJsonParsingError) {
3276
+ return true;
3277
+ }
3278
+ // Cross-origin frame access error
3279
+ const hasCrossOriginError = event?.exception?.values?.some(value => value.type === 'SecurityError' &&
3280
+ value?.value?.includes("Failed to read a named property 'navigator' from 'Window': Blocked a frame with origin"));
3281
+ if (hasCrossOriginError) {
3282
+ return true;
3283
+ }
3284
+ // Non-error exception
3285
+ const isNonErrorException = event?.exception?.values?.[0]?.value?.startsWith('Non-Error exception captured') ??
3286
+ hint?.originalException?.message?.startsWith('Non-Error exception captured');
3287
+ if (isNonErrorException) {
3288
+ return true;
3289
+ }
3290
+ // Edge browser synthetic isTrusted events
3291
+ const isEdge = /Edg\//.test(navigator.userAgent);
3292
+ if (isEdge && hint?.originalException) {
3293
+ const originalException = hint.originalException;
3294
+ if (originalException &&
3295
+ typeof originalException === 'object' &&
3296
+ originalException['isTrusted'] === true) {
3297
+ return true;
3298
+ }
3299
+ }
3300
+ return false;
3301
+ }
3259
3302
  logToConsole(error) {
3260
3303
  // Attempt to print in the console
3261
3304
  try {