ccflare’s provider layer gives the rest of the system a consistent way to deal with multiple upstream APIs without collapsing all provider-specific behavior into the proxy.
packages/providers owns:
- provider registration and lookup
- provider-specific URL construction
- auth header preparation
- OAuth helper adapters
- refresh-token orchestration
- rate-limit parsing
- response/usage parsing helpers
anthropicopenaiclaude-codecodex
These are exposed through /v1/{provider}/... routes.
graph TD
INDEX[packages/providers/src/index.ts]
REGISTRY[ProviderRegistry]
P1[AnthropicProvider]
P2[OpenAIProvider]
P3[ClaudeCodeProvider]
P4[CodexProvider]
INDEX --> REGISTRY
INDEX --> P1
INDEX --> P2
INDEX --> P3
INDEX --> P4
P1 --> REGISTRY
P2 --> REGISTRY
P3 --> REGISTRY
P4 --> REGISTRY
The registry is responsible for:
- registering providers
- resolving providers from route prefixes
- exposing provider lists for health and startup banners
- exposing OAuth-capable provider adapters
The runtime proxy receives paths like:
/v1/anthropic/v1/messages/v1/openai/chat/completions/v1/claude-code/.../v1/codex/...
Flow:
- strip
/v1/{provider}exactly once - resolve the provider implementation
- select an account for that provider
- delegate upstream URL/header behavior to the provider
anthropicopenai
These use api_key accounts and do not depend on refresh-token flows.
claude-codecodex
These use provider-specific OAuth adapters plus the shared OAuth flow package. Access tokens may be refreshed automatically during forwarding.
sequenceDiagram
participant User
participant API
participant OAuthFlow
participant ProviderOAuth
participant AuthServer
participant DB
User->>API: POST /api/auth/{provider}/init
API->>OAuthFlow: begin(...)
OAuthFlow->>ProviderOAuth: get config + auth URL
OAuthFlow->>DB: create auth session
API-->>User: auth URL + session id
User->>AuthServer: authorize
AuthServer-->>User: code
User->>API: POST /api/auth/{provider}/complete
API->>OAuthFlow: complete(...)
OAuthFlow->>ProviderOAuth: exchange code
ProviderOAuth->>AuthServer: token request
AuthServer-->>ProviderOAuth: tokens
OAuthFlow->>DB: create account + update auth session
API-->>User: success
The provider layer supplies:
- provider-specific auth URL logic
- token exchange logic
- refresh-token request details
Each provider implementation owns:
buildUrl(...)prepareHeaders(...)parseRateLimit(...)- optional OAuth adapter hooks
- optional token refresh support
- provider-format-specific usage parsing
This keeps provider-specific protocol logic out of runtime-server and mostly out of proxy.
Providers normalize native rate-limit signals into a shared shape consumed by the proxy/database layers.
Examples:
- Anthropic-family providers parse unified Anthropic rate-limit headers
- OpenAI parses OpenAI rate-limit headers when available
- Codex parses Codex-specific reset/usage headers
The proxy uses normalized rate-limit data to:
- mark accounts unavailable
- persist reset metadata
- avoid repeatedly selecting bad candidates
Providers also own the provider-specific pieces of usage parsing.
That includes:
- non-streaming JSON usage parsing
- SSE response summary parsing where available
- cache-read/cache-write token fields
- reasoning-token fields where available
Heavy stream/websocket aggregation still happens in the proxy worker, but provider modules own the provider-specific parsing rules.
- upstream base URL defaults to
https://api.anthropic.com - API-key authentication
- unified Anthropic rate-limit parsing
- upstream base URL defaults to
https://api.openai.com/v1 - API-key authentication
- OpenAI/responses usage parsing helpers
- OAuth-based provider
- Anthropic-family request behavior
- refresh-token support
- OAuth-based provider
- Codex-specific backend route handling
- custom headers and rate-limit parsing
To add one cleanly:
- implement the provider class
- implement OAuth helpers only if the provider needs OAuth
- register it in
packages/providers/src/index.ts - add provider metadata in
packages/types/src/provider-metadata.ts - add tests for:
- route resolution
- headers
- token refresh, if applicable
- rate-limit parsing
- usage extraction, if applicable
Provider-specific facts belong in the provider layer or provider metadata, not in the runtime server.
That keeps:
- runtime orchestration generic
- proxy logic provider-agnostic where possible
- provider behavior easy to test in isolation