{"version":3,"file":"resolve2.mjs","names":[],"sources":["../../src/core/resolve.ts"],"sourcesContent":["import { builtinProviders, type WebSearchProviderName } from './providers.ts'\nimport { create, has } from './registry.ts'\nimport { NoProviderAvailableError, NoProviderConfiguredError } from './errors.ts'\n\nconst envKeys: Record<string, WebSearchProviderName> = {\n  EXA_API_KEY: 'exa',\n  BRAVE_API_KEY: 'brave',\n  JINA_API_KEY: 'jina',\n  TAVILY_API_KEY: 'tavily',\n  SERPAPI_API_KEY: 'serpapi',\n  SERPBASE_API_KEY: 'serpbase',\n}\n\nfunction envVarFor(name: WebSearchProviderName): string | null {\n  return name === 'searxng' ? null : `${name.toUpperCase()}_API_KEY`\n}\n\nexport function detectAvailableProviders(): WebSearchProviderName[] {\n  const available: WebSearchProviderName[] = []\n\n  for (const [envVar, name] of Object.entries(envKeys)) {\n    if (process.env[envVar]) {\n      available.push(name)\n    }\n  }\n\n  if (has('searxng')) {\n    available.push('searxng')\n  }\n\n  return available\n}\n\nexport function resolveDefaultProvider(): WebSearchProviderName {\n  for (const [envVar, name] of Object.entries(envKeys)) {\n    if (process.env[envVar]) {\n      return name\n    }\n  }\n\n  if (has('searxng')) {\n    return 'searxng'\n  }\n\n  throw new NoProviderConfiguredError()\n}\n\nexport interface ProviderStatus {\n  name: WebSearchProviderName\n  configured: boolean\n  envVar: string | null\n  /**\n   * Set by {@link listProvidersAsync} when the provider implements\n   * {@link SearchProvider.isAvailable}. `true` = probe succeeded, `false` =\n   * probe failed (host down / unreachable / timeout), `undefined` = no probe\n   * was performed (sync caller) or provider has no probe (trust `configured`).\n   */\n  reachable?: boolean\n}\n\nexport function listProviders(): ProviderStatus[] {\n  const available = detectAvailableProviders()\n  return builtinProviders.map(name => ({\n    name,\n    configured: available.includes(name),\n    envVar: envVarFor(name),\n  }))\n}\n\n/**\n * Async variant: returns only providers that are both declaratively configured\n * (env var present or registered) AND — if they implement `isAvailable()` —\n * pass the reachability probe. Use for fan-out flows (`searchAll`) where an\n * unreachable self-hosted endpoint should be skipped instead of producing a\n * connection-refused error. Sync {@link detectAvailableProviders} stays the\n * declarative source of truth for env-var inspection.\n */\nexport async function detectAvailableProvidersAsync(): Promise<WebSearchProviderName[]> {\n  const candidates = detectAvailableProviders()\n  const probes = await Promise.all(candidates.map(async name => {\n    const reachable = await probeConfiguredProvider(name)\n    return reachable === false ? null : name\n  }))\n  return probes.filter((n): n is WebSearchProviderName => n !== null)\n}\n\n/**\n * Async variant of {@link listProviders} that also runs the per-provider\n * reachability probe and surfaces it as `reachable` on each row. Providers\n * without an `isAvailable()` probe get `reachable: undefined` (trust\n * `configured`).\n */\nexport async function listProvidersAsync(): Promise<ProviderStatus[]> {\n  const available = detectAvailableProviders()\n  return Promise.all(builtinProviders.map(async name => {\n    const configured = available.includes(name)\n    const base: ProviderStatus = { name, configured, envVar: envVarFor(name) }\n    if (!configured) return base\n    const reachable = await probeConfiguredProvider(name)\n    return reachable === undefined ? base : { ...base, reachable }\n  }))\n}\n\n/**\n * Async variant of {@link resolveDefaultProvider}: returns the first provider\n * that is configured AND (if it has an `isAvailable()` probe) reachable. Use\n * in flows that should not crash when the env-preferred default is down\n * (e.g. SearXNG on `localhost:8080` without a running instance).\n */\nexport async function resolveDefaultProviderAsync(): Promise<WebSearchProviderName> {\n  const candidates = detectAvailableProviders()\n  for (const name of candidates) {\n    const reachable = await probeConfiguredProvider(name)\n    if (reachable !== false) {\n      return name\n    }\n  }\n\n  if (candidates.length === 0) {\n    throw new NoProviderConfiguredError()\n  }\n  throw new NoProviderAvailableError(candidates)\n}\n\nasync function probeConfiguredProvider(name: WebSearchProviderName): Promise<boolean | undefined> {\n  try {\n    const provider = create(name)\n    if (typeof provider.isAvailable !== 'function') return undefined\n    return await provider.isAvailable()\n  }\n  catch {\n    return false\n  }\n}\n"],"mappings":";;;;AAIA,MAAM,UAAiD;CACrD,aAAa;CACb,eAAe;CACf,cAAc;CACd,gBAAgB;CAChB,iBAAiB;CACjB,kBAAkB;CACnB;AAED,SAAS,UAAU,MAA4C;AAC7D,QAAO,SAAS,YAAY,OAAO,GAAG,KAAK,aAAa,CAAC;;AAG3D,SAAgB,2BAAoD;CAClE,MAAM,YAAqC,EAAE;AAE7C,MAAK,MAAM,CAAC,QAAQ,SAAS,OAAO,QAAQ,QAAQ,CAClD,KAAI,QAAQ,IAAI,QACd,WAAU,KAAK,KAAK;AAIxB,KAAI,IAAI,UAAU,CAChB,WAAU,KAAK,UAAU;AAG3B,QAAO;;AAGT,SAAgB,yBAAgD;AAC9D,MAAK,MAAM,CAAC,QAAQ,SAAS,OAAO,QAAQ,QAAQ,CAClD,KAAI,QAAQ,IAAI,QACd,QAAO;AAIX,KAAI,IAAI,UAAU,CAChB,QAAO;AAGT,OAAM,IAAI,2BAA2B;;AAgBvC,SAAgB,gBAAkC;CAChD,MAAM,YAAY,0BAA0B;AAC5C,QAAO,iBAAiB,KAAI,UAAS;EACnC;EACA,YAAY,UAAU,SAAS,KAAK;EACpC,QAAQ,UAAU,KAAA;EACnB,EAAE;;;;;;;;;;AAWL,eAAsB,gCAAkE;CACtF,MAAM,aAAa,0BAA0B;AAK7C,SAJe,MAAM,QAAQ,IAAI,WAAW,IAAI,OAAM,SAAQ;AAE5D,SADkB,MAAM,wBAAwB,KAAK,KAChC,QAAQ,OAAO;GACpC,CAAC,EACW,QAAQ,MAAkC,MAAM,KAAK;;;;;;;;AASrE,eAAsB,qBAAgD;CACpE,MAAM,YAAY,0BAA0B;AAC5C,QAAO,QAAQ,IAAI,iBAAiB,IAAI,OAAM,SAAQ;EACpD,MAAM,aAAa,UAAU,SAAS,KAAK;EAC3C,MAAM,OAAuB;GAAE;GAAM;GAAY,QAAQ,UAAU,KAAA;GAAO;AAC1E,MAAI,CAAC,WAAY,QAAO;EACxB,MAAM,YAAY,MAAM,wBAAwB,KAAK;AACrD,SAAO,cAAc,KAAA,IAAY,OAAO;GAAE,GAAG;GAAM;GAAW;GAC9D,CAAC;;;;;;;;AASL,eAAsB,8BAA8D;CAClF,MAAM,aAAa,0BAA0B;AAC7C,MAAK,MAAM,QAAQ,WAEjB,KADkB,MAAM,wBAAwB,KAAK,KACnC,MAChB,QAAO;AAIX,KAAI,WAAW,WAAW,EACxB,OAAM,IAAI,2BAA2B;AAEvC,OAAM,IAAI,yBAAyB,WAAW;;AAGhD,eAAe,wBAAwB,MAA2D;AAChG,KAAI;EACF,MAAM,WAAW,OAAO,KAAK;AAC7B,MAAI,OAAO,SAAS,gBAAgB,WAAY,QAAO,KAAA;AACvD,SAAO,MAAM,SAAS,aAAa;SAE/B;AACJ,SAAO"}