/** * Env-var name resolution for provider credentials. * * A provider declares one `authEnv` name, but the same key lives under different * names depending on which tool wrote it (`GEMINI_API_KEY` vs `GOOGLEAI_API_KEY` * vs `GOOGLE_API_KEY`). Rather than make the user rename an already-working env * var, resolve the declared name against a small set of known aliases and pick * the first one that is actually set. * * The candidate list is deliberately a closed set per provider plus names derived * from the provider's own name — never a scan of the environment for anything * key-shaped. A heuristic match could ship one provider's credential to another * provider's endpoint, which is a credential leak, not a convenience. */ import type { CredentialId } from "./credential-id.js"; import { keyIsPresent, type KeystoreOptions } from "./keystore.js"; /** The one credential-presence predicate, owned by the lower-level keystore surface. */ export { keyIsPresent }; /** * The curated aliases only, without the provider-name-derived candidates used by * `candidateEnvNames()`. Importers need this narrower surface: accepting a credential from a * file is allowed only when its NAME is explicitly listed, never because its value happens to * look like a key or because an arbitrary provider slug can be turned into a plausible env name. */ export declare function curatedEnvNames(providerName: string): string[]; /** * Every env-var name that may carry this provider's credential, most-preferred first: * the declared name, then curated aliases, then names derived from the provider name. */ export declare function candidateEnvNames(providerName: string, declared?: string): string[]; /** * The complete legacy credential-name walk, shared by resolution and custody * coverage diagnostics. An env-name-implied provider family is considered before * candidates derived from the configured provider name. */ export declare function credentialCandidateEnvNames(declaredAuthEnv: string | undefined, providerName?: string): string[]; export interface AuthEnvResolution { /** The name to read the key from — the first candidate that is set, else the declared name. */ name: string | undefined; /** True when the key was found under a name other than the declared one. */ viaAlias: boolean; /** Every name that was considered, for diagnostics. */ candidates: string[]; } export interface CredentialResolution { state: CredentialState; value: string | undefined; envName: string | undefined; source: CredentialSource | undefined; provenance?: { entryId: CredentialId; provider: string; }; } export type CredentialSource = "env" | "env-file" | "keystore"; /** * Whether a provider's credential handling is DECLARED, and if so whether the * key is actually there. * * ⚠ Derived from the config DECLARATION, never from `resolveAuthEnv` having * returned a name. Those are different questions: the alias list for anthropic * includes ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN, so a provider with NO * declared authEnv — an intentional passthrough — still resolves to a name * whenever either variable happens to be set in the environment. Deriving state * from the name would classify that passthrough as `declared-present`, making it * inject a key and strip the caller's own token: the exact inversion of the one * behaviour a passthrough exists to provide. */ export type CredentialState = "not-declared" | "declared-present" | "declared-missing"; export declare function credentialState(declaredAuthEnv: string | undefined, env?: NodeJS.ProcessEnv, providerName?: string, keystoreOptions?: KeystoreOptions): CredentialState; export declare function readCredential(declaredAuthEnv: string | undefined, env?: NodeJS.ProcessEnv, providerName?: string, keystoreOptions?: KeystoreOptions): string | undefined; export declare function resolveCredential(declaredAuthEnv: string | undefined, env?: NodeJS.ProcessEnv, providerName?: string, keystoreOptions?: KeystoreOptions): CredentialResolution; /** * Resolve one explicitly-declared fleet slot. Unlike the legacy single `authEnv` form this * intentionally does not consult curated or provider-derived aliases: alias fallback could make * two slots share one environment variable and therefore share a quota domain. */ export declare function resolveCredentialExact(declaredAuthEnv: string | undefined, env?: NodeJS.ProcessEnv, keystoreOptions?: KeystoreOptions): CredentialResolution; /** * Which header a provider's credential is injected into. * * Structurally identical to `AuthHeader` in `config.ts` and freely assignable in * both directions. It is redeclared here rather than imported so this module keeps * ZERO dependency on `config.ts` — `config.ts` imports this one, and `tier-data.ts` * already exists as a separate module for exactly that reason. */ export type AuthHeaderName = "x-api-key" | "authorization"; /** * THE construction site for a provider credential header. * * Returns `{}` when the credential is absent, so the builder — not each caller — * is what guarantees a blank key never reaches the wire as an empty `x-api-key` or * a bare `Bearer`. Callers merge the result; they must not test the key themselves. * * Two normalisations, both deliberate: * - The value is trimmed. A key pasted into `~/.llm-relay/.env` with a trailing * newline is a valid key that 401s, which reads as "my key is bad". * - `Bearer ` prefixing is idempotent. Three of the existing sites already accept a * value that carries its own `Bearer ` prefix; double-prefixing it would break * them on migration. * * ⚠ It obeys the DECLARED `authHeader` and never consults `provider.kind`. Three * current sites (`key-checker.ts`, `ping/ping.ts`, `pool-health.ts`) additionally * force `x-api-key` on any `kind: "anthropic"` provider, which silently discards an * explicit `authHeader: "authorization"`. `config.ts` already defaults an * anthropic-kind provider's `authHeader` to `x-api-key`, so migrating those sites is * behaviour-preserving in every case EXCEPT that explicit override — where honouring * the config is the correct answer. It is called out rather than encoded so the * change is a visible decision, not a silent one. * * Non-credential companions (`anthropic-version`, `Content-Type`) stay with the * caller: this function builds the auth header and nothing else. */ export declare function buildAuthHeaders(key: string | undefined, authHeader: AuthHeaderName): Record; /** * Pick the env-var name this provider's key actually lives under. Falls back to the * declared name when nothing is set, so "missing key" diagnostics still name the * variable the config asked for. */ export declare function resolveAuthEnv(providerName: string, declared: string | undefined, env?: NodeJS.ProcessEnv): AuthEnvResolution;