@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
|
@@ -510,7 +510,7 @@ error.stack=`${stack}\n${MANUAL_ERROR_IDENTIFIER}`;break;case stacktrace:// esli
|
|
|
510
510
|
error.stacktrace=`${stacktrace}\n${MANUAL_ERROR_IDENTIFIER}`;break;case operaSourceloc:default:// eslint-disable-next-line no-param-reassign
|
|
511
511
|
error['opera#sourceloc']=`${operaSourceloc}\n${MANUAL_ERROR_IDENTIFIER}`;break;}}}globalThis.dispatchEvent(new ErrorEvent('error',{error,bubbles:true,cancelable:true,composed:true}));};
|
|
512
512
|
|
|
513
|
-
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.
|
|
513
|
+
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';
|
|
514
514
|
|
|
515
515
|
const QUERY_PARAM_TRAIT_PREFIX='ajs_trait_';const QUERY_PARAM_PROPERTY_PREFIX='ajs_prop_';const QUERY_PARAM_ANONYMOUS_ID_KEY='ajs_aid';const QUERY_PARAM_USER_ID_KEY='ajs_uid';const QUERY_PARAM_TRACK_EVENT_NAME_KEY='ajs_event';
|
|
516
516
|
|
|
@@ -538,8 +538,9 @@ data[dataKey]=params.get(key);}});return data;};/**
|
|
|
538
538
|
* Parse query string into preload buffer events & push into existing array before any other events
|
|
539
539
|
*/const retrieveEventsFromQueryString=(argumentsArray=[])=>{// Mapping for trait and properties values based on key prefix
|
|
540
540
|
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
|
|
541
|
-
if(queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY)){argumentsArray.unshift(['track',queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY),getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.properties)]);}//
|
|
542
|
-
|
|
541
|
+
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
|
|
542
|
+
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
|
|
543
|
+
const identifyApiArgs=[...(userId?[userId]:[]),userTraits];argumentsArray.unshift(['identify',...identifyApiArgs]);}// Set anonymousID
|
|
543
544
|
if(queryObject.get(QUERY_PARAM_ANONYMOUS_ID_KEY)){argumentsArray.unshift(['setAnonymousId',queryObject.get(QUERY_PARAM_ANONYMOUS_ID_KEY)]);}};/**
|
|
544
545
|
* Retrieve an existing buffered load method call and remove from the existing array
|
|
545
546
|
*/const getPreloadedLoadEvent=preloadedEventsArray=>{const loadMethodName='load';let loadEvent=[];/**
|
|
@@ -648,7 +649,7 @@ const BUILD_TYPE='modern';const SDK_CDN_BASE_URL='https://cdn.rudderlabs.com';co
|
|
|
648
649
|
|
|
649
650
|
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';
|
|
650
651
|
|
|
651
|
-
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:
|
|
652
|
+
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));
|
|
652
653
|
|
|
653
654
|
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
|
|
654
655
|
anonymousId:false,initialReferrer:false,initialReferringDomain:false}});const SERVER_SIDE_COOKIES_DEBOUNCE_TIME=10;// milliseconds
|
|
@@ -785,8 +786,8 @@ throw err;}};
|
|
|
785
786
|
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:{}});/**
|
|
786
787
|
* A function to get the Bugsnag release stage for the current environment
|
|
787
788
|
* @param getHostName Optional function to get the hostname (primarily for testing)
|
|
788
|
-
* @returns 'development' if the host is empty (for file:// protocol etc.) or a dev host (localhost, 127.0.0.1, etc.), otherwise ''
|
|
789
|
-
*/const getReleaseStage=(getHostName=()=>window.location.hostname)=>{const host=getHostName();return !host||host&&DEV_HOSTS.includes(host)?'development':'
|
|
789
|
+
* @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)
|
|
790
|
+
*/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
|
|
790
791
|
// so that they show up as separate tabs in the dashboard
|
|
791
792
|
...getAppStateForMetadata(state)},user:getUserDetails(source,session,lifecycle,autoTrack)}]};};/**
|
|
792
793
|
* A function to check if adblockers are active. The promise's resolve function
|
|
@@ -1586,10 +1587,8 @@ enrichedEvent.userId=to??enrichedEvent.userId;return enrichedEvent;}/**
|
|
|
1586
1587
|
*/addEvent(event){this.userSessionManager.refreshSession();const rudderEvent=this.eventFactory.create(event);this.eventRepository.enqueue(rudderEvent,event.callback);}}
|
|
1587
1588
|
|
|
1588
1589
|
class UserSessionManager{/**
|
|
1589
|
-
* Tracks whether
|
|
1590
|
-
|
|
1591
|
-
* Tracks the number of queued cookie set requests
|
|
1592
|
-
*/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={};}/**
|
|
1590
|
+
* Tracks whether a server-side cookie setting request is in progress or not.
|
|
1591
|
+
*/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={};}/**
|
|
1593
1592
|
* Initialize User session with values from storage
|
|
1594
1593
|
*/init(){this.syncStorageDataToState();// Register the effect to sync with storage
|
|
1595
1594
|
this.registerEffects();}syncStorageDataToState(){this.migrateStorageIfNeeded();this.migrateDataFromPreviousStorage();// get the values from storage and set it again
|
|
@@ -1619,32 +1618,28 @@ cutOffDuration=DEFAULT_SESSION_CUT_OFF_DURATION_MS;}else if(cutOffDuration<sessi
|
|
|
1619
1618
|
* @param callback
|
|
1620
1619
|
*/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});}/**
|
|
1621
1620
|
* A function to make an external request to set the cookie from server side
|
|
1622
|
-
* @param key
|
|
1623
|
-
* @param
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
const
|
|
1621
|
+
* @param sessionToCookiesMap map of session key to cookie name
|
|
1622
|
+
* @param cb callback function to be called when the cookie is set
|
|
1623
|
+
* @param store store to be used to get the cookie value
|
|
1624
|
+
*/setServerSideCookies(sessionToCookiesMap,cb,store){// Retrieve the cookie value from the state
|
|
1625
|
+
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
|
|
1626
|
+
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
|
|
1627
|
+
const encryptedCookieData=this.getEncryptedCookieData(getCurrentCookieValuesFromState(),store);if(encryptedCookieData.length>0){// make request to data service to set the cookie from server side
|
|
1627
1628
|
this.makeRequestToSetCookie(encryptedCookieData,(res,details)=>{// Mark the cookie req status as done
|
|
1628
|
-
clearInProgressFlags();if(details?.xhr?.status===200){
|
|
1629
|
-
|
|
1630
|
-
|
|
1629
|
+
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.
|
|
1630
|
+
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
|
|
1631
|
+
// or other cookie requests might have updated the cookie value.
|
|
1632
|
+
// Log an error only when cookie didn't exist previously and currently also doesn't exist.
|
|
1633
|
+
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
|
|
1634
|
+
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
|
|
1635
|
+
clearInProgressFlags();}}/**
|
|
1631
1636
|
* A function to sync values in storage
|
|
1632
1637
|
* @param sessionKey
|
|
1633
|
-
|
|
1634
|
-
*/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
|
|
1635
|
-
const value=stateValue??state.session[sessionKey].value;if(value&&(isString(value)||isNonEmptyObject(value))){// if useServerSideCookies load option is set to true
|
|
1638
|
+
*/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
|
|
1636
1639
|
// set the cookie from server side
|
|
1637
1640
|
if(state.serverCookies.isEnabledServerSideCookies.value&&storageType===COOKIE_STORAGE){// Mark the requests as in progress.
|
|
1638
|
-
this.serverSideCookiesRequestInProgress[sessionKey]=true;
|
|
1639
|
-
|
|
1640
|
-
// The first request is sent immediately to prevent events from missing session info.
|
|
1641
|
-
// Subsequent changes within the debounce window are consolidated into a single request
|
|
1642
|
-
// that sends the latest value after the debounce delay. Intermediate values are not persisted.
|
|
1643
|
-
if(!this.serverSideCookieDebounceFuncs[sessionKey]){this.serverSideCookieSetRequests[sessionKey]=0;// For the first time, make the cookie request anyway.
|
|
1644
|
-
setCookieFunc();this.serverSideCookieDebounceFuncs[sessionKey]=globalThis.setTimeout(()=>{delete this.serverSideCookieDebounceFuncs[sessionKey];// In the debounce function, make the cookie request only when cookie requests are waiting
|
|
1645
|
-
// in the queue. The first request would have been sent already.
|
|
1646
|
-
if(this.serverSideCookieSetRequests[sessionKey]>0){setCookieFunc();this.serverSideCookieSetRequests[sessionKey]=0;}},SERVER_SIDE_COOKIES_DEBOUNCE_TIME);}else {// Increment the queued cookie set actions
|
|
1647
|
-
this.serverSideCookieSetRequests[sessionKey]+=1;}}else {curStore?.set(key,value);}}else {curStore?.remove(key);}}}/**
|
|
1641
|
+
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
|
|
1642
|
+
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);}}}/**
|
|
1648
1643
|
* Function to update storage whenever state value changes
|
|
1649
1644
|
*/registerEffects(){// This will work as long as the user session entry key names are same as the state keys
|
|
1650
1645
|
USER_SESSION_KEYS.forEach(sessionKey=>{E(()=>{this.syncValueToStorage(sessionKey);});});}/**
|
|
@@ -1664,37 +1659,43 @@ const autoCapturedAnonymousId=this.pluginsManager?.invokeSingle('storage.getAnon
|
|
|
1664
1659
|
// This is needed for entries that are fetched from the storage
|
|
1665
1660
|
// during the current session (for example, session info)
|
|
1666
1661
|
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;}/**
|
|
1662
|
+
* Fetches the value for a session key. Preferably from storage, if the server-side
|
|
1663
|
+
* cookies request is not in progress. Otherwise, from the state.
|
|
1664
|
+
* @param sessionKey - The session key to fetch the value for
|
|
1665
|
+
* @returns - The value for the session key
|
|
1666
|
+
*/getUserSessionValue(sessionKey){// If the server-side cookies request is in progress, fetch the value from the state.
|
|
1667
|
+
if(this.serverSideCookiesRequestInProgress[sessionKey]){return state.session[sessionKey].value;}// Otherwise, fetch the value from storage.
|
|
1668
|
+
return this.getEntryValue(sessionKey);}/**
|
|
1667
1669
|
* Fetches User Id
|
|
1668
1670
|
* @returns
|
|
1669
|
-
*/getUserId(){return this.
|
|
1671
|
+
*/getUserId(){return this.getUserSessionValue('userId');}/**
|
|
1670
1672
|
* Fetches User Traits
|
|
1671
1673
|
* @returns
|
|
1672
|
-
*/getUserTraits(){return this.
|
|
1674
|
+
*/getUserTraits(){return this.getUserSessionValue('userTraits');}/**
|
|
1673
1675
|
* Fetches Group Id
|
|
1674
1676
|
* @returns
|
|
1675
|
-
*/getGroupId(){return this.
|
|
1677
|
+
*/getGroupId(){return this.getUserSessionValue('groupId');}/**
|
|
1676
1678
|
* Fetches Group Traits
|
|
1677
1679
|
* @returns
|
|
1678
|
-
*/getGroupTraits(){return this.
|
|
1680
|
+
*/getGroupTraits(){return this.getUserSessionValue('groupTraits');}/**
|
|
1679
1681
|
* Fetches Initial Referrer
|
|
1680
1682
|
* @returns
|
|
1681
|
-
*/getInitialReferrer(){return this.
|
|
1683
|
+
*/getInitialReferrer(){return this.getUserSessionValue('initialReferrer');}/**
|
|
1682
1684
|
* Fetches Initial Referring domain
|
|
1683
1685
|
* @returns
|
|
1684
|
-
*/getInitialReferringDomain(){return this.
|
|
1686
|
+
*/getInitialReferringDomain(){return this.getUserSessionValue('initialReferringDomain');}/**
|
|
1685
1687
|
* Fetches session tracking information from storage
|
|
1686
1688
|
* @returns
|
|
1687
|
-
*/getSessionInfo(){return this.
|
|
1689
|
+
*/getSessionInfo(){return this.getUserSessionValue('sessionInfo');}/**
|
|
1688
1690
|
* Fetches auth token from storage
|
|
1689
1691
|
* @returns
|
|
1690
|
-
*/getAuthToken(){return this.
|
|
1692
|
+
*/getAuthToken(){return this.getUserSessionValue('authToken');}/**
|
|
1691
1693
|
* If session is active it returns the sessionId
|
|
1692
1694
|
* @returns
|
|
1693
1695
|
*/getSessionId(){const sessionInfo=this.getSessionInfo()??DEFAULT_USER_SESSION_VALUES.sessionInfo;if(sessionInfo.autoTrack&&!hasSessionExpired(sessionInfo)||sessionInfo.manualTrack){return sessionInfo.id??null;}return null;}/**
|
|
1694
1696
|
* A function to keep the session information up to date in the state
|
|
1695
1697
|
* before using it for building event payloads.
|
|
1696
|
-
*/refreshSession(){let
|
|
1697
|
-
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.
|
|
1698
|
+
*/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.
|
|
1698
1699
|
// So, we needn't update the session info.
|
|
1699
1700
|
//
|
|
1700
1701
|
// For other scenarios,
|
|
@@ -1704,7 +1705,7 @@ if(initialSessionInfo===null&&this.serverSideCookiesRequestInProgress['sessionIn
|
|
|
1704
1705
|
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.
|
|
1705
1706
|
state.session.sessionInfo.value=sessionInfo;if(state.lifecycle.status.value!=='readyExecuted'){// Force update the storage as the 'effect' blocks are not getting triggered
|
|
1706
1707
|
// when processing preload buffered requests
|
|
1707
|
-
this.syncValueToStorage('sessionInfo'
|
|
1708
|
+
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();}}/**
|
|
1708
1709
|
* Reset state values
|
|
1709
1710
|
* @param options options for reset
|
|
1710
1711
|
* @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.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';
|
|
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=[];/**
|
|
@@ -657,7 +658,7 @@ const BUILD_TYPE='modern';const SDK_CDN_BASE_URL='https://cdn.rudderlabs.com';co
|
|
|
657
658
|
|
|
658
659
|
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';
|
|
659
660
|
|
|
660
|
-
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:
|
|
661
|
+
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$1(clone(defaultLoadOptions));
|
|
661
662
|
|
|
662
663
|
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
|
|
663
664
|
anonymousId:false,initialReferrer:false,initialReferringDomain:false}});const SERVER_SIDE_COOKIES_DEBOUNCE_TIME=10;// milliseconds
|
|
@@ -794,8 +795,8 @@ throw err;}};
|
|
|
794
795
|
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:{}});/**
|
|
795
796
|
* A function to get the Bugsnag release stage for the current environment
|
|
796
797
|
* @param getHostName Optional function to get the hostname (primarily for testing)
|
|
797
|
-
* @returns 'development' if the host is empty (for file:// protocol etc.) or a dev host (localhost, 127.0.0.1, etc.), otherwise ''
|
|
798
|
-
*/const getReleaseStage=(getHostName=()=>window.location.hostname)=>{const host=getHostName();return !host||host&&DEV_HOSTS.includes(host)?'development':'
|
|
798
|
+
* @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)
|
|
799
|
+
*/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
|
|
799
800
|
// so that they show up as separate tabs in the dashboard
|
|
800
801
|
...getAppStateForMetadata(state)},user:getUserDetails(source,session,lifecycle,autoTrack)}]};};/**
|
|
801
802
|
* A function to check if adblockers are active. The promise's resolve function
|
|
@@ -3294,10 +3295,8 @@ enrichedEvent.userId=to??enrichedEvent.userId;return enrichedEvent;}/**
|
|
|
3294
3295
|
*/addEvent(event){this.userSessionManager.refreshSession();const rudderEvent=this.eventFactory.create(event);this.eventRepository.enqueue(rudderEvent,event.callback);}}
|
|
3295
3296
|
|
|
3296
3297
|
class UserSessionManager{/**
|
|
3297
|
-
* Tracks whether
|
|
3298
|
-
|
|
3299
|
-
* Tracks the number of queued cookie set requests
|
|
3300
|
-
*/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={};}/**
|
|
3298
|
+
* Tracks whether a server-side cookie setting request is in progress or not.
|
|
3299
|
+
*/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={};}/**
|
|
3301
3300
|
* Initialize User session with values from storage
|
|
3302
3301
|
*/init(){this.syncStorageDataToState();// Register the effect to sync with storage
|
|
3303
3302
|
this.registerEffects();}syncStorageDataToState(){this.migrateStorageIfNeeded();this.migrateDataFromPreviousStorage();// get the values from storage and set it again
|
|
@@ -3327,32 +3326,28 @@ cutOffDuration=DEFAULT_SESSION_CUT_OFF_DURATION_MS;}else if(cutOffDuration<sessi
|
|
|
3327
3326
|
* @param callback
|
|
3328
3327
|
*/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});}/**
|
|
3329
3328
|
* A function to make an external request to set the cookie from server side
|
|
3330
|
-
* @param key
|
|
3331
|
-
* @param
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
const
|
|
3329
|
+
* @param sessionToCookiesMap map of session key to cookie name
|
|
3330
|
+
* @param cb callback function to be called when the cookie is set
|
|
3331
|
+
* @param store store to be used to get the cookie value
|
|
3332
|
+
*/setServerSideCookies(sessionToCookiesMap,cb,store){// Retrieve the cookie value from the state
|
|
3333
|
+
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
|
|
3334
|
+
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
|
|
3335
|
+
const encryptedCookieData=this.getEncryptedCookieData(getCurrentCookieValuesFromState(),store);if(encryptedCookieData.length>0){// make request to data service to set the cookie from server side
|
|
3335
3336
|
this.makeRequestToSetCookie(encryptedCookieData,(res,details)=>{// Mark the cookie req status as done
|
|
3336
|
-
clearInProgressFlags();if(details?.xhr?.status===200){
|
|
3337
|
-
|
|
3338
|
-
|
|
3337
|
+
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.
|
|
3338
|
+
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
|
|
3339
|
+
// or other cookie requests might have updated the cookie value.
|
|
3340
|
+
// Log an error only when cookie didn't exist previously and currently also doesn't exist.
|
|
3341
|
+
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
|
|
3342
|
+
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
|
|
3343
|
+
clearInProgressFlags();}}/**
|
|
3339
3344
|
* A function to sync values in storage
|
|
3340
3345
|
* @param sessionKey
|
|
3341
|
-
|
|
3342
|
-
*/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
|
|
3343
|
-
const value=stateValue??state.session[sessionKey].value;if(value&&(isString(value)||isNonEmptyObject(value))){// if useServerSideCookies load option is set to true
|
|
3346
|
+
*/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
|
|
3344
3347
|
// set the cookie from server side
|
|
3345
3348
|
if(state.serverCookies.isEnabledServerSideCookies.value&&storageType===COOKIE_STORAGE){// Mark the requests as in progress.
|
|
3346
|
-
this.serverSideCookiesRequestInProgress[sessionKey]=true;
|
|
3347
|
-
|
|
3348
|
-
// The first request is sent immediately to prevent events from missing session info.
|
|
3349
|
-
// Subsequent changes within the debounce window are consolidated into a single request
|
|
3350
|
-
// that sends the latest value after the debounce delay. Intermediate values are not persisted.
|
|
3351
|
-
if(!this.serverSideCookieDebounceFuncs[sessionKey]){this.serverSideCookieSetRequests[sessionKey]=0;// For the first time, make the cookie request anyway.
|
|
3352
|
-
setCookieFunc();this.serverSideCookieDebounceFuncs[sessionKey]=globalThis.setTimeout(()=>{delete this.serverSideCookieDebounceFuncs[sessionKey];// In the debounce function, make the cookie request only when cookie requests are waiting
|
|
3353
|
-
// in the queue. The first request would have been sent already.
|
|
3354
|
-
if(this.serverSideCookieSetRequests[sessionKey]>0){setCookieFunc();this.serverSideCookieSetRequests[sessionKey]=0;}},SERVER_SIDE_COOKIES_DEBOUNCE_TIME);}else {// Increment the queued cookie set actions
|
|
3355
|
-
this.serverSideCookieSetRequests[sessionKey]+=1;}}else {curStore?.set(key,value);}}else {curStore?.remove(key);}}}/**
|
|
3349
|
+
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
|
|
3350
|
+
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);}}}/**
|
|
3356
3351
|
* Function to update storage whenever state value changes
|
|
3357
3352
|
*/registerEffects(){// This will work as long as the user session entry key names are same as the state keys
|
|
3358
3353
|
USER_SESSION_KEYS.forEach(sessionKey=>{E(()=>{this.syncValueToStorage(sessionKey);});});}/**
|
|
@@ -3372,37 +3367,43 @@ const autoCapturedAnonymousId=this.pluginsManager?.invokeSingle('storage.getAnon
|
|
|
3372
3367
|
// This is needed for entries that are fetched from the storage
|
|
3373
3368
|
// during the current session (for example, session info)
|
|
3374
3369
|
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;}/**
|
|
3370
|
+
* Fetches the value for a session key. Preferably from storage, if the server-side
|
|
3371
|
+
* cookies request is not in progress. Otherwise, from the state.
|
|
3372
|
+
* @param sessionKey - The session key to fetch the value for
|
|
3373
|
+
* @returns - The value for the session key
|
|
3374
|
+
*/getUserSessionValue(sessionKey){// If the server-side cookies request is in progress, fetch the value from the state.
|
|
3375
|
+
if(this.serverSideCookiesRequestInProgress[sessionKey]){return state.session[sessionKey].value;}// Otherwise, fetch the value from storage.
|
|
3376
|
+
return this.getEntryValue(sessionKey);}/**
|
|
3375
3377
|
* Fetches User Id
|
|
3376
3378
|
* @returns
|
|
3377
|
-
*/getUserId(){return this.
|
|
3379
|
+
*/getUserId(){return this.getUserSessionValue('userId');}/**
|
|
3378
3380
|
* Fetches User Traits
|
|
3379
3381
|
* @returns
|
|
3380
|
-
*/getUserTraits(){return this.
|
|
3382
|
+
*/getUserTraits(){return this.getUserSessionValue('userTraits');}/**
|
|
3381
3383
|
* Fetches Group Id
|
|
3382
3384
|
* @returns
|
|
3383
|
-
*/getGroupId(){return this.
|
|
3385
|
+
*/getGroupId(){return this.getUserSessionValue('groupId');}/**
|
|
3384
3386
|
* Fetches Group Traits
|
|
3385
3387
|
* @returns
|
|
3386
|
-
*/getGroupTraits(){return this.
|
|
3388
|
+
*/getGroupTraits(){return this.getUserSessionValue('groupTraits');}/**
|
|
3387
3389
|
* Fetches Initial Referrer
|
|
3388
3390
|
* @returns
|
|
3389
|
-
*/getInitialReferrer(){return this.
|
|
3391
|
+
*/getInitialReferrer(){return this.getUserSessionValue('initialReferrer');}/**
|
|
3390
3392
|
* Fetches Initial Referring domain
|
|
3391
3393
|
* @returns
|
|
3392
|
-
*/getInitialReferringDomain(){return this.
|
|
3394
|
+
*/getInitialReferringDomain(){return this.getUserSessionValue('initialReferringDomain');}/**
|
|
3393
3395
|
* Fetches session tracking information from storage
|
|
3394
3396
|
* @returns
|
|
3395
|
-
*/getSessionInfo(){return this.
|
|
3397
|
+
*/getSessionInfo(){return this.getUserSessionValue('sessionInfo');}/**
|
|
3396
3398
|
* Fetches auth token from storage
|
|
3397
3399
|
* @returns
|
|
3398
|
-
*/getAuthToken(){return this.
|
|
3400
|
+
*/getAuthToken(){return this.getUserSessionValue('authToken');}/**
|
|
3399
3401
|
* If session is active it returns the sessionId
|
|
3400
3402
|
* @returns
|
|
3401
3403
|
*/getSessionId(){const sessionInfo=this.getSessionInfo()??DEFAULT_USER_SESSION_VALUES.sessionInfo;if(sessionInfo.autoTrack&&!hasSessionExpired(sessionInfo)||sessionInfo.manualTrack){return sessionInfo.id??null;}return null;}/**
|
|
3402
3404
|
* A function to keep the session information up to date in the state
|
|
3403
3405
|
* before using it for building event payloads.
|
|
3404
|
-
*/refreshSession(){let
|
|
3405
|
-
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.
|
|
3406
|
+
*/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.
|
|
3406
3407
|
// So, we needn't update the session info.
|
|
3407
3408
|
//
|
|
3408
3409
|
// For other scenarios,
|
|
@@ -3412,7 +3413,7 @@ if(initialSessionInfo===null&&this.serverSideCookiesRequestInProgress['sessionIn
|
|
|
3412
3413
|
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.
|
|
3413
3414
|
state.session.sessionInfo.value=sessionInfo;if(state.lifecycle.status.value!=='readyExecuted'){// Force update the storage as the 'effect' blocks are not getting triggered
|
|
3414
3415
|
// when processing preload buffered requests
|
|
3415
|
-
this.syncValueToStorage('sessionInfo'
|
|
3416
|
+
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();}}/**
|
|
3416
3417
|
* Reset state values
|
|
3417
3418
|
* @param options options for reset
|
|
3418
3419
|
* @returns
|