Skip to content

Commit 7274653

Browse files
committed
perf: use in analysis endpoint as well
1 parent 0c98215 commit 7274653

3 files changed

Lines changed: 41 additions & 46 deletions

File tree

app/composables/useNpmRegistry.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import type {
77
NpmPerson,
88
PackageVersionInfo,
99
} from '#shared/types'
10-
import type { PackageVersionsInfoWithMetadata, ResolvedPackageVersion } from 'fast-npm-meta'
10+
import { getVersions } from 'fast-npm-meta'
11+
import type { ResolvedPackageVersion } from 'fast-npm-meta'
1112
import type { ReleaseType } from 'semver'
1213
import { mapWithConcurrency } from '#shared/utils/async'
1314
import { maxSatisfying, prerelease, major, minor, diff, gt, compare } from 'semver'
1415
import { extractInstallScriptsInfo } from '~/utils/install-scripts'
1516
import type { CachedFetchFunction } from '#shared/utils/fetch-cache-config'
16-
import { FAST_NPM_META_API, encodePackageName } from '#shared/utils/npm'
1717

1818
const NPM_REGISTRY = 'https://registry.npmjs.org'
1919
const NPM_API = 'https://api.npmjs.org'
@@ -608,10 +608,7 @@ export async function fetchAllPackageVersions(packageName: string): Promise<Pack
608608
if (cached) return cached
609609

610610
const promise = (async () => {
611-
const encodedName = encodePackageName(packageName)
612-
const data = await $fetch<PackageVersionsInfoWithMetadata>(
613-
`${FAST_NPM_META_API}/versions/${encodedName}?metadata=true`,
614-
)
611+
const data = await getVersions(packageName, { metadata: true })
615612

616613
return Object.entries(data.versionsMeta)
617614
.map(([version, meta]) => ({

server/api/registry/analysis/[...pkg].get.ts

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,7 @@ import {
1818
ERROR_PACKAGE_ANALYSIS_FAILED,
1919
} from '#shared/utils/constants'
2020
import { parseRepoUrl } from '#shared/utils/git-providers'
21-
22-
/** Minimal packument data needed to check deprecation status */
23-
interface MinimalPackument {
24-
'name': string
25-
'dist-tags'?: { latest?: string }
26-
'versions'?: Record<string, { deprecated?: string }>
27-
}
21+
import { getLatestVersion, getLatestVersionBatch } from 'fast-npm-meta'
2822

2923
export default defineCachedEventHandler(
3024
async event => {
@@ -90,31 +84,18 @@ function encodePackageName(name: string): string {
9084
}
9185

9286
/**
93-
* Fetch @types package info including deprecation status.
87+
* Fetch @types package info including deprecation status using fast-npm-meta.
9488
* Returns undefined if the package doesn't exist.
9589
*/
9690
async function fetchTypesPackageInfo(packageName: string): Promise<TypesPackageInfo | undefined> {
97-
try {
98-
const encodedName = encodePackageName(packageName)
99-
// Fetch abbreviated packument to check latest version's deprecation status
100-
const packument = await $fetch<MinimalPackument>(`${NPM_REGISTRY}/${encodedName}`, {
101-
headers: {
102-
// Request abbreviated packument to reduce payload
103-
Accept: 'application/vnd.npm.install-v1+json',
104-
},
105-
})
106-
107-
// Get the latest version's deprecation message if any
108-
const latestVersion = packument['dist-tags']?.latest
109-
const deprecated = latestVersion ? packument.versions?.[latestVersion]?.deprecated : undefined
110-
111-
return {
112-
packageName,
113-
deprecated,
114-
}
115-
} catch {
91+
const result = await getLatestVersion(packageName, { metadata: true, throw: false })
92+
if ('error' in result) {
11693
return undefined
11794
}
95+
return {
96+
packageName,
97+
deprecated: result.deprecated,
98+
}
11899
}
119100

120101
/** Package metadata needed for association validation */
@@ -135,26 +116,46 @@ function getCreatePackageNameCandidates(packageName: string): string[] {
135116
}
136117

137118
/**
138-
* Find an associated create-* package by trying multiple naming patterns in parallel.
119+
* Find an associated create-* package by trying multiple naming patterns using batch API.
139120
* Returns the first associated package found (preferring create-{name} over create-{name}-app).
140121
*/
141122
async function findAssociatedCreatePackage(
142123
packageName: string,
143124
basePkg: ExtendedPackageJson,
144125
): Promise<CreatePackageInfo | undefined> {
145126
const candidates = getCreatePackageNameCandidates(packageName)
146-
const results = await Promise.all(candidates.map(name => fetchCreatePackageInfo(name, basePkg)))
147-
return results.find(r => r !== undefined)
127+
128+
// Use batch API to fetch all candidates in a single request
129+
const results = await getLatestVersionBatch(candidates, { metadata: true, throw: false })
130+
131+
// Process results in order (first valid match wins)
132+
for (let i = 0; i < candidates.length; i++) {
133+
const result = results[i]
134+
const candidateName = candidates[i]
135+
if (!result || !candidateName || 'error' in result) continue
136+
137+
// Need to fetch full package data for association validation (maintainers/repo)
138+
const createPkgInfo = await fetchCreatePackageForValidation(
139+
candidateName,
140+
basePkg,
141+
result.deprecated,
142+
)
143+
if (createPkgInfo) {
144+
return createPkgInfo
145+
}
146+
}
147+
148+
return undefined
148149
}
149150

150151
/**
151-
* Fetch create-* package info including deprecation status.
152-
* Validates that the create-* package is actually associated with the base package.
153-
* Returns undefined if the package doesn't exist or isn't associated.
152+
* Fetch create-* package metadata for association validation.
153+
* Returns CreatePackageInfo if the package is associated with the base package.
154154
*/
155-
async function fetchCreatePackageInfo(
155+
async function fetchCreatePackageForValidation(
156156
createPkgName: string,
157157
basePkg: ExtendedPackageJson,
158+
deprecated: string | undefined,
158159
): Promise<CreatePackageInfo | undefined> {
159160
try {
160161
const encodedName = encodePackageName(createPkgName)
@@ -168,7 +169,7 @@ async function fetchCreatePackageInfo(
168169

169170
return {
170171
packageName: createPkgName,
171-
deprecated: createPkg.deprecated,
172+
deprecated,
172173
}
173174
} catch {
174175
return undefined

shared/utils/npm.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
import type { ResolvedPackageVersion } from 'fast-npm-meta'
1+
import { getLatestVersion } from 'fast-npm-meta'
22
import { createError } from 'h3'
33
import validatePackageName from 'validate-npm-package-name'
44

5-
export const FAST_NPM_META_API = 'https://npm.antfu.dev'
6-
75
/**
86
* Encode package name for URL usage.
97
* Scoped packages need special handling (@scope/name → @scope%2Fname)
@@ -25,8 +23,7 @@ export function encodePackageName(name: string): string {
2523
*/
2624
export async function fetchLatestVersion(name: string): Promise<string | null> {
2725
try {
28-
const encodedName = encodePackageName(name)
29-
const meta = await $fetch<ResolvedPackageVersion>(`${FAST_NPM_META_API}/${encodedName}`)
26+
const meta = await getLatestVersion(name)
3027
return meta.version
3128
} catch {
3229
return null

0 commit comments

Comments
 (0)