@mcpmake/core 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/analyzer/dom-parser.d.ts +28 -0
- package/dist/analyzer/dom-parser.d.ts.map +1 -1
- package/dist/analyzer/dom-parser.js +77 -2
- package/dist/analyzer/dom-parser.js.map +1 -1
- package/dist/analyzer/goal-crawler.d.ts +3 -2
- package/dist/analyzer/goal-crawler.d.ts.map +1 -1
- package/dist/analyzer/goal-crawler.js +67 -18
- package/dist/analyzer/goal-crawler.js.map +1 -1
- package/dist/analyzer/semantic-analyzer.d.ts +2 -2
- package/dist/analyzer/semantic-analyzer.d.ts.map +1 -1
- package/dist/analyzer/semantic-analyzer.js +16 -17
- package/dist/analyzer/semantic-analyzer.js.map +1 -1
- package/dist/analyzer/site-crawler.d.ts.map +1 -1
- package/dist/analyzer/site-crawler.js +86 -12
- package/dist/analyzer/site-crawler.js.map +1 -1
- package/dist/config/mcpmake-config.d.ts.map +1 -1
- package/dist/config/mcpmake-config.js +5 -0
- package/dist/config/mcpmake-config.js.map +1 -1
- package/dist/emitter/code-writer.d.ts +1 -0
- package/dist/emitter/code-writer.d.ts.map +1 -1
- package/dist/emitter/code-writer.js +79 -12
- package/dist/emitter/code-writer.js.map +1 -1
- package/dist/emitter/index.d.ts +8 -0
- package/dist/emitter/index.d.ts.map +1 -1
- package/dist/emitter/index.js.map +1 -1
- package/dist/emitter/python-templates/dockerfile.hbs +4 -1
- package/dist/emitter/python-templates/server.py.hbs +4 -0
- package/dist/emitter/site-scaffolder.d.ts.map +1 -1
- package/dist/emitter/site-scaffolder.js +28 -1
- package/dist/emitter/site-scaffolder.js.map +1 -1
- package/dist/emitter/site-templates/browser-manager.ts.hbs +24 -3
- package/dist/emitter/site-templates/dockerfile.hbs +13 -4
- package/dist/emitter/site-templates/env.example.hbs +8 -0
- package/dist/emitter/site-templates/server-main-http.ts.hbs +53 -0
- package/dist/emitter/site-templates/telemetry.ts.hbs +117 -0
- package/dist/emitter/templates/auth-provider.ts.hbs +9 -5
- package/dist/emitter/templates/config.ts.hbs +22 -0
- package/dist/emitter/templates/dockerfile.hbs +12 -4
- package/dist/emitter/templates/oauth.ts.hbs +19 -65
- package/dist/emitter/templates/server-main-http.ts.hbs +33 -8
- package/dist/emitter/templates/task-handlers.ts.hbs +40 -1
- package/dist/emitter/worker-templates/worker.ts.hbs +88 -25
- package/dist/generator/spec-generator.d.ts.map +1 -1
- package/dist/generator/spec-generator.js +11 -56
- package/dist/generator/spec-generator.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/llm/anthropic-provider.d.ts +14 -0
- package/dist/llm/anthropic-provider.d.ts.map +1 -0
- package/dist/llm/anthropic-provider.js +50 -0
- package/dist/llm/anthropic-provider.js.map +1 -0
- package/dist/llm/index.d.ts +19 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +116 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/openai-provider.d.ts +46 -0
- package/dist/llm/openai-provider.d.ts.map +1 -0
- package/dist/llm/openai-provider.js +245 -0
- package/dist/llm/openai-provider.js.map +1 -0
- package/dist/llm/types.d.ts +61 -0
- package/dist/llm/types.d.ts.map +1 -0
- package/dist/llm/types.js +16 -0
- package/dist/llm/types.js.map +1 -0
- package/dist/parser/har-filter.d.ts +7 -0
- package/dist/parser/har-filter.d.ts.map +1 -1
- package/dist/parser/har-filter.js +107 -1
- package/dist/parser/har-filter.js.map +1 -1
- package/dist/parser/index.d.ts +1 -1
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/index.js +1 -1
- package/dist/parser/index.js.map +1 -1
- package/dist/parser/openapi-loader.d.ts.map +1 -1
- package/dist/parser/openapi-loader.js +36 -2
- package/dist/parser/openapi-loader.js.map +1 -1
- package/dist/parser/postman-loader.d.ts.map +1 -1
- package/dist/parser/postman-loader.js +6 -1
- package/dist/parser/postman-loader.js.map +1 -1
- package/dist/parser/schema-converter.d.ts.map +1 -1
- package/dist/parser/schema-converter.js +34 -23
- package/dist/parser/schema-converter.js.map +1 -1
- package/dist/plugins/loader.d.ts +5 -1
- package/dist/plugins/loader.d.ts.map +1 -1
- package/dist/plugins/loader.js +39 -10
- package/dist/plugins/loader.js.map +1 -1
- package/dist/pricing.d.ts +2 -1
- package/dist/pricing.d.ts.map +1 -1
- package/dist/pricing.js +11 -5
- package/dist/pricing.js.map +1 -1
- package/dist/recorder/browser-recorder.d.ts.map +1 -1
- package/dist/recorder/browser-recorder.js +50 -5
- package/dist/recorder/browser-recorder.js.map +1 -1
- package/dist/rescan/rescan-scheduler.d.ts.map +1 -1
- package/dist/rescan/rescan-scheduler.js +22 -7
- package/dist/rescan/rescan-scheduler.js.map +1 -1
- package/dist/site-transformer/selector-healer.d.ts +1 -1
- package/dist/site-transformer/selector-healer.d.ts.map +1 -1
- package/dist/site-transformer/selector-healer.js +17 -18
- package/dist/site-transformer/selector-healer.js.map +1 -1
- package/dist/transformer/auth-detector.d.ts.map +1 -1
- package/dist/transformer/auth-detector.js +13 -1
- package/dist/transformer/auth-detector.js.map +1 -1
- package/dist/transformer/har-schema-inferrer.d.ts.map +1 -1
- package/dist/transformer/har-schema-inferrer.js +2 -0
- package/dist/transformer/har-schema-inferrer.js.map +1 -1
- package/dist/transformer/har-to-operations.d.ts +1 -0
- package/dist/transformer/har-to-operations.d.ts.map +1 -1
- package/dist/transformer/har-to-operations.js +42 -10
- package/dist/transformer/har-to-operations.js.map +1 -1
- package/dist/transformer/llm-namer.d.ts +1 -1
- package/dist/transformer/llm-namer.d.ts.map +1 -1
- package/dist/transformer/llm-namer.js +12 -15
- package/dist/transformer/llm-namer.js.map +1 -1
- package/dist/transformer/tool-builder.d.ts.map +1 -1
- package/dist/transformer/tool-builder.js +30 -1
- package/dist/transformer/tool-builder.js.map +1 -1
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/fail.d.ts.map +1 -1
- package/dist/utils/fail.js +22 -4
- package/dist/utils/fail.js.map +1 -1
- package/dist/utils/json-extract.d.ts +21 -0
- package/dist/utils/json-extract.d.ts.map +1 -0
- package/dist/utils/json-extract.js +67 -0
- package/dist/utils/json-extract.js.map +1 -0
- package/dist/utils/model-resolver.d.ts.map +1 -1
- package/dist/utils/model-resolver.js +19 -4
- package/dist/utils/model-resolver.js.map +1 -1
- package/dist/utils/sanitize.d.ts +1 -1
- package/dist/utils/sanitize.d.ts.map +1 -1
- package/dist/utils/sanitize.js +6 -2
- package/dist/utils/sanitize.js.map +1 -1
- package/dist/utils/ssrf-guard.d.ts +10 -0
- package/dist/utils/ssrf-guard.d.ts.map +1 -0
- package/dist/utils/ssrf-guard.js +130 -0
- package/dist/utils/ssrf-guard.js.map +1 -0
- package/dist/utils/watcher.d.ts +17 -1
- package/dist/utils/watcher.d.ts.map +1 -1
- package/dist/utils/watcher.js +53 -21
- package/dist/utils/watcher.js.map +1 -1
- package/package.json +2 -1
|
@@ -90,8 +90,34 @@ async function safeEqual(a: string, b: string): Promise<boolean> {
|
|
|
90
90
|
for (let i = 0; i < da.length; i++) diff |= da[i] ^ db[i];
|
|
91
91
|
return diff === 0;
|
|
92
92
|
}
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
// Fail CLOSED: when MCP_AUTH_TOKEN is unset every authenticated route is denied
|
|
94
|
+
// unless the operator opts in with MCP_ALLOW_UNAUTHENTICATED === 'true' (a
|
|
95
|
+
// local/dev escape hatch). We warn once per isolate so the open posture is loud.
|
|
96
|
+
let unauthWarned = false;
|
|
97
|
+
async function isAuthorized(request: Request, env: Env): Promise<boolean> {
|
|
98
|
+
const expected = env.MCP_AUTH_TOKEN;
|
|
99
|
+
if (!expected) {
|
|
100
|
+
if (env.MCP_ALLOW_UNAUTHENTICATED === 'true') {
|
|
101
|
+
if (!unauthWarned) {
|
|
102
|
+
unauthWarned = true;
|
|
103
|
+
console.warn(
|
|
104
|
+
'SECURITY: MCP_AUTH_TOKEN is unset and MCP_ALLOW_UNAUTHENTICATED=true — ' +
|
|
105
|
+
'this Worker is serving authenticated routes WITHOUT a bearer token. ' +
|
|
106
|
+
'Set MCP_AUTH_TOKEN before exposing this endpoint.',
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
if (!unauthWarned) {
|
|
112
|
+
unauthWarned = true;
|
|
113
|
+
console.error(
|
|
114
|
+
'SECURITY: MCP_AUTH_TOKEN is unset — denying all authenticated routes. ' +
|
|
115
|
+
'Set MCP_AUTH_TOKEN (wrangler secret put MCP_AUTH_TOKEN), or set ' +
|
|
116
|
+
'MCP_ALLOW_UNAUTHENTICATED=true for local/dev only.',
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
95
121
|
const header = request.headers.get('authorization');
|
|
96
122
|
if (!header || !header.startsWith('Bearer ')) return false;
|
|
97
123
|
const presented = header.slice(7).trim();
|
|
@@ -99,19 +125,41 @@ async function isAuthorized(request: Request, expected: string | undefined): Pro
|
|
|
99
125
|
return safeEqual(presented, expected);
|
|
100
126
|
}
|
|
101
127
|
|
|
102
|
-
/* ── HTTP / CORS helpers ───────────────────────────────────────────────
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
128
|
+
/* ── HTTP / CORS helpers ───────────────────────────────────────────────
|
|
129
|
+
* These responses are credentialed (gated by a bearer token), so we never
|
|
130
|
+
* emit a blanket `Access-Control-Allow-Origin: *`. CORS headers are reflected
|
|
131
|
+
* only when the request Origin is in the MCP_ALLOWED_ORIGINS allowlist
|
|
132
|
+
* (comma-separated); otherwise the response carries no ACAO header at all. */
|
|
133
|
+
function originAllowed(origin: string | null | undefined, env: Env): boolean {
|
|
134
|
+
if (!origin) return false;
|
|
135
|
+
const raw = env.MCP_ALLOWED_ORIGINS;
|
|
136
|
+
if (!raw) return false;
|
|
137
|
+
return raw
|
|
138
|
+
.split(',')
|
|
139
|
+
.map((s) => s.trim())
|
|
140
|
+
.filter(Boolean)
|
|
141
|
+
.includes(origin);
|
|
142
|
+
}
|
|
143
|
+
function corsHeaders(origin: string | null | undefined, env: Env): Record<string, string> {
|
|
144
|
+
const headers: Record<string, string> = {
|
|
106
145
|
'access-control-allow-methods': 'POST, GET, OPTIONS',
|
|
107
146
|
'access-control-allow-headers':
|
|
108
147
|
'authorization, content-type, mcp-method, mcp-name, mcp-protocol-version, traceparent, tracestate',
|
|
109
148
|
};
|
|
149
|
+
if (originAllowed(origin, env)) {
|
|
150
|
+
headers['access-control-allow-origin'] = origin as string;
|
|
151
|
+
headers['vary'] = 'Origin';
|
|
152
|
+
}
|
|
153
|
+
return headers;
|
|
110
154
|
}
|
|
111
|
-
function json(
|
|
155
|
+
function json(
|
|
156
|
+
body: unknown,
|
|
157
|
+
status = 200,
|
|
158
|
+
extra?: Record<string, string>,
|
|
159
|
+
): Response {
|
|
112
160
|
return new Response(JSON.stringify(body), {
|
|
113
161
|
status,
|
|
114
|
-
headers: { 'content-type': 'application/json', ...
|
|
162
|
+
headers: { 'content-type': 'application/json', ...extra },
|
|
115
163
|
});
|
|
116
164
|
}
|
|
117
165
|
function ok(id: unknown, result: unknown): object {
|
|
@@ -120,8 +168,13 @@ function ok(id: unknown, result: unknown): object {
|
|
|
120
168
|
function err(id: unknown, code: number, message: string): object {
|
|
121
169
|
return { jsonrpc: '2.0', id: id ?? null, error: { code, message } };
|
|
122
170
|
}
|
|
123
|
-
function rpcErrorResponse(
|
|
124
|
-
|
|
171
|
+
function rpcErrorResponse(
|
|
172
|
+
id: unknown,
|
|
173
|
+
code: number,
|
|
174
|
+
message: string,
|
|
175
|
+
cors?: Record<string, string>,
|
|
176
|
+
): Response {
|
|
177
|
+
return json(err(id, code, message), 200, cors);
|
|
125
178
|
}
|
|
126
179
|
|
|
127
180
|
/* ── server/discover (SEP-2575) — VERIFY result shape against the final spec ── */
|
|
@@ -235,16 +288,19 @@ export default {
|
|
|
235
288
|
async fetch(request: Request, env: Env): Promise<Response> {
|
|
236
289
|
const url = new URL(request.url);
|
|
237
290
|
const origin = request.headers.get('origin');
|
|
291
|
+
// Computed once: empty unless the request Origin is in MCP_ALLOWED_ORIGINS.
|
|
292
|
+
const cors = corsHeaders(origin, env);
|
|
238
293
|
|
|
239
294
|
if (request.method === 'OPTIONS') {
|
|
240
|
-
return new Response(null, { status: 204, headers:
|
|
295
|
+
return new Response(null, { status: 204, headers: cors });
|
|
241
296
|
}
|
|
242
297
|
if (url.pathname === '/health') return json({ status: 'ok' });
|
|
243
298
|
if (url.pathname === '/ready') return json({ status: 'ready' });
|
|
244
299
|
|
|
245
300
|
// Bearer authentication (every path except /health and /ready).
|
|
246
|
-
if (!(await isAuthorized(request, env
|
|
301
|
+
if (!(await isAuthorized(request, env))) {
|
|
247
302
|
return json({ error: 'Unauthorized: missing or invalid bearer token' }, 401, {
|
|
303
|
+
...cors,
|
|
248
304
|
'www-authenticate': 'Bearer',
|
|
249
305
|
});
|
|
250
306
|
}
|
|
@@ -256,30 +312,37 @@ export default {
|
|
|
256
312
|
console.log(JSON.stringify({ level: 'info', msg: 'mcp-meta-headers', mcpMethod, mcpName }));
|
|
257
313
|
}
|
|
258
314
|
|
|
259
|
-
if (url.pathname !== '/mcp') return json({ error: 'Not found' }, 404);
|
|
315
|
+
if (url.pathname !== '/mcp') return json({ error: 'Not found' }, 404, cors);
|
|
260
316
|
if (request.method !== 'POST') {
|
|
261
317
|
// Stateless: no SSE stream to open (GET) or session to delete (DELETE).
|
|
262
|
-
return rpcErrorResponse(
|
|
318
|
+
return rpcErrorResponse(
|
|
319
|
+
null,
|
|
320
|
+
-32601,
|
|
321
|
+
'Only POST is supported on this stateless server',
|
|
322
|
+
cors,
|
|
323
|
+
);
|
|
263
324
|
}
|
|
264
325
|
|
|
265
326
|
// Origin guard (DNS-rebinding protection). Enforced only when configured —
|
|
266
327
|
// a Workers endpoint is public and gated by the bearer token, not by origin.
|
|
267
328
|
const allowedOrigin = env.ALLOWED_ORIGIN;
|
|
268
329
|
if (allowedOrigin && origin && origin !== allowedOrigin) {
|
|
269
|
-
return json({ error: 'Forbidden: invalid origin' }, 403);
|
|
330
|
+
return json({ error: 'Forbidden: invalid origin' }, 403, cors);
|
|
270
331
|
}
|
|
271
332
|
|
|
272
333
|
const contentLength = Number(request.headers.get('content-length') ?? '0');
|
|
273
|
-
if (contentLength > MAX_BODY)
|
|
334
|
+
if (contentLength > MAX_BODY)
|
|
335
|
+
return rpcErrorResponse(null, -32600, 'Request body too large', cors);
|
|
274
336
|
const raw = await request.text();
|
|
275
|
-
if (raw.length > MAX_BODY)
|
|
276
|
-
|
|
337
|
+
if (raw.length > MAX_BODY)
|
|
338
|
+
return rpcErrorResponse(null, -32600, 'Request body too large', cors);
|
|
339
|
+
if (!raw) return rpcErrorResponse(null, -32600, 'Empty request body', cors);
|
|
277
340
|
|
|
278
341
|
let parsed: unknown;
|
|
279
342
|
try {
|
|
280
343
|
parsed = JSON.parse(raw);
|
|
281
344
|
} catch {
|
|
282
|
-
return rpcErrorResponse(null, -32700, 'Parse error');
|
|
345
|
+
return rpcErrorResponse(null, -32700, 'Parse error', cors);
|
|
283
346
|
}
|
|
284
347
|
|
|
285
348
|
const config = loadConfig(env);
|
|
@@ -293,25 +356,25 @@ export default {
|
|
|
293
356
|
return runWithTrace(trace, async () => {
|
|
294
357
|
if (Array.isArray(parsed)) {
|
|
295
358
|
if (parsed.length === 0) {
|
|
296
|
-
return rpcErrorResponse(null, -32600, 'Empty JSON-RPC batch');
|
|
359
|
+
return rpcErrorResponse(null, -32600, 'Empty JSON-RPC batch', cors);
|
|
297
360
|
}
|
|
298
361
|
if (parsed.length > MAX_BATCH) {
|
|
299
|
-
return rpcErrorResponse(null, -32600, `Batch too large (max ${MAX_BATCH})
|
|
362
|
+
return rpcErrorResponse(null, -32600, `Batch too large (max ${MAX_BATCH})`, cors);
|
|
300
363
|
}
|
|
301
364
|
const settled = await mapWithConcurrency(parsed, BATCH_CONCURRENCY, (m) =>
|
|
302
365
|
handleRpc(m as { id?: unknown; method?: unknown }, config, env),
|
|
303
366
|
);
|
|
304
367
|
const responses = settled.filter((r): r is object => r !== null);
|
|
305
368
|
if (responses.length === 0) {
|
|
306
|
-
return new Response(null, { status: 202, headers:
|
|
369
|
+
return new Response(null, { status: 202, headers: cors });
|
|
307
370
|
}
|
|
308
|
-
return json(responses);
|
|
371
|
+
return json(responses, 200, cors);
|
|
309
372
|
}
|
|
310
373
|
const response = await handleRpc(parsed as { id?: unknown; method?: unknown }, config, env);
|
|
311
374
|
if (response === null) {
|
|
312
|
-
return new Response(null, { status: 202, headers:
|
|
375
|
+
return new Response(null, { status: 202, headers: cors });
|
|
313
376
|
}
|
|
314
|
-
return json(response);
|
|
377
|
+
return json(response, 200, cors);
|
|
315
378
|
});
|
|
316
379
|
},
|
|
317
380
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec-generator.d.ts","sourceRoot":"","sources":["../../src/generator/spec-generator.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAcD,wBAAsB,2BAA2B,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"spec-generator.d.ts","sourceRoot":"","sources":["../../src/generator/spec-generator.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAcD,wBAAsB,2BAA2B,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoC/F"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { extractJsonObject } from '../utils/json-extract.js';
|
|
2
2
|
import { logger } from '../utils/logger.js';
|
|
3
|
-
import {
|
|
3
|
+
import { requireLlmProvider } from '../llm/index.js';
|
|
4
4
|
const SYSTEM_PROMPT = `You are an API architect. Given a description of an API or service, generate a valid OpenAPI 3.0 specification in JSON format.
|
|
5
5
|
|
|
6
6
|
Rules:
|
|
@@ -13,78 +13,33 @@ Rules:
|
|
|
13
13
|
- Include a servers array with a base URL
|
|
14
14
|
- Keep it practical — 3-10 operations is typical`;
|
|
15
15
|
export async function generateSpecFromDescription(options) {
|
|
16
|
-
const
|
|
17
|
-
if (!apiKey) {
|
|
18
|
-
throw new Error('ANTHROPIC_API_KEY environment variable is required for describe mode.\n' +
|
|
19
|
-
'Set it with: export ANTHROPIC_API_KEY=your-key-here');
|
|
20
|
-
}
|
|
21
|
-
const client = new Anthropic({ apiKey });
|
|
22
|
-
const model = await resolveModel(client, 'balanced', options.model);
|
|
16
|
+
const provider = requireLlmProvider('describe mode');
|
|
23
17
|
let userPrompt = `Generate an OpenAPI 3.0 spec for: ${options.description}`;
|
|
24
18
|
if (options.baseUrl) {
|
|
25
19
|
userPrompt += `\n\nUse this base URL: ${options.baseUrl}`;
|
|
26
20
|
}
|
|
27
21
|
logger.info('Generating OpenAPI spec from description...');
|
|
28
|
-
const
|
|
29
|
-
model,
|
|
30
|
-
max_tokens: 4096,
|
|
22
|
+
const responseText = await provider.completeText({
|
|
31
23
|
system: SYSTEM_PROMPT,
|
|
32
|
-
|
|
24
|
+
prompt: userPrompt,
|
|
25
|
+
tier: 'balanced',
|
|
26
|
+
model: options.model,
|
|
27
|
+
maxTokens: 4096,
|
|
33
28
|
});
|
|
34
|
-
const content = message.content[0];
|
|
35
|
-
if (content.type !== 'text') {
|
|
36
|
-
throw new Error('Unexpected response format from Claude');
|
|
37
|
-
}
|
|
38
29
|
// OpenAPI specs are recursive, so structured outputs can't enforce the shape.
|
|
39
30
|
// Instead, extract the first balanced JSON object — robust to markdown fences,
|
|
40
31
|
// leading/trailing prose, and braces that appear inside string values.
|
|
41
|
-
const json = extractJsonObject(
|
|
32
|
+
const json = extractJsonObject(responseText);
|
|
42
33
|
if (json === null) {
|
|
43
|
-
throw new Error('
|
|
34
|
+
throw new Error('The model did not return a JSON object. Try again or refine your description.');
|
|
44
35
|
}
|
|
45
36
|
// Validate it's parseable JSON
|
|
46
37
|
try {
|
|
47
38
|
JSON.parse(json);
|
|
48
39
|
}
|
|
49
40
|
catch {
|
|
50
|
-
throw new Error('
|
|
41
|
+
throw new Error('The model returned invalid JSON. Try again or refine your description.');
|
|
51
42
|
}
|
|
52
43
|
return json;
|
|
53
44
|
}
|
|
54
|
-
/**
|
|
55
|
-
* Return the substring spanning the first balanced top-level `{...}` object in
|
|
56
|
-
* `text`, or null if none. String-aware (ignores braces inside quoted strings)
|
|
57
|
-
* and linear-time — no regex, so no catastrophic-backtracking risk.
|
|
58
|
-
*/
|
|
59
|
-
function extractJsonObject(text) {
|
|
60
|
-
const start = text.indexOf('{');
|
|
61
|
-
if (start === -1)
|
|
62
|
-
return null;
|
|
63
|
-
let depth = 0;
|
|
64
|
-
let inString = false;
|
|
65
|
-
let escaped = false;
|
|
66
|
-
for (let i = start; i < text.length; i++) {
|
|
67
|
-
const ch = text[i];
|
|
68
|
-
if (inString) {
|
|
69
|
-
if (escaped)
|
|
70
|
-
escaped = false;
|
|
71
|
-
else if (ch === '\\')
|
|
72
|
-
escaped = true;
|
|
73
|
-
else if (ch === '"')
|
|
74
|
-
inString = false;
|
|
75
|
-
}
|
|
76
|
-
else if (ch === '"') {
|
|
77
|
-
inString = true;
|
|
78
|
-
}
|
|
79
|
-
else if (ch === '{') {
|
|
80
|
-
depth++;
|
|
81
|
-
}
|
|
82
|
-
else if (ch === '}') {
|
|
83
|
-
depth--;
|
|
84
|
-
if (depth === 0)
|
|
85
|
-
return text.slice(start, i + 1);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
45
|
//# sourceMappingURL=spec-generator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec-generator.js","sourceRoot":"","sources":["../../src/generator/spec-generator.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"spec-generator.js","sourceRoot":"","sources":["../../src/generator/spec-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAQrD,MAAM,aAAa,GAAG;;;;;;;;;;iDAU2B,CAAC;AAElD,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,OAA4B;IAC5E,MAAM,QAAQ,GAAG,kBAAkB,CAAC,eAAe,CAAC,CAAC;IAErD,IAAI,UAAU,GAAG,qCAAqC,OAAO,CAAC,WAAW,EAAE,CAAC;IAC5E,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,UAAU,IAAI,0BAA0B,OAAO,CAAC,OAAO,EAAE,CAAC;IAC5D,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;IAE3D,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC;QAC/C,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,UAAU;QAClB,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,SAAS,EAAE,IAAI;KAChB,CAAC,CAAC;IAEH,8EAA8E;IAC9E,+EAA+E;IAC/E,uEAAuE;IACvE,MAAM,IAAI,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC7C,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,+EAA+E,CAChF,CAAC;IACJ,CAAC;IAED,+BAA+B;IAC/B,IAAI,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;IAC5F,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export { renderTemplate } from './emitter/template-loader.js';
|
|
|
12
12
|
export { scaffoldSharedModules } from './emitter/project-scaffolder.js';
|
|
13
13
|
export { loadOpenApiSpec } from './parser/openapi-loader.js';
|
|
14
14
|
export type { LoadResult } from './parser/openapi-loader.js';
|
|
15
|
+
export { assertPublicUrl, isPrivateOrReservedIp, privateHostsAllowed } from './utils/ssrf-guard.js';
|
|
15
16
|
export { applyOverlay } from './parser/overlay-loader.js';
|
|
16
17
|
export { extractOperations } from './parser/operation-extractor.js';
|
|
17
18
|
export type { ExtractionResult } from './parser/operation-extractor.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAKxE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,YAAY,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAC9F,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACzF,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAKnE,OAAO,EACL,UAAU,EACV,WAAW,EACX,UAAU,EACV,cAAc,EACd,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,YAAY,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,YAAY,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,YAAY,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,YAAY,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAC5F,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAC1F,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAK3E,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACpF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,YAAY,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,YAAY,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAKnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AACzE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAK3E,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAK5E,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACpF,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAK3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAKtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC/E,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAAE,6BAA6B,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC3F,YAAY,EAAE,qBAAqB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAKpG,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;AAK7E,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAChF,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAK3D,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAKhC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAK/C,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACnG,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ export { scaffoldSharedModules } from './emitter/project-scaffolder.js';
|
|
|
16
16
|
// Parser (OpenAPI / HAR / Postman ingestion)
|
|
17
17
|
// ---------------------------------------------------------------------------
|
|
18
18
|
export { loadOpenApiSpec } from './parser/openapi-loader.js';
|
|
19
|
+
export { assertPublicUrl, isPrivateOrReservedIp, privateHostsAllowed } from './utils/ssrf-guard.js';
|
|
19
20
|
export { applyOverlay } from './parser/overlay-loader.js';
|
|
20
21
|
export { extractOperations } from './parser/operation-extractor.js';
|
|
21
22
|
export { jsonSchemaToZodCode, buildOperationInputSchema } from './parser/schema-converter.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CompleteJsonOptions, CompleteOptions, LlmProvider } from './types.js';
|
|
2
|
+
export interface AnthropicProviderOptions {
|
|
3
|
+
apiKey: string;
|
|
4
|
+
baseURL?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class AnthropicProvider implements LlmProvider {
|
|
7
|
+
readonly name = "anthropic";
|
|
8
|
+
readonly supportsVision = true;
|
|
9
|
+
private readonly client;
|
|
10
|
+
constructor(opts: AnthropicProviderOptions);
|
|
11
|
+
completeText({ system, prompt, tier, model, maxTokens }: CompleteOptions): Promise<string>;
|
|
12
|
+
completeJson<T = unknown>({ system, prompt, schema, tier, model, maxTokens, }: CompleteJsonOptions): Promise<T>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=anthropic-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic-provider.d.ts","sourceRoot":"","sources":["../../src/llm/anthropic-provider.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEpF,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,iBAAkB,YAAW,WAAW;IACnD,QAAQ,CAAC,IAAI,eAAe;IAC5B,QAAQ,CAAC,cAAc,QAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;gBAEvB,IAAI,EAAE,wBAAwB;IAIpC,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC;IAc1F,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,EAC9B,MAAM,EACN,MAAM,EACN,MAAM,EACN,IAAI,EACJ,KAAK,EACL,SAAS,GACV,EAAE,mBAAmB,GAAG,OAAO,CAAC,CAAC,CAAC;CAoBpC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anthropic-backed {@link LlmProvider}. Wraps `@anthropic-ai/sdk`, hiding its
|
|
3
|
+
* wire-format details behind the provider-agnostic interface: text completion
|
|
4
|
+
* via `messages.create` and schema-constrained completion via the native
|
|
5
|
+
* structured-output path (`messages.parse` + `jsonSchemaOutputFormat`). Model
|
|
6
|
+
* ids are resolved against the live Models API (see {@link resolveModel}) so a
|
|
7
|
+
* retired snapshot can't silently 404.
|
|
8
|
+
*/
|
|
9
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
10
|
+
import { jsonSchemaOutputFormat } from '@anthropic-ai/sdk/helpers/json-schema';
|
|
11
|
+
import { resolveModel } from '../utils/model-resolver.js';
|
|
12
|
+
export class AnthropicProvider {
|
|
13
|
+
name = 'anthropic';
|
|
14
|
+
supportsVision = true;
|
|
15
|
+
client;
|
|
16
|
+
constructor(opts) {
|
|
17
|
+
this.client = new Anthropic({ apiKey: opts.apiKey, baseURL: opts.baseURL });
|
|
18
|
+
}
|
|
19
|
+
async completeText({ system, prompt, tier, model, maxTokens }) {
|
|
20
|
+
const resolved = await resolveModel(this.client, tier, model);
|
|
21
|
+
const message = await this.client.messages.create({
|
|
22
|
+
model: resolved,
|
|
23
|
+
max_tokens: maxTokens,
|
|
24
|
+
...(system ? { system } : {}),
|
|
25
|
+
messages: [{ role: 'user', content: prompt }],
|
|
26
|
+
});
|
|
27
|
+
const block = message.content[0];
|
|
28
|
+
return block?.type === 'text' ? block.text : '';
|
|
29
|
+
}
|
|
30
|
+
async completeJson({ system, prompt, schema, tier, model, maxTokens, }) {
|
|
31
|
+
const resolved = await resolveModel(this.client, tier, model);
|
|
32
|
+
const message = await this.client.messages.parse({
|
|
33
|
+
model: resolved,
|
|
34
|
+
max_tokens: maxTokens,
|
|
35
|
+
...(system ? { system } : {}),
|
|
36
|
+
messages: [{ role: 'user', content: prompt }],
|
|
37
|
+
output_config: {
|
|
38
|
+
// `schema` is the interface's `Record<string, unknown>`; the helper wants
|
|
39
|
+
// a stricter JSON-schema type, so cast minimally to keep the public
|
|
40
|
+
// signature intact.
|
|
41
|
+
format: jsonSchemaOutputFormat(schema),
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
const out = message.parsed_output;
|
|
45
|
+
if (out == null)
|
|
46
|
+
throw new Error('Anthropic returned no structured output');
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=anthropic-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic-provider.js","sourceRoot":"","sources":["../../src/llm/anthropic-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAQ1D,MAAM,OAAO,iBAAiB;IACnB,IAAI,GAAG,WAAW,CAAC;IACnB,cAAc,GAAG,IAAI,CAAC;IACd,MAAM,CAAY;IAEnC,YAAY,IAA8B;QACxC,IAAI,CAAC,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAmB;QAC5E,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QAE9D,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YAChD,KAAK,EAAE,QAAQ;YACf,UAAU,EAAE,SAAS;YACrB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7B,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;SAC9C,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACjC,OAAO,KAAK,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,YAAY,CAAc,EAC9B,MAAM,EACN,MAAM,EACN,MAAM,EACN,IAAI,EACJ,KAAK,EACL,SAAS,GACW;QACpB,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QAE9D,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YAC/C,KAAK,EAAE,QAAQ;YACf,UAAU,EAAE,SAAS;YACrB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7B,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;YAC7C,aAAa,EAAE;gBACb,0EAA0E;gBAC1E,oEAAoE;gBACpE,oBAAoB;gBACpB,MAAM,EAAE,sBAAsB,CAAC,MAAsD,CAAC;aACvF;SACF,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC;QAClC,IAAI,GAAG,IAAI,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC5E,OAAO,GAAQ,CAAC;IAClB,CAAC;CACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type LlmProvider, type ProviderKind } from './types.js';
|
|
2
|
+
export * from './types.js';
|
|
3
|
+
/** Resolve the configured provider kind from `MCPMAKE_LLM_PROVIDER` (default: anthropic). */
|
|
4
|
+
export declare function resolveProviderKind(): ProviderKind;
|
|
5
|
+
/**
|
|
6
|
+
* Build the active LLM provider from the environment, or return `null` when it
|
|
7
|
+
* is not usable (missing key, or an `openai-compatible` setup with no base
|
|
8
|
+
* URL). Optional AI steps treat `null` as "warn and skip", exactly as the old
|
|
9
|
+
* direct `ANTHROPIC_API_KEY` checks did. Required features should call
|
|
10
|
+
* {@link requireLlmProvider} instead so they fail with a clear message.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getLlmProvider(): LlmProvider | null;
|
|
13
|
+
/**
|
|
14
|
+
* Like {@link getLlmProvider} but throws a provider-aware error instead of
|
|
15
|
+
* returning null — for features that cannot degrade (spec generation, goal
|
|
16
|
+
* crawl).
|
|
17
|
+
*/
|
|
18
|
+
export declare function requireLlmProvider(feature: string): LlmProvider;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/llm/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAkB,MAAM,YAAY,CAAC;AAIjF,cAAc,YAAY,CAAC;AA+C3B,6FAA6F;AAC7F,wBAAgB,mBAAmB,IAAI,YAAY,CAMlD;AAOD;;;;;;GAMG;AACH,wBAAgB,cAAc,IAAI,WAAW,GAAG,IAAI,CA8BnD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAO/D"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM provider selection. Reads the environment and builds the active
|
|
3
|
+
* {@link LlmProvider}; CLI flags populate that environment (see the CLI's
|
|
4
|
+
* provider options) so core code never needs a provider parameter threaded
|
|
5
|
+
* through every call.
|
|
6
|
+
*/
|
|
7
|
+
import { logger } from '../utils/logger.js';
|
|
8
|
+
import { isPrivateOrReservedIp, privateHostsAllowed } from '../utils/ssrf-guard.js';
|
|
9
|
+
import { PROVIDER_KINDS } from './types.js';
|
|
10
|
+
import { AnthropicProvider } from './anthropic-provider.js';
|
|
11
|
+
import { OpenAiProvider } from './openai-provider.js';
|
|
12
|
+
export * from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* SSRF guard for a provider base URL. A misconfigured `ANTHROPIC_BASE_URL` /
|
|
15
|
+
* `OPENAI_BASE_URL` would send the API key to whatever host it names, so reject
|
|
16
|
+
* non-http(s), malformed, and private/loopback/reserved hosts before the URL
|
|
17
|
+
* reaches the SDK.
|
|
18
|
+
*
|
|
19
|
+
* Provider selection is synchronous (callers expect a sync API), so this does
|
|
20
|
+
* the literal-IP/protocol checks that {@link assertPublicUrl} performs without
|
|
21
|
+
* DNS, plus a string match for loopback hostnames (`localhost` and friends) so
|
|
22
|
+
* the common `http://localhost:…` bypass is closed too. It still cannot resolve
|
|
23
|
+
* an arbitrary hostname that maps to a private address (no DNS here) — that
|
|
24
|
+
* residual gap matches {@link assertPublicUrl}'s own TOCTOU note. The
|
|
25
|
+
* `MCPMAKE_ALLOW_PRIVATE_HOSTS` escape hatch (honored via
|
|
26
|
+
* {@link privateHostsAllowed}) is what keeps trusted localhost endpoints like
|
|
27
|
+
* Ollama working; operators must opt in for those.
|
|
28
|
+
*/
|
|
29
|
+
function isLoopbackHostname(host) {
|
|
30
|
+
const h = host.toLowerCase();
|
|
31
|
+
return h === 'localhost' || h === 'localhost.localdomain' || h.endsWith('.localhost');
|
|
32
|
+
}
|
|
33
|
+
function assertSafeBaseUrl(envVar, value) {
|
|
34
|
+
let url;
|
|
35
|
+
try {
|
|
36
|
+
url = new URL(value);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
throw new Error(`${envVar} is not a valid URL: ${value}`);
|
|
40
|
+
}
|
|
41
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
42
|
+
throw new Error(`${envVar} must be an http(s) URL, got: ${value}`);
|
|
43
|
+
}
|
|
44
|
+
if (privateHostsAllowed())
|
|
45
|
+
return;
|
|
46
|
+
// Strip IPv6 brackets from the hostname for literal checks.
|
|
47
|
+
const host = url.hostname.replace(/^\[/, '').replace(/\]$/, '');
|
|
48
|
+
if (isPrivateOrReservedIp(host) || isLoopbackHostname(host)) {
|
|
49
|
+
throw new Error(`${envVar} points at private/loopback host ${host}; refusing to send credentials there. ` +
|
|
50
|
+
`Set MCPMAKE_ALLOW_PRIVATE_HOSTS=1 to allow trusted localhost endpoints (e.g. Ollama).`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Resolve the configured provider kind from `MCPMAKE_LLM_PROVIDER` (default: anthropic). */
|
|
54
|
+
export function resolveProviderKind() {
|
|
55
|
+
const raw = process.env.MCPMAKE_LLM_PROVIDER?.trim().toLowerCase();
|
|
56
|
+
if (!raw)
|
|
57
|
+
return 'anthropic';
|
|
58
|
+
if (PROVIDER_KINDS.includes(raw))
|
|
59
|
+
return raw;
|
|
60
|
+
logger.warn(`Unknown MCPMAKE_LLM_PROVIDER "${raw}" — falling back to "anthropic"`);
|
|
61
|
+
return 'anthropic';
|
|
62
|
+
}
|
|
63
|
+
/** The env var that holds the API key for a given provider kind. */
|
|
64
|
+
function keyVarFor(kind) {
|
|
65
|
+
return kind === 'anthropic' ? 'ANTHROPIC_API_KEY' : 'OPENAI_API_KEY';
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Build the active LLM provider from the environment, or return `null` when it
|
|
69
|
+
* is not usable (missing key, or an `openai-compatible` setup with no base
|
|
70
|
+
* URL). Optional AI steps treat `null` as "warn and skip", exactly as the old
|
|
71
|
+
* direct `ANTHROPIC_API_KEY` checks did. Required features should call
|
|
72
|
+
* {@link requireLlmProvider} instead so they fail with a clear message.
|
|
73
|
+
*/
|
|
74
|
+
export function getLlmProvider() {
|
|
75
|
+
const kind = resolveProviderKind();
|
|
76
|
+
if (kind === 'anthropic') {
|
|
77
|
+
const apiKey = process.env.ANTHROPIC_API_KEY?.trim();
|
|
78
|
+
if (!apiKey)
|
|
79
|
+
return null;
|
|
80
|
+
const baseURL = process.env.ANTHROPIC_BASE_URL?.trim() || undefined;
|
|
81
|
+
if (baseURL)
|
|
82
|
+
assertSafeBaseUrl('ANTHROPIC_BASE_URL', baseURL);
|
|
83
|
+
return new AnthropicProvider({ apiKey, baseURL });
|
|
84
|
+
}
|
|
85
|
+
// openai / openai-compatible
|
|
86
|
+
const apiKey = process.env.OPENAI_API_KEY?.trim();
|
|
87
|
+
const baseURL = process.env.OPENAI_BASE_URL?.trim() || undefined;
|
|
88
|
+
if (baseURL)
|
|
89
|
+
assertSafeBaseUrl('OPENAI_BASE_URL', baseURL);
|
|
90
|
+
if (kind === 'openai') {
|
|
91
|
+
if (!apiKey)
|
|
92
|
+
return null;
|
|
93
|
+
return new OpenAiProvider({ apiKey, baseURL, kind });
|
|
94
|
+
}
|
|
95
|
+
// openai-compatible: self-hosted servers (Ollama, vLLM, …) frequently need no
|
|
96
|
+
// key, but they do need an explicit endpoint.
|
|
97
|
+
if (!baseURL) {
|
|
98
|
+
logger.warn('MCPMAKE_LLM_PROVIDER=openai-compatible requires OPENAI_BASE_URL — skipping AI step');
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
return new OpenAiProvider({ apiKey: apiKey || 'not-needed', baseURL, kind });
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Like {@link getLlmProvider} but throws a provider-aware error instead of
|
|
105
|
+
* returning null — for features that cannot degrade (spec generation, goal
|
|
106
|
+
* crawl).
|
|
107
|
+
*/
|
|
108
|
+
export function requireLlmProvider(feature) {
|
|
109
|
+
const provider = getLlmProvider();
|
|
110
|
+
if (provider)
|
|
111
|
+
return provider;
|
|
112
|
+
const kind = resolveProviderKind();
|
|
113
|
+
const needs = keyVarFor(kind) + (kind === 'openai-compatible' ? ' and OPENAI_BASE_URL' : '');
|
|
114
|
+
throw new Error(`${feature} requires an LLM provider. Set ${needs} (active provider: ${kind}).`);
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/llm/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { CompleteJsonOptions, CompleteOptions, LlmProvider } from './types.js';
|
|
2
|
+
export interface OpenAiProviderOptions {
|
|
3
|
+
apiKey: string;
|
|
4
|
+
baseURL?: string;
|
|
5
|
+
kind: 'openai' | 'openai-compatible';
|
|
6
|
+
}
|
|
7
|
+
export declare class OpenAiProvider implements LlmProvider {
|
|
8
|
+
readonly name: string;
|
|
9
|
+
readonly supportsVision = true;
|
|
10
|
+
private readonly client;
|
|
11
|
+
private readonly kind;
|
|
12
|
+
private readonly modelCache;
|
|
13
|
+
private readonly baseURL;
|
|
14
|
+
private jsonDowngradeWarned;
|
|
15
|
+
constructor(opts: OpenAiProviderOptions);
|
|
16
|
+
/**
|
|
17
|
+
* Resolve a usable model id for a tier against the live `/v1/models` listing,
|
|
18
|
+
* so a retired id can never silently 404 the way a hardcoded snapshot does.
|
|
19
|
+
*
|
|
20
|
+
* Resolution order:
|
|
21
|
+
* 1. An explicit `override` (e.g. a `--model` flag) wins, unchecked — the
|
|
22
|
+
* caller knows what they want, and a bad id surfaces as a clear API error.
|
|
23
|
+
* 2. The tier's preferred id, **if** the listing contains it.
|
|
24
|
+
* 3. Otherwise the newest served model whose id matches the tier pattern.
|
|
25
|
+
* 4. No match: hosted OpenAI falls back to the preferred id; an
|
|
26
|
+
* openai-compatible server falls back to its first listed model (or throws
|
|
27
|
+
* if it lists nothing).
|
|
28
|
+
* 5. Listing throws (server has no `/v1/models`): hosted OpenAI returns the
|
|
29
|
+
* preferred id WITHOUT caching (so a later call retries); an
|
|
30
|
+
* openai-compatible server throws — there's nothing safe to guess.
|
|
31
|
+
*/
|
|
32
|
+
private resolveModel;
|
|
33
|
+
/**
|
|
34
|
+
* Output-token parameter, keyed by provider kind: newer hosted OpenAI models
|
|
35
|
+
* reject `max_tokens` and require `max_completion_tokens`, while many
|
|
36
|
+
* openai-compatible servers only understand the older `max_tokens`.
|
|
37
|
+
*/
|
|
38
|
+
private tokenParam;
|
|
39
|
+
/** Build the message list: a leading system message only when `system` is set. */
|
|
40
|
+
private buildMessages;
|
|
41
|
+
completeText({ system, prompt, tier, model, maxTokens }: CompleteOptions): Promise<string>;
|
|
42
|
+
completeJson<T = unknown>({ system, prompt, schema, tier, model, maxTokens, }: CompleteJsonOptions): Promise<T>;
|
|
43
|
+
/** Warn once when structured output is downgraded, so the loss is visible. */
|
|
44
|
+
private warnJsonDowngrade;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=openai-provider.d.ts.map
|