@@ -18,6 +18,12 @@ import type { CachedFetchFunction } from '#shared/utils/fetch-cache-config'
1818const NPM_REGISTRY = 'https://registry.npmjs.org'
1919const NPM_API = 'https://api.npmjs.org'
2020
21+ interface NpmSearchError {
22+ data : {
23+ code : string
24+ }
25+ }
26+
2127// Cache for packument fetches to avoid duplicate requests across components
2228const packumentCache = new Map < string , Promise < Packument | null > > ( )
2329
@@ -306,6 +312,7 @@ export function useNpmSearch(
306312 ( ) => `search:incremental:${ toValue ( query ) } ` ,
307313 async ( _nuxtApp , { signal } ) => {
308314 const q = toValue ( query )
315+
309316 if ( ! q . trim ( ) ) {
310317 return emptySearchResponse
311318 }
@@ -321,19 +328,57 @@ export function useNpmSearch(
321328 // Use requested size for initial fetch
322329 params . set ( 'size' , String ( opts . size ?? 25 ) )
323330
324- const { data : response , isStale } = await cachedFetch < NpmSearchResponse > (
325- `${ NPM_REGISTRY } /-/v1/search?${ params . toString ( ) } ` ,
326- { signal } ,
327- 60 ,
328- )
331+ try {
332+ const { data : response , isStale } = await cachedFetch < NpmSearchResponse > (
333+ `${ NPM_REGISTRY } /-/v1/search?${ params . toString ( ) } ` ,
334+ { signal } ,
335+ 60 ,
336+ )
329337
330- cache . value = {
331- query : q ,
332- objects : response . objects ,
333- total : response . total ,
334- }
338+ cache . value = {
339+ query : q ,
340+ objects : response . objects ,
341+ total : response . total ,
342+ }
335343
336- return { ...response , isStale }
344+ return { ...response , isStale }
345+ } catch ( error ) {
346+ if ( ( error as NpmSearchError ) ?. data ?. code === 'ERR_TEXT_LENGTH' ) {
347+ try {
348+ const encodedName = encodePackageName ( q )
349+ const [ { data : pkg } , { data : downloads } ] = await Promise . all ( [
350+ cachedFetch < Packument > ( `${ NPM_REGISTRY } /${ encodedName } ` , { signal } ) ,
351+ cachedFetch < NpmDownloadCount > ( `${ NPM_API } /downloads/point/last-week/${ encodedName } ` , {
352+ signal,
353+ } ) ,
354+ ] )
355+
356+ if ( ! pkg ) {
357+ throw error
358+ }
359+
360+ const result = packumentToSearchResult ( pkg , downloads ?. downloads )
361+
362+ cache . value = {
363+ query : q ,
364+ objects : [ result ] ,
365+ total : 1 ,
366+ }
367+
368+ return {
369+ objects : [ result ] ,
370+ total : 1 ,
371+ isStale : false ,
372+ time : new Date ( ) . toISOString ( ) ,
373+ }
374+ } catch {
375+ // If exact lookup also fails, throw original error
376+ throw error
377+ }
378+ }
379+
380+ throw error
381+ }
337382 } ,
338383 { default : ( ) => lastSearch || emptySearchResponse } ,
339384 )
0 commit comments