@@ -2,7 +2,7 @@ import { Batch } from '@mparticle/event-models';
22import Constants from './constants' ;
33import { SDKEvent , SDKLoggerApi } from './sdkRuntimeModels' ;
44import { convertEvents } from './sdkToEventsApiConverter' ;
5- import { MessageType } from './types' ;
5+ import { MessageType , EventType } from './types' ;
66import { getRampNumber , isEmpty } from './utils' ;
77import { SessionStorageVault , LocalStorageVault } from './vault' ;
88import {
@@ -13,7 +13,7 @@ import {
1313} from './uploaders' ;
1414import { IMParticleUser } from './identity-user-interfaces' ;
1515import { IMParticleWebSDKInstance } from './mp-instance' ;
16-
16+ import { appendUserInfo } from './user-utils' ;
1717/**
1818 * BatchUploader contains all the logic to store/retrieve events and batches
1919 * to/from persistence, and upload batches to mParticle.
@@ -44,6 +44,8 @@ export class BatchUploader {
4444 private batchVault : LocalStorageVault < Batch [ ] > ;
4545 private offlineStorageEnabled : boolean = false ;
4646 private uploader : AsyncUploader ;
47+ private lastASTEventTime : number = 0 ;
48+ private readonly AST_DEBOUNCE_MS : number = 1000 ; // 1 second debounce
4749
4850 /**
4951 * Creates an instance of a BatchUploader
@@ -129,21 +131,79 @@ export class BatchUploader {
129131 return offlineStoragePercentage >= rampNumber ;
130132 }
131133
134+ // debounce AST just in case multiple events are fired in a short period of time due to browser differences
135+ private shouldDebounceAndUpdateLastASTTime ( ) : boolean {
136+ const now = Date . now ( ) ;
137+ if ( now - this . lastASTEventTime < this . AST_DEBOUNCE_MS ) {
138+ return true ;
139+ }
140+
141+ this . lastASTEventTime = now ;
142+ return false ;
143+ }
144+
145+ // https://go.mparticle.com/work/SQDSDKS-7133
146+ private createBackgroundASTEvent ( ) : SDKEvent {
147+ const now = Date . now ( ) ;
148+ const { _Store, Identity, _timeOnSiteTimer, _Helpers } = this . mpInstance ;
149+ const { sessionId, deviceId, sessionStartDate, SDKConfig } = _Store ;
150+ const { generateUniqueId } = _Helpers ;
151+ const { getCurrentUser } = Identity ;
152+
153+ const event = {
154+ AppName : SDKConfig . appName ,
155+ AppVersion : SDKConfig . appVersion ,
156+ Package : SDKConfig . package ,
157+ EventDataType : MessageType . AppStateTransition ,
158+ Timestamp : now ,
159+ SessionId : sessionId ,
160+ DeviceId : deviceId ,
161+ IsFirstRun : false ,
162+ SourceMessageId : generateUniqueId ( ) ,
163+ SDKVersion : Constants . sdkVersion ,
164+ CustomFlags : { } ,
165+ EventAttributes : { } ,
166+ SessionStartDate : sessionStartDate ?. getTime ( ) || now ,
167+ Debug : SDKConfig . isDevelopmentMode ,
168+ ActiveTimeOnSite : _timeOnSiteTimer ?. getTimeInForeground ( ) || 0 ,
169+ IsBackgroundAST : true
170+ } as SDKEvent ;
171+
172+ appendUserInfo ( getCurrentUser ( ) , event ) ;
173+ return event ;
174+ }
175+
132176 // Adds listeners to be used trigger Navigator.sendBeacon if the browser
133177 // loses focus for any reason, such as closing browser tab or minimizing window
134178 private addEventListeners ( ) {
135179 const _this = this ;
136180
181+ const handleExit = ( ) => {
182+ // Check for debounce before creating and queueing event
183+ const {
184+ _Helpers : { getFeatureFlag } ,
185+ } = this . mpInstance ;
186+ const { AstBackgroundEvents } = Constants . FeatureFlags ;
187+
188+ if ( getFeatureFlag ( AstBackgroundEvents ) ) {
189+ if ( _this . shouldDebounceAndUpdateLastASTTime ( ) ) {
190+ return ;
191+ }
192+ // Add application state transition event to queue
193+ const event = _this . createBackgroundASTEvent ( ) ;
194+ _this . queueEvent ( event ) ;
195+ }
196+ // Then trigger the upload with beacon
197+ _this . prepareAndUpload ( false , _this . isBeaconAvailable ( ) ) ;
198+ } ;
137199 // visibility change is a document property, not window
138200 document . addEventListener ( 'visibilitychange' , ( ) => {
139- _this . prepareAndUpload ( false , _this . isBeaconAvailable ( ) ) ;
140- } ) ;
141- window . addEventListener ( 'beforeunload' , ( ) => {
142- _this . prepareAndUpload ( false , _this . isBeaconAvailable ( ) ) ;
143- } ) ;
144- window . addEventListener ( 'pagehide' , ( ) => {
145- _this . prepareAndUpload ( false , _this . isBeaconAvailable ( ) ) ;
201+ if ( document . visibilityState === 'hidden' ) {
202+ handleExit ( ) ;
203+ }
146204 } ) ;
205+ window . addEventListener ( 'beforeunload' , handleExit ) ;
206+ window . addEventListener ( 'pagehide' , handleExit ) ;
147207 }
148208
149209 private isBeaconAvailable ( ) : boolean {
@@ -387,6 +447,7 @@ export class BatchUploader {
387447 let blob = new Blob ( [ fetchPayload . body ] , {
388448 type : 'text/plain;charset=UTF-8' ,
389449 } ) ;
450+
390451 navigator . sendBeacon ( this . uploadUrl , blob ) ;
391452 } else {
392453 try {
0 commit comments