/**
 * Claude-Compatible Proxy Routes
 *
 * Exposes Anthropic-compatible /v1/messages, /v1/models, and /v1/messages/count_tokens
 * endpoints. ALL requests are routed through ctx.neurolink.generate() / ctx.neurolink.stream()
 * -- no direct HTTP calls to Anthropic.
 *
 * An optional ModelRouter can remap incoming model names to different
 * provider/model pairs (e.g. "claude-sonnet-4-20250514" -> vertex/gemini-2.5-pro).
 * Without a router, models are passed through to the Anthropic provider.
 */
import { buildTranslationOptions } from "../../proxy/proxyTranslationEngine.js";
import { ProxyTracer } from "../../proxy/proxyTracer.js";
import { isPermanentRefreshFailure } from "../../proxy/tokenRefresh.js";
import type { AccountAllowlist, AccountCooldownPlan, AccountQuota, AnthropicAttemptLogger, AnthropicAuthRetryResult, AnthropicLoopState, AnthropicSuccessResult, AnthropicUpstreamFetchResult, ClaudeFinalRequestLogger, ClaudeLoggedErrorBuilder, ClaudeRequest, ClaudeProxyRouteRuntimeOptions, ModelRouterInterface, ParsedClaudeError, ProxyBodyCaptureLogger, ProxyPassthroughAccount, RouteGroup, RuntimeAccountState, ServerContext, StreamTerminalOutcome } from "../../types/index.js";
/** Resolve the configured primary's stable key to its current index in the
 *  request's enabledAccounts list. Returns 0 (insertion-order fallback) when
 *  no key is configured or the key cannot be matched (account disabled/
 *  removed). The resolution is per-request because enabledAccounts membership
 *  can shift between requests. */
declare function resolveHomeIndex(enabledAccounts: ProxyPassthroughAccount[], primaryAccountKey: string | undefined): number;
/** If the configured home primary is no longer cooling, reset
 *  primaryAccountIndex back to its index so traffic returns to the preferred
 *  account once its rate limit window expires. Called at the start of each
 *  request. Home is resolved fresh per call via resolveHomeIndex. */
declare function maybeResetPrimaryToHome(enabledAccounts: ProxyPassthroughAccount[], primaryAccountKey: string | undefined): void;
declare function claimTransientRateLimitRetry(accountKey: string, coolingUntil: number, now?: number): number | undefined;
declare function claimTransientCooldownAdmission(accountKey: string, coolingUntil: number, now?: number): number | undefined;
declare function waitForTransientAccountAvailability(orderedAccounts: ProxyPassthroughAccount[]): Promise<ProxyPassthroughAccount[]>;
/** Convert an Anthropic unified-window reset (Unix epoch SECONDS, per the
 *  `anthropic-ratelimit-unified-*-reset` headers) into epoch-ms. Tolerates a
 *  value already expressed in ms (some intermediaries normalise it). Returns
 *  undefined for absent/zero/past-or-garbage timestamps so callers can fall
 *  back to retry-after. */
declare function resetEpochToMs(resetEpoch: number | undefined, now: number): number | undefined;
/**
 * Decide how to cool an account after a genuine (non-anti-abuse) 429.
 *
 * The unified subscription limits expose per-window status + reset:
 *   - weekly (7d) "rejected"  → hard cap for the week; cool until the 7d reset.
 *   - session (5h) "rejected" → paced out for this session; cool until the 5h reset.
 * Both mean "retrying this account is futile until its window resets" → rotate
 * immediately (no same-account retries) and park the account until the ACTUAL
 * reset — never the legacy 60s hardcap that let us re-hammer a spent account.
 *
 * Anything else (window still "allowed" but momentarily 429'd — a per-minute
 * burst / acceleration limit) is transient: honor retry-after as a floor,
 * allow a couple of jittered same-account retries, then a short cooldown.
 */
declare function planCooldownFor429(quota: AccountQuota | null, retryAfterMs: number, now: number, unifiedStatus?: string | undefined): AccountCooldownPlan;
/**
 * Seed each account's runtime quota from the persisted snapshots in
 * ~/.neurolink/account-quotas.json (keyed by label). Runtime state is
 * in-memory only, so without this the quota-aware ordering is blind after a
 * proxy restart: all accounts tie, selection falls back to token-store
 * enumeration order, and the first account served becomes self-reinforcing
 * (it alone has data) — starving the others regardless of their resets.
 * Never overwrites fresher in-memory quota; stale disk snapshots degrade
 * gracefully because past reset timestamps are ignored by resetEpochToMs.
 */
declare function seedRuntimeQuotasFromDisk(accounts: ProxyPassthroughAccount[]): Promise<void>;
/**
 * Order accounts to MAXIMIZE quota utilization (fill-first, smart order):
 * spend the overall weekly allowance that expires SOONEST first, so quota
 * cannot disappear while traffic is consuming a newer weekly window. The 5h
 * window remains an availability boundary: a session at its soft limit is
 * temporarily demoted until that session resets.
 *
 * Priority among usable accounts:
 *   1. no quota data yet — probe first: one request reveals its windows and
 *      self-corrects the ordering. (Ranking unknowns last would starve them
 *      forever: never picked → never observed → never comparable.)
 *   2. session headroom before session-saturated (>= soft limit or
 *      "throttled") — do not re-hammer an urgent weekly account while its 5h
 *      capacity is temporarily unavailable.
 *   3. soonest WEEKLY (7d) reset — consume the oldest overall allowance
 *      before it expires.
 *   4. soonest SESSION (5h) reset — decides equal-weekly or fresh-weekly ties,
 *      using tolerance buckets for comparator stability.
 *   5. highest weekly utilization — finish off the one closest to done.
 *   6. configured primary account, then insertion order
 * Saturated pairs are ordered by soonest 5h recovery first, then weekly reset,
 * because neither can consume more quota until session capacity returns.
 * Cooling/rejected accounts sort last, soonest-back-to-service first, as
 * last resort.
 */
declare function orderAccountsByQuota(accounts: ProxyPassthroughAccount[], now: number, primaryKey: string | undefined, sessionSoftLimit?: number, sessionResetToleranceMs?: number): ProxyPassthroughAccount[];
declare function trackUpstreamReadableStream(source: ReadableStream<Uint8Array>): {
    stream: ReadableStream<Uint8Array>;
    outcome: Promise<StreamTerminalOutcome>;
};
declare function executeClaudeFallbackTranslation(args: {
    ctx: ServerContext;
    body: ClaudeRequest;
    tracer?: ProxyTracer;
    requestStartTime: number;
    logProxyBody: ProxyBodyCaptureLogger;
    logFinalRequest: (status: number, accountLabel: string, accountType: string, errorType?: string, errorMessage?: string, extra?: {
        inputTokens?: number;
        outputTokens?: number;
        cacheCreationTokens?: number;
        cacheReadTokens?: number;
    }) => void;
    options: Parameters<ServerContext["neurolink"]["stream"]>[0];
    providerLabel: string;
}): Promise<unknown>;
declare function executeClaudeFallbackWithRetry(args: Parameters<typeof executeClaudeFallbackTranslation>[0]): Promise<unknown>;
declare function buildClaudeAnthropicFailureResponse(args: {
    tracer?: ProxyTracer;
    requestStartTime: number;
    authFailureMessage: string | null;
    authCooldownMessage: string | null;
    invalidRequestFailure: {
        status: number;
        body: string;
        contentType?: string;
    } | null;
    sawNetworkError: boolean;
    sawTransientFailure: boolean;
    sawRateLimit: boolean;
    lastError: unknown;
    fallbackFailureMessage?: string;
    orderedAccounts: ProxyPassthroughAccount[];
    buildLoggedClaudeError: ClaudeLoggedErrorBuilder;
    logProxyBody: ProxyBodyCaptureLogger;
    logFinalRequest: (status: number, accountLabel: string, accountType: string, errorType?: string, errorMessage?: string, extra?: {
        inputTokens?: number;
        outputTokens?: number;
        cacheCreationTokens?: number;
        cacheReadTokens?: number;
    }) => void;
}): unknown;
declare function handleAnthropicStreamingSuccessResponse(args: {
    ctx: ServerContext;
    body: ClaudeRequest;
    account: ProxyPassthroughAccount;
    accountState: RuntimeAccountState;
    response: Response;
    responseHeaders: Record<string, string>;
    tracer?: ProxyTracer;
    requestStartTime: number;
    fetchStartMs: number;
    attemptNumber: number;
    finalBodyStr: string;
    upstreamSpan?: import("@opentelemetry/api").Span;
    logAttempt: AnthropicAttemptLogger;
    logProxyBody: ProxyBodyCaptureLogger;
    logFinalRequest: (status: number, accountLabel: string, accountType: string, errorType?: string, errorMessage?: string, extra?: {
        inputTokens?: number;
        outputTokens?: number;
        cacheCreationTokens?: number;
        cacheReadTokens?: number;
    }) => void;
}): Promise<AnthropicSuccessResult>;
declare function getStreamFailureDetails(outcome: StreamTerminalOutcome): {
    status: number;
    errorType: string;
    message: string;
} | undefined;
declare function handleAnthropicAuthRetry(args: {
    ctx: ServerContext;
    body: ClaudeRequest;
    account: ProxyPassthroughAccount;
    accountState: RuntimeAccountState;
    headers: Record<string, string>;
    buildUpstreamBody: (token: string) => {
        bodyStr: string;
        sessionId?: string;
    };
    enabledAccounts: ProxyPassthroughAccount[];
    orderedAccounts: ProxyPassthroughAccount[];
    tracer?: ProxyTracer;
    requestStartTime: number;
    allocateAttemptNumber: () => number;
    upstreamSpan?: import("@opentelemetry/api").Span;
    logAttempt: AnthropicAttemptLogger;
    logProxyBody: ProxyBodyCaptureLogger;
    logFinalRequest: (status: number, accountLabel: string, accountType: string, errorType?: string, errorMessage?: string, extra?: {
        inputTokens?: number;
        outputTokens?: number;
        cacheCreationTokens?: number;
        cacheReadTokens?: number;
    }) => void;
    lastError: unknown;
    authFailureMessage: string | null;
    sawRateLimit: boolean;
    sawTransientFailure: boolean;
    sawNetworkError: boolean;
}): Promise<AnthropicAuthRetryResult>;
declare function finalizeAnthropicTerminalFetchError(args: {
    terminalError: NonNullable<AnthropicUpstreamFetchResult["terminalError"]>;
    account: ProxyPassthroughAccount;
    tracer?: ProxyTracer;
    requestStartTime: number;
    attemptNumber: number;
    logProxyBody: ProxyBodyCaptureLogger;
    logFinalRequest: ClaudeFinalRequestLogger;
}): Response | unknown;
/**
 * Detect Anthropic's anti-abuse / request-construction 429.
 *
 * The subscription/OAuth path rejects requests it does not recognise as genuine
 * Claude Code traffic with a 429 `rate_limit_error` whose message is literally
 * "Error" and which carries NONE of the real rate-limit headers (no retry-after,
 * no anthropic-ratelimit-*). This is NOT a capacity limit — retrying or rotating
 * accounts cannot fix it and only burns quota, so the caller must fail fast and
 * return a non-retryable request error instead of "all accounts rate-limited".
 */
declare function isAntiAbuseConstruction429(headers: Record<string, string>, body: string): boolean;
declare function fetchAnthropicAccountResponse(args: {
    url: string;
    headers: Record<string, string>;
    finalBodyStr: string;
    account: ProxyPassthroughAccount;
    accountState: RuntimeAccountState;
    enabledAccounts: ProxyPassthroughAccount[];
    orderedAccounts: ProxyPassthroughAccount[];
    tracer?: ProxyTracer;
    logAttempt: AnthropicAttemptLogger;
    logProxyBody: ProxyBodyCaptureLogger;
    fetchStartMs: number;
    attemptNumber: number;
    currentLastError: unknown;
    currentSawRateLimit: boolean;
    currentSawNetworkError: boolean;
    upstreamSpan?: import("@opentelemetry/api").Span;
}): Promise<AnthropicUpstreamFetchResult>;
declare function shouldAttemptClaudeFallback(loopState: AnthropicLoopState): boolean;
/**
 * Create Claude-compatible proxy routes.
 *
 * Every request flows through ctx.neurolink.generate() or ctx.neurolink.stream().
 * No direct fetch() calls to api.anthropic.com.
 *
 * @param modelRouter - Optional model router for remapping model names.
 * @param basePath    - Base path prefix (default: "" since Claude API uses /v1/...).
 * @returns RouteGroup with Claude-compatible endpoints.
 */
export declare function createClaudeProxyRoutes(modelRouter?: ModelRouterInterface, basePath?: string, accountStrategy?: "round-robin" | "fill-first", passthroughMode?: boolean, primaryAccountKey?: string, accountAllowlistOrRuntimeOptions?: AccountAllowlist | ClaudeProxyRouteRuntimeOptions): RouteGroup;
export declare function getTransientSameAccountRetryDelayMs(retryNumber: number): number;
declare function describeTransportError(error: unknown): string;
/**
 * Parse a Claude error payload when available.
 */
export declare function parseClaudeErrorBody(errBody: string): ParsedClaudeError;
/**
 * Detect malformed request errors that should not trigger account/provider failover.
 */
export declare function isInvalidRequestError(status: number, errBody: string): boolean;
/**
 * Backward-compatible alias — delegates to the shared translation engine.
 */
export declare const buildProxyFallbackOptions: typeof buildTranslationOptions;
/**
 * Detect transient upstream failures that should trigger account/provider failover.
 *
 * Includes Cloudflare 52x statuses and Anthropic 400/api_error wrappers that
 * carry transient HTML responses (e.g. 520 pages) inside `error.message`.
 */
export declare function isTransientHttpFailure(status: number, errBody: string): boolean;
export declare const __testHooks: {
    resolveHomeIndex: typeof resolveHomeIndex;
    maybeResetPrimaryToHome: typeof maybeResetPrimaryToHome;
    planCooldownFor429: typeof planCooldownFor429;
    isPermanentRefreshFailure: typeof isPermanentRefreshFailure;
    getStreamFailureDetails: typeof getStreamFailureDetails;
    trackUpstreamReadableStream: typeof trackUpstreamReadableStream;
    orderAccountsByQuota: typeof orderAccountsByQuota;
    resetEpochToMs: typeof resetEpochToMs;
    seedRuntimeQuotasFromDisk: typeof seedRuntimeQuotasFromDisk;
    getAccountRuntimeState: (key: string) => RuntimeAccountState | undefined;
    setPrimaryAccountIndex: (index: number) => void;
    getPrimaryAccountIndex: () => number;
    setAccountRuntimeState: (key: string, state: Partial<RuntimeAccountState>) => void;
    resetAllRuntimeState: () => void;
    polyfillOAuthBody: (bodyStr: string, isClaudeClientRequest: boolean) => {
        bodyStr: string;
        sessionId?: string;
    };
    isAntiAbuseConstruction429: typeof isAntiAbuseConstruction429;
    fetchAnthropicAccountResponse: typeof fetchAnthropicAccountResponse;
    finalizeAnthropicTerminalFetchError: typeof finalizeAnthropicTerminalFetchError;
    handleAnthropicAuthRetry: typeof handleAnthropicAuthRetry;
    handleAnthropicStreamingSuccessResponse: typeof handleAnthropicStreamingSuccessResponse;
    claimTransientRateLimitRetry: typeof claimTransientRateLimitRetry;
    claimTransientCooldownAdmission: typeof claimTransientCooldownAdmission;
    waitForTransientAccountAvailability: typeof waitForTransientAccountAvailability;
    describeTransportError: typeof describeTransportError;
    shouldAttemptClaudeFallback: typeof shouldAttemptClaudeFallback;
    executeClaudeFallbackWithRetry: typeof executeClaudeFallbackWithRetry;
    buildClaudeAnthropicFailureResponse: typeof buildClaudeAnthropicFailureResponse;
};
export {};
