@@ -18,6 +18,7 @@ import { AppState } from 'react-native';
1818
1919const MAX_SESSION_TIME_IN_MS = 300000 ;
2020const SESSION_ID_KEY = 'previous_session_id' ;
21+ const EVENT_SESSION_ID_KEY = 'event_session_id' ;
2122const LAST_EVENT_TIME_KEY = 'last_event_time' ;
2223const AMP_SESSION_START_EVENT = 'session_start' ;
2324const AMP_SESSION_END_EVENT = 'session_end' ;
@@ -26,8 +27,56 @@ export class AmplitudeSessionPlugin extends EventPlugin {
2627 type = PluginType . enrichment ;
2728 key = 'Actions Amplitude' ;
2829 active = false ;
29- sessionId = - 1 ;
30- lastEventTime = - 1 ;
30+ private _sessionId = - 1 ;
31+ private _eventSessionId = - 1 ;
32+ private _lastEventTime = - 1 ;
33+ resetPending = false ;
34+
35+ get eventSessionId ( ) {
36+ return this . _eventSessionId ;
37+ }
38+ set eventSessionId ( value : number ) {
39+ this . _eventSessionId = value ;
40+ if ( value !== - 1 ) {
41+ AsyncStorage . setItem ( EVENT_SESSION_ID_KEY , value . toString ( ) ) . catch (
42+ ( err ) =>
43+ console . warn (
44+ '[AmplitudeSessionPlugin] Failed to persist eventSessionId:' ,
45+ err
46+ )
47+ ) ;
48+ }
49+ }
50+
51+ get lastEventTime ( ) {
52+ return this . _lastEventTime ;
53+ }
54+ set lastEventTime ( value : number ) {
55+ this . _lastEventTime = value ;
56+ if ( value !== - 1 ) {
57+ AsyncStorage . setItem ( LAST_EVENT_TIME_KEY , value . toString ( ) ) . catch ( ( err ) =>
58+ console . warn (
59+ '[AmplitudeSessionPlugin] Failed to persist lastEventTime:' ,
60+ err
61+ )
62+ ) ;
63+ }
64+ }
65+
66+ get sessionId ( ) {
67+ return this . _sessionId ;
68+ }
69+ set sessionId ( value : number ) {
70+ this . _sessionId = value ;
71+ if ( value !== - 1 ) {
72+ AsyncStorage . setItem ( SESSION_ID_KEY , value . toString ( ) ) . catch ( ( err ) =>
73+ console . warn (
74+ '[AmplitudeSessionPlugin] Failed to persist sessionId:' ,
75+ err
76+ )
77+ ) ;
78+ }
79+ }
3180
3281 configure = async ( analytics : SegmentClient ) : Promise < void > => {
3382 this . analytics = analytics ;
@@ -50,9 +99,7 @@ export class AmplitudeSessionPlugin extends EventPlugin {
5099 if ( this . sessionId === - 1 || this . lastEventTime === - 1 ) {
51100 await this . loadSessionData ( ) ;
52101 }
53-
54102 await this . startNewSessionIfNecessary ( ) ;
55-
56103 let result = event ;
57104 switch ( result . type ) {
58105 case EventType . IdentifyEvent :
@@ -73,8 +120,7 @@ export class AmplitudeSessionPlugin extends EventPlugin {
73120 }
74121
75122 this . lastEventTime = Date . now ( ) ;
76- await this . saveSessionData ( ) ;
77-
123+ //await this.saveSessionData();
78124 return result ;
79125 }
80126
@@ -83,6 +129,32 @@ export class AmplitudeSessionPlugin extends EventPlugin {
83129 }
84130
85131 track ( event : TrackEventType ) {
132+ const eventName = event . event ;
133+
134+ if ( eventName === AMP_SESSION_START_EVENT ) {
135+ this . resetPending = false ;
136+ this . eventSessionId = this . sessionId ;
137+ }
138+
139+ if ( eventName === AMP_SESSION_END_EVENT ) {
140+ console . log ( `[AmplitudeSession] EndSession = ${ this . eventSessionId } ` ) ;
141+ }
142+
143+ if (
144+ eventName . startsWith ( 'Amplitude' ) ||
145+ eventName === AMP_SESSION_START_EVENT ||
146+ eventName === AMP_SESSION_END_EVENT
147+ ) {
148+ const integrations = this . disableAllIntegrations ( event . integrations ) ;
149+ return {
150+ ...event ,
151+ integrations : {
152+ ...integrations ,
153+ [ this . key ] : { session_id : this . eventSessionId } ,
154+ } ,
155+ } ;
156+ }
157+
86158 return this . insertSession ( event ) as TrackEventType ;
87159 }
88160
@@ -104,9 +176,9 @@ export class AmplitudeSessionPlugin extends EventPlugin {
104176
105177 async reset ( ) {
106178 this . sessionId = - 1 ;
179+ this . eventSessionId = - 1 ;
107180 this . lastEventTime = - 1 ;
108181 await AsyncStorage . removeItem ( SESSION_ID_KEY ) ;
109- await AsyncStorage . removeItem ( LAST_EVENT_TIME_KEY ) ;
110182 }
111183
112184 private insertSession = ( event : SegmentEvent ) => {
@@ -132,68 +204,117 @@ export class AmplitudeSessionPlugin extends EventPlugin {
132204
133205 private onBackground = ( ) => {
134206 this . lastEventTime = Date . now ( ) ;
135- this . saveSessionData ( ) ;
136207 } ;
137208
138209 private onForeground = ( ) => {
139210 this . startNewSessionIfNecessary ( ) ;
140211 } ;
141212
142213 private async startNewSessionIfNecessary ( ) {
214+ if ( this . eventSessionId === - 1 ) {
215+ this . eventSessionId = this . sessionId ;
216+ }
217+
218+ if ( this . resetPending ) {
219+ return ;
220+ }
221+
143222 const current = Date . now ( ) ;
223+ const withinSessionLimit = this . withinMinSessionTime ( current ) ;
144224
145- const sessionExpired =
146- this . sessionId === - 1 ||
147- this . lastEventTime === - 1 ||
148- current - this . lastEventTime >= MAX_SESSION_TIME_IN_MS ;
225+ const isSessionExpired =
226+ this . sessionId === - 1 || this . lastEventTime === - 1 || ! withinSessionLimit ;
149227
150- // Avoid loop: if session just started recently, skip restarting
151- if ( ! sessionExpired || current - this . sessionId < 1000 ) {
228+ if ( this . sessionId >= 0 && ! isSessionExpired ) {
152229 return ;
153230 }
154231
155- await this . endSession ( ) ;
232+ // End old session and start a new one
156233 await this . startNewSession ( ) ;
157234 }
158235
236+ /**
237+ * Handles the entire process of starting a new session.
238+ * Can be called directly or from startNewSessionIfNecessary()
239+ */
159240 private async startNewSession ( ) {
160- this . sessionId = Date . now ( ) ;
161- this . lastEventTime = this . sessionId ;
162- await this . saveSessionData ( ) ;
241+ if ( this . resetPending ) {
242+ return ;
243+ }
244+
245+ this . resetPending = true ;
246+
247+ const oldSessionId = this . sessionId ;
248+ if ( oldSessionId >= 0 ) {
249+ await this . endSession ( oldSessionId ) ;
250+ }
251+
252+ const newSessionId = Date . now ( ) ;
253+ this . sessionId = newSessionId ;
254+ this . eventSessionId =
255+ this . eventSessionId === - 1 ? newSessionId : this . eventSessionId ;
256+ this . lastEventTime = newSessionId ;
257+
258+ console . log ( `[AmplitudeSession] startNewSession -> ${ newSessionId } ` ) ;
259+
260+ await this . trackSessionStart ( newSessionId ) ;
261+ }
163262
263+ /**
264+ * Extracted analytics tracking into its own method
265+ */
266+ private async trackSessionStart ( sessionId : number ) {
164267 this . analytics ?. track ( AMP_SESSION_START_EVENT , {
165268 integrations : {
166- [ this . key ] : { session_id : this . sessionId } ,
269+ [ this . key ] : { session_id : sessionId } ,
167270 } ,
168271 } ) ;
169272 }
170273
171- private async endSession ( ) {
274+ private async endSession ( sessionId : number ) {
172275 if ( this . sessionId === - 1 ) {
173276 return ;
174277 }
175278
279+ console . log ( `[AmplitudeSession] endSession -> ${ this . sessionId } ` ) ;
280+
176281 this . analytics ?. track ( AMP_SESSION_END_EVENT , {
177282 integrations : {
178- [ this . key ] : { session_id : this . sessionId } ,
283+ [ this . key ] : { session_id : sessionId } ,
179284 } ,
180285 } ) ;
181286 }
182287
183288 private async loadSessionData ( ) {
184289 const storedSessionId = await AsyncStorage . getItem ( SESSION_ID_KEY ) ;
185290 const storedLastEventTime = await AsyncStorage . getItem ( LAST_EVENT_TIME_KEY ) ;
291+ const storedEventSessionId = await AsyncStorage . getItem (
292+ EVENT_SESSION_ID_KEY
293+ ) ;
294+
186295 this . sessionId = storedSessionId != null ? Number ( storedSessionId ) : - 1 ;
187296 this . lastEventTime =
188297 storedLastEventTime != null ? Number ( storedLastEventTime ) : - 1 ;
298+ this . eventSessionId =
299+ storedEventSessionId != null ? Number ( storedEventSessionId ) : - 1 ;
189300 }
190301
191- private async saveSessionData ( ) {
192- await AsyncStorage . setItem ( SESSION_ID_KEY , this . sessionId . toString ( ) ) ;
193- await AsyncStorage . setItem (
194- LAST_EVENT_TIME_KEY ,
195- this . lastEventTime . toString ( )
196- ) ;
302+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
303+ private disableAllIntegrations ( integrations ?: Record < string , any > ) {
304+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
305+ const result : Record < string , any > = { } ;
306+ if ( ! integrations ) {
307+ return result ;
308+ }
309+ for ( const key of Object . keys ( integrations ) ) {
310+ result [ key ] = false ;
311+ }
312+ return result ;
313+ }
314+
315+ private withinMinSessionTime ( timestamp : number ) : boolean {
316+ const timeDelta = timestamp - this . lastEventTime ;
317+ return timeDelta < MAX_SESSION_TIME_IN_MS ;
197318 }
198319
199320 private handleAppStateChange = ( nextAppState : string ) => {
0 commit comments