Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './npm-registry'
export * from './jsdelivr-registry'
export * from './changelog-fetcher'
export * from './version-checker'
export * from './persistent-cache'
41 changes: 35 additions & 6 deletions src/services/jsdelivr-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Pool, request } from 'undici'
import * as semver from 'semver'
import { CACHE_TTL, JSDELIVR_CDN_URL, MAX_CONCURRENT_REQUESTS, REQUEST_TIMEOUT } from '../config'
import { getAllPackageData } from './npm-registry'
import { persistentCache } from './persistent-cache'
import { OnBatchReadyCallback } from '../types'

// Create a persistent connection pool for jsDelivr CDN with optimal settings
Expand Down Expand Up @@ -129,15 +130,32 @@ export async function getAllPackageDataFromJsdelivr(
const fetchPackageWithFallback = async (packageName: string): Promise<void> => {
const currentVersion = currentVersions?.get(packageName)

// Try to get from cache first
const cached = packageCache.get(packageName)
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
packageData.set(packageName, cached.data)
// Try to get from in-memory cache first (fastest)
const memoryCached = packageCache.get(packageName)
if (memoryCached && Date.now() - memoryCached.timestamp < CACHE_TTL) {
packageData.set(packageName, memoryCached.data)
completedCount++
if (onProgress) {
onProgress(packageName, completedCount, total)
}
addToBatch(packageName, cached.data)
addToBatch(packageName, memoryCached.data)
return
}

// Try persistent disk cache (fast, survives restarts)
const diskCached = persistentCache.get(packageName)
if (diskCached) {
// Also populate in-memory cache for subsequent accesses
packageCache.set(packageName, {
data: diskCached,
timestamp: Date.now(),
})
packageData.set(packageName, diskCached)
completedCount++
if (onProgress) {
onProgress(packageName, completedCount, total)
}
addToBatch(packageName, diskCached)
return
}

Expand Down Expand Up @@ -169,10 +187,13 @@ export async function getAllPackageDataFromJsdelivr(

if (result) {
packageData.set(packageName, result)
// Cache in memory
packageCache.set(packageName, {
data: result,
timestamp: Date.now(),
})
// Cache to disk for persistence
persistentCache.set(packageName, result)
addToBatch(packageName, result)
}

Expand All @@ -196,11 +217,13 @@ export async function getAllPackageDataFromJsdelivr(
allVersions: allVersions.sort(semver.rcompare),
}

// Cache the result
// Cache the result in memory
packageCache.set(packageName, {
data: result,
timestamp: Date.now(),
})
// Cache to disk for persistence
persistentCache.set(packageName, result)

packageData.set(packageName, result)
completedCount++
Expand All @@ -217,10 +240,13 @@ export async function getAllPackageDataFromJsdelivr(

if (result) {
packageData.set(packageName, result)
// Cache in memory
packageCache.set(packageName, {
data: result,
timestamp: Date.now(),
})
// Cache to disk for persistence
persistentCache.set(packageName, result)
addToBatch(packageName, result)
}
} catch (npmError) {
Expand All @@ -240,6 +266,9 @@ export async function getAllPackageDataFromJsdelivr(
// Flush any remaining batch items
flushBatch()

// Flush persistent cache to disk
persistentCache.flush()

// Clear the progress line and show completion time if no custom progress handler
if (!onProgress) {
process.stdout.write('\r' + ' '.repeat(80) + '\r')
Expand Down
27 changes: 22 additions & 5 deletions src/services/npm-registry.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as semver from 'semver'
import { CACHE_TTL, NPM_REGISTRY_URL, REQUEST_TIMEOUT } from '../config'
import { persistentCache } from './persistent-cache'

// In-memory cache for package data
interface CacheEntry {
Expand All @@ -15,10 +16,21 @@ const packageCache = new Map<string, CacheEntry>()
async function fetchPackageFromRegistry(
packageName: string
): Promise<{ latestVersion: string; allVersions: string[] }> {
// Check cache first
const cached = packageCache.get(packageName)
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return cached.data
// Check in-memory cache first (fastest)
const memoryCached = packageCache.get(packageName)
if (memoryCached && Date.now() - memoryCached.timestamp < CACHE_TTL) {
return memoryCached.data
}

// Check persistent disk cache (fast, survives restarts)
const diskCached = persistentCache.get(packageName)
if (diskCached) {
// Also populate in-memory cache for subsequent accesses
packageCache.set(packageName, {
data: diskCached,
timestamp: Date.now(),
})
return diskCached
}

try {
Expand Down Expand Up @@ -70,11 +82,13 @@ async function fetchPackageFromRegistry(
allVersions,
}

// Cache the result
// Cache the result in memory
packageCache.set(packageName, {
data: result,
timestamp: Date.now(),
})
// Cache to disk for persistence
persistentCache.set(packageName, result)

return result
} finally {
Expand Down Expand Up @@ -120,6 +134,9 @@ export async function getAllPackageData(
// Wait for all requests to complete
await Promise.all(allPromises)

// Flush persistent cache to disk
persistentCache.flush()

// Clear the progress line and show completion time if no custom progress handler
if (!onProgress) {
process.stdout.write('\r' + ' '.repeat(80) + '\r')
Expand Down
Loading
Loading