@@ -15,6 +15,7 @@ export async function discoverFeeds(query: FeedDiscoveryQuery, options: { provid
1515 q : query . q . trim ( ) ,
1616 type : query . type ?? "all" ,
1717 limit : clampLimit ( query . limit ) ,
18+ freshnessDays : normalizeFreshnessDays ( query . freshnessDays ) ,
1819 includeUnvalidated : query . includeUnvalidated ?? false ,
1920 includeDeadFeeds : query . includeDeadFeeds ?? false
2021 } ;
@@ -54,6 +55,7 @@ export async function discoverFeeds(query: FeedDiscoveryQuery, options: { provid
5455 const validated = await validateCandidates ( candidates . slice ( 0 , Math . max ( ( resolvedQuery . limit ?? 25 ) * 2 , 25 ) ) , resolvedQuery , config ) ;
5556 const scored = validated
5657 . filter ( ( feed ) => ! resolvedQuery . type || resolvedQuery . type === "all" || feed . kind === resolvedQuery . type )
58+ . filter ( ( feed ) => isWithinFreshnessWindow ( feed . lastPublishedAt , resolvedQuery . freshnessDays ) )
5759 . map ( ( feed ) => scoreFeed ( feed , resolvedQuery ) ) ;
5860 const results = dedupeFeeds ( scored ) . slice ( 0 , resolvedQuery . limit ?? 25 ) ;
5961
@@ -111,6 +113,23 @@ function clampLimit(limit: number | undefined) {
111113 return Math . min ( Math . max ( Math . trunc ( limit ) , 1 ) , 100 ) ;
112114}
113115
116+ function normalizeFreshnessDays ( freshnessDays : number | undefined ) {
117+ return typeof freshnessDays === "number" && Number . isFinite ( freshnessDays ) && freshnessDays > 0
118+ ? freshnessDays
119+ : undefined ;
120+ }
121+
122+ function isWithinFreshnessWindow ( lastPublishedAt : string | undefined , freshnessDays : number | undefined ) {
123+ if ( freshnessDays === undefined ) {
124+ return true ;
125+ }
126+ if ( ! lastPublishedAt ) {
127+ return false ;
128+ }
129+ const ageMs = Date . now ( ) - Date . parse ( lastPublishedAt ) ;
130+ return Number . isFinite ( ageMs ) && ageMs >= 0 && ageMs <= freshnessDays * 86_400_000 ;
131+ }
132+
114133function safeCanonical ( url : string ) {
115134 try {
116135 return canonicalizeUrl ( url ) ;
0 commit comments