Skip to content

Commit 212e175

Browse files
committed
fix: use npm as source of truth for org packages
1 parent 54f6135 commit 212e175

File tree

1 file changed

+32
-23
lines changed

1 file changed

+32
-23
lines changed

app/composables/npm/useOrgPackages.ts

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ async function fetchBulkDownloads(
7979
/**
8080
* Fetch all packages for an npm organization.
8181
*
82-
* When the user has Algolia search enabled, uses Algolia's `owner.name` filter
83-
* for a much faster lookup (single request vs N+1 packument fetches).
84-
* Falls back to the npm registry API when using the npm search provider.
82+
* Always uses the npm registry's org endpoint as the source of truth for which
83+
* packages belong to the org. When Algolia is enabled, uses it to quickly fetch
84+
* metadata for those packages (instead of N+1 packument fetches).
8585
*/
8686
export function useOrgPackages(orgName: MaybeRefOrGetter<string>) {
8787
const { searchProvider } = useSearchProvider()
@@ -95,21 +95,9 @@ export function useOrgPackages(orgName: MaybeRefOrGetter<string>) {
9595
return emptySearchResponse
9696
}
9797

98-
// --- Algolia fast path ---
99-
if (searchProvider.value === 'algolia') {
100-
try {
101-
const response = await searchByOwner(org)
102-
// If Algolia returns no results, the org may not exist — fall through
103-
// to npm registry path which can properly detect a 404
104-
if (response.objects.length > 0) {
105-
return response
106-
}
107-
} catch {
108-
// Fall through to npm registry path on Algolia failure
109-
}
110-
}
111-
112-
// --- npm registry path ---
98+
// Always get the authoritative package list from the npm registry.
99+
// Algolia's owner.name filter doesn't precisely match npm org membership
100+
// (e.g. it includes @nuxtjs/* packages for the @nuxt org).
113101
let packageNames: string[]
114102
try {
115103
const { packages } = await $fetch<{ packages: string[]; count: number }>(
@@ -138,9 +126,33 @@ export function useOrgPackages(orgName: MaybeRefOrGetter<string>) {
138126
return emptySearchResponse
139127
}
140128

141-
// Fetch packuments and downloads in parallel
129+
// --- Algolia fast path: use Algolia to get metadata for known packages ---
130+
if (searchProvider.value === 'algolia') {
131+
try {
132+
const response = await searchByOwner(org)
133+
if (response.objects.length > 0) {
134+
// Filter Algolia results to only include packages that are
135+
// actually in the org (per the npm registry's authoritative list)
136+
const orgPackageSet = new Set(packageNames.map(n => n.toLowerCase()))
137+
const filtered = response.objects.filter(obj =>
138+
orgPackageSet.has(obj.package.name.toLowerCase()),
139+
)
140+
141+
if (filtered.length > 0) {
142+
return {
143+
...response,
144+
objects: filtered,
145+
total: filtered.length,
146+
}
147+
}
148+
}
149+
} catch {
150+
// Fall through to npm registry path
151+
}
152+
}
153+
154+
// --- npm registry path: fetch packuments individually ---
142155
const [packuments, downloads] = await Promise.all([
143-
// Fetch packuments with concurrency limit
144156
(async () => {
145157
const results = await mapWithConcurrency(
146158
packageNames,
@@ -157,16 +169,13 @@ export function useOrgPackages(orgName: MaybeRefOrGetter<string>) {
157169
},
158170
10,
159171
)
160-
// Filter out any unpublished packages (missing dist-tags)
161172
return results.filter(
162173
(pkg): pkg is MinimalPackument => pkg !== null && !!pkg['dist-tags'],
163174
)
164175
})(),
165-
// Fetch downloads in bulk
166176
fetchBulkDownloads($npmApi, packageNames, { signal }),
167177
])
168178

169-
// Convert to search results with download data
170179
const results: NpmSearchResult[] = packuments.map(pkg =>
171180
packumentToSearchResult(pkg, downloads.get(pkg.name)),
172181
)

0 commit comments

Comments
 (0)