@rudderstack/analytics-js 3.26.0 → 3.28.0
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/CHANGELOG.md +19 -0
- package/dist/npm/legacy/bundled/cjs/index.cjs +24 -19
- package/dist/npm/legacy/bundled/esm/index.mjs +24 -19
- package/dist/npm/legacy/bundled/umd/index.js +24 -19
- package/dist/npm/legacy/cjs/index.cjs +24 -19
- package/dist/npm/legacy/content-script/cjs/index.cjs +24 -19
- package/dist/npm/legacy/content-script/esm/index.mjs +24 -19
- package/dist/npm/legacy/content-script/umd/index.js +24 -19
- package/dist/npm/legacy/esm/index.mjs +24 -19
- package/dist/npm/legacy/umd/index.js +24 -19
- package/dist/npm/modern/bundled/cjs/index.cjs +23 -18
- package/dist/npm/modern/bundled/esm/index.mjs +23 -18
- package/dist/npm/modern/bundled/umd/index.js +23 -18
- package/dist/npm/modern/cjs/index.cjs +22 -17
- package/dist/npm/modern/content-script/cjs/index.cjs +23 -18
- package/dist/npm/modern/content-script/esm/index.mjs +23 -18
- package/dist/npm/modern/content-script/umd/index.js +23 -18
- package/dist/npm/modern/esm/index.mjs +22 -17
- package/dist/npm/modern/umd/index.js +22 -17
- package/package.json +1 -1
|
@@ -914,7 +914,7 @@
|
|
|
914
914
|
error.stacktrace="".concat(stacktrace,"\n").concat(MANUAL_ERROR_IDENTIFIER);break;case operaSourceloc:default:// eslint-disable-next-line no-param-reassign
|
|
915
915
|
error['opera#sourceloc']="".concat(operaSourceloc,"\n").concat(MANUAL_ERROR_IDENTIFIER);break;}}}globalThis.dispatchEvent(new ErrorEvent('error',{error:error,bubbles:true,cancelable:true,composed:true}));};
|
|
916
916
|
|
|
917
|
-
var APP_NAME='RudderLabs JavaScript SDK';var APP_VERSION='3.
|
|
917
|
+
var APP_NAME='RudderLabs JavaScript SDK';var APP_VERSION='3.28.0';var APP_NAMESPACE='com.rudderlabs.javascript';var MODULE_TYPE='npm';var ADBLOCK_PAGE_CATEGORY='RudderJS-Initiated';var ADBLOCK_PAGE_NAME='ad-block page request';var ADBLOCK_PAGE_PATH='/ad-blocked';var GLOBAL_PRELOAD_BUFFER='preloadedEventsBuffer';var CONSENT_TRACK_EVENT_NAME='Consent Management Interaction';
|
|
918
918
|
|
|
919
919
|
var QUERY_PARAM_TRAIT_PREFIX='ajs_trait_';var QUERY_PARAM_PROPERTY_PREFIX='ajs_prop_';var QUERY_PARAM_ANONYMOUS_ID_KEY='ajs_aid';var QUERY_PARAM_USER_ID_KEY='ajs_uid';var QUERY_PARAM_TRACK_EVENT_NAME_KEY='ajs_event';
|
|
920
920
|
|
|
@@ -1137,7 +1137,7 @@
|
|
|
1137
1137
|
* Utility to parse XHR JSON response
|
|
1138
1138
|
*/var responseTextToJson=function responseTextToJson(responseText,onError){try{return JSON.parse(responseText||'');}catch(err){var error=getMutatedError(err,'Failed to parse response data');onError(error);}return undefined;};
|
|
1139
1139
|
|
|
1140
|
-
var FAILED_REQUEST_ERR_MSG_PREFIX='The request failed';var PLUGINS_LOAD_FAILURE_MESSAGES=[/Failed to fetch dynamically imported module: .*/];var INTEGRATIONS_LOAD_FAILURE_MESSAGES=[/Unable to load \(.*\) the script with the id .*/,/A timeout of \d+ ms occurred while trying to load the script with id .*/];var ERROR_MESSAGES_TO_BE_FILTERED=[new RegExp("".concat(FAILED_REQUEST_ERR_MSG_PREFIX,".*")),/A script with the id .* is already loaded\./];var SCRIPT_LOAD_FAILURE_MESSAGES=[].concat(PLUGINS_LOAD_FAILURE_MESSAGES,INTEGRATIONS_LOAD_FAILURE_MESSAGES);
|
|
1140
|
+
var FAILED_REQUEST_ERR_MSG_PREFIX='The request failed';var PLUGINS_LOAD_FAILURE_MESSAGES=[/Failed to fetch dynamically imported module: .*/];var INTEGRATIONS_LOAD_FAILURE_MESSAGES=[/Unable to load \(.*\) the script with the id .*/,/A timeout of \d+ ms occurred while trying to load the script with id .*/];var ERROR_MESSAGES_TO_BE_FILTERED=[new RegExp("".concat(FAILED_REQUEST_ERR_MSG_PREFIX,".*")),/A script with the id .* is already loaded\./];var SCRIPT_LOAD_FAILURE_MESSAGES=[].concat(PLUGINS_LOAD_FAILURE_MESSAGES,INTEGRATIONS_LOAD_FAILURE_MESSAGES);var INTEGRATIONS_ERROR_CATEGORY='integrations';var SDK_ERROR_CATEGORY='sdk';var DEFAULT_ERROR_CATEGORY=SDK_ERROR_CATEGORY;
|
|
1141
1141
|
|
|
1142
1142
|
var DEFAULT_XHR_REQUEST_OPTIONS={headers:{Accept:'application/json','Content-Type':'application/json;charset=UTF-8'},method:'GET'};/**
|
|
1143
1143
|
* Utility to create request configuration based on default options
|
|
@@ -1173,7 +1173,7 @@
|
|
|
1173
1173
|
// Potential PII or sensitive data
|
|
1174
1174
|
var APP_STATE_EXCLUDE_KEYS=['userId','userTraits','groupId','groupTraits','anonymousId','config','integration',// integration instance objects
|
|
1175
1175
|
'eventBuffer',// pre-load event buffer (may contain PII)
|
|
1176
|
-
'traits','authToken'];var NOTIFIER_NAME='RudderStack JavaScript SDK';var SDK_GITHUB_URL='git+https://github.com/rudderlabs/rudder-sdk-js.git';var SOURCE_NAME='js';
|
|
1176
|
+
'traits','authToken'];var NOTIFIER_NAME='RudderStack JavaScript SDK';var SDK_GITHUB_URL='git+https://github.com/rudderlabs/rudder-sdk-js.git';var SOURCE_NAME='js';
|
|
1177
1177
|
|
|
1178
1178
|
var detectAdBlockers=function detectAdBlockers(httpClient){state.capabilities.isAdBlockerDetectionInProgress.value=true;try{// Apparently, '?view=ad' is a query param that is blocked by majority of adblockers
|
|
1179
1179
|
// Use source config URL here as it is very unlikely to be blocked by adblockers
|
|
@@ -1217,23 +1217,27 @@
|
|
|
1217
1217
|
checkIfAdBlockersAreActive(state,httpClient,resolve);}}else {// Filter out errors that are not from the RS CDN.
|
|
1218
1218
|
resolve(false);}}else {// Allow the error to be notified if no URL could be extracted from the error message
|
|
1219
1219
|
resolve(true);}}else {resolve(!ERROR_MESSAGES_TO_BE_FILTERED.some(function(e){return e.test(errMsg);}));}});};/**
|
|
1220
|
+
* A function to get the directory name from a file path.
|
|
1221
|
+
* @param {string} filePath The file path
|
|
1222
|
+
* @returns The directory name or undefined if the file path is invalid
|
|
1223
|
+
*/var getDirectoryName=function getDirectoryName(filePath){if(!filePath){return undefined;}var paths=filePath.split('/');return paths.at(-2);};/**
|
|
1224
|
+
* A function to get the top stack path from the exception.
|
|
1225
|
+
* @param {Exception} exception The exception object
|
|
1226
|
+
* @returns The top stack path or undefined if the exception is invalid
|
|
1227
|
+
*/var getTopStackPath=function getTopStackPath(exception){var _exception$stacktrace;var errorOrigin=(_exception$stacktrace=exception.stacktrace[0])===null||_exception$stacktrace===void 0?void 0:_exception$stacktrace.file;if(!errorOrigin||typeof errorOrigin!=='string'){return undefined;}return errorOrigin;};/**
|
|
1220
1228
|
* A function to determine if the error is from Rudder SDK
|
|
1221
1229
|
* @param {Error} exception
|
|
1222
1230
|
* @returns
|
|
1223
|
-
*/var isSDKError=function isSDKError(exception){var
|
|
1224
|
-
// Ex: parentFolderName will be 'sample' for url: https://example.com/sample/file.min.js
|
|
1225
|
-
var parentFolderName=paths[paths.length-2];return parentFolderName===CDN_INT_DIR||SDK_FILE_NAME_PREFIXES().some(function(prefix){return srcFileName.startsWith(prefix)&&srcFileName.endsWith('.js');});};var getErrorDeliveryPayload=function getErrorDeliveryPayload(payload,state,category){var data={version:METRICS_PAYLOAD_VERSION,message_id:generateUUID(),source:{name:SOURCE_NAME,sdk_version:state.context.app.value.version,write_key:state.lifecycle.writeKey.value,install_type:state.context.app.value.installType,category:category!==null&&category!==void 0?category:DEFAULT_ERROR_CATEGORY},errors:payload};return stringifyWithoutCircular(data);};/**
|
|
1231
|
+
*/var isSDKError=function isSDKError(exception){var errorOrigin=getTopStackPath(exception);if(!errorOrigin){return false;}var srcFileName=errorOrigin.substring(errorOrigin.lastIndexOf('/')+1);var parentFolderName=getDirectoryName(errorOrigin);return parentFolderName===CDN_INT_DIR||SDK_FILE_NAME_PREFIXES().some(function(prefix){return srcFileName.startsWith(prefix)&&srcFileName.endsWith('.js');});};var getErrorCategory=function getErrorCategory(exception,category){if(category){return category;}var errorOrigin=getTopStackPath(exception);var directoryName=getDirectoryName(errorOrigin);if(directoryName===CDN_INT_DIR){return INTEGRATIONS_ERROR_CATEGORY;}return DEFAULT_ERROR_CATEGORY;};var getErrorDeliveryPayload=function getErrorDeliveryPayload(payload,state,category){var data={version:METRICS_PAYLOAD_VERSION,message_id:generateUUID(),source:{name:SOURCE_NAME,sdk_version:state.context.app.value.version,write_key:state.lifecycle.writeKey.value,install_type:state.context.app.value.installType,category:category},errors:payload};return stringifyWithoutCircular(data);};/**
|
|
1226
1232
|
* A function to get the grouping hash value to be used for the error event.
|
|
1227
|
-
* Grouping hash is suppressed for non-cdn installs.
|
|
1228
1233
|
* If the grouping hash is an error instance, the normalized error message is used as the grouping hash.
|
|
1229
1234
|
* If the grouping hash is an empty string or not specified, the default grouping hash is used.
|
|
1230
1235
|
* If the grouping hash is a string, it is used as is.
|
|
1231
1236
|
* @param curErrGroupingHash The grouping hash value part of the error event
|
|
1232
1237
|
* @param defaultGroupingHash The default grouping hash value. It is the error message.
|
|
1233
|
-
* @param state The application state
|
|
1234
1238
|
* @param logger The logger instance
|
|
1235
1239
|
* @returns The final grouping hash value to be used for the error event
|
|
1236
|
-
*/var getErrorGroupingHash=function getErrorGroupingHash(curErrGroupingHash,defaultGroupingHash,
|
|
1240
|
+
*/var getErrorGroupingHash=function getErrorGroupingHash(curErrGroupingHash,defaultGroupingHash,logger){var normalizedGroupingHash;if(!isDefined(curErrGroupingHash)){normalizedGroupingHash=defaultGroupingHash;}else if(isString(curErrGroupingHash)){normalizedGroupingHash=curErrGroupingHash;}else {var normalizedErrorInstance=normalizeError(curErrGroupingHash,logger);if(isDefined(normalizedErrorInstance)){normalizedGroupingHash=normalizedErrorInstance.message;}else {normalizedGroupingHash=defaultGroupingHash;}}return normalizedGroupingHash;};
|
|
1237
1241
|
|
|
1238
1242
|
/**
|
|
1239
1243
|
* A service to handle errors
|
|
@@ -1254,18 +1258,18 @@
|
|
|
1254
1258
|
* @param errorInfo.errorType - The type of the error (handled or unhandled)
|
|
1255
1259
|
* @param errorInfo.groupingHash - The grouping hash of the error
|
|
1256
1260
|
* @param errorInfo.category - The category of the error (sdk or integrations)
|
|
1257
|
-
*/},{key:"onError",value:(function(){var _onError=_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(errorInfo){var _errorInfo$errorType,error,context,customMessage,groupingHash,category,errorType,errInstance,normalizedError,customMsgVal,errorMsgPrefix,bsException,stacktrace,isSdkDispatched,isAllowed,errorState,normalizedGroupingHash,bugsnagPayload,_t;return _regenerator().w(function(_context){while(1)switch(_context.p=_context.n){case 0:_context.p=0;error=errorInfo.error,context=errorInfo.context,customMessage=errorInfo.customMessage,groupingHash=errorInfo.groupingHash,category=errorInfo.category;errorType=(_errorInfo$errorType=errorInfo.errorType)!==null&&_errorInfo$errorType!==void 0?_errorInfo$errorType:ErrorType.HANDLEDEXCEPTION;errInstance=getErrInstance(error,errorType);normalizedError=normalizeError(errInstance,this.logger);if(!isUndefined(normalizedError)){_context.n=1;break;}return _context.a(2);case 1:customMsgVal=customMessage?"".concat(customMessage," - "):'';errorMsgPrefix="".concat(context).concat(LOG_CONTEXT_SEPARATOR).concat(customMsgVal);bsException=createBugsnagException(normalizedError,errorMsgPrefix);stacktrace=getStacktrace(normalizedError);isSdkDispatched=stacktrace.includes(MANUAL_ERROR_IDENTIFIER);// Filter errors that are not originated in the SDK.
|
|
1261
|
+
*/},{key:"onError",value:(function(){var _onError=_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(errorInfo){var _errorInfo$errorType,error,context,customMessage,groupingHash,category,errorType,errInstance,normalizedError,customMsgVal,errorMsgPrefix,bsException,stacktrace,isSdkDispatched,isAllowed,errorState,normalizedGroupingHash,bugsnagPayload,errorCategory,_t;return _regenerator().w(function(_context){while(1)switch(_context.p=_context.n){case 0:_context.p=0;error=errorInfo.error,context=errorInfo.context,customMessage=errorInfo.customMessage,groupingHash=errorInfo.groupingHash,category=errorInfo.category;errorType=(_errorInfo$errorType=errorInfo.errorType)!==null&&_errorInfo$errorType!==void 0?_errorInfo$errorType:ErrorType.HANDLEDEXCEPTION;errInstance=getErrInstance(error,errorType);normalizedError=normalizeError(errInstance,this.logger);if(!isUndefined(normalizedError)){_context.n=1;break;}return _context.a(2);case 1:customMsgVal=customMessage?"".concat(customMessage," - "):'';errorMsgPrefix="".concat(context).concat(LOG_CONTEXT_SEPARATOR).concat(customMsgVal);bsException=createBugsnagException(normalizedError,errorMsgPrefix);stacktrace=getStacktrace(normalizedError);isSdkDispatched=stacktrace.includes(MANUAL_ERROR_IDENTIFIER);// Filter errors that are not originated in the SDK.
|
|
1258
1262
|
// In case of NPM installations, the unhandled errors from the SDK cannot be identified
|
|
1259
1263
|
// and will NOT be reported unless they occur in plugins or integrations.
|
|
1260
|
-
if(!(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCEPTION)){_context.n=2;break;}return _context.a(2);case 2:if(!state.reporting.isErrorReportingEnabled.value){_context.n=4;break;}_context.n=3;return checkIfAllowedToBeNotified(bsException,state,this.httpClient);case 3:isAllowed=_context.v;if(isAllowed){errorState={severity:'error',unhandled:errorType!==ErrorType.HANDLEDEXCEPTION,severityReason:{type:errorType}};//
|
|
1261
|
-
//
|
|
1262
|
-
//
|
|
1264
|
+
if(!(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCEPTION)){_context.n=2;break;}return _context.a(2);case 2:if(!state.reporting.isErrorReportingEnabled.value){_context.n=4;break;}_context.n=3;return checkIfAllowedToBeNotified(bsException,state,this.httpClient);case 3:isAllowed=_context.v;if(isAllowed){errorState={severity:'error',unhandled:errorType!==ErrorType.HANDLEDEXCEPTION,severityReason:{type:errorType}};// This will allow custom grouping of errors.
|
|
1265
|
+
// In case of NPM installations, the default grouping by surrounding code
|
|
1266
|
+
// does not make sense as each user application is different and will create a lot of noise in the alerts.
|
|
1263
1267
|
// References:
|
|
1264
1268
|
// https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash
|
|
1265
1269
|
// https://docs.bugsnag.com/product/error-grouping/#user_defined
|
|
1266
|
-
normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,
|
|
1267
|
-
bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);// send it to metrics service
|
|
1268
|
-
this.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state,
|
|
1270
|
+
normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,this.logger);// Get the final payload to be sent to the metrics service
|
|
1271
|
+
bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);errorCategory=getErrorCategory(bsException,category);// send it to metrics service
|
|
1272
|
+
this.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state,errorCategory),sendRawData:true},isRawResponse:true});}case 4:// Log handled errors and errors dispatched by the SDK
|
|
1269
1273
|
if(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}_context.n=6;break;case 5:_context.p=5;_t=_context.v;// If an error occurs while handling an error, log it
|
|
1270
1274
|
this.logger.error(HANDLE_ERROR_FAILURE(ERROR_HANDLER),_t);case 6:return _context.a(2);}},_callee,this,[[0,5]]);}));function onError(_x){return _onError.apply(this,arguments);}return onError;}()/**
|
|
1271
1275
|
* Add breadcrumbs to add insight of a user's journey before an error
|
|
@@ -1351,7 +1355,7 @@
|
|
|
1351
1355
|
var encryptBrowser=function encryptBrowser(value){return "".concat(ENCRYPTION_PREFIX_V3).concat(toBase64(value));};var decryptBrowser=function decryptBrowser(value){if(value!==null&&value!==void 0&&value.startsWith(ENCRYPTION_PREFIX_V3)){return fromBase64(value.substring(ENCRYPTION_PREFIX_V3.length));}return value;};
|
|
1352
1356
|
|
|
1353
1357
|
var EVENT_PAYLOAD_SIZE_BYTES_LIMIT=32*1024;// 32 KB
|
|
1354
|
-
var RETRY_REASON_CLIENT_NETWORK='client-network';var RETRY_REASON_CLIENT_TIMEOUT='client-timeout';var DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;
|
|
1358
|
+
var RETRY_REASON_CLIENT_NETWORK='client-network';var RETRY_REASON_CLIENT_TIMEOUT='client-timeout';var DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;
|
|
1355
1359
|
|
|
1356
1360
|
var isStorageQuotaExceeded=function isStorageQuotaExceeded(e){var matchingNames=['QuotaExceededError','NS_ERROR_DOM_QUOTA_REACHED'];// Everything except Firefox, Firefox
|
|
1357
1361
|
var matchingCodes=[22,1014];if(e instanceof DOMException){return matchingNames.includes(e.name)||matchingCodes.includes(e.code);}return false;};// TODO: also check for SecurityErrors
|
|
@@ -3305,7 +3309,8 @@
|
|
|
3305
3309
|
this.set(key,value);}else {var customMessage=STORE_DATA_SAVE_ERROR(key);this.onError(err,customMessage,customMessage);}}}/**
|
|
3306
3310
|
* Get by Key.
|
|
3307
3311
|
*/},{key:"get",value:function get(key){var validKey=this.createValidKey(key);var decryptedValue;try{if(!validKey){return null;}decryptedValue=this.decrypt(this.engine.getItem(validKey));if(isNullOrUndefined(decryptedValue)||decryptedValue===''){return null;}// storejs that is used in localstorage engine already deserializes json strings but swallows errors
|
|
3308
|
-
return JSON.parse(decryptedValue);}catch(err){var
|
|
3312
|
+
return JSON.parse(decryptedValue);}catch(err){var encryptionPluginName=state.storage.encryptionPluginName.value;// Skip error reporting only when the encryption plugin is configured but failed to load
|
|
3313
|
+
var shouldReportError=!encryptionPluginName||!state.plugins.failedPlugins.value.includes(encryptionPluginName);if(shouldReportError){var customMessage=STORE_DATA_FETCH_ERROR(key);this.onError(err,customMessage,customMessage);}return null;}}/**
|
|
3309
3314
|
* Remove by Key.
|
|
3310
3315
|
*/},{key:"remove",value:function remove(key){var validKey=this.createValidKey(key);if(validKey){this.engine.removeItem(validKey);}}/**
|
|
3311
3316
|
* Get original engine
|
|
@@ -3989,7 +3994,7 @@
|
|
|
3989
3994
|
*/// eslint-disable-next-line class-methods-use-this
|
|
3990
3995
|
},{key:"onDestinationsReady",value:function onDestinationsReady(){// May be do any destination specific actions here
|
|
3991
3996
|
// Mark the ready status if not already done
|
|
3992
|
-
if(state.lifecycle.status.value!=='ready'){state.lifecycle.status.value='ready';}}// End lifecycle methods
|
|
3997
|
+
if(state.lifecycle.status.value!=='ready'){r(function(){state.lifecycle.status.value='ready';});}}// End lifecycle methods
|
|
3993
3998
|
// Start consumer exposed methods
|
|
3994
3999
|
},{key:"ready",value:function ready(callback){var type='ready';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[].concat(_toConsumableArray(state.eventBuffer.toBeProcessedArray.value),[[type,callback]]);return;}this.errorHandler.leaveBreadcrumb("New ".concat(type," invocation"));if(!isFunction(callback)){this.logger.error(INVALID_CALLBACK_FN_ERROR(READY_API));return;}/**
|
|
3995
4000
|
* If destinations are loaded or no integration is available for loading
|
|
@@ -519,7 +519,7 @@ error.stack=`${stack}\n${MANUAL_ERROR_IDENTIFIER}`;break;case stacktrace:// esli
|
|
|
519
519
|
error.stacktrace=`${stacktrace}\n${MANUAL_ERROR_IDENTIFIER}`;break;case operaSourceloc:default:// eslint-disable-next-line no-param-reassign
|
|
520
520
|
error['opera#sourceloc']=`${operaSourceloc}\n${MANUAL_ERROR_IDENTIFIER}`;break;}}}globalThis.dispatchEvent(new ErrorEvent('error',{error,bubbles:true,cancelable:true,composed:true}));};
|
|
521
521
|
|
|
522
|
-
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.
|
|
522
|
+
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.28.0';const APP_NAMESPACE='com.rudderlabs.javascript';const MODULE_TYPE='npm';const ADBLOCK_PAGE_CATEGORY='RudderJS-Initiated';const ADBLOCK_PAGE_NAME='ad-block page request';const ADBLOCK_PAGE_PATH='/ad-blocked';const GLOBAL_PRELOAD_BUFFER='preloadedEventsBuffer';const CONSENT_TRACK_EVENT_NAME='Consent Management Interaction';
|
|
523
523
|
|
|
524
524
|
const QUERY_PARAM_TRAIT_PREFIX='ajs_trait_';const QUERY_PARAM_PROPERTY_PREFIX='ajs_prop_';const QUERY_PARAM_ANONYMOUS_ID_KEY='ajs_aid';const QUERY_PARAM_USER_ID_KEY='ajs_uid';const QUERY_PARAM_TRACK_EVENT_NAME_KEY='ajs_event';
|
|
525
525
|
|
|
@@ -742,7 +742,7 @@ try{if(JSON.stringify(f)==='{}')return accum;return accum.concat(f);}catch{retur
|
|
|
742
742
|
* Utility to parse XHR JSON response
|
|
743
743
|
*/const responseTextToJson=(responseText,onError)=>{try{return JSON.parse(responseText||'');}catch(err){const error=getMutatedError(err,'Failed to parse response data');onError(error);}return undefined;};
|
|
744
744
|
|
|
745
|
-
const FAILED_REQUEST_ERR_MSG_PREFIX='The request failed';const PLUGINS_LOAD_FAILURE_MESSAGES=[/Failed to fetch dynamically imported module: .*/];const INTEGRATIONS_LOAD_FAILURE_MESSAGES=[/Unable to load \(.*\) the script with the id .*/,/A timeout of \d+ ms occurred while trying to load the script with id .*/];const ERROR_MESSAGES_TO_BE_FILTERED=[new RegExp(`${FAILED_REQUEST_ERR_MSG_PREFIX}.*`),/A script with the id .* is already loaded\./];const SCRIPT_LOAD_FAILURE_MESSAGES=[...PLUGINS_LOAD_FAILURE_MESSAGES,...INTEGRATIONS_LOAD_FAILURE_MESSAGES];
|
|
745
|
+
const FAILED_REQUEST_ERR_MSG_PREFIX='The request failed';const PLUGINS_LOAD_FAILURE_MESSAGES=[/Failed to fetch dynamically imported module: .*/];const INTEGRATIONS_LOAD_FAILURE_MESSAGES=[/Unable to load \(.*\) the script with the id .*/,/A timeout of \d+ ms occurred while trying to load the script with id .*/];const ERROR_MESSAGES_TO_BE_FILTERED=[new RegExp(`${FAILED_REQUEST_ERR_MSG_PREFIX}.*`),/A script with the id .* is already loaded\./];const SCRIPT_LOAD_FAILURE_MESSAGES=[...PLUGINS_LOAD_FAILURE_MESSAGES,...INTEGRATIONS_LOAD_FAILURE_MESSAGES];const INTEGRATIONS_ERROR_CATEGORY='integrations';const SDK_ERROR_CATEGORY='sdk';const DEFAULT_ERROR_CATEGORY=SDK_ERROR_CATEGORY;
|
|
746
746
|
|
|
747
747
|
const DEFAULT_XHR_REQUEST_OPTIONS={headers:{Accept:'application/json','Content-Type':'application/json;charset=UTF-8'},method:'GET'};/**
|
|
748
748
|
* Utility to create request configuration based on default options
|
|
@@ -778,7 +778,7 @@ const SDK_FILE_NAME_PREFIXES=()=>['rsa'// Prefix for all the SDK scripts includi
|
|
|
778
778
|
// Potential PII or sensitive data
|
|
779
779
|
const APP_STATE_EXCLUDE_KEYS=['userId','userTraits','groupId','groupTraits','anonymousId','config','integration',// integration instance objects
|
|
780
780
|
'eventBuffer',// pre-load event buffer (may contain PII)
|
|
781
|
-
'traits','authToken'];const NOTIFIER_NAME='RudderStack JavaScript SDK';const SDK_GITHUB_URL='git+https://github.com/rudderlabs/rudder-sdk-js.git';const SOURCE_NAME='js';
|
|
781
|
+
'traits','authToken'];const NOTIFIER_NAME='RudderStack JavaScript SDK';const SDK_GITHUB_URL='git+https://github.com/rudderlabs/rudder-sdk-js.git';const SOURCE_NAME='js';
|
|
782
782
|
|
|
783
783
|
const detectAdBlockers=httpClient=>{state.capabilities.isAdBlockerDetectionInProgress.value=true;try{// Apparently, '?view=ad' is a query param that is blocked by majority of adblockers
|
|
784
784
|
// Use source config URL here as it is very unlikely to be blocked by adblockers
|
|
@@ -824,23 +824,27 @@ if(state.capabilities.cspBlockedURLs.value.includes(extractedURL)){resolve(false
|
|
|
824
824
|
checkIfAdBlockersAreActive(state,httpClient,resolve);}}else {// Filter out errors that are not from the RS CDN.
|
|
825
825
|
resolve(false);}}else {// Allow the error to be notified if no URL could be extracted from the error message
|
|
826
826
|
resolve(true);}}else {resolve(!ERROR_MESSAGES_TO_BE_FILTERED.some(e=>e.test(errMsg)));}});};/**
|
|
827
|
+
* A function to get the directory name from a file path.
|
|
828
|
+
* @param {string} filePath The file path
|
|
829
|
+
* @returns The directory name or undefined if the file path is invalid
|
|
830
|
+
*/const getDirectoryName=filePath=>{if(!filePath){return undefined;}const paths=filePath.split('/');return paths.at(-2);};/**
|
|
831
|
+
* A function to get the top stack path from the exception.
|
|
832
|
+
* @param {Exception} exception The exception object
|
|
833
|
+
* @returns The top stack path or undefined if the exception is invalid
|
|
834
|
+
*/const getTopStackPath=exception=>{const errorOrigin=exception.stacktrace[0]?.file;if(!errorOrigin||typeof errorOrigin!=='string'){return undefined;}return errorOrigin;};/**
|
|
827
835
|
* A function to determine if the error is from Rudder SDK
|
|
828
836
|
* @param {Error} exception
|
|
829
837
|
* @returns
|
|
830
|
-
*/const isSDKError=exception=>{const errorOrigin=exception
|
|
831
|
-
// Ex: parentFolderName will be 'sample' for url: https://example.com/sample/file.min.js
|
|
832
|
-
const parentFolderName=paths[paths.length-2];return parentFolderName===CDN_INT_DIR||SDK_FILE_NAME_PREFIXES().some(prefix=>srcFileName.startsWith(prefix)&&srcFileName.endsWith('.js'));};const getErrorDeliveryPayload=(payload,state,category)=>{const data={version:METRICS_PAYLOAD_VERSION,message_id:generateUUID(),source:{name:SOURCE_NAME,sdk_version:state.context.app.value.version,write_key:state.lifecycle.writeKey.value,install_type:state.context.app.value.installType,category:category??DEFAULT_ERROR_CATEGORY},errors:payload};return stringifyWithoutCircular(data);};/**
|
|
838
|
+
*/const isSDKError=exception=>{const errorOrigin=getTopStackPath(exception);if(!errorOrigin){return false;}const srcFileName=errorOrigin.substring(errorOrigin.lastIndexOf('/')+1);const parentFolderName=getDirectoryName(errorOrigin);return parentFolderName===CDN_INT_DIR||SDK_FILE_NAME_PREFIXES().some(prefix=>srcFileName.startsWith(prefix)&&srcFileName.endsWith('.js'));};const getErrorCategory=(exception,category)=>{if(category){return category;}const errorOrigin=getTopStackPath(exception);const directoryName=getDirectoryName(errorOrigin);if(directoryName===CDN_INT_DIR){return INTEGRATIONS_ERROR_CATEGORY;}return DEFAULT_ERROR_CATEGORY;};const getErrorDeliveryPayload=(payload,state,category)=>{const data={version:METRICS_PAYLOAD_VERSION,message_id:generateUUID(),source:{name:SOURCE_NAME,sdk_version:state.context.app.value.version,write_key:state.lifecycle.writeKey.value,install_type:state.context.app.value.installType,category},errors:payload};return stringifyWithoutCircular(data);};/**
|
|
833
839
|
* A function to get the grouping hash value to be used for the error event.
|
|
834
|
-
* Grouping hash is suppressed for non-cdn installs.
|
|
835
840
|
* If the grouping hash is an error instance, the normalized error message is used as the grouping hash.
|
|
836
841
|
* If the grouping hash is an empty string or not specified, the default grouping hash is used.
|
|
837
842
|
* If the grouping hash is a string, it is used as is.
|
|
838
843
|
* @param curErrGroupingHash The grouping hash value part of the error event
|
|
839
844
|
* @param defaultGroupingHash The default grouping hash value. It is the error message.
|
|
840
|
-
* @param state The application state
|
|
841
845
|
* @param logger The logger instance
|
|
842
846
|
* @returns The final grouping hash value to be used for the error event
|
|
843
|
-
*/const getErrorGroupingHash=(curErrGroupingHash,defaultGroupingHash,
|
|
847
|
+
*/const getErrorGroupingHash=(curErrGroupingHash,defaultGroupingHash,logger)=>{let normalizedGroupingHash;if(!isDefined(curErrGroupingHash)){normalizedGroupingHash=defaultGroupingHash;}else if(isString(curErrGroupingHash)){normalizedGroupingHash=curErrGroupingHash;}else {const normalizedErrorInstance=normalizeError(curErrGroupingHash,logger);if(isDefined(normalizedErrorInstance)){normalizedGroupingHash=normalizedErrorInstance.message;}else {normalizedGroupingHash=defaultGroupingHash;}}return normalizedGroupingHash;};
|
|
844
848
|
|
|
845
849
|
/**
|
|
846
850
|
* A service to handle errors
|
|
@@ -864,15 +868,15 @@ document.addEventListener('securitypolicyviolation',event=>{const blockedURL=isS
|
|
|
864
868
|
*/async onError(errorInfo){try{const{error,context,customMessage,groupingHash,category}=errorInfo;const errorType=errorInfo.errorType??ErrorType.HANDLEDEXCEPTION;const errInstance=getErrInstance(error,errorType);const normalizedError=normalizeError(errInstance,this.logger);if(isUndefined(normalizedError)){return;}const customMsgVal=customMessage?`${customMessage} - `:'';const errorMsgPrefix=`${context}${LOG_CONTEXT_SEPARATOR}${customMsgVal}`;const bsException=createBugsnagException(normalizedError,errorMsgPrefix);const stacktrace=getStacktrace(normalizedError);const isSdkDispatched=stacktrace.includes(MANUAL_ERROR_IDENTIFIER);// Filter errors that are not originated in the SDK.
|
|
865
869
|
// In case of NPM installations, the unhandled errors from the SDK cannot be identified
|
|
866
870
|
// and will NOT be reported unless they occur in plugins or integrations.
|
|
867
|
-
if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCEPTION){return;}if(state.reporting.isErrorReportingEnabled.value){const isAllowed=await checkIfAllowedToBeNotified(bsException,state,this.httpClient);if(isAllowed){const errorState={severity:'error',unhandled:errorType!==ErrorType.HANDLEDEXCEPTION,severityReason:{type:errorType}};//
|
|
868
|
-
//
|
|
869
|
-
//
|
|
871
|
+
if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCEPTION){return;}if(state.reporting.isErrorReportingEnabled.value){const isAllowed=await checkIfAllowedToBeNotified(bsException,state,this.httpClient);if(isAllowed){const errorState={severity:'error',unhandled:errorType!==ErrorType.HANDLEDEXCEPTION,severityReason:{type:errorType}};// This will allow custom grouping of errors.
|
|
872
|
+
// In case of NPM installations, the default grouping by surrounding code
|
|
873
|
+
// does not make sense as each user application is different and will create a lot of noise in the alerts.
|
|
870
874
|
// References:
|
|
871
875
|
// https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash
|
|
872
876
|
// https://docs.bugsnag.com/product/error-grouping/#user_defined
|
|
873
|
-
const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,
|
|
874
|
-
const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);// send it to metrics service
|
|
875
|
-
this.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state,
|
|
877
|
+
const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,this.logger);// Get the final payload to be sent to the metrics service
|
|
878
|
+
const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);const errorCategory=getErrorCategory(bsException,category);// send it to metrics service
|
|
879
|
+
this.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state,errorCategory),sendRawData:true},isRawResponse:true});}}// Log handled errors and errors dispatched by the SDK
|
|
876
880
|
if(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}}catch(err){// If an error occurs while handling an error, log it
|
|
877
881
|
this.logger.error(HANDLE_ERROR_FAILURE(ERROR_HANDLER),err);}}/**
|
|
878
882
|
* Add breadcrumbs to add insight of a user's journey before an error
|
|
@@ -958,7 +962,7 @@ const userIdKey='rl_user_id';const userTraitsKey='rl_trait';const anonymousUserI
|
|
|
958
962
|
const encryptBrowser=value=>`${ENCRYPTION_PREFIX_V3}${toBase64(value)}`;const decryptBrowser=value=>{if(value?.startsWith(ENCRYPTION_PREFIX_V3)){return fromBase64(value.substring(ENCRYPTION_PREFIX_V3.length));}return value;};
|
|
959
963
|
|
|
960
964
|
const EVENT_PAYLOAD_SIZE_BYTES_LIMIT=32*1024;// 32 KB
|
|
961
|
-
const RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;
|
|
965
|
+
const RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;
|
|
962
966
|
|
|
963
967
|
const isStorageQuotaExceeded=e=>{const matchingNames=['QuotaExceededError','NS_ERROR_DOM_QUOTA_REACHED'];// Everything except Firefox, Firefox
|
|
964
968
|
const matchingCodes=[22,1014];if(e instanceof DOMException){return matchingNames.includes(e.name)||matchingCodes.includes(e.code);}return false;};// TODO: also check for SecurityErrors
|
|
@@ -2881,7 +2885,8 @@ this.swapQueueStoreToInMemoryEngine();// and save it there
|
|
|
2881
2885
|
this.set(key,value);}else {const customMessage=STORE_DATA_SAVE_ERROR(key);this.onError(err,customMessage,customMessage);}}}/**
|
|
2882
2886
|
* Get by Key.
|
|
2883
2887
|
*/get(key){const validKey=this.createValidKey(key);let decryptedValue;try{if(!validKey){return null;}decryptedValue=this.decrypt(this.engine.getItem(validKey));if(isNullOrUndefined(decryptedValue)||decryptedValue===''){return null;}// storejs that is used in localstorage engine already deserializes json strings but swallows errors
|
|
2884
|
-
return JSON.parse(decryptedValue);}catch(err){const
|
|
2888
|
+
return JSON.parse(decryptedValue);}catch(err){const encryptionPluginName=state.storage.encryptionPluginName.value;// Skip error reporting only when the encryption plugin is configured but failed to load
|
|
2889
|
+
const shouldReportError=!encryptionPluginName||!state.plugins.failedPlugins.value.includes(encryptionPluginName);if(shouldReportError){const customMessage=STORE_DATA_FETCH_ERROR(key);this.onError(err,customMessage,customMessage);}return null;}}/**
|
|
2885
2890
|
* Remove by Key.
|
|
2886
2891
|
*/remove(key){const validKey=this.createValidKey(key);if(validKey){this.engine.removeItem(validKey);}}/**
|
|
2887
2892
|
* Get original engine
|
|
@@ -3567,7 +3572,7 @@ E(()=>{const areAllDestinationsReady=totalDestinationsToLoad===0||state.nativeDe
|
|
|
3567
3572
|
*/// eslint-disable-next-line class-methods-use-this
|
|
3568
3573
|
onDestinationsReady(){// May be do any destination specific actions here
|
|
3569
3574
|
// Mark the ready status if not already done
|
|
3570
|
-
if(state.lifecycle.status.value!=='ready'){state.lifecycle.status.value='ready';}}// End lifecycle methods
|
|
3575
|
+
if(state.lifecycle.status.value!=='ready'){r(()=>{state.lifecycle.status.value='ready';});}}// End lifecycle methods
|
|
3571
3576
|
// Start consumer exposed methods
|
|
3572
3577
|
ready(callback,isBufferedInvocation=false){const type='ready';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,callback]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} invocation`);if(!isFunction(callback)){this.logger.error(INVALID_CALLBACK_FN_ERROR(READY_API));return;}/**
|
|
3573
3578
|
* If destinations are loaded or no integration is available for loading
|
|
@@ -515,7 +515,7 @@ error.stack=`${stack}\n${MANUAL_ERROR_IDENTIFIER}`;break;case stacktrace:// esli
|
|
|
515
515
|
error.stacktrace=`${stacktrace}\n${MANUAL_ERROR_IDENTIFIER}`;break;case operaSourceloc:default:// eslint-disable-next-line no-param-reassign
|
|
516
516
|
error['opera#sourceloc']=`${operaSourceloc}\n${MANUAL_ERROR_IDENTIFIER}`;break;}}}globalThis.dispatchEvent(new ErrorEvent('error',{error,bubbles:true,cancelable:true,composed:true}));};
|
|
517
517
|
|
|
518
|
-
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.
|
|
518
|
+
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.28.0';const APP_NAMESPACE='com.rudderlabs.javascript';const MODULE_TYPE='npm';const ADBLOCK_PAGE_CATEGORY='RudderJS-Initiated';const ADBLOCK_PAGE_NAME='ad-block page request';const ADBLOCK_PAGE_PATH='/ad-blocked';const GLOBAL_PRELOAD_BUFFER='preloadedEventsBuffer';const CONSENT_TRACK_EVENT_NAME='Consent Management Interaction';
|
|
519
519
|
|
|
520
520
|
const QUERY_PARAM_TRAIT_PREFIX='ajs_trait_';const QUERY_PARAM_PROPERTY_PREFIX='ajs_prop_';const QUERY_PARAM_ANONYMOUS_ID_KEY='ajs_aid';const QUERY_PARAM_USER_ID_KEY='ajs_uid';const QUERY_PARAM_TRACK_EVENT_NAME_KEY='ajs_event';
|
|
521
521
|
|
|
@@ -738,7 +738,7 @@ try{if(JSON.stringify(f)==='{}')return accum;return accum.concat(f);}catch{retur
|
|
|
738
738
|
* Utility to parse XHR JSON response
|
|
739
739
|
*/const responseTextToJson=(responseText,onError)=>{try{return JSON.parse(responseText||'');}catch(err){const error=getMutatedError(err,'Failed to parse response data');onError(error);}return undefined;};
|
|
740
740
|
|
|
741
|
-
const FAILED_REQUEST_ERR_MSG_PREFIX='The request failed';const PLUGINS_LOAD_FAILURE_MESSAGES=[/Failed to fetch dynamically imported module: .*/];const INTEGRATIONS_LOAD_FAILURE_MESSAGES=[/Unable to load \(.*\) the script with the id .*/,/A timeout of \d+ ms occurred while trying to load the script with id .*/];const ERROR_MESSAGES_TO_BE_FILTERED=[new RegExp(`${FAILED_REQUEST_ERR_MSG_PREFIX}.*`),/A script with the id .* is already loaded\./];const SCRIPT_LOAD_FAILURE_MESSAGES=[...PLUGINS_LOAD_FAILURE_MESSAGES,...INTEGRATIONS_LOAD_FAILURE_MESSAGES];
|
|
741
|
+
const FAILED_REQUEST_ERR_MSG_PREFIX='The request failed';const PLUGINS_LOAD_FAILURE_MESSAGES=[/Failed to fetch dynamically imported module: .*/];const INTEGRATIONS_LOAD_FAILURE_MESSAGES=[/Unable to load \(.*\) the script with the id .*/,/A timeout of \d+ ms occurred while trying to load the script with id .*/];const ERROR_MESSAGES_TO_BE_FILTERED=[new RegExp(`${FAILED_REQUEST_ERR_MSG_PREFIX}.*`),/A script with the id .* is already loaded\./];const SCRIPT_LOAD_FAILURE_MESSAGES=[...PLUGINS_LOAD_FAILURE_MESSAGES,...INTEGRATIONS_LOAD_FAILURE_MESSAGES];const INTEGRATIONS_ERROR_CATEGORY='integrations';const SDK_ERROR_CATEGORY='sdk';const DEFAULT_ERROR_CATEGORY=SDK_ERROR_CATEGORY;
|
|
742
742
|
|
|
743
743
|
const DEFAULT_XHR_REQUEST_OPTIONS={headers:{Accept:'application/json','Content-Type':'application/json;charset=UTF-8'},method:'GET'};/**
|
|
744
744
|
* Utility to create request configuration based on default options
|
|
@@ -774,7 +774,7 @@ const SDK_FILE_NAME_PREFIXES=()=>['rsa'// Prefix for all the SDK scripts includi
|
|
|
774
774
|
// Potential PII or sensitive data
|
|
775
775
|
const APP_STATE_EXCLUDE_KEYS=['userId','userTraits','groupId','groupTraits','anonymousId','config','integration',// integration instance objects
|
|
776
776
|
'eventBuffer',// pre-load event buffer (may contain PII)
|
|
777
|
-
'traits','authToken'];const NOTIFIER_NAME='RudderStack JavaScript SDK';const SDK_GITHUB_URL='git+https://github.com/rudderlabs/rudder-sdk-js.git';const SOURCE_NAME='js';
|
|
777
|
+
'traits','authToken'];const NOTIFIER_NAME='RudderStack JavaScript SDK';const SDK_GITHUB_URL='git+https://github.com/rudderlabs/rudder-sdk-js.git';const SOURCE_NAME='js';
|
|
778
778
|
|
|
779
779
|
const detectAdBlockers=httpClient=>{state.capabilities.isAdBlockerDetectionInProgress.value=true;try{// Apparently, '?view=ad' is a query param that is blocked by majority of adblockers
|
|
780
780
|
// Use source config URL here as it is very unlikely to be blocked by adblockers
|
|
@@ -820,23 +820,27 @@ if(state.capabilities.cspBlockedURLs.value.includes(extractedURL)){resolve(false
|
|
|
820
820
|
checkIfAdBlockersAreActive(state,httpClient,resolve);}}else {// Filter out errors that are not from the RS CDN.
|
|
821
821
|
resolve(false);}}else {// Allow the error to be notified if no URL could be extracted from the error message
|
|
822
822
|
resolve(true);}}else {resolve(!ERROR_MESSAGES_TO_BE_FILTERED.some(e=>e.test(errMsg)));}});};/**
|
|
823
|
+
* A function to get the directory name from a file path.
|
|
824
|
+
* @param {string} filePath The file path
|
|
825
|
+
* @returns The directory name or undefined if the file path is invalid
|
|
826
|
+
*/const getDirectoryName=filePath=>{if(!filePath){return undefined;}const paths=filePath.split('/');return paths.at(-2);};/**
|
|
827
|
+
* A function to get the top stack path from the exception.
|
|
828
|
+
* @param {Exception} exception The exception object
|
|
829
|
+
* @returns The top stack path or undefined if the exception is invalid
|
|
830
|
+
*/const getTopStackPath=exception=>{const errorOrigin=exception.stacktrace[0]?.file;if(!errorOrigin||typeof errorOrigin!=='string'){return undefined;}return errorOrigin;};/**
|
|
823
831
|
* A function to determine if the error is from Rudder SDK
|
|
824
832
|
* @param {Error} exception
|
|
825
833
|
* @returns
|
|
826
|
-
*/const isSDKError=exception=>{const errorOrigin=exception
|
|
827
|
-
// Ex: parentFolderName will be 'sample' for url: https://example.com/sample/file.min.js
|
|
828
|
-
const parentFolderName=paths[paths.length-2];return parentFolderName===CDN_INT_DIR||SDK_FILE_NAME_PREFIXES().some(prefix=>srcFileName.startsWith(prefix)&&srcFileName.endsWith('.js'));};const getErrorDeliveryPayload=(payload,state,category)=>{const data={version:METRICS_PAYLOAD_VERSION,message_id:generateUUID(),source:{name:SOURCE_NAME,sdk_version:state.context.app.value.version,write_key:state.lifecycle.writeKey.value,install_type:state.context.app.value.installType,category:category??DEFAULT_ERROR_CATEGORY},errors:payload};return stringifyWithoutCircular(data);};/**
|
|
834
|
+
*/const isSDKError=exception=>{const errorOrigin=getTopStackPath(exception);if(!errorOrigin){return false;}const srcFileName=errorOrigin.substring(errorOrigin.lastIndexOf('/')+1);const parentFolderName=getDirectoryName(errorOrigin);return parentFolderName===CDN_INT_DIR||SDK_FILE_NAME_PREFIXES().some(prefix=>srcFileName.startsWith(prefix)&&srcFileName.endsWith('.js'));};const getErrorCategory=(exception,category)=>{if(category){return category;}const errorOrigin=getTopStackPath(exception);const directoryName=getDirectoryName(errorOrigin);if(directoryName===CDN_INT_DIR){return INTEGRATIONS_ERROR_CATEGORY;}return DEFAULT_ERROR_CATEGORY;};const getErrorDeliveryPayload=(payload,state,category)=>{const data={version:METRICS_PAYLOAD_VERSION,message_id:generateUUID(),source:{name:SOURCE_NAME,sdk_version:state.context.app.value.version,write_key:state.lifecycle.writeKey.value,install_type:state.context.app.value.installType,category},errors:payload};return stringifyWithoutCircular(data);};/**
|
|
829
835
|
* A function to get the grouping hash value to be used for the error event.
|
|
830
|
-
* Grouping hash is suppressed for non-cdn installs.
|
|
831
836
|
* If the grouping hash is an error instance, the normalized error message is used as the grouping hash.
|
|
832
837
|
* If the grouping hash is an empty string or not specified, the default grouping hash is used.
|
|
833
838
|
* If the grouping hash is a string, it is used as is.
|
|
834
839
|
* @param curErrGroupingHash The grouping hash value part of the error event
|
|
835
840
|
* @param defaultGroupingHash The default grouping hash value. It is the error message.
|
|
836
|
-
* @param state The application state
|
|
837
841
|
* @param logger The logger instance
|
|
838
842
|
* @returns The final grouping hash value to be used for the error event
|
|
839
|
-
*/const getErrorGroupingHash=(curErrGroupingHash,defaultGroupingHash,
|
|
843
|
+
*/const getErrorGroupingHash=(curErrGroupingHash,defaultGroupingHash,logger)=>{let normalizedGroupingHash;if(!isDefined(curErrGroupingHash)){normalizedGroupingHash=defaultGroupingHash;}else if(isString(curErrGroupingHash)){normalizedGroupingHash=curErrGroupingHash;}else {const normalizedErrorInstance=normalizeError(curErrGroupingHash,logger);if(isDefined(normalizedErrorInstance)){normalizedGroupingHash=normalizedErrorInstance.message;}else {normalizedGroupingHash=defaultGroupingHash;}}return normalizedGroupingHash;};
|
|
840
844
|
|
|
841
845
|
/**
|
|
842
846
|
* A service to handle errors
|
|
@@ -860,15 +864,15 @@ document.addEventListener('securitypolicyviolation',event=>{const blockedURL=isS
|
|
|
860
864
|
*/async onError(errorInfo){try{const{error,context,customMessage,groupingHash,category}=errorInfo;const errorType=errorInfo.errorType??ErrorType.HANDLEDEXCEPTION;const errInstance=getErrInstance(error,errorType);const normalizedError=normalizeError(errInstance,this.logger);if(isUndefined(normalizedError)){return;}const customMsgVal=customMessage?`${customMessage} - `:'';const errorMsgPrefix=`${context}${LOG_CONTEXT_SEPARATOR}${customMsgVal}`;const bsException=createBugsnagException(normalizedError,errorMsgPrefix);const stacktrace=getStacktrace(normalizedError);const isSdkDispatched=stacktrace.includes(MANUAL_ERROR_IDENTIFIER);// Filter errors that are not originated in the SDK.
|
|
861
865
|
// In case of NPM installations, the unhandled errors from the SDK cannot be identified
|
|
862
866
|
// and will NOT be reported unless they occur in plugins or integrations.
|
|
863
|
-
if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCEPTION){return;}if(state.reporting.isErrorReportingEnabled.value){const isAllowed=await checkIfAllowedToBeNotified(bsException,state,this.httpClient);if(isAllowed){const errorState={severity:'error',unhandled:errorType!==ErrorType.HANDLEDEXCEPTION,severityReason:{type:errorType}};//
|
|
864
|
-
//
|
|
865
|
-
//
|
|
867
|
+
if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCEPTION){return;}if(state.reporting.isErrorReportingEnabled.value){const isAllowed=await checkIfAllowedToBeNotified(bsException,state,this.httpClient);if(isAllowed){const errorState={severity:'error',unhandled:errorType!==ErrorType.HANDLEDEXCEPTION,severityReason:{type:errorType}};// This will allow custom grouping of errors.
|
|
868
|
+
// In case of NPM installations, the default grouping by surrounding code
|
|
869
|
+
// does not make sense as each user application is different and will create a lot of noise in the alerts.
|
|
866
870
|
// References:
|
|
867
871
|
// https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash
|
|
868
872
|
// https://docs.bugsnag.com/product/error-grouping/#user_defined
|
|
869
|
-
const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,
|
|
870
|
-
const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);// send it to metrics service
|
|
871
|
-
this.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state,
|
|
873
|
+
const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,this.logger);// Get the final payload to be sent to the metrics service
|
|
874
|
+
const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);const errorCategory=getErrorCategory(bsException,category);// send it to metrics service
|
|
875
|
+
this.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state,errorCategory),sendRawData:true},isRawResponse:true});}}// Log handled errors and errors dispatched by the SDK
|
|
872
876
|
if(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}}catch(err){// If an error occurs while handling an error, log it
|
|
873
877
|
this.logger.error(HANDLE_ERROR_FAILURE(ERROR_HANDLER),err);}}/**
|
|
874
878
|
* Add breadcrumbs to add insight of a user's journey before an error
|
|
@@ -954,7 +958,7 @@ const userIdKey='rl_user_id';const userTraitsKey='rl_trait';const anonymousUserI
|
|
|
954
958
|
const encryptBrowser=value=>`${ENCRYPTION_PREFIX_V3}${toBase64(value)}`;const decryptBrowser=value=>{if(value?.startsWith(ENCRYPTION_PREFIX_V3)){return fromBase64(value.substring(ENCRYPTION_PREFIX_V3.length));}return value;};
|
|
955
959
|
|
|
956
960
|
const EVENT_PAYLOAD_SIZE_BYTES_LIMIT=32*1024;// 32 KB
|
|
957
|
-
const RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;
|
|
961
|
+
const RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;
|
|
958
962
|
|
|
959
963
|
const isStorageQuotaExceeded=e=>{const matchingNames=['QuotaExceededError','NS_ERROR_DOM_QUOTA_REACHED'];// Everything except Firefox, Firefox
|
|
960
964
|
const matchingCodes=[22,1014];if(e instanceof DOMException){return matchingNames.includes(e.name)||matchingCodes.includes(e.code);}return false;};// TODO: also check for SecurityErrors
|
|
@@ -2877,7 +2881,8 @@ this.swapQueueStoreToInMemoryEngine();// and save it there
|
|
|
2877
2881
|
this.set(key,value);}else {const customMessage=STORE_DATA_SAVE_ERROR(key);this.onError(err,customMessage,customMessage);}}}/**
|
|
2878
2882
|
* Get by Key.
|
|
2879
2883
|
*/get(key){const validKey=this.createValidKey(key);let decryptedValue;try{if(!validKey){return null;}decryptedValue=this.decrypt(this.engine.getItem(validKey));if(isNullOrUndefined(decryptedValue)||decryptedValue===''){return null;}// storejs that is used in localstorage engine already deserializes json strings but swallows errors
|
|
2880
|
-
return JSON.parse(decryptedValue);}catch(err){const
|
|
2884
|
+
return JSON.parse(decryptedValue);}catch(err){const encryptionPluginName=state.storage.encryptionPluginName.value;// Skip error reporting only when the encryption plugin is configured but failed to load
|
|
2885
|
+
const shouldReportError=!encryptionPluginName||!state.plugins.failedPlugins.value.includes(encryptionPluginName);if(shouldReportError){const customMessage=STORE_DATA_FETCH_ERROR(key);this.onError(err,customMessage,customMessage);}return null;}}/**
|
|
2881
2886
|
* Remove by Key.
|
|
2882
2887
|
*/remove(key){const validKey=this.createValidKey(key);if(validKey){this.engine.removeItem(validKey);}}/**
|
|
2883
2888
|
* Get original engine
|
|
@@ -3563,7 +3568,7 @@ E(()=>{const areAllDestinationsReady=totalDestinationsToLoad===0||state.nativeDe
|
|
|
3563
3568
|
*/// eslint-disable-next-line class-methods-use-this
|
|
3564
3569
|
onDestinationsReady(){// May be do any destination specific actions here
|
|
3565
3570
|
// Mark the ready status if not already done
|
|
3566
|
-
if(state.lifecycle.status.value!=='ready'){state.lifecycle.status.value='ready';}}// End lifecycle methods
|
|
3571
|
+
if(state.lifecycle.status.value!=='ready'){r(()=>{state.lifecycle.status.value='ready';});}}// End lifecycle methods
|
|
3567
3572
|
// Start consumer exposed methods
|
|
3568
3573
|
ready(callback,isBufferedInvocation=false){const type='ready';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,callback]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} invocation`);if(!isFunction(callback)){this.logger.error(INVALID_CALLBACK_FN_ERROR(READY_API));return;}/**
|
|
3569
3574
|
* If destinations are loaded or no integration is available for loading
|
|
@@ -521,7 +521,7 @@
|
|
|
521
521
|
error.stacktrace=`${stacktrace}\n${MANUAL_ERROR_IDENTIFIER}`;break;case operaSourceloc:default:// eslint-disable-next-line no-param-reassign
|
|
522
522
|
error['opera#sourceloc']=`${operaSourceloc}\n${MANUAL_ERROR_IDENTIFIER}`;break;}}}globalThis.dispatchEvent(new ErrorEvent('error',{error,bubbles:true,cancelable:true,composed:true}));};
|
|
523
523
|
|
|
524
|
-
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.
|
|
524
|
+
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.28.0';const APP_NAMESPACE='com.rudderlabs.javascript';const MODULE_TYPE='npm';const ADBLOCK_PAGE_CATEGORY='RudderJS-Initiated';const ADBLOCK_PAGE_NAME='ad-block page request';const ADBLOCK_PAGE_PATH='/ad-blocked';const GLOBAL_PRELOAD_BUFFER='preloadedEventsBuffer';const CONSENT_TRACK_EVENT_NAME='Consent Management Interaction';
|
|
525
525
|
|
|
526
526
|
const QUERY_PARAM_TRAIT_PREFIX='ajs_trait_';const QUERY_PARAM_PROPERTY_PREFIX='ajs_prop_';const QUERY_PARAM_ANONYMOUS_ID_KEY='ajs_aid';const QUERY_PARAM_USER_ID_KEY='ajs_uid';const QUERY_PARAM_TRACK_EVENT_NAME_KEY='ajs_event';
|
|
527
527
|
|
|
@@ -744,7 +744,7 @@
|
|
|
744
744
|
* Utility to parse XHR JSON response
|
|
745
745
|
*/const responseTextToJson=(responseText,onError)=>{try{return JSON.parse(responseText||'');}catch(err){const error=getMutatedError(err,'Failed to parse response data');onError(error);}return undefined;};
|
|
746
746
|
|
|
747
|
-
const FAILED_REQUEST_ERR_MSG_PREFIX='The request failed';const PLUGINS_LOAD_FAILURE_MESSAGES=[/Failed to fetch dynamically imported module: .*/];const INTEGRATIONS_LOAD_FAILURE_MESSAGES=[/Unable to load \(.*\) the script with the id .*/,/A timeout of \d+ ms occurred while trying to load the script with id .*/];const ERROR_MESSAGES_TO_BE_FILTERED=[new RegExp(`${FAILED_REQUEST_ERR_MSG_PREFIX}.*`),/A script with the id .* is already loaded\./];const SCRIPT_LOAD_FAILURE_MESSAGES=[...PLUGINS_LOAD_FAILURE_MESSAGES,...INTEGRATIONS_LOAD_FAILURE_MESSAGES];
|
|
747
|
+
const FAILED_REQUEST_ERR_MSG_PREFIX='The request failed';const PLUGINS_LOAD_FAILURE_MESSAGES=[/Failed to fetch dynamically imported module: .*/];const INTEGRATIONS_LOAD_FAILURE_MESSAGES=[/Unable to load \(.*\) the script with the id .*/,/A timeout of \d+ ms occurred while trying to load the script with id .*/];const ERROR_MESSAGES_TO_BE_FILTERED=[new RegExp(`${FAILED_REQUEST_ERR_MSG_PREFIX}.*`),/A script with the id .* is already loaded\./];const SCRIPT_LOAD_FAILURE_MESSAGES=[...PLUGINS_LOAD_FAILURE_MESSAGES,...INTEGRATIONS_LOAD_FAILURE_MESSAGES];const INTEGRATIONS_ERROR_CATEGORY='integrations';const SDK_ERROR_CATEGORY='sdk';const DEFAULT_ERROR_CATEGORY=SDK_ERROR_CATEGORY;
|
|
748
748
|
|
|
749
749
|
const DEFAULT_XHR_REQUEST_OPTIONS={headers:{Accept:'application/json','Content-Type':'application/json;charset=UTF-8'},method:'GET'};/**
|
|
750
750
|
* Utility to create request configuration based on default options
|
|
@@ -780,7 +780,7 @@
|
|
|
780
780
|
// Potential PII or sensitive data
|
|
781
781
|
const APP_STATE_EXCLUDE_KEYS=['userId','userTraits','groupId','groupTraits','anonymousId','config','integration',// integration instance objects
|
|
782
782
|
'eventBuffer',// pre-load event buffer (may contain PII)
|
|
783
|
-
'traits','authToken'];const NOTIFIER_NAME='RudderStack JavaScript SDK';const SDK_GITHUB_URL='git+https://github.com/rudderlabs/rudder-sdk-js.git';const SOURCE_NAME='js';
|
|
783
|
+
'traits','authToken'];const NOTIFIER_NAME='RudderStack JavaScript SDK';const SDK_GITHUB_URL='git+https://github.com/rudderlabs/rudder-sdk-js.git';const SOURCE_NAME='js';
|
|
784
784
|
|
|
785
785
|
const detectAdBlockers=httpClient=>{state.capabilities.isAdBlockerDetectionInProgress.value=true;try{// Apparently, '?view=ad' is a query param that is blocked by majority of adblockers
|
|
786
786
|
// Use source config URL here as it is very unlikely to be blocked by adblockers
|
|
@@ -826,23 +826,27 @@
|
|
|
826
826
|
checkIfAdBlockersAreActive(state,httpClient,resolve);}}else {// Filter out errors that are not from the RS CDN.
|
|
827
827
|
resolve(false);}}else {// Allow the error to be notified if no URL could be extracted from the error message
|
|
828
828
|
resolve(true);}}else {resolve(!ERROR_MESSAGES_TO_BE_FILTERED.some(e=>e.test(errMsg)));}});};/**
|
|
829
|
+
* A function to get the directory name from a file path.
|
|
830
|
+
* @param {string} filePath The file path
|
|
831
|
+
* @returns The directory name or undefined if the file path is invalid
|
|
832
|
+
*/const getDirectoryName=filePath=>{if(!filePath){return undefined;}const paths=filePath.split('/');return paths.at(-2);};/**
|
|
833
|
+
* A function to get the top stack path from the exception.
|
|
834
|
+
* @param {Exception} exception The exception object
|
|
835
|
+
* @returns The top stack path or undefined if the exception is invalid
|
|
836
|
+
*/const getTopStackPath=exception=>{const errorOrigin=exception.stacktrace[0]?.file;if(!errorOrigin||typeof errorOrigin!=='string'){return undefined;}return errorOrigin;};/**
|
|
829
837
|
* A function to determine if the error is from Rudder SDK
|
|
830
838
|
* @param {Error} exception
|
|
831
839
|
* @returns
|
|
832
|
-
*/const isSDKError=exception=>{const errorOrigin=exception
|
|
833
|
-
// Ex: parentFolderName will be 'sample' for url: https://example.com/sample/file.min.js
|
|
834
|
-
const parentFolderName=paths[paths.length-2];return parentFolderName===CDN_INT_DIR||SDK_FILE_NAME_PREFIXES().some(prefix=>srcFileName.startsWith(prefix)&&srcFileName.endsWith('.js'));};const getErrorDeliveryPayload=(payload,state,category)=>{const data={version:METRICS_PAYLOAD_VERSION,message_id:generateUUID(),source:{name:SOURCE_NAME,sdk_version:state.context.app.value.version,write_key:state.lifecycle.writeKey.value,install_type:state.context.app.value.installType,category:category??DEFAULT_ERROR_CATEGORY},errors:payload};return stringifyWithoutCircular(data);};/**
|
|
840
|
+
*/const isSDKError=exception=>{const errorOrigin=getTopStackPath(exception);if(!errorOrigin){return false;}const srcFileName=errorOrigin.substring(errorOrigin.lastIndexOf('/')+1);const parentFolderName=getDirectoryName(errorOrigin);return parentFolderName===CDN_INT_DIR||SDK_FILE_NAME_PREFIXES().some(prefix=>srcFileName.startsWith(prefix)&&srcFileName.endsWith('.js'));};const getErrorCategory=(exception,category)=>{if(category){return category;}const errorOrigin=getTopStackPath(exception);const directoryName=getDirectoryName(errorOrigin);if(directoryName===CDN_INT_DIR){return INTEGRATIONS_ERROR_CATEGORY;}return DEFAULT_ERROR_CATEGORY;};const getErrorDeliveryPayload=(payload,state,category)=>{const data={version:METRICS_PAYLOAD_VERSION,message_id:generateUUID(),source:{name:SOURCE_NAME,sdk_version:state.context.app.value.version,write_key:state.lifecycle.writeKey.value,install_type:state.context.app.value.installType,category},errors:payload};return stringifyWithoutCircular(data);};/**
|
|
835
841
|
* A function to get the grouping hash value to be used for the error event.
|
|
836
|
-
* Grouping hash is suppressed for non-cdn installs.
|
|
837
842
|
* If the grouping hash is an error instance, the normalized error message is used as the grouping hash.
|
|
838
843
|
* If the grouping hash is an empty string or not specified, the default grouping hash is used.
|
|
839
844
|
* If the grouping hash is a string, it is used as is.
|
|
840
845
|
* @param curErrGroupingHash The grouping hash value part of the error event
|
|
841
846
|
* @param defaultGroupingHash The default grouping hash value. It is the error message.
|
|
842
|
-
* @param state The application state
|
|
843
847
|
* @param logger The logger instance
|
|
844
848
|
* @returns The final grouping hash value to be used for the error event
|
|
845
|
-
*/const getErrorGroupingHash=(curErrGroupingHash,defaultGroupingHash,
|
|
849
|
+
*/const getErrorGroupingHash=(curErrGroupingHash,defaultGroupingHash,logger)=>{let normalizedGroupingHash;if(!isDefined(curErrGroupingHash)){normalizedGroupingHash=defaultGroupingHash;}else if(isString(curErrGroupingHash)){normalizedGroupingHash=curErrGroupingHash;}else {const normalizedErrorInstance=normalizeError(curErrGroupingHash,logger);if(isDefined(normalizedErrorInstance)){normalizedGroupingHash=normalizedErrorInstance.message;}else {normalizedGroupingHash=defaultGroupingHash;}}return normalizedGroupingHash;};
|
|
846
850
|
|
|
847
851
|
/**
|
|
848
852
|
* A service to handle errors
|
|
@@ -866,15 +870,15 @@
|
|
|
866
870
|
*/async onError(errorInfo){try{const{error,context,customMessage,groupingHash,category}=errorInfo;const errorType=errorInfo.errorType??ErrorType.HANDLEDEXCEPTION;const errInstance=getErrInstance(error,errorType);const normalizedError=normalizeError(errInstance,this.logger);if(isUndefined(normalizedError)){return;}const customMsgVal=customMessage?`${customMessage} - `:'';const errorMsgPrefix=`${context}${LOG_CONTEXT_SEPARATOR}${customMsgVal}`;const bsException=createBugsnagException(normalizedError,errorMsgPrefix);const stacktrace=getStacktrace(normalizedError);const isSdkDispatched=stacktrace.includes(MANUAL_ERROR_IDENTIFIER);// Filter errors that are not originated in the SDK.
|
|
867
871
|
// In case of NPM installations, the unhandled errors from the SDK cannot be identified
|
|
868
872
|
// and will NOT be reported unless they occur in plugins or integrations.
|
|
869
|
-
if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCEPTION){return;}if(state.reporting.isErrorReportingEnabled.value){const isAllowed=await checkIfAllowedToBeNotified(bsException,state,this.httpClient);if(isAllowed){const errorState={severity:'error',unhandled:errorType!==ErrorType.HANDLEDEXCEPTION,severityReason:{type:errorType}};//
|
|
870
|
-
//
|
|
871
|
-
//
|
|
873
|
+
if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCEPTION){return;}if(state.reporting.isErrorReportingEnabled.value){const isAllowed=await checkIfAllowedToBeNotified(bsException,state,this.httpClient);if(isAllowed){const errorState={severity:'error',unhandled:errorType!==ErrorType.HANDLEDEXCEPTION,severityReason:{type:errorType}};// This will allow custom grouping of errors.
|
|
874
|
+
// In case of NPM installations, the default grouping by surrounding code
|
|
875
|
+
// does not make sense as each user application is different and will create a lot of noise in the alerts.
|
|
872
876
|
// References:
|
|
873
877
|
// https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash
|
|
874
878
|
// https://docs.bugsnag.com/product/error-grouping/#user_defined
|
|
875
|
-
const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,
|
|
876
|
-
const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);// send it to metrics service
|
|
877
|
-
this.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state,
|
|
879
|
+
const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,this.logger);// Get the final payload to be sent to the metrics service
|
|
880
|
+
const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);const errorCategory=getErrorCategory(bsException,category);// send it to metrics service
|
|
881
|
+
this.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state,errorCategory),sendRawData:true},isRawResponse:true});}}// Log handled errors and errors dispatched by the SDK
|
|
878
882
|
if(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}}catch(err){// If an error occurs while handling an error, log it
|
|
879
883
|
this.logger.error(HANDLE_ERROR_FAILURE(ERROR_HANDLER),err);}}/**
|
|
880
884
|
* Add breadcrumbs to add insight of a user's journey before an error
|
|
@@ -960,7 +964,7 @@
|
|
|
960
964
|
const encryptBrowser=value=>`${ENCRYPTION_PREFIX_V3}${toBase64(value)}`;const decryptBrowser=value=>{if(value?.startsWith(ENCRYPTION_PREFIX_V3)){return fromBase64(value.substring(ENCRYPTION_PREFIX_V3.length));}return value;};
|
|
961
965
|
|
|
962
966
|
const EVENT_PAYLOAD_SIZE_BYTES_LIMIT=32*1024;// 32 KB
|
|
963
|
-
const RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;
|
|
967
|
+
const RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;
|
|
964
968
|
|
|
965
969
|
const isStorageQuotaExceeded=e=>{const matchingNames=['QuotaExceededError','NS_ERROR_DOM_QUOTA_REACHED'];// Everything except Firefox, Firefox
|
|
966
970
|
const matchingCodes=[22,1014];if(e instanceof DOMException){return matchingNames.includes(e.name)||matchingCodes.includes(e.code);}return false;};// TODO: also check for SecurityErrors
|
|
@@ -2883,7 +2887,8 @@
|
|
|
2883
2887
|
this.set(key,value);}else {const customMessage=STORE_DATA_SAVE_ERROR(key);this.onError(err,customMessage,customMessage);}}}/**
|
|
2884
2888
|
* Get by Key.
|
|
2885
2889
|
*/get(key){const validKey=this.createValidKey(key);let decryptedValue;try{if(!validKey){return null;}decryptedValue=this.decrypt(this.engine.getItem(validKey));if(isNullOrUndefined(decryptedValue)||decryptedValue===''){return null;}// storejs that is used in localstorage engine already deserializes json strings but swallows errors
|
|
2886
|
-
return JSON.parse(decryptedValue);}catch(err){const
|
|
2890
|
+
return JSON.parse(decryptedValue);}catch(err){const encryptionPluginName=state.storage.encryptionPluginName.value;// Skip error reporting only when the encryption plugin is configured but failed to load
|
|
2891
|
+
const shouldReportError=!encryptionPluginName||!state.plugins.failedPlugins.value.includes(encryptionPluginName);if(shouldReportError){const customMessage=STORE_DATA_FETCH_ERROR(key);this.onError(err,customMessage,customMessage);}return null;}}/**
|
|
2887
2892
|
* Remove by Key.
|
|
2888
2893
|
*/remove(key){const validKey=this.createValidKey(key);if(validKey){this.engine.removeItem(validKey);}}/**
|
|
2889
2894
|
* Get original engine
|
|
@@ -3569,7 +3574,7 @@
|
|
|
3569
3574
|
*/// eslint-disable-next-line class-methods-use-this
|
|
3570
3575
|
onDestinationsReady(){// May be do any destination specific actions here
|
|
3571
3576
|
// Mark the ready status if not already done
|
|
3572
|
-
if(state.lifecycle.status.value!=='ready'){state.lifecycle.status.value='ready';}}// End lifecycle methods
|
|
3577
|
+
if(state.lifecycle.status.value!=='ready'){r(()=>{state.lifecycle.status.value='ready';});}}// End lifecycle methods
|
|
3573
3578
|
// Start consumer exposed methods
|
|
3574
3579
|
ready(callback,isBufferedInvocation=false){const type='ready';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,callback]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} invocation`);if(!isFunction(callback)){this.logger.error(INVALID_CALLBACK_FN_ERROR(READY_API));return;}/**
|
|
3575
3580
|
* If destinations are loaded or no integration is available for loading
|