@@ -98,9 +98,13 @@ AmplitudeClient.prototype.init = function init(apiKey, opt_userId, opt_config, o
9898 } ) ;
9999 this . options . domain = this . cookieStorage . options ( ) . domain ;
100100
101+ if ( this . _instanceName === Constants . DEFAULT_INSTANCE ) {
102+ _upgradeCookieData ( this ) ;
103+ }
101104 _loadCookieData ( this ) ;
102105 this . _pendingReadStorage = true ;
103106
107+
104108 const initFromStorage = ( ) => {
105109 // load deviceId and userId from input, or try to fetch existing value from cookie
106110 this . options . deviceId = ( type ( opt_config ) === 'object' && type ( opt_config . deviceId ) === 'string' &&
@@ -189,6 +193,7 @@ AmplitudeClient.prototype.init = function init(apiKey, opt_userId, opt_config, o
189193 } ) ;
190194 } else {
191195 initFromStorage ( ) ;
196+ this . runQueuedFunctions ( ) ;
192197 }
193198
194199 } catch ( e ) {
@@ -258,13 +263,15 @@ var _parseConfig = function _parseConfig(options, config) {
258263 * @private
259264 */
260265AmplitudeClient . prototype . runQueuedFunctions = function ( ) {
261- for ( var i = 0 ; i < this . _q . length ; i ++ ) {
262- var fn = this [ this . _q [ i ] [ 0 ] ] ;
266+ const queue = this . _q ;
267+ this . _q = [ ] ;
268+
269+ for ( var i = 0 ; i < queue . length ; i ++ ) {
270+ var fn = this [ queue [ i ] [ 0 ] ] ;
263271 if ( type ( fn ) === 'function' ) {
264- fn . apply ( this , this . _q [ i ] . slice ( 1 ) ) ;
272+ fn . apply ( this , queue [ i ] . slice ( 1 ) ) ;
265273 }
266274 }
267- this . _q = [ ] ; // clear function queue after running
268275} ;
269276
270277/**
@@ -430,6 +437,60 @@ AmplitudeClient.prototype._setInStorage = function _setInStorage(storage, key, v
430437 storage . setItem ( key + this . _storageSuffix , value ) ;
431438} ;
432439
440+ var _upgradeCookieData = function _upgradeCookieData ( scope ) {
441+ // skip if already migrated to 4.10+
442+ var cookieData = scope . cookieStorage . get ( scope . options . cookieName + scope . _storageSuffix ) ;
443+ if ( type ( cookieData ) === 'object' ) {
444+ return ;
445+ }
446+ // skip if already migrated to 2.70+
447+ cookieData = scope . cookieStorage . get ( scope . options . cookieName + scope . _legacyStorageSuffix ) ;
448+ if ( type ( cookieData ) === 'object' && cookieData . deviceId && cookieData . sessionId && cookieData . lastEventTime ) {
449+ return ;
450+ }
451+
452+ var _getAndRemoveFromLocalStorage = function _getAndRemoveFromLocalStorage ( key ) {
453+ var value = localStorage . getItem ( key ) ;
454+ localStorage . removeItem ( key ) ;
455+ return value ;
456+ } ;
457+
458+ // in v2.6.0, deviceId, userId, optOut was migrated to localStorage with keys + first 6 char of apiKey
459+ var apiKeySuffix = ( type ( scope . options . apiKey ) === 'string' && ( '_' + scope . options . apiKey . slice ( 0 , 6 ) ) ) || '' ;
460+ var localStorageDeviceId = _getAndRemoveFromLocalStorage ( Constants . DEVICE_ID + apiKeySuffix ) ;
461+ var localStorageUserId = _getAndRemoveFromLocalStorage ( Constants . USER_ID + apiKeySuffix ) ;
462+ var localStorageOptOut = _getAndRemoveFromLocalStorage ( Constants . OPT_OUT + apiKeySuffix ) ;
463+ if ( localStorageOptOut !== null && localStorageOptOut !== undefined ) {
464+ localStorageOptOut = String ( localStorageOptOut ) === 'true' ; // convert to boolean
465+ }
466+
467+ // pre-v2.7.0 event and session meta-data was stored in localStorage. move to cookie for sub-domain support
468+ var localStorageSessionId = parseInt ( _getAndRemoveFromLocalStorage ( Constants . SESSION_ID ) ) ;
469+ var localStorageLastEventTime = parseInt ( _getAndRemoveFromLocalStorage ( Constants . LAST_EVENT_TIME ) ) ;
470+ var localStorageEventId = parseInt ( _getAndRemoveFromLocalStorage ( Constants . LAST_EVENT_ID ) ) ;
471+ var localStorageIdentifyId = parseInt ( _getAndRemoveFromLocalStorage ( Constants . LAST_IDENTIFY_ID ) ) ;
472+ var localStorageSequenceNumber = parseInt ( _getAndRemoveFromLocalStorage ( Constants . LAST_SEQUENCE_NUMBER ) ) ;
473+
474+ var _getFromCookie = function _getFromCookie ( key ) {
475+ return type ( cookieData ) === 'object' && cookieData [ key ] ;
476+ } ;
477+ scope . options . deviceId = _getFromCookie ( 'deviceId' ) || localStorageDeviceId ;
478+ scope . options . userId = _getFromCookie ( 'userId' ) || localStorageUserId ;
479+ scope . _sessionId = _getFromCookie ( 'sessionId' ) || localStorageSessionId || scope . _sessionId ;
480+ scope . _lastEventTime = _getFromCookie ( 'lastEventTime' ) || localStorageLastEventTime || scope . _lastEventTime ;
481+ scope . _eventId = _getFromCookie ( 'eventId' ) || localStorageEventId || scope . _eventId ;
482+ scope . _identifyId = _getFromCookie ( 'identifyId' ) || localStorageIdentifyId || scope . _identifyId ;
483+ scope . _sequenceNumber = _getFromCookie ( 'sequenceNumber' ) || localStorageSequenceNumber || scope . _sequenceNumber ;
484+
485+ // optOut is a little trickier since it is a boolean
486+ scope . options . optOut = localStorageOptOut || false ;
487+ if ( cookieData && cookieData . optOut !== undefined && cookieData . optOut !== null ) {
488+ scope . options . optOut = String ( cookieData . optOut ) === 'true' ;
489+ }
490+
491+ _saveCookieData ( scope ) ;
492+ } ;
493+
433494/**
434495 * Fetches deviceId, userId, event meta data from amplitude cookie
435496 * @private
@@ -1375,8 +1436,16 @@ AmplitudeClient.prototype._mergeEventsAndIdentifys = function _mergeEventsAndIde
13751436
13761437 // case 3: need to compare sequence numbers
13771438 } else {
1378- event = this . _unsentIdentifys [ identifyIndex ++ ] ;
1379- maxIdentifyId = event . event_id ;
1439+ // events logged before v2.5.0 won't have a sequence number, put those first
1440+ if ( ! ( 'sequence_number' in this . _unsentEvents [ eventIndex ] ) ||
1441+ this . _unsentEvents [ eventIndex ] . sequence_number <
1442+ this . _unsentIdentifys [ identifyIndex ] . sequence_number ) {
1443+ event = this . _unsentEvents [ eventIndex ++ ] ;
1444+ maxEventId = event . event_id ;
1445+ } else {
1446+ event = this . _unsentIdentifys [ identifyIndex ++ ] ;
1447+ maxIdentifyId = event . event_id ;
1448+ }
13801449 }
13811450
13821451 eventsToSend . push ( event ) ;
0 commit comments