@@ -8,7 +8,8 @@ import { IDatasetDescriptor, IDiscoverySource, IDiscoverySourceRow } from '../ty
88
99const log = getServiceLogger ( )
1010
11- const DEFAULT_API_URL = 'https://lf-criticality-score-api.example.com'
11+ const DEFAULT_API_HOST = 'lf-criticality-score-api.example.com'
12+ const DEFAULT_API_PORT = 443
1213const PAGE_SIZE = 100
1314
1415interface LfApiResponse {
@@ -20,30 +21,39 @@ interface LfApiResponse {
2021}
2122
2223interface LfApiRow {
23- runDate : string
24- repoUrl : string
24+ rundate : string
25+ repourl : string
2526 owner : string
26- repoName : string
27+ reponame : string
2728 contributors : number
2829 organizations : number
29- sizeSloc : number
30- lastUpdated : number
30+ sizesloc : number
31+ lastupdated : number
3132 age : number
32- commitFreq : number
33+ commitfreq : number
3334 score : number
3435}
3536
3637function getApiBaseUrl ( ) : string {
37- return ( process . env . LF_CRITICALITY_SCORE_API_URL ?? DEFAULT_API_URL ) . replace ( / \/ $ / , '' )
38+ if ( process . env . LF_CRITICALITY_SCORE_API_URL ) {
39+ return process . env . LF_CRITICALITY_SCORE_API_URL . replace ( / \/ $ / , '' )
40+ }
41+ const host = ( process . env . LF_CRITICALITY_SCORE_API_HOST ?? DEFAULT_API_HOST )
42+ . trim ( )
43+ . replace ( / \/ $ / , '' )
44+ const port = parseInt ( process . env . LF_CRITICALITY_SCORE_API_PORT ?? String ( DEFAULT_API_PORT ) , 10 )
45+ const scheme = port === 443 ? 'https' : 'http'
46+ return `${ scheme } ://${ host } :${ port } `
3847}
3948
4049async function fetchPage (
4150 baseUrl : string ,
42- startDate : string ,
43- endDate : string ,
4451 page : number ,
52+ scoredAfter ?: string ,
4553) : Promise < LfApiResponse > {
46- const url = `${ baseUrl } /projects/scores?startDate=${ startDate } &endDate=${ endDate } &page=${ page } &pageSize=${ PAGE_SIZE } `
54+ const params = new URLSearchParams ( { page : String ( page ) , pageSize : String ( PAGE_SIZE ) } )
55+ if ( scoredAfter ) params . set ( 'scoredAfter' , scoredAfter )
56+ const url = `${ baseUrl } /projects?${ params . toString ( ) } `
4757
4858 return new Promise ( ( resolve , reject ) => {
4959 const client = url . startsWith ( 'https://' ) ? https : http
@@ -72,88 +82,81 @@ async function fetchPage(
7282 } )
7383}
7484
75- /**
76- * Generates the first day and last day of a given month.
77- * monthOffset = 0 → current month, -1 → previous month, etc.
78- */
79- function monthRange ( monthOffset : number ) : { startDate : string ; endDate : string } {
80- const now = new Date ( )
81- const year = now . getUTCFullYear ( )
82- const month = now . getUTCMonth ( ) + monthOffset // can be negative; Date handles rollover
83-
84- const first = new Date ( Date . UTC ( year , month , 1 ) )
85- const last = new Date ( Date . UTC ( year , month + 1 , 0 ) ) // last day of month
86-
87- const pad = ( n : number ) => String ( n ) . padStart ( 2 , '0' )
88- const fmt = ( d : Date ) =>
89- `${ d . getUTCFullYear ( ) } -${ pad ( d . getUTCMonth ( ) + 1 ) } -${ pad ( d . getUTCDate ( ) ) } `
90-
91- return { startDate : fmt ( first ) , endDate : fmt ( last ) }
92- }
93-
9485export class LfCriticalityScoreSource implements IDiscoverySource {
9586 public readonly name = 'lf-criticality-score'
9687 public readonly format = 'json' as const
9788
98- async listAvailableDatasets ( ) : Promise < IDatasetDescriptor [ ] > {
89+ async listAvailableDatasets ( options ?: { scoredAfter ?: string } ) : Promise < IDatasetDescriptor [ ] > {
9990 const baseUrl = getApiBaseUrl ( )
100-
101- // Return one dataset per month for the last 12 months (newest first)
102- const datasets : IDatasetDescriptor [ ] = [ ]
103-
104- for ( let offset = 0 ; offset >= - 11 ; offset -- ) {
105- const { startDate, endDate } = monthRange ( offset )
106- const id = startDate . slice ( 0 , 7 ) // e.g. "2026-02"
107-
108- datasets . push ( {
109- id,
110- date : startDate ,
111- url : `${ baseUrl } /projects/scores?startDate=${ startDate } &endDate=${ endDate } ` ,
112- } )
113- }
114-
115- return datasets
91+ const today = new Date ( ) . toISOString ( ) . slice ( 0 , 10 )
92+ const { scoredAfter } = options ?? { }
93+
94+ const params = new URLSearchParams ( )
95+ if ( scoredAfter ) params . set ( 'scoredAfter' , scoredAfter )
96+ const qs = params . toString ( )
97+
98+ return [
99+ {
100+ id : scoredAfter ? `${ today } -since-${ scoredAfter } ` : today ,
101+ date : today ,
102+ url : `${ baseUrl } /projects${ qs ? `?${ qs } ` : '' } ` ,
103+ } ,
104+ ]
116105 }
117106
118- /**
119- * Returns an object-mode Readable that fetches all pages from the API
120- * and pushes each row as a plain object. Activities.ts iterates this
121- * directly (no csv-parse) because format === 'json'.
122- */
123107 async fetchDatasetStream ( dataset : IDatasetDescriptor ) : Promise < Readable > {
124108 const baseUrl = getApiBaseUrl ( )
109+ const scoredAfter = new URL ( dataset . url ) . searchParams . get ( 'scoredAfter' ) ?? undefined
125110
126- // Extract startDate and endDate from the stored URL
127- const parsed = new URL ( dataset . url )
128- const startDate = parsed . searchParams . get ( 'startDate' ) ?? ''
129- const endDate = parsed . searchParams . get ( 'endDate' ) ?? ''
111+ log . info (
112+ { datasetId : dataset . id , baseUrl , scoredAfter : scoredAfter ?? 'none (full fetch)' } ,
113+ 'LF Criticality Score: starting stream fetch.' ,
114+ )
130115
131116 async function * pages ( ) {
132117 let page = 1
133118 let totalPages = 1
134119
135120 do {
136- const response = await fetchPage ( baseUrl , startDate , endDate , page )
121+ log . info (
122+ { datasetId : dataset . id , page, totalPages } ,
123+ 'LF Criticality Score: fetching page...' ,
124+ )
125+ const response = await fetchPage ( baseUrl , page , scoredAfter )
137126 totalPages = response . totalPages
138127
128+ if ( page === 1 ) {
129+ log . info (
130+ {
131+ datasetId : dataset . id ,
132+ total : response . total ,
133+ totalPages,
134+ pageSize : response . pageSize ,
135+ } ,
136+ 'LF Criticality Score: first page received — total records available.' ,
137+ )
138+ }
139+
139140 for ( const row of response . data ) {
140141 yield row
141142 }
142143
143- log . debug (
144+ log . info (
144145 { datasetId : dataset . id , page, totalPages, rowsInPage : response . data . length } ,
145- 'LF Criticality Score page fetched.' ,
146+ 'LF Criticality Score: page fetched.' ,
146147 )
147148
148149 page ++
149150 } while ( page <= totalPages )
151+
152+ log . info ( { datasetId : dataset . id , totalPages } , 'LF Criticality Score: all pages fetched.' )
150153 }
151154
152155 return Readable . from ( pages ( ) , { objectMode : true } )
153156 }
154157
155158 parseRow ( rawRow : Record < string , unknown > ) : IDiscoverySourceRow | null {
156- const repoUrl = rawRow [ 'repoUrl' ] as string | undefined
159+ const repoUrl = ( rawRow [ 'repourl' ] ?? rawRow [ ' repoUrl'] ) as string | undefined
157160 if ( ! repoUrl ) {
158161 return null
159162 }
0 commit comments