@routerxjs/core 0.0.1
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/dist/chunk-PQO5XDOQ.js +71 -0
- package/dist/chunk-PQO5XDOQ.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/router/index.d.ts +80 -0
- package/dist/router/index.js +7 -0
- package/dist/router/index.js.map +1 -0
- package/package.json +29 -0
- package/src/index.ts +9 -0
- package/src/router/Router.ts +86 -0
- package/src/router/index.ts +7 -0
- package/src/router/types.ts +59 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// src/router/Router.ts
|
|
2
|
+
var Router = class {
|
|
3
|
+
providers;
|
|
4
|
+
defaultProviderId;
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.providers = config.providers;
|
|
7
|
+
this.defaultProviderId = config.defaultProviderId;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Find the best provider for a given model
|
|
11
|
+
*/
|
|
12
|
+
route(model) {
|
|
13
|
+
const candidates = this.providers.filter((p) => p.enabled !== false).filter((p) => p.models.includes(model)).sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));
|
|
14
|
+
if (candidates.length > 0) {
|
|
15
|
+
return { provider: candidates[0], model };
|
|
16
|
+
}
|
|
17
|
+
if (this.defaultProviderId) {
|
|
18
|
+
const defaultProvider = this.providers.find(
|
|
19
|
+
(p) => p.id === this.defaultProviderId && p.enabled !== false
|
|
20
|
+
);
|
|
21
|
+
if (defaultProvider) {
|
|
22
|
+
return { provider: defaultProvider, model };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* List all available models across all providers
|
|
29
|
+
*/
|
|
30
|
+
listModels() {
|
|
31
|
+
const models = [];
|
|
32
|
+
for (const provider of this.providers) {
|
|
33
|
+
if (provider.enabled === false) continue;
|
|
34
|
+
for (const model of provider.models) {
|
|
35
|
+
models.push({
|
|
36
|
+
model,
|
|
37
|
+
providerId: provider.id,
|
|
38
|
+
protocol: provider.protocol
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return models;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Add a provider at runtime
|
|
46
|
+
*/
|
|
47
|
+
addProvider(provider) {
|
|
48
|
+
const existing = this.providers.findIndex((p) => p.id === provider.id);
|
|
49
|
+
if (existing >= 0) {
|
|
50
|
+
this.providers[existing] = provider;
|
|
51
|
+
} else {
|
|
52
|
+
this.providers.push(provider);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Remove a provider
|
|
57
|
+
*/
|
|
58
|
+
removeProvider(id) {
|
|
59
|
+
const idx = this.providers.findIndex((p) => p.id === id);
|
|
60
|
+
if (idx >= 0) {
|
|
61
|
+
this.providers.splice(idx, 1);
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export {
|
|
69
|
+
Router
|
|
70
|
+
};
|
|
71
|
+
//# sourceMappingURL=chunk-PQO5XDOQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/router/Router.ts"],"sourcesContent":["/**\n * Router — model matching and provider selection\n *\n * Given a model name, find the best provider to serve it.\n */\n\nimport type { RegisteredProvider, RouteResult, RouterConfig } from \"./types\";\n\nexport class Router {\n private providers: RegisteredProvider[];\n private defaultProviderId?: string;\n\n constructor(config: RouterConfig) {\n this.providers = config.providers;\n this.defaultProviderId = config.defaultProviderId;\n }\n\n /**\n * Find the best provider for a given model\n */\n route(model: string): RouteResult | null {\n // Find providers that explicitly list this model\n const candidates = this.providers\n .filter((p) => p.enabled !== false)\n .filter((p) => p.models.includes(model))\n .sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));\n\n if (candidates.length > 0) {\n return { provider: candidates[0], model };\n }\n\n // Fallback to default provider\n if (this.defaultProviderId) {\n const defaultProvider = this.providers.find(\n (p) => p.id === this.defaultProviderId && p.enabled !== false\n );\n if (defaultProvider) {\n return { provider: defaultProvider, model };\n }\n }\n\n return null;\n }\n\n /**\n * List all available models across all providers\n */\n listModels(): Array<{ model: string; providerId: string; protocol: string }> {\n const models: Array<{ model: string; providerId: string; protocol: string }> = [];\n for (const provider of this.providers) {\n if (provider.enabled === false) continue;\n for (const model of provider.models) {\n models.push({\n model,\n providerId: provider.id,\n protocol: provider.protocol,\n });\n }\n }\n return models;\n }\n\n /**\n * Add a provider at runtime\n */\n addProvider(provider: RegisteredProvider): void {\n const existing = this.providers.findIndex((p) => p.id === provider.id);\n if (existing >= 0) {\n this.providers[existing] = provider;\n } else {\n this.providers.push(provider);\n }\n }\n\n /**\n * Remove a provider\n */\n removeProvider(id: string): boolean {\n const idx = this.providers.findIndex((p) => p.id === id);\n if (idx >= 0) {\n this.providers.splice(idx, 1);\n return true;\n }\n return false;\n }\n}\n"],"mappings":";AAQO,IAAM,SAAN,MAAa;AAAA,EACV;AAAA,EACA;AAAA,EAER,YAAY,QAAsB;AAChC,SAAK,YAAY,OAAO;AACxB,SAAK,oBAAoB,OAAO;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAmC;AAEvC,UAAM,aAAa,KAAK,UACrB,OAAO,CAAC,MAAM,EAAE,YAAY,KAAK,EACjC,OAAO,CAAC,MAAM,EAAE,OAAO,SAAS,KAAK,CAAC,EACtC,KAAK,CAAC,GAAG,OAAO,EAAE,YAAY,QAAQ,EAAE,YAAY,IAAI;AAE3D,QAAI,WAAW,SAAS,GAAG;AACzB,aAAO,EAAE,UAAU,WAAW,CAAC,GAAG,MAAM;AAAA,IAC1C;AAGA,QAAI,KAAK,mBAAmB;AAC1B,YAAM,kBAAkB,KAAK,UAAU;AAAA,QACrC,CAAC,MAAM,EAAE,OAAO,KAAK,qBAAqB,EAAE,YAAY;AAAA,MAC1D;AACA,UAAI,iBAAiB;AACnB,eAAO,EAAE,UAAU,iBAAiB,MAAM;AAAA,MAC5C;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,aAA6E;AAC3E,UAAM,SAAyE,CAAC;AAChF,eAAW,YAAY,KAAK,WAAW;AACrC,UAAI,SAAS,YAAY,MAAO;AAChC,iBAAW,SAAS,SAAS,QAAQ;AACnC,eAAO,KAAK;AAAA,UACV;AAAA,UACA,YAAY,SAAS;AAAA,UACrB,UAAU,SAAS;AAAA,QACrB,CAAC;AAAA,MACH;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,UAAoC;AAC9C,UAAM,WAAW,KAAK,UAAU,UAAU,CAAC,MAAM,EAAE,OAAO,SAAS,EAAE;AACrE,QAAI,YAAY,GAAG;AACjB,WAAK,UAAU,QAAQ,IAAI;AAAA,IAC7B,OAAO;AACL,WAAK,UAAU,KAAK,QAAQ;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,IAAqB;AAClC,UAAM,MAAM,KAAK,UAAU,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE;AACvD,QAAI,OAAO,GAAG;AACZ,WAAK,UAAU,OAAO,KAAK,CAAC;AAC5B,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AACF;","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ProviderProtocol, RegisteredProvider, RouteResult, Router, RouterConfig } from './router/index.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router Types — routing configuration and model matching
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Supported upstream provider protocols
|
|
6
|
+
*/
|
|
7
|
+
type ProviderProtocol = "openai-compatible" | "anthropic";
|
|
8
|
+
/**
|
|
9
|
+
* A registered upstream provider with its capabilities
|
|
10
|
+
*/
|
|
11
|
+
interface RegisteredProvider {
|
|
12
|
+
/** Unique provider ID */
|
|
13
|
+
id: string;
|
|
14
|
+
/** Display name */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Protocol this provider speaks */
|
|
17
|
+
protocol: ProviderProtocol;
|
|
18
|
+
/** API key */
|
|
19
|
+
apiKey: string;
|
|
20
|
+
/** Custom base URL */
|
|
21
|
+
baseUrl?: string;
|
|
22
|
+
/** Models this provider can serve */
|
|
23
|
+
models: string[];
|
|
24
|
+
/** Priority for model matching (lower = higher priority) */
|
|
25
|
+
priority?: number;
|
|
26
|
+
/** Whether this provider is enabled */
|
|
27
|
+
enabled?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The result of routing a request to a provider
|
|
31
|
+
*/
|
|
32
|
+
interface RouteResult {
|
|
33
|
+
/** The matched provider */
|
|
34
|
+
provider: RegisteredProvider;
|
|
35
|
+
/** The model to use (may be remapped) */
|
|
36
|
+
model: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Router configuration
|
|
40
|
+
*/
|
|
41
|
+
interface RouterConfig {
|
|
42
|
+
/** Registered providers */
|
|
43
|
+
providers: RegisteredProvider[];
|
|
44
|
+
/** Default provider ID (fallback when no model match) */
|
|
45
|
+
defaultProviderId?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Router — model matching and provider selection
|
|
50
|
+
*
|
|
51
|
+
* Given a model name, find the best provider to serve it.
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
declare class Router {
|
|
55
|
+
private providers;
|
|
56
|
+
private defaultProviderId?;
|
|
57
|
+
constructor(config: RouterConfig);
|
|
58
|
+
/**
|
|
59
|
+
* Find the best provider for a given model
|
|
60
|
+
*/
|
|
61
|
+
route(model: string): RouteResult | null;
|
|
62
|
+
/**
|
|
63
|
+
* List all available models across all providers
|
|
64
|
+
*/
|
|
65
|
+
listModels(): Array<{
|
|
66
|
+
model: string;
|
|
67
|
+
providerId: string;
|
|
68
|
+
protocol: string;
|
|
69
|
+
}>;
|
|
70
|
+
/**
|
|
71
|
+
* Add a provider at runtime
|
|
72
|
+
*/
|
|
73
|
+
addProvider(provider: RegisteredProvider): void;
|
|
74
|
+
/**
|
|
75
|
+
* Remove a provider
|
|
76
|
+
*/
|
|
77
|
+
removeProvider(id: string): boolean;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export { type ProviderProtocol, type RegisteredProvider, type RouteResult, Router, type RouterConfig };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@routerxjs/core",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./router": {
|
|
13
|
+
"types": "./dist/router/index.d.ts",
|
|
14
|
+
"import": "./dist/router/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"src"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsup",
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"test": "bun test"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"typescript": "^5.9.3"
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router — model matching and provider selection
|
|
3
|
+
*
|
|
4
|
+
* Given a model name, find the best provider to serve it.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { RegisteredProvider, RouteResult, RouterConfig } from "./types";
|
|
8
|
+
|
|
9
|
+
export class Router {
|
|
10
|
+
private providers: RegisteredProvider[];
|
|
11
|
+
private defaultProviderId?: string;
|
|
12
|
+
|
|
13
|
+
constructor(config: RouterConfig) {
|
|
14
|
+
this.providers = config.providers;
|
|
15
|
+
this.defaultProviderId = config.defaultProviderId;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Find the best provider for a given model
|
|
20
|
+
*/
|
|
21
|
+
route(model: string): RouteResult | null {
|
|
22
|
+
// Find providers that explicitly list this model
|
|
23
|
+
const candidates = this.providers
|
|
24
|
+
.filter((p) => p.enabled !== false)
|
|
25
|
+
.filter((p) => p.models.includes(model))
|
|
26
|
+
.sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));
|
|
27
|
+
|
|
28
|
+
if (candidates.length > 0) {
|
|
29
|
+
return { provider: candidates[0], model };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Fallback to default provider
|
|
33
|
+
if (this.defaultProviderId) {
|
|
34
|
+
const defaultProvider = this.providers.find(
|
|
35
|
+
(p) => p.id === this.defaultProviderId && p.enabled !== false
|
|
36
|
+
);
|
|
37
|
+
if (defaultProvider) {
|
|
38
|
+
return { provider: defaultProvider, model };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* List all available models across all providers
|
|
47
|
+
*/
|
|
48
|
+
listModels(): Array<{ model: string; providerId: string; protocol: string }> {
|
|
49
|
+
const models: Array<{ model: string; providerId: string; protocol: string }> = [];
|
|
50
|
+
for (const provider of this.providers) {
|
|
51
|
+
if (provider.enabled === false) continue;
|
|
52
|
+
for (const model of provider.models) {
|
|
53
|
+
models.push({
|
|
54
|
+
model,
|
|
55
|
+
providerId: provider.id,
|
|
56
|
+
protocol: provider.protocol,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return models;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Add a provider at runtime
|
|
65
|
+
*/
|
|
66
|
+
addProvider(provider: RegisteredProvider): void {
|
|
67
|
+
const existing = this.providers.findIndex((p) => p.id === provider.id);
|
|
68
|
+
if (existing >= 0) {
|
|
69
|
+
this.providers[existing] = provider;
|
|
70
|
+
} else {
|
|
71
|
+
this.providers.push(provider);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Remove a provider
|
|
77
|
+
*/
|
|
78
|
+
removeProvider(id: string): boolean {
|
|
79
|
+
const idx = this.providers.findIndex((p) => p.id === id);
|
|
80
|
+
if (idx >= 0) {
|
|
81
|
+
this.providers.splice(idx, 1);
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router Types — routing configuration and model matching
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Supported upstream provider protocols
|
|
7
|
+
*/
|
|
8
|
+
export type ProviderProtocol = "openai-compatible" | "anthropic";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A registered upstream provider with its capabilities
|
|
12
|
+
*/
|
|
13
|
+
export interface RegisteredProvider {
|
|
14
|
+
/** Unique provider ID */
|
|
15
|
+
id: string;
|
|
16
|
+
|
|
17
|
+
/** Display name */
|
|
18
|
+
name: string;
|
|
19
|
+
|
|
20
|
+
/** Protocol this provider speaks */
|
|
21
|
+
protocol: ProviderProtocol;
|
|
22
|
+
|
|
23
|
+
/** API key */
|
|
24
|
+
apiKey: string;
|
|
25
|
+
|
|
26
|
+
/** Custom base URL */
|
|
27
|
+
baseUrl?: string;
|
|
28
|
+
|
|
29
|
+
/** Models this provider can serve */
|
|
30
|
+
models: string[];
|
|
31
|
+
|
|
32
|
+
/** Priority for model matching (lower = higher priority) */
|
|
33
|
+
priority?: number;
|
|
34
|
+
|
|
35
|
+
/** Whether this provider is enabled */
|
|
36
|
+
enabled?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The result of routing a request to a provider
|
|
41
|
+
*/
|
|
42
|
+
export interface RouteResult {
|
|
43
|
+
/** The matched provider */
|
|
44
|
+
provider: RegisteredProvider;
|
|
45
|
+
|
|
46
|
+
/** The model to use (may be remapped) */
|
|
47
|
+
model: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Router configuration
|
|
52
|
+
*/
|
|
53
|
+
export interface RouterConfig {
|
|
54
|
+
/** Registered providers */
|
|
55
|
+
providers: RegisteredProvider[];
|
|
56
|
+
|
|
57
|
+
/** Default provider ID (fallback when no model match) */
|
|
58
|
+
defaultProviderId?: string;
|
|
59
|
+
}
|