@mcpmake/core 0.3.3 → 0.3.5
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/goal-crawler.d.ts.map +1 -1
- package/dist/analyzer/goal-crawler.js +6 -12
- package/dist/analyzer/goal-crawler.js.map +1 -1
- package/dist/analyzer/same-origin.d.ts +21 -0
- package/dist/analyzer/same-origin.d.ts.map +1 -0
- package/dist/analyzer/same-origin.js +32 -0
- package/dist/analyzer/same-origin.js.map +1 -0
- package/dist/analyzer/semantic-analyzer.d.ts.map +1 -1
- package/dist/analyzer/semantic-analyzer.js +3 -0
- 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 +12 -13
- package/dist/analyzer/site-crawler.js.map +1 -1
- package/dist/emitter/index.d.ts.map +1 -1
- package/dist/emitter/index.js +149 -19
- package/dist/emitter/index.js.map +1 -1
- package/dist/emitter/mcpb-bundler.d.ts +14 -0
- package/dist/emitter/mcpb-bundler.d.ts.map +1 -1
- package/dist/emitter/mcpb-bundler.js +52 -4
- package/dist/emitter/mcpb-bundler.js.map +1 -1
- package/dist/emitter/project-scaffolder.d.ts +5 -0
- package/dist/emitter/project-scaffolder.d.ts.map +1 -1
- package/dist/emitter/project-scaffolder.js +1 -1
- package/dist/emitter/project-scaffolder.js.map +1 -1
- package/dist/emitter/python-annotations.d.ts +77 -0
- package/dist/emitter/python-annotations.d.ts.map +1 -0
- package/dist/emitter/python-annotations.js +330 -0
- package/dist/emitter/python-annotations.js.map +1 -0
- package/dist/emitter/python-template-loader.js +1 -1
- package/dist/emitter/python-template-loader.js.map +1 -1
- package/dist/emitter/python-templates/server.py.hbs +69 -33
- package/dist/emitter/site-templates/browser-manager.ts.hbs +145 -32
- package/dist/emitter/site-templates/config.ts.hbs +21 -4
- package/dist/emitter/site-templates/env.example.hbs +8 -0
- package/dist/emitter/site-templates/server-main-http.ts.hbs +13 -4
- package/dist/emitter/site-templates/server-main.ts.hbs +5 -2
- package/dist/emitter/site-templates/telemetry.ts.hbs +13 -2
- package/dist/emitter/templates/config.ts.hbs +29 -2
- package/dist/emitter/templates/discovery.ts.hbs +66 -13
- package/dist/emitter/templates/http-executor.ts.hbs +4 -3
- package/dist/emitter/templates/oauth.ts.hbs +1 -2
- package/dist/emitter/templates/readme.md.hbs +3 -2
- package/dist/emitter/templates/resources.ts.hbs +3 -2
- package/dist/emitter/templates/server-main-http.ts.hbs +218 -130
- package/dist/emitter/templates/task-handlers.ts.hbs +2 -1
- package/dist/emitter/templates/task-manager.ts.hbs +5 -3
- package/dist/emitter/templates/task-sse.ts.hbs +9 -1
- package/dist/emitter/templates/tool-handler.ts.hbs +17 -4
- package/dist/emitter/worker-templates/config.ts.hbs +25 -2
- package/dist/emitter/worker-templates/worker.ts.hbs +6 -2
- package/dist/emitter/worker-templates/wrangler.toml.hbs +5 -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/parser/har-normalizer.d.ts.map +1 -1
- package/dist/parser/har-normalizer.js +28 -3
- package/dist/parser/har-normalizer.js.map +1 -1
- package/dist/parser/openapi-loader.d.ts +19 -0
- package/dist/parser/openapi-loader.d.ts.map +1 -1
- package/dist/parser/openapi-loader.js +78 -10
- package/dist/parser/openapi-loader.js.map +1 -1
- package/dist/parser/operation-extractor.js +4 -4
- package/dist/parser/operation-extractor.js.map +1 -1
- package/dist/parser/overlay-loader.js +50 -11
- package/dist/parser/overlay-loader.js.map +1 -1
- package/dist/parser/postman-loader.d.ts.map +1 -1
- package/dist/parser/postman-loader.js +64 -6
- package/dist/parser/postman-loader.js.map +1 -1
- package/dist/parser/schema-converter.d.ts +15 -1
- package/dist/parser/schema-converter.d.ts.map +1 -1
- package/dist/parser/schema-converter.js +30 -2
- package/dist/parser/schema-converter.js.map +1 -1
- package/dist/recorder/browser-recorder.d.ts.map +1 -1
- package/dist/recorder/browser-recorder.js +2 -1
- package/dist/recorder/browser-recorder.js.map +1 -1
- package/dist/rescan/diff-engine.js +17 -10
- package/dist/rescan/diff-engine.js.map +1 -1
- package/dist/rescan/rescan-runner.js +4 -4
- package/dist/rescan/rescan-runner.js.map +1 -1
- package/dist/rescan/rescan-scheduler.d.ts +54 -2
- package/dist/rescan/rescan-scheduler.d.ts.map +1 -1
- package/dist/rescan/rescan-scheduler.js +193 -19
- package/dist/rescan/rescan-scheduler.js.map +1 -1
- package/dist/site-transformer/selector-healer.d.ts.map +1 -1
- package/dist/site-transformer/selector-healer.js +9 -0
- package/dist/site-transformer/selector-healer.js.map +1 -1
- package/dist/site-transformer/tool-generator.js +4 -7
- package/dist/site-transformer/tool-generator.js.map +1 -1
- package/dist/transformer/auth-detector.d.ts.map +1 -1
- package/dist/transformer/auth-detector.js +49 -1
- package/dist/transformer/auth-detector.js.map +1 -1
- package/dist/transformer/catalog-builder.d.ts +25 -3
- package/dist/transformer/catalog-builder.d.ts.map +1 -1
- package/dist/transformer/catalog-builder.js +32 -12
- package/dist/transformer/catalog-builder.js.map +1 -1
- package/dist/transformer/client-compat.d.ts.map +1 -1
- package/dist/transformer/client-compat.js +17 -6
- package/dist/transformer/client-compat.js.map +1 -1
- package/dist/transformer/har-dedup.js +2 -2
- package/dist/transformer/har-dedup.js.map +1 -1
- package/dist/transformer/har-to-operations.d.ts.map +1 -1
- package/dist/transformer/har-to-operations.js +10 -3
- package/dist/transformer/har-to-operations.js.map +1 -1
- package/dist/transformer/llm-namer.d.ts.map +1 -1
- package/dist/transformer/llm-namer.js +3 -0
- package/dist/transformer/llm-namer.js.map +1 -1
- package/dist/transformer/resource-builder.d.ts.map +1 -1
- package/dist/transformer/resource-builder.js +112 -18
- package/dist/transformer/resource-builder.js.map +1 -1
- package/dist/transformer/stainless-translator.d.ts.map +1 -1
- package/dist/transformer/stainless-translator.js +5 -2
- package/dist/transformer/stainless-translator.js.map +1 -1
- package/dist/transformer/tool-builder.d.ts.map +1 -1
- package/dist/transformer/tool-builder.js +67 -16
- package/dist/transformer/tool-builder.js.map +1 -1
- package/dist/types/index.d.ts +39 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/logger.d.ts +38 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +75 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/playwright-loader.d.ts +21 -0
- package/dist/utils/playwright-loader.d.ts.map +1 -0
- package/dist/utils/playwright-loader.js +21 -0
- package/dist/utils/playwright-loader.js.map +1 -0
- package/dist/utils/ssrf-guard.d.ts.map +1 -1
- package/dist/utils/ssrf-guard.js +8 -0
- package/dist/utils/ssrf-guard.js.map +1 -1
- package/package.json +4 -3
|
@@ -174,6 +174,39 @@ if (transportMode === 'http') {
|
|
|
174
174
|
}
|
|
175
175
|
const allowedOrigin = process.env.ALLOWED_ORIGIN;
|
|
176
176
|
const authToken = process.env.MCP_AUTH_TOKEN;
|
|
177
|
+
{{#if hasOAuth}}
|
|
178
|
+
/* ── OAuth issuer resolution inputs ──────────────────────────────────────
|
|
179
|
+
* The unauthenticated /.well-known/oauth-authorization-server endpoint must
|
|
180
|
+
* not reflect an arbitrary client-controlled Host header into the issuer
|
|
181
|
+
* (host-header spoofing). Operators pin the issuer with one of:
|
|
182
|
+
* - ALLOWED_ORIGIN (existing; takes precedence)
|
|
183
|
+
* - MCP_PUBLIC_URL (absolute http(s) URL; its origin is used)
|
|
184
|
+
* - MCP_ALLOWED_HOSTS (comma/space-separated Host allowlist)
|
|
185
|
+
* With none set we fall back to the request Host for backward-compat (dev),
|
|
186
|
+
* after warning once that the issuer is Host-derived. */
|
|
187
|
+
const mcpPublicOrigin = (() => {
|
|
188
|
+
const raw = process.env.MCP_PUBLIC_URL;
|
|
189
|
+
if (!raw) return undefined;
|
|
190
|
+
try {
|
|
191
|
+
const u = new URL(raw);
|
|
192
|
+
if (u.protocol !== 'http:' && u.protocol !== 'https:') {
|
|
193
|
+
log('error', 'MCP_PUBLIC_URL must be an http(s) URL — ignoring', { MCP_PUBLIC_URL: raw });
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
return u.origin;
|
|
197
|
+
} catch {
|
|
198
|
+
log('error', 'MCP_PUBLIC_URL is not a valid absolute URL — ignoring', { MCP_PUBLIC_URL: raw });
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
})();
|
|
202
|
+
const allowedHosts = new Set(
|
|
203
|
+
(process.env.MCP_ALLOWED_HOSTS ?? '')
|
|
204
|
+
.split(/[\s,]+/)
|
|
205
|
+
.map((h) => h.trim().toLowerCase())
|
|
206
|
+
.filter((h) => h.length > 0),
|
|
207
|
+
);
|
|
208
|
+
let warnedHostDerivedIssuer = false;
|
|
209
|
+
{{/if}}
|
|
177
210
|
/* Fail closed: with no MCP_AUTH_TOKEN the server denies every authenticated
|
|
178
211
|
* route (401) unless the operator opted in via MCP_ALLOW_UNAUTHENTICATED=true.
|
|
179
212
|
* Warn loudly, once, when running wide open so it is never a silent default. */
|
|
@@ -321,157 +354,209 @@ if (transportMode === 'http') {
|
|
|
321
354
|
}
|
|
322
355
|
|
|
323
356
|
const httpServer = http.createServer(async (req, res) => {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
357
|
+
try {
|
|
358
|
+
const url = new URL(req.url ?? '/', `http://localhost:${port}`);
|
|
359
|
+
const method = req.method ?? 'GET';
|
|
360
|
+
|
|
361
|
+
/* ── Authentication ─────────────────────────────────────────────
|
|
362
|
+
* Every endpoint except /health, /ready{{#if hasOAuth}}, and the public
|
|
363
|
+
* OAuth metadata{{/if}} requires a valid bearer token. With MCP_AUTH_TOKEN
|
|
364
|
+
* unset the server fails closed (401) unless MCP_ALLOW_UNAUTHENTICATED=true.
|
|
365
|
+
* This is the in-container line of defense; the hosting backend also
|
|
366
|
+
* validates before proxying. */
|
|
367
|
+
const isPublicPath =
|
|
368
|
+
url.pathname === '/health' ||
|
|
369
|
+
url.pathname === '/ready'{{#if hasOAuth}} ||
|
|
370
|
+
url.pathname === '/.well-known/oauth-authorization-server'{{/if}};
|
|
371
|
+
if (!isPublicPath && !isAuthorized(req, authToken)) {
|
|
372
|
+
log('error', 'Unauthorized request rejected', { path: url.pathname });
|
|
373
|
+
res.writeHead(401, {
|
|
374
|
+
'Content-Type': 'application/json',
|
|
375
|
+
'WWW-Authenticate': 'Bearer',
|
|
376
|
+
});
|
|
377
|
+
res.end(JSON.stringify({ error: 'Unauthorized: missing or invalid bearer token' }));
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
346
380
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
381
|
+
/* ── Routing-header observability (SEP-2243, additive) ─────────── */
|
|
382
|
+
const mcpMethod = req.headers['mcp-method'];
|
|
383
|
+
const mcpName = req.headers['mcp-name'];
|
|
384
|
+
if (mcpMethod || mcpName) {
|
|
385
|
+
log('info', 'mcp-meta-headers', { mcpMethod, mcpName, path: url.pathname });
|
|
386
|
+
}
|
|
353
387
|
|
|
354
388
|
{{#if hasOAuth}}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
389
|
+
/* ── OAuth Authorization Server Metadata (RFC 8414) ─────────────
|
|
390
|
+
* Public discovery endpoint (the 2026-07-28 auth changes clarify
|
|
391
|
+
* .well-known discovery; DCR is retained, not replaced). */
|
|
392
|
+
if (url.pathname === '/.well-known/oauth-authorization-server') {
|
|
393
|
+
if (method !== 'GET') {
|
|
394
|
+
res.writeHead(405, { Allow: 'GET' });
|
|
395
|
+
res.end();
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
const authorizationUrl = config.oauth2AuthorizationUrl;
|
|
399
|
+
const tokenUrl = config.oauth2TokenUrl;
|
|
400
|
+
if (!authorizationUrl || !tokenUrl) {
|
|
401
|
+
sendJson(res, 503, { error: 'OAuth is not configured' });
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
const proto = req.headers['x-forwarded-proto'] === 'https' ? 'https' : 'http';
|
|
405
|
+
/* Resolve the OAuth issuer without trusting an arbitrary Host header.
|
|
406
|
+
* Precedence: ALLOWED_ORIGIN → MCP_PUBLIC_URL → MCP_ALLOWED_HOSTS →
|
|
407
|
+
* (dev fallback) the request Host, but only when no allowlist/public
|
|
408
|
+
* URL pins it. When MCP_ALLOWED_HOSTS is configured, a Host outside it
|
|
409
|
+
* is rejected rather than reflected. */
|
|
410
|
+
const rawHost = req.headers.host;
|
|
411
|
+
const host = typeof rawHost === 'string' ? rawHost.toLowerCase() : undefined;
|
|
412
|
+
// Parse the Host once. `hostname` (no port, no userinfo) drives the
|
|
413
|
+
// allowlist so a bare-hostname allowlist (MCP_ALLOWED_HOSTS=example.com)
|
|
414
|
+
// matches `Host: example.com:3000`; `hostPort` (hostname:port, userinfo
|
|
415
|
+
// STRIPPED) builds the issuer so a `Host: evil@example.com` cannot inject
|
|
416
|
+
// a userinfo segment into the issued metadata. URL parsing also handles
|
|
417
|
+
// IPv6 brackets. Falls back to undefined when the Host is malformed.
|
|
418
|
+
const parsedHost = (() => {
|
|
419
|
+
if (typeof rawHost !== 'string') return undefined;
|
|
420
|
+
try {
|
|
421
|
+
const u = new URL(`http://${rawHost}`);
|
|
422
|
+
return { hostname: u.hostname.toLowerCase(), hostPort: u.host };
|
|
423
|
+
} catch {
|
|
424
|
+
return undefined;
|
|
425
|
+
}
|
|
426
|
+
})();
|
|
427
|
+
const hostNoPort = parsedHost?.hostname ?? host;
|
|
428
|
+
let issuer: string;
|
|
429
|
+
if (allowedOrigin) {
|
|
430
|
+
issuer = allowedOrigin;
|
|
431
|
+
} else if (mcpPublicOrigin) {
|
|
432
|
+
issuer = mcpPublicOrigin;
|
|
433
|
+
} else if (allowedHosts.size > 0) {
|
|
434
|
+
if (!host || (!allowedHosts.has(host) && !(hostNoPort && allowedHosts.has(hostNoPort)))) {
|
|
435
|
+
log('error', 'Invalid Host header for OAuth metadata', { host: rawHost });
|
|
436
|
+
sendJson(res, 400, { error: 'Invalid Host header for OAuth metadata' });
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
// Build from the parsed host:port (userinfo stripped), never raw.
|
|
440
|
+
issuer = `${proto}://${parsedHost?.hostPort ?? rawHost}`;
|
|
441
|
+
} else {
|
|
442
|
+
/* No issuer pinned: reflect the request Host for backward-compat with
|
|
443
|
+
* proxy deployments that set neither var. Warn once so operators know
|
|
444
|
+
* to lock it down via MCP_PUBLIC_URL or MCP_ALLOWED_HOSTS. */
|
|
445
|
+
if (!warnedHostDerivedIssuer) {
|
|
446
|
+
warnedHostDerivedIssuer = true;
|
|
447
|
+
log('info', 'OAuth issuer derived from the Host header — set MCP_PUBLIC_URL or MCP_ALLOWED_HOSTS to pin it', { host: rawHost });
|
|
448
|
+
}
|
|
449
|
+
issuer = `${proto}://${rawHost ?? 'localhost'}`;
|
|
450
|
+
}
|
|
451
|
+
sendJson(
|
|
452
|
+
res,
|
|
453
|
+
200,
|
|
454
|
+
getAuthServerMetadata(
|
|
455
|
+
{
|
|
456
|
+
clientId: config.oauth2ClientId ?? '',
|
|
457
|
+
clientSecret: config.oauth2ClientSecret,
|
|
458
|
+
authorizationUrl,
|
|
459
|
+
tokenUrl,
|
|
460
|
+
scopes: config.oauth2Scopes,
|
|
461
|
+
redirectUri: config.oauth2RedirectUri ?? '',
|
|
462
|
+
},
|
|
463
|
+
issuer,
|
|
464
|
+
),
|
|
465
|
+
);
|
|
368
466
|
return;
|
|
369
467
|
}
|
|
370
|
-
const proto = req.headers['x-forwarded-proto'] === 'https' ? 'https' : 'http';
|
|
371
|
-
const issuer = allowedOrigin ?? `${proto}://${req.headers.host ?? 'localhost'}`;
|
|
372
|
-
sendJson(
|
|
373
|
-
res,
|
|
374
|
-
200,
|
|
375
|
-
getAuthServerMetadata(
|
|
376
|
-
{
|
|
377
|
-
clientId: config.oauth2ClientId ?? '',
|
|
378
|
-
clientSecret: config.oauth2ClientSecret,
|
|
379
|
-
authorizationUrl,
|
|
380
|
-
tokenUrl,
|
|
381
|
-
scopes: config.oauth2Scopes,
|
|
382
|
-
redirectUri: config.oauth2RedirectUri ?? '',
|
|
383
|
-
},
|
|
384
|
-
issuer,
|
|
385
|
-
),
|
|
386
|
-
);
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
468
|
|
|
390
469
|
{{/if}}
|
|
391
470
|
{{#if hasAsyncTools}}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
471
|
+
/* ── Task management REST routes (retained during the grace period) ── */
|
|
472
|
+
if (handleTaskSse(req, res, url)) return;
|
|
473
|
+
if (handleTaskRoutes(req, res, url)) return;
|
|
395
474
|
|
|
396
475
|
{{/if}}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
476
|
+
if (url.pathname === '/mcp') {
|
|
477
|
+
/* Origin validation (DNS-rebinding protection per MCP spec) */
|
|
478
|
+
const origin = req.headers.origin;
|
|
479
|
+
if (allowedOrigin) {
|
|
480
|
+
if (origin && origin !== allowedOrigin) {
|
|
481
|
+
log('error', 'Origin rejected', { origin, allowedOrigin });
|
|
482
|
+
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
483
|
+
res.end(JSON.stringify({ error: 'Forbidden: invalid origin' }));
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
} else if (origin) {
|
|
487
|
+
/* No allowlist configured but Origin header present — reject cross-origin requests */
|
|
488
|
+
log('error', 'Cross-origin request rejected (ALLOWED_ORIGIN not set)', { origin });
|
|
403
489
|
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
404
|
-
res.end(JSON.stringify({ error: 'Forbidden:
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
|
-
} else if (origin) {
|
|
408
|
-
/* No allowlist configured but Origin header present — reject cross-origin requests */
|
|
409
|
-
log('error', 'Cross-origin request rejected (ALLOWED_ORIGIN not set)', { origin });
|
|
410
|
-
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
411
|
-
res.end(JSON.stringify({ error: 'Forbidden: ALLOWED_ORIGIN not configured' }));
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
/* POST carries a JSON-RPC body: peek for server/discover + tasks/* and
|
|
416
|
-
* forward the parsed body to the transport. GET/DELETE (SSE stream /
|
|
417
|
-
* session teardown) pass straight through. */
|
|
418
|
-
if (method === 'POST') {
|
|
419
|
-
const raw = await readBody(req);
|
|
420
|
-
if (raw === null) {
|
|
421
|
-
rpcError(res, null, -32600, 'Request body too large');
|
|
422
|
-
return;
|
|
423
|
-
}
|
|
424
|
-
if (raw.length === 0) {
|
|
425
|
-
rpcError(res, null, -32600, 'Empty request body');
|
|
426
|
-
return;
|
|
427
|
-
}
|
|
428
|
-
let parsed: unknown;
|
|
429
|
-
try {
|
|
430
|
-
parsed = JSON.parse(raw.toString('utf-8'));
|
|
431
|
-
} catch {
|
|
432
|
-
rpcError(res, null, -32700, 'Parse error');
|
|
490
|
+
res.end(JSON.stringify({ error: 'Forbidden: ALLOWED_ORIGIN not configured' }));
|
|
433
491
|
return;
|
|
434
492
|
}
|
|
435
493
|
|
|
436
|
-
/*
|
|
437
|
-
*
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
const
|
|
441
|
-
if (
|
|
442
|
-
|
|
494
|
+
/* POST carries a JSON-RPC body: peek for server/discover + tasks/* and
|
|
495
|
+
* forward the parsed body to the transport. GET/DELETE (SSE stream /
|
|
496
|
+
* session teardown) pass straight through. */
|
|
497
|
+
if (method === 'POST') {
|
|
498
|
+
const raw = await readBody(req);
|
|
499
|
+
if (raw === null) {
|
|
500
|
+
rpcError(res, null, -32600, 'Request body too large');
|
|
443
501
|
return;
|
|
444
502
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
503
|
+
if (raw.length === 0) {
|
|
504
|
+
rpcError(res, null, -32600, 'Empty request body');
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
let parsed: unknown;
|
|
508
|
+
try {
|
|
509
|
+
parsed = JSON.parse(raw.toString('utf-8'));
|
|
510
|
+
} catch {
|
|
511
|
+
rpcError(res, null, -32700, 'Parse error');
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/* Intercept single-object JSON-RPC extension methods the SDK doesn't
|
|
516
|
+
* dispatch yet. Batches are forwarded untouched. */
|
|
517
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
518
|
+
const rpcMethod = (parsed as { method?: unknown }).method;
|
|
519
|
+
const rpcId = (parsed as { id?: unknown }).id;
|
|
520
|
+
if (rpcMethod === 'server/discover') {
|
|
521
|
+
sendJson(res, 200, buildDiscoverResult(rpcId));
|
|
450
522
|
return;
|
|
451
523
|
}
|
|
452
|
-
|
|
524
|
+
{{#if hasAsyncTools}}
|
|
525
|
+
if (typeof rpcMethod === 'string' && rpcMethod.startsWith('tasks/')) {
|
|
526
|
+
const handled = handleTaskRpc(rpcMethod, (parsed as { params?: unknown }).params, rpcId);
|
|
527
|
+
if (handled) {
|
|
528
|
+
sendJson(res, 200, handled);
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
453
532
|
{{/if}}
|
|
454
|
-
|
|
533
|
+
}
|
|
455
534
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
535
|
+
await dispatchToTransport(req, res, parsed);
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
459
538
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
463
|
-
res.end(JSON.stringify({ status: 'ok' }));
|
|
464
|
-
} else if (url.pathname === '/ready') {
|
|
465
|
-
if (isReady) {
|
|
539
|
+
await dispatchToTransport(req, res);
|
|
540
|
+
} else if (url.pathname === '/health') {
|
|
466
541
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
467
|
-
res.end(JSON.stringify({ status: '
|
|
542
|
+
res.end(JSON.stringify({ status: 'ok' }));
|
|
543
|
+
} else if (url.pathname === '/ready') {
|
|
544
|
+
if (isReady) {
|
|
545
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
546
|
+
res.end(JSON.stringify({ status: 'ready' }));
|
|
547
|
+
} else {
|
|
548
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
549
|
+
res.end(JSON.stringify({ status: 'not ready' }));
|
|
550
|
+
}
|
|
468
551
|
} else {
|
|
469
|
-
res.writeHead(
|
|
470
|
-
res.end(
|
|
552
|
+
res.writeHead(404);
|
|
553
|
+
res.end('Not found');
|
|
554
|
+
}
|
|
555
|
+
} catch (e) {
|
|
556
|
+
log('error', 'Unhandled error in request handler', { err: String(e) });
|
|
557
|
+
if (!res.headersSent) {
|
|
558
|
+
sendJson(res, 500, { error: 'Internal server error' });
|
|
471
559
|
}
|
|
472
|
-
} else {
|
|
473
|
-
res.writeHead(404);
|
|
474
|
-
res.end('Not found');
|
|
475
560
|
}
|
|
476
561
|
});
|
|
477
562
|
|
|
@@ -489,8 +574,8 @@ if (transportMode === 'http') {
|
|
|
489
574
|
|
|
490
575
|
/* ── Graceful shutdown ─────────────────────────────────────────────── */
|
|
491
576
|
|
|
492
|
-
|
|
493
|
-
log('info',
|
|
577
|
+
const shutdown = (signal: string) => {
|
|
578
|
+
log('info', `${signal} received, shutting down`);
|
|
494
579
|
isReady = false;
|
|
495
580
|
clearInterval(reaper);
|
|
496
581
|
|
|
@@ -514,7 +599,10 @@ if (transportMode === 'http') {
|
|
|
514
599
|
log('error', 'Shutdown timed out after 5 s, forcing exit');
|
|
515
600
|
process.exit(1);
|
|
516
601
|
}, 5000).unref();
|
|
517
|
-
}
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
605
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
518
606
|
} else {
|
|
519
607
|
const server = createMcpServer(config);
|
|
520
608
|
const transport = new StdioServerTransport();
|
|
@@ -131,7 +131,8 @@ export function handleTaskRoutes(
|
|
|
131
131
|
|
|
132
132
|
const statusParam = url.searchParams.get('status') ?? undefined;
|
|
133
133
|
const limitParam = url.searchParams.get('limit');
|
|
134
|
-
const
|
|
134
|
+
const rawLimit = parseInt(limitParam ?? '', 10);
|
|
135
|
+
const limit = Number.isInteger(rawLimit) && rawLimit > 0 && rawLimit <= 1000 ? rawLimit : 50;
|
|
135
136
|
|
|
136
137
|
if (statusParam && !VALID_STATUSES.has(statusParam)) {
|
|
137
138
|
sendJson(res, 400, { error: `Invalid status filter: ${statusParam}` });
|
|
@@ -35,10 +35,12 @@ const MAX_TASKS = 1000;
|
|
|
35
35
|
export const taskEvents = new EventEmitter();
|
|
36
36
|
|
|
37
37
|
export function createTask(toolName: string): Task {
|
|
38
|
-
// Evict oldest if
|
|
38
|
+
// Evict a terminal task first; only fall back to the oldest (by insertion order) if none exist.
|
|
39
39
|
if (tasks.size >= MAX_TASKS) {
|
|
40
|
-
const
|
|
41
|
-
|
|
40
|
+
const terminalKey = [...tasks.entries()].find(
|
|
41
|
+
([, t]) => t.status === 'completed' || t.status === 'failed' || t.status === 'cancelled',
|
|
42
|
+
)?.[0] ?? tasks.keys().next().value;
|
|
43
|
+
if (terminalKey !== undefined) tasks.delete(terminalKey);
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
const task: Task = {
|
|
@@ -37,7 +37,7 @@ function stopHeartbeatIfEmpty(): void {
|
|
|
37
37
|
function broadcast(eventName: string, data: unknown, taskId: string): void {
|
|
38
38
|
const payload = `event: ${eventName}\ndata: ${JSON.stringify(data)}\n\n`;
|
|
39
39
|
for (const conn of connections) {
|
|
40
|
-
if (conn.res.writableEnded) continue;
|
|
40
|
+
if (conn.res.writableEnded) { connections.delete(conn); continue; }
|
|
41
41
|
if (conn.taskIdFilter && conn.taskIdFilter !== taskId) continue;
|
|
42
42
|
conn.res.write(payload);
|
|
43
43
|
}
|
|
@@ -83,6 +83,14 @@ export function handleTaskSse(
|
|
|
83
83
|
|
|
84
84
|
const taskIdFilter = url.searchParams.get('taskId') ?? null;
|
|
85
85
|
|
|
86
|
+
const rawMax = parseInt(process.env.MCP_MAX_SSE_CONNECTIONS ?? '', 10);
|
|
87
|
+
const maxConnections = Number.isInteger(rawMax) && rawMax > 0 ? rawMax : 500;
|
|
88
|
+
if (connections.size >= maxConnections) {
|
|
89
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
90
|
+
res.end(JSON.stringify({ error: 'SSE connection limit reached' }));
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
|
|
86
94
|
res.writeHead(200, {
|
|
87
95
|
'Content-Type': 'text/event-stream',
|
|
88
96
|
'Cache-Control': 'no-cache',
|
|
@@ -31,9 +31,9 @@ const controlSchema = {
|
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
const inputSchema = ({{{inputSchemaCode}}}).extend(controlSchema);
|
|
34
|
-
{{#if outputSchemaCode}}
|
|
34
|
+
{{#if outputSchemaCode}}{{#unless isAsync}}
|
|
35
35
|
const outputSchema = {{{outputSchemaCode}}};
|
|
36
|
-
{{/if}}
|
|
36
|
+
{{/unless}}{{/if}}
|
|
37
37
|
|
|
38
38
|
/** Execute the HTTP request for this tool and return the (optionally filtered) data. */
|
|
39
39
|
async function runRequest(rawInput: Record<string, unknown>, config: AppConfig): Promise<unknown> {
|
|
@@ -86,9 +86,9 @@ export function register(server: McpServer, config: AppConfig): void {
|
|
|
86
86
|
title: '{{title}}',
|
|
87
87
|
description: `{{{description}}}`,
|
|
88
88
|
inputSchema,
|
|
89
|
-
{{#if outputSchemaCode}}
|
|
89
|
+
{{#if outputSchemaCode}}{{#unless isAsync}}
|
|
90
90
|
outputSchema,
|
|
91
|
-
{{/if}}
|
|
91
|
+
{{/unless}}{{/if}}
|
|
92
92
|
{{#if annotations}}
|
|
93
93
|
annotations: {
|
|
94
94
|
{{#if annotations.readOnlyHint}}
|
|
@@ -136,6 +136,19 @@ export function register(server: McpServer, config: AppConfig): void {
|
|
|
136
136
|
text: JSON.stringify(result, null, 2),
|
|
137
137
|
},
|
|
138
138
|
],
|
|
139
|
+
{{#if outputSchemaCode}}{{#unless isAsync}}
|
|
140
|
+
// MCP SDK validates structuredContent against outputSchema when set.
|
|
141
|
+
// wrapArrayRoot (schema-converter.ts) wraps ONLY type:array schemas as
|
|
142
|
+
// { type:object, properties:{ items }, required:[items] } and passes
|
|
143
|
+
// objects AND scalars through bare. Mirror that exactly at runtime:
|
|
144
|
+
// - array → { items: result } (matches the wrapped object schema)
|
|
145
|
+
// - object → result as-is (bare object, no wrap)
|
|
146
|
+
// - scalar → result as-is (bare scalar; cast required for TS)
|
|
147
|
+
structuredContent:
|
|
148
|
+
Array.isArray(result)
|
|
149
|
+
? { items: result }
|
|
150
|
+
: (result as unknown as Record<string, unknown>),
|
|
151
|
+
{{/unless}}{{/if}}
|
|
139
152
|
};
|
|
140
153
|
} catch (error) {
|
|
141
154
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -7,18 +7,26 @@ export interface AppConfig {
|
|
|
7
7
|
baseUrl: string;
|
|
8
8
|
{{#each authSchemes}}
|
|
9
9
|
{{#if (eq type "apiKey")}}
|
|
10
|
+
{{#unless (eq emitApiKeyValue false)}}
|
|
10
11
|
apiKey?: string;
|
|
12
|
+
{{/unless}}
|
|
11
13
|
{{#if (eq in "query")}}
|
|
14
|
+
{{#unless (eq emitApiKeyQueryName false)}}
|
|
12
15
|
/** Query-parameter name the API key is appended under (apiKey-in-query auth). */
|
|
13
16
|
apiKeyQueryName?: string;
|
|
17
|
+
{{/unless}}
|
|
14
18
|
{{/if}}
|
|
15
19
|
{{/if}}
|
|
16
20
|
{{#if (eq type "http-bearer")}}
|
|
21
|
+
{{#unless (eq emitBearer false)}}
|
|
17
22
|
bearerToken?: string;
|
|
23
|
+
{{/unless}}
|
|
18
24
|
{{/if}}
|
|
19
25
|
{{#if (eq type "http-basic")}}
|
|
26
|
+
{{#unless (eq emitBasic false)}}
|
|
20
27
|
basicUsername?: string;
|
|
21
28
|
basicPassword?: string;
|
|
29
|
+
{{/unless}}
|
|
22
30
|
{{/if}}
|
|
23
31
|
{{/each}}
|
|
24
32
|
maxRetries: number;
|
|
@@ -29,6 +37,17 @@ export interface AppConfig {
|
|
|
29
37
|
|
|
30
38
|
type EnvLike = Record<string, string | undefined>;
|
|
31
39
|
|
|
40
|
+
const posInt = (v: string | undefined, d: number): number => {
|
|
41
|
+
const n = parseInt(v ?? '', 10);
|
|
42
|
+
return Number.isInteger(n) && n > 0 ? n : d;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/** Like posInt but accepts 0 — useful where 0 is a meaningful "disable" value. */
|
|
46
|
+
const nonNegInt = (v: string | undefined, d: number): number => {
|
|
47
|
+
const n = parseInt(v ?? '', 10);
|
|
48
|
+
return Number.isInteger(n) && n >= 0 ? n : d;
|
|
49
|
+
};
|
|
50
|
+
|
|
32
51
|
/**
|
|
33
52
|
* Resolve the upstream base URL with optional named environments.
|
|
34
53
|
* `MCP_ENVIRONMENTS` is a JSON object mapping name → base URL; `API_ENVIRONMENT`
|
|
@@ -72,9 +91,13 @@ export function loadConfig(env: EnvLike): AppConfig {
|
|
|
72
91
|
baseUrl: resolveBaseUrl(env),
|
|
73
92
|
{{#each authSchemes}}
|
|
74
93
|
{{#if (eq type "apiKey")}}
|
|
94
|
+
{{#unless (eq emitApiKeyValue false)}}
|
|
75
95
|
apiKey: env.{{envVarName}},
|
|
96
|
+
{{/unless}}
|
|
76
97
|
{{#if (eq in "query")}}
|
|
98
|
+
{{#unless (eq emitApiKeyQueryName false)}}
|
|
77
99
|
apiKeyQueryName: {{{json headerName}}},
|
|
100
|
+
{{/unless}}
|
|
78
101
|
{{/if}}
|
|
79
102
|
{{/if}}
|
|
80
103
|
{{#if (eq type "http-bearer")}}
|
|
@@ -85,8 +108,8 @@ export function loadConfig(env: EnvLike): AppConfig {
|
|
|
85
108
|
basicPassword: env.BASIC_PASSWORD,
|
|
86
109
|
{{/if}}
|
|
87
110
|
{{/each}}
|
|
88
|
-
maxRetries:
|
|
89
|
-
requestIntervalMs:
|
|
111
|
+
maxRetries: nonNegInt(env.MAX_RETRIES, 3),
|
|
112
|
+
requestIntervalMs: nonNegInt(env.REQUEST_INTERVAL_MS, 100),
|
|
90
113
|
defaultHeaders: loadDefaultHeaders(env),
|
|
91
114
|
};
|
|
92
115
|
}
|
|
@@ -216,8 +216,12 @@ async function handleToolCall(
|
|
|
216
216
|
if (!parsed.success) {
|
|
217
217
|
return err(id, -32602, `Invalid arguments for ${name}: ${parsed.error.message}`);
|
|
218
218
|
}
|
|
219
|
-
|
|
220
|
-
|
|
219
|
+
try {
|
|
220
|
+
const result = await entry.handler(parsed.data as Record<string, unknown>, config);
|
|
221
|
+
return ok(id, result);
|
|
222
|
+
} catch {
|
|
223
|
+
return err(id, -32000, 'Tool execution error');
|
|
224
|
+
}
|
|
221
225
|
}
|
|
222
226
|
|
|
223
227
|
/* Map `items` through `fn` with at most `limit` in flight at once, preserving
|
|
@@ -7,7 +7,11 @@ compatibility_flags = ["nodejs_compat"]
|
|
|
7
7
|
|
|
8
8
|
# Non-secret configuration. Override per-environment as needed.
|
|
9
9
|
[vars]
|
|
10
|
-
|
|
10
|
+
# {{{json}}} emits a JSON string literal, which is a valid TOML basic string with
|
|
11
|
+
# identical escape semantics. Unlike a raw "{{baseUrl}}" interpolation, this fully
|
|
12
|
+
# escapes backslashes/quotes/newlines so an attacker-controlled URL cannot inject a
|
|
13
|
+
# spurious key or [section] header into the generated wrangler.toml (A4-15).
|
|
14
|
+
BASE_URL = {{{json baseUrl}}}
|
|
11
15
|
MAX_RETRIES = "3"
|
|
12
16
|
REQUEST_INTERVAL_MS = "100"
|
|
13
17
|
# ALLOWED_ORIGIN = "https://your-client.example.com"
|
package/dist/index.d.ts
CHANGED
|
@@ -74,6 +74,7 @@ export { fail } from './utils/fail.js';
|
|
|
74
74
|
export { pathExists } from './utils/fs.js';
|
|
75
75
|
export { confirmOperations } from './utils/interactive.js';
|
|
76
76
|
export { watchFile } from './utils/watcher.js';
|
|
77
|
+
export { loadChromium } from './utils/playwright-loader.js';
|
|
77
78
|
export { FAMILY_A_PRICING, DEFAULT_PRICING_SERVER, fetchPricing, formatPrice } from './pricing.js';
|
|
78
79
|
export type { BillingPeriod, PricePoint } from './pricing.js';
|
|
79
80
|
//# sourceMappingURL=index.d.ts.map
|
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,eAAe,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACpG,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;
|
|
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,eAAe,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACpG,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;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAK5D,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACnG,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -97,6 +97,7 @@ export { fail } from './utils/fail.js';
|
|
|
97
97
|
export { pathExists } from './utils/fs.js';
|
|
98
98
|
export { confirmOperations } from './utils/interactive.js';
|
|
99
99
|
export { watchFile } from './utils/watcher.js';
|
|
100
|
+
export { loadChromium } from './utils/playwright-loader.js';
|
|
100
101
|
// ---------------------------------------------------------------------------
|
|
101
102
|
// Pricing
|
|
102
103
|
// ---------------------------------------------------------------------------
|