@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,
|
|
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
|
-
//
|
|
1112
|
-
|
|
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
|
|
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
|
|
3125
|
+
return this.classifyErrorByType(error);
|
|
3196
3126
|
}
|
|
3197
|
-
return 'object_error';
|
|
3198
3127
|
}
|
|
3199
|
-
return '
|
|
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 {
|