proxitor 0.1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,200 @@
1
+ # proxitor
2
+
3
+ > Lightweight proxy for routing CLI requests (claude-code, codex) to [OpenRouter](https://openrouter.ai)
4
+
5
+ ## Why
6
+
7
+ When using AI CLI tools like Claude Code or Codex, you may want to route requests through OpenRouter for model selection, cost control, or unified API access. Proxitor sits between your CLI tools and OpenRouter, injecting [provider routing](https://openrouter.ai/docs/api/reference/streaming) into requests and streaming responses back unchanged — including SSE streams from LLM models.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ # npm
13
+ npm install -g proxitor
14
+
15
+ # bun
16
+ bun install -g proxitor
17
+
18
+ # npx (no install)
19
+ npx proxitor
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ### Start the proxy
25
+
26
+ ```bash
27
+ # With env var
28
+ OPENROUTER_API_KEY=sk-... proxitor
29
+
30
+ # With CLI flag
31
+ proxitor --openrouter-key sk-...
32
+
33
+ # With config file
34
+ proxitor --config ./proxitor.config.yaml
35
+ ```
36
+
37
+ ### Configure CLI tools
38
+
39
+ Point your AI CLI tools at the proxy:
40
+
41
+ ```bash
42
+ # Claude Code
43
+ ANTHROPIC_BASE_URL=http://localhost:8080/v1 claude
44
+
45
+ # Codex
46
+ OPENAI_BASE_URL=http://localhost:8080/v1 codex
47
+ ```
48
+
49
+ ## Configuration
50
+
51
+ Proxitor looks for config files in this order:
52
+
53
+ 1. `proxitor.config.yaml`
54
+ 2. `proxitor.config.yml`
55
+ 3. `proxitor.config.json`
56
+ 4. `.proxitor.yaml`
57
+ 5. `.proxitor.yml`
58
+ 6. `.proxitor.json`
59
+
60
+ See [`proxitor.config.example.yaml`](./proxitor.config.example.yaml) for a full example.
61
+
62
+ ### Priority
63
+
64
+ CLI flags > config file > environment variables > defaults
65
+
66
+ ### Provider routing
67
+
68
+ Control which upstream provider handles your requests. Both `only` and `order` accept a single string or an array:
69
+
70
+ ```yaml
71
+ # Use a single provider exclusively (no fallbacks)
72
+ provider:
73
+ only: "deepinfra"
74
+
75
+ # Use multiple providers exclusively
76
+ provider:
77
+ only:
78
+ - "openai"
79
+ - "azure"
80
+
81
+ # Prefer a provider, allow fallbacks
82
+ provider:
83
+ order: "anthropic"
84
+ allowFallbacks: true
85
+
86
+ # Try providers in order
87
+ provider:
88
+ order:
89
+ - "anthropic"
90
+ - "deepinfra"
91
+ allowFallbacks: false
92
+ ```
93
+
94
+ Without `provider` configured, the proxy forwards requests unchanged.
95
+ See the [OpenRouter provider routing docs](https://openrouter.ai/docs/guides/routing/provider-selection) for the full list of supported providers.
96
+
97
+ ### Per-model overrides
98
+
99
+ Route different models to different providers using `modelOverrides`. Keys are exact model names or prefix patterns (e.g. `claude-*`). Overrides layer on top of global settings — `provider` replaces the global value, `headers` merge:
100
+
101
+ ```yaml
102
+ provider:
103
+ order: "deepinfra"
104
+
105
+ modelOverrides:
106
+ # Exact match — force Anthropic models to Anthropic's own infrastructure
107
+ "claude-sonnet-4-6":
108
+ provider:
109
+ only: "anthropic"
110
+
111
+ # Wildcard — all Claude models prefer Anthropic with fallback
112
+ "claude-*":
113
+ provider:
114
+ order:
115
+ - "anthropic"
116
+ - "deepinfra"
117
+
118
+ # Wildcard — GPT models to OpenAI/Azure, plus a custom header
119
+ "gpt-*":
120
+ provider:
121
+ only:
122
+ - "openai"
123
+ - "azure"
124
+ headers:
125
+ X-Model-Family: "gpt"
126
+ ```
127
+
128
+ When a model name matches multiple patterns, the most specific match wins (exact name > longer prefix > shorter prefix).
129
+
130
+ ### Custom headers
131
+
132
+ Add custom headers to all proxied requests, or per-model via `modelOverrides`:
133
+
134
+ ```yaml
135
+ # Global custom headers
136
+ headers:
137
+ X-Custom-Header: "my-value"
138
+ X-Environment: "production"
139
+
140
+ # Per-model headers (merged on top of global)
141
+ modelOverrides:
142
+ "claude-*":
143
+ headers:
144
+ X-Custom-Header: "claude-override" # overrides global value
145
+ X-Extra: "only-for-claude" # added only for this model
146
+ ```
147
+
148
+ ### Health check
149
+
150
+ ```bash
151
+ curl http://localhost:8080/health
152
+ ```
153
+
154
+ ## CLI Options
155
+
156
+ ```text
157
+ proxitor [options]
158
+
159
+ Options:
160
+ -p, --port <port> Proxy server port (default: 8080)
161
+ -h, --host <host> Proxy server host (default: 0.0.0.0)
162
+ -c, --config <path> Path to config file
163
+ --openrouter-key <key> OpenRouter API key
164
+ --verbose Enable verbose logging
165
+ -v, --version Display version
166
+ --help Display help
167
+ ```
168
+
169
+ ## Development
170
+
171
+ ```bash
172
+ # Install dependencies
173
+ pnpm install
174
+
175
+ # Run in dev mode with watch
176
+ pnpm run dev
177
+
178
+ # Run tests
179
+ pnpm run test
180
+
181
+ # Type check
182
+ pnpm run typecheck
183
+
184
+ # Lint + format (Biome)
185
+ pnpm run check:biome
186
+
187
+ # Auto-fix lint + format issues
188
+ pnpm run lint:fix
189
+ pnpm run format
190
+
191
+ # Build
192
+ pnpm run build
193
+
194
+ # Full check (typecheck + biome + test)
195
+ pnpm run check
196
+ ```
197
+
198
+ ## License
199
+
200
+ [MIT](./LICENSE)
package/dist/cli.cjs ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ const require_proxy = require("./proxy.cjs");
3
+ let cac = require("cac");
4
+ let dotenv = require("dotenv");
5
+ //#region src/version.ts
6
+ const version = "0.1.0";
7
+ //#endregion
8
+ //#region src/cli.ts
9
+ (0, dotenv.config)();
10
+ const cli = (0, cac.cac)("proxitor");
11
+ cli.version(version).usage("[options]").help();
12
+ cli.option("-p, --port <port>", "Proxy server port", { default: 8080 }).option("-h, --host <host>", "Proxy server host", { default: "0.0.0.0" }).option("-c, --config <path>", "Path to config file").option("--no-config", "Skip config file discovery").option("--openrouter-key <key>", "OpenRouter API key").option("--verbose", "Enable verbose logging");
13
+ const parsed = cli.parse();
14
+ async function main() {
15
+ try {
16
+ const config = await require_proxy.loadConfig({
17
+ configPath: typeof parsed.options.config === "string" ? parsed.options.config : void 0,
18
+ noConfig: parsed.options.config === false,
19
+ port: parsed.options.port,
20
+ host: parsed.options.host,
21
+ openrouterKey: parsed.options.openrouterKey,
22
+ verbose: parsed.options.verbose
23
+ });
24
+ require_proxy.startProxyServer(config, () => {
25
+ require_proxy.logger.ready(`Proxitor proxy listening on ${config.host}:${config.port}`);
26
+ require_proxy.logger.info(`Routing requests to OpenRouter`);
27
+ });
28
+ } catch (error) {
29
+ require_proxy.logger.error("Failed to start proxy:", error);
30
+ process.exit(1);
31
+ }
32
+ }
33
+ main();
34
+ //#endregion
35
+
36
+ //# sourceMappingURL=cli.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.cjs","names":["loadConfig"],"sources":["../src/version.ts","../src/cli.ts"],"sourcesContent":["export const version = '0.1.0'\n","#!/usr/bin/env node\nimport { cac } from 'cac'\nimport { config as loadDotenv } from 'dotenv'\nimport { loadConfig } from './config.js'\nimport { logger } from './logger.js'\nimport { startProxyServer } from './proxy.js'\nimport { version } from './version.js'\n\nloadDotenv()\n\nconst cli = cac('proxitor')\n\ncli.version(version).usage('[options]').help()\n\ncli\n .option('-p, --port <port>', 'Proxy server port', { default: 8080 })\n .option('-h, --host <host>', 'Proxy server host', { default: '0.0.0.0' })\n .option('-c, --config <path>', 'Path to config file')\n .option('--no-config', 'Skip config file discovery')\n .option('--openrouter-key <key>', 'OpenRouter API key')\n .option('--verbose', 'Enable verbose logging')\n\nconst parsed = cli.parse()\n\nasync function main() {\n try {\n const config = await loadConfig({\n configPath:\n typeof parsed.options.config === 'string' ? parsed.options.config : undefined,\n noConfig: parsed.options.config === false,\n port: parsed.options.port,\n host: parsed.options.host,\n openrouterKey: parsed.options.openrouterKey,\n verbose: parsed.options.verbose,\n })\n\n startProxyServer(config, () => {\n logger.ready(`Proxitor proxy listening on ${config.host}:${config.port}`)\n logger.info(`Routing requests to OpenRouter`)\n })\n } catch (error) {\n logger.error('Failed to start proxy:', error)\n process.exit(1)\n }\n}\n\nvoid main()\n"],"mappings":";;;;;AAAA,MAAa,UAAU;;;mBCQZ;AAEX,MAAM,OAAA,GAAA,IAAA,KAAU,UAAU;AAE1B,IAAI,QAAQ,OAAO,EAAE,MAAM,WAAW,EAAE,KAAK;AAE7C,IACG,OAAO,qBAAqB,qBAAqB,EAAE,SAAS,KAAK,CAAC,EAClE,OAAO,qBAAqB,qBAAqB,EAAE,SAAS,UAAU,CAAC,EACvE,OAAO,uBAAuB,qBAAqB,EACnD,OAAO,eAAe,4BAA4B,EAClD,OAAO,0BAA0B,oBAAoB,EACrD,OAAO,aAAa,wBAAwB;AAE/C,MAAM,SAAS,IAAI,MAAM;AAEzB,eAAe,OAAO;CACpB,IAAI;EACF,MAAM,SAAS,MAAMA,cAAAA,WAAW;GAC9B,YACE,OAAO,OAAO,QAAQ,WAAW,WAAW,OAAO,QAAQ,SAAS,KAAA;GACtE,UAAU,OAAO,QAAQ,WAAW;GACpC,MAAM,OAAO,QAAQ;GACrB,MAAM,OAAO,QAAQ;GACrB,eAAe,OAAO,QAAQ;GAC9B,SAAS,OAAO,QAAQ;EAC1B,CAAC;EAED,cAAA,iBAAiB,cAAc;GAC7B,cAAA,OAAO,MAAM,+BAA+B,OAAO,KAAK,GAAG,OAAO,MAAM;GACxE,cAAA,OAAO,KAAK,gCAAgC;EAC9C,CAAC;CACH,SAAS,OAAO;EACd,cAAA,OAAO,MAAM,0BAA0B,KAAK;EAC5C,QAAQ,KAAK,CAAC;CAChB;AACF;AAEK,KAAK"}
package/dist/cli.d.cts ADDED
@@ -0,0 +1 @@
1
+ export { };
package/dist/cli.d.mts ADDED
@@ -0,0 +1 @@
1
+ export { };
package/dist/cli.mjs ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+ import { i as logger, n as startProxyServer, o as loadConfig } from "./proxy.mjs";
3
+ import { cac } from "cac";
4
+ import { config } from "dotenv";
5
+ //#region src/version.ts
6
+ const version = "0.1.0";
7
+ //#endregion
8
+ //#region src/cli.ts
9
+ config();
10
+ const cli = cac("proxitor");
11
+ cli.version(version).usage("[options]").help();
12
+ cli.option("-p, --port <port>", "Proxy server port", { default: 8080 }).option("-h, --host <host>", "Proxy server host", { default: "0.0.0.0" }).option("-c, --config <path>", "Path to config file").option("--no-config", "Skip config file discovery").option("--openrouter-key <key>", "OpenRouter API key").option("--verbose", "Enable verbose logging");
13
+ const parsed = cli.parse();
14
+ async function main() {
15
+ try {
16
+ const config = await loadConfig({
17
+ configPath: typeof parsed.options.config === "string" ? parsed.options.config : void 0,
18
+ noConfig: parsed.options.config === false,
19
+ port: parsed.options.port,
20
+ host: parsed.options.host,
21
+ openrouterKey: parsed.options.openrouterKey,
22
+ verbose: parsed.options.verbose
23
+ });
24
+ startProxyServer(config, () => {
25
+ logger.ready(`Proxitor proxy listening on ${config.host}:${config.port}`);
26
+ logger.info(`Routing requests to OpenRouter`);
27
+ });
28
+ } catch (error) {
29
+ logger.error("Failed to start proxy:", error);
30
+ process.exit(1);
31
+ }
32
+ }
33
+ main();
34
+ //#endregion
35
+ export {};
36
+
37
+ //# sourceMappingURL=cli.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.mjs","names":["loadDotenv"],"sources":["../src/version.ts","../src/cli.ts"],"sourcesContent":["export const version = '0.1.0'\n","#!/usr/bin/env node\nimport { cac } from 'cac'\nimport { config as loadDotenv } from 'dotenv'\nimport { loadConfig } from './config.js'\nimport { logger } from './logger.js'\nimport { startProxyServer } from './proxy.js'\nimport { version } from './version.js'\n\nloadDotenv()\n\nconst cli = cac('proxitor')\n\ncli.version(version).usage('[options]').help()\n\ncli\n .option('-p, --port <port>', 'Proxy server port', { default: 8080 })\n .option('-h, --host <host>', 'Proxy server host', { default: '0.0.0.0' })\n .option('-c, --config <path>', 'Path to config file')\n .option('--no-config', 'Skip config file discovery')\n .option('--openrouter-key <key>', 'OpenRouter API key')\n .option('--verbose', 'Enable verbose logging')\n\nconst parsed = cli.parse()\n\nasync function main() {\n try {\n const config = await loadConfig({\n configPath:\n typeof parsed.options.config === 'string' ? parsed.options.config : undefined,\n noConfig: parsed.options.config === false,\n port: parsed.options.port,\n host: parsed.options.host,\n openrouterKey: parsed.options.openrouterKey,\n verbose: parsed.options.verbose,\n })\n\n startProxyServer(config, () => {\n logger.ready(`Proxitor proxy listening on ${config.host}:${config.port}`)\n logger.info(`Routing requests to OpenRouter`)\n })\n } catch (error) {\n logger.error('Failed to start proxy:', error)\n process.exit(1)\n }\n}\n\nvoid main()\n"],"mappings":";;;;;AAAA,MAAa,UAAU;;;ACQvBA,OAAW;AAEX,MAAM,MAAM,IAAI,UAAU;AAE1B,IAAI,QAAQ,OAAO,EAAE,MAAM,WAAW,EAAE,KAAK;AAE7C,IACG,OAAO,qBAAqB,qBAAqB,EAAE,SAAS,KAAK,CAAC,EAClE,OAAO,qBAAqB,qBAAqB,EAAE,SAAS,UAAU,CAAC,EACvE,OAAO,uBAAuB,qBAAqB,EACnD,OAAO,eAAe,4BAA4B,EAClD,OAAO,0BAA0B,oBAAoB,EACrD,OAAO,aAAa,wBAAwB;AAE/C,MAAM,SAAS,IAAI,MAAM;AAEzB,eAAe,OAAO;CACpB,IAAI;EACF,MAAM,SAAS,MAAM,WAAW;GAC9B,YACE,OAAO,OAAO,QAAQ,WAAW,WAAW,OAAO,QAAQ,SAAS,KAAA;GACtE,UAAU,OAAO,QAAQ,WAAW;GACpC,MAAM,OAAO,QAAQ;GACrB,MAAM,OAAO,QAAQ;GACrB,eAAe,OAAO,QAAQ;GAC9B,SAAS,OAAO,QAAQ;EAC1B,CAAC;EAED,iBAAiB,cAAc;GAC7B,OAAO,MAAM,+BAA+B,OAAO,KAAK,GAAG,OAAO,MAAM;GACxE,OAAO,KAAK,gCAAgC;EAC9C,CAAC;CACH,SAAS,OAAO;EACd,OAAO,MAAM,0BAA0B,KAAK;EAC5C,QAAQ,KAAK,CAAC;CAChB;AACF;AAEK,KAAK"}
package/dist/index.cjs ADDED
@@ -0,0 +1,10 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_proxy = require("./proxy.cjs");
3
+ exports.buildProviderRouting = require_proxy.buildProviderRouting;
4
+ exports.createProxyServer = require_proxy.createProxyServer;
5
+ exports.extractModel = require_proxy.extractModel;
6
+ exports.loadConfig = require_proxy.loadConfig;
7
+ exports.matchScore = require_proxy.matchScore;
8
+ exports.resolveModelConfig = require_proxy.resolveModelConfig;
9
+ exports.toArray = require_proxy.toArray;
10
+ exports.tryParseBody = require_proxy.tryParseBody;
@@ -0,0 +1,91 @@
1
+ import { ServerType } from "@hono/node-server";
2
+
3
+ //#region src/config.d.ts
4
+ /** Percentile cutoffs for performance thresholds */
5
+ type PercentileCutoffs = {
6
+ p50?: number;
7
+ p75?: number;
8
+ p90?: number;
9
+ p99?: number;
10
+ };
11
+ /** Provider sorting options */
12
+ type ProviderSort = 'price' | 'throughput' | 'latency' | {
13
+ by: 'price' | 'throughput' | 'latency';
14
+ partition?: 'model' | 'none';
15
+ };
16
+ /** Maximum pricing for a request */
17
+ type MaxPrice = {
18
+ prompt?: number;
19
+ completion?: number;
20
+ request?: number;
21
+ image?: number;
22
+ };
23
+ type ProviderConfig = {
24
+ /** Allow only these providers (e.g. "deepinfra" or ["anthropic", "openai"]) */only?: string | string[]; /** Try providers in this order (e.g. "anthropic" or ["openai", "together"]) */
25
+ order?: string | string[]; /** Ignore these providers (mirror of only — skip specific providers) */
26
+ ignore?: string | string[]; /** Allow fallback to other providers (default: true) */
27
+ allowFallbacks?: boolean; /** Sort providers by price, throughput, or latency */
28
+ sort?: ProviderSort; /** Filter by quantization levels (e.g. ["fp8", "int4"]) */
29
+ quantizations?: string[]; /** Maximum pricing to accept */
30
+ maxPrice?: MaxPrice; /** Only use providers that support all request parameters (default: false) */
31
+ requireParameters?: boolean; /** Control data collection policy: "allow" or "deny" (default: "allow") */
32
+ dataCollection?: 'allow' | 'deny'; /** Restrict routing to Zero Data Retention endpoints */
33
+ zdr?: boolean; /** Restrict routing to models that allow text distillation */
34
+ enforceDistillableText?: boolean; /** Preferred minimum throughput (tokens/sec) */
35
+ preferredMinThroughput?: number | PercentileCutoffs; /** Preferred maximum latency (seconds) */
36
+ preferredMaxLatency?: number | PercentileCutoffs;
37
+ };
38
+ /** Per-model override: layers on top of global config */
39
+ type ModelOverride = {
40
+ /** Override provider routing for matching models */provider?: ProviderConfig; /** Additional headers to merge for matching models */
41
+ headers?: Record<string, string>;
42
+ };
43
+ /** Result of merging global config with a model-specific override */
44
+ type ResolvedModelConfig = {
45
+ provider?: ProviderConfig;
46
+ headers?: Record<string, string>;
47
+ };
48
+ type ProxyConfig = {
49
+ host: string;
50
+ port: number;
51
+ openrouterKey: string;
52
+ openrouterBaseUrl: string;
53
+ verbose: boolean; /** Request body size limit (default: "50mb") */
54
+ bodyLimit: string; /** Provider routing configuration (global default) */
55
+ provider?: ProviderConfig; /** HTTP-Referer for OpenRouter attribution */
56
+ attributionReferer: string; /** X-Title for OpenRouter attribution */
57
+ attributionTitle: string; /** Custom headers to add to proxied requests (global default) */
58
+ headers?: Record<string, string>; /** Per-model config overrides. Keys are exact model names or prefix patterns (e.g. "claude-*") */
59
+ modelOverrides?: Record<string, ModelOverride>;
60
+ };
61
+ type LoadConfigOptions = {
62
+ configPath?: string;
63
+ noConfig?: boolean;
64
+ host?: string;
65
+ openrouterKey?: string;
66
+ port?: number;
67
+ verbose?: boolean;
68
+ };
69
+ /** Build the provider routing object for OpenRouter request body injection */
70
+ declare function buildProviderRouting(provider?: ProviderConfig): Record<string, unknown> | undefined;
71
+ /** Score a pattern against a model name. Higher = better match. -1 = no match. */
72
+ declare function matchScore(pattern: string, modelName: string): number;
73
+ /** Resolve the effective config for a given model by merging global defaults with the best-matching override */
74
+ declare function resolveModelConfig(config: ProxyConfig, modelName?: string): ResolvedModelConfig;
75
+ declare function loadConfig(options: LoadConfigOptions): Promise<ProxyConfig>;
76
+ //#endregion
77
+ //#region src/proxy/inject.d.ts
78
+ /** Extract the model name from a raw request body. Returns undefined if not parseable or absent. */
79
+ declare function extractModel(rawBody: ArrayBuffer): string | undefined;
80
+ //#endregion
81
+ //#region src/proxy.d.ts
82
+ declare function createProxyServer(config: ProxyConfig, onReady?: () => void): ServerType;
83
+ //#endregion
84
+ //#region src/utils.d.ts
85
+ /** Normalize a single string or array of strings to an array. Returns undefined for empty arrays. */
86
+ declare function toArray(value: string | string[] | undefined): string[] | undefined;
87
+ /** Try to parse an ArrayBuffer as JSON. Returns undefined on failure or empty body. */
88
+ declare function tryParseBody(raw: ArrayBuffer): Record<string, unknown> | undefined;
89
+ //#endregion
90
+ export { type ModelOverride, type ProviderConfig, type ProxyConfig, type ResolvedModelConfig, buildProviderRouting, createProxyServer, extractModel, loadConfig, matchScore, resolveModelConfig, toArray, tryParseBody };
91
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/config.ts","../src/proxy/inject.ts","../src/proxy.ts","../src/utils.ts"],"mappings":";;;;KAOY,iBAAA;EACV,GAAA;EACA,GAAA;EACA,GAAA;EACA,GAAA;AAAA;;KAIU,YAAA;EAIN,EAAA;EAAwC,SAAS;AAAA;AARlD;AAAA,KAWO,QAAA;EACV,MAAA;EACA,UAAA;EACA,OAAA;EACA,KAAA;AAAA;AAAA,KAGU,cAAA;iFAEV,IAAA,sBARA;EAUA,KAAA,sBARA;EAUA,MAAA,sBATK;EAWL,cAAA,YARU;EAUV,IAAA,GAAO,YAAA;EAEP,aAAA,aAEW;EAAX,QAAA,GAAW,QAAA,EAYoB;EAV/B,iBAAA,YAUgD;EARhD,cAAA,qBAdA;EAgBA,GAAA,YAZA;EAcA,sBAAA,YAZO;EAcP,sBAAA,YAAkC,iBAAA,EAVlC;EAYA,mBAAA,YAA+B,iBAAA;AAAA;;KAIrB,aAAA;EARV,oDAUA,QAAA,GAAW,cAAA,EARuB;EAUlC,OAAA,GAAU,MAAM;AAAA;;KAIN,mBAAA;EACV,QAAA,GAAW,cAAA;EACX,OAAA,GAAU,MAAM;AAAA;AAAA,KAGN,WAAA;EACV,IAAA;EACA,IAAA;EACA,aAAA;EACA,iBAAA;EACA,OAAA,WAdgB;EAgBhB,SAAA,UAZ6B;EAc7B,QAAA,GAAW,cAAA,EAZK;EAchB,kBAAA,UAfW;EAiBX,gBAAA,UAhBU;EAkBV,OAAA,GAAU,MAAA,kBAlBM;EAoBhB,cAAA,GAAiB,MAAA,SAAe,aAAA;AAAA;AAAA,KAc7B,iBAAA;EACH,UAAA;EACA,QAAA;EACA,IAAA;EACA,aAAA;EACA,IAAA;EACA,OAAA;AAAA;;iBAwBc,oBAAA,CACd,QAAA,GAAW,cAAA,GACV,MAAM;;iBA0BO,UAAA,CAAW,OAAA,UAAiB,SAAiB;;iBAW7C,kBAAA,CACd,MAAA,EAAQ,WAAA,EACR,SAAA,YACC,mBAAmB;AAAA,iBAgCA,UAAA,CAAW,OAAA,EAAS,iBAAA,GAAoB,OAAA,CAAQ,WAAA;;;;iBC5MtD,YAAA,CAAa,OAAoB,EAAX,WAAW;;;iBC0JjC,iBAAA,CAAkB,MAAA,EAAQ,WAAA,EAAa,OAAA,gBAAuB,UAAU;;;;iBC5JxE,OAAA,CAAQ,KAAoC;;iBAO5C,YAAA,CAAa,GAAA,EAAK,WAAA,GAAc,MAAM"}
@@ -0,0 +1,91 @@
1
+ import { ServerType } from "@hono/node-server";
2
+
3
+ //#region src/config.d.ts
4
+ /** Percentile cutoffs for performance thresholds */
5
+ type PercentileCutoffs = {
6
+ p50?: number;
7
+ p75?: number;
8
+ p90?: number;
9
+ p99?: number;
10
+ };
11
+ /** Provider sorting options */
12
+ type ProviderSort = 'price' | 'throughput' | 'latency' | {
13
+ by: 'price' | 'throughput' | 'latency';
14
+ partition?: 'model' | 'none';
15
+ };
16
+ /** Maximum pricing for a request */
17
+ type MaxPrice = {
18
+ prompt?: number;
19
+ completion?: number;
20
+ request?: number;
21
+ image?: number;
22
+ };
23
+ type ProviderConfig = {
24
+ /** Allow only these providers (e.g. "deepinfra" or ["anthropic", "openai"]) */only?: string | string[]; /** Try providers in this order (e.g. "anthropic" or ["openai", "together"]) */
25
+ order?: string | string[]; /** Ignore these providers (mirror of only — skip specific providers) */
26
+ ignore?: string | string[]; /** Allow fallback to other providers (default: true) */
27
+ allowFallbacks?: boolean; /** Sort providers by price, throughput, or latency */
28
+ sort?: ProviderSort; /** Filter by quantization levels (e.g. ["fp8", "int4"]) */
29
+ quantizations?: string[]; /** Maximum pricing to accept */
30
+ maxPrice?: MaxPrice; /** Only use providers that support all request parameters (default: false) */
31
+ requireParameters?: boolean; /** Control data collection policy: "allow" or "deny" (default: "allow") */
32
+ dataCollection?: 'allow' | 'deny'; /** Restrict routing to Zero Data Retention endpoints */
33
+ zdr?: boolean; /** Restrict routing to models that allow text distillation */
34
+ enforceDistillableText?: boolean; /** Preferred minimum throughput (tokens/sec) */
35
+ preferredMinThroughput?: number | PercentileCutoffs; /** Preferred maximum latency (seconds) */
36
+ preferredMaxLatency?: number | PercentileCutoffs;
37
+ };
38
+ /** Per-model override: layers on top of global config */
39
+ type ModelOverride = {
40
+ /** Override provider routing for matching models */provider?: ProviderConfig; /** Additional headers to merge for matching models */
41
+ headers?: Record<string, string>;
42
+ };
43
+ /** Result of merging global config with a model-specific override */
44
+ type ResolvedModelConfig = {
45
+ provider?: ProviderConfig;
46
+ headers?: Record<string, string>;
47
+ };
48
+ type ProxyConfig = {
49
+ host: string;
50
+ port: number;
51
+ openrouterKey: string;
52
+ openrouterBaseUrl: string;
53
+ verbose: boolean; /** Request body size limit (default: "50mb") */
54
+ bodyLimit: string; /** Provider routing configuration (global default) */
55
+ provider?: ProviderConfig; /** HTTP-Referer for OpenRouter attribution */
56
+ attributionReferer: string; /** X-Title for OpenRouter attribution */
57
+ attributionTitle: string; /** Custom headers to add to proxied requests (global default) */
58
+ headers?: Record<string, string>; /** Per-model config overrides. Keys are exact model names or prefix patterns (e.g. "claude-*") */
59
+ modelOverrides?: Record<string, ModelOverride>;
60
+ };
61
+ type LoadConfigOptions = {
62
+ configPath?: string;
63
+ noConfig?: boolean;
64
+ host?: string;
65
+ openrouterKey?: string;
66
+ port?: number;
67
+ verbose?: boolean;
68
+ };
69
+ /** Build the provider routing object for OpenRouter request body injection */
70
+ declare function buildProviderRouting(provider?: ProviderConfig): Record<string, unknown> | undefined;
71
+ /** Score a pattern against a model name. Higher = better match. -1 = no match. */
72
+ declare function matchScore(pattern: string, modelName: string): number;
73
+ /** Resolve the effective config for a given model by merging global defaults with the best-matching override */
74
+ declare function resolveModelConfig(config: ProxyConfig, modelName?: string): ResolvedModelConfig;
75
+ declare function loadConfig(options: LoadConfigOptions): Promise<ProxyConfig>;
76
+ //#endregion
77
+ //#region src/proxy/inject.d.ts
78
+ /** Extract the model name from a raw request body. Returns undefined if not parseable or absent. */
79
+ declare function extractModel(rawBody: ArrayBuffer): string | undefined;
80
+ //#endregion
81
+ //#region src/proxy.d.ts
82
+ declare function createProxyServer(config: ProxyConfig, onReady?: () => void): ServerType;
83
+ //#endregion
84
+ //#region src/utils.d.ts
85
+ /** Normalize a single string or array of strings to an array. Returns undefined for empty arrays. */
86
+ declare function toArray(value: string | string[] | undefined): string[] | undefined;
87
+ /** Try to parse an ArrayBuffer as JSON. Returns undefined on failure or empty body. */
88
+ declare function tryParseBody(raw: ArrayBuffer): Record<string, unknown> | undefined;
89
+ //#endregion
90
+ export { type ModelOverride, type ProviderConfig, type ProxyConfig, type ResolvedModelConfig, buildProviderRouting, createProxyServer, extractModel, loadConfig, matchScore, resolveModelConfig, toArray, tryParseBody };
91
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/config.ts","../src/proxy/inject.ts","../src/proxy.ts","../src/utils.ts"],"mappings":";;;;KAOY,iBAAA;EACV,GAAA;EACA,GAAA;EACA,GAAA;EACA,GAAA;AAAA;;KAIU,YAAA;EAIN,EAAA;EAAwC,SAAS;AAAA;AARlD;AAAA,KAWO,QAAA;EACV,MAAA;EACA,UAAA;EACA,OAAA;EACA,KAAA;AAAA;AAAA,KAGU,cAAA;iFAEV,IAAA,sBARA;EAUA,KAAA,sBARA;EAUA,MAAA,sBATK;EAWL,cAAA,YARU;EAUV,IAAA,GAAO,YAAA;EAEP,aAAA,aAEW;EAAX,QAAA,GAAW,QAAA,EAYoB;EAV/B,iBAAA,YAUgD;EARhD,cAAA,qBAdA;EAgBA,GAAA,YAZA;EAcA,sBAAA,YAZO;EAcP,sBAAA,YAAkC,iBAAA,EAVlC;EAYA,mBAAA,YAA+B,iBAAA;AAAA;;KAIrB,aAAA;EARV,oDAUA,QAAA,GAAW,cAAA,EARuB;EAUlC,OAAA,GAAU,MAAM;AAAA;;KAIN,mBAAA;EACV,QAAA,GAAW,cAAA;EACX,OAAA,GAAU,MAAM;AAAA;AAAA,KAGN,WAAA;EACV,IAAA;EACA,IAAA;EACA,aAAA;EACA,iBAAA;EACA,OAAA,WAdgB;EAgBhB,SAAA,UAZ6B;EAc7B,QAAA,GAAW,cAAA,EAZK;EAchB,kBAAA,UAfW;EAiBX,gBAAA,UAhBU;EAkBV,OAAA,GAAU,MAAA,kBAlBM;EAoBhB,cAAA,GAAiB,MAAA,SAAe,aAAA;AAAA;AAAA,KAc7B,iBAAA;EACH,UAAA;EACA,QAAA;EACA,IAAA;EACA,aAAA;EACA,IAAA;EACA,OAAA;AAAA;;iBAwBc,oBAAA,CACd,QAAA,GAAW,cAAA,GACV,MAAM;;iBA0BO,UAAA,CAAW,OAAA,UAAiB,SAAiB;;iBAW7C,kBAAA,CACd,MAAA,EAAQ,WAAA,EACR,SAAA,YACC,mBAAmB;AAAA,iBAgCA,UAAA,CAAW,OAAA,EAAS,iBAAA,GAAoB,OAAA,CAAQ,WAAA;;;;iBC5MtD,YAAA,CAAa,OAAoB,EAAX,WAAW;;;iBC0JjC,iBAAA,CAAkB,MAAA,EAAQ,WAAA,EAAa,OAAA,gBAAuB,UAAU;;;;iBC5JxE,OAAA,CAAQ,KAAoC;;iBAO5C,YAAA,CAAa,GAAA,EAAK,WAAA,GAAc,MAAM"}
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import { a as buildProviderRouting, c as resolveModelConfig, l as toArray, o as loadConfig, r as extractModel, s as matchScore, t as createProxyServer, u as tryParseBody } from "./proxy.mjs";
2
+ export { buildProviderRouting, createProxyServer, extractModel, loadConfig, matchScore, resolveModelConfig, toArray, tryParseBody };