@rudderstack/analytics-js 3.25.1-beta.pr.2607.9d63b74 → 3.26.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 +12 -0
- package/dist/npm/legacy/bundled/cjs/index.cjs +44 -43
- package/dist/npm/legacy/bundled/esm/index.mjs +44 -43
- package/dist/npm/legacy/bundled/umd/index.js +44 -43
- package/dist/npm/legacy/cjs/index.cjs +44 -43
- package/dist/npm/legacy/content-script/cjs/index.cjs +44 -43
- package/dist/npm/legacy/content-script/esm/index.mjs +44 -43
- package/dist/npm/legacy/content-script/umd/index.js +44 -43
- package/dist/npm/legacy/esm/index.mjs +44 -43
- package/dist/npm/legacy/umd/index.js +44 -43
- package/dist/npm/modern/bundled/cjs/index.cjs +43 -42
- package/dist/npm/modern/bundled/esm/index.mjs +43 -42
- package/dist/npm/modern/bundled/umd/index.js +43 -42
- package/dist/npm/modern/cjs/index.cjs +43 -42
- package/dist/npm/modern/content-script/cjs/index.cjs +43 -42
- package/dist/npm/modern/content-script/esm/index.mjs +43 -42
- package/dist/npm/modern/content-script/umd/index.js +43 -42
- package/dist/npm/modern/esm/index.mjs +43 -42
- package/dist/npm/modern/umd/index.js +43 -42
- package/package.json +1 -1
|
@@ -506,7 +506,7 @@ error.stack=`${stack}\n${MANUAL_ERROR_IDENTIFIER}`;break;case stacktrace:// esli
|
|
|
506
506
|
error.stacktrace=`${stacktrace}\n${MANUAL_ERROR_IDENTIFIER}`;break;case operaSourceloc:default:// eslint-disable-next-line no-param-reassign
|
|
507
507
|
error['opera#sourceloc']=`${operaSourceloc}\n${MANUAL_ERROR_IDENTIFIER}`;break;}}}globalThis.dispatchEvent(new ErrorEvent('error',{error,bubbles:true,cancelable:true,composed:true}));};
|
|
508
508
|
|
|
509
|
-
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.
|
|
509
|
+
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.26.0';const APP_NAMESPACE='com.rudderlabs.javascript';const MODULE_TYPE='npm';const ADBLOCK_PAGE_CATEGORY='RudderJS-Initiated';const ADBLOCK_PAGE_NAME='ad-block page request';const ADBLOCK_PAGE_PATH='/ad-blocked';const GLOBAL_PRELOAD_BUFFER='preloadedEventsBuffer';const CONSENT_TRACK_EVENT_NAME='Consent Management Interaction';
|
|
510
510
|
|
|
511
511
|
const QUERY_PARAM_TRAIT_PREFIX='ajs_trait_';const QUERY_PARAM_PROPERTY_PREFIX='ajs_prop_';const QUERY_PARAM_ANONYMOUS_ID_KEY='ajs_aid';const QUERY_PARAM_USER_ID_KEY='ajs_uid';const QUERY_PARAM_TRACK_EVENT_NAME_KEY='ajs_event';
|
|
512
512
|
|
|
@@ -534,8 +534,9 @@ data[dataKey]=params.get(key);}});return data;};/**
|
|
|
534
534
|
* Parse query string into preload buffer events & push into existing array before any other events
|
|
535
535
|
*/const retrieveEventsFromQueryString=(argumentsArray=[])=>{// Mapping for trait and properties values based on key prefix
|
|
536
536
|
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
|
|
537
|
-
if(queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY)){argumentsArray.unshift(['track',queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY),getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.properties)]);}//
|
|
538
|
-
|
|
537
|
+
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
|
|
538
|
+
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
|
|
539
|
+
const identifyApiArgs=[...(userId?[userId]:[]),userTraits];argumentsArray.unshift(['identify',...identifyApiArgs]);}// Set anonymousID
|
|
539
540
|
if(queryObject.get(QUERY_PARAM_ANONYMOUS_ID_KEY)){argumentsArray.unshift(['setAnonymousId',queryObject.get(QUERY_PARAM_ANONYMOUS_ID_KEY)]);}};/**
|
|
540
541
|
* Retrieve an existing buffered load method call and remove from the existing array
|
|
541
542
|
*/const getPreloadedLoadEvent=preloadedEventsArray=>{const loadMethodName='load';let loadEvent=[];/**
|
|
@@ -644,7 +645,7 @@ const BUILD_TYPE='modern';const SDK_CDN_BASE_URL='https://cdn.rudderlabs.com';co
|
|
|
644
645
|
|
|
645
646
|
const DEFAULT_STORAGE_ENCRYPTION_VERSION='v3';const DEFAULT_DATA_PLANE_EVENTS_TRANSPORT='xhr';const ConsentManagersToPluginNameMap={iubenda:'IubendaConsentManager',oneTrust:'OneTrustConsentManager',ketch:'KetchConsentManager',custom:'CustomConsentManager'};const StorageEncryptionVersionsToPluginNameMap={[DEFAULT_STORAGE_ENCRYPTION_VERSION]:'StorageEncryption',legacy:'StorageEncryptionLegacy'};const DataPlaneEventsTransportToPluginNameMap={[DEFAULT_DATA_PLANE_EVENTS_TRANSPORT]:'XhrQueue',beacon:'BeaconQueue'};const DEFAULT_DATA_SERVICE_ENDPOINT='rsaRequest';const METRICS_SERVICE_ENDPOINT='rsaMetrics';const CUSTOM_DEVICE_MODE_DESTINATION_DISPLAY_NAME='Custom Device Mode';
|
|
646
647
|
|
|
647
|
-
const defaultLoadOptions={configUrl:DEFAULT_CONFIG_BE_URL,loadIntegration:true,sessions:{autoTrack:true,timeout:DEFAULT_SESSION_TIMEOUT_MS,cutOff:{enabled:false}},sameSiteCookie:'Lax',polyfillIfRequired:true,integrations:DEFAULT_INTEGRATIONS_CONFIG,useBeacon:false,beaconQueueOptions:{},destinationsQueueOptions:{},queueOptions:{},lockIntegrationsVersion:
|
|
648
|
+
const defaultLoadOptions={configUrl:DEFAULT_CONFIG_BE_URL,loadIntegration:true,sessions:{autoTrack:true,timeout:DEFAULT_SESSION_TIMEOUT_MS,cutOff:{enabled:false}},sameSiteCookie:'Lax',polyfillIfRequired:true,integrations:DEFAULT_INTEGRATIONS_CONFIG,useBeacon:false,beaconQueueOptions:{},destinationsQueueOptions:{},queueOptions:{},lockIntegrationsVersion:true,lockPluginsVersion:true,uaChTrackLevel:'none',plugins:[],useGlobalIntegrationsConfigInEvents:false,bufferDataPlaneEventsUntilReady:false,dataPlaneEventsBufferTimeout:DEFAULT_DATA_PLANE_EVENTS_BUFFER_TIMEOUT_MS,storage:{encryption:{version:DEFAULT_STORAGE_ENCRYPTION_VERSION},migrate:true,cookie:{}},sendAdblockPage:false,sameDomainCookiesOnly:false,secureCookie:false,sendAdblockPageOptions:{},useServerSideCookies:false};const loadOptionsState=d(clone(defaultLoadOptions));
|
|
648
649
|
|
|
649
650
|
const DEFAULT_USER_SESSION_VALUES=deepFreeze({userId:'',userTraits:{},anonymousId:'',groupId:'',groupTraits:{},initialReferrer:'',initialReferringDomain:'',sessionInfo:{},authToken:null});const DEFAULT_RESET_OPTIONS=deepFreeze({entries:{userId:true,userTraits:true,groupId:true,groupTraits:true,sessionInfo:true,authToken:true,// These are not reset by default
|
|
650
651
|
anonymousId:false,initialReferrer:false,initialReferringDomain:false}});const SERVER_SIDE_COOKIES_DEBOUNCE_TIME=10;// milliseconds
|
|
@@ -781,8 +782,8 @@ throw err;}};
|
|
|
781
782
|
const getErrInstance=(err,errorType)=>{switch(errorType){case ErrorType.UNHANDLEDEXCEPTION:{const{error}=err;return error||err;}case ErrorType.UNHANDLEDREJECTION:{return err.reason;}case ErrorType.HANDLEDEXCEPTION:default:return err;}};const createNewBreadcrumb=message=>({type:'manual',name:message,timestamp:new Date(),metaData:{}});/**
|
|
782
783
|
* A function to get the Bugsnag release stage for the current environment
|
|
783
784
|
* @param getHostName Optional function to get the hostname (primarily for testing)
|
|
784
|
-
* @returns 'development' if the host is empty (for file:// protocol etc.) or a dev host (localhost, 127.0.0.1, etc.), otherwise ''
|
|
785
|
-
*/const getReleaseStage=(getHostName=()=>window.location.hostname)=>{const host=getHostName();return !host||host&&DEV_HOSTS.includes(host)?'development':'
|
|
785
|
+
* @returns 'development' if the host is empty (for file:// protocol etc.) or a dev host (localhost, 127.0.0.1, etc.), otherwise ''production'' (it'll be replaced with the actual release stage during the build)
|
|
786
|
+
*/const getReleaseStage=(getHostName=()=>window.location.hostname)=>{const host=getHostName();return !host||host&&DEV_HOSTS.includes(host)?'development':'production';};const getAppStateForMetadata=state=>{const stateStr=stringifyWithoutCircular(state,false,APP_STATE_EXCLUDE_KEYS);return stateStr!==null?JSON.parse(stateStr):{};};const getURLWithoutQueryString=()=>{const url=globalThis.location.href.split('?');return url[0];};const getUserDetails=(source,session,lifecycle,autoTrack)=>({id:`${source.value?.id??lifecycle.writeKey.value}..${session.sessionInfo.value.id??'NA'}..${autoTrack.pageLifecycle.pageViewId.value??'NA'}`,name:source.value?.name??'NA'});const getDeviceDetails=(locale,userAgent)=>({locale:locale.value??'NA',userAgent:userAgent.value??'NA',time:new Date()});const getBugsnagErrorEvent=(exception,errorState,state,groupingHash)=>{const{context,lifecycle,session,source,reporting,autoTrack}=state;const{app,locale,userAgent,timezone,screen,library}=context;return {payloadVersion:'5',notifier:{name:NOTIFIER_NAME,version:app.value.version,url:SDK_GITHUB_URL},events:[{exceptions:[clone(exception)],severity:errorState.severity,unhandled:errorState.unhandled,severityReason:errorState.severityReason,app:{version:app.value.version,releaseStage:getReleaseStage(),type:app.value.installType},device:getDeviceDetails(locale,userAgent),request:{url:getURLWithoutQueryString(),clientIp:'[NOT COLLECTED]'},breadcrumbs:clone(reporting.breadcrumbs.value),context:exception.message,groupingHash,metaData:{app:{snippetVersion:library.value.snippetVersion},device:{...screen.value,timezone:timezone.value},// Add rest of the state groups as metadata
|
|
786
787
|
// so that they show up as separate tabs in the dashboard
|
|
787
788
|
...getAppStateForMetadata(state)},user:getUserDetails(source,session,lifecycle,autoTrack)}]};};/**
|
|
788
789
|
* A function to check if adblockers are active. The promise's resolve function
|
|
@@ -1582,10 +1583,8 @@ enrichedEvent.userId=to??enrichedEvent.userId;return enrichedEvent;}/**
|
|
|
1582
1583
|
*/addEvent(event){this.userSessionManager.refreshSession();const rudderEvent=this.eventFactory.create(event);this.eventRepository.enqueue(rudderEvent,event.callback);}}
|
|
1583
1584
|
|
|
1584
1585
|
class UserSessionManager{/**
|
|
1585
|
-
* Tracks whether
|
|
1586
|
-
|
|
1587
|
-
* Tracks the number of queued cookie set requests
|
|
1588
|
-
*/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={};this.serverSideCookieSetRequests={};}/**
|
|
1586
|
+
* Tracks whether a server-side cookie setting request is in progress or not.
|
|
1587
|
+
*/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={};}/**
|
|
1589
1588
|
* Initialize User session with values from storage
|
|
1590
1589
|
*/init(){this.syncStorageDataToState();// Register the effect to sync with storage
|
|
1591
1590
|
this.registerEffects();}syncStorageDataToState(){this.migrateStorageIfNeeded();this.migrateDataFromPreviousStorage();// get the values from storage and set it again
|
|
@@ -1615,32 +1614,28 @@ cutOffDuration=DEFAULT_SESSION_CUT_OFF_DURATION_MS;}else if(cutOffDuration<sessi
|
|
|
1615
1614
|
* @param callback
|
|
1616
1615
|
*/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});}/**
|
|
1617
1616
|
* A function to make an external request to set the cookie from server side
|
|
1618
|
-
* @param key
|
|
1619
|
-
* @param
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
const
|
|
1617
|
+
* @param sessionToCookiesMap map of session key to cookie name
|
|
1618
|
+
* @param cb callback function to be called when the cookie is set
|
|
1619
|
+
* @param store store to be used to get the cookie value
|
|
1620
|
+
*/setServerSideCookies(sessionToCookiesMap,cb,store){// Retrieve the cookie value from the state
|
|
1621
|
+
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
|
|
1622
|
+
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
|
|
1623
|
+
const encryptedCookieData=this.getEncryptedCookieData(getCurrentCookieValuesFromState(),store);if(encryptedCookieData.length>0){// make request to data service to set the cookie from server side
|
|
1623
1624
|
this.makeRequestToSetCookie(encryptedCookieData,(res,details)=>{// Mark the cookie req status as done
|
|
1624
|
-
clearInProgressFlags();if(details?.xhr?.status===200){
|
|
1625
|
-
|
|
1626
|
-
|
|
1625
|
+
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.
|
|
1626
|
+
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
|
|
1627
|
+
// or other cookie requests might have updated the cookie value.
|
|
1628
|
+
// Log an error only when cookie didn't exist previously and currently also doesn't exist.
|
|
1629
|
+
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
|
|
1630
|
+
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
|
|
1631
|
+
clearInProgressFlags();}}/**
|
|
1627
1632
|
* A function to sync values in storage
|
|
1628
1633
|
* @param sessionKey
|
|
1629
|
-
|
|
1630
|
-
*/syncValueToStorage(sessionKey,stateValue){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;// Determine the final user session entry value
|
|
1631
|
-
const value=stateValue??state.session[sessionKey].value;if(value&&(isString(value)||isNonEmptyObject(value))){// if useServerSideCookies load option is set to true
|
|
1634
|
+
*/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
|
|
1632
1635
|
// set the cookie from server side
|
|
1633
1636
|
if(state.serverCookies.isEnabledServerSideCookies.value&&storageType===COOKIE_STORAGE){// Mark the requests as in progress.
|
|
1634
|
-
this.serverSideCookiesRequestInProgress[sessionKey]=true;
|
|
1635
|
-
|
|
1636
|
-
// The first request is sent immediately to prevent events from missing session info.
|
|
1637
|
-
// Subsequent changes within the debounce window are consolidated into a single request
|
|
1638
|
-
// that sends the latest value after the debounce delay. Intermediate values are not persisted.
|
|
1639
|
-
if(!this.serverSideCookieDebounceFuncs[sessionKey]){this.serverSideCookieSetRequests[sessionKey]=0;// For the first time, make the cookie request anyway.
|
|
1640
|
-
setCookieFunc();this.serverSideCookieDebounceFuncs[sessionKey]=globalThis.setTimeout(()=>{delete this.serverSideCookieDebounceFuncs[sessionKey];// In the debounce function, make the cookie request only when cookie requests are waiting
|
|
1641
|
-
// in the queue. The first request would have been sent already.
|
|
1642
|
-
if(this.serverSideCookieSetRequests[sessionKey]>0){setCookieFunc();this.serverSideCookieSetRequests[sessionKey]=0;}},SERVER_SIDE_COOKIES_DEBOUNCE_TIME);}else {// Increment the queued cookie set actions
|
|
1643
|
-
this.serverSideCookieSetRequests[sessionKey]+=1;}}else {curStore?.set(key,value);}}else {curStore?.remove(key);}}}/**
|
|
1637
|
+
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
|
|
1638
|
+
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);}}}/**
|
|
1644
1639
|
* Function to update storage whenever state value changes
|
|
1645
1640
|
*/registerEffects(){// This will work as long as the user session entry key names are same as the state keys
|
|
1646
1641
|
USER_SESSION_KEYS.forEach(sessionKey=>{E(()=>{this.syncValueToStorage(sessionKey);});});}/**
|
|
@@ -1660,37 +1655,43 @@ const autoCapturedAnonymousId=this.pluginsManager?.invokeSingle('storage.getAnon
|
|
|
1660
1655
|
// This is needed for entries that are fetched from the storage
|
|
1661
1656
|
// during the current session (for example, session info)
|
|
1662
1657
|
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;}/**
|
|
1658
|
+
* Fetches the value for a session key. Preferably from storage, if the server-side
|
|
1659
|
+
* cookies request is not in progress. Otherwise, from the state.
|
|
1660
|
+
* @param sessionKey - The session key to fetch the value for
|
|
1661
|
+
* @returns - The value for the session key
|
|
1662
|
+
*/getUserSessionValue(sessionKey){// If the server-side cookies request is in progress, fetch the value from the state.
|
|
1663
|
+
if(this.serverSideCookiesRequestInProgress[sessionKey]){return state.session[sessionKey].value;}// Otherwise, fetch the value from storage.
|
|
1664
|
+
return this.getEntryValue(sessionKey);}/**
|
|
1663
1665
|
* Fetches User Id
|
|
1664
1666
|
* @returns
|
|
1665
|
-
*/getUserId(){return this.
|
|
1667
|
+
*/getUserId(){return this.getUserSessionValue('userId');}/**
|
|
1666
1668
|
* Fetches User Traits
|
|
1667
1669
|
* @returns
|
|
1668
|
-
*/getUserTraits(){return this.
|
|
1670
|
+
*/getUserTraits(){return this.getUserSessionValue('userTraits');}/**
|
|
1669
1671
|
* Fetches Group Id
|
|
1670
1672
|
* @returns
|
|
1671
|
-
*/getGroupId(){return this.
|
|
1673
|
+
*/getGroupId(){return this.getUserSessionValue('groupId');}/**
|
|
1672
1674
|
* Fetches Group Traits
|
|
1673
1675
|
* @returns
|
|
1674
|
-
*/getGroupTraits(){return this.
|
|
1676
|
+
*/getGroupTraits(){return this.getUserSessionValue('groupTraits');}/**
|
|
1675
1677
|
* Fetches Initial Referrer
|
|
1676
1678
|
* @returns
|
|
1677
|
-
*/getInitialReferrer(){return this.
|
|
1679
|
+
*/getInitialReferrer(){return this.getUserSessionValue('initialReferrer');}/**
|
|
1678
1680
|
* Fetches Initial Referring domain
|
|
1679
1681
|
* @returns
|
|
1680
|
-
*/getInitialReferringDomain(){return this.
|
|
1682
|
+
*/getInitialReferringDomain(){return this.getUserSessionValue('initialReferringDomain');}/**
|
|
1681
1683
|
* Fetches session tracking information from storage
|
|
1682
1684
|
* @returns
|
|
1683
|
-
*/getSessionInfo(){return this.
|
|
1685
|
+
*/getSessionInfo(){return this.getUserSessionValue('sessionInfo');}/**
|
|
1684
1686
|
* Fetches auth token from storage
|
|
1685
1687
|
* @returns
|
|
1686
|
-
*/getAuthToken(){return this.
|
|
1688
|
+
*/getAuthToken(){return this.getUserSessionValue('authToken');}/**
|
|
1687
1689
|
* If session is active it returns the sessionId
|
|
1688
1690
|
* @returns
|
|
1689
1691
|
*/getSessionId(){const sessionInfo=this.getSessionInfo()??DEFAULT_USER_SESSION_VALUES.sessionInfo;if(sessionInfo.autoTrack&&!hasSessionExpired(sessionInfo)||sessionInfo.manualTrack){return sessionInfo.id??null;}return null;}/**
|
|
1690
1692
|
* A function to keep the session information up to date in the state
|
|
1691
1693
|
* before using it for building event payloads.
|
|
1692
|
-
*/refreshSession(){let
|
|
1693
|
-
if(initialSessionInfo===null&&this.serverSideCookiesRequestInProgress['sessionInfo']){initialSessionInfo=state.session.sessionInfo.value;}let sessionInfo=initialSessionInfo??DEFAULT_USER_SESSION_VALUES.sessionInfo;if(sessionInfo.autoTrack||sessionInfo.manualTrack){if(sessionInfo.autoTrack){this.startOrRenewAutoTracking(sessionInfo);sessionInfo=state.session.sessionInfo.value;}// Note that if sessionStart is false, then it's an active session.
|
|
1694
|
+
*/refreshSession(){let sessionInfo=this.getSessionInfo()??DEFAULT_USER_SESSION_VALUES.sessionInfo;if(sessionInfo.autoTrack||sessionInfo.manualTrack){if(sessionInfo.autoTrack){this.startOrRenewAutoTracking(sessionInfo);sessionInfo=state.session.sessionInfo.value;}// Note that if sessionStart is false, then it's an active session.
|
|
1694
1695
|
// So, we needn't update the session info.
|
|
1695
1696
|
//
|
|
1696
1697
|
// For other scenarios,
|
|
@@ -1700,7 +1701,7 @@ if(initialSessionInfo===null&&this.serverSideCookiesRequestInProgress['sessionIn
|
|
|
1700
1701
|
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.
|
|
1701
1702
|
state.session.sessionInfo.value=sessionInfo;if(state.lifecycle.status.value!=='readyExecuted'){// Force update the storage as the 'effect' blocks are not getting triggered
|
|
1702
1703
|
// when processing preload buffered requests
|
|
1703
|
-
this.syncValueToStorage('sessionInfo'
|
|
1704
|
+
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();}}/**
|
|
1704
1705
|
* Reset state values
|
|
1705
1706
|
* @param options options for reset
|
|
1706
1707
|
* @returns
|
|
@@ -512,7 +512,7 @@
|
|
|
512
512
|
error.stacktrace=`${stacktrace}\n${MANUAL_ERROR_IDENTIFIER}`;break;case operaSourceloc:default:// eslint-disable-next-line no-param-reassign
|
|
513
513
|
error['opera#sourceloc']=`${operaSourceloc}\n${MANUAL_ERROR_IDENTIFIER}`;break;}}}globalThis.dispatchEvent(new ErrorEvent('error',{error,bubbles:true,cancelable:true,composed:true}));};
|
|
514
514
|
|
|
515
|
-
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.
|
|
515
|
+
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.26.0';const APP_NAMESPACE='com.rudderlabs.javascript';const MODULE_TYPE='npm';const ADBLOCK_PAGE_CATEGORY='RudderJS-Initiated';const ADBLOCK_PAGE_NAME='ad-block page request';const ADBLOCK_PAGE_PATH='/ad-blocked';const GLOBAL_PRELOAD_BUFFER='preloadedEventsBuffer';const CONSENT_TRACK_EVENT_NAME='Consent Management Interaction';
|
|
516
516
|
|
|
517
517
|
const QUERY_PARAM_TRAIT_PREFIX='ajs_trait_';const QUERY_PARAM_PROPERTY_PREFIX='ajs_prop_';const QUERY_PARAM_ANONYMOUS_ID_KEY='ajs_aid';const QUERY_PARAM_USER_ID_KEY='ajs_uid';const QUERY_PARAM_TRACK_EVENT_NAME_KEY='ajs_event';
|
|
518
518
|
|
|
@@ -540,8 +540,9 @@
|
|
|
540
540
|
* Parse query string into preload buffer events & push into existing array before any other events
|
|
541
541
|
*/const retrieveEventsFromQueryString=(argumentsArray=[])=>{// Mapping for trait and properties values based on key prefix
|
|
542
542
|
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
|
|
543
|
-
if(queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY)){argumentsArray.unshift(['track',queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY),getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.properties)]);}//
|
|
544
|
-
|
|
543
|
+
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
|
|
544
|
+
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
|
|
545
|
+
const identifyApiArgs=[...(userId?[userId]:[]),userTraits];argumentsArray.unshift(['identify',...identifyApiArgs]);}// Set anonymousID
|
|
545
546
|
if(queryObject.get(QUERY_PARAM_ANONYMOUS_ID_KEY)){argumentsArray.unshift(['setAnonymousId',queryObject.get(QUERY_PARAM_ANONYMOUS_ID_KEY)]);}};/**
|
|
546
547
|
* Retrieve an existing buffered load method call and remove from the existing array
|
|
547
548
|
*/const getPreloadedLoadEvent=preloadedEventsArray=>{const loadMethodName='load';let loadEvent=[];/**
|
|
@@ -650,7 +651,7 @@
|
|
|
650
651
|
|
|
651
652
|
const DEFAULT_STORAGE_ENCRYPTION_VERSION='v3';const DEFAULT_DATA_PLANE_EVENTS_TRANSPORT='xhr';const ConsentManagersToPluginNameMap={iubenda:'IubendaConsentManager',oneTrust:'OneTrustConsentManager',ketch:'KetchConsentManager',custom:'CustomConsentManager'};const StorageEncryptionVersionsToPluginNameMap={[DEFAULT_STORAGE_ENCRYPTION_VERSION]:'StorageEncryption',legacy:'StorageEncryptionLegacy'};const DataPlaneEventsTransportToPluginNameMap={[DEFAULT_DATA_PLANE_EVENTS_TRANSPORT]:'XhrQueue',beacon:'BeaconQueue'};const DEFAULT_DATA_SERVICE_ENDPOINT='rsaRequest';const METRICS_SERVICE_ENDPOINT='rsaMetrics';const CUSTOM_DEVICE_MODE_DESTINATION_DISPLAY_NAME='Custom Device Mode';
|
|
652
653
|
|
|
653
|
-
const defaultLoadOptions={configUrl:DEFAULT_CONFIG_BE_URL,loadIntegration:true,sessions:{autoTrack:true,timeout:DEFAULT_SESSION_TIMEOUT_MS,cutOff:{enabled:false}},sameSiteCookie:'Lax',polyfillIfRequired:true,integrations:DEFAULT_INTEGRATIONS_CONFIG,useBeacon:false,beaconQueueOptions:{},destinationsQueueOptions:{},queueOptions:{},lockIntegrationsVersion:
|
|
654
|
+
const defaultLoadOptions={configUrl:DEFAULT_CONFIG_BE_URL,loadIntegration:true,sessions:{autoTrack:true,timeout:DEFAULT_SESSION_TIMEOUT_MS,cutOff:{enabled:false}},sameSiteCookie:'Lax',polyfillIfRequired:true,integrations:DEFAULT_INTEGRATIONS_CONFIG,useBeacon:false,beaconQueueOptions:{},destinationsQueueOptions:{},queueOptions:{},lockIntegrationsVersion:true,lockPluginsVersion:true,uaChTrackLevel:'none',plugins:[],useGlobalIntegrationsConfigInEvents:false,bufferDataPlaneEventsUntilReady:false,dataPlaneEventsBufferTimeout:DEFAULT_DATA_PLANE_EVENTS_BUFFER_TIMEOUT_MS,storage:{encryption:{version:DEFAULT_STORAGE_ENCRYPTION_VERSION},migrate:true,cookie:{}},sendAdblockPage:false,sameDomainCookiesOnly:false,secureCookie:false,sendAdblockPageOptions:{},useServerSideCookies:false};const loadOptionsState=d(clone(defaultLoadOptions));
|
|
654
655
|
|
|
655
656
|
const DEFAULT_USER_SESSION_VALUES=deepFreeze({userId:'',userTraits:{},anonymousId:'',groupId:'',groupTraits:{},initialReferrer:'',initialReferringDomain:'',sessionInfo:{},authToken:null});const DEFAULT_RESET_OPTIONS=deepFreeze({entries:{userId:true,userTraits:true,groupId:true,groupTraits:true,sessionInfo:true,authToken:true,// These are not reset by default
|
|
656
657
|
anonymousId:false,initialReferrer:false,initialReferringDomain:false}});const SERVER_SIDE_COOKIES_DEBOUNCE_TIME=10;// milliseconds
|
|
@@ -787,8 +788,8 @@
|
|
|
787
788
|
const getErrInstance=(err,errorType)=>{switch(errorType){case ErrorType.UNHANDLEDEXCEPTION:{const{error}=err;return error||err;}case ErrorType.UNHANDLEDREJECTION:{return err.reason;}case ErrorType.HANDLEDEXCEPTION:default:return err;}};const createNewBreadcrumb=message=>({type:'manual',name:message,timestamp:new Date(),metaData:{}});/**
|
|
788
789
|
* A function to get the Bugsnag release stage for the current environment
|
|
789
790
|
* @param getHostName Optional function to get the hostname (primarily for testing)
|
|
790
|
-
* @returns 'development' if the host is empty (for file:// protocol etc.) or a dev host (localhost, 127.0.0.1, etc.), otherwise ''
|
|
791
|
-
*/const getReleaseStage=(getHostName=()=>window.location.hostname)=>{const host=getHostName();return !host||host&&DEV_HOSTS.includes(host)?'development':'
|
|
791
|
+
* @returns 'development' if the host is empty (for file:// protocol etc.) or a dev host (localhost, 127.0.0.1, etc.), otherwise ''production'' (it'll be replaced with the actual release stage during the build)
|
|
792
|
+
*/const getReleaseStage=(getHostName=()=>window.location.hostname)=>{const host=getHostName();return !host||host&&DEV_HOSTS.includes(host)?'development':'production';};const getAppStateForMetadata=state=>{const stateStr=stringifyWithoutCircular(state,false,APP_STATE_EXCLUDE_KEYS);return stateStr!==null?JSON.parse(stateStr):{};};const getURLWithoutQueryString=()=>{const url=globalThis.location.href.split('?');return url[0];};const getUserDetails=(source,session,lifecycle,autoTrack)=>({id:`${source.value?.id??lifecycle.writeKey.value}..${session.sessionInfo.value.id??'NA'}..${autoTrack.pageLifecycle.pageViewId.value??'NA'}`,name:source.value?.name??'NA'});const getDeviceDetails=(locale,userAgent)=>({locale:locale.value??'NA',userAgent:userAgent.value??'NA',time:new Date()});const getBugsnagErrorEvent=(exception,errorState,state,groupingHash)=>{const{context,lifecycle,session,source,reporting,autoTrack}=state;const{app,locale,userAgent,timezone,screen,library}=context;return {payloadVersion:'5',notifier:{name:NOTIFIER_NAME,version:app.value.version,url:SDK_GITHUB_URL},events:[{exceptions:[clone(exception)],severity:errorState.severity,unhandled:errorState.unhandled,severityReason:errorState.severityReason,app:{version:app.value.version,releaseStage:getReleaseStage(),type:app.value.installType},device:getDeviceDetails(locale,userAgent),request:{url:getURLWithoutQueryString(),clientIp:'[NOT COLLECTED]'},breadcrumbs:clone(reporting.breadcrumbs.value),context:exception.message,groupingHash,metaData:{app:{snippetVersion:library.value.snippetVersion},device:{...screen.value,timezone:timezone.value},// Add rest of the state groups as metadata
|
|
792
793
|
// so that they show up as separate tabs in the dashboard
|
|
793
794
|
...getAppStateForMetadata(state)},user:getUserDetails(source,session,lifecycle,autoTrack)}]};};/**
|
|
794
795
|
* A function to check if adblockers are active. The promise's resolve function
|
|
@@ -1588,10 +1589,8 @@
|
|
|
1588
1589
|
*/addEvent(event){this.userSessionManager.refreshSession();const rudderEvent=this.eventFactory.create(event);this.eventRepository.enqueue(rudderEvent,event.callback);}}
|
|
1589
1590
|
|
|
1590
1591
|
class UserSessionManager{/**
|
|
1591
|
-
* Tracks whether
|
|
1592
|
-
|
|
1593
|
-
* Tracks the number of queued cookie set requests
|
|
1594
|
-
*/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={};this.serverSideCookieSetRequests={};}/**
|
|
1592
|
+
* Tracks whether a server-side cookie setting request is in progress or not.
|
|
1593
|
+
*/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={};}/**
|
|
1595
1594
|
* Initialize User session with values from storage
|
|
1596
1595
|
*/init(){this.syncStorageDataToState();// Register the effect to sync with storage
|
|
1597
1596
|
this.registerEffects();}syncStorageDataToState(){this.migrateStorageIfNeeded();this.migrateDataFromPreviousStorage();// get the values from storage and set it again
|
|
@@ -1621,32 +1620,28 @@
|
|
|
1621
1620
|
* @param callback
|
|
1622
1621
|
*/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});}/**
|
|
1623
1622
|
* A function to make an external request to set the cookie from server side
|
|
1624
|
-
* @param key
|
|
1625
|
-
* @param
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
const
|
|
1623
|
+
* @param sessionToCookiesMap map of session key to cookie name
|
|
1624
|
+
* @param cb callback function to be called when the cookie is set
|
|
1625
|
+
* @param store store to be used to get the cookie value
|
|
1626
|
+
*/setServerSideCookies(sessionToCookiesMap,cb,store){// Retrieve the cookie value from the state
|
|
1627
|
+
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
|
|
1628
|
+
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
|
|
1629
|
+
const encryptedCookieData=this.getEncryptedCookieData(getCurrentCookieValuesFromState(),store);if(encryptedCookieData.length>0){// make request to data service to set the cookie from server side
|
|
1629
1630
|
this.makeRequestToSetCookie(encryptedCookieData,(res,details)=>{// Mark the cookie req status as done
|
|
1630
|
-
clearInProgressFlags();if(details?.xhr?.status===200){
|
|
1631
|
-
|
|
1632
|
-
|
|
1631
|
+
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.
|
|
1632
|
+
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
|
|
1633
|
+
// or other cookie requests might have updated the cookie value.
|
|
1634
|
+
// Log an error only when cookie didn't exist previously and currently also doesn't exist.
|
|
1635
|
+
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
|
|
1636
|
+
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
|
|
1637
|
+
clearInProgressFlags();}}/**
|
|
1633
1638
|
* A function to sync values in storage
|
|
1634
1639
|
* @param sessionKey
|
|
1635
|
-
|
|
1636
|
-
*/syncValueToStorage(sessionKey,stateValue){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;// Determine the final user session entry value
|
|
1637
|
-
const value=stateValue??state.session[sessionKey].value;if(value&&(isString(value)||isNonEmptyObject(value))){// if useServerSideCookies load option is set to true
|
|
1640
|
+
*/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
|
|
1638
1641
|
// set the cookie from server side
|
|
1639
1642
|
if(state.serverCookies.isEnabledServerSideCookies.value&&storageType===COOKIE_STORAGE){// Mark the requests as in progress.
|
|
1640
|
-
this.serverSideCookiesRequestInProgress[sessionKey]=true;
|
|
1641
|
-
|
|
1642
|
-
// The first request is sent immediately to prevent events from missing session info.
|
|
1643
|
-
// Subsequent changes within the debounce window are consolidated into a single request
|
|
1644
|
-
// that sends the latest value after the debounce delay. Intermediate values are not persisted.
|
|
1645
|
-
if(!this.serverSideCookieDebounceFuncs[sessionKey]){this.serverSideCookieSetRequests[sessionKey]=0;// For the first time, make the cookie request anyway.
|
|
1646
|
-
setCookieFunc();this.serverSideCookieDebounceFuncs[sessionKey]=globalThis.setTimeout(()=>{delete this.serverSideCookieDebounceFuncs[sessionKey];// In the debounce function, make the cookie request only when cookie requests are waiting
|
|
1647
|
-
// in the queue. The first request would have been sent already.
|
|
1648
|
-
if(this.serverSideCookieSetRequests[sessionKey]>0){setCookieFunc();this.serverSideCookieSetRequests[sessionKey]=0;}},SERVER_SIDE_COOKIES_DEBOUNCE_TIME);}else {// Increment the queued cookie set actions
|
|
1649
|
-
this.serverSideCookieSetRequests[sessionKey]+=1;}}else {curStore?.set(key,value);}}else {curStore?.remove(key);}}}/**
|
|
1643
|
+
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
|
|
1644
|
+
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);}}}/**
|
|
1650
1645
|
* Function to update storage whenever state value changes
|
|
1651
1646
|
*/registerEffects(){// This will work as long as the user session entry key names are same as the state keys
|
|
1652
1647
|
USER_SESSION_KEYS.forEach(sessionKey=>{E(()=>{this.syncValueToStorage(sessionKey);});});}/**
|
|
@@ -1666,37 +1661,43 @@
|
|
|
1666
1661
|
// This is needed for entries that are fetched from the storage
|
|
1667
1662
|
// during the current session (for example, session info)
|
|
1668
1663
|
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;}/**
|
|
1664
|
+
* Fetches the value for a session key. Preferably from storage, if the server-side
|
|
1665
|
+
* cookies request is not in progress. Otherwise, from the state.
|
|
1666
|
+
* @param sessionKey - The session key to fetch the value for
|
|
1667
|
+
* @returns - The value for the session key
|
|
1668
|
+
*/getUserSessionValue(sessionKey){// If the server-side cookies request is in progress, fetch the value from the state.
|
|
1669
|
+
if(this.serverSideCookiesRequestInProgress[sessionKey]){return state.session[sessionKey].value;}// Otherwise, fetch the value from storage.
|
|
1670
|
+
return this.getEntryValue(sessionKey);}/**
|
|
1669
1671
|
* Fetches User Id
|
|
1670
1672
|
* @returns
|
|
1671
|
-
*/getUserId(){return this.
|
|
1673
|
+
*/getUserId(){return this.getUserSessionValue('userId');}/**
|
|
1672
1674
|
* Fetches User Traits
|
|
1673
1675
|
* @returns
|
|
1674
|
-
*/getUserTraits(){return this.
|
|
1676
|
+
*/getUserTraits(){return this.getUserSessionValue('userTraits');}/**
|
|
1675
1677
|
* Fetches Group Id
|
|
1676
1678
|
* @returns
|
|
1677
|
-
*/getGroupId(){return this.
|
|
1679
|
+
*/getGroupId(){return this.getUserSessionValue('groupId');}/**
|
|
1678
1680
|
* Fetches Group Traits
|
|
1679
1681
|
* @returns
|
|
1680
|
-
*/getGroupTraits(){return this.
|
|
1682
|
+
*/getGroupTraits(){return this.getUserSessionValue('groupTraits');}/**
|
|
1681
1683
|
* Fetches Initial Referrer
|
|
1682
1684
|
* @returns
|
|
1683
|
-
*/getInitialReferrer(){return this.
|
|
1685
|
+
*/getInitialReferrer(){return this.getUserSessionValue('initialReferrer');}/**
|
|
1684
1686
|
* Fetches Initial Referring domain
|
|
1685
1687
|
* @returns
|
|
1686
|
-
*/getInitialReferringDomain(){return this.
|
|
1688
|
+
*/getInitialReferringDomain(){return this.getUserSessionValue('initialReferringDomain');}/**
|
|
1687
1689
|
* Fetches session tracking information from storage
|
|
1688
1690
|
* @returns
|
|
1689
|
-
*/getSessionInfo(){return this.
|
|
1691
|
+
*/getSessionInfo(){return this.getUserSessionValue('sessionInfo');}/**
|
|
1690
1692
|
* Fetches auth token from storage
|
|
1691
1693
|
* @returns
|
|
1692
|
-
*/getAuthToken(){return this.
|
|
1694
|
+
*/getAuthToken(){return this.getUserSessionValue('authToken');}/**
|
|
1693
1695
|
* If session is active it returns the sessionId
|
|
1694
1696
|
* @returns
|
|
1695
1697
|
*/getSessionId(){const sessionInfo=this.getSessionInfo()??DEFAULT_USER_SESSION_VALUES.sessionInfo;if(sessionInfo.autoTrack&&!hasSessionExpired(sessionInfo)||sessionInfo.manualTrack){return sessionInfo.id??null;}return null;}/**
|
|
1696
1698
|
* A function to keep the session information up to date in the state
|
|
1697
1699
|
* before using it for building event payloads.
|
|
1698
|
-
*/refreshSession(){let
|
|
1699
|
-
if(initialSessionInfo===null&&this.serverSideCookiesRequestInProgress['sessionInfo']){initialSessionInfo=state.session.sessionInfo.value;}let sessionInfo=initialSessionInfo??DEFAULT_USER_SESSION_VALUES.sessionInfo;if(sessionInfo.autoTrack||sessionInfo.manualTrack){if(sessionInfo.autoTrack){this.startOrRenewAutoTracking(sessionInfo);sessionInfo=state.session.sessionInfo.value;}// Note that if sessionStart is false, then it's an active session.
|
|
1700
|
+
*/refreshSession(){let sessionInfo=this.getSessionInfo()??DEFAULT_USER_SESSION_VALUES.sessionInfo;if(sessionInfo.autoTrack||sessionInfo.manualTrack){if(sessionInfo.autoTrack){this.startOrRenewAutoTracking(sessionInfo);sessionInfo=state.session.sessionInfo.value;}// Note that if sessionStart is false, then it's an active session.
|
|
1700
1701
|
// So, we needn't update the session info.
|
|
1701
1702
|
//
|
|
1702
1703
|
// For other scenarios,
|
|
@@ -1706,7 +1707,7 @@
|
|
|
1706
1707
|
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.
|
|
1707
1708
|
state.session.sessionInfo.value=sessionInfo;if(state.lifecycle.status.value!=='readyExecuted'){// Force update the storage as the 'effect' blocks are not getting triggered
|
|
1708
1709
|
// when processing preload buffered requests
|
|
1709
|
-
this.syncValueToStorage('sessionInfo'
|
|
1710
|
+
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();}}/**
|
|
1710
1711
|
* Reset state values
|
|
1711
1712
|
* @param options options for reset
|
|
1712
1713
|
* @returns
|
package/package.json
CHANGED