UNPKG

@mparticle/web-sdk

Version:
1,133 lines (1,026 loc) 41.5 kB
import Constants from './constants'; import Polyfill from './polyfill'; import * as Utils from './utils'; var Base64 = Polyfill.Base64, Messages = Constants.Messages, Base64CookieKeys = Constants.Base64CookieKeys, SDKv2NonMPIDCookieKeys = Constants.SDKv2NonMPIDCookieKeys, StorageNames = Constants.StorageNames; export default function _Persistence(mpInstance) { var self = this; // https://go.mparticle.com/work/SQDSDKS-5022 this.useLocalStorage = function() { return ( !mpInstance._Store.SDKConfig.useCookieStorage && mpInstance._Store.isLocalStorageAvailable ); }; this.initializeStorage = function() { try { var storage, localStorageData = self.getLocalStorage(), cookies = self.getCookie(), allData; // https://go.mparticle.com/work/SQDSDKS-6045 // Determine if there is any data in cookies or localStorage to figure out if it is the first time the browser is loading mParticle if (!localStorageData && !cookies) { mpInstance._Store.isFirstRun = true; mpInstance._Store.mpid = 0; } else { mpInstance._Store.isFirstRun = false; } // https://go.mparticle.com/work/SQDSDKS-6045 if (!mpInstance._Store.isLocalStorageAvailable) { mpInstance._Store.SDKConfig.useCookieStorage = true; } // https://go.mparticle.com/work/SQDSDKS-6046 if (mpInstance._Store.isLocalStorageAvailable) { storage = window.localStorage; if (mpInstance._Store.SDKConfig.useCookieStorage) { // For migrating from localStorage to cookies -- If an instance switches from localStorage to cookies, then // no mParticle cookie exists yet and there is localStorage. Get the localStorage, set them to cookies, then delete the localStorage item. if (localStorageData) { if (cookies) { // https://go.mparticle.com/work/SQDSDKS-6047 allData = mpInstance._Helpers.extend( false, localStorageData, cookies ); } else { allData = localStorageData; } storage.removeItem(mpInstance._Store.storageName); } else if (cookies) { allData = cookies; } self.storeDataInMemory(allData); } else { // For migrating from cookie to localStorage -- If an instance is newly switching from cookies to localStorage, then // no mParticle localStorage exists yet and there are cookies. Get the cookies, set them to localStorage, then delete the cookies. if (cookies) { if (localStorageData) { // https://go.mparticle.com/work/SQDSDKS-6047 allData = mpInstance._Helpers.extend( false, localStorageData, cookies ); } else { allData = cookies; } self.storeDataInMemory(allData); self.expireCookies(mpInstance._Store.storageName); } else { self.storeDataInMemory(localStorageData); } } } else { self.storeDataInMemory(cookies); } // https://go.mparticle.com/work/SQDSDKS-6048 try { if (mpInstance._Store.isLocalStorageAvailable) { var encodedProducts = localStorage.getItem( mpInstance._Store.prodStorageName ); if (encodedProducts) { var decodedProducts = JSON.parse( Base64.decode(encodedProducts) ); } if (mpInstance._Store.mpid) { self.storeProductsInMemory( decodedProducts, mpInstance._Store.mpid ); } } } catch (e) { if (mpInstance._Store.isLocalStorageAvailable) { localStorage.removeItem(mpInstance._Store.prodStorageName); } mpInstance._Store.cartProducts = []; mpInstance.Logger.error( 'Error loading products in initialization: ' + e ); } // https://go.mparticle.com/work/SQDSDKS-6046 // Stores all non-current user MPID information into the store for (var key in allData) { if (allData.hasOwnProperty(key)) { if (!SDKv2NonMPIDCookieKeys[key]) { mpInstance._Store.nonCurrentUserMPIDs[key] = allData[key]; } } } self.update(); } catch (e) { // If cookies or local storage is corrupt, we want to remove it // so that in the future, initializeStorage will work if ( self.useLocalStorage() && mpInstance._Store.isLocalStorageAvailable ) { localStorage.removeItem(mpInstance._Store.storageName); } else { self.expireCookies(mpInstance._Store.storageName); } mpInstance.Logger.error('Error initializing storage: ' + e); } }; this.update = function() { if (!mpInstance._Store.webviewBridgeEnabled) { if (mpInstance._Store.SDKConfig.useCookieStorage) { self.setCookie(); } self.setLocalStorage(); } }; this.storeProductsInMemory = function(products, mpid) { if (products) { try { mpInstance._Store.cartProducts = products[mpid] && products[mpid].cp ? products[mpid].cp : []; } catch (e) { mpInstance.Logger.error( Messages.ErrorMessages.CookieParseError ); } } }; // https://go.mparticle.com/work/SQDSDKS-6045 this.storeDataInMemory = function(obj, currentMPID) { try { if (!obj) { mpInstance.Logger.verbose( Messages.InformationMessages.CookieNotFound ); mpInstance._Store.clientId = mpInstance._Store.clientId || mpInstance._Helpers.generateUniqueId(); mpInstance._Store.deviceId = mpInstance._Store.deviceId || mpInstance._Helpers.generateUniqueId(); } else { // Set MPID first, then change object to match MPID data if (currentMPID) { mpInstance._Store.mpid = currentMPID; } else { mpInstance._Store.mpid = obj.cu || 0; } obj.gs = obj.gs || {}; mpInstance._Store.sessionId = obj.gs.sid || mpInstance._Store.sessionId; mpInstance._Store.isEnabled = typeof obj.gs.ie !== 'undefined' ? obj.gs.ie : mpInstance._Store.isEnabled; mpInstance._Store.sessionAttributes = obj.gs.sa || mpInstance._Store.sessionAttributes; mpInstance._Store.localSessionAttributes = obj.gs.lsa || mpInstance._Store.localSessionAttributes; mpInstance._Store.serverSettings = obj.gs.ss || mpInstance._Store.serverSettings; mpInstance._Store.devToken = mpInstance._Store.devToken || obj.gs.dt; mpInstance._Store.SDKConfig.appVersion = mpInstance._Store.SDKConfig.appVersion || obj.gs.av; mpInstance._Store.clientId = obj.gs.cgid || mpInstance._Store.clientId || mpInstance._Helpers.generateUniqueId(); // For most persistence values, we prioritize localstorage/cookie values over // Store. However, we allow device ID to be overriden via a config value and // thus the priority of the deviceId value is // 1. value passed via config.deviceId // 2. previous value in persistence // 3. generate new guid mpInstance._Store.deviceId = mpInstance._Store.deviceId || obj.gs.das || mpInstance._Helpers.generateUniqueId(); mpInstance._Store.integrationAttributes = obj.gs.ia || {}; mpInstance._Store.context = obj.gs.c || mpInstance._Store.context; mpInstance._Store.currentSessionMPIDs = obj.gs.csm || mpInstance._Store.currentSessionMPIDs; mpInstance._Store.isLoggedIn = obj.l === true; if (obj.gs.les) { mpInstance._Store.dateLastEventSent = new Date(obj.gs.les); } if (obj.gs.ssd) { mpInstance._Store.sessionStartDate = new Date(obj.gs.ssd); } else { mpInstance._Store.sessionStartDate = new Date(); } if (currentMPID) { obj = obj[currentMPID]; } else { obj = obj[obj.cu]; } } } catch (e) { mpInstance.Logger.error(Messages.ErrorMessages.CookieParseError); } }; // https://go.mparticle.com/work/SQDSDKS-5022 this.determineLocalStorageAvailability = function(storage) { var result; if (window.mParticle && window.mParticle._forceNoLocalStorage) { storage = undefined; } try { storage.setItem('mparticle', 'test'); result = storage.getItem('mparticle') === 'test'; storage.removeItem('mparticle'); return result && storage; } catch (e) { return false; } }; this.getUserProductsFromLS = function(mpid) { if (!mpInstance._Store.isLocalStorageAvailable) { return []; } var decodedProducts, userProducts, parsedProducts, encodedProducts = localStorage.getItem( mpInstance._Store.prodStorageName ); if (encodedProducts) { decodedProducts = Base64.decode(encodedProducts); } // if there is an MPID, we are retrieving the user's products, which is an array if (mpid) { try { if (decodedProducts) { parsedProducts = JSON.parse(decodedProducts); } if ( decodedProducts && parsedProducts[mpid] && parsedProducts[mpid].cp && Array.isArray(parsedProducts[mpid].cp) ) { userProducts = parsedProducts[mpid].cp; } else { userProducts = []; } return userProducts; } catch (e) { return []; } } else { return []; } }; this.getAllUserProductsFromLS = function() { var decodedProducts, encodedProducts = localStorage.getItem( mpInstance._Store.prodStorageName ), parsedDecodedProducts; if (encodedProducts) { decodedProducts = Base64.decode(encodedProducts); } // returns an object with keys of MPID and values of array of products try { parsedDecodedProducts = JSON.parse(decodedProducts); } catch (e) { parsedDecodedProducts = {}; } return parsedDecodedProducts; }; // https://go.mparticle.com/work/SQDSDKS-6021 this.setLocalStorage = function() { if (!mpInstance._Store.isLocalStorageAvailable) { return; } var key = mpInstance._Store.storageName, allLocalStorageProducts = self.getAllUserProductsFromLS(), localStorageData = self.getLocalStorage() || {}, currentUser = mpInstance.Identity.getCurrentUser(), mpid = currentUser ? currentUser.getMPID() : null, currentUserProducts = { cp: allLocalStorageProducts[mpid] ? allLocalStorageProducts[mpid].cp : [], }; if (mpid) { allLocalStorageProducts = allLocalStorageProducts || {}; allLocalStorageProducts[mpid] = currentUserProducts; try { window.localStorage.setItem( encodeURIComponent(mpInstance._Store.prodStorageName), Base64.encode(JSON.stringify(allLocalStorageProducts)) ); } catch (e) { mpInstance.Logger.error( 'Error with setting products on localStorage.' ); } } if (!mpInstance._Store.SDKConfig.useCookieStorage) { localStorageData.gs = localStorageData.gs || {}; localStorageData.l = mpInstance._Store.isLoggedIn ? 1 : 0; if (mpInstance._Store.sessionId) { localStorageData.gs.csm = mpInstance._Store.currentSessionMPIDs; } localStorageData.gs.ie = mpInstance._Store.isEnabled; if (mpid) { localStorageData.cu = mpid; } if (Object.keys(mpInstance._Store.nonCurrentUserMPIDs).length) { localStorageData = mpInstance._Helpers.extend( {}, localStorageData, mpInstance._Store.nonCurrentUserMPIDs ); mpInstance._Store.nonCurrentUserMPIDs = {}; } localStorageData = setGlobalStorageAttributes(localStorageData); try { window.localStorage.setItem( encodeURIComponent(key), self.encodePersistence(JSON.stringify(localStorageData)) ); } catch (e) { mpInstance.Logger.error( 'Error with setting localStorage item.' ); } } }; function setGlobalStorageAttributes(data) { var store = mpInstance._Store; data.gs.sid = store.sessionId; data.gs.ie = store.isEnabled; data.gs.sa = store.sessionAttributes; data.gs.lsa = store.localSessionAttributes; data.gs.ss = store.serverSettings; data.gs.dt = store.devToken; data.gs.les = store.dateLastEventSent ? store.dateLastEventSent.getTime() : null; data.gs.av = store.SDKConfig.appVersion; data.gs.cgid = store.clientId; data.gs.das = store.deviceId; data.gs.c = store.context; data.gs.ssd = store.sessionStartDate ? store.sessionStartDate.getTime() : 0; data.gs.ia = store.integrationAttributes; return data; } this.getLocalStorage = function() { if (!mpInstance._Store.isLocalStorageAvailable) { return null; } var key = mpInstance._Store.storageName, localStorageData = self.decodePersistence( window.localStorage.getItem(key) ), obj = {}, j; if (localStorageData) { localStorageData = JSON.parse(localStorageData); for (j in localStorageData) { if (localStorageData.hasOwnProperty(j)) { obj[j] = localStorageData[j]; } } } if (Object.keys(obj).length) { return obj; } return null; }; function removeLocalStorage(localStorageName) { localStorage.removeItem(localStorageName); } this.expireCookies = function(cookieName) { var date = new Date(), expires, domain, cookieDomain; cookieDomain = self.getCookieDomain(); if (cookieDomain === '') { domain = ''; } else { domain = ';domain=' + cookieDomain; } date.setTime(date.getTime() - 24 * 60 * 60 * 1000); expires = '; expires=' + date.toUTCString(); document.cookie = cookieName + '=' + '' + expires + '; path=/' + domain; }; this.getCookie = function() { var cookies, key = mpInstance._Store.storageName, i, l, parts, name, cookie, result = key ? undefined : {}; mpInstance.Logger.verbose(Messages.InformationMessages.CookieSearch); try { cookies = window.document.cookie.split('; '); } catch (e) { mpInstance.Logger.verbose('Unable to parse undefined cookie'); return null; } for (i = 0, l = cookies.length; i < l; i++) { try { parts = cookies[i].split('='); name = parts.shift(); cookie = parts.join('='); } catch (e) { mpInstance.Logger.verbose( 'Unable to parse cookie: ' + name + '. Skipping.' ); } if (key && key === name) { result = mpInstance._Helpers.converted(cookie); break; } if (!key) { result[name] = mpInstance._Helpers.converted(cookie); } } if (result) { mpInstance.Logger.verbose(Messages.InformationMessages.CookieFound); return JSON.parse(self.decodePersistence(result)); } else { return null; } }; // https://go.mparticle.com/work/SQDSDKS-5022 // https://go.mparticle.com/work/SQDSDKS-6021 this.setCookie = function() { var mpid, currentUser = mpInstance.Identity.getCurrentUser(); if (currentUser) { mpid = currentUser.getMPID(); } var date = new Date(), key = mpInstance._Store.storageName, cookies = self.getCookie() || {}, expires = new Date( date.getTime() + mpInstance._Store.SDKConfig.cookieExpiration * 24 * 60 * 60 * 1000 ).toGMTString(), cookieDomain, domain, encodedCookiesWithExpirationAndPath; cookieDomain = self.getCookieDomain(); if (cookieDomain === '') { domain = ''; } else { domain = ';domain=' + cookieDomain; } cookies.gs = cookies.gs || {}; if (mpInstance._Store.sessionId) { cookies.gs.csm = mpInstance._Store.currentSessionMPIDs; } if (mpid) { cookies.cu = mpid; } cookies.l = mpInstance._Store.isLoggedIn ? 1 : 0; cookies = setGlobalStorageAttributes(cookies); if (Object.keys(mpInstance._Store.nonCurrentUserMPIDs).length) { cookies = mpInstance._Helpers.extend( {}, cookies, mpInstance._Store.nonCurrentUserMPIDs ); mpInstance._Store.nonCurrentUserMPIDs = {}; } encodedCookiesWithExpirationAndPath = self.reduceAndEncodePersistence( cookies, expires, domain, mpInstance._Store.SDKConfig.maxCookieSize ); mpInstance.Logger.verbose(Messages.InformationMessages.CookieSet); window.document.cookie = encodeURIComponent(key) + '=' + encodedCookiesWithExpirationAndPath; }; /* This function determines if a cookie is greater than the configured maxCookieSize. - If it is, we remove an MPID and its associated UI/UA/CSD from the cookie. - Once removed, check size, and repeat. - Never remove the currentUser's MPID from the cookie. MPID removal priority: 1. If there are no currentSessionMPIDs, remove a random MPID from the the cookie. 2. If there are currentSessionMPIDs: a. Remove at random MPIDs on the cookie that are not part of the currentSessionMPIDs b. Then remove MPIDs based on order in currentSessionMPIDs array, which stores MPIDs based on earliest login. */ this.reduceAndEncodePersistence = function( persistence, expires, domain, maxCookieSize ) { var encodedCookiesWithExpirationAndPath, currentSessionMPIDs = persistence.gs.csm ? persistence.gs.csm : []; // Comment 1 above if (!currentSessionMPIDs.length) { for (var key in persistence) { if (persistence.hasOwnProperty(key)) { encodedCookiesWithExpirationAndPath = createFullEncodedCookie( persistence, expires, domain ); if ( encodedCookiesWithExpirationAndPath.length > maxCookieSize ) { if ( !SDKv2NonMPIDCookieKeys[key] && key !== persistence.cu ) { delete persistence[key]; } } } } } else { // Comment 2 above - First create an object of all MPIDs on the cookie var MPIDsOnCookie = {}; for (var potentialMPID in persistence) { if (persistence.hasOwnProperty(potentialMPID)) { if ( !SDKv2NonMPIDCookieKeys[potentialMPID] && potentialMPID !== persistence.cu ) { MPIDsOnCookie[potentialMPID] = 1; } } } // Comment 2a above if (Object.keys(MPIDsOnCookie).length) { for (var mpid in MPIDsOnCookie) { encodedCookiesWithExpirationAndPath = createFullEncodedCookie( persistence, expires, domain ); if ( encodedCookiesWithExpirationAndPath.length > maxCookieSize ) { if (MPIDsOnCookie.hasOwnProperty(mpid)) { if (currentSessionMPIDs.indexOf(mpid) === -1) { delete persistence[mpid]; } } } } } // Comment 2b above for (var i = 0; i < currentSessionMPIDs.length; i++) { encodedCookiesWithExpirationAndPath = createFullEncodedCookie( persistence, expires, domain ); if ( encodedCookiesWithExpirationAndPath.length > maxCookieSize ) { var MPIDtoRemove = currentSessionMPIDs[i]; if (persistence[MPIDtoRemove]) { mpInstance.Logger.verbose( 'Size of new encoded cookie is larger than maxCookieSize setting of ' + maxCookieSize + '. Removing from cookie the earliest logged in MPID containing: ' + JSON.stringify(persistence[MPIDtoRemove], 0, 2) ); delete persistence[MPIDtoRemove]; } else { mpInstance.Logger.error( 'Unable to save MPID data to cookies because the resulting encoded cookie is larger than the maxCookieSize setting of ' + maxCookieSize + '. We recommend using a maxCookieSize of 1500.' ); } } else { break; } } } return encodedCookiesWithExpirationAndPath; }; function createFullEncodedCookie(persistence, expires, domain) { return ( self.encodePersistence(JSON.stringify(persistence)) + ';expires=' + expires + ';path=/' + domain ); } this.findPrevCookiesBasedOnUI = function(identityApiData) { var persistence = mpInstance._Persistence.getPersistence(); var matchedUser; if (identityApiData) { for (var requestedIdentityType in identityApiData.userIdentities) { if (persistence && Object.keys(persistence).length) { for (var key in persistence) { // any value in persistence that has an MPID key will be an MPID to search through // other keys on the cookie are currentSessionMPIDs and currentMPID which should not be searched if (persistence[key].mpid) { var cookieUIs = persistence[key].ui; for (var cookieUIType in cookieUIs) { if ( requestedIdentityType === cookieUIType && identityApiData.userIdentities[ requestedIdentityType ] === cookieUIs[cookieUIType] ) { matchedUser = key; break; } } } } } } } if (matchedUser) { self.storeDataInMemory(persistence, matchedUser); } }; this.encodePersistence = function(persistence) { persistence = JSON.parse(persistence); for (var key in persistence.gs) { if (persistence.gs.hasOwnProperty(key)) { if (Base64CookieKeys[key]) { if (persistence.gs[key]) { // base64 encode any value that is an object or Array in globalSettings if ( (Array.isArray(persistence.gs[key]) && persistence.gs[key].length) || (mpInstance._Helpers.isObject( persistence.gs[key] ) && Object.keys(persistence.gs[key]).length) ) { persistence.gs[key] = Base64.encode( JSON.stringify(persistence.gs[key]) ); } else { delete persistence.gs[key]; } } else { delete persistence.gs[key]; } } else if (key === 'ie') { persistence.gs[key] = persistence.gs[key] ? 1 : 0; } else if (!persistence.gs[key]) { delete persistence.gs[key]; } } } for (var mpid in persistence) { if (persistence.hasOwnProperty(mpid)) { if (!SDKv2NonMPIDCookieKeys[mpid]) { for (key in persistence[mpid]) { if (persistence[mpid].hasOwnProperty(key)) { if (Base64CookieKeys[key]) { if ( mpInstance._Helpers.isObject( persistence[mpid][key] ) && Object.keys(persistence[mpid][key]).length ) { persistence[mpid][key] = Base64.encode( JSON.stringify(persistence[mpid][key]) ); } else { delete persistence[mpid][key]; } } } } } } } return Utils.createCookieString(JSON.stringify(persistence)); }; // TODO: This should actually be decodePersistenceString or // we should refactor this to take a string and return an object this.decodePersistence = function(persistence) { try { if (persistence) { persistence = JSON.parse(Utils.revertCookieString(persistence)); if ( mpInstance._Helpers.isObject(persistence) && Object.keys(persistence).length ) { for (var key in persistence.gs) { if (persistence.gs.hasOwnProperty(key)) { if (Base64CookieKeys[key]) { persistence.gs[key] = JSON.parse( Base64.decode(persistence.gs[key]) ); } else if (key === 'ie') { persistence.gs[key] = Boolean( persistence.gs[key] ); } } } for (var mpid in persistence) { if (persistence.hasOwnProperty(mpid)) { if (!SDKv2NonMPIDCookieKeys[mpid]) { for (key in persistence[mpid]) { if (persistence[mpid].hasOwnProperty(key)) { if (Base64CookieKeys[key]) { if (persistence[mpid][key].length) { persistence[mpid][ key ] = JSON.parse( Base64.decode( persistence[mpid][key] ) ); } } } } } else if (mpid === 'l') { persistence[mpid] = Boolean(persistence[mpid]); } } } } return JSON.stringify(persistence); } } catch (e) { mpInstance.Logger.error('Problem with decoding cookie', e); } }; this.getCookieDomain = function() { if (mpInstance._Store.SDKConfig.cookieDomain) { return mpInstance._Store.SDKConfig.cookieDomain; } else { var rootDomain = self.getDomain(document, location.hostname); if (rootDomain === '') { return ''; } else { return '.' + rootDomain; } } }; // This function loops through the parts of a full hostname, attempting to set a cookie on that domain. It will set a cookie at the highest level possible. // For example subdomain.domain.co.uk would try the following combinations: // "co.uk" -> fail // "domain.co.uk" -> success, return // "subdomain.domain.co.uk" -> skipped, because already found this.getDomain = function(doc, locationHostname) { var i, testParts, mpTest = 'mptest=cookie', hostname = locationHostname.split('.'); for (i = hostname.length - 1; i >= 0; i--) { testParts = hostname.slice(i).join('.'); doc.cookie = mpTest + ';domain=.' + testParts + ';'; if (doc.cookie.indexOf(mpTest) > -1) { doc.cookie = mpTest.split('=')[0] + '=;domain=.' + testParts + ';expires=Thu, 01 Jan 1970 00:00:01 GMT;'; return testParts; } } return ''; }; this.getCartProducts = function(mpid) { var allCartProducts, cartProductsString = localStorage.getItem( mpInstance._Store.prodStorageName ); if (cartProductsString) { allCartProducts = JSON.parse(Base64.decode(cartProductsString)); if ( allCartProducts && allCartProducts[mpid] && allCartProducts[mpid].cp ) { return allCartProducts[mpid].cp; } } return []; }; this.setCartProducts = function(allProducts) { if (!mpInstance._Store.isLocalStorageAvailable) { return; } try { window.localStorage.setItem( encodeURIComponent(mpInstance._Store.prodStorageName), Base64.encode(JSON.stringify(allProducts)) ); } catch (e) { mpInstance.Logger.error( 'Error with setting products on localStorage.' ); } }; this.saveUserCookieSyncDatesToPersistence = function(mpid, csd) { if (csd) { var persistence = self.getPersistence(); if (persistence) { if (persistence[mpid]) { persistence[mpid].csd = csd; } else { persistence[mpid] = { csd: csd, }; } } self.savePersistence(persistence); } }; this.swapCurrentUser = function( previousMPID, currentMPID, currentSessionMPIDs ) { if (previousMPID && currentMPID && previousMPID !== currentMPID) { var persistence = self.getPersistence(); if (persistence) { persistence.cu = currentMPID; persistence.gs.csm = currentSessionMPIDs; self.savePersistence(persistence); } } }; // https://go.mparticle.com/work/SQDSDKS-6021 this.savePersistence = function(persistence) { var encodedPersistence = self.encodePersistence( JSON.stringify(persistence) ), date = new Date(), key = mpInstance._Store.storageName, expires = new Date( date.getTime() + mpInstance._Store.SDKConfig.cookieExpiration * 24 * 60 * 60 * 1000 ).toGMTString(), cookieDomain = self.getCookieDomain(), domain; if (cookieDomain === '') { domain = ''; } else { domain = ';domain=' + cookieDomain; } if (mpInstance._Store.SDKConfig.useCookieStorage) { var encodedCookiesWithExpirationAndPath = self.reduceAndEncodePersistence( persistence, expires, domain, mpInstance._Store.SDKConfig.maxCookieSize ); window.document.cookie = encodeURIComponent(key) + '=' + encodedCookiesWithExpirationAndPath; } else { if (mpInstance._Store.isLocalStorageAvailable) { localStorage.setItem( mpInstance._Store.storageName, encodedPersistence ); } } }; this.getPersistence = function() { var persistence = this.useLocalStorage() ? this.getLocalStorage() : this.getCookie(); return persistence; }; this.getFirstSeenTime = function(mpid) { if (!mpid) { return null; } var persistence = self.getPersistence(); if (persistence && persistence[mpid] && persistence[mpid].fst) { return persistence[mpid].fst; } else { return null; } }; /** * set the "first seen" time for a user. the time will only be set once for a given * mpid after which subsequent calls will be ignored */ this.setFirstSeenTime = function(mpid, time) { if (!mpid) { return; } // https://go.mparticle.com/work/SQDSDKS-6329 if (!time) { time = new Date().getTime(); } var persistence = self.getPersistence(); if (persistence) { if (!persistence[mpid]) { persistence[mpid] = {}; } if (!persistence[mpid].fst) { persistence[mpid].fst = time; self.savePersistence(persistence); } } }; /** * returns the "last seen" time for a user. If the mpid represents the current user, the * return value will always be the current time, otherwise it will be to stored "last seen" * time */ this.getLastSeenTime = function(mpid) { if (!mpid) { return null; } if (mpid === mpInstance.Identity.getCurrentUser().getMPID()) { //if the mpid is the current user, its last seen time is the current time return new Date().getTime(); } else { var persistence = self.getPersistence(); if (persistence && persistence[mpid] && persistence[mpid].lst) { return persistence[mpid].lst; } return null; } }; this.setLastSeenTime = function(mpid, time) { if (!mpid) { return; } // https://go.mparticle.com/work/SQDSDKS-6329 if (!time) { time = new Date().getTime(); } var persistence = self.getPersistence(); if (persistence && persistence[mpid]) { persistence[mpid].lst = time; self.savePersistence(persistence); } }; this.getDeviceId = function() { return mpInstance._Store.deviceId; }; this.setDeviceId = function(guid) { mpInstance._Store.deviceId = guid; self.update(); }; this.resetPersistence = function() { removeLocalStorage(StorageNames.localStorageName); removeLocalStorage(StorageNames.localStorageNameV3); removeLocalStorage(StorageNames.localStorageNameV4); removeLocalStorage(mpInstance._Store.prodStorageName); removeLocalStorage(mpInstance._Store.storageName); removeLocalStorage(StorageNames.localStorageProductsV4); self.expireCookies(StorageNames.cookieName); self.expireCookies(StorageNames.cookieNameV2); self.expireCookies(StorageNames.cookieNameV3); self.expireCookies(StorageNames.cookieNameV4); self.expireCookies(mpInstance._Store.prodStorageName); self.expireCookies(mpInstance._Store.storageName); if (mParticle._isTestEnv) { var testWorkspaceToken = 'abcdef'; removeLocalStorage( mpInstance._Helpers.createMainStorageName(testWorkspaceToken) ); self.expireCookies( mpInstance._Helpers.createMainStorageName(testWorkspaceToken) ); removeLocalStorage( mpInstance._Helpers.createProductStorageName(testWorkspaceToken) ); } }; // https://go.mparticle.com/work/SQDSDKS-6045 // Forwarder Batching Code this.forwardingStatsBatches = { uploadsTable: {}, forwardingStatsEventQueue: [], }; }