@@ -59,7 +59,51 @@ async function generateAnalyticsData() {
59
59
console . log ( "🔄 Fetching analytics data..." ) ;
60
60
61
61
const response = await fetch ( "https://r2.amanv.dev/export.csv" ) ;
62
- const csvText = await response . text ( ) ;
62
+ let csvText = await response . text ( ) ;
63
+
64
+ // Fix malformed CSV data - if it's all on one line, try to split it properly
65
+ if ( ! csvText . includes ( "\n" ) || csvText . split ( "\n" ) . length < 3 ) {
66
+ console . log ( "⚠️ Detected malformed CSV data, attempting to fix..." ) ;
67
+
68
+ // Try to split by common patterns that indicate row boundaries
69
+ const possibleSplitters = [
70
+ / \s { 3 , } / , // 3 or more spaces
71
+ / \s { 2 , } 0 { 8 , } / , // 2+ spaces followed by 8+ zeros (UUID pattern)
72
+ / \s { 2 , } [ a - f 0 - 9 ] { 8 } - [ a - f 0 - 9 ] { 4 } - [ a - f 0 - 9 ] { 4 } - [ a - f 0 - 9 ] { 4 } - [ a - f 0 - 9 ] { 12 } / , // UUID pattern
73
+ ] ;
74
+
75
+ for ( const splitter of possibleSplitters ) {
76
+ const parts = csvText . split ( splitter ) ;
77
+ if ( parts . length > 2 ) {
78
+ console . log ( `✅ Fixed CSV using pattern: ${ splitter } ` ) ;
79
+ csvText = parts . join ( "\n" ) ;
80
+ break ;
81
+ }
82
+ }
83
+
84
+ // If still malformed, try manual parsing
85
+ if ( ! csvText . includes ( "\n" ) || csvText . split ( "\n" ) . length < 3 ) {
86
+ console . log ( "⚠️ CSV still malformed, attempting manual parsing..." ) ;
87
+
88
+ // Extract header and data manually
89
+ const headerMatch = csvText . match ( / ^ ( [ ^ , ] + (?: , [ ^ , ] + ) * ) / ) ;
90
+ if ( headerMatch ) {
91
+ const header = headerMatch [ 1 ] ;
92
+ const dataPart = csvText . substring ( header . length ) ;
93
+
94
+ // Split data by UUID patterns
95
+ const dataRows = dataPart
96
+ . split (
97
+ / \s { 2 , } [ a - f 0 - 9 ] { 8 } - [ a - f 0 - 9 ] { 4 } - [ a - f 0 - 9 ] { 4 } - [ a - f 0 - 9 ] { 4 } - [ a - f 0 - 9 ] { 12 } / ,
98
+ )
99
+ . filter ( ( row ) => row . trim ( ) . length > 0 )
100
+ . map ( ( row ) => row . trim ( ) ) ;
101
+
102
+ csvText = header + "\n" + dataRows . join ( "\n" ) ;
103
+ console . log ( `✅ Manually parsed ${ dataRows . length } rows` ) ;
104
+ }
105
+ }
106
+ }
63
107
64
108
console . log ( "📊 Processing CSV data..." ) ;
65
109
@@ -90,16 +134,43 @@ async function generateAnalyticsData() {
90
134
91
135
Papa . parse < CSVRow > ( csvText , {
92
136
header : true ,
137
+ skipEmptyLines : true ,
93
138
complete : ( results ) => {
94
139
try {
95
- results . data . forEach ( ( row ) => {
96
- const timestamp = row [ "*.timestamp" ] || new Date ( ) . toISOString ( ) ;
140
+ console . log ( "📈 Processing" , results . data . length , "rows..." ) ;
141
+ console . log (
142
+ "📋 Sample row keys:" ,
143
+ Object . keys ( results . data [ 0 ] || { } ) ,
144
+ ) ;
145
+
146
+ results . data . forEach ( ( row , index ) => {
147
+ // Skip rows that don't have essential data
148
+ if ( ! row [ "*.timestamp" ] && ! row [ "timestamp" ] ) {
149
+ if ( index < 5 ) {
150
+ console . log (
151
+ `⚠️ Skipping row ${ index } - no timestamp:` ,
152
+ Object . keys ( row ) ,
153
+ ) ;
154
+ }
155
+ return ;
156
+ }
157
+
158
+ const timestamp =
159
+ row [ "*.timestamp" ] ||
160
+ row [ "timestamp" ] ||
161
+ new Date ( ) . toISOString ( ) ;
97
162
const date = timestamp . includes ( "T" )
98
163
? timestamp . split ( "T" ) [ 0 ]
99
164
: timestamp . split ( " " ) [ 0 ] ;
100
165
101
166
// Skip invalid records
102
167
if ( ! date || row [ "*.properties.platform" ] === "unknown" ) {
168
+ if ( index < 5 ) {
169
+ console . log (
170
+ `⚠️ Skipping row ${ index } - invalid date or platform:` ,
171
+ { date, platform : row [ "*.properties.platform" ] } ,
172
+ ) ;
173
+ }
103
174
return ;
104
175
}
105
176
@@ -113,6 +184,7 @@ async function generateAnalyticsData() {
113
184
const monthKey = `${ timestampDate . getFullYear ( ) } -${ String ( timestampDate . getMonth ( ) + 1 ) . padStart ( 2 , "0" ) } ` ;
114
185
monthlyCounts [ monthKey ] = ( monthlyCounts [ monthKey ] || 0 ) + 1 ;
115
186
187
+ // Use UTC hours for consistent timezone handling
116
188
const hour = timestampDate . getUTCHours ( ) ;
117
189
hourlyCounts [ hour ] = ( hourlyCounts [ hour ] || 0 ) + 1 ;
118
190
}
@@ -250,6 +322,15 @@ async function generateAnalyticsData() {
250
322
dbORMComboCounts [ combo ] = ( dbORMComboCounts [ combo ] || 0 ) + 1 ;
251
323
}
252
324
} ) ;
325
+
326
+ console . log (
327
+ "✅ Successfully processed" ,
328
+ totalRecords ,
329
+ "valid records" ,
330
+ ) ;
331
+ console . log ( "📊 Platform distribution:" , platformCounts ) ;
332
+ console . log ( "📊 Backend distribution:" , backendCounts ) ;
333
+ console . log ( "📊 Database distribution:" , databaseCounts ) ;
253
334
} catch ( error ) {
254
335
console . error ( "Error parsing CSV:" , error ) ;
255
336
}
0 commit comments