Problem
The streak calculation logic is duplicated across at least 6 files in the codebase. Three key functions appear multiple times:
dateDiffDays — calculates the difference in days between two dates
toDateStr — converts a date to a YYYY-MM-DD string
Streak calculation logic — takes commit/contribution data and computes current streak, longest streak, etc.
Duplication Map
Version 1: Main streak endpoint
src/app/api/metrics/streak/route.ts
Contains the primary (and most complete) implementation:
toDateStr, dateDiffDays ~ lines 17-35
Full streak calculation (current streak, longest streak, todayActive)
This is the "authoritative" version.
Version 2: Badge endpoint
src/app/api/badge/streak-shield/route.ts
Contains its own copy of:
dateDiffDays (line 11)
Streak calculation logic (lines 19-62)
Uses different variable naming (commitDates vs dates)
Version 3: Public profile endpoint
src/app/api/public/[username]/route.ts
Contains its own copy of:
dateDiffDays (line 10)
toDateStr (line 18)
Streak calculation logic (lines 83-133)
Version 4: Compare endpoint
src/app/api/metrics/compare/route.ts
Contains its own copy of:
toDateStr (line 7)
Partial streak-related date handling
Version 5: Repos endpoint
src/app/api/metrics/repos/route.ts
Contains:
dateDiffDays helper (line 8)
Version 6: Contributions endpoint
src/app/api/metrics/contributions/route.ts
Contains:
Streak-like date grouping logic
Specific Code Examples
In src/app/api/metrics/streak/route.ts :
function toDateStr ( date : Date ) : string {
return date . toISOString ( ) . split ( "T" ) [ 0 ] ;
}
function dateDiffDays ( date1 : Date , date2 : Date ) : number {
const d1 = new Date ( date1 . toISOString ( ) . split ( "T" ) [ 0 ] ) ;
const d2 = new Date ( date2 . toISOString ( ) . split ( "T" ) [ 0 ] ) ;
return Math . floor ( ( d2 . getTime ( ) - d1 . getTime ( ) ) / ( 1000 * 60 * 60 * 24 ) ) ;
}
In src/app/api/badge/streak-shield/route.ts :
function dateDiffDays ( date1 : Date , date2 : Date ) : number {
const d1 = new Date ( Date . UTC ( date1 . getFullYear ( ) , date1 . getMonth ( ) , date1 . getDate ( ) ) ) ;
const d2 = new Date ( Date . UTC ( date2 . getFullYear ( ) , date2 . getMonth ( ) , date2 . getDate ( ) ) ) ;
return Math . floor ( ( d2 . getTime ( ) - d1 . getTime ( ) ) / ( 1000 * 60 * 60 * 24 ) ) ;
}
Notice the slightly different implementation! The streak endpoint uses toISOString().split("T")[0], while the badge endpoint uses Date.UTC(...). These can produce different results for dates near midnight in different time zones.
Impact
Maintenance: Any fix or enhancement to streak logic must be manually applied to 6+ files
Bug risk: The differences in dateDiffDays implementation (ISO string truncation vs Date.UTC) can cause off-by-one errors in streak calculation for users in certain time zones
Code bloat: Approximately 150+ lines of duplicated code across the codebase
Testing gaps: Tests for streak logic exist only for the main streak/route.ts (issue test: add unit tests for streak calculation utility functions #1069 ), not for the duplicated versions
Required Changes
1. Extract shared functions to a library module
Create src/lib/streak.ts:
export function toDateStr ( date : Date ) : string {
return date . toISOString ( ) . split ( "T" ) [ 0 ] ;
}
export function dateDiffDays ( date1 : Date , date2 : Date ) : number {
const d1 = new Date ( date1 . toISOString ( ) . split ( "T" ) [ 0 ] ) ;
const d2 = new Date ( date2 . toISOString ( ) . split ( "T" ) [ 0 ] ) ;
return Math . floor ( ( d2 . getTime ( ) - d1 . getTime ( ) ) / ( 1000 * 60 * 60 * 24 ) ) ;
}
export function calculateStreak ( dates : Date [ ] ) : {
currentStreak : number ;
longestStreak : number ;
todayActive : boolean ;
lastCommitDate : string | null ;
} {
// main streak calculation logic extracted from streak/route.ts
// ...
}
2. Update all files to import from the shared module
Replace local definitions in:
src/app/api/metrics/streak/route.ts → remove local toDateStr, dateDiffDays; add imports
src/app/api/badge/streak-shield/route.ts → remove local dateDiffDays and streak logic; add imports
src/app/api/public/[username]/route.ts → remove local dateDiffDays, toDateStr, streak logic; add imports
src/app/api/metrics/compare/route.ts → remove local toDateStr; add import
src/app/api/metrics/repos/route.ts → remove local dateDiffDays; add import
src/app/api/metrics/contributions/route.ts → use shared streak grouping logic
3. Handle behavioral differences
Audit each duplicated implementation for subtle differences:
streak-shield/route.ts uses Date.UTC() for date normalization → may produce different results than ISO string truncation
compare/route.ts may handle edge cases (empty arrays, single dates) differently
Choose the correct implementation for the shared library (likely the most-used version from streak/route.ts)
4. Add comprehensive tests
Add tests for the shared src/lib/streak.ts covering:
Normal streak calculation
Edge cases: no commits, single day, every day, gaps
Timezone boundary cases (commits near midnight UTC)
dateDiffDays with dates across DST transitions (if applicable)
Verification
All streak-related endpoints should return identical results before and after refactoring
Compare results from:
/api/metrics/streak
/api/badge/streak-shield
/api/public/[username]
Run existing tests (if any) to verify no regression
Verify no remaining duplicate definitions using rg "function dateDiffDays" and rg "function toDateStr"
Problem
The streak calculation logic is duplicated across at least 6 files in the codebase. Three key functions appear multiple times:
dateDiffDays— calculates the difference in days between two datestoDateStr— converts a date to a YYYY-MM-DD stringDuplication Map
Version 1: Main streak endpoint
src/app/api/metrics/streak/route.tsContains the primary (and most complete) implementation:
toDateStr,dateDiffDays~ lines 17-35This is the "authoritative" version.
Version 2: Badge endpoint
src/app/api/badge/streak-shield/route.tsContains its own copy of:
dateDiffDays(line 11)commitDatesvsdates)Version 3: Public profile endpoint
src/app/api/public/[username]/route.tsContains its own copy of:
dateDiffDays(line 10)toDateStr(line 18)Version 4: Compare endpoint
src/app/api/metrics/compare/route.tsContains its own copy of:
toDateStr(line 7)Version 5: Repos endpoint
src/app/api/metrics/repos/route.tsContains:
dateDiffDayshelper (line 8)Version 6: Contributions endpoint
src/app/api/metrics/contributions/route.tsContains:
Specific Code Examples
In
src/app/api/metrics/streak/route.ts:In
src/app/api/badge/streak-shield/route.ts:Notice the slightly different implementation! The streak endpoint uses
toISOString().split("T")[0], while the badge endpoint usesDate.UTC(...). These can produce different results for dates near midnight in different time zones.Impact
dateDiffDaysimplementation (ISO string truncation vs Date.UTC) can cause off-by-one errors in streak calculation for users in certain time zonesstreak/route.ts(issue test: add unit tests for streak calculation utility functions #1069), not for the duplicated versionsRequired Changes
1. Extract shared functions to a library module
Create
src/lib/streak.ts:2. Update all files to import from the shared module
Replace local definitions in:
src/app/api/metrics/streak/route.ts→ remove localtoDateStr,dateDiffDays; add importssrc/app/api/badge/streak-shield/route.ts→ remove localdateDiffDaysand streak logic; add importssrc/app/api/public/[username]/route.ts→ remove localdateDiffDays,toDateStr, streak logic; add importssrc/app/api/metrics/compare/route.ts→ remove localtoDateStr; add importsrc/app/api/metrics/repos/route.ts→ remove localdateDiffDays; add importsrc/app/api/metrics/contributions/route.ts→ use shared streak grouping logic3. Handle behavioral differences
Audit each duplicated implementation for subtle differences:
streak-shield/route.tsusesDate.UTC()for date normalization → may produce different results than ISO string truncationcompare/route.tsmay handle edge cases (empty arrays, single dates) differentlystreak/route.ts)4. Add comprehensive tests
Add tests for the shared
src/lib/streak.tscovering:dateDiffDayswith dates across DST transitions (if applicable)Verification
/api/metrics/streak/api/badge/streak-shield/api/public/[username]rg "function dateDiffDays"andrg "function toDateStr"