@@ -316,14 +316,13 @@ interface ValidatedSuggestion {
316316/** Cache for existence checks to avoid repeated API calls */
317317const existenceCache = ref <Record <string , boolean | ' pending' >>({})
318318
319- interface NpmSearchResponse {
320- total: number
321- objects: Array <{ package: { name: string } }>
322- }
319+ const { search : algoliaSearch } = useAlgoliaSearch ()
320+ const { isAlgolia } = useSearchProvider ()
323321
324322/**
325- * Check if an org exists by searching for packages with @orgname scope
326- * Uses the search API which has CORS enabled
323+ * Check if an org exists by searching for scoped packages (@orgname/...).
324+ * When Algolia is active, searches for `@name /` scoped packages via text query.
325+ * Falls back to npm registry search API otherwise.
327326 */
328327async function checkOrgExists(name : string ): Promise <boolean > {
329328 const cacheKey = ` org:${name .toLowerCase ()} `
@@ -333,12 +332,24 @@ async function checkOrgExists(name: string): Promise<boolean> {
333332 }
334333 existenceCache .value [cacheKey ] = ' pending'
335334 try {
336- // Search for packages in the @org scope
337- const response = await $fetch <NpmSearchResponse >(` ${NPM_REGISTRY }/-/v1/search ` , {
338- query: { text: ` @${name } ` , size: 5 },
339- })
340- // Verify at least one result actually starts with @orgname/
341335 const scopePrefix = ` @${name .toLowerCase ()}/ `
336+
337+ if (isAlgolia .value ) {
338+ // Algolia: search for scoped packages — use the scope as a text query
339+ // and verify a result actually starts with @name/
340+ const response = await algoliaSearch (` @${name } ` , { size: 5 })
341+ const exists = response .objects .some (obj =>
342+ obj .package .name .toLowerCase ().startsWith (scopePrefix ),
343+ )
344+ existenceCache .value [cacheKey ] = exists
345+ return exists
346+ }
347+
348+ // npm registry: search for packages in the @org scope
349+ const response = await $fetch <{ total: number ; objects: Array <{ package: { name: string } }> }>(
350+ ` ${NPM_REGISTRY }/-/v1/search ` ,
351+ { query: { text: ` @${name } ` , size: 5 } },
352+ )
342353 const exists = response .objects .some (obj =>
343354 obj .package .name .toLowerCase ().startsWith (scopePrefix ),
344355 )
@@ -351,8 +362,10 @@ async function checkOrgExists(name: string): Promise<boolean> {
351362}
352363
353364/**
354- * Check if a user exists by searching for packages they maintain
355- * Uses the search API which has CORS enabled
365+ * Check if a user exists by searching for packages they maintain.
366+ * Always uses the npm registry `maintainer:` search because Algolia's
367+ * `owner.name` field represents the org/account, not individual maintainers,
368+ * and cannot reliably distinguish users from orgs.
356369 */
357370async function checkUserExists(name : string ): Promise <boolean > {
358371 const cacheKey = ` user:${name .toLowerCase ()} `
@@ -418,8 +431,8 @@ const parsedQuery = computed<ParsedQuery>(() => {
418431const validatedSuggestions = ref <ValidatedSuggestion []>([])
419432const suggestionsLoading = shallowRef (false )
420433
421- /** Debounced function to validate suggestions */
422- const validateSuggestions = debounce ( async ( parsed : ParsedQuery ) => {
434+ /** Validate suggestions (check org/user existence) */
435+ async function validateSuggestionsImpl( parsed : ParsedQuery ) {
423436 if (! parsed .type || ! parsed .name ) {
424437 validatedSuggestions .value = []
425438 return
@@ -458,17 +471,36 @@ const validateSuggestions = debounce(async (parsed: ParsedQuery) => {
458471 }
459472
460473 validatedSuggestions .value = suggestions
461- }, 200 )
474+ }
475+
476+ // Debounce lightly for npm (extra API calls are slower), skip debounce for Algolia (fast)
477+ const validateSuggestionsDebounced = debounce (validateSuggestionsImpl , 100 )
462478
463479// Validate suggestions when query changes
464480watch (
465481 parsedQuery ,
466482 parsed => {
467- validateSuggestions (parsed )
483+ if (isAlgolia .value ) {
484+ // Algolia existence checks are fast - fire immediately
485+ validateSuggestionsImpl (parsed )
486+ } else {
487+ validateSuggestionsDebounced (parsed )
488+ }
468489 },
469490 { immediate: true },
470491)
471492
493+ // Re-validate suggestions and clear caches when provider changes
494+ watch (isAlgolia , () => {
495+ // Clear existence cache since results may differ between providers
496+ existenceCache .value = {}
497+ // Re-validate with current query
498+ const parsed = parsedQuery .value
499+ if (parsed .type ) {
500+ validateSuggestionsImpl (parsed )
501+ }
502+ })
503+
472504/** Check if there's an exact package match in results */
473505const hasExactPackageMatch = computed (() => {
474506 const q = query .value .trim ().toLowerCase ()
0 commit comments