Skip to content

Commit 6e49401

Browse files
committed
feat: progressive loading for org packages
Instead of capping at 1000 packages and blocking on all metadata, load the first 250 immediately and fetch the rest on demand. Filtering/sorting triggers loadAll() so client-side search still works on the full set.
1 parent 824cba3 commit 6e49401

5 files changed

Lines changed: 275 additions & 87 deletions

File tree

‎app/composables/npm/useAlgoliaSearch.ts‎

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,33 @@ export function useAlgoliaSearch() {
222222
}
223223
}
224224

225+
/** Fetch metadata for a single batch of packages (max 1000) by exact name. */
226+
asyncfunctiongetPackagesByNameSlice(names: string[]): Promise<NpmSearchResult[]>{
227+
if(names.length===0)return[]
228+
229+
constresponse=await$fetch<{results: (AlgoliaHit|null)[]}>(
230+
`https://${algolia.appId}-dsn.algolia.net/1/indexes/*/objects`,
231+
{
232+
method: 'POST',
233+
headers: {
234+
'x-algolia-api-key': algolia.apiKey,
235+
'x-algolia-application-id': algolia.appId,
236+
},
237+
body: {
238+
requests: names.map(name=>({
239+
indexName,
240+
objectID: name,
241+
attributesToRetrieve: ATTRIBUTES_TO_RETRIEVE,
242+
})),
243+
},
244+
},
245+
)
246+
247+
returnresponse.results
248+
.filter((r): r is AlgoliaHit=>r!==null&&'name'inr)
249+
.map(hitToSearchResult)
250+
}
251+
225252
/** Fetch metadata for specific packages by exact name using Algolia's getObjects API. */
226253
asyncfunctiongetPackagesByName(packageNames: string[]): Promise<NpmSearchResponse>{
227254
if(packageNames.length===0){
@@ -230,36 +257,18 @@ export function useAlgoliaSearch() {
230257

231258
// Algolia getObjects has a limit of 1000 objects per request, so batch if needed
232259
constBATCH_SIZE=1000
233-
constallHits: AlgoliaHit[]=[]
234-
260+
constbatches: string[][]=[]
235261
for(leti=0;i<packageNames.length;i+=BATCH_SIZE){
236-
constbatch=packageNames.slice(i,i+BATCH_SIZE)
237-
constresponse=await$fetch<{results: (AlgoliaHit|null)[]}>(
238-
`https://${algolia.appId}-dsn.algolia.net/1/indexes/*/objects`,
239-
{
240-
method: 'POST',
241-
headers: {
242-
'x-algolia-api-key': algolia.apiKey,
243-
'x-algolia-application-id': algolia.appId,
244-
},
245-
body: {
246-
requests: batch.map(name=>({
247-
indexName,
248-
objectID: name,
249-
attributesToRetrieve: ATTRIBUTES_TO_RETRIEVE,
250-
})),
251-
},
252-
},
253-
)
254-
255-
consthits=response.results.filter((r): r is AlgoliaHit=>r!==null&&'name'inr)
256-
allHits.push(...hits)
262+
batches.push(packageNames.slice(i,i+BATCH_SIZE))
257263
}
258264

265+
constresults=awaitPromise.all(batches.map(batch=>getPackagesByNameSlice(batch)))
266+
constallObjects=results.flat()
267+
259268
return{
260269
isStale: false,
261-
objects: allHits.map(hitToSearchResult),
262-
total: allHits.length,
270+
objects: allObjects,
271+
total: allObjects.length,
263272
time: newDate().toISOString(),
264273
}
265274
}
@@ -366,5 +375,6 @@ export function useAlgoliaSearch() {
366375
searchWithSuggestions,
367376
searchByOwner,
368377
getPackagesByName,
378+
getPackagesByNameSlice,
369379
}
370380
}

0 commit comments

Comments
 (0)