@careob/llm-gateway 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ import type { GatewayConfig, ChatRequest, ChatResponse, StreamChunk } from './types.js';
2
+ export declare class LLMGateway {
3
+ private pool;
4
+ private config;
5
+ private providersByKey;
6
+ constructor(config: GatewayConfig);
7
+ /**
8
+ * Auto-discover keys from environment variables.
9
+ * Scans for OPENAI_API_KEY, ANTHROPIC_KEY, GEMINI_API_KEY_1, DEEPSEEK_KEY, etc.
10
+ */
11
+ static fromEnv(overrides?: Omit<GatewayConfig, 'keys'>, env?: Record<string, string | undefined>): LLMGateway;
12
+ chat(request: ChatRequest): Promise<ChatResponse>;
13
+ chatStream(request: ChatRequest): AsyncGenerator<StreamChunk, void, unknown>;
14
+ /** Get health/stats for all registered keys */
15
+ getStats(): {
16
+ provider: string;
17
+ label: string;
18
+ healthy: boolean;
19
+ requestsThisMinute: number;
20
+ totalRequests: number;
21
+ totalErrors: number;
22
+ cooldownUntil: number;
23
+ }[];
24
+ /** List all registered providers */
25
+ getProviders(): string[];
26
+ private registerKeys;
27
+ private resolveProviders;
28
+ private logUsage;
29
+ }
30
+ export type GatewayErrorCode = 'CONFIG_ERROR' | 'PROVIDER_ERROR' | 'NETWORK_ERROR' | 'TIMEOUT' | 'ALL_EXHAUSTED' | 'UNSUPPORTED';
31
+ export declare class GatewayError extends Error {
32
+ code: GatewayErrorCode;
33
+ statusCode?: number | undefined;
34
+ constructor(message: string, code: GatewayErrorCode, statusCode?: number | undefined);
35
+ }
36
+ //# sourceMappingURL=gateway.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../src/gateway.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,aAAa,EAEb,WAAW,EACX,YAAY,EACZ,WAAW,EAIZ,MAAM,YAAY,CAAC;AAEpB,qBAAa,UAAU;IACrB,OAAO,CAAC,IAAI,CAAU;IACtB,OAAO,CAAC,MAAM,CAAgF;IAC9F,OAAO,CAAC,cAAc,CAAkC;gBAE5C,MAAM,EAAE,aAAa;IAWjC;;;OAGG;IACH,MAAM,CAAC,OAAO,CACZ,SAAS,GAAE,IAAI,CAAC,aAAa,EAAE,MAAM,CAAM,EAC3C,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACvC,UAAU;IAWP,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAwEhD,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC;IAwFnF,+CAA+C;IAC/C,QAAQ;;;;;;;;;IAIR,oCAAoC;IACpC,YAAY;IAMZ,OAAO,CAAC,YAAY;IA8BpB,OAAO,CAAC,gBAAgB;IAqBxB,OAAO,CAAC,QAAQ;CAoCjB;AAED,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd,gBAAgB,GAChB,eAAe,GACf,SAAS,GACT,eAAe,GACf,aAAa,CAAC;AAElB,qBAAa,YAAa,SAAQ,KAAK;IAG5B,IAAI,EAAE,gBAAgB;IACtB,UAAU,CAAC,EAAE,MAAM;gBAF1B,OAAO,EAAE,MAAM,EACR,IAAI,EAAE,gBAAgB,EACtB,UAAU,CAAC,EAAE,MAAM,YAAA;CAK7B"}
@@ -0,0 +1,256 @@
1
+ import { KeyPool } from './key-pool.js';
2
+ import { PROVIDERS, detectProvider, discoverKeysFromEnv, findProviderForModel, buildRequest, parseResponse, parseStreamChunk, estimateCost, } from './registry.js';
3
+ export class LLMGateway {
4
+ pool;
5
+ config;
6
+ providersByKey = new Map();
7
+ constructor(config) {
8
+ this.config = {
9
+ ...config,
10
+ maxRetries: config.maxRetries ?? 3,
11
+ cooldownMs: config.cooldownMs ?? 60_000,
12
+ timeoutMs: config.timeoutMs ?? 30_000,
13
+ };
14
+ this.pool = new KeyPool(this.config.cooldownMs);
15
+ this.registerKeys(config.keys);
16
+ }
17
+ /**
18
+ * Auto-discover keys from environment variables.
19
+ * Scans for OPENAI_API_KEY, ANTHROPIC_KEY, GEMINI_API_KEY_1, DEEPSEEK_KEY, etc.
20
+ */
21
+ static fromEnv(overrides = {}, env) {
22
+ const discovered = discoverKeysFromEnv(env);
23
+ if (discovered.length === 0) {
24
+ throw new GatewayError('No API keys found in environment. Expected vars like OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, etc.', 'CONFIG_ERROR');
25
+ }
26
+ return new LLMGateway({
27
+ ...overrides,
28
+ keys: discovered.map((d) => ({ key: d.key, provider: d.provider, label: d.label })),
29
+ });
30
+ }
31
+ async chat(request) {
32
+ const model = request.model ?? this.config.defaultModel;
33
+ if (!model)
34
+ throw new GatewayError('No model specified and no defaultModel configured', 'CONFIG_ERROR');
35
+ const fullRequest = { ...request, model, stream: false };
36
+ const providers = this.resolveProviders(fullRequest);
37
+ let lastError = null;
38
+ let attempt = 0;
39
+ for (const providerDef of providers) {
40
+ for (let retry = 0; retry < this.config.maxRetries; retry++) {
41
+ const key = this.pool.getNextKey(providerDef.id);
42
+ if (!key)
43
+ break;
44
+ attempt++;
45
+ const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
46
+ const start = Date.now();
47
+ try {
48
+ const { url, init } = buildRequest(providerDef, fullRequest, key.key);
49
+ const controller = new AbortController();
50
+ const timeout = setTimeout(() => controller.abort(), this.config.timeoutMs);
51
+ init.signal = controller.signal;
52
+ const res = await fetch(url, init);
53
+ clearTimeout(timeout);
54
+ if (res.status === 429) {
55
+ this.pool.recordRateLimit(key);
56
+ this.logUsage(requestId, providerDef.id, key, model, start, 'rate_limited', undefined, 'Rate limited');
57
+ continue;
58
+ }
59
+ if (!res.ok) {
60
+ const errorText = await res.text().catch(() => `HTTP ${res.status}`);
61
+ this.pool.recordError(key);
62
+ lastError = new GatewayError(`${providerDef.label}: ${errorText}`, 'PROVIDER_ERROR', res.status);
63
+ this.logUsage(requestId, providerDef.id, key, model, start, 'error', undefined, errorText);
64
+ continue;
65
+ }
66
+ const data = await res.json();
67
+ const parsed = parseResponse(providerDef, data);
68
+ parsed._gateway = {
69
+ provider: providerDef.id,
70
+ keyLabel: key.label,
71
+ latencyMs: Date.now() - start,
72
+ attempt,
73
+ };
74
+ this.pool.recordSuccess(key, parsed.usage.total_tokens);
75
+ this.logUsage(requestId, providerDef.id, key, model, start, 'success', parsed.usage, undefined, request.metadata);
76
+ return parsed;
77
+ }
78
+ catch (err) {
79
+ const msg = err instanceof Error ? err.message : String(err);
80
+ this.pool.recordError(key);
81
+ if (msg.includes('abort')) {
82
+ lastError = new GatewayError(`${providerDef.label}: timeout`, 'TIMEOUT');
83
+ }
84
+ else {
85
+ lastError = err instanceof GatewayError ? err : new GatewayError(`${providerDef.label}: ${msg}`, 'NETWORK_ERROR');
86
+ }
87
+ this.logUsage(requestId, providerDef.id, key, model, start, 'error', undefined, msg);
88
+ }
89
+ }
90
+ this.config.onAllKeysExhausted?.(providerDef.id);
91
+ }
92
+ throw lastError ?? new GatewayError('All providers and keys exhausted', 'ALL_EXHAUSTED');
93
+ }
94
+ async *chatStream(request) {
95
+ const model = request.model ?? this.config.defaultModel;
96
+ if (!model)
97
+ throw new GatewayError('No model specified and no defaultModel configured', 'CONFIG_ERROR');
98
+ const fullRequest = { ...request, model, stream: true };
99
+ const providers = this.resolveProviders(fullRequest);
100
+ let lastError = null;
101
+ for (const providerDef of providers) {
102
+ if (providerDef.format !== 'openai') {
103
+ continue;
104
+ }
105
+ for (let retry = 0; retry < this.config.maxRetries; retry++) {
106
+ const key = this.pool.getNextKey(providerDef.id);
107
+ if (!key)
108
+ break;
109
+ const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
110
+ const start = Date.now();
111
+ try {
112
+ const { url, init } = buildRequest(providerDef, fullRequest, key.key);
113
+ const controller = new AbortController();
114
+ const timeout = setTimeout(() => controller.abort(), this.config.timeoutMs * 3);
115
+ init.signal = controller.signal;
116
+ const res = await fetch(url, init);
117
+ clearTimeout(timeout);
118
+ if (res.status === 429) {
119
+ this.pool.recordRateLimit(key);
120
+ continue;
121
+ }
122
+ if (!res.ok) {
123
+ this.pool.recordError(key);
124
+ lastError = new GatewayError(`${providerDef.label}: HTTP ${res.status}`, 'PROVIDER_ERROR', res.status);
125
+ continue;
126
+ }
127
+ if (!res.body)
128
+ throw new GatewayError('No response body for stream', 'PROVIDER_ERROR');
129
+ const reader = res.body.getReader();
130
+ const decoder = new TextDecoder();
131
+ let buffer = '';
132
+ let totalTokens = 0;
133
+ try {
134
+ while (true) {
135
+ const { done, value } = await reader.read();
136
+ if (done)
137
+ break;
138
+ buffer += decoder.decode(value, { stream: true });
139
+ const lines = buffer.split('\n');
140
+ buffer = lines.pop() ?? '';
141
+ for (const line of lines) {
142
+ const chunk = parseStreamChunk(line);
143
+ if (chunk) {
144
+ if (chunk.usage)
145
+ totalTokens = chunk.usage.total_tokens;
146
+ yield chunk;
147
+ }
148
+ }
149
+ }
150
+ }
151
+ finally {
152
+ reader.releaseLock();
153
+ }
154
+ this.pool.recordSuccess(key, totalTokens);
155
+ this.logUsage(requestId, providerDef.id, key, model, start, 'success', {
156
+ prompt_tokens: 0, completion_tokens: 0, total_tokens: totalTokens,
157
+ }, undefined, request.metadata);
158
+ return;
159
+ }
160
+ catch (err) {
161
+ if (err instanceof GatewayError)
162
+ throw err;
163
+ this.pool.recordError(key);
164
+ lastError = new GatewayError(`${providerDef.label}: ${err instanceof Error ? err.message : String(err)}`, 'NETWORK_ERROR');
165
+ }
166
+ }
167
+ }
168
+ throw lastError ?? new GatewayError('All providers exhausted for streaming', 'ALL_EXHAUSTED');
169
+ }
170
+ /** Get health/stats for all registered keys */
171
+ getStats() {
172
+ return this.pool.getStats();
173
+ }
174
+ /** List all registered providers */
175
+ getProviders() {
176
+ return this.pool.getProviders();
177
+ }
178
+ // ── Private ──────────────────────────────────────────────────
179
+ registerKeys(keys) {
180
+ let autoIndex = 0;
181
+ for (const input of keys) {
182
+ const normalized = typeof input === 'string' ? { key: input } : input;
183
+ const providerId = normalized.provider ?? detectProvider(normalized.key);
184
+ if (!providerId) {
185
+ throw new GatewayError(`Cannot auto-detect provider for key "${normalized.key.slice(0, 4)}****". ` +
186
+ `Pass { key, provider: "deepseek" } explicitly.`, 'CONFIG_ERROR');
187
+ }
188
+ const providerDef = PROVIDERS[providerId];
189
+ if (!providerDef) {
190
+ throw new GatewayError(`Unknown provider "${providerId}". Known: ${Object.keys(PROVIDERS).join(', ')}`, 'CONFIG_ERROR');
191
+ }
192
+ autoIndex++;
193
+ const label = normalized.label ?? `${providerId}-${autoIndex}`;
194
+ const rpm = normalized.rpm ?? providerDef.defaultRpm;
195
+ const tpm = normalized.tpm ?? 0;
196
+ this.pool.addKey(normalized.key, providerId, label, rpm, tpm);
197
+ this.providersByKey.set(normalized.key, providerDef);
198
+ }
199
+ }
200
+ resolveProviders(request) {
201
+ if (request.provider) {
202
+ const def = PROVIDERS[request.provider];
203
+ if (!def)
204
+ throw new GatewayError(`Provider "${request.provider}" not found`, 'CONFIG_ERROR');
205
+ return [def];
206
+ }
207
+ const registeredProviders = this.pool.getProviders();
208
+ const modelProvider = findProviderForModel(request.model);
209
+ if (modelProvider && registeredProviders.includes(modelProvider.id)) {
210
+ const others = registeredProviders
211
+ .filter((id) => id !== modelProvider.id)
212
+ .map((id) => PROVIDERS[id])
213
+ .filter(Boolean);
214
+ return [modelProvider, ...others];
215
+ }
216
+ return registeredProviders.map((id) => PROVIDERS[id]).filter(Boolean);
217
+ }
218
+ logUsage(requestId, provider, key, model, startMs, status, usage, error, metadata) {
219
+ if (!this.config.onUsage)
220
+ return;
221
+ const log = {
222
+ requestId,
223
+ provider,
224
+ keyLabel: key.label,
225
+ model,
226
+ promptTokens: usage?.prompt_tokens ?? 0,
227
+ completionTokens: usage?.completion_tokens ?? 0,
228
+ totalTokens: usage?.total_tokens ?? 0,
229
+ estimatedCostUsd: usage ? estimateCost(model, usage.prompt_tokens, usage.completion_tokens) : 0,
230
+ latencyMs: Date.now() - startMs,
231
+ status,
232
+ error,
233
+ metadata,
234
+ timestamp: new Date(),
235
+ };
236
+ try {
237
+ const result = this.config.onUsage(log);
238
+ if (result instanceof Promise)
239
+ result.catch(() => { });
240
+ }
241
+ catch {
242
+ // spend tracking should never crash the gateway
243
+ }
244
+ }
245
+ }
246
+ export class GatewayError extends Error {
247
+ code;
248
+ statusCode;
249
+ constructor(message, code, statusCode) {
250
+ super(message);
251
+ this.code = code;
252
+ this.statusCode = statusCode;
253
+ this.name = 'GatewayError';
254
+ }
255
+ }
256
+ //# sourceMappingURL=gateway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway.js","sourceRoot":"","sources":["../src/gateway.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export { LLMGateway, GatewayError } from './gateway.js';
2
+ export type { GatewayErrorCode } from './gateway.js';
3
+ export { KeyPool } from './key-pool.js';
4
+ export { createExpressProxy } from './middleware.js';
5
+ export type { ProxyOptions } from './middleware.js';
6
+ export { PROVIDERS, detectProvider, discoverKeysFromEnv, findProviderForModel, estimateCost, } from './registry.js';
7
+ export type { ProviderDef, ApiFormat, AuthStyle } from './registry.js';
8
+ export type { KeyInput, GatewayConfig, ChatMessage, ChatRequest, ChatResponse, StreamChunk, TokenUsage, UsageLog, KeyState, } from './types.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACxD,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EACL,SAAS,EACT,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACvE,YAAY,EACV,QAAQ,EACR,aAAa,EACb,WAAW,EACX,WAAW,EACX,YAAY,EACZ,WAAW,EACX,UAAU,EACV,QAAQ,EACR,QAAQ,GACT,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { LLMGateway, GatewayError } from './gateway.js';
2
+ export { KeyPool } from './key-pool.js';
3
+ export { createExpressProxy } from './middleware.js';
4
+ export { PROVIDERS, detectProvider, discoverKeysFromEnv, findProviderForModel, estimateCost, } from './registry.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAExD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,OAAO,EACL,SAAS,EACT,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,GACb,MAAM,eAAe,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { KeyState } from './types.js';
2
+ export declare class KeyPool {
3
+ private cooldownMs;
4
+ private keys;
5
+ private roundRobinIndex;
6
+ constructor(cooldownMs: number);
7
+ addKey(key: string, provider: string, label: string, rpm: number, tpm: number): void;
8
+ getNextKey(provider: string): KeyState | null;
9
+ recordSuccess(key: KeyState, tokens: number): void;
10
+ recordRateLimit(key: KeyState): void;
11
+ recordError(key: KeyState): void;
12
+ getProviders(): string[];
13
+ getStats(): {
14
+ provider: string;
15
+ label: string;
16
+ healthy: boolean;
17
+ requestsThisMinute: number;
18
+ totalRequests: number;
19
+ totalErrors: number;
20
+ cooldownUntil: number;
21
+ }[];
22
+ }
23
+ //# sourceMappingURL=key-pool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-pool.d.ts","sourceRoot":"","sources":["../src/key-pool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,qBAAa,OAAO;IAIN,OAAO,CAAC,UAAU;IAH9B,OAAO,CAAC,IAAI,CAAkB;IAC9B,OAAO,CAAC,eAAe,CAAK;gBAER,UAAU,EAAE,MAAM;IAEtC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAiBpF,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAgC7C,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAMlD,eAAe,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI;IAMpC,WAAW,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI;IAIhC,YAAY,IAAI,MAAM,EAAE;IAIxB,QAAQ;;;;;;;;;CAWT"}
@@ -0,0 +1,83 @@
1
+ export class KeyPool {
2
+ cooldownMs;
3
+ keys = [];
4
+ roundRobinIndex = 0;
5
+ constructor(cooldownMs) {
6
+ this.cooldownMs = cooldownMs;
7
+ }
8
+ addKey(key, provider, label, rpm, tpm) {
9
+ this.keys.push({
10
+ key,
11
+ provider,
12
+ label,
13
+ rpm,
14
+ tpm,
15
+ requestsThisMinute: 0,
16
+ tokensThisMinute: 0,
17
+ minuteStart: Date.now(),
18
+ cooldownUntil: 0,
19
+ totalRequests: 0,
20
+ totalErrors: 0,
21
+ healthy: true,
22
+ });
23
+ }
24
+ getNextKey(provider) {
25
+ const candidates = this.keys.filter((k) => k.provider === provider);
26
+ if (candidates.length === 0)
27
+ return null;
28
+ const now = Date.now();
29
+ const startIdx = this.roundRobinIndex % candidates.length;
30
+ for (let i = 0; i < candidates.length; i++) {
31
+ const idx = (startIdx + i) % candidates.length;
32
+ const key = candidates[idx];
33
+ if (now - key.minuteStart > 60_000) {
34
+ key.requestsThisMinute = 0;
35
+ key.tokensThisMinute = 0;
36
+ key.minuteStart = now;
37
+ }
38
+ if (key.cooldownUntil > now)
39
+ continue;
40
+ if (!key.healthy) {
41
+ if (key.cooldownUntil <= now)
42
+ key.healthy = true;
43
+ else
44
+ continue;
45
+ }
46
+ if (key.requestsThisMinute >= key.rpm)
47
+ continue;
48
+ if (key.tpm > 0 && key.tokensThisMinute >= key.tpm)
49
+ continue;
50
+ this.roundRobinIndex = idx + 1;
51
+ return key;
52
+ }
53
+ return null;
54
+ }
55
+ recordSuccess(key, tokens) {
56
+ key.requestsThisMinute++;
57
+ key.tokensThisMinute += tokens;
58
+ key.totalRequests++;
59
+ }
60
+ recordRateLimit(key) {
61
+ key.cooldownUntil = Date.now() + this.cooldownMs;
62
+ key.healthy = false;
63
+ key.totalErrors++;
64
+ }
65
+ recordError(key) {
66
+ key.totalErrors++;
67
+ }
68
+ getProviders() {
69
+ return [...new Set(this.keys.map((k) => k.provider))];
70
+ }
71
+ getStats() {
72
+ return this.keys.map((k) => ({
73
+ provider: k.provider,
74
+ label: k.label,
75
+ healthy: k.healthy && k.cooldownUntil <= Date.now(),
76
+ requestsThisMinute: k.requestsThisMinute,
77
+ totalRequests: k.totalRequests,
78
+ totalErrors: k.totalErrors,
79
+ cooldownUntil: k.cooldownUntil,
80
+ }));
81
+ }
82
+ }
83
+ //# sourceMappingURL=key-pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-pool.js","sourceRoot":"","sources":["../src/key-pool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { Request, Response } from 'express';
2
+ import { LLMGateway } from './gateway.js';
3
+ export interface ProxyOptions {
4
+ /** Optional auth check before proxying. Return true to allow. */
5
+ authorize?: (req: Request) => boolean | Promise<boolean>;
6
+ /** Extract metadata from request for spend tracking */
7
+ extractMetadata?: (req: Request) => Record<string, string>;
8
+ }
9
+ /**
10
+ * Returns Express route handlers you can mount on any route.
11
+ *
12
+ * Usage:
13
+ * const proxy = createExpressProxy(gateway);
14
+ * app.post('/llm/v1/chat/completions', proxy.chatCompletions);
15
+ * app.get('/llm/v1/health', proxy.health);
16
+ */
17
+ export declare function createExpressProxy(gateway: LLMGateway, options?: ProxyOptions): {
18
+ chatCompletions: (req: Request, res: Response) => Promise<void>;
19
+ health: (_req: Request, res: Response) => void;
20
+ };
21
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAGxD,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,uDAAuD;IACvD,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5D;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,GAAE,YAAiB;2BAC5C,OAAO,OAAO,QAAQ;mBAiEpC,OAAO,OAAO,QAAQ;EAU7C"}
@@ -0,0 +1,83 @@
1
+ import { GatewayError } from './gateway.js';
2
+ /**
3
+ * Returns Express route handlers you can mount on any route.
4
+ *
5
+ * Usage:
6
+ * const proxy = createExpressProxy(gateway);
7
+ * app.post('/llm/v1/chat/completions', proxy.chatCompletions);
8
+ * app.get('/llm/v1/health', proxy.health);
9
+ */
10
+ export function createExpressProxy(gateway, options = {}) {
11
+ const chatCompletions = async (req, res) => {
12
+ const body = req.body;
13
+ if (!body?.messages) {
14
+ res.status(400).json({ error: 'messages is required' });
15
+ return;
16
+ }
17
+ if (options.authorize) {
18
+ try {
19
+ const allowed = await options.authorize(req);
20
+ if (!allowed) {
21
+ res.status(401).json({ error: 'Unauthorized' });
22
+ return;
23
+ }
24
+ }
25
+ catch {
26
+ res.status(401).json({ error: 'Authorization failed' });
27
+ return;
28
+ }
29
+ }
30
+ const metadata = options.extractMetadata?.(req);
31
+ const request = {
32
+ model: body.model,
33
+ messages: body.messages,
34
+ temperature: body.temperature,
35
+ max_tokens: body.max_tokens,
36
+ top_p: body.top_p,
37
+ stream: body.stream,
38
+ tools: body.tools,
39
+ tool_choice: body.tool_choice,
40
+ response_format: body.response_format,
41
+ provider: body.provider,
42
+ metadata,
43
+ };
44
+ if (body.stream) {
45
+ res.setHeader('Content-Type', 'text/event-stream');
46
+ res.setHeader('Cache-Control', 'no-cache');
47
+ res.setHeader('Connection', 'keep-alive');
48
+ try {
49
+ for await (const chunk of gateway.chatStream(request)) {
50
+ res.write(`data: ${JSON.stringify(chunk)}\n\n`);
51
+ }
52
+ res.write('data: [DONE]\n\n');
53
+ res.end();
54
+ }
55
+ catch (err) {
56
+ const ge = err instanceof GatewayError ? err : new GatewayError(String(err), 'PROVIDER_ERROR');
57
+ res.write(`data: ${JSON.stringify({ error: ge.message, code: ge.code })}\n\n`);
58
+ res.end();
59
+ }
60
+ return;
61
+ }
62
+ try {
63
+ const response = await gateway.chat(request);
64
+ res.json(response);
65
+ }
66
+ catch (err) {
67
+ const ge = err instanceof GatewayError ? err : new GatewayError(String(err), 'PROVIDER_ERROR');
68
+ res.status(ge.statusCode ?? 502).json({
69
+ error: { message: ge.message, code: ge.code },
70
+ });
71
+ }
72
+ };
73
+ const health = (_req, res) => {
74
+ const stats = gateway.getStats();
75
+ const healthy = stats.some((s) => s.healthy);
76
+ res.status(healthy ? 200 : 503).json({
77
+ status: healthy ? 'healthy' : 'degraded',
78
+ keys: stats,
79
+ });
80
+ };
81
+ return { chatCompletions, health };
82
+ }
83
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { ChatRequest, ChatResponse, TokenUsage } from './types.js';
2
+ export type ApiFormat = 'openai' | 'anthropic' | 'gemini';
3
+ export type AuthStyle = 'bearer' | 'x-api-key' | 'query';
4
+ export interface ProviderDef {
5
+ id: string;
6
+ label: string;
7
+ baseUrl: string;
8
+ format: ApiFormat;
9
+ authStyle: AuthStyle;
10
+ extraHeaders?: Record<string, string>;
11
+ keyPatterns: RegExp[];
12
+ envPrefixes: string[];
13
+ models: string[];
14
+ defaultRpm: number;
15
+ costs: Record<string, {
16
+ prompt: number;
17
+ completion: number;
18
+ }>;
19
+ }
20
+ export declare const PROVIDERS: Record<string, ProviderDef>;
21
+ export declare function detectProvider(key: string): string | null;
22
+ export declare function discoverKeysFromEnv(env?: Record<string, string | undefined>): Array<{
23
+ key: string;
24
+ provider: string;
25
+ label: string;
26
+ }>;
27
+ export declare function buildRequest(provider: ProviderDef, request: ChatRequest, apiKey: string): {
28
+ url: string;
29
+ init: RequestInit;
30
+ };
31
+ export declare function parseResponse(provider: ProviderDef, data: unknown): ChatResponse;
32
+ export declare function parseStreamChunk(line: string): StreamChunkResult | null;
33
+ type StreamChunkResult = import('./types.js').StreamChunk & {
34
+ usage?: TokenUsage;
35
+ };
36
+ export declare function estimateCost(model: string, promptTokens: number, completionTokens: number): number;
37
+ export declare function findProviderForModel(model: string): ProviderDef | null;
38
+ export {};
39
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAMrF,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,CAAC;AAC1D,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,CAAC;AAIzD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,EAAE,SAAS,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/D;AAKD,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAuMjD,CAAC;AAIF,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQzD;AAED,wBAAgB,mBAAmB,CACjC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAqD,GAC1F,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAuBzD;AAKD,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GACb;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,CAyBpC;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,GAAG,YAAY,CAOhF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAUvE;AAED,KAAK,iBAAiB,GAAG,OAAO,YAAY,EAAE,WAAW,GAAG;IAAE,KAAK,CAAC,EAAE,UAAU,CAAA;CAAE,CAAC;AAInF,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM,CASlG;AAID,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAKtE"}
@@ -0,0 +1,413 @@
1
+ // ─── Provider Registry ────────────────────────────────────────
2
+ // To add a new provider: add one object here. That's it.
3
+ export const PROVIDERS = {
4
+ openai: {
5
+ id: 'openai',
6
+ label: 'OpenAI',
7
+ baseUrl: 'https://api.openai.com/v1',
8
+ format: 'openai',
9
+ authStyle: 'bearer',
10
+ keyPatterns: [/^sk-proj-/],
11
+ envPrefixes: ['OPENAI'],
12
+ models: ['gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'gpt-4', 'gpt-3.5-turbo', 'o1', 'o1-mini', 'o3-mini', 'o4-mini'],
13
+ defaultRpm: 500,
14
+ costs: {
15
+ 'gpt-4o': { prompt: 2.5, completion: 10 },
16
+ 'gpt-4o-mini': { prompt: 0.15, completion: 0.6 },
17
+ 'gpt-4-turbo': { prompt: 10, completion: 30 },
18
+ 'gpt-4': { prompt: 30, completion: 60 },
19
+ 'gpt-3.5-turbo': { prompt: 0.5, completion: 1.5 },
20
+ 'o1': { prompt: 15, completion: 60 },
21
+ 'o1-mini': { prompt: 3, completion: 12 },
22
+ 'o3-mini': { prompt: 1.1, completion: 4.4 },
23
+ 'o4-mini': { prompt: 1.1, completion: 4.4 },
24
+ },
25
+ },
26
+ anthropic: {
27
+ id: 'anthropic',
28
+ label: 'Anthropic',
29
+ baseUrl: 'https://api.anthropic.com/v1',
30
+ format: 'anthropic',
31
+ authStyle: 'x-api-key',
32
+ extraHeaders: { 'anthropic-version': '2023-06-01' },
33
+ keyPatterns: [/^sk-ant-/],
34
+ envPrefixes: ['ANTHROPIC', 'CLAUDE'],
35
+ models: ['claude-opus-4-20250514', 'claude-sonnet-4-20250514', 'claude-haiku-3-5-20241022'],
36
+ defaultRpm: 300,
37
+ costs: {
38
+ 'claude-opus-4-20250514': { prompt: 15, completion: 75 },
39
+ 'claude-sonnet-4-20250514': { prompt: 3, completion: 15 },
40
+ 'claude-haiku-3-5-20241022': { prompt: 0.8, completion: 4 },
41
+ },
42
+ },
43
+ gemini: {
44
+ id: 'gemini',
45
+ label: 'Google Gemini',
46
+ baseUrl: 'https://generativelanguage.googleapis.com/v1beta',
47
+ format: 'gemini',
48
+ authStyle: 'query',
49
+ keyPatterns: [/^AIza/],
50
+ envPrefixes: ['GEMINI', 'GOOGLE_AI'],
51
+ models: ['gemini-2.5-pro', 'gemini-2.5-flash', 'gemini-2.0-flash', 'gemini-1.5-pro', 'gemini-1.5-flash'],
52
+ defaultRpm: 360,
53
+ costs: {
54
+ 'gemini-2.5-pro': { prompt: 1.25, completion: 10 },
55
+ 'gemini-2.5-flash': { prompt: 0.15, completion: 0.6 },
56
+ 'gemini-2.0-flash': { prompt: 0.1, completion: 0.4 },
57
+ 'gemini-1.5-pro': { prompt: 1.25, completion: 5 },
58
+ 'gemini-1.5-flash': { prompt: 0.075, completion: 0.3 },
59
+ },
60
+ },
61
+ deepseek: {
62
+ id: 'deepseek',
63
+ label: 'DeepSeek',
64
+ baseUrl: 'https://api.deepseek.com/v1',
65
+ format: 'openai',
66
+ authStyle: 'bearer',
67
+ keyPatterns: [/^sk-[a-f0-9]{48}$/],
68
+ envPrefixes: ['DEEPSEEK'],
69
+ models: ['deepseek-chat', 'deepseek-coder', 'deepseek-reasoner'],
70
+ defaultRpm: 300,
71
+ costs: {
72
+ 'deepseek-chat': { prompt: 0.14, completion: 0.28 },
73
+ 'deepseek-coder': { prompt: 0.14, completion: 0.28 },
74
+ 'deepseek-reasoner': { prompt: 0.55, completion: 2.19 },
75
+ },
76
+ },
77
+ qwen: {
78
+ id: 'qwen',
79
+ label: 'Alibaba Qwen',
80
+ baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
81
+ format: 'openai',
82
+ authStyle: 'bearer',
83
+ keyPatterns: [],
84
+ envPrefixes: ['QWEN', 'DASHSCOPE', 'ALIBABA'],
85
+ models: ['qwen-turbo', 'qwen-plus', 'qwen-max', 'qwen-long', 'qwen-vl-plus', 'qwen-coder-turbo'],
86
+ defaultRpm: 300,
87
+ costs: {
88
+ 'qwen-turbo': { prompt: 0.08, completion: 0.16 },
89
+ 'qwen-plus': { prompt: 0.4, completion: 0.8 },
90
+ 'qwen-max': { prompt: 1.6, completion: 3.2 },
91
+ 'qwen-long': { prompt: 0.04, completion: 0.08 },
92
+ 'qwen-coder-turbo': { prompt: 0.15, completion: 0.3 },
93
+ },
94
+ },
95
+ zhipu: {
96
+ id: 'zhipu',
97
+ label: 'Zhipu GLM',
98
+ baseUrl: 'https://open.bigmodel.cn/api/paas/v4',
99
+ format: 'openai',
100
+ authStyle: 'bearer',
101
+ keyPatterns: [],
102
+ envPrefixes: ['ZHIPU', 'GLM', 'CHATGLM'],
103
+ models: ['glm-4', 'glm-4-flash', 'glm-4-plus', 'glm-4-long', 'glm-4v'],
104
+ defaultRpm: 300,
105
+ costs: {
106
+ 'glm-4': { prompt: 1.4, completion: 1.4 },
107
+ 'glm-4-flash': { prompt: 0.01, completion: 0.01 },
108
+ 'glm-4-plus': { prompt: 0.7, completion: 0.7 },
109
+ 'glm-4-long': { prompt: 0.14, completion: 0.14 },
110
+ },
111
+ },
112
+ moonshot: {
113
+ id: 'moonshot',
114
+ label: 'Moonshot Kimi',
115
+ baseUrl: 'https://api.moonshot.cn/v1',
116
+ format: 'openai',
117
+ authStyle: 'bearer',
118
+ keyPatterns: [],
119
+ envPrefixes: ['MOONSHOT', 'KIMI'],
120
+ models: ['moonshot-v1-8k', 'moonshot-v1-32k', 'moonshot-v1-128k'],
121
+ defaultRpm: 300,
122
+ costs: {
123
+ 'moonshot-v1-8k': { prompt: 0.15, completion: 0.15 },
124
+ 'moonshot-v1-32k': { prompt: 0.35, completion: 0.35 },
125
+ 'moonshot-v1-128k': { prompt: 0.85, completion: 0.85 },
126
+ },
127
+ },
128
+ yi: {
129
+ id: 'yi',
130
+ label: '01.AI Yi',
131
+ baseUrl: 'https://api.01.ai/v1',
132
+ format: 'openai',
133
+ authStyle: 'bearer',
134
+ keyPatterns: [],
135
+ envPrefixes: ['YI', 'LINGYIWANWU'],
136
+ models: ['yi-large', 'yi-medium', 'yi-spark', 'yi-large-turbo'],
137
+ defaultRpm: 300,
138
+ costs: {
139
+ 'yi-large': { prompt: 2.5, completion: 2.5 },
140
+ 'yi-medium': { prompt: 0.36, completion: 0.36 },
141
+ 'yi-spark': { prompt: 0.12, completion: 0.12 },
142
+ 'yi-large-turbo': { prompt: 1.7, completion: 1.7 },
143
+ },
144
+ },
145
+ groq: {
146
+ id: 'groq',
147
+ label: 'Groq',
148
+ baseUrl: 'https://api.groq.com/openai/v1',
149
+ format: 'openai',
150
+ authStyle: 'bearer',
151
+ keyPatterns: [/^gsk_/],
152
+ envPrefixes: ['GROQ'],
153
+ models: ['llama-3.3-70b-versatile', 'llama-3.1-8b-instant', 'mixtral-8x7b-32768', 'gemma2-9b-it'],
154
+ defaultRpm: 30,
155
+ costs: {
156
+ 'llama-3.3-70b-versatile': { prompt: 0.59, completion: 0.79 },
157
+ 'llama-3.1-8b-instant': { prompt: 0.05, completion: 0.08 },
158
+ 'mixtral-8x7b-32768': { prompt: 0.24, completion: 0.24 },
159
+ },
160
+ },
161
+ together: {
162
+ id: 'together',
163
+ label: 'Together AI',
164
+ baseUrl: 'https://api.together.xyz/v1',
165
+ format: 'openai',
166
+ authStyle: 'bearer',
167
+ keyPatterns: [],
168
+ envPrefixes: ['TOGETHER'],
169
+ models: ['meta-llama/Llama-3.3-70B-Instruct-Turbo', 'Qwen/Qwen2.5-72B-Instruct-Turbo', 'deepseek-ai/DeepSeek-R1'],
170
+ defaultRpm: 300,
171
+ costs: {
172
+ 'meta-llama/Llama-3.3-70B-Instruct-Turbo': { prompt: 0.88, completion: 0.88 },
173
+ 'deepseek-ai/DeepSeek-R1': { prompt: 3.0, completion: 7.0 },
174
+ },
175
+ },
176
+ mistral: {
177
+ id: 'mistral',
178
+ label: 'Mistral AI',
179
+ baseUrl: 'https://api.mistral.ai/v1',
180
+ format: 'openai',
181
+ authStyle: 'bearer',
182
+ keyPatterns: [],
183
+ envPrefixes: ['MISTRAL'],
184
+ models: ['mistral-large-latest', 'mistral-small-latest', 'codestral-latest', 'open-mistral-nemo'],
185
+ defaultRpm: 300,
186
+ costs: {
187
+ 'mistral-large-latest': { prompt: 2, completion: 6 },
188
+ 'mistral-small-latest': { prompt: 0.1, completion: 0.3 },
189
+ 'codestral-latest': { prompt: 0.3, completion: 0.9 },
190
+ },
191
+ },
192
+ };
193
+ // ─── Auto-Detection ────────────────────────────────────────────
194
+ export function detectProvider(key) {
195
+ for (const [id, def] of Object.entries(PROVIDERS)) {
196
+ for (const pattern of def.keyPatterns) {
197
+ if (pattern.test(key))
198
+ return id;
199
+ }
200
+ }
201
+ if (/^sk-/.test(key))
202
+ return 'openai';
203
+ return null;
204
+ }
205
+ export function discoverKeysFromEnv(env = process.env) {
206
+ const found = [];
207
+ for (const [envName, value] of Object.entries(env)) {
208
+ if (!value || value.length < 8)
209
+ continue;
210
+ for (const [providerId, def] of Object.entries(PROVIDERS)) {
211
+ for (const prefix of def.envPrefixes) {
212
+ const pattern = new RegExp(`^${prefix}_(?:API_)?KEY(?:_(\\d+))?$`, 'i');
213
+ const match = envName.match(pattern);
214
+ if (match) {
215
+ const suffix = match[1] ? `-${match[1]}` : '';
216
+ found.push({
217
+ key: value,
218
+ provider: providerId,
219
+ label: `${providerId}${suffix}`,
220
+ });
221
+ }
222
+ }
223
+ }
224
+ }
225
+ return found;
226
+ }
227
+ // ─── Request Building (Dynamic) ────────────────────────────────
228
+ // 3 format functions handle all 11+ providers.
229
+ export function buildRequest(provider, request, apiKey) {
230
+ const headers = buildAuthHeaders(provider, apiKey);
231
+ const FORMATS = {
232
+ openai: () => ({
233
+ url: `${provider.baseUrl}/chat/completions`,
234
+ body: buildOpenAIBody(request),
235
+ }),
236
+ anthropic: () => ({
237
+ url: `${provider.baseUrl}/messages`,
238
+ body: buildAnthropicBody(request),
239
+ }),
240
+ gemini: () => {
241
+ const endpoint = request.stream ? 'streamGenerateContent' : 'generateContent';
242
+ return {
243
+ url: `${provider.baseUrl}/models/${request.model}:${endpoint}?key=${apiKey}`,
244
+ body: buildGeminiBody(request),
245
+ };
246
+ },
247
+ };
248
+ const { url, body } = FORMATS[provider.format]();
249
+ return {
250
+ url,
251
+ init: { method: 'POST', headers, body: JSON.stringify(body) },
252
+ };
253
+ }
254
+ export function parseResponse(provider, data) {
255
+ const PARSERS = {
256
+ openai: parseOpenAIFormat,
257
+ anthropic: parseAnthropicFormat,
258
+ gemini: parseGeminiFormat,
259
+ };
260
+ return PARSERS[provider.format](data);
261
+ }
262
+ export function parseStreamChunk(line) {
263
+ const trimmed = line.trim();
264
+ if (!trimmed.startsWith('data: '))
265
+ return null;
266
+ const payload = trimmed.slice(6);
267
+ if (payload === '[DONE]')
268
+ return null;
269
+ try {
270
+ return JSON.parse(payload);
271
+ }
272
+ catch {
273
+ return null;
274
+ }
275
+ }
276
+ // ─── Cost Estimation ──────────────────────────────────────────
277
+ export function estimateCost(model, promptTokens, completionTokens) {
278
+ for (const def of Object.values(PROVIDERS)) {
279
+ const costs = def.costs[model];
280
+ if (costs) {
281
+ return (promptTokens / 1_000_000) * costs.prompt
282
+ + (completionTokens / 1_000_000) * costs.completion;
283
+ }
284
+ }
285
+ return 0;
286
+ }
287
+ // ─── Resolve model → provider ─────────────────────────────────
288
+ export function findProviderForModel(model) {
289
+ for (const def of Object.values(PROVIDERS)) {
290
+ if (def.models.includes(model))
291
+ return def;
292
+ }
293
+ return null;
294
+ }
295
+ // ─── Shared Internals ─────────────────────────────────────────
296
+ function buildAuthHeaders(provider, apiKey) {
297
+ const headers = { 'Content-Type': 'application/json' };
298
+ const AUTH = {
299
+ bearer: () => { headers['Authorization'] = `Bearer ${apiKey}`; },
300
+ 'x-api-key': () => { headers['x-api-key'] = apiKey; },
301
+ query: () => { },
302
+ };
303
+ AUTH[provider.authStyle]();
304
+ if (provider.extraHeaders)
305
+ Object.assign(headers, provider.extraHeaders);
306
+ return headers;
307
+ }
308
+ function splitSystemMessages(messages) {
309
+ let system;
310
+ const rest = [];
311
+ for (const msg of messages) {
312
+ if (msg.role === 'system')
313
+ system = (system ? system + '\n' : '') + msg.content;
314
+ else
315
+ rest.push({ role: msg.role, content: msg.content });
316
+ }
317
+ return { system, rest };
318
+ }
319
+ function buildOpenAIBody(req) {
320
+ const body = { model: req.model, messages: req.messages };
321
+ if (req.temperature !== undefined)
322
+ body.temperature = req.temperature;
323
+ if (req.max_tokens !== undefined)
324
+ body.max_tokens = req.max_tokens;
325
+ if (req.top_p !== undefined)
326
+ body.top_p = req.top_p;
327
+ if (req.stream !== undefined)
328
+ body.stream = req.stream;
329
+ if (req.tools)
330
+ body.tools = req.tools;
331
+ if (req.tool_choice !== undefined)
332
+ body.tool_choice = req.tool_choice;
333
+ if (req.response_format)
334
+ body.response_format = req.response_format;
335
+ if (req.stream)
336
+ body.stream_options = { include_usage: true };
337
+ return body;
338
+ }
339
+ function buildAnthropicBody(req) {
340
+ const { system, rest } = splitSystemMessages(req.messages);
341
+ const body = { model: req.model, messages: rest, max_tokens: req.max_tokens ?? 4096 };
342
+ if (system)
343
+ body.system = system;
344
+ if (req.temperature !== undefined)
345
+ body.temperature = req.temperature;
346
+ if (req.top_p !== undefined)
347
+ body.top_p = req.top_p;
348
+ if (req.stream !== undefined)
349
+ body.stream = req.stream;
350
+ return body;
351
+ }
352
+ function buildGeminiBody(req) {
353
+ const contents = [];
354
+ let systemText;
355
+ for (const msg of req.messages) {
356
+ if (msg.role === 'system')
357
+ systemText = (systemText ? systemText + '\n' : '') + msg.content;
358
+ else
359
+ contents.push({ role: msg.role === 'assistant' ? 'model' : 'user', parts: [{ text: msg.content }] });
360
+ }
361
+ const body = { contents };
362
+ if (systemText)
363
+ body.systemInstruction = { parts: [{ text: systemText }] };
364
+ const genConfig = {};
365
+ if (req.temperature !== undefined)
366
+ genConfig.temperature = req.temperature;
367
+ if (req.max_tokens !== undefined)
368
+ genConfig.maxOutputTokens = req.max_tokens;
369
+ if (req.top_p !== undefined)
370
+ genConfig.topP = req.top_p;
371
+ if (Object.keys(genConfig).length > 0)
372
+ body.generationConfig = genConfig;
373
+ return body;
374
+ }
375
+ function parseOpenAIFormat(data) {
376
+ const raw = data;
377
+ const usage = (raw.usage ?? { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 });
378
+ return {
379
+ id: raw.id ?? `gen-${Date.now()}`,
380
+ object: raw.object ?? 'chat.completion',
381
+ model: raw.model,
382
+ choices: raw.choices,
383
+ usage,
384
+ _gateway: { provider: '', keyLabel: '', latencyMs: 0, attempt: 0 },
385
+ };
386
+ }
387
+ function parseAnthropicFormat(data) {
388
+ const raw = data;
389
+ const text = raw.content.filter((c) => c.type === 'text').map((c) => c.text).join('');
390
+ return {
391
+ id: raw.id,
392
+ object: 'chat.completion',
393
+ model: raw.model,
394
+ choices: [{ index: 0, message: { role: 'assistant', content: text }, finish_reason: raw.stop_reason === 'end_turn' ? 'stop' : raw.stop_reason }],
395
+ usage: { prompt_tokens: raw.usage.input_tokens, completion_tokens: raw.usage.output_tokens, total_tokens: raw.usage.input_tokens + raw.usage.output_tokens },
396
+ _gateway: { provider: '', keyLabel: '', latencyMs: 0, attempt: 0 },
397
+ };
398
+ }
399
+ function parseGeminiFormat(data) {
400
+ const raw = data;
401
+ const candidate = raw.candidates?.[0];
402
+ const text = candidate?.content?.parts?.map((p) => p.text).join('') ?? '';
403
+ const meta = raw.usageMetadata;
404
+ return {
405
+ id: `gemini-${Date.now()}`,
406
+ object: 'chat.completion',
407
+ model: 'gemini',
408
+ choices: [{ index: 0, message: { role: 'assistant', content: text }, finish_reason: candidate?.finishReason === 'STOP' ? 'stop' : (candidate?.finishReason ?? 'stop') }],
409
+ usage: { prompt_tokens: meta?.promptTokenCount ?? 0, completion_tokens: meta?.candidatesTokenCount ?? 0, total_tokens: meta?.totalTokenCount ?? 0 },
410
+ _gateway: { provider: '', keyLabel: '', latencyMs: 0, attempt: 0 },
411
+ };
412
+ }
413
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAyBA,iEAAiE;AACjE,yDAAyD;AAEzD,MAAM,CAAC,MAAM,SAAS,GAAgC;IACpD,MAAM,EAAE;QACN,EAAE,EAAE,QAAQ;QACZ,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,2BAA2B;QACpC,MAAM,EAAE,QAAQ;QAChB,SAAS,EAAE,QAAQ;QACnB,WAAW,EAAE,CAAC,WAAW,CAAC;QAC1B,WAAW,EAAE,CAAC,QAAQ,CAAC;QACvB,MAAM,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC;QACjH,UAAU,EAAE,GAAG;QACf,KAAK,EAAE;YACL,QAAQ,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE;YACzC,aAAa,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE;YAChD,aAAa,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;YAC7C,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;YACvC,eAAe,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;YACjD,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;YACpC,SAAS,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE;YACxC,SAAS,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;YAC3C,SAAS,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;SAC5C;KACF;IAED,SAAS,EAAE;QACT,EAAE,EAAE,WAAW;QACf,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,8BAA8B;QACvC,MAAM,EAAE,WAAW;QACnB,SAAS,EAAE,WAAW;QACtB,YAAY,EAAE,EAAE,mBAAmB,EAAE,YAAY,EAAE;QACnD,WAAW,EAAE,CAAC,UAAU,CAAC;QACzB,WAAW,EAAE,CAAC,WAAW,EAAE,QAAQ,CAAC;QACpC,MAAM,EAAE,CAAC,wBAAwB,EAAE,0BAA0B,EAAE,2BAA2B,CAAC;QAC3F,UAAU,EAAE,GAAG;QACf,KAAK,EAAE;YACL,wBAAwB,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;YACxD,0BAA0B,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE;YACzD,2BAA2B,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE;SAC5D;KACF;IAED,MAAM,EAAE;QACN,EAAE,EAAE,QAAQ;QACZ,KAAK,EAAE,eAAe;QACtB,OAAO,EAAE,kDAAkD;QAC3D,MAAM,EAAE,QAAQ;QAChB,SAAS,EAAE,OAAO;QAClB,WAAW,EAAE,CAAC,OAAO,CAAC;QACtB,WAAW,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC;QACpC,MAAM,EAAE,CAAC,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,kBAAkB,CAAC;QACxG,UAAU,EAAE,GAAG;QACf,KAAK,EAAE;YACL,gBAAgB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE;YAClD,kBAAkB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE;YACrD,kBAAkB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;YACpD,gBAAgB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE;YACjD,kBAAkB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE;SACvD;KACF;IAED,QAAQ,EAAE;QACR,EAAE,EAAE,UAAU;QACd,KAAK,EAAE,UAAU;QACjB,OAAO,EAAE,6BAA6B;QACtC,MAAM,EAAE,QAAQ;QAChB,SAAS,EAAE,QAAQ;QACnB,WAAW,EAAE,CAAC,mBAAmB,CAAC;QAClC,WAAW,EAAE,CAAC,UAAU,CAAC;QACzB,MAAM,EAAE,CAAC,eAAe,EAAE,gBAAgB,EAAE,mBAAmB,CAAC;QAChE,UAAU,EAAE,GAAG;QACf,KAAK,EAAE;YACL,eAAe,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;YACnD,gBAAgB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;YACpD,mBAAmB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;SACxD;KACF;IAED,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM;QACV,KAAK,EAAE,cAAc;QACrB,OAAO,EAAE,mDAAmD;QAC5D,MAAM,EAAE,QAAQ;QAChB,SAAS,EAAE,QAAQ;QACnB,WAAW,EAAE,EAAE;QACf,WAAW,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,CAAC;QAC7C,MAAM,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,kBAAkB,CAAC;QAChG,UAAU,EAAE,GAAG;QACf,KAAK,EAAE;YACL,YAAY,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;YAChD,WAAW,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;YAC7C,UAAU,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;YAC5C,WAAW,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;YAC/C,kBAAkB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE;SACtD;KACF;IAED,KAAK,EAAE;QACL,EAAE,EAAE,OAAO;QACX,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,sCAAsC;QAC/C,MAAM,EAAE,QAAQ;QAChB,SAAS,EAAE,QAAQ;QACnB,WAAW,EAAE,EAAE;QACf,WAAW,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,SAAS,CAAC;QACxC,MAAM,EAAE,CAAC,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,CAAC;QACtE,UAAU,EAAE,GAAG;QACf,KAAK,EAAE;YACL,OAAO,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;YACzC,aAAa,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;YACjD,YAAY,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;YAC9C,YAAY,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;SACjD;KACF;IAED,QAAQ,EAAE;QACR,EAAE,EAAE,UAAU;QACd,KAAK,EAAE,eAAe;QACtB,OAAO,EAAE,4BAA4B;QACrC,MAAM,EAAE,QAAQ;QAChB,SAAS,EAAE,QAAQ;QACnB,WAAW,EAAE,EAAE;QACf,WAAW,EAAE,CAAC,UAAU,EAAE,MAAM,CAAC;QACjC,MAAM,EAAE,CAAC,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,CAAC;QACjE,UAAU,EAAE,GAAG;QACf,KAAK,EAAE;YACL,gBAAgB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;YACpD,iBAAiB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;YACrD,kBAAkB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;SACvD;KACF;IAED,EAAE,EAAE;QACF,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,UAAU;QACjB,OAAO,EAAE,sBAAsB;QAC/B,MAAM,EAAE,QAAQ;QAChB,SAAS,EAAE,QAAQ;QACnB,WAAW,EAAE,EAAE;QACf,WAAW,EAAE,CAAC,IAAI,EAAE,aAAa,CAAC;QAClC,MAAM,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,CAAC;QAC/D,UAAU,EAAE,GAAG;QACf,KAAK,EAAE;YACL,UAAU,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;YAC5C,WAAW,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;YAC/C,UAAU,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;YAC9C,gBAAgB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;SACnD;KACF;IAED,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM;QACV,KAAK,EAAE,MAAM;QACb,OAAO,EAAE,gCAAgC;QACzC,MAAM,EAAE,QAAQ;QAChB,SAAS,EAAE,QAAQ;QACnB,WAAW,EAAE,CAAC,OAAO,CAAC;QACtB,WAAW,EAAE,CAAC,MAAM,CAAC;QACrB,MAAM,EAAE,CAAC,yBAAyB,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,cAAc,CAAC;QACjG,UAAU,EAAE,EAAE;QACd,KAAK,EAAE;YACL,yBAAyB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;YAC7D,sBAAsB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;YAC1D,oBAAoB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;SACzD;KACF;IAED,QAAQ,EAAE;QACR,EAAE,EAAE,UAAU;QACd,KAAK,EAAE,aAAa;QACpB,OAAO,EAAE,6BAA6B;QACtC,MAAM,EAAE,QAAQ;QAChB,SAAS,EAAE,QAAQ;QACnB,WAAW,EAAE,EAAE;QACf,WAAW,EAAE,CAAC,UAAU,CAAC;QACzB,MAAM,EAAE,CAAC,yCAAyC,EAAE,iCAAiC,EAAE,yBAAyB,CAAC;QACjH,UAAU,EAAE,GAAG;QACf,KAAK,EAAE;YACL,yCAAyC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;YAC7E,yBAAyB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;SAC5D;KACF;IAED,OAAO,EAAE;QACP,EAAE,EAAE,SAAS;QACb,KAAK,EAAE,YAAY;QACnB,OAAO,EAAE,2BAA2B;QACpC,MAAM,EAAE,QAAQ;QAChB,SAAS,EAAE,QAAQ;QACnB,WAAW,EAAE,EAAE;QACf,WAAW,EAAE,CAAC,SAAS,CAAC;QACxB,MAAM,EAAE,CAAC,sBAAsB,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,mBAAmB,CAAC;QACjG,UAAU,EAAE,GAAG;QACf,KAAK,EAAE;YACL,sBAAsB,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE;YACpD,sBAAsB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;YACxD,kBAAkB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;SACrD;KACF;CACF,CAAC;AAEF,kEAAkE;AAElE,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAClD,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;YACtC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;gBAAE,OAAO,EAAE,CAAC;QACnC,CAAC;IACH,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IACtC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,MAA0C,OAAO,CAAC,GAAyC;IAE3F,MAAM,KAAK,GAA4D,EAAE,CAAC;IAE1E,KAAK,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACnD,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QAEzC,KAAK,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1D,KAAK,MAAM,MAAM,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;gBACrC,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,IAAI,MAAM,4BAA4B,EAAE,GAAG,CAAC,CAAC;gBACxE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACrC,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC9C,KAAK,CAAC,IAAI,CAAC;wBACT,GAAG,EAAE,KAAK;wBACV,QAAQ,EAAE,UAAU;wBACpB,KAAK,EAAE,GAAG,UAAU,GAAG,MAAM,EAAE;qBAChC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,kEAAkE;AAClE,+CAA+C;AAE/C,MAAM,UAAU,YAAY,CAC1B,QAAqB,EACrB,OAAoB,EACpB,MAAc;IAEd,MAAM,OAAO,GAAG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACnD,MAAM,OAAO,GAA4E;QACvF,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;YACb,GAAG,EAAE,GAAG,QAAQ,CAAC,OAAO,mBAAmB;YAC3C,IAAI,EAAE,eAAe,CAAC,OAAO,CAAC;SAC/B,CAAC;QACF,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;YAChB,GAAG,EAAE,GAAG,QAAQ,CAAC,OAAO,WAAW;YACnC,IAAI,EAAE,kBAAkB,CAAC,OAAO,CAAC;SAClC,CAAC;QACF,MAAM,EAAE,GAAG,EAAE;YACX,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,iBAAiB,CAAC;YAC9E,OAAO;gBACL,GAAG,EAAE,GAAG,QAAQ,CAAC,OAAO,WAAW,OAAO,CAAC,KAAK,IAAI,QAAQ,QAAQ,MAAM,EAAE;gBAC5E,IAAI,EAAE,eAAe,CAAC,OAAO,CAAC;aAC/B,CAAC;QACJ,CAAC;KACF,CAAC;IAEF,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;IACjD,OAAO;QACL,GAAG;QACH,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAiB;KAC7E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAqB,EAAE,IAAa;IAChE,MAAM,OAAO,GAAoD;QAC/D,MAAM,EAAE,iBAAiB;QACzB,SAAS,EAAE,oBAAoB;QAC/B,MAAM,EAAE,iBAAiB;KAC1B,CAAC;IACF,OAAO,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACjC,IAAI,OAAO,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAsB,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAID,iEAAiE;AAEjE,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,YAAoB,EAAE,gBAAwB;IACxF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC,MAAM;kBAC5C,CAAC,gBAAgB,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC;QACxD,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,iEAAiE;AAEjE,MAAM,UAAU,oBAAoB,CAAC,KAAa;IAChD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3C,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,GAAG,CAAC;IAC7C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,iEAAiE;AAEjE,SAAS,gBAAgB,CAAC,QAAqB,EAAE,MAAc;IAC7D,MAAM,OAAO,GAA2B,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;IAC/E,MAAM,IAAI,GAAkC;QAC1C,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,MAAM,EAAE,CAAC,CAAC,CAAC;QAChE,WAAW,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;QACrD,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC;KAChB,CAAC;IACF,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;IAC3B,IAAI,QAAQ,CAAC,YAAY;QAAE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;IACzE,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,mBAAmB,CAAC,QAAuB;IAClD,IAAI,MAA0B,CAAC;IAC/B,MAAM,IAAI,GAA6C,EAAE,CAAC;IAC1D,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC;;YAC3E,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED,SAAS,eAAe,CAAC,GAAgB;IACvC,MAAM,IAAI,GAA4B,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;IACnF,IAAI,GAAG,CAAC,WAAW,KAAK,SAAS;QAAE,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC;IACtE,IAAI,GAAG,CAAC,UAAU,KAAK,SAAS;QAAE,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC,UAAU,CAAC;IACnE,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;IACpD,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;QAAE,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IACvD,IAAI,GAAG,CAAC,KAAK;QAAE,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;IACtC,IAAI,GAAG,CAAC,WAAW,KAAK,SAAS;QAAE,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC;IACtE,IAAI,GAAG,CAAC,eAAe;QAAE,IAAI,CAAC,eAAe,GAAG,GAAG,CAAC,eAAe,CAAC;IACpE,IAAI,GAAG,CAAC,MAAM;QAAE,IAAI,CAAC,cAAc,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;IAC9D,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAgB;IAC1C,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC3D,MAAM,IAAI,GAA4B,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC;IAC/G,IAAI,MAAM;QAAE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACjC,IAAI,GAAG,CAAC,WAAW,KAAK,SAAS;QAAE,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC;IACtE,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;IACpD,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;QAAE,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IACvD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,eAAe,CAAC,GAAgB;IACvC,MAAM,QAAQ,GAA4D,EAAE,CAAC;IAC7E,IAAI,UAA8B,CAAC;IACnC,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC/B,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ;YAAE,UAAU,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC;;YACvF,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5G,CAAC;IACD,MAAM,IAAI,GAA4B,EAAE,QAAQ,EAAE,CAAC;IACnD,IAAI,UAAU;QAAE,IAAI,CAAC,iBAAiB,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;IAC3E,MAAM,SAAS,GAA4B,EAAE,CAAC;IAC9C,IAAI,GAAG,CAAC,WAAW,KAAK,SAAS;QAAE,SAAS,CAAC,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC;IAC3E,IAAI,GAAG,CAAC,UAAU,KAAK,SAAS;QAAE,SAAS,CAAC,eAAe,GAAG,GAAG,CAAC,UAAU,CAAC;IAC7E,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS;QAAE,SAAS,CAAC,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC;IACxD,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;IACzE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAa;IACtC,MAAM,GAAG,GAAG,IAA+B,CAAC;IAC5C,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,aAAa,EAAE,CAAC,EAAE,iBAAiB,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAe,CAAC;IACvG,OAAO;QACL,EAAE,EAAG,GAAG,CAAC,EAAa,IAAI,OAAO,IAAI,CAAC,GAAG,EAAE,EAAE;QAC7C,MAAM,EAAG,GAAG,CAAC,MAAiB,IAAI,iBAAiB;QACnD,KAAK,EAAE,GAAG,CAAC,KAAe;QAC1B,OAAO,EAAE,GAAG,CAAC,OAAkC;QAC/C,KAAK;QACL,QAAQ,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;KACnE,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAAC,IAAa;IACzC,MAAM,GAAG,GAAG,IAMX,CAAC;IACF,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtF,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,MAAM,EAAE,iBAAiB;QACzB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,aAAa,EAAE,GAAG,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;QAChJ,KAAK,EAAE,EAAE,aAAa,EAAE,GAAG,CAAC,KAAK,CAAC,YAAY,EAAE,iBAAiB,EAAE,GAAG,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,EAAE,GAAG,CAAC,KAAK,CAAC,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,aAAa,EAAE;QAC5J,QAAQ,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;KACnE,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAa;IACtC,MAAM,GAAG,GAAG,IAGX,CAAC;IACF,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;IAC1E,MAAM,IAAI,GAAG,GAAG,CAAC,aAAa,CAAC;IAC/B,OAAO;QACL,EAAE,EAAE,UAAU,IAAI,CAAC,GAAG,EAAE,EAAE;QAC1B,MAAM,EAAE,iBAAiB;QACzB,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,YAAY,IAAI,MAAM,CAAC,EAAE,CAAC;QACxK,KAAK,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,gBAAgB,IAAI,CAAC,EAAE,iBAAiB,EAAE,IAAI,EAAE,oBAAoB,IAAI,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,IAAI,CAAC,EAAE;QACnJ,QAAQ,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;KACnE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,112 @@
1
+ export interface KeyInput {
2
+ key: string;
3
+ /** Provider name — auto-detected from key prefix if omitted */
4
+ provider?: string;
5
+ /** Requests per minute limit. Default: from provider registry */
6
+ rpm?: number;
7
+ /** Tokens per minute limit. Optional */
8
+ tpm?: number;
9
+ /** Human label (e.g. "prod-key-1"). Auto-generated if omitted */
10
+ label?: string;
11
+ }
12
+ export interface GatewayConfig {
13
+ /** API keys — strings auto-detect provider; objects allow explicit control */
14
+ keys: Array<string | KeyInput>;
15
+ /** Default model to use when not specified in request */
16
+ defaultModel?: string;
17
+ /** Retries across keys before failing. Default: 3 */
18
+ maxRetries?: number;
19
+ /** Cooldown ms for a rate-limited key. Default: 60000 */
20
+ cooldownMs?: number;
21
+ /** Request timeout ms. Default: 30000 */
22
+ timeoutMs?: number;
23
+ /** Called after every LLM request for logging/tracking */
24
+ onUsage?: (log: UsageLog) => void | Promise<void>;
25
+ /** Called when all keys for a provider are exhausted */
26
+ onAllKeysExhausted?: (provider: string) => void;
27
+ }
28
+ export interface ChatMessage {
29
+ role: 'system' | 'user' | 'assistant' | 'tool';
30
+ content: string;
31
+ name?: string;
32
+ tool_call_id?: string;
33
+ tool_calls?: unknown[];
34
+ }
35
+ export interface ChatRequest {
36
+ model?: string;
37
+ messages: ChatMessage[];
38
+ temperature?: number;
39
+ max_tokens?: number;
40
+ top_p?: number;
41
+ stream?: boolean;
42
+ tools?: unknown[];
43
+ tool_choice?: unknown;
44
+ response_format?: unknown;
45
+ /** Force a specific provider by name */
46
+ provider?: string;
47
+ /** Metadata for spend tracking */
48
+ metadata?: Record<string, string>;
49
+ }
50
+ export interface ChatChoice {
51
+ index: number;
52
+ message: ChatMessage;
53
+ finish_reason: string | null;
54
+ }
55
+ export interface TokenUsage {
56
+ prompt_tokens: number;
57
+ completion_tokens: number;
58
+ total_tokens: number;
59
+ }
60
+ export interface ChatResponse {
61
+ id: string;
62
+ object: string;
63
+ model: string;
64
+ choices: ChatChoice[];
65
+ usage: TokenUsage;
66
+ _gateway: {
67
+ provider: string;
68
+ keyLabel: string;
69
+ latencyMs: number;
70
+ attempt: number;
71
+ };
72
+ }
73
+ export interface StreamChunk {
74
+ id: string;
75
+ object: string;
76
+ model: string;
77
+ choices: Array<{
78
+ index: number;
79
+ delta: Partial<ChatMessage>;
80
+ finish_reason: string | null;
81
+ }>;
82
+ }
83
+ export interface UsageLog {
84
+ requestId: string;
85
+ provider: string;
86
+ keyLabel: string;
87
+ model: string;
88
+ promptTokens: number;
89
+ completionTokens: number;
90
+ totalTokens: number;
91
+ estimatedCostUsd: number;
92
+ latencyMs: number;
93
+ status: 'success' | 'rate_limited' | 'error';
94
+ error?: string;
95
+ metadata?: Record<string, string>;
96
+ timestamp: Date;
97
+ }
98
+ export interface KeyState {
99
+ key: string;
100
+ provider: string;
101
+ label: string;
102
+ rpm: number;
103
+ tpm: number;
104
+ requestsThisMinute: number;
105
+ tokensThisMinute: number;
106
+ minuteStart: number;
107
+ cooldownUntil: number;
108
+ totalRequests: number;
109
+ totalErrors: number;
110
+ healthy: boolean;
111
+ }
112
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC;IAC/B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,wDAAwD;IACxD,kBAAkB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CACjD;AAID,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,WAAW,CAAC;IACrB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,KAAK,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;QAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;KAC9B,CAAC,CAAC;CACJ;AAID,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,SAAS,GAAG,cAAc,GAAG,OAAO,CAAC;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,SAAS,EAAE,IAAI,CAAC;CACjB;AAID,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ // ─── Key & Provider Config ─────────────────────────────────────
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,kEAAkE"}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@careob/llm-gateway",
3
+ "version": "1.0.0",
4
+ "description": "Lightweight LLM gateway with multi-key rotation, rate-limit handling, provider failover, and spend tracking for Node.js/Express apps",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "typecheck": "tsc --noEmit",
17
+ "dev": "tsc --watch"
18
+ },
19
+ "dependencies": {},
20
+ "peerDependencies": {
21
+ "express": "^4.18.0 || ^5.0.0"
22
+ },
23
+ "peerDependenciesMeta": {
24
+ "express": { "optional": true }
25
+ },
26
+ "devDependencies": {
27
+ "@types/express": "^4.17.21",
28
+ "@types/node": "^20.14.9",
29
+ "typescript": "^5.5.3"
30
+ },
31
+ "files": ["dist", "README.md"],
32
+ "keywords": ["llm", "gateway", "openai", "anthropic", "key-rotation", "rate-limit", "express"],
33
+ "license": "MIT"
34
+ }