{"version":3,"file":"resolve.mjs","names":[],"sources":["../../src/core/resolve.ts"],"sourcesContent":["/** Auto-select providers by environment, chain, and operation capability. */\n\nimport { create, providers, has, supportsCapability, supportsChain } from \"./registry.js\";\nimport {\n  AuthError,\n  PlanRestrictedError,\n  RateLimitError,\n  UnknownProviderError,\n  UnsupportedChainError,\n  UnsupportedOperationError,\n} from \"./errors.js\";\nimport type { Provider, ProviderCapability } from \"./provider.js\";\nimport { normalizeChain } from \"./types.js\";\nimport type { ChainKey } from \"./types.js\";\n\nconst ENV_MAP: Record<string, string[]> = {\n  etherscan: [\"ETHERSCAN_API_KEY\"],\n  blockscout: [],\n  blockchair: [\"BLOCKCHAIR_API_KEY\"],\n  mempool: [],\n  blockstream: [],\n  solscan: [\"SOLSCAN_API_KEY\"],\n  helius: [\"HELIUS_API_KEY\"],\n  ton: [],\n  tronscan: [\"TRONSCAN_API_KEY\"],\n  aptos: [],\n  blockberry: [\"BLOCKBERRY_API_KEY\"],\n  koios: [],\n  arweave: [],\n  dcrdata: [],\n  horizon: [],\n};\n\nconst OPTIONAL_CREDENTIAL_PROVIDERS: readonly string[] = [\"blockchair\"];\n\n/** Provider-specific default chains */\nexport const PROVIDER_DEFAULT_CHAIN: Partial<Record<string, ChainKey>> = {\n  mempool: \"bitcoin\",\n  blockstream: \"bitcoin\",\n  solscan: \"solana\",\n  helius: \"solana\",\n  ton: \"ton\",\n  tronscan: \"tron\",\n  aptos: \"aptos\",\n  blockberry: \"sui\",\n  koios: \"cardano\",\n  arweave: \"arweave\",\n  dcrdata: \"decred\",\n  horizon: \"stellar\",\n};\n\nfunction hasConfiguredCredentials(envKeys: readonly string[]): boolean {\n  return envKeys.length > 0 && envKeys.every((key) => process.env[key]);\n}\n\nfunction isKeylessCandidate(\n  name: string,\n  envKeys: readonly string[],\n  mode: \"primary\" | \"fallback\",\n): boolean {\n  return (\n    envKeys.length === 0 || (mode === \"fallback\" && OPTIONAL_CREDENTIAL_PROVIDERS.includes(name))\n  );\n}\n\nfunction appendRankedProvider(\n  ranked: readonly string[],\n  name: string,\n  chain?: ChainKey,\n  capability?: ProviderCapability,\n): readonly string[] {\n  const fitsChain = chain === undefined || supportsChain(name, chain);\n  const fitsCapability = capability === undefined || supportsCapability(name, capability);\n  return has(name) && fitsChain && fitsCapability && !ranked.includes(name)\n    ? [...ranked, name]\n    : ranked;\n}\n\nfunction configuredProviderNames(): string[] {\n  return Object.entries(ENV_MAP)\n    .filter(([, envKeys]) => hasConfiguredCredentials(envKeys))\n    .map(([name]) => name);\n}\n\nfunction keylessProviderNames(mode: \"primary\" | \"fallback\"): string[] {\n  return Object.entries(ENV_MAP)\n    .filter(([name, envKeys]) => isKeylessCandidate(name, envKeys, mode))\n    .map(([name]) => name);\n}\n\nfunction appendCandidates(\n  ranked: readonly string[],\n  candidates: readonly string[],\n  chain?: ChainKey,\n  capability?: ProviderCapability,\n): readonly string[] {\n  let result = ranked;\n  for (const name of candidates) result = appendRankedProvider(result, name, chain, capability);\n  return result;\n}\n\nfunction rankProviders(\n  chain?: ChainKey,\n  mode: \"primary\" | \"fallback\" = \"primary\",\n  capability?: ProviderCapability,\n): string[] {\n  let ranked = appendCandidates([], configuredProviderNames(), chain, capability);\n  ranked = appendCandidates(ranked, keylessProviderNames(mode), chain, capability);\n  if (mode === \"primary\" && chain !== undefined) {\n    ranked = appendCandidates(ranked, providers(), chain, capability);\n  }\n  return [...ranked];\n}\n\n/**\n * Choose a registered provider for the current environment.\n *\n * An explicit preference wins, even for a chain it cannot serve, so misconfiguration stays visible.\n * Without one, candidates that declare support for the requested chain and optional capability are\n * considered in order: configured credentials first, then keyless providers, then any matching\n * registry entry, and finally Blockscout when no provider matches the chain.\n *\n * @throws {UnknownProviderError} When an explicit preference is not registered.\n *\n * @param {string} preferred - The `preferred` value.\n * @param {ChainKey} chain - The `chain` value.\n * @param {ProviderCapability} capability - Operation required from an automatic selection.\n * @returns {string} The resulting value.\n */\nexport function resolveProvider(\n  preferred?: string,\n  chain?: ChainKey,\n  capability?: ProviderCapability,\n): string {\n  if (preferred !== undefined) {\n    if (!has(preferred)) throw new UnknownProviderError(preferred);\n    return preferred;\n  }\n\n  const selected = rankProviders(chain, \"primary\", capability)[0];\n  if (selected !== undefined) return selected;\n\n  // If no backend serves the operation, preserve chain-aware selection so its typed limitation\n  // stays more useful than an unrelated provider's chain error.\n  if (capability !== undefined) {\n    const chainMatch = rankProviders(chain)[0];\n    if (chainMatch !== undefined) return chainMatch;\n  }\n\n  return has(\"blockscout\") ? \"blockscout\" : (providers()[0] ?? \"blockscout\");\n}\n\n/** Provider and effective chain selected for one read. */\nexport interface ProviderContext {\n  readonly chain: ChainKey;\n  readonly name: string;\n  readonly provider: Provider;\n}\n\nfunction preservesPrimaryError(error: unknown): boolean {\n  return (\n    error instanceof AuthError ||\n    error instanceof UnsupportedChainError ||\n    error instanceof UnsupportedOperationError\n  );\n}\n\nasync function runFallback<T>(\n  execute: (name: string) => Promise<T>,\n  fallbackName: string,\n  primaryError: unknown,\n): Promise<T> {\n  try {\n    return await execute(fallbackName);\n  } catch (fallbackError) {\n    if (preservesPrimaryError(fallbackError)) throw primaryError;\n    throw fallbackError;\n  }\n}\n\n/**\n * Run one read with provider selection and one automatic retry after a transient or plan limit.\n *\n * When neither provider nor chain is explicit, selection starts on Ethereum. An explicit provider\n * without a chain keeps that provider's default chain. The callback must be safe to run twice.\n *\n * @param {string | undefined} preferred - The `preferred` value.\n * @param {ChainKey | undefined} chain - The `chain` value.\n * @param {(context: Readonly<ProviderContext>) => Promise<T>} run - The `run` value.\n * @param {ProviderCapability} capability - Operation required from an automatic selection.\n * @returns {Promise<T>} The resulting value.\n */\nexport async function withProvider<T>(\n  preferred: string | undefined,\n  chain: ChainKey | undefined,\n  /* oxlint-disable-next-line typescript/prefer-readonly-parameter-types */\n  run: (context: ProviderContext) => Promise<T>,\n  capability?: ProviderCapability,\n): Promise<T> {\n  const requestedChain = chain ?? (preferred === undefined ? normalizeChain() : undefined);\n  const primaryName = resolveProvider(preferred, requestedChain, capability);\n  const effectiveChain = requestedChain ?? normalizeChain(PROVIDER_DEFAULT_CHAIN[primaryName]);\n  const fallbackName = rankProviders(effectiveChain, \"fallback\", capability).find(\n    (name) => name !== primaryName,\n  );\n  const execute = async (name: string) =>\n    run({ chain: effectiveChain, name, provider: await create(name) });\n\n  try {\n    return await execute(primaryName);\n  } catch (error) {\n    if (\n      preferred !== undefined ||\n      fallbackName === undefined ||\n      !(error instanceof RateLimitError || error instanceof PlanRestrictedError)\n    ) {\n      throw error;\n    }\n\n    return runFallback(execute, fallbackName, error);\n  }\n}\n"],"mappings":"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"}