diff --git a/src/app/api/v1/search/route.ts b/src/app/api/v1/search/route.ts index 313b72dece..ceb78643ec 100644 --- a/src/app/api/v1/search/route.ts +++ b/src/app/api/v1/search/route.ts @@ -56,7 +56,7 @@ export async function OPTIONS() { * GET /v1/search — list available search providers */ export async function GET() { - const settings = await getSettings().catch(() => ({} as any)); + const settings = await getSettings().catch(() => ({}) as any); const blockedProviders = settings?.blockedProviders || []; const providers = getAllSearchProviders(blockedProviders); const timestamp = Math.floor(Date.now() / 1000); @@ -139,7 +139,7 @@ async function postHandler(request: Request, context: unknown) { const policy = await enforceApiKeyPolicy(request, "search"); if (policy.rejection) return policy.rejection; - const settings = await getSettings().catch(() => ({} as any)); + const settings = await getSettings().catch(() => ({}) as any); const blockedProviders = settings?.blockedProviders || []; // Resolve provider and credentials @@ -247,6 +247,34 @@ async function postHandler(request: Request, context: unknown) { } } + // Last resort before failing: promote a fallback-only free provider (e.g. + // duckduckgo-free) to the primary pick so out-of-the-box search works when + // no credentialed provider is configured at all. + if (!credentials) { + const fallbackProviders = Object.values(SEARCH_PROVIDERS) + .filter( + (provider) => + provider.fallbackOnly && + supportsSearchType(provider, body.search_type) && + !isProviderBlockedByIdOrAlias(provider.id, blockedProviders) + ) + .sort((a, b) => a.costPerQuery - b.costPerQuery); + + for (const fallbackProvider of fallbackProviders) { + providerConfig = fallbackProvider; + if (fallbackProvider.id === "duckduckgo-free") { + credentials = {}; + break; + } + const fallbackCreds = await resolveSearchCredentials(fallbackProvider.id); + if (isAllRateLimitedCredentials(fallbackCreds)) continue; + if (fallbackCreds) { + credentials = fallbackCreds; + break; + } + } + } + if (!credentials) { if (firstRateLimitedCredentials) { return rateLimitedProviderResponse( diff --git a/src/shared/components/OmniRouteLogo.tsx b/src/shared/components/OmniRouteLogo.tsx index 32a09cb6fa..a6520fa680 100644 --- a/src/shared/components/OmniRouteLogo.tsx +++ b/src/shared/components/OmniRouteLogo.tsx @@ -16,6 +16,7 @@ export default function OmniRouteLogo({ size = 20, className = "" }: OmniRouteLo fill="none" xmlns="http://www.w3.org/2000/svg" className={className} + suppressHydrationWarning > {/* Central node */}