@rudderstack/analytics-js 3.27.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.
@@ -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.27.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';
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';const DEFAULT_ERROR_CATEGORY='sdk';
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,12 +824,18 @@ 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.stacktrace[0]?.file;if(!errorOrigin||typeof errorOrigin!=='string'){return false;}const srcFileName=errorOrigin.substring(errorOrigin.lastIndexOf('/')+1);const paths=errorOrigin.split('/');// extract the parent folder name from the error origin file path
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
840
  * If the grouping hash is an error instance, the normalized error message is used as the grouping hash.
835
841
  * If the grouping hash is an empty string or not specified, the default grouping hash is used.
@@ -869,8 +875,8 @@ if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCE
869
875
  // https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash
870
876
  // https://docs.bugsnag.com/product/error-grouping/#user_defined
871
877
  const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,this.logger);// Get the final payload to be sent to the metrics service
872
- const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);// send it to metrics service
873
- this.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state,category),sendRawData:true},isRawResponse:true});}}// Log handled errors and errors dispatched by the SDK
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
874
880
  if(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}}catch(err){// If an error occurs while handling an error, log it
875
881
  this.logger.error(HANDLE_ERROR_FAILURE(ERROR_HANDLER),err);}}/**
876
882
  * Add breadcrumbs to add insight of a user's journey before an error
@@ -956,7 +962,7 @@ const userIdKey='rl_user_id';const userTraitsKey='rl_trait';const anonymousUserI
956
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;};
957
963
 
958
964
  const EVENT_PAYLOAD_SIZE_BYTES_LIMIT=32*1024;// 32 KB
959
- const RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;const INTEGRATIONS_ERROR_CATEGORY='integrations';
965
+ const RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;
960
966
 
961
967
  const isStorageQuotaExceeded=e=>{const matchingNames=['QuotaExceededError','NS_ERROR_DOM_QUOTA_REACHED'];// Everything except Firefox, Firefox
962
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
@@ -2879,7 +2885,8 @@ this.swapQueueStoreToInMemoryEngine();// and save it there
2879
2885
  this.set(key,value);}else {const customMessage=STORE_DATA_SAVE_ERROR(key);this.onError(err,customMessage,customMessage);}}}/**
2880
2886
  * Get by Key.
2881
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
2882
- return JSON.parse(decryptedValue);}catch(err){const customMessage=STORE_DATA_FETCH_ERROR(key);this.onError(err,customMessage,customMessage);return null;}}/**
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;}}/**
2883
2890
  * Remove by Key.
2884
2891
  */remove(key){const validKey=this.createValidKey(key);if(validKey){this.engine.removeItem(validKey);}}/**
2885
2892
  * Get original engine
@@ -3565,7 +3572,7 @@ E(()=>{const areAllDestinationsReady=totalDestinationsToLoad===0||state.nativeDe
3565
3572
  */// eslint-disable-next-line class-methods-use-this
3566
3573
  onDestinationsReady(){// May be do any destination specific actions here
3567
3574
  // Mark the ready status if not already done
3568
- 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
3569
3576
  // Start consumer exposed methods
3570
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;}/**
3571
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.27.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';
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';const DEFAULT_ERROR_CATEGORY='sdk';
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,12 +820,18 @@ 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.stacktrace[0]?.file;if(!errorOrigin||typeof errorOrigin!=='string'){return false;}const srcFileName=errorOrigin.substring(errorOrigin.lastIndexOf('/')+1);const paths=errorOrigin.split('/');// extract the parent folder name from the error origin file path
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
836
  * If the grouping hash is an error instance, the normalized error message is used as the grouping hash.
831
837
  * If the grouping hash is an empty string or not specified, the default grouping hash is used.
@@ -865,8 +871,8 @@ if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCE
865
871
  // https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash
866
872
  // https://docs.bugsnag.com/product/error-grouping/#user_defined
867
873
  const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,this.logger);// Get the final payload to be sent to the metrics service
868
- const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);// send it to metrics service
869
- this.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state,category),sendRawData:true},isRawResponse:true});}}// Log handled errors and errors dispatched by the SDK
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
870
876
  if(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}}catch(err){// If an error occurs while handling an error, log it
871
877
  this.logger.error(HANDLE_ERROR_FAILURE(ERROR_HANDLER),err);}}/**
872
878
  * Add breadcrumbs to add insight of a user's journey before an error
@@ -952,7 +958,7 @@ const userIdKey='rl_user_id';const userTraitsKey='rl_trait';const anonymousUserI
952
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;};
953
959
 
954
960
  const EVENT_PAYLOAD_SIZE_BYTES_LIMIT=32*1024;// 32 KB
955
- const RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;const INTEGRATIONS_ERROR_CATEGORY='integrations';
961
+ const RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;
956
962
 
957
963
  const isStorageQuotaExceeded=e=>{const matchingNames=['QuotaExceededError','NS_ERROR_DOM_QUOTA_REACHED'];// Everything except Firefox, Firefox
958
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
@@ -2875,7 +2881,8 @@ this.swapQueueStoreToInMemoryEngine();// and save it there
2875
2881
  this.set(key,value);}else {const customMessage=STORE_DATA_SAVE_ERROR(key);this.onError(err,customMessage,customMessage);}}}/**
2876
2882
  * Get by Key.
2877
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
2878
- return JSON.parse(decryptedValue);}catch(err){const customMessage=STORE_DATA_FETCH_ERROR(key);this.onError(err,customMessage,customMessage);return null;}}/**
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;}}/**
2879
2886
  * Remove by Key.
2880
2887
  */remove(key){const validKey=this.createValidKey(key);if(validKey){this.engine.removeItem(validKey);}}/**
2881
2888
  * Get original engine
@@ -3561,7 +3568,7 @@ E(()=>{const areAllDestinationsReady=totalDestinationsToLoad===0||state.nativeDe
3561
3568
  */// eslint-disable-next-line class-methods-use-this
3562
3569
  onDestinationsReady(){// May be do any destination specific actions here
3563
3570
  // Mark the ready status if not already done
3564
- 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
3565
3572
  // Start consumer exposed methods
3566
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;}/**
3567
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.27.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';
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';const DEFAULT_ERROR_CATEGORY='sdk';
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,12 +826,18 @@
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.stacktrace[0]?.file;if(!errorOrigin||typeof errorOrigin!=='string'){return false;}const srcFileName=errorOrigin.substring(errorOrigin.lastIndexOf('/')+1);const paths=errorOrigin.split('/');// extract the parent folder name from the error origin file path
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
842
  * If the grouping hash is an error instance, the normalized error message is used as the grouping hash.
837
843
  * If the grouping hash is an empty string or not specified, the default grouping hash is used.
@@ -871,8 +877,8 @@
871
877
  // https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash
872
878
  // https://docs.bugsnag.com/product/error-grouping/#user_defined
873
879
  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);// send it to metrics service
875
- this.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state,category),sendRawData:true},isRawResponse:true});}}// Log handled errors and errors dispatched by the SDK
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
876
882
  if(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}}catch(err){// If an error occurs while handling an error, log it
877
883
  this.logger.error(HANDLE_ERROR_FAILURE(ERROR_HANDLER),err);}}/**
878
884
  * Add breadcrumbs to add insight of a user's journey before an error
@@ -958,7 +964,7 @@
958
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;};
959
965
 
960
966
  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;const INTEGRATIONS_ERROR_CATEGORY='integrations';
967
+ const RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;
962
968
 
963
969
  const isStorageQuotaExceeded=e=>{const matchingNames=['QuotaExceededError','NS_ERROR_DOM_QUOTA_REACHED'];// Everything except Firefox, Firefox
964
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
@@ -2881,7 +2887,8 @@
2881
2887
  this.set(key,value);}else {const customMessage=STORE_DATA_SAVE_ERROR(key);this.onError(err,customMessage,customMessage);}}}/**
2882
2888
  * Get by Key.
2883
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
2884
- return JSON.parse(decryptedValue);}catch(err){const customMessage=STORE_DATA_FETCH_ERROR(key);this.onError(err,customMessage,customMessage);return null;}}/**
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;}}/**
2885
2892
  * Remove by Key.
2886
2893
  */remove(key){const validKey=this.createValidKey(key);if(validKey){this.engine.removeItem(validKey);}}/**
2887
2894
  * Get original engine
@@ -3567,7 +3574,7 @@
3567
3574
  */// eslint-disable-next-line class-methods-use-this
3568
3575
  onDestinationsReady(){// May be do any destination specific actions here
3569
3576
  // Mark the ready status if not already done
3570
- 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
3571
3578
  // Start consumer exposed methods
3572
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;}/**
3573
3580
  * If destinations are loaded or no integration is available for loading
@@ -510,7 +510,7 @@ error.stack=`${stack}\n${MANUAL_ERROR_IDENTIFIER}`;break;case stacktrace:// esli
510
510
  error.stacktrace=`${stacktrace}\n${MANUAL_ERROR_IDENTIFIER}`;break;case operaSourceloc:default:// eslint-disable-next-line no-param-reassign
511
511
  error['opera#sourceloc']=`${operaSourceloc}\n${MANUAL_ERROR_IDENTIFIER}`;break;}}}globalThis.dispatchEvent(new ErrorEvent('error',{error,bubbles:true,cancelable:true,composed:true}));};
512
512
 
513
- const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.27.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';
513
+ 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';
514
514
 
515
515
  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';
516
516
 
@@ -733,7 +733,7 @@ try{if(JSON.stringify(f)==='{}')return accum;return accum.concat(f);}catch{retur
733
733
  * Utility to parse XHR JSON response
734
734
  */const responseTextToJson=(responseText,onError)=>{try{return JSON.parse(responseText||'');}catch(err){const error=getMutatedError(err,'Failed to parse response data');onError(error);}return undefined;};
735
735
 
736
- 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];
736
+ 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;
737
737
 
738
738
  const DEFAULT_XHR_REQUEST_OPTIONS={headers:{Accept:'application/json','Content-Type':'application/json;charset=UTF-8'},method:'GET'};/**
739
739
  * Utility to create request configuration based on default options
@@ -769,7 +769,7 @@ const SDK_FILE_NAME_PREFIXES=()=>['rsa'// Prefix for all the SDK scripts includi
769
769
  // Potential PII or sensitive data
770
770
  const APP_STATE_EXCLUDE_KEYS=['userId','userTraits','groupId','groupTraits','anonymousId','config','integration',// integration instance objects
771
771
  'eventBuffer',// pre-load event buffer (may contain PII)
772
- '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';const DEFAULT_ERROR_CATEGORY='sdk';
772
+ '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';
773
773
 
774
774
  const detectAdBlockers=httpClient=>{state.capabilities.isAdBlockerDetectionInProgress.value=true;try{// Apparently, '?view=ad' is a query param that is blocked by majority of adblockers
775
775
  // Use source config URL here as it is very unlikely to be blocked by adblockers
@@ -815,12 +815,18 @@ if(state.capabilities.cspBlockedURLs.value.includes(extractedURL)){resolve(false
815
815
  checkIfAdBlockersAreActive(state,httpClient,resolve);}}else {// Filter out errors that are not from the RS CDN.
816
816
  resolve(false);}}else {// Allow the error to be notified if no URL could be extracted from the error message
817
817
  resolve(true);}}else {resolve(!ERROR_MESSAGES_TO_BE_FILTERED.some(e=>e.test(errMsg)));}});};/**
818
+ * A function to get the directory name from a file path.
819
+ * @param {string} filePath The file path
820
+ * @returns The directory name or undefined if the file path is invalid
821
+ */const getDirectoryName=filePath=>{if(!filePath){return undefined;}const paths=filePath.split('/');return paths.at(-2);};/**
822
+ * A function to get the top stack path from the exception.
823
+ * @param {Exception} exception The exception object
824
+ * @returns The top stack path or undefined if the exception is invalid
825
+ */const getTopStackPath=exception=>{const errorOrigin=exception.stacktrace[0]?.file;if(!errorOrigin||typeof errorOrigin!=='string'){return undefined;}return errorOrigin;};/**
818
826
  * A function to determine if the error is from Rudder SDK
819
827
  * @param {Error} exception
820
828
  * @returns
821
- */const isSDKError=exception=>{const errorOrigin=exception.stacktrace[0]?.file;if(!errorOrigin||typeof errorOrigin!=='string'){return false;}const srcFileName=errorOrigin.substring(errorOrigin.lastIndexOf('/')+1);const paths=errorOrigin.split('/');// extract the parent folder name from the error origin file path
822
- // Ex: parentFolderName will be 'sample' for url: https://example.com/sample/file.min.js
823
- 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);};/**
829
+ */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);};/**
824
830
  * A function to get the grouping hash value to be used for the error event.
825
831
  * If the grouping hash is an error instance, the normalized error message is used as the grouping hash.
826
832
  * If the grouping hash is an empty string or not specified, the default grouping hash is used.
@@ -860,8 +866,8 @@ if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCE
860
866
  // https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash
861
867
  // https://docs.bugsnag.com/product/error-grouping/#user_defined
862
868
  const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,this.logger);// Get the final payload to be sent to the metrics service
863
- const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);// send it to metrics service
864
- this.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state,category),sendRawData:true},isRawResponse:true});}}// Log handled errors and errors dispatched by the SDK
869
+ const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);const errorCategory=getErrorCategory(bsException,category);// send it to metrics service
870
+ 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
865
871
  if(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}}catch(err){// If an error occurs while handling an error, log it
866
872
  this.logger.error(HANDLE_ERROR_FAILURE(ERROR_HANDLER),err);}}/**
867
873
  * Add breadcrumbs to add insight of a user's journey before an error
@@ -1154,7 +1160,8 @@ this.swapQueueStoreToInMemoryEngine();// and save it there
1154
1160
  this.set(key,value);}else {const customMessage=STORE_DATA_SAVE_ERROR(key);this.onError(err,customMessage,customMessage);}}}/**
1155
1161
  * Get by Key.
1156
1162
  */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
1157
- return JSON.parse(decryptedValue);}catch(err){const customMessage=STORE_DATA_FETCH_ERROR(key);this.onError(err,customMessage,customMessage);return null;}}/**
1163
+ 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
1164
+ 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;}}/**
1158
1165
  * Remove by Key.
1159
1166
  */remove(key){const validKey=this.createValidKey(key);if(validKey){this.engine.removeItem(validKey);}}/**
1160
1167
  * Get original engine
@@ -1857,7 +1864,7 @@ E(()=>{const areAllDestinationsReady=totalDestinationsToLoad===0||state.nativeDe
1857
1864
  */// eslint-disable-next-line class-methods-use-this
1858
1865
  onDestinationsReady(){// May be do any destination specific actions here
1859
1866
  // Mark the ready status if not already done
1860
- if(state.lifecycle.status.value!=='ready'){state.lifecycle.status.value='ready';}}// End lifecycle methods
1867
+ if(state.lifecycle.status.value!=='ready'){r(()=>{state.lifecycle.status.value='ready';});}}// End lifecycle methods
1861
1868
  // Start consumer exposed methods
1862
1869
  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;}/**
1863
1870
  * 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.27.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';
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';const DEFAULT_ERROR_CATEGORY='sdk';
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,12 +824,18 @@ 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.stacktrace[0]?.file;if(!errorOrigin||typeof errorOrigin!=='string'){return false;}const srcFileName=errorOrigin.substring(errorOrigin.lastIndexOf('/')+1);const paths=errorOrigin.split('/');// extract the parent folder name from the error origin file path
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
840
  * If the grouping hash is an error instance, the normalized error message is used as the grouping hash.
835
841
  * If the grouping hash is an empty string or not specified, the default grouping hash is used.
@@ -869,8 +875,8 @@ if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCE
869
875
  // https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash
870
876
  // https://docs.bugsnag.com/product/error-grouping/#user_defined
871
877
  const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,this.logger);// Get the final payload to be sent to the metrics service
872
- const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);// send it to metrics service
873
- this.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state,category),sendRawData:true},isRawResponse:true});}}// Log handled errors and errors dispatched by the SDK
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
874
880
  if(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}}catch(err){// If an error occurs while handling an error, log it
875
881
  this.logger.error(HANDLE_ERROR_FAILURE(ERROR_HANDLER),err);}}/**
876
882
  * Add breadcrumbs to add insight of a user's journey before an error
@@ -956,7 +962,7 @@ const userIdKey='rl_user_id';const userTraitsKey='rl_trait';const anonymousUserI
956
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;};
957
963
 
958
964
  const EVENT_PAYLOAD_SIZE_BYTES_LIMIT=32*1024;// 32 KB
959
- const RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;const INTEGRATIONS_ERROR_CATEGORY='integrations';
965
+ const RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;
960
966
 
961
967
  const isStorageQuotaExceeded=e=>{const matchingNames=['QuotaExceededError','NS_ERROR_DOM_QUOTA_REACHED'];// Everything except Firefox, Firefox
962
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
@@ -2879,7 +2885,8 @@ this.swapQueueStoreToInMemoryEngine();// and save it there
2879
2885
  this.set(key,value);}else {const customMessage=STORE_DATA_SAVE_ERROR(key);this.onError(err,customMessage,customMessage);}}}/**
2880
2886
  * Get by Key.
2881
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
2882
- return JSON.parse(decryptedValue);}catch(err){const customMessage=STORE_DATA_FETCH_ERROR(key);this.onError(err,customMessage,customMessage);return null;}}/**
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;}}/**
2883
2890
  * Remove by Key.
2884
2891
  */remove(key){const validKey=this.createValidKey(key);if(validKey){this.engine.removeItem(validKey);}}/**
2885
2892
  * Get original engine
@@ -3565,7 +3572,7 @@ E(()=>{const areAllDestinationsReady=totalDestinationsToLoad===0||state.nativeDe
3565
3572
  */// eslint-disable-next-line class-methods-use-this
3566
3573
  onDestinationsReady(){// May be do any destination specific actions here
3567
3574
  // Mark the ready status if not already done
3568
- 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
3569
3576
  // Start consumer exposed methods
3570
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;}/**
3571
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.27.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';
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';const DEFAULT_ERROR_CATEGORY='sdk';
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,12 +820,18 @@ 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.stacktrace[0]?.file;if(!errorOrigin||typeof errorOrigin!=='string'){return false;}const srcFileName=errorOrigin.substring(errorOrigin.lastIndexOf('/')+1);const paths=errorOrigin.split('/');// extract the parent folder name from the error origin file path
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
836
  * If the grouping hash is an error instance, the normalized error message is used as the grouping hash.
831
837
  * If the grouping hash is an empty string or not specified, the default grouping hash is used.
@@ -865,8 +871,8 @@ if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCE
865
871
  // https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash
866
872
  // https://docs.bugsnag.com/product/error-grouping/#user_defined
867
873
  const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,this.logger);// Get the final payload to be sent to the metrics service
868
- const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);// send it to metrics service
869
- this.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state,category),sendRawData:true},isRawResponse:true});}}// Log handled errors and errors dispatched by the SDK
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
870
876
  if(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}}catch(err){// If an error occurs while handling an error, log it
871
877
  this.logger.error(HANDLE_ERROR_FAILURE(ERROR_HANDLER),err);}}/**
872
878
  * Add breadcrumbs to add insight of a user's journey before an error
@@ -952,7 +958,7 @@ const userIdKey='rl_user_id';const userTraitsKey='rl_trait';const anonymousUserI
952
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;};
953
959
 
954
960
  const EVENT_PAYLOAD_SIZE_BYTES_LIMIT=32*1024;// 32 KB
955
- const RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;const INTEGRATIONS_ERROR_CATEGORY='integrations';
961
+ const RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;
956
962
 
957
963
  const isStorageQuotaExceeded=e=>{const matchingNames=['QuotaExceededError','NS_ERROR_DOM_QUOTA_REACHED'];// Everything except Firefox, Firefox
958
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
@@ -2875,7 +2881,8 @@ this.swapQueueStoreToInMemoryEngine();// and save it there
2875
2881
  this.set(key,value);}else {const customMessage=STORE_DATA_SAVE_ERROR(key);this.onError(err,customMessage,customMessage);}}}/**
2876
2882
  * Get by Key.
2877
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
2878
- return JSON.parse(decryptedValue);}catch(err){const customMessage=STORE_DATA_FETCH_ERROR(key);this.onError(err,customMessage,customMessage);return null;}}/**
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;}}/**
2879
2886
  * Remove by Key.
2880
2887
  */remove(key){const validKey=this.createValidKey(key);if(validKey){this.engine.removeItem(validKey);}}/**
2881
2888
  * Get original engine
@@ -3561,7 +3568,7 @@ E(()=>{const areAllDestinationsReady=totalDestinationsToLoad===0||state.nativeDe
3561
3568
  */// eslint-disable-next-line class-methods-use-this
3562
3569
  onDestinationsReady(){// May be do any destination specific actions here
3563
3570
  // Mark the ready status if not already done
3564
- 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
3565
3572
  // Start consumer exposed methods
3566
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;}/**
3567
3574
  * If destinations are loaded or no integration is available for loading