mppx 0.2.5 → 0.3.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/proxy/Proxy.d.ts +4 -0
- package/dist/proxy/Proxy.d.ts.map +1 -1
- package/dist/proxy/Proxy.js +74 -5
- package/dist/proxy/Proxy.js.map +1 -1
- package/dist/proxy/Service.d.ts +33 -6
- package/dist/proxy/Service.d.ts.map +1 -1
- package/dist/proxy/Service.js +73 -33
- package/dist/proxy/Service.js.map +1 -1
- package/dist/proxy/services/anthropic.d.ts.map +1 -1
- package/dist/proxy/services/anthropic.js +2 -0
- package/dist/proxy/services/anthropic.js.map +1 -1
- package/dist/proxy/services/openai.d.ts +1 -0
- package/dist/proxy/services/openai.d.ts.map +1 -1
- package/dist/proxy/services/openai.js +5 -0
- package/dist/proxy/services/openai.js.map +1 -1
- package/dist/proxy/services/stripe.d.ts.map +1 -1
- package/dist/proxy/services/stripe.js +5 -0
- package/dist/proxy/services/stripe.js.map +1 -1
- package/package.json +1 -1
- package/src/proxy/Proxy.test.ts +198 -23
- package/src/proxy/Proxy.ts +93 -5
- package/src/proxy/Service.ts +94 -36
- package/src/proxy/services/anthropic.ts +2 -0
- package/src/proxy/services/openai.ts +7 -0
- package/src/proxy/services/stripe.ts +6 -0
package/dist/proxy/Proxy.d.ts
CHANGED
|
@@ -38,10 +38,14 @@ export declare namespace create {
|
|
|
38
38
|
type Config = {
|
|
39
39
|
/** Base path prefix to strip before routing (e.g. `'/api/proxy'`). */
|
|
40
40
|
basePath?: string | undefined;
|
|
41
|
+
/** Short description of the proxy shown in `llms.txt`. */
|
|
42
|
+
description?: string | undefined;
|
|
41
43
|
/** Custom `fetch` implementation. Defaults to `globalThis.fetch`. */
|
|
42
44
|
fetch?: typeof globalThis.fetch | undefined;
|
|
43
45
|
/** Services to proxy. Each service is mounted at `/{serviceId}/`. */
|
|
44
46
|
services: Service.Service[];
|
|
47
|
+
/** Human-readable title for the proxy shown in `llms.txt`. */
|
|
48
|
+
title?: string | undefined;
|
|
45
49
|
};
|
|
46
50
|
}
|
|
47
51
|
//# sourceMappingURL=Proxy.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Proxy.d.ts","sourceRoot":"","sources":["../../src/proxy/Proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,IAAI,MAAM,WAAW,CAAA;AAKtC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AAEvC,kFAAkF;AAClF,MAAM,MAAM,KAAK,GAAG;IAClB,sFAAsF;IACtF,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC9C,uFAAuF;IACvF,QAAQ,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,KAAK,IAAI,CAAA;CACxE,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,KAAK,
|
|
1
|
+
{"version":3,"file":"Proxy.d.ts","sourceRoot":"","sources":["../../src/proxy/Proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,IAAI,MAAM,WAAW,CAAA;AAKtC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AAEvC,kFAAkF;AAClF,MAAM,MAAM,KAAK,GAAG;IAClB,sFAAsF;IACtF,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC9C,uFAAuF;IACvF,QAAQ,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,KAAK,IAAI,CAAA;CACxE,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,KAAK,CA6HnD;AAED,MAAM,CAAC,OAAO,WAAW,MAAM,CAAC;IAC9B,KAAY,MAAM,GAAG;QACnB,sEAAsE;QACtE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAC7B,0DAA0D;QAC1D,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAChC,qEAAqE;QACrE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,GAAG,SAAS,CAAA;QAC3C,qEAAqE;QACrE,QAAQ,EAAE,OAAO,CAAC,OAAO,EAAE,CAAA;QAC3B,8DAA8D;QAC9D,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAC3B,CAAA;CACF"}
|
package/dist/proxy/Proxy.js
CHANGED
|
@@ -45,17 +45,47 @@ export function create(config) {
|
|
|
45
45
|
if (!pathname)
|
|
46
46
|
return new Response('Not Found', { status: 404 });
|
|
47
47
|
if (request.method === 'GET' && pathname === '/llms.txt')
|
|
48
|
-
return new Response(Service.toLlmsTxt(config.services
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
return new Response(Service.toLlmsTxt(config.services, {
|
|
49
|
+
title: config.title,
|
|
50
|
+
description: config.description,
|
|
51
|
+
}), { headers: { 'Content-Type': 'text/plain; charset=utf-8' } });
|
|
52
|
+
if (request.method === 'GET' && pathname === '/discover.md')
|
|
53
|
+
return new Response(Service.toLlmsTxt(config.services, {
|
|
54
|
+
title: config.title,
|
|
55
|
+
description: config.description,
|
|
56
|
+
}), { headers: { 'Content-Type': 'text/plain; charset=utf-8' } });
|
|
57
|
+
if (request.method === 'GET' && (pathname === '/discover' || pathname === '/discover/')) {
|
|
58
|
+
if (wantsMarkdown(request))
|
|
59
|
+
return new Response(Service.toLlmsTxt(config.services, {
|
|
60
|
+
title: config.title,
|
|
61
|
+
description: config.description,
|
|
62
|
+
}), { headers: { 'Content-Type': 'text/plain; charset=utf-8' } });
|
|
63
|
+
return Response.json(config.services.map(Service.serialize));
|
|
64
|
+
}
|
|
65
|
+
if (request.method === 'GET' &&
|
|
66
|
+
(pathname === '/discover/all' || pathname === '/discover/all/')) {
|
|
67
|
+
if (wantsMarkdown(request))
|
|
68
|
+
return new Response(Service.toServicesMarkdown(config.services), {
|
|
69
|
+
headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
|
|
70
|
+
});
|
|
52
71
|
return Response.json(config.services.map(Service.serialize));
|
|
72
|
+
}
|
|
73
|
+
if (request.method === 'GET' && pathname === '/discover/all.md')
|
|
74
|
+
return new Response(Service.toServicesMarkdown(config.services), {
|
|
75
|
+
headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
|
|
76
|
+
});
|
|
53
77
|
{
|
|
54
|
-
|
|
78
|
+
// List service
|
|
79
|
+
const match = pathname.match(/^\/discover\/([^/]+)\.md$/) ?? pathname.match(/^\/discover\/([^/]+)\/?$/);
|
|
55
80
|
if (request.method === 'GET' && match) {
|
|
56
81
|
const service = config.services.find((s) => s.id === match[1]);
|
|
57
82
|
if (!service)
|
|
58
83
|
return new Response('Not Found', { status: 404 });
|
|
84
|
+
const wantsText = pathname.endsWith('.md') || wantsMarkdown(request);
|
|
85
|
+
if (wantsText)
|
|
86
|
+
return new Response(Service.toMarkdown(service), {
|
|
87
|
+
headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
|
|
88
|
+
});
|
|
59
89
|
return Response.json(Service.serialize(service));
|
|
60
90
|
}
|
|
61
91
|
}
|
|
@@ -123,4 +153,43 @@ async function proxyUpstream(options) {
|
|
|
123
153
|
upstreamRes = await service.rewriteResponse(upstreamRes, ctx);
|
|
124
154
|
return upstreamRes;
|
|
125
155
|
}
|
|
156
|
+
const aiUserAgents = [
|
|
157
|
+
'GPTBot',
|
|
158
|
+
'OAI-SearchBot',
|
|
159
|
+
'ChatGPT-User',
|
|
160
|
+
'anthropic-ai',
|
|
161
|
+
'ClaudeBot',
|
|
162
|
+
'claude-web',
|
|
163
|
+
'PerplexityBot',
|
|
164
|
+
'Perplexity-User',
|
|
165
|
+
'Google-Extended',
|
|
166
|
+
'Googlebot',
|
|
167
|
+
'Bingbot',
|
|
168
|
+
'Amazonbot',
|
|
169
|
+
'Applebot',
|
|
170
|
+
'Applebot-Extended',
|
|
171
|
+
'FacebookBot',
|
|
172
|
+
'meta-externalagent',
|
|
173
|
+
'Bytespider',
|
|
174
|
+
'DuckAssistBot',
|
|
175
|
+
'cohere-ai',
|
|
176
|
+
'AI2Bot',
|
|
177
|
+
'CCBot',
|
|
178
|
+
'Diffbot',
|
|
179
|
+
'YouBot',
|
|
180
|
+
'MistralAI-User',
|
|
181
|
+
'GoogleAgent-Mariner',
|
|
182
|
+
];
|
|
183
|
+
const terminalUserAgents = ['curl', 'Wget', 'HTTPie', 'httpie-go', 'mppx', 'presto', 'xh'];
|
|
184
|
+
function wantsMarkdown(request) {
|
|
185
|
+
const accept = request.headers.get('accept');
|
|
186
|
+
if (accept && (accept.includes('text/markdown') || accept.includes('text/plain')))
|
|
187
|
+
return true;
|
|
188
|
+
const ua = request.headers.get('user-agent') ?? '';
|
|
189
|
+
if (aiUserAgents.some((agent) => ua.includes(agent)))
|
|
190
|
+
return true;
|
|
191
|
+
if (terminalUserAgents.some((agent) => ua.includes(agent)))
|
|
192
|
+
return true;
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
126
195
|
//# sourceMappingURL=Proxy.js.map
|
package/dist/proxy/Proxy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Proxy.js","sourceRoot":"","sources":["../../src/proxy/Proxy.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,KAAK,OAAO,MAAM,sBAAsB,CAAA;AAC/C,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAA;AAChD,OAAO,KAAK,KAAK,MAAM,qBAAqB,CAAA;AAC5C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AAUvC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,MAAM,CAAC,MAAqB;IAC1C,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAA;IAElD,MAAM,QAAQ,GAAG,IAAI,GAAG,CACtB,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACxB,MAAM,KAAK,GAAG,gBAAgB,CAAC,CAAC,CAAC,OAAO,EAAE;YACxC,KAAK,EAAE,SAAS;YAChB,mBAAmB,EAAE,KAAK;YAC1B,iBAAiB,EAAE,KAAK;SACzB,CAAC,CAAA;QACF,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAU,CAAA;IAC/C,CAAC,CAAC,CACH,CAAA;IAED,KAAK,UAAU,MAAM,CAAC,OAA2B;QAC/C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAEhC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;QAErD,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;QAEhE,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,QAAQ,KAAK,WAAW;YACtD,OAAO,IAAI,QAAQ,
|
|
1
|
+
{"version":3,"file":"Proxy.js","sourceRoot":"","sources":["../../src/proxy/Proxy.ts"],"names":[],"mappings":"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"}
|
package/dist/proxy/Service.d.ts
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
/** A proxied upstream service with route definitions and optional request/response hooks. */
|
|
2
2
|
export type Service = {
|
|
3
|
-
/** Unique identifier used as the URL prefix (e.g. `'openai'` → `/{id}/...`). */
|
|
4
|
-
id: string;
|
|
5
3
|
/** Base URL of the upstream service (e.g. `'https://api.openai.com'`). */
|
|
6
4
|
baseUrl: string;
|
|
7
|
-
/**
|
|
8
|
-
|
|
5
|
+
/** Short description of the service. */
|
|
6
|
+
description?: string | undefined;
|
|
7
|
+
/** Unique identifier used as the URL prefix (e.g. `'openai'` → `/{id}/...`). */
|
|
8
|
+
id: string;
|
|
9
|
+
/** Returns a documentation URL. Called with no argument for the service root, or with a route pattern for per-endpoint docs. */
|
|
10
|
+
docsLlmsUrl?: ((options: {
|
|
11
|
+
route?: string | undefined;
|
|
12
|
+
}) => string | undefined) | undefined;
|
|
9
13
|
/** Hook to modify the upstream request before sending (e.g. inject auth headers). */
|
|
10
14
|
rewriteRequest?: ((req: Request, ctx: Context) => Request | Promise<Request>) | undefined;
|
|
11
15
|
/** Hook to modify the upstream response before returning to the client. */
|
|
12
16
|
rewriteResponse?: ((res: Response, ctx: Context) => Response | Promise<Response>) | undefined;
|
|
17
|
+
/** Map of route patterns to endpoint handlers. */
|
|
18
|
+
routes: EndpointMap;
|
|
19
|
+
/** Human-readable title for the service (e.g. `'OpenAI'`). */
|
|
20
|
+
title?: string | undefined;
|
|
13
21
|
};
|
|
14
22
|
/**
|
|
15
23
|
* An endpoint definition.
|
|
@@ -71,30 +79,49 @@ export declare namespace from {
|
|
|
71
79
|
baseUrl: string;
|
|
72
80
|
/** Shorthand: inject `Authorization: Bearer {token}` header. */
|
|
73
81
|
bearer?: string | undefined;
|
|
82
|
+
/** Short description of the service. */
|
|
83
|
+
description?: string | undefined;
|
|
74
84
|
/** Shorthand: inject custom headers. */
|
|
75
85
|
headers?: Record<string, string> | undefined;
|
|
86
|
+
/** Documentation URL for the service. String for a static base URL, or a function receiving an optional endpoint pattern. */
|
|
87
|
+
docsLlmsUrl?: string | ((options: {
|
|
88
|
+
route?: string | undefined;
|
|
89
|
+
}) => string | undefined) | undefined;
|
|
76
90
|
/** Shorthand: full request mutation function. Takes priority over `bearer`/`headers`. */
|
|
77
91
|
mutate?: ((req: Request) => Request | Promise<Request>) | undefined;
|
|
78
92
|
/** Hook to modify the upstream request. Receives typed per-endpoint options via `ctx`. */
|
|
79
93
|
rewriteRequest?: ((req: Request, ctx: Context & Partial<options & {}>) => Request | Promise<Request>) | undefined;
|
|
80
94
|
/** Map of route patterns to endpoint definitions. */
|
|
81
95
|
routes: EndpointMap;
|
|
96
|
+
/** Human-readable title for the service. */
|
|
97
|
+
title?: string | undefined;
|
|
82
98
|
};
|
|
83
99
|
}
|
|
84
100
|
export { from as custom };
|
|
85
101
|
/** Serializes a service for discovery responses. */
|
|
86
102
|
export declare function serialize(s: Service): {
|
|
87
|
-
id: string;
|
|
88
103
|
baseUrl: string;
|
|
104
|
+
description: string | undefined;
|
|
105
|
+
id: string;
|
|
106
|
+
docsLlmsUrl: string | undefined;
|
|
89
107
|
routes: {
|
|
108
|
+
docsLlmsUrl: string | undefined;
|
|
90
109
|
method: string | undefined;
|
|
91
110
|
path: string;
|
|
92
111
|
pattern: string;
|
|
93
112
|
payment: Record<string, unknown> | null;
|
|
94
113
|
}[];
|
|
114
|
+
title: string | undefined;
|
|
95
115
|
};
|
|
96
116
|
/** Renders an llms.txt markdown string for a list of services. */
|
|
97
|
-
export declare function toLlmsTxt(services: Service[]
|
|
117
|
+
export declare function toLlmsTxt(services: Service[], options?: {
|
|
118
|
+
title?: string | undefined;
|
|
119
|
+
description?: string | undefined;
|
|
120
|
+
}): string;
|
|
121
|
+
/** Renders a full markdown listing of all services with their routes. */
|
|
122
|
+
export declare function toServicesMarkdown(services: Service[]): string;
|
|
123
|
+
/** Renders a markdown string for a single service. */
|
|
124
|
+
export declare function toMarkdown(s: Service): string;
|
|
98
125
|
/** Extracts per-endpoint options from an endpoint definition. */
|
|
99
126
|
export declare function getOptions(endpoint: Endpoint): EndpointOptions | undefined;
|
|
100
127
|
//# sourceMappingURL=Service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Service.d.ts","sourceRoot":"","sources":["../../src/proxy/Service.ts"],"names":[],"mappings":"AAEA,6FAA6F;AAC7F,MAAM,MAAM,OAAO,GAAG;IACpB,gFAAgF;IAChF,EAAE,EAAE,MAAM,CAAA;IACV,
|
|
1
|
+
{"version":3,"file":"Service.d.ts","sourceRoot":"","sources":["../../src/proxy/Service.ts"],"names":[],"mappings":"AAEA,6FAA6F;AAC7F,MAAM,MAAM,OAAO,GAAG;IACpB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAA;IACf,wCAAwC;IACxC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,gFAAgF;IAChF,EAAE,EAAE,MAAM,CAAA;IACV,gIAAgI;IAChI,WAAW,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,KAAK,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,CAAA;IAC3F,qFAAqF;IACrF,cAAc,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,SAAS,CAAA;IACzF,2EAA2E;IAC3E,eAAe,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,SAAS,CAAA;IAC7F,kDAAkD;IAClD,MAAM,EAAE,WAAW,CAAA;IACnB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC3B,CAAA;AAED;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,GAAG,aAAa,GAAG;IAAE,GAAG,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,GAAG,IAAI,CAAA;AAE9F,+DAA+D;AAC/D,MAAM,MAAM,WAAW,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,GACzF,MAAM,CAAC,MAAM,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAA;AAE/B,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB,CAAA;AAED,mEAAmE;AACnE,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;AAErE,6FAA6F;AAC7F,MAAM,MAAM,YAAY,GACpB;IAAE,SAAS,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,GACpC;IAAE,MAAM,EAAE,GAAG,CAAC;IAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,KAAK,QAAQ,CAAA;CAAE,CAAA;AAE5E,sGAAsG;AACtG,MAAM,MAAM,OAAO,GAAG;IACpB,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;CACrB,GAAG,eAAe,CAAA;AAEnB,MAAM,MAAM,IAAI,CACd,OAAO,SAAS;IACd,MAAM,EAAE,MAAM,CAAA;CACf,IACC;IACF,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAA;CACvC,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;AAE3B;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,IAAI,CAAC,OAAO,GAAG,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,OAAO,CAkBzF;AAED,MAAM,CAAC,OAAO,WAAW,IAAI,CAAC;IAC5B,KAAY,MAAM,CAAC,OAAO,GAAG,OAAO,IAAI;QACtC,wCAAwC;QACxC,OAAO,EAAE,MAAM,CAAA;QACf,gEAAgE;QAChE,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAC3B,wCAAwC;QACxC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAChC,wCAAwC;QACxC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;QAC5C,6HAA6H;QAC7H,WAAW,CAAC,EACR,MAAM,GACN,CAAC,CAAC,OAAO,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE,KAAK,MAAM,GAAG,SAAS,CAAC,GACjE,SAAS,CAAA;QACb,yFAAyF;QACzF,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,SAAS,CAAA;QACnE,0FAA0F;QAC1F,cAAc,CAAC,EACX,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,GAAG,EAAE,CAAC,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,GACpF,SAAS,CAAA;QACb,qDAAqD;QACrD,MAAM,EAAE,WAAW,CAAA;QACnB,4CAA4C;QAC5C,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAC3B,CAAA;CACF;AAED,OAAO,EAAE,IAAI,IAAI,MAAM,EAAE,CAAA;AAiCzB,oDAAoD;AACpD,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;EAmBnC;AAED,kEAAkE;AAClE,wBAAgB,SAAS,CACvB,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GACzE,MAAM,CAmBR;AAED,yEAAyE;AACzE,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAY9D;AAED,sDAAsD;AACtD,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAO7C;AA6BD,iEAAiE;AACjE,wBAAgB,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,eAAe,GAAG,SAAS,CAI1E"}
|
package/dist/proxy/Service.js
CHANGED
|
@@ -17,9 +17,12 @@ import { Value } from 'ox';
|
|
|
17
17
|
export function from(id, config) {
|
|
18
18
|
const rewriteFromConfig = resolveRewriteRequest(config);
|
|
19
19
|
return {
|
|
20
|
-
id,
|
|
21
20
|
baseUrl: config.baseUrl,
|
|
21
|
+
description: config.description,
|
|
22
|
+
id,
|
|
23
|
+
docsLlmsUrl: resolveLlmsUrl(config.docsLlmsUrl),
|
|
22
24
|
routes: config.routes,
|
|
25
|
+
title: config.title,
|
|
23
26
|
rewriteRequest: config.rewriteRequest
|
|
24
27
|
? rewriteFromConfig
|
|
25
28
|
? async (req, ctx) => {
|
|
@@ -63,66 +66,96 @@ function resolveRewriteRequest(config) {
|
|
|
63
66
|
/** Serializes a service for discovery responses. */
|
|
64
67
|
export function serialize(s) {
|
|
65
68
|
return {
|
|
66
|
-
id: s.id,
|
|
67
69
|
baseUrl: s.baseUrl,
|
|
70
|
+
description: s.description,
|
|
71
|
+
id: s.id,
|
|
72
|
+
docsLlmsUrl: s.docsLlmsUrl?.({}),
|
|
68
73
|
routes: Object.entries(s.routes).map(([pattern, endpoint]) => {
|
|
69
74
|
const tokens = pattern.trim().split(/\s+/);
|
|
70
75
|
const hasMethod = tokens.length >= 2;
|
|
71
76
|
return {
|
|
77
|
+
docsLlmsUrl: s.docsLlmsUrl?.({ route: pattern }),
|
|
72
78
|
method: hasMethod ? tokens[0] : undefined,
|
|
73
79
|
path: hasMethod ? tokens.slice(1).join(' ') : tokens[0],
|
|
74
80
|
pattern,
|
|
75
81
|
payment: endpoint ? resolvePayment(endpoint) : null,
|
|
76
82
|
};
|
|
77
83
|
}),
|
|
84
|
+
title: s.title,
|
|
78
85
|
};
|
|
79
86
|
}
|
|
80
87
|
/** Renders an llms.txt markdown string for a list of services. */
|
|
81
|
-
export function toLlmsTxt(services) {
|
|
88
|
+
export function toLlmsTxt(services, options) {
|
|
82
89
|
const lines = [
|
|
83
|
-
'
|
|
84
|
-
'',
|
|
85
|
-
'> Paid API proxy powered by [Machine Payments Protocol](https://mpp.tempo.xyz).',
|
|
90
|
+
`# ${options?.title ?? 'API Proxy'}`,
|
|
86
91
|
'',
|
|
87
|
-
'
|
|
92
|
+
`> ${options?.description ?? 'Paid API proxy powered by [Machine Payments Protocol](https://mpp.tempo.xyz).'}`,
|
|
88
93
|
'',
|
|
89
94
|
];
|
|
90
95
|
if (services.length === 0)
|
|
91
96
|
return lines.join('\n');
|
|
92
97
|
lines.push('## Services', '');
|
|
93
98
|
for (const s of services) {
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
const parts = [paid && `${paid} paid`, free && `${free} free`].filter(Boolean).join(', ');
|
|
98
|
-
lines.push(`- [${s.id}](${s.baseUrl}): ${parts}`);
|
|
99
|
+
const label = s.title ?? s.id;
|
|
100
|
+
const desc = s.description ? `: ${s.description}` : '';
|
|
101
|
+
lines.push(`- [${label}](/discover/${s.id}.md)${desc}`);
|
|
99
102
|
}
|
|
103
|
+
lines.push('', '[See all service definitions](/discover/all.md)');
|
|
104
|
+
return lines.join('\n');
|
|
105
|
+
}
|
|
106
|
+
/** Renders a full markdown listing of all services with their routes. */
|
|
107
|
+
export function toServicesMarkdown(services) {
|
|
108
|
+
const lines = ['# Services', ''];
|
|
109
|
+
if (services.length === 0)
|
|
110
|
+
return lines.join('\n');
|
|
100
111
|
for (const s of services) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
112
|
+
lines.push(`## [${s.title ?? s.id}](/discover/${s.id}.md)`, '');
|
|
113
|
+
if (s.description)
|
|
114
|
+
lines.push(s.description, '');
|
|
115
|
+
pushRoutes(lines, s);
|
|
116
|
+
}
|
|
117
|
+
return lines.join('\n');
|
|
118
|
+
}
|
|
119
|
+
/** Renders a markdown string for a single service. */
|
|
120
|
+
export function toMarkdown(s) {
|
|
121
|
+
const docsLlmsUrl = s.docsLlmsUrl?.({});
|
|
122
|
+
const lines = [`# ${s.title ?? s.id}`, ''];
|
|
123
|
+
if (docsLlmsUrl)
|
|
124
|
+
lines.push(`> Documentation: ${docsLlmsUrl}`, '');
|
|
125
|
+
if (s.description)
|
|
126
|
+
lines.push(s.description, '');
|
|
127
|
+
pushRoutes(lines, s, '##');
|
|
128
|
+
return lines.join('\n');
|
|
129
|
+
}
|
|
130
|
+
function pushRoutes(lines, s, heading = '###') {
|
|
131
|
+
lines.push(`${heading} Routes`, '');
|
|
132
|
+
const serialized = serialize(s);
|
|
133
|
+
for (const route of serialized.routes) {
|
|
134
|
+
const p = route.payment;
|
|
135
|
+
const desc = p?.description ? `: ${p.description}` : '';
|
|
136
|
+
lines.push(`- \`${route.pattern}\`${desc}`);
|
|
137
|
+
if (!p) {
|
|
138
|
+
lines.push(' - Type: free');
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
lines.push(` - Type: ${p.intent}`);
|
|
110
142
|
if (p.amount) {
|
|
111
|
-
const
|
|
112
|
-
|
|
143
|
+
const perUnit = p.unitType ? `/${p.unitType}` : '';
|
|
144
|
+
if (p.decimals !== undefined) {
|
|
145
|
+
const price = Number(p.amount) / 10 ** Number(p.decimals);
|
|
146
|
+
lines.push(` - Price: ${price}${perUnit} (${p.amount} units, ${p.decimals} decimals)`);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
lines.push(` - Units: ${p.amount}${perUnit}`);
|
|
150
|
+
}
|
|
113
151
|
}
|
|
114
|
-
if (p.
|
|
115
|
-
|
|
116
|
-
const meta = [
|
|
117
|
-
p.currency && `currency: ${p.currency}`,
|
|
118
|
-
p.decimals !== undefined && `decimals: ${p.decimals}`,
|
|
119
|
-
].filter(Boolean);
|
|
120
|
-
if (meta.length)
|
|
121
|
-
parts.push(`(${meta.join(', ')})`);
|
|
122
|
-
lines.push(`- \`${route.pattern}\`: ${parts.join(' — ')}`);
|
|
152
|
+
if (p.currency)
|
|
153
|
+
lines.push(` - Currency: ${p.currency}`);
|
|
123
154
|
}
|
|
155
|
+
if (route.docsLlmsUrl)
|
|
156
|
+
lines.push(` - Docs: ${route.docsLlmsUrl}`);
|
|
157
|
+
lines.push('');
|
|
124
158
|
}
|
|
125
|
-
return lines.join('\n');
|
|
126
159
|
}
|
|
127
160
|
/** Extracts per-endpoint options from an endpoint definition. */
|
|
128
161
|
export function getOptions(endpoint) {
|
|
@@ -144,4 +177,11 @@ function resolvePayment(endpoint) {
|
|
|
144
177
|
})();
|
|
145
178
|
return { intent, method: name, ...rest, ...(amount !== undefined && { amount }) };
|
|
146
179
|
}
|
|
180
|
+
function resolveLlmsUrl(input) {
|
|
181
|
+
if (!input)
|
|
182
|
+
return undefined;
|
|
183
|
+
if (typeof input === 'function')
|
|
184
|
+
return input;
|
|
185
|
+
return ({ route }) => (route ? undefined : input);
|
|
186
|
+
}
|
|
147
187
|
//# sourceMappingURL=Service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Service.js","sourceRoot":"","sources":["../../src/proxy/Service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"Service.js","sourceRoot":"","sources":["../../src/proxy/Service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/proxy/services/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AAExC;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/proxy/services/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AAExC;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,mBAYjD;AAED,MAAM,CAAC,OAAO,WAAW,SAAS,CAAC;IACjC,KAAY,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;QAChC,qDAAqD;QACrD,MAAM,EAAE,MAAM,CAAA;QACd,oEAAoE;QACpE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAC5B,MAAM,EACF,mBAAmB,GACnB,2BAA2B,GAC3B,0BAA0B,GAC1B,mCAAmC,GACnC,mBAAmB,CAAA;KACxB,CAAC,CAAA;CACH"}
|
|
@@ -19,12 +19,14 @@ import * as Service from '../Service.js';
|
|
|
19
19
|
export function anthropic(config) {
|
|
20
20
|
return Service.from('anthropic', {
|
|
21
21
|
baseUrl: config.baseUrl ?? 'https://api.anthropic.com',
|
|
22
|
+
description: 'Claude language models for messages and completions.',
|
|
22
23
|
rewriteRequest(request, ctx) {
|
|
23
24
|
const apiKey = ctx.apiKey ?? config.apiKey;
|
|
24
25
|
request.headers.set('x-api-key', apiKey);
|
|
25
26
|
return request;
|
|
26
27
|
},
|
|
27
28
|
routes: config.routes,
|
|
29
|
+
title: 'Anthropic',
|
|
28
30
|
});
|
|
29
31
|
}
|
|
30
32
|
//# sourceMappingURL=anthropic.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/proxy/services/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AAExC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,SAAS,CAAC,MAAwB;IAChD,OAAO,OAAO,CAAC,IAAI,CAAmB,WAAW,EAAE;QACjD,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,2BAA2B;QACtD,cAAc,CAAC,OAAO,EAAE,GAAG;YACzB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAA;YAC1C,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;YACxC,OAAO,OAAO,CAAA;QAChB,CAAC;QACD,MAAM,EAAE,MAAM,CAAC,MAAM;
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/proxy/services/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AAExC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,SAAS,CAAC,MAAwB;IAChD,OAAO,OAAO,CAAC,IAAI,CAAmB,WAAW,EAAE;QACjD,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,2BAA2B;QACtD,WAAW,EAAE,sDAAsD;QACnE,cAAc,CAAC,OAAO,EAAE,GAAG;YACzB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAA;YAC1C,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;YACxC,OAAO,OAAO,CAAA;QAChB,CAAC;QACD,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,KAAK,EAAE,WAAW;KACnB,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -23,6 +23,7 @@ export declare namespace openai {
|
|
|
23
23
|
apiKey: string;
|
|
24
24
|
/** Base URL override. Defaults to `'https://api.openai.com'`. */
|
|
25
25
|
baseUrl?: string | undefined;
|
|
26
|
+
/** Route definitions for OpenAI endpoints. */
|
|
26
27
|
routes: 'POST /v1/chat/completions' | 'POST /v1/completions' | 'POST /v1/embeddings' | 'POST /v1/images/generations' | 'POST /v1/images/edits' | 'POST /v1/images/variations' | 'POST /v1/audio/transcriptions' | 'POST /v1/audio/translations';
|
|
27
28
|
}>;
|
|
28
29
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/proxy/services/openai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AAExC;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/proxy/services/openai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AAExC;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,mBAgB3C;AAED,MAAM,CAAC,OAAO,WAAW,MAAM,CAAC;IAC9B,KAAY,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;QAChC,8DAA8D;QAC9D,MAAM,EAAE,MAAM,CAAA;QACd,iEAAiE;QACjE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAC5B,8CAA8C;QAC9C,MAAM,EACF,2BAA2B,GAC3B,sBAAsB,GACtB,qBAAqB,GACrB,6BAA6B,GAC7B,uBAAuB,GACvB,4BAA4B,GAC5B,+BAA+B,GAC/B,6BAA6B,CAAA;KAClC,CAAC,CAAA;CACH"}
|
|
@@ -19,12 +19,17 @@ import * as Service from '../Service.js';
|
|
|
19
19
|
export function openai(config) {
|
|
20
20
|
return Service.from('openai', {
|
|
21
21
|
baseUrl: config.baseUrl ?? 'https://api.openai.com',
|
|
22
|
+
description: 'Chat completions, embeddings, image generation, and audio transcription.',
|
|
23
|
+
docsLlmsUrl: ({ route }) => route
|
|
24
|
+
? `https://context7.com/websites/platform_openai/llms.txt?topic=${encodeURIComponent(route)}`
|
|
25
|
+
: 'https://context7.com/websites/platform_openai/llms.txt',
|
|
22
26
|
rewriteRequest(request, ctx) {
|
|
23
27
|
const apiKey = ctx.apiKey ?? config.apiKey;
|
|
24
28
|
request.headers.set('Authorization', `Bearer ${apiKey}`);
|
|
25
29
|
return request;
|
|
26
30
|
},
|
|
27
31
|
routes: config.routes,
|
|
32
|
+
title: 'OpenAI',
|
|
28
33
|
});
|
|
29
34
|
}
|
|
30
35
|
//# sourceMappingURL=openai.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/proxy/services/openai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AAExC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,MAAM,CAAC,MAAqB;IAC1C,OAAO,OAAO,CAAC,IAAI,CAAgB,QAAQ,EAAE;QAC3C,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,wBAAwB;QACnD,cAAc,CAAC,OAAO,EAAE,GAAG;YACzB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAA;YAC1C,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,MAAM,EAAE,CAAC,CAAA;YACxD,OAAO,OAAO,CAAA;QAChB,CAAC;QACD,MAAM,EAAE,MAAM,CAAC,MAAM;
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/proxy/services/openai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AAExC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,MAAM,CAAC,MAAqB;IAC1C,OAAO,OAAO,CAAC,IAAI,CAAgB,QAAQ,EAAE;QAC3C,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,wBAAwB;QACnD,WAAW,EAAE,0EAA0E;QACvF,WAAW,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CACzB,KAAK;YACH,CAAC,CAAC,gEAAgE,kBAAkB,CAAC,KAAK,CAAC,EAAE;YAC7F,CAAC,CAAC,wDAAwD;QAC9D,cAAc,CAAC,OAAO,EAAE,GAAG;YACzB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAA;YAC1C,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,MAAM,EAAE,CAAC,CAAA;YACxD,OAAO,OAAO,CAAA;QAChB,CAAC;QACD,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,KAAK,EAAE,QAAQ;KAChB,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stripe.d.ts","sourceRoot":"","sources":["../../../src/proxy/services/stripe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AAExC;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"stripe.d.ts","sourceRoot":"","sources":["../../../src/proxy/services/stripe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AAExC;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,mBAgB3C;AAED,MAAM,CAAC,OAAO,WAAW,MAAM,CAAC;IAC9B,KAAY,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;QAChC,mDAAmD;QACnD,MAAM,EAAE,MAAM,CAAA;QACd,iEAAiE;QACjE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAC5B,MAAM,EACF,kBAAkB,GAClB,oBAAoB,GACpB,uBAAuB,GACvB,0BAA0B,GAC1B,6BAA6B,GAC7B,wBAAwB,GACxB,2BAA2B,GAC3B,mBAAmB,GACnB,sBAAsB,CAAA;KAC3B,CAAC,CAAA;CACH"}
|
|
@@ -19,12 +19,17 @@ import * as Service from '../Service.js';
|
|
|
19
19
|
export function stripe(config) {
|
|
20
20
|
return Service.from('stripe', {
|
|
21
21
|
baseUrl: config.baseUrl ?? 'https://api.stripe.com',
|
|
22
|
+
description: 'Payment processing, customers, subscriptions, and invoices.',
|
|
23
|
+
docsLlmsUrl: ({ route }) => route
|
|
24
|
+
? `https://context7.com/websites/stripe/llms.txt?topic=${encodeURIComponent(route)}`
|
|
25
|
+
: 'https://docs.stripe.com/llms.txt',
|
|
22
26
|
rewriteRequest(request, ctx) {
|
|
23
27
|
const apiKey = ctx.apiKey ?? config.apiKey;
|
|
24
28
|
request.headers.set('Authorization', `Basic ${btoa(`${apiKey}:`)}`);
|
|
25
29
|
return request;
|
|
26
30
|
},
|
|
27
31
|
routes: config.routes,
|
|
32
|
+
title: 'Stripe',
|
|
28
33
|
});
|
|
29
34
|
}
|
|
30
35
|
//# sourceMappingURL=stripe.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stripe.js","sourceRoot":"","sources":["../../../src/proxy/services/stripe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AAExC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,MAAM,CAAC,MAAqB;IAC1C,OAAO,OAAO,CAAC,IAAI,CAAgB,QAAQ,EAAE;QAC3C,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,wBAAwB;QACnD,cAAc,CAAC,OAAO,EAAE,GAAG;YACzB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAA;YAC1C,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,SAAS,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,CAAA;YACnE,OAAO,OAAO,CAAA;QAChB,CAAC;QACD,MAAM,EAAE,MAAM,CAAC,MAAM;
|
|
1
|
+
{"version":3,"file":"stripe.js","sourceRoot":"","sources":["../../../src/proxy/services/stripe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AAExC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,MAAM,CAAC,MAAqB;IAC1C,OAAO,OAAO,CAAC,IAAI,CAAgB,QAAQ,EAAE;QAC3C,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,wBAAwB;QACnD,WAAW,EAAE,6DAA6D;QAC1E,WAAW,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CACzB,KAAK;YACH,CAAC,CAAC,uDAAuD,kBAAkB,CAAC,KAAK,CAAC,EAAE;YACpF,CAAC,CAAC,kCAAkC;QACxC,cAAc,CAAC,OAAO,EAAE,GAAG;YACzB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAA;YAC1C,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,SAAS,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,CAAA;YACnE,OAAO,OAAO,CAAA;QAChB,CAAC;QACD,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,KAAK,EAAE,QAAQ;KAChB,CAAC,CAAA;AACJ,CAAC"}
|
package/package.json
CHANGED
package/src/proxy/Proxy.test.ts
CHANGED
|
@@ -61,7 +61,7 @@ function createUpstream(handler: (req: Request) => Response | Promise<Response>)
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
describe('create', () => {
|
|
64
|
-
test('behavior: GET /
|
|
64
|
+
test('behavior: GET /discover/all returns service discovery JSON', async () => {
|
|
65
65
|
const proxy = ApiProxy.create({
|
|
66
66
|
services: [
|
|
67
67
|
Service.from('api', {
|
|
@@ -80,7 +80,7 @@ describe('create', () => {
|
|
|
80
80
|
})
|
|
81
81
|
proxyServer = await Http.createServer(proxy.listener)
|
|
82
82
|
|
|
83
|
-
const res = await fetch(`${proxyServer.url}/
|
|
83
|
+
const res = await fetch(`${proxyServer.url}/discover/all`)
|
|
84
84
|
expect(res.status).toBe(200)
|
|
85
85
|
expect(await res.json()).toMatchInlineSnapshot(`
|
|
86
86
|
[
|
|
@@ -129,8 +129,28 @@ describe('create', () => {
|
|
|
129
129
|
`)
|
|
130
130
|
})
|
|
131
131
|
|
|
132
|
-
test('behavior: GET /
|
|
132
|
+
test('behavior: GET /discover returns JSON by default', async () => {
|
|
133
133
|
const proxy = ApiProxy.create({
|
|
134
|
+
services: [
|
|
135
|
+
Service.from('api', {
|
|
136
|
+
baseUrl: 'https://api.example.com',
|
|
137
|
+
routes: {
|
|
138
|
+
'GET /v1/models': true,
|
|
139
|
+
},
|
|
140
|
+
}),
|
|
141
|
+
],
|
|
142
|
+
})
|
|
143
|
+
proxyServer = await Http.createServer(proxy.listener)
|
|
144
|
+
|
|
145
|
+
const res = await fetch(`${proxyServer.url}/discover`)
|
|
146
|
+
expect(res.status).toBe(200)
|
|
147
|
+
expect(res.headers.get('content-type')).toMatchInlineSnapshot(`"application/json"`)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
test('behavior: GET /discover returns llms.txt for markdown clients', async () => {
|
|
151
|
+
const proxy = ApiProxy.create({
|
|
152
|
+
title: 'My AI Gateway',
|
|
153
|
+
description: 'A paid proxy for LLM and AI services.',
|
|
134
154
|
services: [
|
|
135
155
|
openai({
|
|
136
156
|
apiKey: 'sk-test',
|
|
@@ -163,34 +183,26 @@ describe('create', () => {
|
|
|
163
183
|
})
|
|
164
184
|
proxyServer = await Http.createServer(proxy.listener)
|
|
165
185
|
|
|
166
|
-
const res = await fetch(`${proxyServer.url}/
|
|
186
|
+
const res = await fetch(`${proxyServer.url}/discover`, {
|
|
187
|
+
headers: { Accept: 'text/plain' },
|
|
188
|
+
})
|
|
167
189
|
expect(res.status).toBe(200)
|
|
168
190
|
expect(res.headers.get('content-type')).toBe('text/plain; charset=utf-8')
|
|
169
191
|
expect(await res.text()).toMatchInlineSnapshot(`
|
|
170
|
-
"#
|
|
171
|
-
|
|
172
|
-
> Paid API proxy powered by [Machine Payments Protocol](https://mpp.tempo.xyz).
|
|
192
|
+
"# My AI Gateway
|
|
173
193
|
|
|
174
|
-
|
|
194
|
+
> A paid proxy for LLM and AI services.
|
|
175
195
|
|
|
176
196
|
## Services
|
|
177
197
|
|
|
178
|
-
- [
|
|
179
|
-
- [
|
|
198
|
+
- [OpenAI](/discover/openai.md): Chat completions, embeddings, image generation, and audio transcription.
|
|
199
|
+
- [Anthropic](/discover/anthropic.md): Claude language models for messages and completions.
|
|
180
200
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
- \`POST /v1/chat/completions\`: charge — 50000 units — "Chat completion" — (currency: 0x20c0000000000000000000000000000000000001, decimals: 6)
|
|
184
|
-
- \`POST /v1/embeddings\`: charge — 10000 units — "Generate embeddings" — (currency: 0x20c0000000000000000000000000000000000001, decimals: 6)
|
|
185
|
-
|
|
186
|
-
## anthropic
|
|
187
|
-
|
|
188
|
-
- \`POST /v1/messages\`: charge — 30000 units — "Send message" — (currency: 0x20c0000000000000000000000000000000000001, decimals: 6)
|
|
189
|
-
- \`POST /v1/messages/stream\`: session — 10000 units per token — "Stream message" — (currency: 0x20c0000000000000000000000000000000000001, decimals: 6)"
|
|
201
|
+
[See all service definitions](/discover/all.md)"
|
|
190
202
|
`)
|
|
191
203
|
})
|
|
192
204
|
|
|
193
|
-
test('behavior: GET /
|
|
205
|
+
test('behavior: GET /discover/:id returns single service', async () => {
|
|
194
206
|
const proxy = ApiProxy.create({
|
|
195
207
|
services: [
|
|
196
208
|
Service.from('api', {
|
|
@@ -204,7 +216,7 @@ describe('create', () => {
|
|
|
204
216
|
})
|
|
205
217
|
proxyServer = await Http.createServer(proxy.listener)
|
|
206
218
|
|
|
207
|
-
const res = await fetch(`${proxyServer.url}/
|
|
219
|
+
const res = await fetch(`${proxyServer.url}/discover/api`)
|
|
208
220
|
expect(res.status).toBe(200)
|
|
209
221
|
expect(await res.json()).toMatchInlineSnapshot(`
|
|
210
222
|
{
|
|
@@ -236,10 +248,173 @@ describe('create', () => {
|
|
|
236
248
|
`)
|
|
237
249
|
})
|
|
238
250
|
|
|
239
|
-
test('behavior: GET /
|
|
251
|
+
test('behavior: GET /discover/all.md returns full markdown with routes', async () => {
|
|
252
|
+
const proxy = ApiProxy.create({
|
|
253
|
+
services: [
|
|
254
|
+
openai({
|
|
255
|
+
apiKey: 'sk-test',
|
|
256
|
+
routes: {
|
|
257
|
+
'POST /v1/chat/completions': mppx_server.charge({
|
|
258
|
+
amount: '0.05',
|
|
259
|
+
description: 'Chat completion',
|
|
260
|
+
}),
|
|
261
|
+
'GET /v1/models': true,
|
|
262
|
+
},
|
|
263
|
+
}),
|
|
264
|
+
anthropic({
|
|
265
|
+
apiKey: 'sk-ant-test',
|
|
266
|
+
routes: {
|
|
267
|
+
'POST /v1/messages': mppx_server.charge({
|
|
268
|
+
amount: '0.03',
|
|
269
|
+
description: 'Send message',
|
|
270
|
+
}),
|
|
271
|
+
},
|
|
272
|
+
}),
|
|
273
|
+
],
|
|
274
|
+
})
|
|
275
|
+
proxyServer = await Http.createServer(proxy.listener)
|
|
276
|
+
|
|
277
|
+
const res = await fetch(`${proxyServer.url}/discover/all.md`)
|
|
278
|
+
expect(res.status).toBe(200)
|
|
279
|
+
expect(res.headers.get('content-type')).toBe('text/markdown; charset=utf-8')
|
|
280
|
+
expect(await res.text()).toMatchInlineSnapshot(`
|
|
281
|
+
"# Services
|
|
282
|
+
|
|
283
|
+
## [OpenAI](/discover/openai.md)
|
|
284
|
+
|
|
285
|
+
Chat completions, embeddings, image generation, and audio transcription.
|
|
286
|
+
|
|
287
|
+
### Routes
|
|
288
|
+
|
|
289
|
+
- \`POST /v1/chat/completions\`: Chat completion
|
|
290
|
+
- Type: charge
|
|
291
|
+
- Price: 0.05 (50000 units, 6 decimals)
|
|
292
|
+
- Currency: 0x20c0000000000000000000000000000000000001
|
|
293
|
+
- Docs: https://context7.com/websites/platform_openai/llms.txt?topic=POST%20%2Fv1%2Fchat%2Fcompletions
|
|
294
|
+
|
|
295
|
+
- \`GET /v1/models\`
|
|
296
|
+
- Type: free
|
|
297
|
+
- Docs: https://context7.com/websites/platform_openai/llms.txt?topic=GET%20%2Fv1%2Fmodels
|
|
298
|
+
|
|
299
|
+
## [Anthropic](/discover/anthropic.md)
|
|
300
|
+
|
|
301
|
+
Claude language models for messages and completions.
|
|
302
|
+
|
|
303
|
+
### Routes
|
|
304
|
+
|
|
305
|
+
- \`POST /v1/messages\`: Send message
|
|
306
|
+
- Type: charge
|
|
307
|
+
- Price: 0.03 (30000 units, 6 decimals)
|
|
308
|
+
- Currency: 0x20c0000000000000000000000000000000000001
|
|
309
|
+
"
|
|
310
|
+
`)
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
test('behavior: GET /discover/:id.md returns markdown', async () => {
|
|
314
|
+
const proxy = ApiProxy.create({
|
|
315
|
+
services: [
|
|
316
|
+
openai({
|
|
317
|
+
apiKey: 'sk-test',
|
|
318
|
+
routes: {
|
|
319
|
+
'POST /v1/chat/completions': mppx_server.charge({
|
|
320
|
+
amount: '0.05',
|
|
321
|
+
description: 'Chat completion',
|
|
322
|
+
}),
|
|
323
|
+
'GET /v1/models': true,
|
|
324
|
+
},
|
|
325
|
+
}),
|
|
326
|
+
anthropic({
|
|
327
|
+
apiKey: 'sk-ant-test',
|
|
328
|
+
routes: {
|
|
329
|
+
'POST /v1/messages': mppx_server.charge({ amount: '0.03' }),
|
|
330
|
+
},
|
|
331
|
+
}),
|
|
332
|
+
],
|
|
333
|
+
})
|
|
334
|
+
proxyServer = await Http.createServer(proxy.listener)
|
|
335
|
+
|
|
336
|
+
const res = await fetch(`${proxyServer.url}/discover/openai.md`)
|
|
337
|
+
expect(res.status).toBe(200)
|
|
338
|
+
expect(res.headers.get('content-type')).toBe('text/markdown; charset=utf-8')
|
|
339
|
+
expect(await res.text()).toMatchInlineSnapshot(`
|
|
340
|
+
"# OpenAI
|
|
341
|
+
|
|
342
|
+
> Documentation: https://context7.com/websites/platform_openai/llms.txt
|
|
343
|
+
|
|
344
|
+
Chat completions, embeddings, image generation, and audio transcription.
|
|
345
|
+
|
|
346
|
+
## Routes
|
|
347
|
+
|
|
348
|
+
- \`POST /v1/chat/completions\`: Chat completion
|
|
349
|
+
- Type: charge
|
|
350
|
+
- Price: 0.05 (50000 units, 6 decimals)
|
|
351
|
+
- Currency: 0x20c0000000000000000000000000000000000001
|
|
352
|
+
- Docs: https://context7.com/websites/platform_openai/llms.txt?topic=POST%20%2Fv1%2Fchat%2Fcompletions
|
|
353
|
+
|
|
354
|
+
- \`GET /v1/models\`
|
|
355
|
+
- Type: free
|
|
356
|
+
- Docs: https://context7.com/websites/platform_openai/llms.txt?topic=GET%20%2Fv1%2Fmodels
|
|
357
|
+
"
|
|
358
|
+
`)
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
test('behavior: GET /discover/:id with Accept: text/markdown returns markdown', async () => {
|
|
362
|
+
const proxy = ApiProxy.create({
|
|
363
|
+
services: [
|
|
364
|
+
openai({
|
|
365
|
+
apiKey: 'sk-test',
|
|
366
|
+
routes: { 'GET /v1/models': true },
|
|
367
|
+
}),
|
|
368
|
+
anthropic({
|
|
369
|
+
apiKey: 'sk-ant-test',
|
|
370
|
+
routes: {
|
|
371
|
+
'POST /v1/messages': mppx_server.charge({ amount: '0.03' }),
|
|
372
|
+
},
|
|
373
|
+
}),
|
|
374
|
+
],
|
|
375
|
+
})
|
|
376
|
+
proxyServer = await Http.createServer(proxy.listener)
|
|
377
|
+
|
|
378
|
+
const res = await fetch(`${proxyServer.url}/discover/anthropic`, {
|
|
379
|
+
headers: { Accept: 'text/markdown' },
|
|
380
|
+
})
|
|
381
|
+
expect(res.status).toBe(200)
|
|
382
|
+
expect(res.headers.get('content-type')).toBe('text/markdown; charset=utf-8')
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
test('behavior: GET /discover/:id without Accept returns JSON', async () => {
|
|
386
|
+
const proxy = ApiProxy.create({
|
|
387
|
+
services: [
|
|
388
|
+
openai({
|
|
389
|
+
apiKey: 'sk-test',
|
|
390
|
+
routes: { 'GET /v1/models': true },
|
|
391
|
+
}),
|
|
392
|
+
anthropic({
|
|
393
|
+
apiKey: 'sk-ant-test',
|
|
394
|
+
routes: {
|
|
395
|
+
'POST /v1/messages': mppx_server.charge({ amount: '0.03' }),
|
|
396
|
+
},
|
|
397
|
+
}),
|
|
398
|
+
],
|
|
399
|
+
})
|
|
400
|
+
proxyServer = await Http.createServer(proxy.listener)
|
|
401
|
+
|
|
402
|
+
const res = await fetch(`${proxyServer.url}/discover/openai`)
|
|
403
|
+
expect(res.status).toBe(200)
|
|
404
|
+
expect(res.headers.get('content-type')).toMatchInlineSnapshot(`"application/json"`)
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
test('behavior: GET /discover/:id.md returns 404 for unknown', async () => {
|
|
408
|
+
const proxy = ApiProxy.create({ services: [] })
|
|
409
|
+
proxyServer = await Http.createServer(proxy.listener)
|
|
410
|
+
const res = await fetch(`${proxyServer.url}/discover/unknown.md`)
|
|
411
|
+
expect(res.status).toBe(404)
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
test('behavior: GET /discover/:id returns 404 for unknown', async () => {
|
|
240
415
|
const proxy = ApiProxy.create({ services: [] })
|
|
241
416
|
proxyServer = await Http.createServer(proxy.listener)
|
|
242
|
-
const res = await fetch(`${proxyServer.url}/
|
|
417
|
+
const res = await fetch(`${proxyServer.url}/discover/unknown`)
|
|
243
418
|
expect(res.status).toBe(404)
|
|
244
419
|
})
|
|
245
420
|
|
package/src/proxy/Proxy.ts
CHANGED
|
@@ -61,18 +61,63 @@ export function create(config: create.Config): Proxy {
|
|
|
61
61
|
if (!pathname) return new Response('Not Found', { status: 404 })
|
|
62
62
|
|
|
63
63
|
if (request.method === 'GET' && pathname === '/llms.txt')
|
|
64
|
-
return new Response(
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
return new Response(
|
|
65
|
+
Service.toLlmsTxt(config.services, {
|
|
66
|
+
title: config.title,
|
|
67
|
+
description: config.description,
|
|
68
|
+
}),
|
|
69
|
+
{ headers: { 'Content-Type': 'text/plain; charset=utf-8' } },
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
if (request.method === 'GET' && pathname === '/discover.md')
|
|
73
|
+
return new Response(
|
|
74
|
+
Service.toLlmsTxt(config.services, {
|
|
75
|
+
title: config.title,
|
|
76
|
+
description: config.description,
|
|
77
|
+
}),
|
|
78
|
+
{ headers: { 'Content-Type': 'text/plain; charset=utf-8' } },
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
if (request.method === 'GET' && (pathname === '/discover' || pathname === '/discover/')) {
|
|
82
|
+
if (wantsMarkdown(request))
|
|
83
|
+
return new Response(
|
|
84
|
+
Service.toLlmsTxt(config.services, {
|
|
85
|
+
title: config.title,
|
|
86
|
+
description: config.description,
|
|
87
|
+
}),
|
|
88
|
+
{ headers: { 'Content-Type': 'text/plain; charset=utf-8' } },
|
|
89
|
+
)
|
|
90
|
+
return Response.json(config.services.map(Service.serialize))
|
|
91
|
+
}
|
|
67
92
|
|
|
68
|
-
if (
|
|
93
|
+
if (
|
|
94
|
+
request.method === 'GET' &&
|
|
95
|
+
(pathname === '/discover/all' || pathname === '/discover/all/')
|
|
96
|
+
) {
|
|
97
|
+
if (wantsMarkdown(request))
|
|
98
|
+
return new Response(Service.toServicesMarkdown(config.services), {
|
|
99
|
+
headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
|
|
100
|
+
})
|
|
69
101
|
return Response.json(config.services.map(Service.serialize))
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (request.method === 'GET' && pathname === '/discover/all.md')
|
|
105
|
+
return new Response(Service.toServicesMarkdown(config.services), {
|
|
106
|
+
headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
|
|
107
|
+
})
|
|
70
108
|
|
|
71
109
|
{
|
|
72
|
-
|
|
110
|
+
// List service
|
|
111
|
+
const match =
|
|
112
|
+
pathname.match(/^\/discover\/([^/]+)\.md$/) ?? pathname.match(/^\/discover\/([^/]+)\/?$/)
|
|
73
113
|
if (request.method === 'GET' && match) {
|
|
74
114
|
const service = config.services.find((s) => s.id === match[1])
|
|
75
115
|
if (!service) return new Response('Not Found', { status: 404 })
|
|
116
|
+
const wantsText = pathname.endsWith('.md') || wantsMarkdown(request)
|
|
117
|
+
if (wantsText)
|
|
118
|
+
return new Response(Service.toMarkdown(service), {
|
|
119
|
+
headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
|
|
120
|
+
})
|
|
76
121
|
return Response.json(Service.serialize(service))
|
|
77
122
|
}
|
|
78
123
|
}
|
|
@@ -125,10 +170,14 @@ export declare namespace create {
|
|
|
125
170
|
export type Config = {
|
|
126
171
|
/** Base path prefix to strip before routing (e.g. `'/api/proxy'`). */
|
|
127
172
|
basePath?: string | undefined
|
|
173
|
+
/** Short description of the proxy shown in `llms.txt`. */
|
|
174
|
+
description?: string | undefined
|
|
128
175
|
/** Custom `fetch` implementation. Defaults to `globalThis.fetch`. */
|
|
129
176
|
fetch?: typeof globalThis.fetch | undefined
|
|
130
177
|
/** Services to proxy. Each service is mounted at `/{serviceId}/`. */
|
|
131
178
|
services: Service.Service[]
|
|
179
|
+
/** Human-readable title for the proxy shown in `llms.txt`. */
|
|
180
|
+
title?: string | undefined
|
|
132
181
|
}
|
|
133
182
|
}
|
|
134
183
|
|
|
@@ -173,3 +222,42 @@ async function proxyUpstream(options: proxyUpstream.Options): Promise<Response>
|
|
|
173
222
|
|
|
174
223
|
return upstreamRes
|
|
175
224
|
}
|
|
225
|
+
|
|
226
|
+
const aiUserAgents = [
|
|
227
|
+
'GPTBot',
|
|
228
|
+
'OAI-SearchBot',
|
|
229
|
+
'ChatGPT-User',
|
|
230
|
+
'anthropic-ai',
|
|
231
|
+
'ClaudeBot',
|
|
232
|
+
'claude-web',
|
|
233
|
+
'PerplexityBot',
|
|
234
|
+
'Perplexity-User',
|
|
235
|
+
'Google-Extended',
|
|
236
|
+
'Googlebot',
|
|
237
|
+
'Bingbot',
|
|
238
|
+
'Amazonbot',
|
|
239
|
+
'Applebot',
|
|
240
|
+
'Applebot-Extended',
|
|
241
|
+
'FacebookBot',
|
|
242
|
+
'meta-externalagent',
|
|
243
|
+
'Bytespider',
|
|
244
|
+
'DuckAssistBot',
|
|
245
|
+
'cohere-ai',
|
|
246
|
+
'AI2Bot',
|
|
247
|
+
'CCBot',
|
|
248
|
+
'Diffbot',
|
|
249
|
+
'YouBot',
|
|
250
|
+
'MistralAI-User',
|
|
251
|
+
'GoogleAgent-Mariner',
|
|
252
|
+
]
|
|
253
|
+
|
|
254
|
+
const terminalUserAgents = ['curl', 'Wget', 'HTTPie', 'httpie-go', 'mppx', 'presto', 'xh']
|
|
255
|
+
|
|
256
|
+
function wantsMarkdown(request: globalThis.Request): boolean {
|
|
257
|
+
const accept = request.headers.get('accept')
|
|
258
|
+
if (accept && (accept.includes('text/markdown') || accept.includes('text/plain'))) return true
|
|
259
|
+
const ua = request.headers.get('user-agent') ?? ''
|
|
260
|
+
if (aiUserAgents.some((agent) => ua.includes(agent))) return true
|
|
261
|
+
if (terminalUserAgents.some((agent) => ua.includes(agent))) return true
|
|
262
|
+
return false
|
|
263
|
+
}
|
package/src/proxy/Service.ts
CHANGED
|
@@ -2,16 +2,22 @@ import { Value } from 'ox'
|
|
|
2
2
|
|
|
3
3
|
/** A proxied upstream service with route definitions and optional request/response hooks. */
|
|
4
4
|
export type Service = {
|
|
5
|
-
/** Unique identifier used as the URL prefix (e.g. `'openai'` → `/{id}/...`). */
|
|
6
|
-
id: string
|
|
7
5
|
/** Base URL of the upstream service (e.g. `'https://api.openai.com'`). */
|
|
8
6
|
baseUrl: string
|
|
9
|
-
/**
|
|
10
|
-
|
|
7
|
+
/** Short description of the service. */
|
|
8
|
+
description?: string | undefined
|
|
9
|
+
/** Unique identifier used as the URL prefix (e.g. `'openai'` → `/{id}/...`). */
|
|
10
|
+
id: string
|
|
11
|
+
/** Returns a documentation URL. Called with no argument for the service root, or with a route pattern for per-endpoint docs. */
|
|
12
|
+
docsLlmsUrl?: ((options: { route?: string | undefined }) => string | undefined) | undefined
|
|
11
13
|
/** Hook to modify the upstream request before sending (e.g. inject auth headers). */
|
|
12
14
|
rewriteRequest?: ((req: Request, ctx: Context) => Request | Promise<Request>) | undefined
|
|
13
15
|
/** Hook to modify the upstream response before returning to the client. */
|
|
14
16
|
rewriteResponse?: ((res: Response, ctx: Context) => Response | Promise<Response>) | undefined
|
|
17
|
+
/** Map of route patterns to endpoint handlers. */
|
|
18
|
+
routes: EndpointMap
|
|
19
|
+
/** Human-readable title for the service (e.g. `'OpenAI'`). */
|
|
20
|
+
title?: string | undefined
|
|
15
21
|
}
|
|
16
22
|
|
|
17
23
|
/**
|
|
@@ -73,9 +79,12 @@ export type From<
|
|
|
73
79
|
export function from<options = unknown>(id: string, config: from.Config<options>): Service {
|
|
74
80
|
const rewriteFromConfig = resolveRewriteRequest(config)
|
|
75
81
|
return {
|
|
76
|
-
id,
|
|
77
82
|
baseUrl: config.baseUrl,
|
|
83
|
+
description: config.description,
|
|
84
|
+
id,
|
|
85
|
+
docsLlmsUrl: resolveLlmsUrl(config.docsLlmsUrl),
|
|
78
86
|
routes: config.routes,
|
|
87
|
+
title: config.title,
|
|
79
88
|
rewriteRequest: config.rewriteRequest
|
|
80
89
|
? rewriteFromConfig
|
|
81
90
|
? async (req, ctx) => {
|
|
@@ -93,8 +102,15 @@ export declare namespace from {
|
|
|
93
102
|
baseUrl: string
|
|
94
103
|
/** Shorthand: inject `Authorization: Bearer {token}` header. */
|
|
95
104
|
bearer?: string | undefined
|
|
105
|
+
/** Short description of the service. */
|
|
106
|
+
description?: string | undefined
|
|
96
107
|
/** Shorthand: inject custom headers. */
|
|
97
108
|
headers?: Record<string, string> | undefined
|
|
109
|
+
/** Documentation URL for the service. String for a static base URL, or a function receiving an optional endpoint pattern. */
|
|
110
|
+
docsLlmsUrl?:
|
|
111
|
+
| string
|
|
112
|
+
| ((options: { route?: string | undefined }) => string | undefined)
|
|
113
|
+
| undefined
|
|
98
114
|
/** Shorthand: full request mutation function. Takes priority over `bearer`/`headers`. */
|
|
99
115
|
mutate?: ((req: Request) => Request | Promise<Request>) | undefined
|
|
100
116
|
/** Hook to modify the upstream request. Receives typed per-endpoint options via `ctx`. */
|
|
@@ -103,6 +119,8 @@ export declare namespace from {
|
|
|
103
119
|
| undefined
|
|
104
120
|
/** Map of route patterns to endpoint definitions. */
|
|
105
121
|
routes: EndpointMap
|
|
122
|
+
/** Human-readable title for the service. */
|
|
123
|
+
title?: string | undefined
|
|
106
124
|
}
|
|
107
125
|
}
|
|
108
126
|
|
|
@@ -142,29 +160,34 @@ function resolveRewriteRequest(
|
|
|
142
160
|
/** Serializes a service for discovery responses. */
|
|
143
161
|
export function serialize(s: Service) {
|
|
144
162
|
return {
|
|
145
|
-
id: s.id,
|
|
146
163
|
baseUrl: s.baseUrl,
|
|
164
|
+
description: s.description,
|
|
165
|
+
id: s.id,
|
|
166
|
+
docsLlmsUrl: s.docsLlmsUrl?.({}),
|
|
147
167
|
routes: Object.entries(s.routes).map(([pattern, endpoint]) => {
|
|
148
168
|
const tokens = pattern.trim().split(/\s+/)
|
|
149
169
|
const hasMethod = tokens.length >= 2
|
|
150
170
|
return {
|
|
171
|
+
docsLlmsUrl: s.docsLlmsUrl?.({ route: pattern }),
|
|
151
172
|
method: hasMethod ? tokens[0] : undefined,
|
|
152
173
|
path: hasMethod ? tokens.slice(1).join(' ') : tokens[0],
|
|
153
174
|
pattern,
|
|
154
175
|
payment: endpoint ? resolvePayment(endpoint) : null,
|
|
155
176
|
}
|
|
156
177
|
}),
|
|
178
|
+
title: s.title,
|
|
157
179
|
}
|
|
158
180
|
}
|
|
159
181
|
|
|
160
182
|
/** Renders an llms.txt markdown string for a list of services. */
|
|
161
|
-
export function toLlmsTxt(
|
|
183
|
+
export function toLlmsTxt(
|
|
184
|
+
services: Service[],
|
|
185
|
+
options?: { title?: string | undefined; description?: string | undefined },
|
|
186
|
+
): string {
|
|
162
187
|
const lines: string[] = [
|
|
163
|
-
'
|
|
188
|
+
`# ${options?.title ?? 'API Proxy'}`,
|
|
164
189
|
'',
|
|
165
|
-
'
|
|
166
|
-
'',
|
|
167
|
-
'For machine-readable service data, use `GET /services` (JSON).',
|
|
190
|
+
`> ${options?.description ?? 'Paid API proxy powered by [Machine Payments Protocol](https://mpp.tempo.xyz).'}`,
|
|
168
191
|
'',
|
|
169
192
|
]
|
|
170
193
|
|
|
@@ -172,38 +195,65 @@ export function toLlmsTxt(services: Service[]): string {
|
|
|
172
195
|
|
|
173
196
|
lines.push('## Services', '')
|
|
174
197
|
for (const s of services) {
|
|
175
|
-
const
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
const parts = [paid && `${paid} paid`, free && `${free} free`].filter(Boolean).join(', ')
|
|
179
|
-
lines.push(`- [${s.id}](${s.baseUrl}): ${parts}`)
|
|
198
|
+
const label = s.title ?? s.id
|
|
199
|
+
const desc = s.description ? `: ${s.description}` : ''
|
|
200
|
+
lines.push(`- [${label}](/discover/${s.id}.md)${desc}`)
|
|
180
201
|
}
|
|
202
|
+
lines.push('', '[See all service definitions](/discover/all.md)')
|
|
203
|
+
|
|
204
|
+
return lines.join('\n')
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Renders a full markdown listing of all services with their routes. */
|
|
208
|
+
export function toServicesMarkdown(services: Service[]): string {
|
|
209
|
+
const lines: string[] = ['# Services', '']
|
|
210
|
+
|
|
211
|
+
if (services.length === 0) return lines.join('\n')
|
|
181
212
|
|
|
182
213
|
for (const s of services) {
|
|
183
|
-
|
|
184
|
-
lines.push(
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
214
|
+
lines.push(`## [${s.title ?? s.id}](/discover/${s.id}.md)`, '')
|
|
215
|
+
if (s.description) lines.push(s.description, '')
|
|
216
|
+
pushRoutes(lines, s)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return lines.join('\n')
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Renders a markdown string for a single service. */
|
|
223
|
+
export function toMarkdown(s: Service): string {
|
|
224
|
+
const docsLlmsUrl = s.docsLlmsUrl?.({})
|
|
225
|
+
const lines: string[] = [`# ${s.title ?? s.id}`, '']
|
|
226
|
+
if (docsLlmsUrl) lines.push(`> Documentation: ${docsLlmsUrl}`, '')
|
|
227
|
+
if (s.description) lines.push(s.description, '')
|
|
228
|
+
pushRoutes(lines, s, '##')
|
|
229
|
+
return lines.join('\n')
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function pushRoutes(lines: string[], s: Service, heading: '##' | '###' = '###') {
|
|
233
|
+
lines.push(`${heading} Routes`, '')
|
|
234
|
+
const serialized = serialize(s)
|
|
235
|
+
for (const route of serialized.routes) {
|
|
236
|
+
const p = route.payment as Record<string, unknown> | null
|
|
237
|
+
const desc = p?.description ? `: ${p.description}` : ''
|
|
238
|
+
lines.push(`- \`${route.pattern}\`${desc}`)
|
|
239
|
+
if (!p) {
|
|
240
|
+
lines.push(' - Type: free')
|
|
241
|
+
} else {
|
|
242
|
+
lines.push(` - Type: ${p.intent}`)
|
|
192
243
|
if (p.amount) {
|
|
193
|
-
const
|
|
194
|
-
|
|
244
|
+
const perUnit = p.unitType ? `/${p.unitType}` : ''
|
|
245
|
+
if (p.decimals !== undefined) {
|
|
246
|
+
const price = Number(p.amount) / 10 ** Number(p.decimals)
|
|
247
|
+
lines.push(` - Price: ${price}${perUnit} (${p.amount} units, ${p.decimals} decimals)`)
|
|
248
|
+
} else {
|
|
249
|
+
lines.push(` - Units: ${p.amount}${perUnit}`)
|
|
250
|
+
}
|
|
195
251
|
}
|
|
196
|
-
if (p.
|
|
197
|
-
const meta = [
|
|
198
|
-
p.currency && `currency: ${p.currency}`,
|
|
199
|
-
p.decimals !== undefined && `decimals: ${p.decimals}`,
|
|
200
|
-
].filter(Boolean)
|
|
201
|
-
if (meta.length) parts.push(`(${meta.join(', ')})`)
|
|
202
|
-
lines.push(`- \`${route.pattern}\`: ${parts.join(' — ')}`)
|
|
252
|
+
if (p.currency) lines.push(` - Currency: ${p.currency}`)
|
|
203
253
|
}
|
|
254
|
+
if (route.docsLlmsUrl) lines.push(` - Docs: ${route.docsLlmsUrl}`)
|
|
255
|
+
lines.push('')
|
|
204
256
|
}
|
|
205
|
-
|
|
206
|
-
return lines.join('\n')
|
|
207
257
|
}
|
|
208
258
|
|
|
209
259
|
/** Extracts per-endpoint options from an endpoint definition. */
|
|
@@ -225,3 +275,11 @@ function resolvePayment(endpoint: Endpoint): Record<string, unknown> | null {
|
|
|
225
275
|
})()
|
|
226
276
|
return { intent, method: name, ...rest, ...(amount !== undefined && { amount }) }
|
|
227
277
|
}
|
|
278
|
+
|
|
279
|
+
function resolveLlmsUrl(
|
|
280
|
+
input: string | ((options: { route?: string | undefined }) => string | undefined) | undefined,
|
|
281
|
+
): Service['docsLlmsUrl'] {
|
|
282
|
+
if (!input) return undefined
|
|
283
|
+
if (typeof input === 'function') return input
|
|
284
|
+
return ({ route }) => (route ? undefined : input)
|
|
285
|
+
}
|
|
@@ -20,12 +20,14 @@ import * as Service from '../Service.js'
|
|
|
20
20
|
export function anthropic(config: anthropic.Config) {
|
|
21
21
|
return Service.from<anthropic.Config>('anthropic', {
|
|
22
22
|
baseUrl: config.baseUrl ?? 'https://api.anthropic.com',
|
|
23
|
+
description: 'Claude language models for messages and completions.',
|
|
23
24
|
rewriteRequest(request, ctx) {
|
|
24
25
|
const apiKey = ctx.apiKey ?? config.apiKey
|
|
25
26
|
request.headers.set('x-api-key', apiKey)
|
|
26
27
|
return request
|
|
27
28
|
},
|
|
28
29
|
routes: config.routes,
|
|
30
|
+
title: 'Anthropic',
|
|
29
31
|
})
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -20,12 +20,18 @@ import * as Service from '../Service.js'
|
|
|
20
20
|
export function openai(config: openai.Config) {
|
|
21
21
|
return Service.from<openai.Config>('openai', {
|
|
22
22
|
baseUrl: config.baseUrl ?? 'https://api.openai.com',
|
|
23
|
+
description: 'Chat completions, embeddings, image generation, and audio transcription.',
|
|
24
|
+
docsLlmsUrl: ({ route }) =>
|
|
25
|
+
route
|
|
26
|
+
? `https://context7.com/websites/platform_openai/llms.txt?topic=${encodeURIComponent(route)}`
|
|
27
|
+
: 'https://context7.com/websites/platform_openai/llms.txt',
|
|
23
28
|
rewriteRequest(request, ctx) {
|
|
24
29
|
const apiKey = ctx.apiKey ?? config.apiKey
|
|
25
30
|
request.headers.set('Authorization', `Bearer ${apiKey}`)
|
|
26
31
|
return request
|
|
27
32
|
},
|
|
28
33
|
routes: config.routes,
|
|
34
|
+
title: 'OpenAI',
|
|
29
35
|
})
|
|
30
36
|
}
|
|
31
37
|
|
|
@@ -35,6 +41,7 @@ export declare namespace openai {
|
|
|
35
41
|
apiKey: string
|
|
36
42
|
/** Base URL override. Defaults to `'https://api.openai.com'`. */
|
|
37
43
|
baseUrl?: string | undefined
|
|
44
|
+
/** Route definitions for OpenAI endpoints. */
|
|
38
45
|
routes:
|
|
39
46
|
| 'POST /v1/chat/completions'
|
|
40
47
|
| 'POST /v1/completions'
|
|
@@ -20,12 +20,18 @@ import * as Service from '../Service.js'
|
|
|
20
20
|
export function stripe(config: stripe.Config) {
|
|
21
21
|
return Service.from<stripe.Config>('stripe', {
|
|
22
22
|
baseUrl: config.baseUrl ?? 'https://api.stripe.com',
|
|
23
|
+
description: 'Payment processing, customers, subscriptions, and invoices.',
|
|
24
|
+
docsLlmsUrl: ({ route }) =>
|
|
25
|
+
route
|
|
26
|
+
? `https://context7.com/websites/stripe/llms.txt?topic=${encodeURIComponent(route)}`
|
|
27
|
+
: 'https://docs.stripe.com/llms.txt',
|
|
23
28
|
rewriteRequest(request, ctx) {
|
|
24
29
|
const apiKey = ctx.apiKey ?? config.apiKey
|
|
25
30
|
request.headers.set('Authorization', `Basic ${btoa(`${apiKey}:`)}`)
|
|
26
31
|
return request
|
|
27
32
|
},
|
|
28
33
|
routes: config.routes,
|
|
34
|
+
title: 'Stripe',
|
|
29
35
|
})
|
|
30
36
|
}
|
|
31
37
|
|