Skip to content

Commit 6f4c2e7

Browse files
committed
wip: proof of concept unifying all registry requests
1 parent ac82a5c commit 6f4c2e7

5 files changed

Lines changed: 53 additions & 36 deletions

File tree

app/composables/useNpmRegistry.ts

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ import { isExactVersion } from '~/utils/versions'
1414
import { extractInstallScriptsInfo } from '~/utils/install-scripts'
1515
import type { CachedFetchFunction } from '#shared/utils/fetch-cache-config'
1616

17-
const NPM_REGISTRY = 'https://registry.npmjs.org'
18-
const NPM_API = 'https://api.npmjs.org'
19-
2017
// Cache for packument fetches to avoid duplicate requests across components
2118
const packumentCache = new Map<string, Promise<Packument | null>>()
2219

@@ -30,6 +27,8 @@ async function fetchBulkDownloads(packageNames: string[]): Promise<Map<string, n
3027
const downloads = new Map<string, number>()
3128
if (packageNames.length === 0) return downloads
3229

30+
const { $npmApi } = useNuxtApp()
31+
3332
// Separate scoped and unscoped packages
3433
const scopedPackages = packageNames.filter(n => n.startsWith('@'))
3534
const unscopedPackages = packageNames.filter(n => !n.startsWith('@'))
@@ -42,10 +41,10 @@ async function fetchBulkDownloads(packageNames: string[]): Promise<Map<string, n
4241
bulkPromises.push(
4342
(async () => {
4443
try {
45-
const response = await $fetch<Record<string, { downloads: number } | null>>(
46-
`${NPM_API}/downloads/point/last-week/${chunk.join(',')}`,
44+
const response = await $npmApi<Record<string, { downloads: number } | null>>(
45+
`/downloads/point/last-week/${chunk.join(',')}`,
4746
)
48-
for (const [name, data] of Object.entries(response)) {
47+
for (const [name, data] of Object.entries(response.data)) {
4948
if (data?.downloads !== undefined) {
5049
downloads.set(name, data.downloads)
5150
}
@@ -67,8 +66,8 @@ async function fetchBulkDownloads(packageNames: string[]): Promise<Map<string, n
6766
const results = await Promise.allSettled(
6867
batch.map(async name => {
6968
const encoded = encodePackageName(name)
70-
const data = await $fetch<{ downloads: number }>(
71-
`${NPM_API}/downloads/point/last-week/${encoded}`,
69+
const { data } = await $npmApi<{ downloads: number }>(
70+
`/downloads/point/last-week/${encoded}`,
7271
)
7372
return { name, downloads: data.downloads }
7473
}),
@@ -180,13 +179,11 @@ export function usePackage(
180179
name: MaybeRefOrGetter<string>,
181180
requestedVersion?: MaybeRefOrGetter<string | null>,
182181
) {
183-
const cachedFetch = useCachedFetch()
184-
185182
const asyncData = useLazyAsyncData(
186183
() => `package:${toValue(name)}:${toValue(requestedVersion) ?? ''}`,
187-
async (_nuxtApp, { signal }) => {
184+
async ({ $npmRegistry }, { signal }) => {
188185
const encodedName = encodePackageName(toValue(name))
189-
const { data: r, isStale } = await cachedFetch<Packument>(`${NPM_REGISTRY}/${encodedName}`, {
186+
const { data: r, isStale } = await $npmRegistry<Packument>(`/${encodedName}`, {
190187
signal,
191188
})
192189
const reqVer = toValue(requestedVersion)
@@ -229,14 +226,14 @@ export function usePackageDownloads(
229226
name: MaybeRefOrGetter<string>,
230227
period: MaybeRefOrGetter<'last-day' | 'last-week' | 'last-month' | 'last-year'> = 'last-week',
231228
) {
232-
const cachedFetch = useCachedFetch()
229+
const { $npmApi } = useNuxtApp()
233230

234231
const asyncData = useLazyAsyncData(
235232
() => `downloads:${toValue(name)}:${toValue(period)}`,
236233
async (_nuxtApp, { signal }) => {
237234
const encodedName = encodePackageName(toValue(name))
238-
const { data, isStale } = await cachedFetch<NpmDownloadCount>(
239-
`${NPM_API}/downloads/point/${toValue(period)}/${encodedName}`,
235+
const { data, isStale } = await $npmApi<NpmDownloadCount>(
236+
`/downloads/point/${toValue(period)}/${encodedName}`,
240237
{ signal },
241238
)
242239
return { ...data, isStale }
@@ -269,9 +266,11 @@ export async function fetchNpmDownloadsRange(
269266
end: string,
270267
): Promise<NpmDownloadsRangeResponse> {
271268
const encodedName = encodePackageName(packageName)
272-
return await $fetch<NpmDownloadsRangeResponse>(
273-
`${NPM_API}/downloads/range/${start}:${end}/${encodedName}`,
274-
)
269+
const { $npmApi } = useNuxtApp()
270+
271+
return (
272+
await $npmApi<NpmDownloadsRangeResponse>(`/downloads/range/${start}:${end}/${encodedName}`)
273+
).data
275274
}
276275

277276
const emptySearchResponse = {
@@ -290,7 +289,6 @@ export function useNpmSearch(
290289
query: MaybeRefOrGetter<string>,
291290
options: MaybeRefOrGetter<NpmSearchOptions> = {},
292291
) {
293-
const cachedFetch = useCachedFetch()
294292
// Client-side cache
295293
const cache = shallowRef<{
296294
query: string
@@ -305,7 +303,7 @@ export function useNpmSearch(
305303

306304
const asyncData = useLazyAsyncData(
307305
() => `search:incremental:${toValue(query)}`,
308-
async (_nuxtApp, { signal }) => {
306+
async ({ $npmRegistry }, { signal }) => {
309307
const q = toValue(query)
310308
if (!q.trim()) {
311309
return emptySearchResponse
@@ -322,8 +320,8 @@ export function useNpmSearch(
322320
// Use requested size for initial fetch
323321
params.set('size', String(opts.size ?? 25))
324322

325-
const { data: response, isStale } = await cachedFetch<NpmSearchResponse>(
326-
`${NPM_REGISTRY}/-/v1/search?${params.toString()}`,
323+
const { data: response, isStale } = await $npmRegistry<NpmSearchResponse>(
324+
`/-/v1/search?${params.toString()}`,
327325
{ signal },
328326
60,
329327
)
@@ -364,6 +362,8 @@ export function useNpmSearch(
364362

365363
isLoadingMore.value = true
366364

365+
const { $npmRegistry } = useNuxtApp()
366+
367367
try {
368368
// Fetch from where we left off - calculate size needed
369369
const from = currentCount
@@ -374,7 +374,7 @@ export function useNpmSearch(
374374
params.set('size', String(size))
375375
params.set('from', String(from))
376376

377-
const { data: response } = await cachedFetch<NpmSearchResponse>(
377+
const { data: response } = await $npmRegistry<NpmSearchResponse>(
378378
`${NPM_REGISTRY}/-/v1/search?${params.toString()}`,
379379
{},
380380
60,
@@ -505,11 +505,9 @@ function packumentToSearchResult(pkg: MinimalPackument, weeklyDownloads?: number
505505
* Returns search-result-like objects for compatibility with PackageList
506506
*/
507507
export function useOrgPackages(orgName: MaybeRefOrGetter<string>) {
508-
const cachedFetch = useCachedFetch()
509-
510508
const asyncData = useLazyAsyncData(
511509
() => `org-packages:${toValue(orgName)}`,
512-
async (_nuxtApp, { signal }) => {
510+
async ({ $npmRegistry }, { signal }) => {
513511
const org = toValue(orgName)
514512
if (!org) {
515513
return emptySearchResponse
@@ -518,8 +516,8 @@ export function useOrgPackages(orgName: MaybeRefOrGetter<string>) {
518516
// Get all package names in the org
519517
let packageNames: string[]
520518
try {
521-
const { data } = await cachedFetch<Record<string, string>>(
522-
`${NPM_REGISTRY}/-/org/${encodeURIComponent(org)}/package`,
519+
const { data } = await $npmRegistry<Record<string, string>>(
520+
`/-/org/${encodeURIComponent(org)}/package`,
523521
{ signal },
524522
)
525523
packageNames = Object.keys(data)
@@ -552,10 +550,9 @@ export function useOrgPackages(orgName: MaybeRefOrGetter<string>) {
552550
batch.map(async name => {
553551
try {
554552
const encoded = encodePackageName(name)
555-
const { data: pkg } = await cachedFetch<MinimalPackument>(
556-
`${NPM_REGISTRY}/${encoded}`,
557-
{ signal },
558-
)
553+
const { data: pkg } = await $npmRegistry<MinimalPackument>(`/${encoded}`, {
554+
signal,
555+
})
559556
return pkg
560557
} catch {
561558
return null
@@ -698,6 +695,7 @@ async function checkDependencyOutdated(
698695
if (cached) {
699696
packument = await cached
700697
} else {
698+
// todo: use $npmRegistry here
701699
const promise = cachedFetch<Packument>(`${NPM_REGISTRY}/${encodePackageName(packageName)}`)
702700
.then(({ data }) => data)
703701
.catch(() => null)

app/pages/search.vue

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,6 @@ interface ValidatedSuggestion {
312312
/** Cache for existence checks to avoid repeated API calls */
313313
const existenceCache = ref<Record<string, boolean | 'pending'>>({})
314314
315-
const NPM_REGISTRY = 'https://registry.npmjs.org'
316-
317315
interface NpmSearchResponse {
318316
total: number
319317
objects: Array<{ package: { name: string } }>

app/plugins/npm.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export default defineNuxtPlugin(() => {
2+
const cachedFetch = useCachedFetch()
3+
4+
return {
5+
provide: {
6+
npmRegistry: <T>(
7+
url: Parameters<CachedFetchFunction>[0],
8+
options?: Parameters<CachedFetchFunction>[1],
9+
ttl?: Parameters<CachedFetchFunction>[2],
10+
) => {
11+
return cachedFetch<T>(url, { baseURL: NPM_REGISTRY, ...options }, ttl)
12+
},
13+
npmApi: <T>(
14+
url: Parameters<CachedFetchFunction>[0],
15+
options?: Parameters<CachedFetchFunction>[1],
16+
ttl?: Parameters<CachedFetchFunction>[2],
17+
) => {
18+
return cachedFetch<T>(url, { baseURL: NPM_API, ...options }, ttl)
19+
},
20+
},
21+
}
22+
})

app/utils/package-name.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@ export interface CheckNameResult {
7070
similarPackages?: SimilarPackage[]
7171
}
7272

73-
const NPM_REGISTRY = 'https://registry.npmjs.org'
74-
7573
export async function checkPackageExists(name: string): Promise<boolean> {
7674
try {
7775
const encodedName = name.startsWith('@')

shared/utils/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const CACHE_MAX_AGE_ONE_YEAR = 60 * 60 * 24 * 365
66

77
// API Strings
88
export const NPM_REGISTRY = 'https://registry.npmjs.org'
9+
export const NPM_API = 'https://api.npmjs.org'
910
export const ERROR_PACKAGE_ANALYSIS_FAILED = 'Failed to analyze package.'
1011
export const ERROR_PACKAGE_VERSION_AND_FILE_FAILED = 'Version and file path are required.'
1112
export const ERROR_PACKAGE_REQUIREMENTS_FAILED =

0 commit comments

Comments
 (0)