@@ -205,47 +205,72 @@ const S3_SOAP_API_METADATA_JSON_PATH =
205205 process . env . S3_SOAP_API_METADATA_JSON_PATH ||
206206 'soap-api/soap-api-metadata.json' ;
207207
208- let guidesMetadataCache : readonly JsonMetadata [ ] | null = null ;
209- let solutionsMetadataCache : readonly JsonMetadata [ ] | null = null ;
210- let releaseNotesMetadataCache : readonly JsonMetadata [ ] | null = null ;
211- let soapApiMetadataCache : readonly SoapApiJsonMetadata [ ] | null = null ;
212-
213- // Add timestamp-based cache invalidation
214- // eslint-disable-next-line functional/no-let
215- let guidesMetadataCacheTime = 0 ;
216-
217- // eslint-disable-next-line functional/no-let
218- let solutionsMetadataCacheTime = 0 ;
208+ type MetadataCacheItem < T > = {
209+ readonly category : string ;
210+ readonly locale : string ;
211+ readonly data : readonly T [ ] | null ;
212+ readonly refreshTime : number ;
213+ } ;
219214
220- // eslint-disable-next-line functional/no-let
221- let releaseNotesMetadataCacheTime = 0 ;
215+ let metadataCache : readonly MetadataCacheItem < Record < string , unknown > > [ ] = [ ] ;
222216
223217const METADATA_CACHE_TTL = 5 * 60 * 1000 ; // 5 minutes
224218
225- export const getGuidesMetadata = async ( locale : string , dirName ?: string ) => {
219+ async function fetchMetadataWithCache < T extends { readonly dirName : string } > (
220+ locale : string ,
221+ metadataCategory : string ,
222+ fetchFunction : ( ) => Promise < readonly T [ ] | null > ,
223+ dirName ?: string
224+ ) : Promise < MetadataCacheItem < T > > {
226225 const now = Date . now ( ) ;
227-
228- if (
229- guidesMetadataCache &&
230- now - guidesMetadataCacheTime < METADATA_CACHE_TTL &&
231- ( ! dirName || guidesMetadataCache . some ( ( m ) => m . dirName === dirName ) )
232- ) {
233- return guidesMetadataCache ;
226+ const cacheResult = metadataCache . find ( ( item ) => {
227+ const categoryMatch = item . category === metadataCategory ;
228+ const localeMatch = item . locale === locale ;
229+ const timeMatch = item . data && now - item . refreshTime < METADATA_CACHE_TTL ;
230+ const dirNameMatch =
231+ ! dirName ||
232+ ( Array . isArray ( item . data ) &&
233+ item . data . length > 0 &&
234+ 'dirName' in item . data [ 0 ] &&
235+ item . data . some ( ( m : Record < string , unknown > ) => m . dirName === dirName ) ) ;
236+ return categoryMatch && localeMatch && timeMatch && dirNameMatch ;
237+ } ) as MetadataCacheItem < T > | undefined ;
238+
239+ if ( cacheResult ) {
240+ return cacheResult ;
234241 }
235242
236- guidesMetadataCache = await fetchMetadataFromCDN < JsonMetadata > (
243+ const fetchMetadataResult = await fetchFunction ( ) ;
244+
245+ const newCacheItem : MetadataCacheItem < T > = {
246+ category : metadataCategory ,
247+ locale,
248+ data : fetchMetadataResult ,
249+ refreshTime : now ,
250+ } ;
251+
252+ metadataCache = [
253+ ...metadataCache . filter (
254+ ( item ) => ! ( item . category === metadataCategory && item . locale === locale )
255+ ) ,
256+ newCacheItem ,
257+ ] ;
258+
259+ return newCacheItem ;
260+ }
261+
262+ export const getGuidesMetadata = async ( locale : string , dirName ?: string ) => {
263+ const fetchFromCdnPath = dirName
264+ ? path . join ( locale , S3_PATH_TO_GITBOOK_DOCS , dirName , S3_METADATA_JSON_PATH )
265+ : `${ locale } /${ S3_GUIDES_METADATA_JSON_PATH } ` ;
266+ const cacheResult = await fetchMetadataWithCache < JsonMetadata > (
267+ locale ,
268+ 'guides' ,
269+ ( ) => fetchMetadataFromCDN < JsonMetadata > ( fetchFromCdnPath ) ,
237270 dirName
238- ? path . join (
239- locale ,
240- S3_PATH_TO_GITBOOK_DOCS ,
241- dirName ,
242- S3_METADATA_JSON_PATH
243- )
244- : `${ locale } /${ S3_GUIDES_METADATA_JSON_PATH } `
245271 ) ;
246- guidesMetadataCacheTime = now ;
247272
248- return guidesMetadataCache || [ ] ;
273+ return cacheResult . data || [ ] ;
249274} ;
250275
251276const removeTrailingSlash = ( value : string ) => value . replace ( / \/ + $ / , '' ) ;
@@ -324,29 +349,18 @@ export const getSolutionsMetadata = async (
324349 locale : string ,
325350 dirName ?: string
326351) => {
327- const now = Date . now ( ) ;
328-
329- if (
330- solutionsMetadataCache &&
331- now - solutionsMetadataCacheTime < METADATA_CACHE_TTL &&
332- ( ! dirName || solutionsMetadataCache . some ( ( m ) => m . dirName === dirName ) )
333- ) {
334- return solutionsMetadataCache ;
335- }
336-
337- solutionsMetadataCache = await fetchMetadataFromCDN < JsonMetadata > (
352+ const fetchFromCdnPath = dirName
353+ ? path . join ( locale , S3_PATH_TO_GITBOOK_DOCS , dirName , S3_METADATA_JSON_PATH )
354+ : `${ locale } /${ S3_SOLUTIONS_METADATA_JSON_PATH } ` ;
355+
356+ const cacheResult = await fetchMetadataWithCache < JsonMetadata > (
357+ locale ,
358+ 'solutions' ,
359+ ( ) => fetchMetadataFromCDN < JsonMetadata > ( fetchFromCdnPath ) ,
338360 dirName
339- ? path . join (
340- locale ,
341- S3_PATH_TO_GITBOOK_DOCS ,
342- dirName ,
343- S3_METADATA_JSON_PATH
344- )
345- : `${ locale } /${ S3_SOLUTIONS_METADATA_JSON_PATH } `
346361 ) ;
347- solutionsMetadataCacheTime = now ;
348362
349- return solutionsMetadataCache || [ ] ;
363+ return cacheResult . data || [ ] ;
350364} ;
351365
352366export const getReleaseNotesMetadataByDirNames = async (
@@ -368,36 +382,29 @@ export const getReleaseNotesMetadata = async (
368382 locale : string ,
369383 dirName ?: string
370384) => {
371- const now = Date . now ( ) ;
372-
373- if (
374- releaseNotesMetadataCache &&
375- now - releaseNotesMetadataCacheTime < METADATA_CACHE_TTL &&
376- ( ! dirName || releaseNotesMetadataCache . some ( ( m ) => m . dirName === dirName ) )
377- ) {
378- return releaseNotesMetadataCache ;
379- }
380-
381- releaseNotesMetadataCache = await fetchMetadataFromCDN < JsonMetadata > (
385+ const fetchFromCdnPath = dirName
386+ ? path . join ( locale , S3_PATH_TO_GITBOOK_DOCS , dirName , S3_METADATA_JSON_PATH )
387+ : `${ locale } /${ S3_RELEASE_NOTES_METADATA_JSON_PATH } ` ;
388+
389+ const cacheResult = await fetchMetadataWithCache < JsonMetadata > (
390+ locale ,
391+ 'releaseNotes' ,
392+ ( ) => fetchMetadataFromCDN < JsonMetadata > ( fetchFromCdnPath ) ,
382393 dirName
383- ? path . join (
384- locale ,
385- S3_PATH_TO_GITBOOK_DOCS ,
386- dirName ,
387- S3_METADATA_JSON_PATH
388- )
389- : `${ locale } /${ S3_RELEASE_NOTES_METADATA_JSON_PATH } `
390394 ) ;
391- releaseNotesMetadataCacheTime = now ;
392395
393- return releaseNotesMetadataCache || [ ] ;
396+ return cacheResult . data || [ ] ;
394397} ;
395398
396399export const getSoapApiMetadata = async ( locale : string ) => {
397- if ( ! soapApiMetadataCache ) {
398- soapApiMetadataCache = await fetchMetadataFromCDN < SoapApiJsonMetadata > (
399- `${ locale } /${ S3_SOAP_API_METADATA_JSON_PATH } `
400- ) ;
401- }
402- return soapApiMetadataCache || [ ] ;
400+ const cacheResult = await fetchMetadataWithCache < SoapApiJsonMetadata > (
401+ locale ,
402+ 'soapApi' ,
403+ ( ) =>
404+ fetchMetadataFromCDN < SoapApiJsonMetadata > (
405+ `${ locale } /${ S3_SOAP_API_METADATA_JSON_PATH } `
406+ )
407+ ) ;
408+
409+ return cacheResult . data || [ ] ;
403410} ;
0 commit comments