@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.
@@ -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
@@ -506,7 +506,7 @@ error.stack=`${stack}\n${MANUAL_ERROR_IDENTIFIER}`;break;case stacktrace:// esli
506
506
  error.stacktrace=`${stacktrace}\n${MANUAL_ERROR_IDENTIFIER}`;break;case operaSourceloc:default:// eslint-disable-next-line no-param-reassign
507
507
  error['opera#sourceloc']=`${operaSourceloc}\n${MANUAL_ERROR_IDENTIFIER}`;break;}}}globalThis.dispatchEvent(new ErrorEvent('error',{error,bubbles:true,cancelable:true,composed:true}));};
508
508
 
509
- 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';
509
+ 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';
510
510
 
511
511
  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';
512
512
 
@@ -729,7 +729,7 @@ try{if(JSON.stringify(f)==='{}')return accum;return accum.concat(f);}catch{retur
729
729
  * Utility to parse XHR JSON response
730
730
  */const responseTextToJson=(responseText,onError)=>{try{return JSON.parse(responseText||'');}catch(err){const error=getMutatedError(err,'Failed to parse response data');onError(error);}return undefined;};
731
731
 
732
- 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];
732
+ 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;
733
733
 
734
734
  const DEFAULT_XHR_REQUEST_OPTIONS={headers:{Accept:'application/json','Content-Type':'application/json;charset=UTF-8'},method:'GET'};/**
735
735
  * Utility to create request configuration based on default options
@@ -765,7 +765,7 @@ const SDK_FILE_NAME_PREFIXES=()=>['rsa'// Prefix for all the SDK scripts includi
765
765
  // Potential PII or sensitive data
766
766
  const APP_STATE_EXCLUDE_KEYS=['userId','userTraits','groupId','groupTraits','anonymousId','config','integration',// integration instance objects
767
767
  'eventBuffer',// pre-load event buffer (may contain PII)
768
- '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';
768
+ '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';
769
769
 
770
770
  const detectAdBlockers=httpClient=>{state.capabilities.isAdBlockerDetectionInProgress.value=true;try{// Apparently, '?view=ad' is a query param that is blocked by majority of adblockers
771
771
  // Use source config URL here as it is very unlikely to be blocked by adblockers
@@ -811,12 +811,18 @@ if(state.capabilities.cspBlockedURLs.value.includes(extractedURL)){resolve(false
811
811
  checkIfAdBlockersAreActive(state,httpClient,resolve);}}else {// Filter out errors that are not from the RS CDN.
812
812
  resolve(false);}}else {// Allow the error to be notified if no URL could be extracted from the error message
813
813
  resolve(true);}}else {resolve(!ERROR_MESSAGES_TO_BE_FILTERED.some(e=>e.test(errMsg)));}});};/**
814
+ * A function to get the directory name from a file path.
815
+ * @param {string} filePath The file path
816
+ * @returns The directory name or undefined if the file path is invalid
817
+ */const getDirectoryName=filePath=>{if(!filePath){return undefined;}const paths=filePath.split('/');return paths.at(-2);};/**
818
+ * A function to get the top stack path from the exception.
819
+ * @param {Exception} exception The exception object
820
+ * @returns The top stack path or undefined if the exception is invalid
821
+ */const getTopStackPath=exception=>{const errorOrigin=exception.stacktrace[0]?.file;if(!errorOrigin||typeof errorOrigin!=='string'){return undefined;}return errorOrigin;};/**
814
822
  * A function to determine if the error is from Rudder SDK
815
823
  * @param {Error} exception
816
824
  * @returns
817
- */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
818
- // Ex: parentFolderName will be 'sample' for url: https://example.com/sample/file.min.js
819
- 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);};/**
825
+ */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);};/**
820
826
  * A function to get the grouping hash value to be used for the error event.
821
827
  * If the grouping hash is an error instance, the normalized error message is used as the grouping hash.
822
828
  * If the grouping hash is an empty string or not specified, the default grouping hash is used.
@@ -856,8 +862,8 @@ if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCE
856
862
  // https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash
857
863
  // https://docs.bugsnag.com/product/error-grouping/#user_defined
858
864
  const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,this.logger);// Get the final payload to be sent to the metrics service
859
- const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);// send it to metrics service
860
- 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
865
+ const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);const errorCategory=getErrorCategory(bsException,category);// send it to metrics service
866
+ 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
861
867
  if(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}}catch(err){// If an error occurs while handling an error, log it
862
868
  this.logger.error(HANDLE_ERROR_FAILURE(ERROR_HANDLER),err);}}/**
863
869
  * Add breadcrumbs to add insight of a user's journey before an error
@@ -1150,7 +1156,8 @@ this.swapQueueStoreToInMemoryEngine();// and save it there
1150
1156
  this.set(key,value);}else {const customMessage=STORE_DATA_SAVE_ERROR(key);this.onError(err,customMessage,customMessage);}}}/**
1151
1157
  * Get by Key.
1152
1158
  */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
1153
- return JSON.parse(decryptedValue);}catch(err){const customMessage=STORE_DATA_FETCH_ERROR(key);this.onError(err,customMessage,customMessage);return null;}}/**
1159
+ 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
1160
+ 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;}}/**
1154
1161
  * Remove by Key.
1155
1162
  */remove(key){const validKey=this.createValidKey(key);if(validKey){this.engine.removeItem(validKey);}}/**
1156
1163
  * Get original engine
@@ -1853,7 +1860,7 @@ E(()=>{const areAllDestinationsReady=totalDestinationsToLoad===0||state.nativeDe
1853
1860
  */// eslint-disable-next-line class-methods-use-this
1854
1861
  onDestinationsReady(){// May be do any destination specific actions here
1855
1862
  // Mark the ready status if not already done
1856
- if(state.lifecycle.status.value!=='ready'){state.lifecycle.status.value='ready';}}// End lifecycle methods
1863
+ if(state.lifecycle.status.value!=='ready'){r(()=>{state.lifecycle.status.value='ready';});}}// End lifecycle methods
1857
1864
  // Start consumer exposed methods
1858
1865
  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;}/**
1859
1866
  * If destinations are loaded or no integration is available for loading
@@ -512,7 +512,7 @@
512
512
  error.stacktrace=`${stacktrace}\n${MANUAL_ERROR_IDENTIFIER}`;break;case operaSourceloc:default:// eslint-disable-next-line no-param-reassign
513
513
  error['opera#sourceloc']=`${operaSourceloc}\n${MANUAL_ERROR_IDENTIFIER}`;break;}}}globalThis.dispatchEvent(new ErrorEvent('error',{error,bubbles:true,cancelable:true,composed:true}));};
514
514
 
515
- 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';
515
+ 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';
516
516
 
517
517
  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';
518
518
 
@@ -735,7 +735,7 @@
735
735
  * Utility to parse XHR JSON response
736
736
  */const responseTextToJson=(responseText,onError)=>{try{return JSON.parse(responseText||'');}catch(err){const error=getMutatedError(err,'Failed to parse response data');onError(error);}return undefined;};
737
737
 
738
- 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];
738
+ 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;
739
739
 
740
740
  const DEFAULT_XHR_REQUEST_OPTIONS={headers:{Accept:'application/json','Content-Type':'application/json;charset=UTF-8'},method:'GET'};/**
741
741
  * Utility to create request configuration based on default options
@@ -771,7 +771,7 @@
771
771
  // Potential PII or sensitive data
772
772
  const APP_STATE_EXCLUDE_KEYS=['userId','userTraits','groupId','groupTraits','anonymousId','config','integration',// integration instance objects
773
773
  'eventBuffer',// pre-load event buffer (may contain PII)
774
- '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';
774
+ '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';
775
775
 
776
776
  const detectAdBlockers=httpClient=>{state.capabilities.isAdBlockerDetectionInProgress.value=true;try{// Apparently, '?view=ad' is a query param that is blocked by majority of adblockers
777
777
  // Use source config URL here as it is very unlikely to be blocked by adblockers
@@ -817,12 +817,18 @@
817
817
  checkIfAdBlockersAreActive(state,httpClient,resolve);}}else {// Filter out errors that are not from the RS CDN.
818
818
  resolve(false);}}else {// Allow the error to be notified if no URL could be extracted from the error message
819
819
  resolve(true);}}else {resolve(!ERROR_MESSAGES_TO_BE_FILTERED.some(e=>e.test(errMsg)));}});};/**
820
+ * A function to get the directory name from a file path.
821
+ * @param {string} filePath The file path
822
+ * @returns The directory name or undefined if the file path is invalid
823
+ */const getDirectoryName=filePath=>{if(!filePath){return undefined;}const paths=filePath.split('/');return paths.at(-2);};/**
824
+ * A function to get the top stack path from the exception.
825
+ * @param {Exception} exception The exception object
826
+ * @returns The top stack path or undefined if the exception is invalid
827
+ */const getTopStackPath=exception=>{const errorOrigin=exception.stacktrace[0]?.file;if(!errorOrigin||typeof errorOrigin!=='string'){return undefined;}return errorOrigin;};/**
820
828
  * A function to determine if the error is from Rudder SDK
821
829
  * @param {Error} exception
822
830
  * @returns
823
- */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
824
- // Ex: parentFolderName will be 'sample' for url: https://example.com/sample/file.min.js
825
- 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);};/**
831
+ */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);};/**
826
832
  * A function to get the grouping hash value to be used for the error event.
827
833
  * If the grouping hash is an error instance, the normalized error message is used as the grouping hash.
828
834
  * If the grouping hash is an empty string or not specified, the default grouping hash is used.
@@ -862,8 +868,8 @@
862
868
  // https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash
863
869
  // https://docs.bugsnag.com/product/error-grouping/#user_defined
864
870
  const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,this.logger);// Get the final payload to be sent to the metrics service
865
- const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);// send it to metrics service
866
- 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
871
+ const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);const errorCategory=getErrorCategory(bsException,category);// send it to metrics service
872
+ 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
867
873
  if(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}}catch(err){// If an error occurs while handling an error, log it
868
874
  this.logger.error(HANDLE_ERROR_FAILURE(ERROR_HANDLER),err);}}/**
869
875
  * Add breadcrumbs to add insight of a user's journey before an error
@@ -1156,7 +1162,8 @@
1156
1162
  this.set(key,value);}else {const customMessage=STORE_DATA_SAVE_ERROR(key);this.onError(err,customMessage,customMessage);}}}/**
1157
1163
  * Get by Key.
1158
1164
  */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
1159
- return JSON.parse(decryptedValue);}catch(err){const customMessage=STORE_DATA_FETCH_ERROR(key);this.onError(err,customMessage,customMessage);return null;}}/**
1165
+ 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
1166
+ 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;}}/**
1160
1167
  * Remove by Key.
1161
1168
  */remove(key){const validKey=this.createValidKey(key);if(validKey){this.engine.removeItem(validKey);}}/**
1162
1169
  * Get original engine
@@ -1859,7 +1866,7 @@
1859
1866
  */// eslint-disable-next-line class-methods-use-this
1860
1867
  onDestinationsReady(){// May be do any destination specific actions here
1861
1868
  // Mark the ready status if not already done
1862
- if(state.lifecycle.status.value!=='ready'){state.lifecycle.status.value='ready';}}// End lifecycle methods
1869
+ if(state.lifecycle.status.value!=='ready'){r(()=>{state.lifecycle.status.value='ready';});}}// End lifecycle methods
1863
1870
  // Start consumer exposed methods
1864
1871
  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;}/**
1865
1872
  * If destinations are loaded or no integration is available for loading
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rudderstack/analytics-js",
3
- "version": "3.27.0",
3
+ "version": "3.28.0",
4
4
  "description": "RudderStack JavaScript SDK",
5
5
  "main": "dist/npm/modern/cjs/index.cjs",
6
6
  "module": "dist/npm/modern/esm/index.mjs",