@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.
- package/CHANGELOG.md +19 -0
- package/dist/npm/legacy/bundled/cjs/index.cjs +49 -30
- package/dist/npm/legacy/bundled/esm/index.mjs +49 -30
- package/dist/npm/legacy/bundled/umd/index.js +49 -30
- package/dist/npm/legacy/cjs/index.cjs +49 -30
- package/dist/npm/legacy/content-script/cjs/index.cjs +49 -30
- package/dist/npm/legacy/content-script/esm/index.mjs +49 -30
- package/dist/npm/legacy/content-script/umd/index.js +49 -30
- package/dist/npm/legacy/esm/index.mjs +49 -30
- package/dist/npm/legacy/umd/index.js +49 -30
- package/dist/npm/modern/bundled/cjs/index.cjs +48 -29
- package/dist/npm/modern/bundled/esm/index.mjs +48 -29
- package/dist/npm/modern/bundled/umd/index.js +48 -29
- package/dist/npm/modern/cjs/index.cjs +48 -29
- package/dist/npm/modern/content-script/cjs/index.cjs +48 -29
- package/dist/npm/modern/content-script/esm/index.mjs +48 -29
- package/dist/npm/modern/content-script/umd/index.js +48 -29
- package/dist/npm/modern/esm/index.mjs +48 -29
- package/dist/npm/modern/umd/index.js +48 -29
- package/package.json +1 -1
|
@@ -914,7 +914,7 @@
|
|
|
914
914
|
error.stacktrace="".concat(stacktrace,"\n").concat(MANUAL_ERROR_IDENTIFIER);break;case operaSourceloc:default:// eslint-disable-next-line no-param-reassign
|
|
915
915
|
error['opera#sourceloc']="".concat(operaSourceloc,"\n").concat(MANUAL_ERROR_IDENTIFIER);break;}}}globalThis.dispatchEvent(new ErrorEvent('error',{error:error,bubbles:true,cancelable:true,composed:true}));};
|
|
916
916
|
|
|
917
|
-
var APP_NAME='RudderLabs JavaScript SDK';var APP_VERSION='3.
|
|
917
|
+
var APP_NAME='RudderLabs JavaScript SDK';var APP_VERSION='3.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)]);}//
|
|
946
|
-
|
|
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,
|
|
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}};//
|
|
1260
|
-
//
|
|
1261
|
-
//
|
|
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,
|
|
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(){
|
|
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
|
|
3749
|
-
* @param
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
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
|
-
|
|
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){
|
|
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
|
|
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$
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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'
|
|
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.
|
|
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)]);}//
|
|
551
|
-
|
|
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,
|
|
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}};//
|
|
867
|
-
//
|
|
868
|
-
//
|
|
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,
|
|
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{
|
|
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
|
|
3327
|
-
* @param
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
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
|
-
|
|
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){
|
|
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
|
|
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.
|
|
3377
|
+
*/getUserId(){return this.getUserSessionValue('userId');}/**
|
|
3359
3378
|
* Fetches User Traits
|
|
3360
3379
|
* @returns
|
|
3361
|
-
*/getUserTraits(){return this.
|
|
3380
|
+
*/getUserTraits(){return this.getUserSessionValue('userTraits');}/**
|
|
3362
3381
|
* Fetches Group Id
|
|
3363
3382
|
* @returns
|
|
3364
|
-
*/getGroupId(){return this.
|
|
3383
|
+
*/getGroupId(){return this.getUserSessionValue('groupId');}/**
|
|
3365
3384
|
* Fetches Group Traits
|
|
3366
3385
|
* @returns
|
|
3367
|
-
*/getGroupTraits(){return this.
|
|
3386
|
+
*/getGroupTraits(){return this.getUserSessionValue('groupTraits');}/**
|
|
3368
3387
|
* Fetches Initial Referrer
|
|
3369
3388
|
* @returns
|
|
3370
|
-
*/getInitialReferrer(){return this.
|
|
3389
|
+
*/getInitialReferrer(){return this.getUserSessionValue('initialReferrer');}/**
|
|
3371
3390
|
* Fetches Initial Referring domain
|
|
3372
3391
|
* @returns
|
|
3373
|
-
*/getInitialReferringDomain(){return this.
|
|
3392
|
+
*/getInitialReferringDomain(){return this.getUserSessionValue('initialReferringDomain');}/**
|
|
3374
3393
|
* Fetches session tracking information from storage
|
|
3375
3394
|
* @returns
|
|
3376
|
-
*/getSessionInfo(){return this.
|
|
3395
|
+
*/getSessionInfo(){return this.getUserSessionValue('sessionInfo');}/**
|
|
3377
3396
|
* Fetches auth token from storage
|
|
3378
3397
|
* @returns
|
|
3379
|
-
*/getAuthToken(){return this.
|
|
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'
|
|
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.
|
|
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)]);}//
|
|
547
|
-
|
|
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,
|
|
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}};//
|
|
863
|
-
//
|
|
864
|
-
//
|
|
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,
|
|
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{
|
|
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
|
|
3323
|
-
* @param
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
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
|
-
|
|
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){
|
|
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
|
|
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.
|
|
3373
|
+
*/getUserId(){return this.getUserSessionValue('userId');}/**
|
|
3355
3374
|
* Fetches User Traits
|
|
3356
3375
|
* @returns
|
|
3357
|
-
*/getUserTraits(){return this.
|
|
3376
|
+
*/getUserTraits(){return this.getUserSessionValue('userTraits');}/**
|
|
3358
3377
|
* Fetches Group Id
|
|
3359
3378
|
* @returns
|
|
3360
|
-
*/getGroupId(){return this.
|
|
3379
|
+
*/getGroupId(){return this.getUserSessionValue('groupId');}/**
|
|
3361
3380
|
* Fetches Group Traits
|
|
3362
3381
|
* @returns
|
|
3363
|
-
*/getGroupTraits(){return this.
|
|
3382
|
+
*/getGroupTraits(){return this.getUserSessionValue('groupTraits');}/**
|
|
3364
3383
|
* Fetches Initial Referrer
|
|
3365
3384
|
* @returns
|
|
3366
|
-
*/getInitialReferrer(){return this.
|
|
3385
|
+
*/getInitialReferrer(){return this.getUserSessionValue('initialReferrer');}/**
|
|
3367
3386
|
* Fetches Initial Referring domain
|
|
3368
3387
|
* @returns
|
|
3369
|
-
*/getInitialReferringDomain(){return this.
|
|
3388
|
+
*/getInitialReferringDomain(){return this.getUserSessionValue('initialReferringDomain');}/**
|
|
3370
3389
|
* Fetches session tracking information from storage
|
|
3371
3390
|
* @returns
|
|
3372
|
-
*/getSessionInfo(){return this.
|
|
3391
|
+
*/getSessionInfo(){return this.getUserSessionValue('sessionInfo');}/**
|
|
3373
3392
|
* Fetches auth token from storage
|
|
3374
3393
|
* @returns
|
|
3375
|
-
*/getAuthToken(){return this.
|
|
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'
|
|
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
|