@mini-passy/sdk 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/.env.example ADDED
@@ -0,0 +1,38 @@
1
+ # Mini-Passy Environment Configuration
2
+ # Copy this file to .env and fill in your API keys
3
+
4
+ # Provider Configuration
5
+ # Format: PROVIDER_{NAME}_URL and PROVIDER_{NAME}_KEY
6
+ # The {NAME} can be any identifier (lowercase recommended)
7
+
8
+ PROVIDER_OPENAI_URL=https://api.openai.com
9
+ PROVIDER_OPENAI_KEY=sk-your-openai-key-here
10
+
11
+ PROVIDER_ANTHROPIC_URL=https://api.anthropic.com
12
+ PROVIDER_ANTHROPIC_KEY=sk-your-anthropic-key-here
13
+
14
+ # Example: Add Nebius provider
15
+ # PROVIDER_NEBIUS_URL=https://api.studio.nebius.ai
16
+ # PROVIDER_NEBIUS_KEY=your-nebius-key-here
17
+
18
+ # Model Aliases
19
+ # Format: ALIAS_{NAME}=provider:model
20
+ # Use the provider name from above (lowercase)
21
+
22
+ ALIAS_GPT4O=openai:gpt-4o
23
+ ALIAS_GPT4O_MINI=openai:gpt-4o-mini
24
+ ALIAS_CLAUDE_HAIKU=anthropic:claude-3-haiku-20240307
25
+ ALIAS_CLAUDE_SONNET=anthropic:claude-3-sonnet-20240229
26
+
27
+ # Example: Add alias for Nebius model
28
+ # ALIAS_LLAMA70B=nebius:meta-llama/Meta-Llama-3.1-70B-Instruct
29
+
30
+ # Fallback Configuration (optional)
31
+ # Format: ALIAS_{NAME}_FALLBACK=provider1,provider2
32
+ # If the primary provider fails, it will try these in order
33
+
34
+ # Example: Try nebius first, fall back to deepinfra
35
+ # ALIAS_LLAMA70B_FALLBACK=deepinfra
36
+
37
+ # Server Configuration
38
+ PORT=3333
@@ -0,0 +1,3 @@
1
+ import type { Provider } from "./types.js";
2
+ export declare function discoverProviders(providers: Map<string, Provider>): Promise<void>;
3
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAkD3C,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,GAC/B,OAAO,CAAC,IAAI,CAAC,CAyDf"}
@@ -0,0 +1,96 @@
1
+ // Simple fetch wrapper using Node's https/http
2
+ function fetchWithTimeout(url, options) {
3
+ return new Promise((resolve, reject) => {
4
+ const urlObj = new URL(url);
5
+ const isHttps = urlObj.protocol === "https:";
6
+ const httpModule = isHttps ? require("node:https") : require("node:http");
7
+ const reqOptions = {
8
+ hostname: urlObj.hostname,
9
+ port: urlObj.port || (isHttps ? 443 : 80),
10
+ path: urlObj.pathname + urlObj.search,
11
+ method: "GET",
12
+ headers: options.headers,
13
+ timeout: options.timeout,
14
+ };
15
+ const req = httpModule.request(reqOptions, (res) => {
16
+ let data = "";
17
+ res.on("data", (chunk) => (data += chunk));
18
+ res.on("end", () => {
19
+ console.log(`[fetch] Response status: ${res.statusCode}, data length: ${data.length}`);
20
+ if (data.length > 0) {
21
+ console.log(`[fetch] Response preview: ${data.substring(0, 200)}`);
22
+ }
23
+ resolve({
24
+ ok: res.statusCode >= 200 && res.statusCode < 300,
25
+ json: async () => JSON.parse(data),
26
+ });
27
+ });
28
+ });
29
+ req.on("error", (err) => {
30
+ console.log(`[fetch] Error: ${err.message}`);
31
+ reject(err);
32
+ });
33
+ req.on("timeout", () => {
34
+ console.log(`[fetch] Timeout after ${options.timeout}ms`);
35
+ req.destroy();
36
+ reject(new Error("Timeout"));
37
+ });
38
+ req.end();
39
+ });
40
+ }
41
+ export async function discoverProviders(providers) {
42
+ for (const [name, provider] of providers) {
43
+ console.log(`[${name}] Discovering...`);
44
+ // Try OpenAI format
45
+ try {
46
+ const res = await fetchWithTimeout(`${provider.url}/v1/models`, {
47
+ headers: { Authorization: `Bearer ${provider.key}` },
48
+ timeout: 10000,
49
+ });
50
+ if (res.ok) {
51
+ const data = (await res.json());
52
+ provider.openai = true;
53
+ provider.models = data.data?.map((m) => m.id) || [];
54
+ console.log(`[${name}] ✓ OpenAI format, ${provider.models.length} models`);
55
+ }
56
+ else {
57
+ console.log(`[${name}] OpenAI format returned non-OK status`);
58
+ }
59
+ }
60
+ catch (e) {
61
+ const errorMsg = e instanceof Error ? e.message : String(e);
62
+ console.log(`[${name}] ✗ OpenAI format failed: ${errorMsg}`);
63
+ }
64
+ // Try Anthropic format (if OpenAI failed or for additional models)
65
+ if (!provider.openai || provider.models.length === 0) {
66
+ try {
67
+ const res = await fetchWithTimeout(`${provider.url}/v1/models`, {
68
+ headers: {
69
+ "x-api-key": provider.key,
70
+ "anthropic-version": "2023-06-01",
71
+ },
72
+ timeout: 10000,
73
+ });
74
+ if (res.ok) {
75
+ const data = (await res.json());
76
+ provider.anthropic = true;
77
+ const anthropicModels = data.data?.map((m) => m.id) || [];
78
+ // Merge models (avoid duplicates)
79
+ provider.models = [...new Set([...provider.models, ...anthropicModels])];
80
+ console.log(`[${name}] ✓ Anthropic format, ${anthropicModels.length} models`);
81
+ }
82
+ else {
83
+ console.log(`[${name}] Anthropic format returned non-OK status`);
84
+ }
85
+ }
86
+ catch (e) {
87
+ const errorMsg = e instanceof Error ? e.message : String(e);
88
+ console.log(`[${name}] ✗ Anthropic format failed: ${errorMsg}`);
89
+ }
90
+ }
91
+ if (!provider.openai && !provider.anthropic) {
92
+ console.log(`[${name}] ✗ No compatible format found`);
93
+ }
94
+ }
95
+ }
96
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
package/dist/env.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import type { EnvConfig } from "./types.js";
2
+ export declare function loadEnv(): EnvConfig;
3
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,SAAS,EAAE,MAAM,YAAY,CAAC;AAE7D,wBAAgB,OAAO,IAAI,SAAS,CA4DnC"}
package/dist/env.js ADDED
@@ -0,0 +1,56 @@
1
+ export function loadEnv() {
2
+ const port = parseInt(process.env.PORT || "3333", 10);
3
+ const providers = new Map();
4
+ const aliases = new Map();
5
+ // Parse PROVIDER_*_URL and PROVIDER_*_KEY
6
+ for (const [key, value] of Object.entries(process.env)) {
7
+ const match = key.match(/^PROVIDER_(.+)_URL$/);
8
+ if (match && value) {
9
+ const name = match[1].toLowerCase();
10
+ const url = value;
11
+ const apiKey = process.env[`PROVIDER_${match[1]}_KEY`];
12
+ if (apiKey) {
13
+ providers.set(name, {
14
+ name,
15
+ url,
16
+ key: apiKey,
17
+ openai: false,
18
+ anthropic: false,
19
+ models: [],
20
+ });
21
+ }
22
+ }
23
+ }
24
+ // Parse ALIAS_* and ALIAS_*_FALLBACK
25
+ for (const [key, value] of Object.entries(process.env)) {
26
+ const match = key.match(/^ALIAS_(.+)$/);
27
+ if (match && value && !key.endsWith("_FALLBACK")) {
28
+ const name = match[1].toLowerCase();
29
+ // Parse "provider:model" or just "provider" (uses same model name)
30
+ const [providerName, modelName] = value.includes(":")
31
+ ? value.split(":")
32
+ : [value, name];
33
+ const fallbackKey = `ALIAS_${match[1]}_FALLBACK`;
34
+ const fallbackStr = process.env[fallbackKey];
35
+ const fallbackProviders = fallbackStr
36
+ ? fallbackStr.split(",").map((s) => s.trim().toLowerCase())
37
+ : [];
38
+ // Build targets list: primary + fallbacks
39
+ const targets = [
40
+ { provider: providerName.toLowerCase(), model: modelName || name },
41
+ ];
42
+ for (const fb of fallbackProviders) {
43
+ if (fb !== providerName.toLowerCase()) {
44
+ targets.push({ provider: fb, model: modelName || name });
45
+ }
46
+ }
47
+ aliases.set(name, {
48
+ name,
49
+ targets,
50
+ fallbackOn: ["5xx", "timeout", "rate_limit"],
51
+ });
52
+ }
53
+ }
54
+ return { port, providers, aliases };
55
+ }
56
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ export { startServer } from "./server.js";
3
+ export { loadEnv } from "./env.js";
4
+ export { discoverProviders } from "./discovery.js";
5
+ export { proxyWithFallback } from "./proxy.js";
6
+ export type { EnvConfig, Provider, Alias } from "./types.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAMA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env node
2
+ import { config } from "dotenv";
3
+ import { resolve } from "path";
4
+ import { startServer } from "./server.js";
5
+ // Export for programmatic use
6
+ export { startServer } from "./server.js";
7
+ export { loadEnv } from "./env.js";
8
+ export { discoverProviders } from "./discovery.js";
9
+ export { proxyWithFallback } from "./proxy.js";
10
+ // Load .env from project root (wherever the command is run from)
11
+ const envPath = resolve(process.cwd(), ".env");
12
+ config({ path: envPath });
13
+ const port = parseInt(process.env.PORT || "3333", 10);
14
+ async function main() {
15
+ let currentPort = port;
16
+ // Try to bind, auto-increment if occupied
17
+ for (let attempt = 0; attempt < 10; attempt++) {
18
+ try {
19
+ const server = await startServer(currentPort);
20
+ return;
21
+ }
22
+ catch (e) {
23
+ if (e instanceof Error &&
24
+ "code" in e &&
25
+ e.code === "EADDRINUSE") {
26
+ currentPort++;
27
+ }
28
+ else {
29
+ throw e;
30
+ }
31
+ }
32
+ }
33
+ console.error("Failed to start Mini-Passy: all ports occupied");
34
+ process.exit(1);
35
+ }
36
+ // Only run main if this is the entry point
37
+ if (import.meta.url === `file://${process.argv[1]}`) {
38
+ main();
39
+ }
40
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,8BAA8B;AAC9B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAG/C,iEAAiE;AACjE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;AAC/C,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;AAE1B,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;AAEtD,KAAK,UAAU,IAAI;IACjB,IAAI,WAAW,GAAG,IAAI,CAAC;IAEvB,0CAA0C;IAC1C,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC;QAC9C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC,CAAC;YAC9C,OAAO;QACT,CAAC;QAAC,OAAO,CAAU,EAAE,CAAC;YACpB,IACE,CAAC,YAAY,KAAK;gBAClB,MAAM,IAAI,CAAC;gBACV,CAA2B,CAAC,IAAI,KAAK,YAAY,EAClD,CAAC;gBACD,WAAW,EAAE,CAAC;YAChB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,CAAC;YACV,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;IAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,2CAA2C;AAC3C,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,UAAU,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACpD,IAAI,EAAE,CAAC;AACT,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type http from "node:http";
2
+ import type { Provider, Alias } from "./types.js";
3
+ export declare function proxyWithFallback(alias: Alias, body: Record<string, unknown>, providers: Map<string, Provider>, res: http.ServerResponse): void;
4
+ //# sourceMappingURL=proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAkFlD,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,EAChC,GAAG,EAAE,IAAI,CAAC,cAAc,GACvB,IAAI,CA2DN"}
package/dist/proxy.js ADDED
@@ -0,0 +1,116 @@
1
+ import https from "node:https";
2
+ import httpModule from "node:http";
3
+ // Connection pooling agents
4
+ const httpsAgent = new https.Agent({
5
+ keepAlive: true,
6
+ maxSockets: 50,
7
+ maxFreeSockets: 10,
8
+ timeout: 60000,
9
+ });
10
+ const httpAgent = new httpModule.Agent({
11
+ keepAlive: true,
12
+ maxSockets: 50,
13
+ maxFreeSockets: 10,
14
+ timeout: 60000,
15
+ });
16
+ function proxyRequest(provider, path, body, format, res) {
17
+ const payload = JSON.stringify(body);
18
+ const url = new URL(provider.url);
19
+ const isHttps = url.protocol === "https:";
20
+ const agent = isHttps ? httpsAgent : httpAgent;
21
+ const requestModule = isHttps ? https : httpModule;
22
+ const headers = {
23
+ "Content-Type": "application/json",
24
+ "Content-Length": Buffer.byteLength(payload).toString(),
25
+ };
26
+ if (format === "openai") {
27
+ headers["Authorization"] = `Bearer ${provider.key}`;
28
+ }
29
+ else {
30
+ headers["x-api-key"] = provider.key;
31
+ headers["anthropic-version"] = "2023-06-01";
32
+ }
33
+ const options = {
34
+ hostname: url.hostname,
35
+ port: url.port || (isHttps ? 443 : 80),
36
+ path,
37
+ method: "POST",
38
+ agent,
39
+ headers,
40
+ };
41
+ const upstream = requestModule.request(options, (upRes) => {
42
+ const isStreaming = body.stream || upRes.headers["content-type"]?.includes("text/event-stream");
43
+ res.writeHead(upRes.statusCode || 200, {
44
+ "Content-Type": isStreaming ? "text/event-stream" : "application/json",
45
+ ...(isStreaming && {
46
+ "Cache-Control": "no-cache",
47
+ Connection: "keep-alive",
48
+ }),
49
+ });
50
+ upRes.pipe(res);
51
+ });
52
+ upstream.on("error", (err) => {
53
+ console.error(`[${provider.name}] Upstream error:`, err.message);
54
+ res.writeHead(502, { "Content-Type": "application/json" });
55
+ res.end(JSON.stringify({ error: "Upstream service unavailable" }));
56
+ });
57
+ upstream.on("timeout", () => {
58
+ upstream.destroy();
59
+ res.writeHead(504, { "Content-Type": "application/json" });
60
+ res.end(JSON.stringify({ error: "Gateway timeout" }));
61
+ });
62
+ upstream.write(payload);
63
+ upstream.end();
64
+ }
65
+ export function proxyWithFallback(alias, body, providers, res) {
66
+ const errors = [];
67
+ function tryNext(targetIndex) {
68
+ if (targetIndex >= alias.targets.length) {
69
+ // All failed
70
+ res.writeHead(502, { "Content-Type": "application/json" });
71
+ res.end(JSON.stringify({
72
+ error: "All providers failed",
73
+ details: errors,
74
+ }));
75
+ return;
76
+ }
77
+ const target = alias.targets[targetIndex];
78
+ const provider = providers.get(target.provider);
79
+ if (!provider) {
80
+ errors.push(`${target.provider}: not configured`);
81
+ tryNext(targetIndex + 1);
82
+ return;
83
+ }
84
+ // Skip model availability check - assume model exists if alias is configured
85
+ // The provider will return an error if the model doesn't exist
86
+ // Determine format and path
87
+ // If discovery failed (no format detected), assume OpenAI format as default
88
+ let path;
89
+ let format;
90
+ let requestBody;
91
+ if (provider.anthropic) {
92
+ path = "/v1/messages";
93
+ format = "anthropic";
94
+ // Convert OpenAI format to Anthropic
95
+ requestBody = {
96
+ model: target.model,
97
+ messages: body.messages,
98
+ max_tokens: body.max_tokens || 4096,
99
+ stream: body.stream,
100
+ temperature: body.temperature,
101
+ };
102
+ }
103
+ else {
104
+ // Default to OpenAI format (works for OpenAI, Nebius, DeepInfra, etc.)
105
+ path = "/v1/chat/completions";
106
+ format = "openai";
107
+ requestBody = { ...body, model: target.model };
108
+ }
109
+ // For simplicity, we don't do complex fallback detection here
110
+ // In a production system, you'd wrap this and detect 5xx/timeout errors
111
+ console.log(`[${alias.name}] Trying ${provider.name}...`);
112
+ proxyRequest(provider, path, requestBody, format, res);
113
+ }
114
+ tryNext(0);
115
+ }
116
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function startServer(port: number): Promise<{
2
+ port: number;
3
+ stop: () => void;
4
+ }>;
5
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AA4KA,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,IAAI,CAAA;CAAE,CAAC,CA0B7C"}
package/dist/server.js ADDED
@@ -0,0 +1,144 @@
1
+ import http from "node:http";
2
+ import { loadEnv } from "./env.js";
3
+ import { discoverProviders } from "./discovery.js";
4
+ import { proxyWithFallback } from "./proxy.js";
5
+ const MAX_BODY_SIZE = 10 * 1024 * 1024; // 10MB
6
+ function parseBody(req) {
7
+ return new Promise((resolve, reject) => {
8
+ const chunks = [];
9
+ let totalSize = 0;
10
+ req.on("data", (chunk) => {
11
+ totalSize += chunk.length;
12
+ if (totalSize > MAX_BODY_SIZE) {
13
+ reject(new Error("Request body too large"));
14
+ return;
15
+ }
16
+ chunks.push(chunk);
17
+ });
18
+ req.on("end", () => {
19
+ try {
20
+ resolve(Buffer.concat(chunks).toString("utf-8"));
21
+ }
22
+ catch (err) {
23
+ reject(new Error("Failed to decode request body"));
24
+ }
25
+ });
26
+ req.on("error", reject);
27
+ req.on("aborted", () => reject(new Error("Request aborted")));
28
+ });
29
+ }
30
+ function sendJson(res, data, status = 200) {
31
+ res.writeHead(status, { "Content-Type": "application/json" });
32
+ res.end(JSON.stringify(data));
33
+ }
34
+ function sendError(res, message, status = 500, code) {
35
+ const error = { error: message };
36
+ if (code)
37
+ error.code = code;
38
+ sendJson(res, error, status);
39
+ }
40
+ function createRequestHandler(env) {
41
+ return async function handleRequest(req, res) {
42
+ const path = req.url || "/";
43
+ const method = req.method || "GET";
44
+ try {
45
+ // Health check
46
+ if (path === "/health" && method === "GET") {
47
+ return sendJson(res, {
48
+ status: "ok",
49
+ providers: Array.from(env.providers.values()).map((p) => ({
50
+ name: p.name,
51
+ models: p.models.length,
52
+ openai: p.openai,
53
+ anthropic: p.anthropic,
54
+ })),
55
+ aliases: Array.from(env.aliases.keys()),
56
+ });
57
+ }
58
+ // List models (from aliases)
59
+ if (path === "/v1/models" && method === "GET") {
60
+ const data = Array.from(env.aliases.values()).map((alias) => ({
61
+ id: alias.name,
62
+ object: "model",
63
+ created: Date.now(),
64
+ owned_by: alias.targets[0]?.provider || "unknown",
65
+ }));
66
+ return sendJson(res, { object: "list", data });
67
+ }
68
+ // Chat completions
69
+ if (path === "/v1/chat/completions" && method === "POST") {
70
+ const rawBody = await parseBody(req);
71
+ let body;
72
+ try {
73
+ body = JSON.parse(rawBody);
74
+ }
75
+ catch {
76
+ return sendError(res, "Invalid JSON in request body", 400, "invalid_json");
77
+ }
78
+ const aliasName = body.model?.toLowerCase();
79
+ if (!aliasName) {
80
+ return sendError(res, "Missing 'model' field in request body", 400, "missing_model");
81
+ }
82
+ const alias = env.aliases.get(aliasName);
83
+ if (!alias) {
84
+ return sendJson(res, { error: `Unknown model: ${aliasName}` }, 404);
85
+ }
86
+ return proxyWithFallback(alias, body, env.providers, res);
87
+ }
88
+ // Anthropic messages endpoint
89
+ if (path === "/v1/messages" && method === "POST") {
90
+ const rawBody = await parseBody(req);
91
+ let body;
92
+ try {
93
+ body = JSON.parse(rawBody);
94
+ }
95
+ catch {
96
+ return sendError(res, "Invalid JSON in request body", 400, "invalid_json");
97
+ }
98
+ const aliasName = body.model?.toLowerCase();
99
+ if (!aliasName) {
100
+ return sendError(res, "Missing 'model' field in request body", 400, "missing_model");
101
+ }
102
+ const alias = env.aliases.get(aliasName);
103
+ if (!alias) {
104
+ return sendJson(res, { error: `Unknown model: ${aliasName}` }, 404);
105
+ }
106
+ return proxyWithFallback(alias, body, env.providers, res);
107
+ }
108
+ return sendError(res, "Not found", 404, "not_found");
109
+ }
110
+ catch (err) {
111
+ console.error("Request handling error:", err);
112
+ const message = err instanceof Error ? err.message : "Internal server error";
113
+ const sanitizedMessage = message.includes("body too large")
114
+ ? "Request body too large"
115
+ : "Internal server error";
116
+ sendError(res, sanitizedMessage, 500, "internal_error");
117
+ }
118
+ };
119
+ }
120
+ export async function startServer(port) {
121
+ // Load environment and discover providers
122
+ const env = loadEnv();
123
+ await discoverProviders(env.providers);
124
+ const server = http.createServer(createRequestHandler(env));
125
+ return new Promise((resolve, reject) => {
126
+ server.on("error", (err) => {
127
+ reject(err);
128
+ });
129
+ server.listen(port, "127.0.0.1", () => {
130
+ const addr = server.address();
131
+ const actualPort = typeof addr === "object" && addr ? addr.port : port;
132
+ console.log(`Mini-Passy running on http://127.0.0.1:${actualPort}`);
133
+ console.log(`Aliases: ${Array.from(env.aliases.keys()).join(", ")}`);
134
+ resolve({
135
+ port: actualPort,
136
+ stop: () => {
137
+ server.closeAllConnections?.();
138
+ server.close();
139
+ },
140
+ });
141
+ });
142
+ });
143
+ }
144
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAG/C,MAAM,aAAa,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO;AAE/C,SAAS,SAAS,CAAC,GAAyB;IAC1C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,SAAS,GAAG,CAAC,CAAC;QAElB,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YAC/B,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC;YAC1B,IAAI,SAAS,GAAG,aAAa,EAAE,CAAC;gBAC9B,MAAM,CAAC,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC,CAAC;gBAC5C,OAAO;YACT,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACjB,IAAI,CAAC;gBACH,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;YACnD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC;YACrD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACxB,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,QAAQ,CAAC,GAAwB,EAAE,IAAa,EAAE,MAAM,GAAG,GAAG;IACrE,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC9D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,SAAS,CAChB,GAAwB,EACxB,OAAe,EACf,MAAM,GAAG,GAAG,EACZ,IAAa;IAEb,MAAM,KAAK,GAAqC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IACnE,IAAI,IAAI;QAAE,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,oBAAoB,CAAC,GAAc;IAC1C,OAAO,KAAK,UAAU,aAAa,CACjC,GAAyB,EACzB,GAAwB;QAExB,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC;QAC5B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,KAAK,CAAC;QAEnC,IAAI,CAAC;YACH,eAAe;YACf,IAAI,IAAI,KAAK,SAAS,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBAC3C,OAAO,QAAQ,CAAC,GAAG,EAAE;oBACnB,MAAM,EAAE,IAAI;oBACZ,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;wBACxD,IAAI,EAAE,CAAC,CAAC,IAAI;wBACZ,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM;wBACvB,MAAM,EAAE,CAAC,CAAC,MAAM;wBAChB,SAAS,EAAE,CAAC,CAAC,SAAS;qBACvB,CAAC,CAAC;oBACH,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;iBACxC,CAAC,CAAC;YACL,CAAC;YAED,6BAA6B;YAC7B,IAAI,IAAI,KAAK,YAAY,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;oBAC5D,EAAE,EAAE,KAAK,CAAC,IAAI;oBACd,MAAM,EAAE,OAAO;oBACf,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE;oBACnB,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,IAAI,SAAS;iBAClD,CAAC,CAAC,CAAC;gBACJ,OAAO,QAAQ,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACjD,CAAC;YAED,mBAAmB;YACnB,IAAI,IAAI,KAAK,sBAAsB,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACzD,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;gBACrC,IAAI,IAAwB,CAAC;gBAC7B,IAAI,CAAC;oBACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAuB,CAAC;gBACnD,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,SAAS,CACd,GAAG,EACH,8BAA8B,EAC9B,GAAG,EACH,cAAc,CACf,CAAC;gBACJ,CAAC;gBAED,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC;gBAC5C,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,OAAO,SAAS,CACd,GAAG,EACH,uCAAuC,EACvC,GAAG,EACH,eAAe,CAChB,CAAC;gBACJ,CAAC;gBAED,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBACzC,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,OAAO,QAAQ,CACb,GAAG,EACH,EAAE,KAAK,EAAE,kBAAkB,SAAS,EAAE,EAAE,EACxC,GAAG,CACJ,CAAC;gBACJ,CAAC;gBAED,OAAO,iBAAiB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YAC5D,CAAC;YAED,8BAA8B;YAC9B,IAAI,IAAI,KAAK,cAAc,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACjD,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;gBACrC,IAAI,IAAwB,CAAC;gBAC7B,IAAI,CAAC;oBACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAuB,CAAC;gBACnD,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,SAAS,CACd,GAAG,EACH,8BAA8B,EAC9B,GAAG,EACH,cAAc,CACf,CAAC;gBACJ,CAAC;gBAED,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC;gBAC5C,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,OAAO,SAAS,CACd,GAAG,EACH,uCAAuC,EACvC,GAAG,EACH,eAAe,CAChB,CAAC;gBACJ,CAAC;gBAED,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBACzC,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,OAAO,QAAQ,CACb,GAAG,EACH,EAAE,KAAK,EAAE,kBAAkB,SAAS,EAAE,EAAE,EACxC,GAAG,CACJ,CAAC;gBACJ,CAAC;gBAED,OAAO,iBAAiB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YAC5D,CAAC;YAED,OAAO,SAAS,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;YAC9C,MAAM,OAAO,GACX,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB,CAAC;YAC/D,MAAM,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;gBACzD,CAAC,CAAC,wBAAwB;gBAC1B,CAAC,CAAC,uBAAuB,CAAC;YAC5B,SAAS,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,gBAAgB,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAY;IAEZ,0CAA0C;IAC1C,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,MAAM,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAEvC,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC;IAE5D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAA0B,EAAE,EAAE;YAChD,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE;YACpC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YAC9B,MAAM,UAAU,GAAG,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YACvE,OAAO,CAAC,GAAG,CAAC,0CAA0C,UAAU,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACrE,OAAO,CAAC;gBACN,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,GAAG,EAAE;oBACT,MAAM,CAAC,mBAAmB,EAAE,EAAE,CAAC;oBAC/B,MAAM,CAAC,KAAK,EAAE,CAAC;gBACjB,CAAC;aACF,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,22 @@
1
+ export interface Provider {
2
+ name: string;
3
+ url: string;
4
+ key: string;
5
+ openai: boolean;
6
+ anthropic: boolean;
7
+ models: string[];
8
+ }
9
+ export interface Alias {
10
+ name: string;
11
+ targets: {
12
+ provider: string;
13
+ model: string;
14
+ }[];
15
+ fallbackOn: string[];
16
+ }
17
+ export interface EnvConfig {
18
+ port: number;
19
+ providers: Map<string, Provider>;
20
+ aliases: Map<string, Alias>;
21
+ }
22
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC/C,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;CAC7B"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@mini-passy/sdk",
3
+ "version": "0.1.0",
4
+ "description": "Lightweight AI gateway SDK for routing LLM requests",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "README.md",
14
+ ".env.example"
15
+ ],
16
+ "bin": {
17
+ "mini-passy": "./dist/index.js"
18
+ },
19
+ "scripts": {
20
+ "build": "tsc -p tsconfig.build.json",
21
+ "clean": "rm -rf dist",
22
+ "dev": "tsx src/index.ts",
23
+ "start": "node dist/index.js",
24
+ "prepublishOnly": "npm run clean && npm run build"
25
+ },
26
+ "engines": {
27
+ "node": ">=18.0.0"
28
+ },
29
+ "dependencies": {
30
+ "dotenv": "^16.4.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^20.0.0",
34
+ "tsx": "^4.0.0",
35
+ "typescript": "^5.0.0"
36
+ },
37
+ "keywords": [
38
+ "ai",
39
+ "llm",
40
+ "gateway",
41
+ "openai",
42
+ "anthropic",
43
+ "proxy",
44
+ "routing"
45
+ ],
46
+ "license": "MIT",
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "https://github.com/svliantiss/mini-passy.git"
50
+ }
51
+ }