mcpmake 0.1.1 → 0.2.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/README.md +88 -635
- package/dist/commands/bundle.d.ts +1 -0
- package/dist/commands/bundle.d.ts.map +1 -0
- package/dist/commands/bundle.js +5 -4
- package/dist/commands/bundle.js.map +1 -0
- package/dist/commands/ci.d.ts +1 -0
- package/dist/commands/ci.d.ts.map +1 -0
- package/dist/commands/ci.js +3 -2
- package/dist/commands/ci.js.map +1 -0
- package/dist/commands/deploy.d.ts +1 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +4 -3
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/diff.d.ts +1 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +5 -4
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/from/describe.d.ts +1 -0
- package/dist/commands/from/describe.d.ts.map +1 -0
- package/dist/commands/from/describe.js +11 -10
- package/dist/commands/from/describe.js.map +1 -0
- package/dist/commands/from/har.d.ts +1 -0
- package/dist/commands/from/har.d.ts.map +1 -0
- package/dist/commands/from/har.js +14 -13
- package/dist/commands/from/har.js.map +1 -0
- package/dist/commands/from/openapi.d.ts +1 -0
- package/dist/commands/from/openapi.d.ts.map +1 -0
- package/dist/commands/from/openapi.js +17 -16
- package/dist/commands/from/openapi.js.map +1 -0
- package/dist/commands/from/postman.d.ts +1 -0
- package/dist/commands/from/postman.d.ts.map +1 -0
- package/dist/commands/from/postman.js +13 -12
- package/dist/commands/from/postman.js.map +1 -0
- package/dist/commands/from/stainless.d.ts +110 -0
- package/dist/commands/from/stainless.d.ts.map +1 -0
- package/dist/commands/from/stainless.js +272 -0
- package/dist/commands/from/stainless.js.map +1 -0
- package/dist/commands/from/target-support.d.ts +1 -0
- package/dist/commands/from/target-support.d.ts.map +1 -0
- package/dist/commands/from/target-support.js +2 -1
- package/dist/commands/from/target-support.js.map +1 -0
- package/dist/commands/from/url.d.ts +1 -0
- package/dist/commands/from/url.d.ts.map +1 -0
- package/dist/commands/from/url.js +14 -13
- package/dist/commands/from/url.js.map +1 -0
- package/dist/commands/from/website.d.ts +1 -0
- package/dist/commands/from/website.d.ts.map +1 -0
- package/dist/commands/from/website.js +17 -16
- package/dist/commands/from/website.js.map +1 -0
- package/dist/commands/lint.d.ts +1 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +6 -5
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/merge.d.ts +1 -0
- package/dist/commands/merge.d.ts.map +1 -0
- package/dist/commands/merge.js +3 -2
- package/dist/commands/merge.js.map +1 -0
- package/dist/commands/publish.d.ts +1 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +4 -3
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/rescan.d.ts +1 -0
- package/dist/commands/rescan.d.ts.map +1 -0
- package/dist/commands/rescan.js +12 -11
- package/dist/commands/rescan.js.map +1 -0
- package/dist/commands/update.d.ts +1 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +10 -9
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/verify.d.ts +1 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +7 -6
- package/dist/commands/verify.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -2
- package/dist/index.js.map +1 -0
- package/dist/registry/official-registry.d.ts +1 -0
- package/dist/registry/official-registry.d.ts.map +1 -0
- package/dist/registry/official-registry.js +1 -0
- package/dist/registry/official-registry.js.map +1 -0
- package/package.json +20 -46
- package/dist/analyzer/auth-detector.d.ts +0 -12
- package/dist/analyzer/auth-detector.js +0 -142
- package/dist/analyzer/dom-parser.d.ts +0 -10
- package/dist/analyzer/dom-parser.js +0 -259
- package/dist/analyzer/goal-crawler.d.ts +0 -25
- package/dist/analyzer/goal-crawler.js +0 -177
- package/dist/analyzer/hybrid-detector.d.ts +0 -28
- package/dist/analyzer/hybrid-detector.js +0 -96
- package/dist/analyzer/index.d.ts +0 -12
- package/dist/analyzer/index.js +0 -8
- package/dist/analyzer/screenshot-capture.d.ts +0 -29
- package/dist/analyzer/screenshot-capture.js +0 -42
- package/dist/analyzer/selector-builder.d.ts +0 -19
- package/dist/analyzer/selector-builder.js +0 -199
- package/dist/analyzer/semantic-analyzer.d.ts +0 -13
- package/dist/analyzer/semantic-analyzer.js +0 -145
- package/dist/analyzer/site-crawler.d.ts +0 -38
- package/dist/analyzer/site-crawler.js +0 -235
- package/dist/cloud/billing/billing-engine.d.ts +0 -44
- package/dist/cloud/billing/billing-engine.js +0 -81
- package/dist/cloud/billing/credit-store.d.ts +0 -64
- package/dist/cloud/billing/credit-store.js +0 -168
- package/dist/cloud/billing/index.d.ts +0 -4
- package/dist/cloud/billing/index.js +0 -2
- package/dist/cloud/billing/usage-store.d.ts +0 -42
- package/dist/cloud/billing/usage-store.js +0 -85
- package/dist/cloud/billing/usage-tracker.d.ts +0 -38
- package/dist/cloud/billing/usage-tracker.js +0 -95
- package/dist/cloud/build-pipeline.d.ts +0 -39
- package/dist/cloud/build-pipeline.js +0 -310
- package/dist/cloud/build-queue.d.ts +0 -30
- package/dist/cloud/build-queue.js +0 -70
- package/dist/cloud/caddy-manager.d.ts +0 -18
- package/dist/cloud/caddy-manager.js +0 -97
- package/dist/cloud/container-backend.d.ts +0 -62
- package/dist/cloud/container-backend.js +0 -59
- package/dist/cloud/container-manager.d.ts +0 -64
- package/dist/cloud/container-manager.js +0 -301
- package/dist/cloud/crypto.d.ts +0 -27
- package/dist/cloud/crypto.js +0 -63
- package/dist/cloud/db/index.d.ts +0 -27
- package/dist/cloud/db/index.js +0 -53
- package/dist/cloud/db/migrations.d.ts +0 -12
- package/dist/cloud/db/migrations.js +0 -329
- package/dist/cloud/db/pg-store.d.ts +0 -45
- package/dist/cloud/db/pg-store.js +0 -336
- package/dist/cloud/failure-tracker.d.ts +0 -51
- package/dist/cloud/failure-tracker.js +0 -102
- package/dist/cloud/idle-monitor.d.ts +0 -30
- package/dist/cloud/idle-monitor.js +0 -70
- package/dist/cloud/mailer.d.ts +0 -21
- package/dist/cloud/mailer.js +0 -193
- package/dist/cloud/mcp-proxy.d.ts +0 -58
- package/dist/cloud/mcp-proxy.js +0 -203
- package/dist/cloud/metric-samples.d.ts +0 -43
- package/dist/cloud/metric-samples.js +0 -85
- package/dist/cloud/metrics.d.ts +0 -26
- package/dist/cloud/metrics.js +0 -59
- package/dist/cloud/multipart.d.ts +0 -26
- package/dist/cloud/multipart.js +0 -132
- package/dist/cloud/observability.d.ts +0 -27
- package/dist/cloud/observability.js +0 -98
- package/dist/cloud/rate-limiter.d.ts +0 -31
- package/dist/cloud/rate-limiter.js +0 -58
- package/dist/cloud/request-security.d.ts +0 -5
- package/dist/cloud/request-security.js +0 -74
- package/dist/cloud/resource-monitor.d.ts +0 -69
- package/dist/cloud/resource-monitor.js +0 -130
- package/dist/cloud/secret-store.d.ts +0 -38
- package/dist/cloud/secret-store.js +0 -103
- package/dist/cloud/security.d.ts +0 -26
- package/dist/cloud/security.js +0 -142
- package/dist/cloud/server.d.ts +0 -21
- package/dist/cloud/server.js +0 -1079
- package/dist/cloud/shared-state.d.ts +0 -72
- package/dist/cloud/shared-state.js +0 -159
- package/dist/cloud/ssrf.d.ts +0 -43
- package/dist/cloud/ssrf.js +0 -150
- package/dist/cloud/store.d.ts +0 -41
- package/dist/cloud/store.js +0 -75
- package/dist/cloud/stripe.d.ts +0 -78
- package/dist/cloud/stripe.js +0 -317
- package/dist/cloud/telemetry-store.d.ts +0 -53
- package/dist/cloud/telemetry-store.js +0 -108
- package/dist/cloud/web/auth.d.ts +0 -225
- package/dist/cloud/web/auth.js +0 -555
- package/dist/cloud/web/charts.d.ts +0 -70
- package/dist/cloud/web/charts.js +0 -178
- package/dist/cloud/web/csrf.d.ts +0 -14
- package/dist/cloud/web/csrf.js +0 -22
- package/dist/cloud/web/docs.d.ts +0 -40
- package/dist/cloud/web/docs.js +0 -174
- package/dist/cloud/web/router.d.ts +0 -25
- package/dist/cloud/web/router.js +0 -1921
- package/dist/cloud/web/static/alpine.min.js +0 -5
- package/dist/cloud/web/static/favicon.svg +0 -4
- package/dist/cloud/web/static/htmx-sse.js +0 -290
- package/dist/cloud/web/static/htmx.min.js +0 -1
- package/dist/cloud/web/static/style.css +0 -2683
- package/dist/cloud/web/static-server.d.ts +0 -13
- package/dist/cloud/web/static-server.js +0 -73
- package/dist/cloud/web/template-engine.d.ts +0 -27
- package/dist/cloud/web/template-engine.js +0 -146
- package/dist/cloud/web/templates/layouts/admin.hbs +0 -57
- package/dist/cloud/web/templates/layouts/auth.hbs +0 -138
- package/dist/cloud/web/templates/layouts/base.hbs +0 -16
- package/dist/cloud/web/templates/layouts/dashboard.hbs +0 -39
- package/dist/cloud/web/templates/layouts/landing.hbs +0 -82
- package/dist/cloud/web/templates/pages/admin/overview.hbs +0 -123
- package/dist/cloud/web/templates/pages/admin/servers.hbs +0 -129
- package/dist/cloud/web/templates/pages/admin/telemetry.hbs +0 -39
- package/dist/cloud/web/templates/pages/admin/user-edit.hbs +0 -91
- package/dist/cloud/web/templates/pages/admin/users.hbs +0 -179
- package/dist/cloud/web/templates/pages/auth/forgot-password.hbs +0 -25
- package/dist/cloud/web/templates/pages/auth/login.hbs +0 -33
- package/dist/cloud/web/templates/pages/auth/register.hbs +0 -32
- package/dist/cloud/web/templates/pages/auth/reset-password.hbs +0 -34
- package/dist/cloud/web/templates/pages/dashboard/billing.hbs +0 -140
- package/dist/cloud/web/templates/pages/dashboard/create.hbs +0 -173
- package/dist/cloud/web/templates/pages/dashboard/index.hbs +0 -8
- package/dist/cloud/web/templates/pages/dashboard/server-detail.hbs +0 -280
- package/dist/cloud/web/templates/pages/dashboard/server-logs.hbs +0 -35
- package/dist/cloud/web/templates/pages/dashboard/server-metrics.hbs +0 -63
- package/dist/cloud/web/templates/pages/dashboard/servers-partial.hbs +0 -21
- package/dist/cloud/web/templates/pages/dashboard/servers.hbs +0 -44
- package/dist/cloud/web/templates/pages/docs/show.hbs +0 -16
- package/dist/cloud/web/templates/pages/errors/404.hbs +0 -9
- package/dist/cloud/web/templates/pages/errors/500.hbs +0 -8
- package/dist/cloud/web/templates/pages/landing/index.hbs +0 -223
- package/dist/cloud/web/templates/pages/legal/privacy.hbs +0 -71
- package/dist/cloud/web/templates/pages/legal/terms.hbs +0 -73
- package/dist/cloud/web/templates/partials/admin-stats.hbs +0 -52
- package/dist/cloud/web/templates/partials/flash-message.hbs +0 -6
- package/dist/cloud/web/templates/partials/pricing-table.hbs +0 -103
- package/dist/cloud/web/templates/partials/server-card.hbs +0 -19
- package/dist/cloud/web/templates/partials/status-badge.hbs +0 -1
- package/dist/config/configurable-command.d.ts +0 -13
- package/dist/config/configurable-command.js +0 -70
- package/dist/config/mcpmake-config.d.ts +0 -68
- package/dist/config/mcpmake-config.js +0 -207
- package/dist/docs/cli.md +0 -400
- package/dist/docs/mcp-2026-07-28-migration.md +0 -78
- package/dist/docs/migrate-from-stainless.md +0 -94
- package/dist/docs/quickstart.md +0 -166
- package/dist/docs/show-hn.md +0 -26
- package/dist/docs/website-servers.md +0 -169
- package/dist/emitter/code-writer.d.ts +0 -8
- package/dist/emitter/code-writer.js +0 -25
- package/dist/emitter/index.d.ts +0 -32
- package/dist/emitter/index.js +0 -280
- package/dist/emitter/mcpb-bundler.d.ts +0 -31
- package/dist/emitter/mcpb-bundler.js +0 -172
- package/dist/emitter/project-scaffolder.d.ts +0 -4
- package/dist/emitter/project-scaffolder.js +0 -89
- package/dist/emitter/python-template-loader.d.ts +0 -4
- package/dist/emitter/python-template-loader.js +0 -30
- package/dist/emitter/python-templates/dockerfile.hbs +0 -14
- package/dist/emitter/python-templates/env.example.hbs +0 -6
- package/dist/emitter/python-templates/requirements.txt.hbs +0 -4
- package/dist/emitter/python-templates/server.py.hbs +0 -77
- package/dist/emitter/site-scaffolder.d.ts +0 -13
- package/dist/emitter/site-scaffolder.js +0 -70
- package/dist/emitter/site-template-loader.d.ts +0 -5
- package/dist/emitter/site-template-loader.js +0 -47
- package/dist/emitter/site-templates/browser-manager.ts.hbs +0 -233
- package/dist/emitter/site-templates/config.ts.hbs +0 -28
- package/dist/emitter/site-templates/dockerfile.hbs +0 -31
- package/dist/emitter/site-templates/env.example.hbs +0 -19
- package/dist/emitter/site-templates/package.json.hbs +0 -26
- package/dist/emitter/site-templates/server-main-http.ts.hbs +0 -108
- package/dist/emitter/site-templates/server-main.ts.hbs +0 -23
- package/dist/emitter/site-templates/tool-handler-action.ts.hbs +0 -86
- package/dist/emitter/site-templates/tool-handler-form.ts.hbs +0 -116
- package/dist/emitter/site-templates/tool-handler-lifecycle.ts.hbs +0 -146
- package/dist/emitter/site-templates/tool-index.ts.hbs +0 -11
- package/dist/emitter/template-loader.d.ts +0 -1
- package/dist/emitter/template-loader.js +0 -27
- package/dist/emitter/templates/auth-provider.ts.hbs +0 -57
- package/dist/emitter/templates/config.ts.hbs +0 -63
- package/dist/emitter/templates/discovery.ts.hbs +0 -301
- package/dist/emitter/templates/dockerfile.hbs +0 -34
- package/dist/emitter/templates/env.example.hbs +0 -28
- package/dist/emitter/templates/gitignore.hbs +0 -5
- package/dist/emitter/templates/http-executor.ts.hbs +0 -117
- package/dist/emitter/templates/oauth.ts.hbs +0 -188
- package/dist/emitter/templates/package.json.hbs +0 -25
- package/dist/emitter/templates/prompts.ts.hbs +0 -22
- package/dist/emitter/templates/readme.md.hbs +0 -123
- package/dist/emitter/templates/resources.ts.hbs +0 -63
- package/dist/emitter/templates/server-main-http.ts.hbs +0 -407
- package/dist/emitter/templates/server-main.ts.hbs +0 -40
- package/dist/emitter/templates/task-handlers.ts.hbs +0 -189
- package/dist/emitter/templates/task-manager.ts.hbs +0 -139
- package/dist/emitter/templates/task-sse.ts.hbs +0 -105
- package/dist/emitter/templates/tool-handler.ts.hbs +0 -124
- package/dist/emitter/templates/tool-index.ts.hbs +0 -11
- package/dist/emitter/templates/tool-test.ts.hbs +0 -57
- package/dist/emitter/templates/trace.ts.hbs +0 -79
- package/dist/emitter/templates/tsconfig.json.hbs +0 -16
- package/dist/emitter/templates/types.ts.hbs +0 -5
- package/dist/emitter/worker-template-loader.d.ts +0 -5
- package/dist/emitter/worker-template-loader.js +0 -33
- package/dist/emitter/worker-templates/config.ts.hbs +0 -54
- package/dist/emitter/worker-templates/dev-vars.example.hbs +0 -10
- package/dist/emitter/worker-templates/gitignore.hbs +0 -6
- package/dist/emitter/worker-templates/package.json.hbs +0 -24
- package/dist/emitter/worker-templates/readme.md.hbs +0 -53
- package/dist/emitter/worker-templates/server.test.ts.hbs +0 -20
- package/dist/emitter/worker-templates/tool-handler.ts.hbs +0 -85
- package/dist/emitter/worker-templates/tool-index.ts.hbs +0 -28
- package/dist/emitter/worker-templates/tsconfig.json.hbs +0 -17
- package/dist/emitter/worker-templates/worker.ts.hbs +0 -242
- package/dist/emitter/worker-templates/wrangler.toml.hbs +0 -19
- package/dist/generator/spec-generator.d.ts +0 -6
- package/dist/generator/spec-generator.js +0 -50
- package/dist/parser/har-filter.d.ts +0 -8
- package/dist/parser/har-filter.js +0 -71
- package/dist/parser/har-loader.d.ts +0 -2
- package/dist/parser/har-loader.js +0 -14
- package/dist/parser/har-normalizer.d.ts +0 -20
- package/dist/parser/har-normalizer.js +0 -78
- package/dist/parser/index.d.ts +0 -10
- package/dist/parser/index.js +0 -6
- package/dist/parser/openapi-loader.d.ts +0 -6
- package/dist/parser/openapi-loader.js +0 -308
- package/dist/parser/operation-extractor.d.ts +0 -13
- package/dist/parser/operation-extractor.js +0 -155
- package/dist/parser/overlay-loader.d.ts +0 -10
- package/dist/parser/overlay-loader.js +0 -184
- package/dist/parser/postman-loader.d.ts +0 -9
- package/dist/parser/postman-loader.js +0 -106
- package/dist/parser/schema-converter.d.ts +0 -12
- package/dist/parser/schema-converter.js +0 -117
- package/dist/plugins/adapter.d.ts +0 -40
- package/dist/plugins/adapter.js +0 -15
- package/dist/plugins/loader.d.ts +0 -25
- package/dist/plugins/loader.js +0 -58
- package/dist/pricing.d.ts +0 -55
- package/dist/pricing.js +0 -133
- package/dist/providers/index.d.ts +0 -15
- package/dist/providers/index.js +0 -56
- package/dist/recorder/browser-recorder.d.ts +0 -22
- package/dist/recorder/browser-recorder.js +0 -205
- package/dist/rescan/diff-engine.d.ts +0 -5
- package/dist/rescan/diff-engine.js +0 -312
- package/dist/rescan/index.d.ts +0 -3
- package/dist/rescan/index.js +0 -2
- package/dist/rescan/rescan-runner.d.ts +0 -42
- package/dist/rescan/rescan-runner.js +0 -69
- package/dist/rescan/rescan-scheduler.d.ts +0 -41
- package/dist/rescan/rescan-scheduler.js +0 -179
- package/dist/site-transformer/browser-tools.d.ts +0 -10
- package/dist/site-transformer/browser-tools.js +0 -59
- package/dist/site-transformer/index.d.ts +0 -2
- package/dist/site-transformer/index.js +0 -2
- package/dist/site-transformer/selector-healer.d.ts +0 -8
- package/dist/site-transformer/selector-healer.js +0 -106
- package/dist/site-transformer/tool-generator.d.ts +0 -13
- package/dist/site-transformer/tool-generator.js +0 -245
- package/dist/transformer/auth-detector.d.ts +0 -13
- package/dist/transformer/auth-detector.js +0 -90
- package/dist/transformer/catalog-builder.d.ts +0 -18
- package/dist/transformer/catalog-builder.js +0 -56
- package/dist/transformer/client-compat.d.ts +0 -6
- package/dist/transformer/client-compat.js +0 -44
- package/dist/transformer/har-clusterer.d.ts +0 -9
- package/dist/transformer/har-clusterer.js +0 -27
- package/dist/transformer/har-dedup.d.ts +0 -10
- package/dist/transformer/har-dedup.js +0 -81
- package/dist/transformer/har-schema-inferrer.d.ts +0 -15
- package/dist/transformer/har-schema-inferrer.js +0 -90
- package/dist/transformer/har-to-operations.d.ts +0 -13
- package/dist/transformer/har-to-operations.js +0 -192
- package/dist/transformer/index.d.ts +0 -8
- package/dist/transformer/index.js +0 -6
- package/dist/transformer/llm-namer.d.ts +0 -6
- package/dist/transformer/llm-namer.js +0 -59
- package/dist/transformer/naming.d.ts +0 -4
- package/dist/transformer/naming.js +0 -30
- package/dist/transformer/operation-filter.d.ts +0 -13
- package/dist/transformer/operation-filter.js +0 -52
- package/dist/transformer/resource-builder.d.ts +0 -12
- package/dist/transformer/resource-builder.js +0 -80
- package/dist/transformer/schema-merger.d.ts +0 -14
- package/dist/transformer/schema-merger.js +0 -65
- package/dist/transformer/tool-builder.d.ts +0 -3
- package/dist/transformer/tool-builder.js +0 -114
- package/dist/types/index.d.ts +0 -131
- package/dist/types/index.js +0 -1
- package/dist/types/site.d.ts +0 -284
- package/dist/types/site.js +0 -8
- package/dist/utils/fail.d.ts +0 -48
- package/dist/utils/fail.js +0 -204
- package/dist/utils/fs.d.ts +0 -5
- package/dist/utils/fs.js +0 -28
- package/dist/utils/interactive.d.ts +0 -6
- package/dist/utils/interactive.js +0 -30
- package/dist/utils/logger.d.ts +0 -1
- package/dist/utils/logger.js +0 -2
- package/dist/utils/sanitize.d.ts +0 -28
- package/dist/utils/sanitize.js +0 -44
- package/dist/utils/watcher.d.ts +0 -11
- package/dist/utils/watcher.js +0 -36
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Spec -> Generated project pipeline.
|
|
3
|
-
*
|
|
4
|
-
* Takes an uploaded spec file (OpenAPI or HAR), runs it through the existing
|
|
5
|
-
* parser/transformer/emitter pipeline, audits the output, and returns a
|
|
6
|
-
* BuildResult with the slug and image metadata.
|
|
7
|
-
*/
|
|
8
|
-
import { randomBytes } from 'node:crypto';
|
|
9
|
-
import { mkdir, readFile, rm, access } from 'node:fs/promises';
|
|
10
|
-
import { join, extname, resolve } from 'node:path';
|
|
11
|
-
import { logger } from '../utils/logger.js';
|
|
12
|
-
import { auditGeneratedCode } from './security.js';
|
|
13
|
-
// OpenAPI pipeline imports
|
|
14
|
-
import { loadOpenApiSpec } from '../parser/openapi-loader.js';
|
|
15
|
-
import { extractOperations } from '../parser/operation-extractor.js';
|
|
16
|
-
import { detectAuthSchemes } from '../transformer/auth-detector.js';
|
|
17
|
-
import { buildAllTools } from '../transformer/tool-builder.js';
|
|
18
|
-
import { buildResources, buildPrompts } from '../transformer/resource-builder.js';
|
|
19
|
-
import { emitProject } from '../emitter/index.js';
|
|
20
|
-
// HAR pipeline imports
|
|
21
|
-
import { loadHarFile } from '../parser/har-loader.js';
|
|
22
|
-
import { filterHarEntries } from '../parser/har-filter.js';
|
|
23
|
-
import { normalizeEntry } from '../parser/har-normalizer.js';
|
|
24
|
-
import { clusterEntries } from '../transformer/har-clusterer.js';
|
|
25
|
-
import { clustersToOperations } from '../transformer/har-to-operations.js';
|
|
26
|
-
const BUILD_BASE_DIR = '/tmp/mcpmake-build';
|
|
27
|
-
/**
|
|
28
|
-
* Generate a slug from a name (or random if not provided).
|
|
29
|
-
* Format: kebab-case-name-xxxx where xxxx is 4 random hex chars.
|
|
30
|
-
*/
|
|
31
|
-
function generateSlug(name) {
|
|
32
|
-
const suffix = randomBytes(2).toString('hex');
|
|
33
|
-
if (!name) {
|
|
34
|
-
return `mcp-server-${suffix}`;
|
|
35
|
-
}
|
|
36
|
-
const base = name
|
|
37
|
-
.toLowerCase()
|
|
38
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
39
|
-
.replace(/^-|-$/g, '')
|
|
40
|
-
.slice(0, 40);
|
|
41
|
-
return base ? `${base}-${suffix}` : `mcp-server-${suffix}`;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Convert a title to a valid package name.
|
|
45
|
-
*/
|
|
46
|
-
function toPackageName(title) {
|
|
47
|
-
return title
|
|
48
|
-
.toLowerCase()
|
|
49
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
50
|
-
.replace(/^-|-$/g, '');
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Build a project from an uploaded spec file.
|
|
54
|
-
*
|
|
55
|
-
* Steps:
|
|
56
|
-
* 1. Generate slug and create temp build dir
|
|
57
|
-
* 2. Run the appropriate pipeline (OpenAPI or HAR) to generate the project
|
|
58
|
-
* 3. Audit the generated code for dangerous patterns
|
|
59
|
-
* 4. Return build result
|
|
60
|
-
*/
|
|
61
|
-
export async function buildFromSpec(specPath, opts) {
|
|
62
|
-
const slug = generateSlug(opts.name);
|
|
63
|
-
const buildDir = join(BUILD_BASE_DIR, slug);
|
|
64
|
-
// Path traversal guard: ensure buildDir stays within BUILD_BASE_DIR
|
|
65
|
-
const resolvedBuildDir = resolve(buildDir);
|
|
66
|
-
const resolvedBase = resolve(BUILD_BASE_DIR);
|
|
67
|
-
if (!resolvedBuildDir.startsWith(resolvedBase + '/')) {
|
|
68
|
-
throw new Error('Invalid build directory path');
|
|
69
|
-
}
|
|
70
|
-
await mkdir(buildDir, { recursive: true });
|
|
71
|
-
logger.info(`Build directory: ${buildDir}`);
|
|
72
|
-
let toolCount;
|
|
73
|
-
let buildSuccess = false;
|
|
74
|
-
try {
|
|
75
|
-
if (opts.format === 'openapi') {
|
|
76
|
-
toolCount = await runOpenApiPipeline(specPath, buildDir, opts.name);
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
toolCount = await runHarPipeline(specPath, buildDir, opts.name);
|
|
80
|
-
}
|
|
81
|
-
// Audit the entire generated project (not just src/)
|
|
82
|
-
const audit = await auditGeneratedCode(buildDir);
|
|
83
|
-
if (!audit.safe) {
|
|
84
|
-
const findingsList = audit.findings.join('\n - ');
|
|
85
|
-
throw new Error(`Code audit failed. Dangerous patterns found in generated code:\n - ${findingsList}`);
|
|
86
|
-
}
|
|
87
|
-
logger.info('Code audit passed');
|
|
88
|
-
buildSuccess = true;
|
|
89
|
-
}
|
|
90
|
-
finally {
|
|
91
|
-
// Clean up build directory on failure
|
|
92
|
-
if (!buildSuccess) {
|
|
93
|
-
try {
|
|
94
|
-
await rm(buildDir, { recursive: true, force: true });
|
|
95
|
-
}
|
|
96
|
-
catch {
|
|
97
|
-
// Ignore cleanup errors
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
// Detect server type from generated project dependencies
|
|
102
|
-
const serverType = await detectServerType(buildDir);
|
|
103
|
-
return {
|
|
104
|
-
slug,
|
|
105
|
-
imageName: `mcpmake/${slug}`,
|
|
106
|
-
imageTag: 'latest',
|
|
107
|
-
buildDir,
|
|
108
|
-
toolCount,
|
|
109
|
-
serverType,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Run the OpenAPI pipeline: parse spec -> extract operations -> build tools -> emit project.
|
|
114
|
-
* Returns the number of tools generated.
|
|
115
|
-
*/
|
|
116
|
-
async function runOpenApiPipeline(specPath, outputDir, name) {
|
|
117
|
-
logger.info(`Running OpenAPI pipeline for: ${specPath}`);
|
|
118
|
-
const { api } = await loadOpenApiSpec(specPath);
|
|
119
|
-
const { operations, baseUrl, securitySchemes, info } = extractOperations(api);
|
|
120
|
-
if (operations.length === 0) {
|
|
121
|
-
throw new Error('No operations found in the OpenAPI spec');
|
|
122
|
-
}
|
|
123
|
-
logger.info(`Found ${operations.length} operations`);
|
|
124
|
-
const tools = buildAllTools(operations);
|
|
125
|
-
const { authSchemes, envVars } = detectAuthSchemes(securitySchemes);
|
|
126
|
-
const serverName = name ? toPackageName(name) : toPackageName(info.title);
|
|
127
|
-
const resolvedBaseUrl = baseUrl;
|
|
128
|
-
if (!resolvedBaseUrl) {
|
|
129
|
-
throw new Error('No base URL found in spec');
|
|
130
|
-
}
|
|
131
|
-
const resources = buildResources(operations);
|
|
132
|
-
const prompts = buildPrompts(operations);
|
|
133
|
-
const manifest = {
|
|
134
|
-
serverName,
|
|
135
|
-
serverVersion: info.version ?? '1.0.0',
|
|
136
|
-
baseUrl: resolvedBaseUrl,
|
|
137
|
-
transport: 'http', // Always HTTP for hosted servers
|
|
138
|
-
tools,
|
|
139
|
-
resources,
|
|
140
|
-
prompts,
|
|
141
|
-
authSchemes,
|
|
142
|
-
envVars: [
|
|
143
|
-
{
|
|
144
|
-
name: 'BASE_URL',
|
|
145
|
-
description: 'API base URL',
|
|
146
|
-
required: true,
|
|
147
|
-
example: resolvedBaseUrl,
|
|
148
|
-
},
|
|
149
|
-
...envVars,
|
|
150
|
-
],
|
|
151
|
-
};
|
|
152
|
-
await emitProject(manifest, {
|
|
153
|
-
outputDir,
|
|
154
|
-
force: true,
|
|
155
|
-
dryRun: false,
|
|
156
|
-
});
|
|
157
|
-
return tools.length;
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Run the HAR pipeline: load HAR -> filter -> normalize -> cluster -> emit project.
|
|
161
|
-
* Returns the number of tools generated.
|
|
162
|
-
*/
|
|
163
|
-
async function runHarPipeline(specPath, outputDir, name) {
|
|
164
|
-
logger.info(`Running HAR pipeline for: ${specPath}`);
|
|
165
|
-
const har = await loadHarFile(specPath);
|
|
166
|
-
logger.info(`Found ${har.log.entries.length} total entries`);
|
|
167
|
-
// Filter noise (no domain restriction for hosted builds)
|
|
168
|
-
const filtered = filterHarEntries(har.log.entries, {
|
|
169
|
-
includeErrors: false,
|
|
170
|
-
});
|
|
171
|
-
if (filtered.length === 0) {
|
|
172
|
-
throw new Error('No API requests found in HAR file after filtering');
|
|
173
|
-
}
|
|
174
|
-
logger.info(`${filtered.length} API entries after filtering`);
|
|
175
|
-
// Normalize paths
|
|
176
|
-
const normalized = filtered.map(normalizeEntry);
|
|
177
|
-
// Cluster into operations
|
|
178
|
-
const clusters = clusterEntries(normalized);
|
|
179
|
-
logger.info(`Clustered into ${clusters.length} operations`);
|
|
180
|
-
// Convert to OperationDescriptors
|
|
181
|
-
const { operations, baseUrl, detectedAuth } = clustersToOperations(clusters);
|
|
182
|
-
if (operations.length === 0) {
|
|
183
|
-
throw new Error('No operations could be derived from HAR file');
|
|
184
|
-
}
|
|
185
|
-
// Build auth schemes and env vars
|
|
186
|
-
const authSchemes = [];
|
|
187
|
-
const envVars = [];
|
|
188
|
-
for (const auth of detectedAuth) {
|
|
189
|
-
if (auth.type === 'bearer') {
|
|
190
|
-
authSchemes.push({
|
|
191
|
-
type: 'http-bearer',
|
|
192
|
-
envVarName: 'BEARER_TOKEN',
|
|
193
|
-
description: 'Bearer token detected in HAR',
|
|
194
|
-
});
|
|
195
|
-
envVars.push({
|
|
196
|
-
name: 'BEARER_TOKEN',
|
|
197
|
-
description: 'Bearer authentication token',
|
|
198
|
-
required: true,
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
else if (auth.type === 'basic') {
|
|
202
|
-
authSchemes.push({
|
|
203
|
-
type: 'http-basic',
|
|
204
|
-
envVarName: 'BASIC_USERNAME',
|
|
205
|
-
description: 'Basic auth detected in HAR',
|
|
206
|
-
});
|
|
207
|
-
envVars.push({ name: 'BASIC_USERNAME', description: 'Basic auth username', required: true }, { name: 'BASIC_PASSWORD', description: 'Basic auth password', required: true });
|
|
208
|
-
}
|
|
209
|
-
else if (auth.type === 'apiKey') {
|
|
210
|
-
authSchemes.push({
|
|
211
|
-
type: 'apiKey',
|
|
212
|
-
envVarName: 'API_KEY',
|
|
213
|
-
headerName: auth.headerName,
|
|
214
|
-
in: 'header',
|
|
215
|
-
description: `API key header: ${auth.headerName}`,
|
|
216
|
-
});
|
|
217
|
-
envVars.push({
|
|
218
|
-
name: 'API_KEY',
|
|
219
|
-
description: `API key (sent as header "${auth.headerName}")`,
|
|
220
|
-
required: true,
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
// Dedupe env vars
|
|
225
|
-
const seen = new Set();
|
|
226
|
-
const uniqueEnvVars = envVars.filter((v) => {
|
|
227
|
-
if (seen.has(v.name))
|
|
228
|
-
return false;
|
|
229
|
-
seen.add(v.name);
|
|
230
|
-
return true;
|
|
231
|
-
});
|
|
232
|
-
const tools = buildAllTools(operations);
|
|
233
|
-
const serverName = name ? toPackageName(name) : toPackageName(new URL(baseUrl).hostname);
|
|
234
|
-
const manifest = {
|
|
235
|
-
serverName,
|
|
236
|
-
serverVersion: '1.0.0',
|
|
237
|
-
baseUrl,
|
|
238
|
-
transport: 'http', // Always HTTP for hosted servers
|
|
239
|
-
tools,
|
|
240
|
-
authSchemes,
|
|
241
|
-
envVars: [
|
|
242
|
-
{ name: 'BASE_URL', description: 'API base URL', required: true, example: baseUrl },
|
|
243
|
-
...uniqueEnvVars,
|
|
244
|
-
],
|
|
245
|
-
};
|
|
246
|
-
await emitProject(manifest, {
|
|
247
|
-
outputDir,
|
|
248
|
-
force: true,
|
|
249
|
-
dryRun: false,
|
|
250
|
-
});
|
|
251
|
-
return tools.length;
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Detect whether a generated project is a Playwright-based server
|
|
255
|
-
* by checking for a "playwright" dependency in its package.json.
|
|
256
|
-
*/
|
|
257
|
-
async function detectServerType(buildDir) {
|
|
258
|
-
const pkgPath = join(buildDir, 'package.json');
|
|
259
|
-
try {
|
|
260
|
-
await access(pkgPath);
|
|
261
|
-
const raw = await readFile(pkgPath, 'utf-8');
|
|
262
|
-
const pkg = JSON.parse(raw);
|
|
263
|
-
const allDeps = {
|
|
264
|
-
...pkg.dependencies,
|
|
265
|
-
...pkg.devDependencies,
|
|
266
|
-
};
|
|
267
|
-
if ('playwright' in allDeps || 'playwright-core' in allDeps) {
|
|
268
|
-
logger.info('Detected Playwright server from package.json dependencies');
|
|
269
|
-
return 'playwright';
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
catch {
|
|
273
|
-
// No package.json or unreadable — default to http
|
|
274
|
-
}
|
|
275
|
-
return 'http';
|
|
276
|
-
}
|
|
277
|
-
/**
|
|
278
|
-
* Detect the spec format from a file path.
|
|
279
|
-
*/
|
|
280
|
-
export function detectFormat(filePath, contentType) {
|
|
281
|
-
const ext = extname(filePath).toLowerCase();
|
|
282
|
-
if (ext === '.har')
|
|
283
|
-
return 'har';
|
|
284
|
-
if (ext === '.yaml' || ext === '.yml' || ext === '.json') {
|
|
285
|
-
// Could be either OpenAPI JSON or HAR JSON; check content type hint
|
|
286
|
-
if (contentType?.includes('har'))
|
|
287
|
-
return 'har';
|
|
288
|
-
return 'openapi';
|
|
289
|
-
}
|
|
290
|
-
// Default to OpenAPI
|
|
291
|
-
return 'openapi';
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* Detect format by inspecting file content.
|
|
295
|
-
* Useful when the file extension is ambiguous (e.g., .json).
|
|
296
|
-
*/
|
|
297
|
-
export async function detectFormatFromContent(filePath) {
|
|
298
|
-
const raw = await readFile(filePath, 'utf-8');
|
|
299
|
-
try {
|
|
300
|
-
const parsed = JSON.parse(raw);
|
|
301
|
-
// HAR files have a top-level "log" object with "entries"
|
|
302
|
-
if (parsed.log && Array.isArray(parsed.log.entries)) {
|
|
303
|
-
return 'har';
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
catch {
|
|
307
|
-
// Not valid JSON — probably YAML, assume OpenAPI
|
|
308
|
-
}
|
|
309
|
-
return 'openapi';
|
|
310
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bounded-concurrency queue for expensive build work.
|
|
3
|
-
*
|
|
4
|
-
* Each hosted-server build runs `npm install` + `docker build`, which are
|
|
5
|
-
* CPU/IO heavy. Without a limit, a burst of create requests can exhaust the
|
|
6
|
-
* host (a DoS / cryptomining vector). This serializes the heavy steps to a
|
|
7
|
-
* small number of concurrent slots; excess work waits in a FIFO queue rather
|
|
8
|
-
* than running all at once.
|
|
9
|
-
*
|
|
10
|
-
* Concurrency is `BUILD_CONCURRENCY` (default 2).
|
|
11
|
-
*/
|
|
12
|
-
export declare class BuildQueue {
|
|
13
|
-
private readonly concurrency;
|
|
14
|
-
private active;
|
|
15
|
-
private readonly waiters;
|
|
16
|
-
constructor(concurrency: number);
|
|
17
|
-
/** Number of tasks currently running. */
|
|
18
|
-
get activeCount(): number;
|
|
19
|
-
/** Number of tasks waiting for a free slot. */
|
|
20
|
-
get queuedCount(): number;
|
|
21
|
-
private acquire;
|
|
22
|
-
private release;
|
|
23
|
-
/**
|
|
24
|
-
* Run `fn` once a build slot is available, releasing the slot afterwards
|
|
25
|
-
* (even if `fn` throws).
|
|
26
|
-
*/
|
|
27
|
-
run<T>(fn: () => Promise<T>): Promise<T>;
|
|
28
|
-
}
|
|
29
|
-
/** Shared build queue used by all create / re-deploy paths. */
|
|
30
|
-
export declare const buildQueue: BuildQueue;
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bounded-concurrency queue for expensive build work.
|
|
3
|
-
*
|
|
4
|
-
* Each hosted-server build runs `npm install` + `docker build`, which are
|
|
5
|
-
* CPU/IO heavy. Without a limit, a burst of create requests can exhaust the
|
|
6
|
-
* host (a DoS / cryptomining vector). This serializes the heavy steps to a
|
|
7
|
-
* small number of concurrent slots; excess work waits in a FIFO queue rather
|
|
8
|
-
* than running all at once.
|
|
9
|
-
*
|
|
10
|
-
* Concurrency is `BUILD_CONCURRENCY` (default 2).
|
|
11
|
-
*/
|
|
12
|
-
import { logger } from '../utils/logger.js';
|
|
13
|
-
export class BuildQueue {
|
|
14
|
-
concurrency;
|
|
15
|
-
active = 0;
|
|
16
|
-
waiters = [];
|
|
17
|
-
constructor(concurrency) {
|
|
18
|
-
this.concurrency = concurrency;
|
|
19
|
-
}
|
|
20
|
-
/** Number of tasks currently running. */
|
|
21
|
-
get activeCount() {
|
|
22
|
-
return this.active;
|
|
23
|
-
}
|
|
24
|
-
/** Number of tasks waiting for a free slot. */
|
|
25
|
-
get queuedCount() {
|
|
26
|
-
return this.waiters.length;
|
|
27
|
-
}
|
|
28
|
-
acquire() {
|
|
29
|
-
if (this.active < this.concurrency) {
|
|
30
|
-
this.active++;
|
|
31
|
-
return Promise.resolve();
|
|
32
|
-
}
|
|
33
|
-
return new Promise((resolve) => this.waiters.push(resolve));
|
|
34
|
-
}
|
|
35
|
-
release() {
|
|
36
|
-
const next = this.waiters.shift();
|
|
37
|
-
if (next) {
|
|
38
|
-
// Transfer the slot directly to the next waiter (active stays counted).
|
|
39
|
-
next();
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
this.active--;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Run `fn` once a build slot is available, releasing the slot afterwards
|
|
47
|
-
* (even if `fn` throws).
|
|
48
|
-
*/
|
|
49
|
-
async run(fn) {
|
|
50
|
-
const waitingBefore = this.queuedCount;
|
|
51
|
-
if (this.active >= this.concurrency) {
|
|
52
|
-
logger.info(`[build-queue] at capacity (${this.activeCount} active); queueing build (${waitingBefore + 1} waiting)`);
|
|
53
|
-
}
|
|
54
|
-
await this.acquire();
|
|
55
|
-
try {
|
|
56
|
-
return await fn();
|
|
57
|
-
}
|
|
58
|
-
finally {
|
|
59
|
-
this.release();
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
function parseConcurrency() {
|
|
64
|
-
const raw = parseInt(process.env.BUILD_CONCURRENCY ?? '2', 10);
|
|
65
|
-
if (!Number.isFinite(raw) || raw < 1)
|
|
66
|
-
return 2;
|
|
67
|
-
return Math.min(raw, 16);
|
|
68
|
-
}
|
|
69
|
-
/** Shared build queue used by all create / re-deploy paths. */
|
|
70
|
-
export const buildQueue = new BuildQueue(parseConcurrency());
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dynamic reverse proxy routing via Caddy Admin API.
|
|
3
|
-
*
|
|
4
|
-
* Manages routes that map {slug}.{domain} -> localhost:{port}.
|
|
5
|
-
* Caddy Admin API is assumed to run at http://localhost:2019.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Add a route: {slug}.{domain} -> localhost:{port}
|
|
9
|
-
*/
|
|
10
|
-
export declare function addRoute(slug: string, port: number, domain: string): Promise<void>;
|
|
11
|
-
/**
|
|
12
|
-
* Remove a route by slug.
|
|
13
|
-
*/
|
|
14
|
-
export declare function removeRoute(slug: string, _domain: string): Promise<void>;
|
|
15
|
-
/**
|
|
16
|
-
* Check if a route exists for a given slug.
|
|
17
|
-
*/
|
|
18
|
-
export declare function routeExists(slug: string, _domain: string): Promise<boolean>;
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dynamic reverse proxy routing via Caddy Admin API.
|
|
3
|
-
*
|
|
4
|
-
* Manages routes that map {slug}.{domain} -> localhost:{port}.
|
|
5
|
-
* Caddy Admin API is assumed to run at http://localhost:2019.
|
|
6
|
-
*/
|
|
7
|
-
import http from 'node:http';
|
|
8
|
-
import { logger } from '../utils/logger.js';
|
|
9
|
-
const CADDY_ADMIN = 'http://localhost:2019';
|
|
10
|
-
/**
|
|
11
|
-
* Add a route: {slug}.{domain} -> localhost:{port}
|
|
12
|
-
*/
|
|
13
|
-
export async function addRoute(slug, port, domain) {
|
|
14
|
-
const hostname = `${slug}.${domain}`;
|
|
15
|
-
const route = {
|
|
16
|
-
'@id': `mcpmake-${slug}`,
|
|
17
|
-
match: [
|
|
18
|
-
{
|
|
19
|
-
host: [hostname],
|
|
20
|
-
},
|
|
21
|
-
],
|
|
22
|
-
handle: [
|
|
23
|
-
{
|
|
24
|
-
handler: 'reverse_proxy',
|
|
25
|
-
upstreams: [
|
|
26
|
-
{
|
|
27
|
-
dial: `localhost:${port}`,
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
},
|
|
31
|
-
],
|
|
32
|
-
};
|
|
33
|
-
await caddyRequest('POST', '/config/apps/http/servers/srv0/routes', route);
|
|
34
|
-
logger.info(`Caddy route added: ${hostname} -> localhost:${port}`);
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Remove a route by slug.
|
|
38
|
-
*/
|
|
39
|
-
export async function removeRoute(slug, _domain) {
|
|
40
|
-
await caddyRequest('DELETE', `/id/mcpmake-${slug}`, undefined);
|
|
41
|
-
logger.info(`Caddy route removed: ${slug}`);
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Check if a route exists for a given slug.
|
|
45
|
-
*/
|
|
46
|
-
export async function routeExists(slug, _domain) {
|
|
47
|
-
try {
|
|
48
|
-
const body = await caddyRequest('GET', `/id/mcpmake-${slug}`, undefined);
|
|
49
|
-
return body !== null;
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Low-level helper to call the Caddy Admin API.
|
|
57
|
-
*/
|
|
58
|
-
function caddyRequest(method, path, body) {
|
|
59
|
-
return new Promise((resolve, reject) => {
|
|
60
|
-
const url = new URL(path, CADDY_ADMIN);
|
|
61
|
-
const payload = body !== undefined ? JSON.stringify(body) : undefined;
|
|
62
|
-
const req = http.request({
|
|
63
|
-
hostname: url.hostname,
|
|
64
|
-
port: Number(url.port),
|
|
65
|
-
path: url.pathname,
|
|
66
|
-
method,
|
|
67
|
-
headers: {
|
|
68
|
-
...(payload
|
|
69
|
-
? { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) }
|
|
70
|
-
: {}),
|
|
71
|
-
},
|
|
72
|
-
}, (res) => {
|
|
73
|
-
const chunks = [];
|
|
74
|
-
res.on('data', (chunk) => chunks.push(chunk));
|
|
75
|
-
res.on('end', () => {
|
|
76
|
-
const responseBody = Buffer.concat(chunks).toString('utf-8');
|
|
77
|
-
if (res.statusCode && res.statusCode >= 400) {
|
|
78
|
-
reject(new Error(`Caddy API ${method} ${path} returned ${res.statusCode}: ${responseBody}`));
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
try {
|
|
82
|
-
resolve(responseBody ? JSON.parse(responseBody) : null);
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
resolve(responseBody || null);
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
req.on('error', (err) => {
|
|
90
|
-
reject(new Error(`Caddy API request failed: ${err.message}`));
|
|
91
|
-
});
|
|
92
|
-
if (payload) {
|
|
93
|
-
req.write(payload);
|
|
94
|
-
}
|
|
95
|
-
req.end();
|
|
96
|
-
});
|
|
97
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Container backend driver abstraction.
|
|
3
|
-
*
|
|
4
|
-
* All container lifecycle operations go through a `ContainerBackend` rather than
|
|
5
|
-
* calling the Docker socket helpers directly. Today the only implementation is
|
|
6
|
-
* `LocalDockerDriver` (the local `/var/run/docker.sock`, no behavior change).
|
|
7
|
-
*
|
|
8
|
-
* The seam exists so a future cloud / multi-node move is a driver swap, not a
|
|
9
|
-
* rewrite: a `RemoteDockerDriver` (TCP + mTLS) or a managed-cloud driver
|
|
10
|
-
* (Fly Machines / Cloud Run) implements the same interface, and a placement
|
|
11
|
-
* layer picks which driver to use per server. See TODO.md Sprint 8 — "Prep
|
|
12
|
-
* seams" and "Tiered placement".
|
|
13
|
-
*/
|
|
14
|
-
import type { StartContainerOpts, ContainerStatus } from './container-manager.js';
|
|
15
|
-
export type { StartContainerOpts, ContainerStatus };
|
|
16
|
-
/**
|
|
17
|
-
* A backend capable of building images and running tenant containers.
|
|
18
|
-
*
|
|
19
|
-
* Method contracts mirror the existing `container-manager` functions exactly,
|
|
20
|
-
* so swapping the default driver is invisible to callers.
|
|
21
|
-
*/
|
|
22
|
-
export interface ContainerBackend {
|
|
23
|
-
/** Stable identifier for logs / the server record (which backend ran a container). */
|
|
24
|
-
readonly name: string;
|
|
25
|
-
/** Build an image from a generated project directory containing a Dockerfile. */
|
|
26
|
-
buildImage(buildDir: string, imageName: string, imageTag: string): Promise<void>;
|
|
27
|
-
/** Create + start a container; resolves to the container ID. */
|
|
28
|
-
startContainer(opts: StartContainerOpts): Promise<string>;
|
|
29
|
-
/** Stop and remove a container (best-effort; never throws on already-stopped). */
|
|
30
|
-
stopContainer(containerId: string): Promise<void>;
|
|
31
|
-
/** Stream container logs (multiplexed Docker frames decoded to text lines). */
|
|
32
|
-
getContainerLogs(containerId: string): AsyncIterable<string>;
|
|
33
|
-
/** Current runtime status; resolves to 'error' if the backend is unreachable. */
|
|
34
|
-
getContainerStatus(containerId: string): Promise<ContainerStatus>;
|
|
35
|
-
/** Reclaim disk by removing dangling images (best-effort). */
|
|
36
|
-
pruneDanglingImages(): Promise<void>;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Default driver: the local Docker daemon over its Unix socket.
|
|
40
|
-
*
|
|
41
|
-
* Delegates to the `container-manager` helpers at call time (not construction)
|
|
42
|
-
* so the well-tested socket code stays the single implementation and module
|
|
43
|
-
* mocks still intercept.
|
|
44
|
-
*/
|
|
45
|
-
export declare class LocalDockerDriver implements ContainerBackend {
|
|
46
|
-
readonly name = "local-docker";
|
|
47
|
-
buildImage(buildDir: string, imageName: string, imageTag: string): Promise<void>;
|
|
48
|
-
startContainer(opts: StartContainerOpts): Promise<string>;
|
|
49
|
-
stopContainer(containerId: string): Promise<void>;
|
|
50
|
-
getContainerLogs(containerId: string): AsyncIterable<string>;
|
|
51
|
-
getContainerStatus(containerId: string): Promise<ContainerStatus>;
|
|
52
|
-
pruneDanglingImages(): Promise<void>;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Resolve the container backend.
|
|
56
|
-
*
|
|
57
|
-
* Single local driver for now; the future placement layer will pass the target
|
|
58
|
-
* server/plan here to pick a driver per tenant.
|
|
59
|
-
*/
|
|
60
|
-
export declare function getContainerBackend(): ContainerBackend;
|
|
61
|
-
/** Override the backend (tests / future placement wiring). Pass null to reset. */
|
|
62
|
-
export declare function setContainerBackend(backend: ContainerBackend | null): void;
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Container backend driver abstraction.
|
|
3
|
-
*
|
|
4
|
-
* All container lifecycle operations go through a `ContainerBackend` rather than
|
|
5
|
-
* calling the Docker socket helpers directly. Today the only implementation is
|
|
6
|
-
* `LocalDockerDriver` (the local `/var/run/docker.sock`, no behavior change).
|
|
7
|
-
*
|
|
8
|
-
* The seam exists so a future cloud / multi-node move is a driver swap, not a
|
|
9
|
-
* rewrite: a `RemoteDockerDriver` (TCP + mTLS) or a managed-cloud driver
|
|
10
|
-
* (Fly Machines / Cloud Run) implements the same interface, and a placement
|
|
11
|
-
* layer picks which driver to use per server. See TODO.md Sprint 8 — "Prep
|
|
12
|
-
* seams" and "Tiered placement".
|
|
13
|
-
*/
|
|
14
|
-
import * as docker from './container-manager.js';
|
|
15
|
-
/**
|
|
16
|
-
* Default driver: the local Docker daemon over its Unix socket.
|
|
17
|
-
*
|
|
18
|
-
* Delegates to the `container-manager` helpers at call time (not construction)
|
|
19
|
-
* so the well-tested socket code stays the single implementation and module
|
|
20
|
-
* mocks still intercept.
|
|
21
|
-
*/
|
|
22
|
-
export class LocalDockerDriver {
|
|
23
|
-
name = 'local-docker';
|
|
24
|
-
buildImage(buildDir, imageName, imageTag) {
|
|
25
|
-
return docker.buildImage(buildDir, imageName, imageTag);
|
|
26
|
-
}
|
|
27
|
-
startContainer(opts) {
|
|
28
|
-
return docker.startContainer(opts);
|
|
29
|
-
}
|
|
30
|
-
stopContainer(containerId) {
|
|
31
|
-
return docker.stopContainer(containerId);
|
|
32
|
-
}
|
|
33
|
-
getContainerLogs(containerId) {
|
|
34
|
-
return docker.getContainerLogs(containerId);
|
|
35
|
-
}
|
|
36
|
-
getContainerStatus(containerId) {
|
|
37
|
-
return docker.getContainerStatus(containerId);
|
|
38
|
-
}
|
|
39
|
-
pruneDanglingImages() {
|
|
40
|
-
return docker.pruneDanglingImages();
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
let cached = null;
|
|
44
|
-
/**
|
|
45
|
-
* Resolve the container backend.
|
|
46
|
-
*
|
|
47
|
-
* Single local driver for now; the future placement layer will pass the target
|
|
48
|
-
* server/plan here to pick a driver per tenant.
|
|
49
|
-
*/
|
|
50
|
-
export function getContainerBackend() {
|
|
51
|
-
if (!cached) {
|
|
52
|
-
cached = new LocalDockerDriver();
|
|
53
|
-
}
|
|
54
|
-
return cached;
|
|
55
|
-
}
|
|
56
|
-
/** Override the backend (tests / future placement wiring). Pass null to reset. */
|
|
57
|
-
export function setContainerBackend(backend) {
|
|
58
|
-
cached = backend;
|
|
59
|
-
}
|