@@ -63,85 +63,132 @@ function getOrCreateAnonId(original: string): string {
6363 return anonIdMap . get ( original ) || '' ;
6464}
6565
66+ function formatBrowserName ( browser : string ) : string {
67+ if ( ! browser ) {
68+ return '' ;
69+ }
70+
71+ // Replace hyphens with spaces and capitalize each word
72+ return browser
73+ . replace ( / - / g, ' ' )
74+ . split ( ' ' )
75+ . map ( ( word ) => word . charAt ( 0 ) . toUpperCase ( ) + word . slice ( 1 ) . toLowerCase ( ) )
76+ . join ( ' ' ) ;
77+ }
78+
79+ function determineEventType (
80+ row : UmamiCsvRow ,
81+ isLastInSession = false
82+ ) : 'screen_view' | 'page_exit' {
83+ if ( isLastInSession ) {
84+ return 'page_exit' ;
85+ }
86+ return 'screen_view' ;
87+ }
88+
6689export const umamiAdapter = (
67- clientId : string
68- ) : AnalyticsEventAdapter < UmamiCsvRow > => ( {
69- mapRowToEvent ( row : UmamiCsvRow ) : AnalyticsEvent {
70- return {
71- id : crypto . randomUUID ( ) ,
72- client_id : clientId ,
73- event_name : 'screen_view' ,
74- anonymous_id : getOrCreateAnonId ( row . distinct_id ) ,
75- time : new Date ( row . created_at ) . getTime ( ) ,
76- session_id : getOrCreateSessionId ( row . session_id ) ,
77- event_type : 'track' ,
78- event_id : row . event_id ,
79- session_start_time : undefined ,
80- timestamp : undefined ,
81- referrer :
82- row . referrer_domain && row . referrer_domain . trim ( ) !== ''
83- ? row . referrer_domain
84- : 'direct' ,
85- url : row . url_path ,
86- path : row . url_path ,
87- title : row . page_title || '' ,
88- ip : '' ,
89- user_agent : '' ,
90- browser_name : row . browser || '' ,
91- browser_version : undefined ,
92- os_name : row . os || '' ,
93- os_version : undefined ,
94- device_type : row . device || '' ,
95- device_brand : undefined ,
96- device_model : undefined ,
97- country : row . country || '' ,
98- region : row . region || '' ,
99- city : row . city || '' ,
100- screen_resolution : row . screen || '' ,
101- viewport_size : undefined ,
102- language : row . language || '' ,
103- timezone : undefined ,
104- connection_type : undefined ,
105- rtt : undefined ,
106- downlink : undefined ,
107- time_on_page : undefined ,
108- scroll_depth : undefined ,
109- interaction_count : undefined ,
110- exit_intent : 0 ,
111- page_count : 1 ,
112- is_bounce : 0 ,
113- has_exit_intent : undefined ,
114- page_size : undefined ,
115- utm_source : row . utm_source || '' ,
116- utm_medium : row . utm_medium || '' ,
117- utm_campaign : row . utm_campaign || '' ,
118- utm_term : row . utm_term || '' ,
119- utm_content : row . utm_content || '' ,
120- load_time : undefined ,
121- dom_ready_time : undefined ,
122- dom_interactive : undefined ,
123- ttfb : undefined ,
124- connection_time : undefined ,
125- request_time : undefined ,
126- render_time : undefined ,
127- redirect_time : undefined ,
128- domain_lookup_time : undefined ,
129- fcp : undefined ,
130- lcp : undefined ,
131- cls : undefined ,
132- fid : undefined ,
133- inp : undefined ,
134- href : undefined ,
135- text : undefined ,
136- value : undefined ,
137- error_message : undefined ,
138- error_filename : undefined ,
139- error_lineno : undefined ,
140- error_colno : undefined ,
141- error_stack : undefined ,
142- error_type : undefined ,
143- properties : '' ,
144- created_at : new Date ( row . created_at ) . getTime ( ) ,
145- } ;
146- } ,
147- } ) ;
90+ clientId : string ,
91+ rows ?: UmamiCsvRow [ ]
92+ ) : AnalyticsEventAdapter < UmamiCsvRow > => {
93+ // Pre-analyze sessions for page exit detection if rows are provided
94+ let isLastInSessionMap : Map < string , boolean > | undefined ;
95+
96+ if ( rows && rows . length > 0 ) {
97+ isLastInSessionMap = analyzeSessionsForPageExits ( rows ) ;
98+ }
99+
100+ function analyzeSessionsForPageExits (
101+ sessionRows : UmamiCsvRow [ ]
102+ ) : Map < string , boolean > {
103+ const sessionGroups = new Map < string , UmamiCsvRow [ ] > ( ) ;
104+
105+ for ( const row of sessionRows ) {
106+ if ( ! sessionGroups . has ( row . session_id ) ) {
107+ sessionGroups . set ( row . session_id , [ ] ) ;
108+ }
109+ sessionGroups . get ( row . session_id ) ?. push ( row ) ;
110+ }
111+
112+ const lastInSessionMap = new Map < string , boolean > ( ) ;
113+
114+ for ( const [ sessionId , sessionEvents ] of sessionGroups ) {
115+ if ( sessionEvents . length >= 2 ) {
116+ sessionEvents . sort (
117+ ( a , b ) =>
118+ new Date ( a . created_at ) . getTime ( ) - new Date ( b . created_at ) . getTime ( )
119+ ) ;
120+
121+ const lastEvent = sessionEvents . at ( - 1 ) ;
122+ lastInSessionMap . set ( lastEvent . event_id , true ) ;
123+ }
124+ }
125+
126+ return lastInSessionMap ;
127+ }
128+
129+ return {
130+ mapRowToEvent ( row : UmamiCsvRow ) : AnalyticsEvent {
131+ const isLastInSession = isLastInSessionMap ?. get ( row . event_id ) ;
132+
133+ return {
134+ id : crypto . randomUUID ( ) ,
135+ client_id : clientId ,
136+ event_name : determineEventType ( row , isLastInSession ) ,
137+ anonymous_id : getOrCreateAnonId ( row . distinct_id ) ,
138+ time : new Date ( row . created_at ) . getTime ( ) ,
139+ session_id : getOrCreateSessionId ( row . session_id ) ,
140+ event_type : 'track' ,
141+ event_id : row . event_id ,
142+ session_start_time : undefined ,
143+ timestamp : undefined ,
144+ referrer :
145+ row . referrer_domain && row . referrer_domain . trim ( ) !== ''
146+ ? row . referrer_domain
147+ : 'direct' ,
148+ url : row . url_path ,
149+ path : row . url_path ,
150+ title : row . page_title || '' ,
151+ ip : '' ,
152+ user_agent : '' ,
153+ browser_name : formatBrowserName ( row . browser || '' ) ,
154+ browser_version : undefined ,
155+ os_name : row . os || '' ,
156+ os_version : undefined ,
157+ device_type : row . device || '' ,
158+ device_brand : undefined ,
159+ device_model : undefined ,
160+ country : row . country || '' ,
161+ region : row . region || '' ,
162+ city : row . city || '' ,
163+ screen_resolution : row . screen || '' ,
164+ viewport_size : undefined ,
165+ language : row . language || '' ,
166+ timezone : undefined ,
167+ connection_type : undefined ,
168+ rtt : undefined ,
169+ downlink : undefined ,
170+ time_on_page : undefined ,
171+ scroll_depth : undefined ,
172+ interaction_count : undefined ,
173+ page_count : 1 ,
174+ page_size : undefined ,
175+ utm_source : row . utm_source || '' ,
176+ utm_medium : row . utm_medium || '' ,
177+ utm_campaign : row . utm_campaign || '' ,
178+ utm_term : row . utm_term || '' ,
179+ utm_content : row . utm_content || '' ,
180+ load_time : undefined ,
181+ dom_ready_time : undefined ,
182+ dom_interactive : undefined ,
183+ ttfb : undefined ,
184+ connection_time : undefined ,
185+ request_time : undefined ,
186+ render_time : undefined ,
187+ redirect_time : undefined ,
188+ domain_lookup_time : undefined ,
189+ properties : '' ,
190+ created_at : new Date ( row . created_at ) . getTime ( ) ,
191+ } ;
192+ } ,
193+ } ;
194+ } ;
0 commit comments