@rudderstack/analytics-js 3.25.1 → 3.27.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.
@@ -914,7 +914,7 @@
914
914
  error.stacktrace="".concat(stacktrace,"\n").concat(MANUAL_ERROR_IDENTIFIER);break;case operaSourceloc:default:// eslint-disable-next-line no-param-reassign
915
915
  error['opera#sourceloc']="".concat(operaSourceloc,"\n").concat(MANUAL_ERROR_IDENTIFIER);break;}}}globalThis.dispatchEvent(new ErrorEvent('error',{error:error,bubbles:true,cancelable:true,composed:true}));};
916
916
 
917
- var APP_NAME='RudderLabs JavaScript SDK';var APP_VERSION='3.25.1';var APP_NAMESPACE='com.rudderlabs.javascript';var MODULE_TYPE='npm';var ADBLOCK_PAGE_CATEGORY='RudderJS-Initiated';var ADBLOCK_PAGE_NAME='ad-block page request';var ADBLOCK_PAGE_PATH='/ad-blocked';var GLOBAL_PRELOAD_BUFFER='preloadedEventsBuffer';var CONSENT_TRACK_EVENT_NAME='Consent Management Interaction';
917
+ var APP_NAME='RudderLabs JavaScript SDK';var APP_VERSION='3.27.0';var APP_NAMESPACE='com.rudderlabs.javascript';var MODULE_TYPE='npm';var ADBLOCK_PAGE_CATEGORY='RudderJS-Initiated';var ADBLOCK_PAGE_NAME='ad-block page request';var ADBLOCK_PAGE_PATH='/ad-blocked';var GLOBAL_PRELOAD_BUFFER='preloadedEventsBuffer';var CONSENT_TRACK_EVENT_NAME='Consent Management Interaction';
918
918
 
919
919
  var QUERY_PARAM_TRAIT_PREFIX='ajs_trait_';var QUERY_PARAM_PROPERTY_PREFIX='ajs_prop_';var QUERY_PARAM_ANONYMOUS_ID_KEY='ajs_aid';var QUERY_PARAM_USER_ID_KEY='ajs_uid';var QUERY_PARAM_TRACK_EVENT_NAME_KEY='ajs_event';
920
920
 
@@ -942,8 +942,9 @@
942
942
  * Parse query string into preload buffer events & push into existing array before any other events
943
943
  */var retrieveEventsFromQueryString=function retrieveEventsFromQueryString(){var argumentsArray=arguments.length>0&&arguments[0]!==undefined?arguments[0]:[];// Mapping for trait and properties values based on key prefix
944
944
  var eventArgumentToQueryParamMap={trait:QUERY_PARAM_TRAIT_PREFIX,properties:QUERY_PARAM_PROPERTY_PREFIX};var queryObject=new URLSearchParams(globalThis.location.search);// Add track events with name and properties
945
- if(queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY)){argumentsArray.unshift(['track',queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY),getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.properties)]);}// Set userId and user traits
946
- if(queryObject.get(QUERY_PARAM_USER_ID_KEY)){argumentsArray.unshift(['identify',queryObject.get(QUERY_PARAM_USER_ID_KEY),getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.trait)]);}// Set anonymousID
945
+ if(queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY)){argumentsArray.unshift(['track',queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY),getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.properties)]);}// Send identify event
946
+ var userId=queryObject.get(QUERY_PARAM_USER_ID_KEY);var userTraits=getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.trait);if(userId||isNonEmptyObject(userTraits)){// In identify API, user ID is optional
947
+ var identifyApiArgs=[].concat(_toConsumableArray(userId?[userId]:[]),[userTraits]);argumentsArray.unshift(['identify'].concat(_toConsumableArray(identifyApiArgs)));}// Set anonymousID
947
948
  if(queryObject.get(QUERY_PARAM_ANONYMOUS_ID_KEY)){argumentsArray.unshift(['setAnonymousId',queryObject.get(QUERY_PARAM_ANONYMOUS_ID_KEY)]);}};/**
948
949
  * Retrieve an existing buffered load method call and remove from the existing array
949
950
  */var getPreloadedLoadEvent=function getPreloadedLoadEvent(preloadedEventsArray){var loadMethodName='load';var loadEvent=[];/**
@@ -1223,16 +1224,14 @@
1223
1224
  // Ex: parentFolderName will be 'sample' for url: https://example.com/sample/file.min.js
1224
1225
  var parentFolderName=paths[paths.length-2];return parentFolderName===CDN_INT_DIR||SDK_FILE_NAME_PREFIXES().some(function(prefix){return srcFileName.startsWith(prefix)&&srcFileName.endsWith('.js');});};var getErrorDeliveryPayload=function getErrorDeliveryPayload(payload,state,category){var data={version:METRICS_PAYLOAD_VERSION,message_id:generateUUID(),source:{name:SOURCE_NAME,sdk_version:state.context.app.value.version,write_key:state.lifecycle.writeKey.value,install_type:state.context.app.value.installType,category:category!==null&&category!==void 0?category:DEFAULT_ERROR_CATEGORY},errors:payload};return stringifyWithoutCircular(data);};/**
1225
1226
  * A function to get the grouping hash value to be used for the error event.
1226
- * Grouping hash is suppressed for non-cdn installs.
1227
1227
  * If the grouping hash is an error instance, the normalized error message is used as the grouping hash.
1228
1228
  * If the grouping hash is an empty string or not specified, the default grouping hash is used.
1229
1229
  * If the grouping hash is a string, it is used as is.
1230
1230
  * @param curErrGroupingHash The grouping hash value part of the error event
1231
1231
  * @param defaultGroupingHash The default grouping hash value. It is the error message.
1232
- * @param state The application state
1233
1232
  * @param logger The logger instance
1234
1233
  * @returns The final grouping hash value to be used for the error event
1235
- */var getErrorGroupingHash=function getErrorGroupingHash(curErrGroupingHash,defaultGroupingHash,state,logger){var normalizedGroupingHash;if(state.context.app.value.installType!=='cdn'){return normalizedGroupingHash;}if(!isDefined(curErrGroupingHash)){normalizedGroupingHash=defaultGroupingHash;}else if(isString(curErrGroupingHash)){normalizedGroupingHash=curErrGroupingHash;}else {var normalizedErrorInstance=normalizeError(curErrGroupingHash,logger);if(isDefined(normalizedErrorInstance)){normalizedGroupingHash=normalizedErrorInstance.message;}else {normalizedGroupingHash=defaultGroupingHash;}}return normalizedGroupingHash;};
1234
+ */var getErrorGroupingHash=function getErrorGroupingHash(curErrGroupingHash,defaultGroupingHash,logger){var normalizedGroupingHash;if(!isDefined(curErrGroupingHash)){normalizedGroupingHash=defaultGroupingHash;}else if(isString(curErrGroupingHash)){normalizedGroupingHash=curErrGroupingHash;}else {var normalizedErrorInstance=normalizeError(curErrGroupingHash,logger);if(isDefined(normalizedErrorInstance)){normalizedGroupingHash=normalizedErrorInstance.message;}else {normalizedGroupingHash=defaultGroupingHash;}}return normalizedGroupingHash;};
1236
1235
 
1237
1236
  /**
1238
1237
  * A service to handle errors
@@ -1256,13 +1255,13 @@
1256
1255
  */},{key:"onError",value:(function(){var _onError=_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(errorInfo){var _errorInfo$errorType,error,context,customMessage,groupingHash,category,errorType,errInstance,normalizedError,customMsgVal,errorMsgPrefix,bsException,stacktrace,isSdkDispatched,isAllowed,errorState,normalizedGroupingHash,bugsnagPayload,_t;return _regenerator().w(function(_context){while(1)switch(_context.p=_context.n){case 0:_context.p=0;error=errorInfo.error,context=errorInfo.context,customMessage=errorInfo.customMessage,groupingHash=errorInfo.groupingHash,category=errorInfo.category;errorType=(_errorInfo$errorType=errorInfo.errorType)!==null&&_errorInfo$errorType!==void 0?_errorInfo$errorType:ErrorType.HANDLEDEXCEPTION;errInstance=getErrInstance(error,errorType);normalizedError=normalizeError(errInstance,this.logger);if(!isUndefined(normalizedError)){_context.n=1;break;}return _context.a(2);case 1:customMsgVal=customMessage?"".concat(customMessage," - "):'';errorMsgPrefix="".concat(context).concat(LOG_CONTEXT_SEPARATOR).concat(customMsgVal);bsException=createBugsnagException(normalizedError,errorMsgPrefix);stacktrace=getStacktrace(normalizedError);isSdkDispatched=stacktrace.includes(MANUAL_ERROR_IDENTIFIER);// Filter errors that are not originated in the SDK.
1257
1256
  // In case of NPM installations, the unhandled errors from the SDK cannot be identified
1258
1257
  // and will NOT be reported unless they occur in plugins or integrations.
1259
- if(!(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCEPTION)){_context.n=2;break;}return _context.a(2);case 2:if(!state.reporting.isErrorReportingEnabled.value){_context.n=4;break;}_context.n=3;return checkIfAllowedToBeNotified(bsException,state,this.httpClient);case 3:isAllowed=_context.v;if(isAllowed){errorState={severity:'error',unhandled:errorType!==ErrorType.HANDLEDEXCEPTION,severityReason:{type:errorType}};// Set grouping hash only for CDN installations (as an experiment)
1260
- // This will allow us to group errors by the message instead of the surrounding code.
1261
- // In case of NPM installations, the default grouping by surrounding code does not make sense as each user application is different.
1258
+ if(!(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCEPTION)){_context.n=2;break;}return _context.a(2);case 2:if(!state.reporting.isErrorReportingEnabled.value){_context.n=4;break;}_context.n=3;return checkIfAllowedToBeNotified(bsException,state,this.httpClient);case 3:isAllowed=_context.v;if(isAllowed){errorState={severity:'error',unhandled:errorType!==ErrorType.HANDLEDEXCEPTION,severityReason:{type:errorType}};// This will allow custom grouping of errors.
1259
+ // In case of NPM installations, the default grouping by surrounding code
1260
+ // does not make sense as each user application is different and will create a lot of noise in the alerts.
1262
1261
  // References:
1263
1262
  // https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash
1264
1263
  // https://docs.bugsnag.com/product/error-grouping/#user_defined
1265
- normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,state,this.logger);// Get the final payload to be sent to the metrics service
1264
+ normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,this.logger);// Get the final payload to be sent to the metrics service
1266
1265
  bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);// send it to metrics service
1267
1266
  this.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state,category),sendRawData:true},isRawResponse:true});}case 4:// Log handled errors and errors dispatched by the SDK
1268
1267
  if(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}_context.n=6;break;case 5:_context.p=5;_t=_context.v;// If an error occurs while handling an error, log it
@@ -3715,7 +3714,9 @@
3715
3714
  * @param event Incoming event data
3716
3715
  */},{key:"addEvent",value:function addEvent(event){this.userSessionManager.refreshSession();var rudderEvent=this.eventFactory.create(event);this.eventRepository.enqueue(rudderEvent,event.callback);}}]);}();
3717
3716
 
3718
- var UserSessionManager=/*#__PURE__*/function(){function UserSessionManager(pluginsManager,storeManager,httpClient,errorHandler,logger){_classCallCheck(this,UserSessionManager);this.storeManager=storeManager;this.pluginsManager=pluginsManager;this.logger=logger;this.errorHandler=errorHandler;this.httpClient=httpClient;this.onError=this.onError.bind(this);this.serverSideCookieDebounceFuncs={};}/**
3717
+ var UserSessionManager=/*#__PURE__*/function(){/**
3718
+ * Tracks whether a server-side cookie setting request is in progress or not.
3719
+ */function UserSessionManager(pluginsManager,storeManager,httpClient,errorHandler,logger){_classCallCheck(this,UserSessionManager);this.storeManager=storeManager;this.pluginsManager=pluginsManager;this.logger=logger;this.errorHandler=errorHandler;this.httpClient=httpClient;this.onError=this.onError.bind(this);this.serverSideCookieDebounceFuncs={};this.serverSideCookiesRequestInProgress={};}/**
3719
3720
  * Initialize User session with values from storage
3720
3721
  */return _createClass(UserSessionManager,[{key:"init",value:function init(){this.syncStorageDataToState();// Register the effect to sync with storage
3721
3722
  this.registerEffects();}},{key:"syncStorageDataToState",value:function syncStorageDataToState(){this.migrateStorageIfNeeded();this.migrateDataFromPreviousStorage();// get the values from storage and set it again
@@ -3745,20 +3746,31 @@
3745
3746
  * @param callback
3746
3747
  */},{key:"makeRequestToSetCookie",value:function makeRequestToSetCookie(encryptedCookieData,callback){var _this$httpClient,_state$source$value,_state$storage$cookie,_state$storage$cookie2,_state$storage$cookie3,_state$storage$cookie4,_state$storage$cookie5,_state$storage$cookie6;(_this$httpClient=this.httpClient)===null||_this$httpClient===void 0||_this$httpClient.getAsyncData({url:state.serverCookies.dataServiceUrl.value,options:{method:'POST',data:stringifyWithoutCircular({reqType:'setCookies',workspaceId:(_state$source$value=state.source.value)===null||_state$source$value===void 0?void 0:_state$source$value.workspaceId,data:{options:{maxAge:(_state$storage$cookie=state.storage.cookie.value)===null||_state$storage$cookie===void 0?void 0:_state$storage$cookie.maxage,path:(_state$storage$cookie2=state.storage.cookie.value)===null||_state$storage$cookie2===void 0?void 0:_state$storage$cookie2.path,domain:(_state$storage$cookie3=state.storage.cookie.value)===null||_state$storage$cookie3===void 0?void 0:_state$storage$cookie3.domain,sameSite:(_state$storage$cookie4=state.storage.cookie.value)===null||_state$storage$cookie4===void 0?void 0:_state$storage$cookie4.samesite,secure:(_state$storage$cookie5=state.storage.cookie.value)===null||_state$storage$cookie5===void 0?void 0:_state$storage$cookie5.secure,expires:(_state$storage$cookie6=state.storage.cookie.value)===null||_state$storage$cookie6===void 0?void 0:_state$storage$cookie6.expires},cookies:encryptedCookieData}}),sendRawData:true,withCredentials:true},isRawResponse:true,callback:callback});}/**
3747
3748
  * A function to make an external request to set the cookie from server side
3748
- * @param key cookie name
3749
- * @param value encrypted cookie value
3750
- */},{key:"setServerSideCookies",value:function setServerSideCookies(cookiesData,cb,store){var _this4=this;try{// encrypt cookies values
3751
- var encryptedCookieData=this.getEncryptedCookieData(cookiesData,store);if(encryptedCookieData.length>0){// make request to data service to set the cookie from server side
3752
- this.makeRequestToSetCookie(encryptedCookieData,function(res,details){var _details$xhr;if((details===null||details===void 0||(_details$xhr=details.xhr)===null||_details$xhr===void 0?void 0:_details$xhr.status)===200){cookiesData.forEach(function(cData){var cookieValue=store===null||store===void 0?void 0:store.get(cData.name);var before=stringifyWithoutCircular(cData.value,false,[]);var after=stringifyWithoutCircular(cookieValue,false,[]);if(after!==before){_this4.logger.error(FAILED_SETTING_COOKIE_FROM_SERVER_ERROR(cData.name));if(cb){cb(cData.name,cData.value);}}});}else {var _details$xhr2;_this4.logger.error(DATA_SERVER_REQUEST_FAIL_ERROR(details===null||details===void 0||(_details$xhr2=details.xhr)===null||_details$xhr2===void 0?void 0:_details$xhr2.status));cookiesData.forEach(function(each){if(cb){cb(each.name,each.value);}});}});}}catch(e){this.onError(e,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR);cookiesData.forEach(function(each){if(cb){cb(each.name,each.value);}});}}/**
3749
+ * @param sessionToCookiesMap map of session key to cookie name
3750
+ * @param cb callback function to be called when the cookie is set
3751
+ * @param store store to be used to get the cookie value
3752
+ */},{key:"setServerSideCookies",value:function setServerSideCookies(sessionToCookiesMap,cb,store){var _this4=this;// Retrieve the cookie value from the state
3753
+ var sessionKeys=Object.keys(sessionToCookiesMap);var getCurrentCookieValuesFromState=function getCurrentCookieValuesFromState(){return sessionKeys.map(function(sessionKey){return {name:sessionToCookiesMap[sessionKey].name,value:state.session[sessionKey].value};});};// Preserve the current cookie values
3754
+ var originalCookieValues={};sessionKeys.forEach(function(sessionKey){originalCookieValues[sessionToCookiesMap[sessionKey].name]=store===null||store===void 0?void 0:store.get(sessionToCookiesMap[sessionKey].name);});var clearInProgressFlags=function clearInProgressFlags(){sessionKeys.forEach(function(sessionKey){_this4.serverSideCookiesRequestInProgress[sessionKey]=false;});};var setCookiesClientSide=function setCookiesClientSide(){getCurrentCookieValuesFromState().forEach(function(each){if(cb){cb(each.name,each.value);}});};try{var expectedCookieValues={};sessionKeys.forEach(function(sessionKey){expectedCookieValues[sessionToCookiesMap[sessionKey].name]=state.session[sessionKey].value;});// encrypt cookies values
3755
+ var encryptedCookieData=this.getEncryptedCookieData(getCurrentCookieValuesFromState(),store);if(encryptedCookieData.length>0){// make request to data service to set the cookie from server side
3756
+ this.makeRequestToSetCookie(encryptedCookieData,function(res,details){var _details$xhr;// Mark the cookie req status as done
3757
+ clearInProgressFlags();if((details===null||details===void 0||(_details$xhr=details.xhr)===null||_details$xhr===void 0?void 0:_details$xhr.status)===200){getCurrentCookieValuesFromState().forEach(function(cData){var originalCookieVal=originalCookieValues[cData.name];var currentCookieVal=store===null||store===void 0?void 0:store.get(cData.name);// Check if the expected cookie values are set.
3758
+ if(stringifyWithoutCircular(expectedCookieValues[cData.name],false,[])!==stringifyWithoutCircular(currentCookieVal,false,[])){// It's fine if the values don't match as other active SDK sessions might have updated the cookie values
3759
+ // or other cookie requests might have updated the cookie value.
3760
+ // Log an error only when cookie didn't exist previously and currently also doesn't exist.
3761
+ if(isNull(originalCookieVal)&&isNull(currentCookieVal)){_this4.logger.error(FAILED_SETTING_COOKIE_FROM_SERVER_ERROR(cData.name));}if(cb){cb(cData.name,cData.value);}}});}else {var _details$xhr2;_this4.logger.error(DATA_SERVER_REQUEST_FAIL_ERROR(details===null||details===void 0||(_details$xhr2=details.xhr)===null||_details$xhr2===void 0?void 0:_details$xhr2.status));setCookiesClientSide();}});}else {setCookiesClientSide();// Mark the cookie req status as done
3762
+ clearInProgressFlags();}}catch(e){this.onError(e,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR);setCookiesClientSide();// Mark the cookie req status as done
3763
+ clearInProgressFlags();}}/**
3753
3764
  * A function to sync values in storage
3754
3765
  * @param sessionKey
3755
- * @param value
3756
- */},{key:"syncValueToStorage",value:function syncValueToStorage(sessionKey,value){var _entries$sessionKey,_this5=this;var entries=state.storage.entries.value;var storageType=(_entries$sessionKey=entries[sessionKey])===null||_entries$sessionKey===void 0?void 0:_entries$sessionKey.type;if(isStorageTypeValidForStoringData(storageType)){var _this$storeManager3,_entries$sessionKey2;var curStore=(_this$storeManager3=this.storeManager)===null||_this$storeManager3===void 0?void 0:_this$storeManager3.getStore(storageClientDataStoreNameMap[storageType]);var key=(_entries$sessionKey2=entries[sessionKey])===null||_entries$sessionKey2===void 0?void 0:_entries$sessionKey2.key;if(value&&(isString(value)||isNonEmptyObject(value))){// if useServerSideCookies load option is set to true
3766
+ */},{key:"syncValueToStorage",value:function syncValueToStorage(sessionKey){var _entries$sessionKey,_this5=this;var entries=state.storage.entries.value;var storageType=(_entries$sessionKey=entries[sessionKey])===null||_entries$sessionKey===void 0?void 0:_entries$sessionKey.type;if(isStorageTypeValidForStoringData(storageType)){var _entries$sessionKey2;var curStore=this.storeManager.getStore(storageClientDataStoreNameMap[storageType]);var cookieName=(_entries$sessionKey2=entries[sessionKey])===null||_entries$sessionKey2===void 0?void 0:_entries$sessionKey2.key;var cookieValue=state.session[sessionKey].value;if(cookieValue&&(isString(cookieValue)||isNonEmptyObject(cookieValue))){// if useServerSideCookies load option is set to true
3757
3767
  // set the cookie from server side
3758
- if(state.serverCookies.isEnabledServerSideCookies.value&&storageType===COOKIE_STORAGE){if(this.serverSideCookieDebounceFuncs[sessionKey]){globalThis.clearTimeout(this.serverSideCookieDebounceFuncs[sessionKey]);}this.serverSideCookieDebounceFuncs[sessionKey]=globalThis.setTimeout(function(){_this5.setServerSideCookies([{name:key,value:value}],function(cookieName,cookieValue){curStore===null||curStore===void 0||curStore.set(cookieName,cookieValue);},curStore);},SERVER_SIDE_COOKIES_DEBOUNCE_TIME);}else {curStore===null||curStore===void 0||curStore.set(key,value);}}else {curStore===null||curStore===void 0||curStore.remove(key);}}}/**
3768
+ if(state.serverCookies.isEnabledServerSideCookies.value&&storageType===COOKIE_STORAGE){// Mark the requests as in progress.
3769
+ this.serverSideCookiesRequestInProgress[sessionKey]=true;if(this.serverSideCookieDebounceFuncs[sessionKey]){globalThis.clearTimeout(this.serverSideCookieDebounceFuncs[sessionKey]);}this.serverSideCookieDebounceFuncs[sessionKey]=globalThis.setTimeout(function(){// Create a map of session key to cookie name
3770
+ var sessionToCookiesMap=_defineProperty({},sessionKey,{name:cookieName});_this5.setServerSideCookies(sessionToCookiesMap,function(cookieName,cookieValue){curStore===null||curStore===void 0||curStore.set(cookieName,cookieValue);},curStore);},SERVER_SIDE_COOKIES_DEBOUNCE_TIME);}else {curStore===null||curStore===void 0||curStore.set(cookieName,cookieValue);}}else {curStore===null||curStore===void 0||curStore.remove(cookieName);}}}/**
3759
3771
  * Function to update storage whenever state value changes
3760
3772
  */},{key:"registerEffects",value:function registerEffects(){var _this6=this;// This will work as long as the user session entry key names are same as the state keys
3761
- USER_SESSION_KEYS.forEach(function(sessionKey){E(function(){_this6.syncValueToStorage(sessionKey,state.session[sessionKey].value);});});}/**
3773
+ USER_SESSION_KEYS.forEach(function(sessionKey){E(function(){_this6.syncValueToStorage(sessionKey);});});}/**
3762
3774
  * Sets anonymous id in the following precedence:
3763
3775
  *
3764
3776
  * 1. anonymousId: Id directly provided to the function.
@@ -3771,34 +3783,41 @@
3771
3783
  * @returns anonymousId
3772
3784
  */},{key:"getAnonymousId",value:function getAnonymousId(options){var _state$storage$entrie2;var storage=(_state$storage$entrie2=state.storage.entries.value.anonymousId)===null||_state$storage$entrie2===void 0?void 0:_state$storage$entrie2.type;if(isStorageTypeValidForStoringData(storage)){var persistedAnonymousId=state.session.anonymousId.value;// If the anonymous ID is the default value, fetch it from storage
3773
3785
  if(!persistedAnonymousId||persistedAnonymousId===DEFAULT_USER_SESSION_VALUES.anonymousId){persistedAnonymousId=this.getEntryValue('anonymousId');}if(!persistedAnonymousId&&options){var _this$pluginsManager2;// fetch anonymousId from external source
3774
- var autoCapturedAnonymousId=(_this$pluginsManager2=this.pluginsManager)===null||_this$pluginsManager2===void 0?void 0:_this$pluginsManager2.invokeSingle('storage.getAnonymousId',getStorageEngine,options);persistedAnonymousId=autoCapturedAnonymousId;}state.session.anonymousId.value=persistedAnonymousId||generateAnonymousId();}return state.session.anonymousId.value;}},{key:"getEntryValue",value:function getEntryValue(sessionKey){var _entries$sessionKey3;var entries=state.storage.entries.value;var storageType=(_entries$sessionKey3=entries[sessionKey])===null||_entries$sessionKey3===void 0?void 0:_entries$sessionKey3.type;if(isStorageTypeValidForStoringData(storageType)){var _this$storeManager4,_entries$sessionKey4,_store$get;var store=(_this$storeManager4=this.storeManager)===null||_this$storeManager4===void 0?void 0:_this$storeManager4.getStore(storageClientDataStoreNameMap[storageType]);// Migrate the storage data before fetching the value
3786
+ var autoCapturedAnonymousId=(_this$pluginsManager2=this.pluginsManager)===null||_this$pluginsManager2===void 0?void 0:_this$pluginsManager2.invokeSingle('storage.getAnonymousId',getStorageEngine,options);persistedAnonymousId=autoCapturedAnonymousId;}state.session.anonymousId.value=persistedAnonymousId||generateAnonymousId();}return state.session.anonymousId.value;}},{key:"getEntryValue",value:function getEntryValue(sessionKey){var _entries$sessionKey3;var entries=state.storage.entries.value;var storageType=(_entries$sessionKey3=entries[sessionKey])===null||_entries$sessionKey3===void 0?void 0:_entries$sessionKey3.type;if(isStorageTypeValidForStoringData(storageType)){var _this$storeManager3,_entries$sessionKey4,_store$get;var store=(_this$storeManager3=this.storeManager)===null||_this$storeManager3===void 0?void 0:_this$storeManager3.getStore(storageClientDataStoreNameMap[storageType]);// Migrate the storage data before fetching the value
3775
3787
  // This is needed for entries that are fetched from the storage
3776
3788
  // during the current session (for example, session info)
3777
3789
  this.migrateStorageIfNeeded([store],[sessionKey]);var storageKey=(_entries$sessionKey4=entries[sessionKey])===null||_entries$sessionKey4===void 0?void 0:_entries$sessionKey4.key;return (_store$get=store===null||store===void 0?void 0:store.get(storageKey))!==null&&_store$get!==void 0?_store$get:null;}return null;}},{key:"getExternalAnonymousIdByCookieName",value:function getExternalAnonymousIdByCookieName(key){var storageEngine=getStorageEngine(COOKIE_STORAGE);if(storageEngine!==null&&storageEngine!==void 0&&storageEngine.isEnabled){var _storageEngine$getIte;return (_storageEngine$getIte=storageEngine.getItem(key))!==null&&_storageEngine$getIte!==void 0?_storageEngine$getIte:null;}return null;}/**
3790
+ * Fetches the value for a session key. Preferably from storage, if the server-side
3791
+ * cookies request is not in progress. Otherwise, from the state.
3792
+ * @param sessionKey - The session key to fetch the value for
3793
+ * @returns - The value for the session key
3794
+ */},{key:"getUserSessionValue",value:function getUserSessionValue(sessionKey){// If the server-side cookies request is in progress, fetch the value from the state.
3795
+ if(this.serverSideCookiesRequestInProgress[sessionKey]){return state.session[sessionKey].value;}// Otherwise, fetch the value from storage.
3796
+ return this.getEntryValue(sessionKey);}/**
3778
3797
  * Fetches User Id
3779
3798
  * @returns
3780
- */},{key:"getUserId",value:function getUserId(){return this.getEntryValue('userId');}/**
3799
+ */},{key:"getUserId",value:function getUserId(){return this.getUserSessionValue('userId');}/**
3781
3800
  * Fetches User Traits
3782
3801
  * @returns
3783
- */},{key:"getUserTraits",value:function getUserTraits(){return this.getEntryValue('userTraits');}/**
3802
+ */},{key:"getUserTraits",value:function getUserTraits(){return this.getUserSessionValue('userTraits');}/**
3784
3803
  * Fetches Group Id
3785
3804
  * @returns
3786
- */},{key:"getGroupId",value:function getGroupId(){return this.getEntryValue('groupId');}/**
3805
+ */},{key:"getGroupId",value:function getGroupId(){return this.getUserSessionValue('groupId');}/**
3787
3806
  * Fetches Group Traits
3788
3807
  * @returns
3789
- */},{key:"getGroupTraits",value:function getGroupTraits(){return this.getEntryValue('groupTraits');}/**
3808
+ */},{key:"getGroupTraits",value:function getGroupTraits(){return this.getUserSessionValue('groupTraits');}/**
3790
3809
  * Fetches Initial Referrer
3791
3810
  * @returns
3792
- */},{key:"getInitialReferrer",value:function getInitialReferrer(){return this.getEntryValue('initialReferrer');}/**
3811
+ */},{key:"getInitialReferrer",value:function getInitialReferrer(){return this.getUserSessionValue('initialReferrer');}/**
3793
3812
  * Fetches Initial Referring domain
3794
3813
  * @returns
3795
- */},{key:"getInitialReferringDomain",value:function getInitialReferringDomain(){return this.getEntryValue('initialReferringDomain');}/**
3814
+ */},{key:"getInitialReferringDomain",value:function getInitialReferringDomain(){return this.getUserSessionValue('initialReferringDomain');}/**
3796
3815
  * Fetches session tracking information from storage
3797
3816
  * @returns
3798
- */},{key:"getSessionInfo",value:function getSessionInfo(){return this.getEntryValue('sessionInfo');}/**
3817
+ */},{key:"getSessionInfo",value:function getSessionInfo(){return this.getUserSessionValue('sessionInfo');}/**
3799
3818
  * Fetches auth token from storage
3800
3819
  * @returns
3801
- */},{key:"getAuthToken",value:function getAuthToken(){return this.getEntryValue('authToken');}/**
3820
+ */},{key:"getAuthToken",value:function getAuthToken(){return this.getUserSessionValue('authToken');}/**
3802
3821
  * If session is active it returns the sessionId
3803
3822
  * @returns
3804
3823
  */},{key:"getSessionId",value:function getSessionId(){var _this$getSessionInfo2;var sessionInfo=(_this$getSessionInfo2=this.getSessionInfo())!==null&&_this$getSessionInfo2!==void 0?_this$getSessionInfo2:DEFAULT_USER_SESSION_VALUES.sessionInfo;if(sessionInfo.autoTrack&&!hasSessionExpired(sessionInfo)||sessionInfo.manualTrack){var _sessionInfo$id;return (_sessionInfo$id=sessionInfo.id)!==null&&_sessionInfo$id!==void 0?_sessionInfo$id:null;}return null;}/**
@@ -3814,7 +3833,7 @@
3814
3833
  if(sessionInfo.sessionStart===undefined){sessionInfo=_objectSpread2(_objectSpread2({},sessionInfo),{},{sessionStart:true});}else if(sessionInfo.sessionStart){sessionInfo=_objectSpread2(_objectSpread2({},sessionInfo),{},{sessionStart:false});}}// Always write to state (in-turn to storage) to keep the session info up to date.
3815
3834
  state.session.sessionInfo.value=sessionInfo;if(state.lifecycle.status.value!=='readyExecuted'){// Force update the storage as the 'effect' blocks are not getting triggered
3816
3835
  // when processing preload buffered requests
3817
- this.syncValueToStorage('sessionInfo',sessionInfo);}}},{key:"resetAndStartNewSession",value:function resetAndStartNewSession(){var session=state.session;var _session$sessionInfo$=session.sessionInfo.value,manualTrack=_session$sessionInfo$.manualTrack,autoTrack=_session$sessionInfo$.autoTrack,timeout=_session$sessionInfo$.timeout,cutOff=_session$sessionInfo$.cutOff;if(autoTrack){var sessionInfo=_objectSpread2(_objectSpread2({},DEFAULT_USER_SESSION_VALUES.sessionInfo),{},{timeout:timeout});if(cutOff){sessionInfo.cutOff={enabled:cutOff.enabled,duration:cutOff.duration};}session.sessionInfo.value=sessionInfo;this.startOrRenewAutoTracking(session.sessionInfo.value);}else if(manualTrack){this.startManualTrackingInternal();}}/**
3836
+ this.syncValueToStorage('sessionInfo');}}},{key:"resetAndStartNewSession",value:function resetAndStartNewSession(){var session=state.session;var _session$sessionInfo$=session.sessionInfo.value,manualTrack=_session$sessionInfo$.manualTrack,autoTrack=_session$sessionInfo$.autoTrack,timeout=_session$sessionInfo$.timeout,cutOff=_session$sessionInfo$.cutOff;if(autoTrack){var sessionInfo=_objectSpread2(_objectSpread2({},DEFAULT_USER_SESSION_VALUES.sessionInfo),{},{timeout:timeout});if(cutOff){sessionInfo.cutOff={enabled:cutOff.enabled,duration:cutOff.duration};}session.sessionInfo.value=sessionInfo;this.startOrRenewAutoTracking(session.sessionInfo.value);}else if(manualTrack){this.startManualTrackingInternal();}}/**
3818
3837
  * Reset state values
3819
3838
  * @param options options for reset
3820
3839
  * @returns
@@ -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.25.1';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.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';
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
 
@@ -547,8 +547,9 @@ data[dataKey]=params.get(key);}});return data;};/**
547
547
  * Parse query string into preload buffer events & push into existing array before any other events
548
548
  */const retrieveEventsFromQueryString=(argumentsArray=[])=>{// Mapping for trait and properties values based on key prefix
549
549
  const eventArgumentToQueryParamMap={trait:QUERY_PARAM_TRAIT_PREFIX,properties:QUERY_PARAM_PROPERTY_PREFIX};const queryObject=new URLSearchParams(globalThis.location.search);// Add track events with name and properties
550
- if(queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY)){argumentsArray.unshift(['track',queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY),getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.properties)]);}// Set userId and user traits
551
- if(queryObject.get(QUERY_PARAM_USER_ID_KEY)){argumentsArray.unshift(['identify',queryObject.get(QUERY_PARAM_USER_ID_KEY),getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.trait)]);}// Set anonymousID
550
+ if(queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY)){argumentsArray.unshift(['track',queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY),getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.properties)]);}// Send identify event
551
+ const userId=queryObject.get(QUERY_PARAM_USER_ID_KEY);const userTraits=getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.trait);if(userId||isNonEmptyObject(userTraits)){// In identify API, user ID is optional
552
+ const identifyApiArgs=[...(userId?[userId]:[]),userTraits];argumentsArray.unshift(['identify',...identifyApiArgs]);}// Set anonymousID
552
553
  if(queryObject.get(QUERY_PARAM_ANONYMOUS_ID_KEY)){argumentsArray.unshift(['setAnonymousId',queryObject.get(QUERY_PARAM_ANONYMOUS_ID_KEY)]);}};/**
553
554
  * Retrieve an existing buffered load method call and remove from the existing array
554
555
  */const getPreloadedLoadEvent=preloadedEventsArray=>{const loadMethodName='load';let loadEvent=[];/**
@@ -830,16 +831,14 @@ resolve(true);}}else {resolve(!ERROR_MESSAGES_TO_BE_FILTERED.some(e=>e.test(errM
830
831
  // Ex: parentFolderName will be 'sample' for url: https://example.com/sample/file.min.js
831
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);};/**
832
833
  * A function to get the grouping hash value to be used for the error event.
833
- * Grouping hash is suppressed for non-cdn installs.
834
834
  * If the grouping hash is an error instance, the normalized error message is used as the grouping hash.
835
835
  * If the grouping hash is an empty string or not specified, the default grouping hash is used.
836
836
  * If the grouping hash is a string, it is used as is.
837
837
  * @param curErrGroupingHash The grouping hash value part of the error event
838
838
  * @param defaultGroupingHash The default grouping hash value. It is the error message.
839
- * @param state The application state
840
839
  * @param logger The logger instance
841
840
  * @returns The final grouping hash value to be used for the error event
842
- */const getErrorGroupingHash=(curErrGroupingHash,defaultGroupingHash,state,logger)=>{let normalizedGroupingHash;if(state.context.app.value.installType!=='cdn'){return normalizedGroupingHash;}if(!isDefined(curErrGroupingHash)){normalizedGroupingHash=defaultGroupingHash;}else if(isString(curErrGroupingHash)){normalizedGroupingHash=curErrGroupingHash;}else {const normalizedErrorInstance=normalizeError(curErrGroupingHash,logger);if(isDefined(normalizedErrorInstance)){normalizedGroupingHash=normalizedErrorInstance.message;}else {normalizedGroupingHash=defaultGroupingHash;}}return normalizedGroupingHash;};
841
+ */const getErrorGroupingHash=(curErrGroupingHash,defaultGroupingHash,logger)=>{let normalizedGroupingHash;if(!isDefined(curErrGroupingHash)){normalizedGroupingHash=defaultGroupingHash;}else if(isString(curErrGroupingHash)){normalizedGroupingHash=curErrGroupingHash;}else {const normalizedErrorInstance=normalizeError(curErrGroupingHash,logger);if(isDefined(normalizedErrorInstance)){normalizedGroupingHash=normalizedErrorInstance.message;}else {normalizedGroupingHash=defaultGroupingHash;}}return normalizedGroupingHash;};
843
842
 
844
843
  /**
845
844
  * A service to handle errors
@@ -863,13 +862,13 @@ document.addEventListener('securitypolicyviolation',event=>{const blockedURL=isS
863
862
  */async onError(errorInfo){try{const{error,context,customMessage,groupingHash,category}=errorInfo;const errorType=errorInfo.errorType??ErrorType.HANDLEDEXCEPTION;const errInstance=getErrInstance(error,errorType);const normalizedError=normalizeError(errInstance,this.logger);if(isUndefined(normalizedError)){return;}const customMsgVal=customMessage?`${customMessage} - `:'';const errorMsgPrefix=`${context}${LOG_CONTEXT_SEPARATOR}${customMsgVal}`;const bsException=createBugsnagException(normalizedError,errorMsgPrefix);const stacktrace=getStacktrace(normalizedError);const isSdkDispatched=stacktrace.includes(MANUAL_ERROR_IDENTIFIER);// Filter errors that are not originated in the SDK.
864
863
  // In case of NPM installations, the unhandled errors from the SDK cannot be identified
865
864
  // and will NOT be reported unless they occur in plugins or integrations.
866
- if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCEPTION){return;}if(state.reporting.isErrorReportingEnabled.value){const isAllowed=await checkIfAllowedToBeNotified(bsException,state,this.httpClient);if(isAllowed){const errorState={severity:'error',unhandled:errorType!==ErrorType.HANDLEDEXCEPTION,severityReason:{type:errorType}};// Set grouping hash only for CDN installations (as an experiment)
867
- // This will allow us to group errors by the message instead of the surrounding code.
868
- // In case of NPM installations, the default grouping by surrounding code does not make sense as each user application is different.
865
+ if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCEPTION){return;}if(state.reporting.isErrorReportingEnabled.value){const isAllowed=await checkIfAllowedToBeNotified(bsException,state,this.httpClient);if(isAllowed){const errorState={severity:'error',unhandled:errorType!==ErrorType.HANDLEDEXCEPTION,severityReason:{type:errorType}};// This will allow custom grouping of errors.
866
+ // In case of NPM installations, the default grouping by surrounding code
867
+ // does not make sense as each user application is different and will create a lot of noise in the alerts.
869
868
  // References:
870
869
  // https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash
871
870
  // https://docs.bugsnag.com/product/error-grouping/#user_defined
872
- const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,state,this.logger);// Get the final payload to be sent to the metrics service
871
+ const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,this.logger);// Get the final payload to be sent to the metrics service
873
872
  const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);// send it to metrics service
874
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
875
874
  if(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}}catch(err){// If an error occurs while handling an error, log it
@@ -3293,7 +3292,9 @@ enrichedEvent.userId=to??enrichedEvent.userId;return enrichedEvent;}/**
3293
3292
  * @param event Incoming event data
3294
3293
  */addEvent(event){this.userSessionManager.refreshSession();const rudderEvent=this.eventFactory.create(event);this.eventRepository.enqueue(rudderEvent,event.callback);}}
3295
3294
 
3296
- class UserSessionManager{constructor(pluginsManager,storeManager,httpClient,errorHandler,logger){this.storeManager=storeManager;this.pluginsManager=pluginsManager;this.logger=logger;this.errorHandler=errorHandler;this.httpClient=httpClient;this.onError=this.onError.bind(this);this.serverSideCookieDebounceFuncs={};}/**
3295
+ class UserSessionManager{/**
3296
+ * Tracks whether a server-side cookie setting request is in progress or not.
3297
+ */constructor(pluginsManager,storeManager,httpClient,errorHandler,logger){this.storeManager=storeManager;this.pluginsManager=pluginsManager;this.logger=logger;this.errorHandler=errorHandler;this.httpClient=httpClient;this.onError=this.onError.bind(this);this.serverSideCookieDebounceFuncs={};this.serverSideCookiesRequestInProgress={};}/**
3297
3298
  * Initialize User session with values from storage
3298
3299
  */init(){this.syncStorageDataToState();// Register the effect to sync with storage
3299
3300
  this.registerEffects();}syncStorageDataToState(){this.migrateStorageIfNeeded();this.migrateDataFromPreviousStorage();// get the values from storage and set it again
@@ -3323,20 +3324,31 @@ cutOffDuration=DEFAULT_SESSION_CUT_OFF_DURATION_MS;}else if(cutOffDuration<sessi
3323
3324
  * @param callback
3324
3325
  */makeRequestToSetCookie(encryptedCookieData,callback){this.httpClient?.getAsyncData({url:state.serverCookies.dataServiceUrl.value,options:{method:'POST',data:stringifyWithoutCircular({reqType:'setCookies',workspaceId:state.source.value?.workspaceId,data:{options:{maxAge:state.storage.cookie.value?.maxage,path:state.storage.cookie.value?.path,domain:state.storage.cookie.value?.domain,sameSite:state.storage.cookie.value?.samesite,secure:state.storage.cookie.value?.secure,expires:state.storage.cookie.value?.expires},cookies:encryptedCookieData}}),sendRawData:true,withCredentials:true},isRawResponse:true,callback});}/**
3325
3326
  * A function to make an external request to set the cookie from server side
3326
- * @param key cookie name
3327
- * @param value encrypted cookie value
3328
- */setServerSideCookies(cookiesData,cb,store){try{// encrypt cookies values
3329
- const encryptedCookieData=this.getEncryptedCookieData(cookiesData,store);if(encryptedCookieData.length>0){// make request to data service to set the cookie from server side
3330
- this.makeRequestToSetCookie(encryptedCookieData,(res,details)=>{if(details?.xhr?.status===200){cookiesData.forEach(cData=>{const cookieValue=store?.get(cData.name);const before=stringifyWithoutCircular(cData.value,false,[]);const after=stringifyWithoutCircular(cookieValue,false,[]);if(after!==before){this.logger.error(FAILED_SETTING_COOKIE_FROM_SERVER_ERROR(cData.name));if(cb){cb(cData.name,cData.value);}}});}else {this.logger.error(DATA_SERVER_REQUEST_FAIL_ERROR(details?.xhr?.status));cookiesData.forEach(each=>{if(cb){cb(each.name,each.value);}});}});}}catch(e){this.onError(e,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR);cookiesData.forEach(each=>{if(cb){cb(each.name,each.value);}});}}/**
3327
+ * @param sessionToCookiesMap map of session key to cookie name
3328
+ * @param cb callback function to be called when the cookie is set
3329
+ * @param store store to be used to get the cookie value
3330
+ */setServerSideCookies(sessionToCookiesMap,cb,store){// Retrieve the cookie value from the state
3331
+ const sessionKeys=Object.keys(sessionToCookiesMap);const getCurrentCookieValuesFromState=()=>{return sessionKeys.map(sessionKey=>{return {name:sessionToCookiesMap[sessionKey].name,value:state.session[sessionKey].value};});};// Preserve the current cookie values
3332
+ const originalCookieValues={};sessionKeys.forEach(sessionKey=>{originalCookieValues[sessionToCookiesMap[sessionKey].name]=store?.get(sessionToCookiesMap[sessionKey].name);});const clearInProgressFlags=()=>{sessionKeys.forEach(sessionKey=>{this.serverSideCookiesRequestInProgress[sessionKey]=false;});};const setCookiesClientSide=()=>{getCurrentCookieValuesFromState().forEach(each=>{if(cb){cb(each.name,each.value);}});};try{const expectedCookieValues={};sessionKeys.forEach(sessionKey=>{expectedCookieValues[sessionToCookiesMap[sessionKey].name]=state.session[sessionKey].value;});// encrypt cookies values
3333
+ const encryptedCookieData=this.getEncryptedCookieData(getCurrentCookieValuesFromState(),store);if(encryptedCookieData.length>0){// make request to data service to set the cookie from server side
3334
+ this.makeRequestToSetCookie(encryptedCookieData,(res,details)=>{// Mark the cookie req status as done
3335
+ clearInProgressFlags();if(details?.xhr?.status===200){getCurrentCookieValuesFromState().forEach(cData=>{const originalCookieVal=originalCookieValues[cData.name];const currentCookieVal=store?.get(cData.name);// Check if the expected cookie values are set.
3336
+ if(stringifyWithoutCircular(expectedCookieValues[cData.name],false,[])!==stringifyWithoutCircular(currentCookieVal,false,[])){// It's fine if the values don't match as other active SDK sessions might have updated the cookie values
3337
+ // or other cookie requests might have updated the cookie value.
3338
+ // Log an error only when cookie didn't exist previously and currently also doesn't exist.
3339
+ if(isNull(originalCookieVal)&&isNull(currentCookieVal)){this.logger.error(FAILED_SETTING_COOKIE_FROM_SERVER_ERROR(cData.name));}if(cb){cb(cData.name,cData.value);}}});}else {this.logger.error(DATA_SERVER_REQUEST_FAIL_ERROR(details?.xhr?.status));setCookiesClientSide();}});}else {setCookiesClientSide();// Mark the cookie req status as done
3340
+ clearInProgressFlags();}}catch(e){this.onError(e,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR);setCookiesClientSide();// Mark the cookie req status as done
3341
+ clearInProgressFlags();}}/**
3331
3342
  * A function to sync values in storage
3332
3343
  * @param sessionKey
3333
- * @param value
3334
- */syncValueToStorage(sessionKey,value){const entries=state.storage.entries.value;const storageType=entries[sessionKey]?.type;if(isStorageTypeValidForStoringData(storageType)){const curStore=this.storeManager?.getStore(storageClientDataStoreNameMap[storageType]);const key=entries[sessionKey]?.key;if(value&&(isString(value)||isNonEmptyObject(value))){// if useServerSideCookies load option is set to true
3344
+ */syncValueToStorage(sessionKey){const entries=state.storage.entries.value;const storageType=entries[sessionKey]?.type;if(isStorageTypeValidForStoringData(storageType)){const curStore=this.storeManager.getStore(storageClientDataStoreNameMap[storageType]);const cookieName=entries[sessionKey]?.key;const cookieValue=state.session[sessionKey].value;if(cookieValue&&(isString(cookieValue)||isNonEmptyObject(cookieValue))){// if useServerSideCookies load option is set to true
3335
3345
  // set the cookie from server side
3336
- if(state.serverCookies.isEnabledServerSideCookies.value&&storageType===COOKIE_STORAGE){if(this.serverSideCookieDebounceFuncs[sessionKey]){globalThis.clearTimeout(this.serverSideCookieDebounceFuncs[sessionKey]);}this.serverSideCookieDebounceFuncs[sessionKey]=globalThis.setTimeout(()=>{this.setServerSideCookies([{name:key,value}],(cookieName,cookieValue)=>{curStore?.set(cookieName,cookieValue);},curStore);},SERVER_SIDE_COOKIES_DEBOUNCE_TIME);}else {curStore?.set(key,value);}}else {curStore?.remove(key);}}}/**
3346
+ if(state.serverCookies.isEnabledServerSideCookies.value&&storageType===COOKIE_STORAGE){// Mark the requests as in progress.
3347
+ this.serverSideCookiesRequestInProgress[sessionKey]=true;if(this.serverSideCookieDebounceFuncs[sessionKey]){globalThis.clearTimeout(this.serverSideCookieDebounceFuncs[sessionKey]);}this.serverSideCookieDebounceFuncs[sessionKey]=globalThis.setTimeout(()=>{// Create a map of session key to cookie name
3348
+ const sessionToCookiesMap={[sessionKey]:{name:cookieName}};this.setServerSideCookies(sessionToCookiesMap,(cookieName,cookieValue)=>{curStore?.set(cookieName,cookieValue);},curStore);},SERVER_SIDE_COOKIES_DEBOUNCE_TIME);}else {curStore?.set(cookieName,cookieValue);}}else {curStore?.remove(cookieName);}}}/**
3337
3349
  * Function to update storage whenever state value changes
3338
3350
  */registerEffects(){// This will work as long as the user session entry key names are same as the state keys
3339
- USER_SESSION_KEYS.forEach(sessionKey=>{E(()=>{this.syncValueToStorage(sessionKey,state.session[sessionKey].value);});});}/**
3351
+ USER_SESSION_KEYS.forEach(sessionKey=>{E(()=>{this.syncValueToStorage(sessionKey);});});}/**
3340
3352
  * Sets anonymous id in the following precedence:
3341
3353
  *
3342
3354
  * 1. anonymousId: Id directly provided to the function.
@@ -3353,30 +3365,37 @@ const autoCapturedAnonymousId=this.pluginsManager?.invokeSingle('storage.getAnon
3353
3365
  // This is needed for entries that are fetched from the storage
3354
3366
  // during the current session (for example, session info)
3355
3367
  this.migrateStorageIfNeeded([store],[sessionKey]);const storageKey=entries[sessionKey]?.key;return store?.get(storageKey)??null;}return null;}getExternalAnonymousIdByCookieName(key){const storageEngine=getStorageEngine(COOKIE_STORAGE);if(storageEngine?.isEnabled){return storageEngine.getItem(key)??null;}return null;}/**
3368
+ * Fetches the value for a session key. Preferably from storage, if the server-side
3369
+ * cookies request is not in progress. Otherwise, from the state.
3370
+ * @param sessionKey - The session key to fetch the value for
3371
+ * @returns - The value for the session key
3372
+ */getUserSessionValue(sessionKey){// If the server-side cookies request is in progress, fetch the value from the state.
3373
+ if(this.serverSideCookiesRequestInProgress[sessionKey]){return state.session[sessionKey].value;}// Otherwise, fetch the value from storage.
3374
+ return this.getEntryValue(sessionKey);}/**
3356
3375
  * Fetches User Id
3357
3376
  * @returns
3358
- */getUserId(){return this.getEntryValue('userId');}/**
3377
+ */getUserId(){return this.getUserSessionValue('userId');}/**
3359
3378
  * Fetches User Traits
3360
3379
  * @returns
3361
- */getUserTraits(){return this.getEntryValue('userTraits');}/**
3380
+ */getUserTraits(){return this.getUserSessionValue('userTraits');}/**
3362
3381
  * Fetches Group Id
3363
3382
  * @returns
3364
- */getGroupId(){return this.getEntryValue('groupId');}/**
3383
+ */getGroupId(){return this.getUserSessionValue('groupId');}/**
3365
3384
  * Fetches Group Traits
3366
3385
  * @returns
3367
- */getGroupTraits(){return this.getEntryValue('groupTraits');}/**
3386
+ */getGroupTraits(){return this.getUserSessionValue('groupTraits');}/**
3368
3387
  * Fetches Initial Referrer
3369
3388
  * @returns
3370
- */getInitialReferrer(){return this.getEntryValue('initialReferrer');}/**
3389
+ */getInitialReferrer(){return this.getUserSessionValue('initialReferrer');}/**
3371
3390
  * Fetches Initial Referring domain
3372
3391
  * @returns
3373
- */getInitialReferringDomain(){return this.getEntryValue('initialReferringDomain');}/**
3392
+ */getInitialReferringDomain(){return this.getUserSessionValue('initialReferringDomain');}/**
3374
3393
  * Fetches session tracking information from storage
3375
3394
  * @returns
3376
- */getSessionInfo(){return this.getEntryValue('sessionInfo');}/**
3395
+ */getSessionInfo(){return this.getUserSessionValue('sessionInfo');}/**
3377
3396
  * Fetches auth token from storage
3378
3397
  * @returns
3379
- */getAuthToken(){return this.getEntryValue('authToken');}/**
3398
+ */getAuthToken(){return this.getUserSessionValue('authToken');}/**
3380
3399
  * If session is active it returns the sessionId
3381
3400
  * @returns
3382
3401
  */getSessionId(){const sessionInfo=this.getSessionInfo()??DEFAULT_USER_SESSION_VALUES.sessionInfo;if(sessionInfo.autoTrack&&!hasSessionExpired(sessionInfo)||sessionInfo.manualTrack){return sessionInfo.id??null;}return null;}/**
@@ -3392,7 +3411,7 @@ this.migrateStorageIfNeeded([store],[sessionKey]);const storageKey=entries[sessi
3392
3411
  if(sessionInfo.sessionStart===undefined){sessionInfo={...sessionInfo,sessionStart:true};}else if(sessionInfo.sessionStart){sessionInfo={...sessionInfo,sessionStart:false};}}// Always write to state (in-turn to storage) to keep the session info up to date.
3393
3412
  state.session.sessionInfo.value=sessionInfo;if(state.lifecycle.status.value!=='readyExecuted'){// Force update the storage as the 'effect' blocks are not getting triggered
3394
3413
  // when processing preload buffered requests
3395
- this.syncValueToStorage('sessionInfo',sessionInfo);}}resetAndStartNewSession(){const session=state.session;const{manualTrack,autoTrack,timeout,cutOff}=session.sessionInfo.value;if(autoTrack){const sessionInfo={...DEFAULT_USER_SESSION_VALUES.sessionInfo,timeout};if(cutOff){sessionInfo.cutOff={enabled:cutOff.enabled,duration:cutOff.duration};}session.sessionInfo.value=sessionInfo;this.startOrRenewAutoTracking(session.sessionInfo.value);}else if(manualTrack){this.startManualTrackingInternal();}}/**
3414
+ this.syncValueToStorage('sessionInfo');}}resetAndStartNewSession(){const session=state.session;const{manualTrack,autoTrack,timeout,cutOff}=session.sessionInfo.value;if(autoTrack){const sessionInfo={...DEFAULT_USER_SESSION_VALUES.sessionInfo,timeout};if(cutOff){sessionInfo.cutOff={enabled:cutOff.enabled,duration:cutOff.duration};}session.sessionInfo.value=sessionInfo;this.startOrRenewAutoTracking(session.sessionInfo.value);}else if(manualTrack){this.startManualTrackingInternal();}}/**
3396
3415
  * Reset state values
3397
3416
  * @param options options for reset
3398
3417
  * @returns
@@ -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.25.1';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.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';
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
 
@@ -543,8 +543,9 @@ data[dataKey]=params.get(key);}});return data;};/**
543
543
  * Parse query string into preload buffer events & push into existing array before any other events
544
544
  */const retrieveEventsFromQueryString=(argumentsArray=[])=>{// Mapping for trait and properties values based on key prefix
545
545
  const eventArgumentToQueryParamMap={trait:QUERY_PARAM_TRAIT_PREFIX,properties:QUERY_PARAM_PROPERTY_PREFIX};const queryObject=new URLSearchParams(globalThis.location.search);// Add track events with name and properties
546
- if(queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY)){argumentsArray.unshift(['track',queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY),getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.properties)]);}// Set userId and user traits
547
- if(queryObject.get(QUERY_PARAM_USER_ID_KEY)){argumentsArray.unshift(['identify',queryObject.get(QUERY_PARAM_USER_ID_KEY),getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.trait)]);}// Set anonymousID
546
+ if(queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY)){argumentsArray.unshift(['track',queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY),getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.properties)]);}// Send identify event
547
+ const userId=queryObject.get(QUERY_PARAM_USER_ID_KEY);const userTraits=getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.trait);if(userId||isNonEmptyObject(userTraits)){// In identify API, user ID is optional
548
+ const identifyApiArgs=[...(userId?[userId]:[]),userTraits];argumentsArray.unshift(['identify',...identifyApiArgs]);}// Set anonymousID
548
549
  if(queryObject.get(QUERY_PARAM_ANONYMOUS_ID_KEY)){argumentsArray.unshift(['setAnonymousId',queryObject.get(QUERY_PARAM_ANONYMOUS_ID_KEY)]);}};/**
549
550
  * Retrieve an existing buffered load method call and remove from the existing array
550
551
  */const getPreloadedLoadEvent=preloadedEventsArray=>{const loadMethodName='load';let loadEvent=[];/**
@@ -826,16 +827,14 @@ resolve(true);}}else {resolve(!ERROR_MESSAGES_TO_BE_FILTERED.some(e=>e.test(errM
826
827
  // Ex: parentFolderName will be 'sample' for url: https://example.com/sample/file.min.js
827
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);};/**
828
829
  * A function to get the grouping hash value to be used for the error event.
829
- * Grouping hash is suppressed for non-cdn installs.
830
830
  * If the grouping hash is an error instance, the normalized error message is used as the grouping hash.
831
831
  * If the grouping hash is an empty string or not specified, the default grouping hash is used.
832
832
  * If the grouping hash is a string, it is used as is.
833
833
  * @param curErrGroupingHash The grouping hash value part of the error event
834
834
  * @param defaultGroupingHash The default grouping hash value. It is the error message.
835
- * @param state The application state
836
835
  * @param logger The logger instance
837
836
  * @returns The final grouping hash value to be used for the error event
838
- */const getErrorGroupingHash=(curErrGroupingHash,defaultGroupingHash,state,logger)=>{let normalizedGroupingHash;if(state.context.app.value.installType!=='cdn'){return normalizedGroupingHash;}if(!isDefined(curErrGroupingHash)){normalizedGroupingHash=defaultGroupingHash;}else if(isString(curErrGroupingHash)){normalizedGroupingHash=curErrGroupingHash;}else {const normalizedErrorInstance=normalizeError(curErrGroupingHash,logger);if(isDefined(normalizedErrorInstance)){normalizedGroupingHash=normalizedErrorInstance.message;}else {normalizedGroupingHash=defaultGroupingHash;}}return normalizedGroupingHash;};
837
+ */const getErrorGroupingHash=(curErrGroupingHash,defaultGroupingHash,logger)=>{let normalizedGroupingHash;if(!isDefined(curErrGroupingHash)){normalizedGroupingHash=defaultGroupingHash;}else if(isString(curErrGroupingHash)){normalizedGroupingHash=curErrGroupingHash;}else {const normalizedErrorInstance=normalizeError(curErrGroupingHash,logger);if(isDefined(normalizedErrorInstance)){normalizedGroupingHash=normalizedErrorInstance.message;}else {normalizedGroupingHash=defaultGroupingHash;}}return normalizedGroupingHash;};
839
838
 
840
839
  /**
841
840
  * A service to handle errors
@@ -859,13 +858,13 @@ document.addEventListener('securitypolicyviolation',event=>{const blockedURL=isS
859
858
  */async onError(errorInfo){try{const{error,context,customMessage,groupingHash,category}=errorInfo;const errorType=errorInfo.errorType??ErrorType.HANDLEDEXCEPTION;const errInstance=getErrInstance(error,errorType);const normalizedError=normalizeError(errInstance,this.logger);if(isUndefined(normalizedError)){return;}const customMsgVal=customMessage?`${customMessage} - `:'';const errorMsgPrefix=`${context}${LOG_CONTEXT_SEPARATOR}${customMsgVal}`;const bsException=createBugsnagException(normalizedError,errorMsgPrefix);const stacktrace=getStacktrace(normalizedError);const isSdkDispatched=stacktrace.includes(MANUAL_ERROR_IDENTIFIER);// Filter errors that are not originated in the SDK.
860
859
  // In case of NPM installations, the unhandled errors from the SDK cannot be identified
861
860
  // and will NOT be reported unless they occur in plugins or integrations.
862
- if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCEPTION){return;}if(state.reporting.isErrorReportingEnabled.value){const isAllowed=await checkIfAllowedToBeNotified(bsException,state,this.httpClient);if(isAllowed){const errorState={severity:'error',unhandled:errorType!==ErrorType.HANDLEDEXCEPTION,severityReason:{type:errorType}};// Set grouping hash only for CDN installations (as an experiment)
863
- // This will allow us to group errors by the message instead of the surrounding code.
864
- // In case of NPM installations, the default grouping by surrounding code does not make sense as each user application is different.
861
+ if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCEPTION){return;}if(state.reporting.isErrorReportingEnabled.value){const isAllowed=await checkIfAllowedToBeNotified(bsException,state,this.httpClient);if(isAllowed){const errorState={severity:'error',unhandled:errorType!==ErrorType.HANDLEDEXCEPTION,severityReason:{type:errorType}};// This will allow custom grouping of errors.
862
+ // In case of NPM installations, the default grouping by surrounding code
863
+ // does not make sense as each user application is different and will create a lot of noise in the alerts.
865
864
  // References:
866
865
  // https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash
867
866
  // https://docs.bugsnag.com/product/error-grouping/#user_defined
868
- const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,state,this.logger);// Get the final payload to be sent to the metrics service
867
+ const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,this.logger);// Get the final payload to be sent to the metrics service
869
868
  const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);// send it to metrics service
870
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
871
870
  if(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}}catch(err){// If an error occurs while handling an error, log it
@@ -3289,7 +3288,9 @@ enrichedEvent.userId=to??enrichedEvent.userId;return enrichedEvent;}/**
3289
3288
  * @param event Incoming event data
3290
3289
  */addEvent(event){this.userSessionManager.refreshSession();const rudderEvent=this.eventFactory.create(event);this.eventRepository.enqueue(rudderEvent,event.callback);}}
3291
3290
 
3292
- class UserSessionManager{constructor(pluginsManager,storeManager,httpClient,errorHandler,logger){this.storeManager=storeManager;this.pluginsManager=pluginsManager;this.logger=logger;this.errorHandler=errorHandler;this.httpClient=httpClient;this.onError=this.onError.bind(this);this.serverSideCookieDebounceFuncs={};}/**
3291
+ class UserSessionManager{/**
3292
+ * Tracks whether a server-side cookie setting request is in progress or not.
3293
+ */constructor(pluginsManager,storeManager,httpClient,errorHandler,logger){this.storeManager=storeManager;this.pluginsManager=pluginsManager;this.logger=logger;this.errorHandler=errorHandler;this.httpClient=httpClient;this.onError=this.onError.bind(this);this.serverSideCookieDebounceFuncs={};this.serverSideCookiesRequestInProgress={};}/**
3293
3294
  * Initialize User session with values from storage
3294
3295
  */init(){this.syncStorageDataToState();// Register the effect to sync with storage
3295
3296
  this.registerEffects();}syncStorageDataToState(){this.migrateStorageIfNeeded();this.migrateDataFromPreviousStorage();// get the values from storage and set it again
@@ -3319,20 +3320,31 @@ cutOffDuration=DEFAULT_SESSION_CUT_OFF_DURATION_MS;}else if(cutOffDuration<sessi
3319
3320
  * @param callback
3320
3321
  */makeRequestToSetCookie(encryptedCookieData,callback){this.httpClient?.getAsyncData({url:state.serverCookies.dataServiceUrl.value,options:{method:'POST',data:stringifyWithoutCircular({reqType:'setCookies',workspaceId:state.source.value?.workspaceId,data:{options:{maxAge:state.storage.cookie.value?.maxage,path:state.storage.cookie.value?.path,domain:state.storage.cookie.value?.domain,sameSite:state.storage.cookie.value?.samesite,secure:state.storage.cookie.value?.secure,expires:state.storage.cookie.value?.expires},cookies:encryptedCookieData}}),sendRawData:true,withCredentials:true},isRawResponse:true,callback});}/**
3321
3322
  * A function to make an external request to set the cookie from server side
3322
- * @param key cookie name
3323
- * @param value encrypted cookie value
3324
- */setServerSideCookies(cookiesData,cb,store){try{// encrypt cookies values
3325
- const encryptedCookieData=this.getEncryptedCookieData(cookiesData,store);if(encryptedCookieData.length>0){// make request to data service to set the cookie from server side
3326
- this.makeRequestToSetCookie(encryptedCookieData,(res,details)=>{if(details?.xhr?.status===200){cookiesData.forEach(cData=>{const cookieValue=store?.get(cData.name);const before=stringifyWithoutCircular(cData.value,false,[]);const after=stringifyWithoutCircular(cookieValue,false,[]);if(after!==before){this.logger.error(FAILED_SETTING_COOKIE_FROM_SERVER_ERROR(cData.name));if(cb){cb(cData.name,cData.value);}}});}else {this.logger.error(DATA_SERVER_REQUEST_FAIL_ERROR(details?.xhr?.status));cookiesData.forEach(each=>{if(cb){cb(each.name,each.value);}});}});}}catch(e){this.onError(e,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR);cookiesData.forEach(each=>{if(cb){cb(each.name,each.value);}});}}/**
3323
+ * @param sessionToCookiesMap map of session key to cookie name
3324
+ * @param cb callback function to be called when the cookie is set
3325
+ * @param store store to be used to get the cookie value
3326
+ */setServerSideCookies(sessionToCookiesMap,cb,store){// Retrieve the cookie value from the state
3327
+ const sessionKeys=Object.keys(sessionToCookiesMap);const getCurrentCookieValuesFromState=()=>{return sessionKeys.map(sessionKey=>{return {name:sessionToCookiesMap[sessionKey].name,value:state.session[sessionKey].value};});};// Preserve the current cookie values
3328
+ const originalCookieValues={};sessionKeys.forEach(sessionKey=>{originalCookieValues[sessionToCookiesMap[sessionKey].name]=store?.get(sessionToCookiesMap[sessionKey].name);});const clearInProgressFlags=()=>{sessionKeys.forEach(sessionKey=>{this.serverSideCookiesRequestInProgress[sessionKey]=false;});};const setCookiesClientSide=()=>{getCurrentCookieValuesFromState().forEach(each=>{if(cb){cb(each.name,each.value);}});};try{const expectedCookieValues={};sessionKeys.forEach(sessionKey=>{expectedCookieValues[sessionToCookiesMap[sessionKey].name]=state.session[sessionKey].value;});// encrypt cookies values
3329
+ const encryptedCookieData=this.getEncryptedCookieData(getCurrentCookieValuesFromState(),store);if(encryptedCookieData.length>0){// make request to data service to set the cookie from server side
3330
+ this.makeRequestToSetCookie(encryptedCookieData,(res,details)=>{// Mark the cookie req status as done
3331
+ clearInProgressFlags();if(details?.xhr?.status===200){getCurrentCookieValuesFromState().forEach(cData=>{const originalCookieVal=originalCookieValues[cData.name];const currentCookieVal=store?.get(cData.name);// Check if the expected cookie values are set.
3332
+ if(stringifyWithoutCircular(expectedCookieValues[cData.name],false,[])!==stringifyWithoutCircular(currentCookieVal,false,[])){// It's fine if the values don't match as other active SDK sessions might have updated the cookie values
3333
+ // or other cookie requests might have updated the cookie value.
3334
+ // Log an error only when cookie didn't exist previously and currently also doesn't exist.
3335
+ if(isNull(originalCookieVal)&&isNull(currentCookieVal)){this.logger.error(FAILED_SETTING_COOKIE_FROM_SERVER_ERROR(cData.name));}if(cb){cb(cData.name,cData.value);}}});}else {this.logger.error(DATA_SERVER_REQUEST_FAIL_ERROR(details?.xhr?.status));setCookiesClientSide();}});}else {setCookiesClientSide();// Mark the cookie req status as done
3336
+ clearInProgressFlags();}}catch(e){this.onError(e,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR);setCookiesClientSide();// Mark the cookie req status as done
3337
+ clearInProgressFlags();}}/**
3327
3338
  * A function to sync values in storage
3328
3339
  * @param sessionKey
3329
- * @param value
3330
- */syncValueToStorage(sessionKey,value){const entries=state.storage.entries.value;const storageType=entries[sessionKey]?.type;if(isStorageTypeValidForStoringData(storageType)){const curStore=this.storeManager?.getStore(storageClientDataStoreNameMap[storageType]);const key=entries[sessionKey]?.key;if(value&&(isString(value)||isNonEmptyObject(value))){// if useServerSideCookies load option is set to true
3340
+ */syncValueToStorage(sessionKey){const entries=state.storage.entries.value;const storageType=entries[sessionKey]?.type;if(isStorageTypeValidForStoringData(storageType)){const curStore=this.storeManager.getStore(storageClientDataStoreNameMap[storageType]);const cookieName=entries[sessionKey]?.key;const cookieValue=state.session[sessionKey].value;if(cookieValue&&(isString(cookieValue)||isNonEmptyObject(cookieValue))){// if useServerSideCookies load option is set to true
3331
3341
  // set the cookie from server side
3332
- if(state.serverCookies.isEnabledServerSideCookies.value&&storageType===COOKIE_STORAGE){if(this.serverSideCookieDebounceFuncs[sessionKey]){globalThis.clearTimeout(this.serverSideCookieDebounceFuncs[sessionKey]);}this.serverSideCookieDebounceFuncs[sessionKey]=globalThis.setTimeout(()=>{this.setServerSideCookies([{name:key,value}],(cookieName,cookieValue)=>{curStore?.set(cookieName,cookieValue);},curStore);},SERVER_SIDE_COOKIES_DEBOUNCE_TIME);}else {curStore?.set(key,value);}}else {curStore?.remove(key);}}}/**
3342
+ if(state.serverCookies.isEnabledServerSideCookies.value&&storageType===COOKIE_STORAGE){// Mark the requests as in progress.
3343
+ this.serverSideCookiesRequestInProgress[sessionKey]=true;if(this.serverSideCookieDebounceFuncs[sessionKey]){globalThis.clearTimeout(this.serverSideCookieDebounceFuncs[sessionKey]);}this.serverSideCookieDebounceFuncs[sessionKey]=globalThis.setTimeout(()=>{// Create a map of session key to cookie name
3344
+ const sessionToCookiesMap={[sessionKey]:{name:cookieName}};this.setServerSideCookies(sessionToCookiesMap,(cookieName,cookieValue)=>{curStore?.set(cookieName,cookieValue);},curStore);},SERVER_SIDE_COOKIES_DEBOUNCE_TIME);}else {curStore?.set(cookieName,cookieValue);}}else {curStore?.remove(cookieName);}}}/**
3333
3345
  * Function to update storage whenever state value changes
3334
3346
  */registerEffects(){// This will work as long as the user session entry key names are same as the state keys
3335
- USER_SESSION_KEYS.forEach(sessionKey=>{E(()=>{this.syncValueToStorage(sessionKey,state.session[sessionKey].value);});});}/**
3347
+ USER_SESSION_KEYS.forEach(sessionKey=>{E(()=>{this.syncValueToStorage(sessionKey);});});}/**
3336
3348
  * Sets anonymous id in the following precedence:
3337
3349
  *
3338
3350
  * 1. anonymousId: Id directly provided to the function.
@@ -3349,30 +3361,37 @@ const autoCapturedAnonymousId=this.pluginsManager?.invokeSingle('storage.getAnon
3349
3361
  // This is needed for entries that are fetched from the storage
3350
3362
  // during the current session (for example, session info)
3351
3363
  this.migrateStorageIfNeeded([store],[sessionKey]);const storageKey=entries[sessionKey]?.key;return store?.get(storageKey)??null;}return null;}getExternalAnonymousIdByCookieName(key){const storageEngine=getStorageEngine(COOKIE_STORAGE);if(storageEngine?.isEnabled){return storageEngine.getItem(key)??null;}return null;}/**
3364
+ * Fetches the value for a session key. Preferably from storage, if the server-side
3365
+ * cookies request is not in progress. Otherwise, from the state.
3366
+ * @param sessionKey - The session key to fetch the value for
3367
+ * @returns - The value for the session key
3368
+ */getUserSessionValue(sessionKey){// If the server-side cookies request is in progress, fetch the value from the state.
3369
+ if(this.serverSideCookiesRequestInProgress[sessionKey]){return state.session[sessionKey].value;}// Otherwise, fetch the value from storage.
3370
+ return this.getEntryValue(sessionKey);}/**
3352
3371
  * Fetches User Id
3353
3372
  * @returns
3354
- */getUserId(){return this.getEntryValue('userId');}/**
3373
+ */getUserId(){return this.getUserSessionValue('userId');}/**
3355
3374
  * Fetches User Traits
3356
3375
  * @returns
3357
- */getUserTraits(){return this.getEntryValue('userTraits');}/**
3376
+ */getUserTraits(){return this.getUserSessionValue('userTraits');}/**
3358
3377
  * Fetches Group Id
3359
3378
  * @returns
3360
- */getGroupId(){return this.getEntryValue('groupId');}/**
3379
+ */getGroupId(){return this.getUserSessionValue('groupId');}/**
3361
3380
  * Fetches Group Traits
3362
3381
  * @returns
3363
- */getGroupTraits(){return this.getEntryValue('groupTraits');}/**
3382
+ */getGroupTraits(){return this.getUserSessionValue('groupTraits');}/**
3364
3383
  * Fetches Initial Referrer
3365
3384
  * @returns
3366
- */getInitialReferrer(){return this.getEntryValue('initialReferrer');}/**
3385
+ */getInitialReferrer(){return this.getUserSessionValue('initialReferrer');}/**
3367
3386
  * Fetches Initial Referring domain
3368
3387
  * @returns
3369
- */getInitialReferringDomain(){return this.getEntryValue('initialReferringDomain');}/**
3388
+ */getInitialReferringDomain(){return this.getUserSessionValue('initialReferringDomain');}/**
3370
3389
  * Fetches session tracking information from storage
3371
3390
  * @returns
3372
- */getSessionInfo(){return this.getEntryValue('sessionInfo');}/**
3391
+ */getSessionInfo(){return this.getUserSessionValue('sessionInfo');}/**
3373
3392
  * Fetches auth token from storage
3374
3393
  * @returns
3375
- */getAuthToken(){return this.getEntryValue('authToken');}/**
3394
+ */getAuthToken(){return this.getUserSessionValue('authToken');}/**
3376
3395
  * If session is active it returns the sessionId
3377
3396
  * @returns
3378
3397
  */getSessionId(){const sessionInfo=this.getSessionInfo()??DEFAULT_USER_SESSION_VALUES.sessionInfo;if(sessionInfo.autoTrack&&!hasSessionExpired(sessionInfo)||sessionInfo.manualTrack){return sessionInfo.id??null;}return null;}/**
@@ -3388,7 +3407,7 @@ this.migrateStorageIfNeeded([store],[sessionKey]);const storageKey=entries[sessi
3388
3407
  if(sessionInfo.sessionStart===undefined){sessionInfo={...sessionInfo,sessionStart:true};}else if(sessionInfo.sessionStart){sessionInfo={...sessionInfo,sessionStart:false};}}// Always write to state (in-turn to storage) to keep the session info up to date.
3389
3408
  state.session.sessionInfo.value=sessionInfo;if(state.lifecycle.status.value!=='readyExecuted'){// Force update the storage as the 'effect' blocks are not getting triggered
3390
3409
  // when processing preload buffered requests
3391
- this.syncValueToStorage('sessionInfo',sessionInfo);}}resetAndStartNewSession(){const session=state.session;const{manualTrack,autoTrack,timeout,cutOff}=session.sessionInfo.value;if(autoTrack){const sessionInfo={...DEFAULT_USER_SESSION_VALUES.sessionInfo,timeout};if(cutOff){sessionInfo.cutOff={enabled:cutOff.enabled,duration:cutOff.duration};}session.sessionInfo.value=sessionInfo;this.startOrRenewAutoTracking(session.sessionInfo.value);}else if(manualTrack){this.startManualTrackingInternal();}}/**
3410
+ this.syncValueToStorage('sessionInfo');}}resetAndStartNewSession(){const session=state.session;const{manualTrack,autoTrack,timeout,cutOff}=session.sessionInfo.value;if(autoTrack){const sessionInfo={...DEFAULT_USER_SESSION_VALUES.sessionInfo,timeout};if(cutOff){sessionInfo.cutOff={enabled:cutOff.enabled,duration:cutOff.duration};}session.sessionInfo.value=sessionInfo;this.startOrRenewAutoTracking(session.sessionInfo.value);}else if(manualTrack){this.startManualTrackingInternal();}}/**
3392
3411
  * Reset state values
3393
3412
  * @param options options for reset
3394
3413
  * @returns