File size: 3,334 Bytes
ae9d2aa
 
3784bc3
 
 
 
 
 
 
 
 
 
 
 
 
 
ae9d2aa
 
3784bc3
 
ae9d2aa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3784bc3
 
 
 
ae9d2aa
 
3784bc3
 
ae9d2aa
 
 
 
 
 
 
3784bc3
 
 
 
 
 
 
ae9d2aa
 
 
 
 
 
 
 
 
 
 
3784bc3
 
ae9d2aa
 
 
 
3784bc3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/** Shared TypeScript types for the proxy server. */

/** Per-provider upstream configuration used by the generic forwarder. */
export interface ProviderConfig {
    /** Human-readable name for logging (e.g. "anthropic", "gemini"). */
    readonly name: string;
    /** Upstream base URL (e.g. "https://api.anthropic.com"). */
    readonly baseUrl: string;
    /** The API key value to inject into upstream requests. */
    readonly apiKey: string;
    /** The header name for the API key (e.g. "x-api-key" for Anthropic, "x-goog-api-key" for Gemini). */
    readonly apiKeyHeader: string;
    /** Headers from the client request that should be forwarded upstream. */
    readonly forwardedHeaders: ReadonlyArray<string>;
}

/** Typed server configuration derived from environment variables. */
export interface ProxyConfig {
    /** Anthropic API key (undefined = Anthropic relay disabled). */
    readonly anthropicApiKey: string | undefined;
    /** Shared secret token for client authentication. */
    readonly proxyAuthToken: string;
    /** Server listen port. */
    readonly port: number;
    /** Server listen host. */
    readonly host: string;
    /** Pino log level. */
    readonly logLevel: string;
    /** Max requests per rate-limit window per IP. */
    readonly rateLimitMax: number;
    /** Rate-limit window duration in ms. */
    readonly rateLimitWindowMs: number;
    /** Max request body size in bytes. */
    readonly bodyLimit: number;
    /** CORS origin (empty string = disabled). */
    readonly corsOrigin: string;
    /** Upstream Anthropic base URL. */
    readonly anthropicBaseUrl: string;
    /** Upstream request timeout in ms. */
    readonly upstreamTimeoutMs: number;
    /** Gemini API key (undefined = Gemini relay disabled). */
    readonly geminiApiKey: string | undefined;
    /** Upstream Gemini base URL. */
    readonly geminiBaseUrl: string;
}

/** Headers forwarded to the Anthropic upstream API. */
export const ANTHROPIC_FORWARDED_HEADERS: ReadonlyArray<string> = [
    'anthropic-beta',
    'anthropic-version',
    'content-type',
    'accept',
    'x-request-id',
] as const;

/** Headers forwarded to the Gemini upstream API. */
export const GEMINI_FORWARDED_HEADERS: ReadonlyArray<string> = [
    'content-type',
    'accept',
    'x-request-id',
] as const;

/** Hop-by-hop headers that must be stripped before forwarding. */
export const HOP_BY_HOP_HEADERS: ReadonlyArray<string> = [
    'connection',          // Controls if the network connection stays open after the current transaction.
    'keep-alive',          // Settings for persistent connections.
    'transfer-encoding',   // Specifies the form of encoding used to safely transfer the payload.
    'upgrade',             // Mechanism for switching to a different protocol (e.g., WebSocket).
    'proxy-authorization', // Credentials for authenticating the client with a proxy.
    'te',                  // Specifies the transfer encodings the user agent is willing to accept.
    'trailer',             // Indicates that specific headers will be present in the trailer of a chunked message.
] as const;

/** Allowed Anthropic proxy route paths. */
export const ANTHROPIC_ROUTES = [
    '/v1/messages',
    '/v1/messages/count_tokens',
] as const;

export type AnthropicRoute = (typeof ANTHROPIC_ROUTES)[number];