mcpmake 0.1.0
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 +691 -0
- package/bin/mcpmake.mjs +2 -0
- package/dist/analyzer/auth-detector.d.ts +12 -0
- package/dist/analyzer/auth-detector.js +142 -0
- package/dist/analyzer/dom-parser.d.ts +10 -0
- package/dist/analyzer/dom-parser.js +259 -0
- package/dist/analyzer/goal-crawler.d.ts +25 -0
- package/dist/analyzer/goal-crawler.js +177 -0
- package/dist/analyzer/hybrid-detector.d.ts +28 -0
- package/dist/analyzer/hybrid-detector.js +96 -0
- package/dist/analyzer/index.d.ts +12 -0
- package/dist/analyzer/index.js +8 -0
- package/dist/analyzer/screenshot-capture.d.ts +29 -0
- package/dist/analyzer/screenshot-capture.js +42 -0
- package/dist/analyzer/selector-builder.d.ts +19 -0
- package/dist/analyzer/selector-builder.js +199 -0
- package/dist/analyzer/semantic-analyzer.d.ts +13 -0
- package/dist/analyzer/semantic-analyzer.js +145 -0
- package/dist/analyzer/site-crawler.d.ts +38 -0
- package/dist/analyzer/site-crawler.js +235 -0
- package/dist/cloud/billing/billing-engine.d.ts +44 -0
- package/dist/cloud/billing/billing-engine.js +81 -0
- package/dist/cloud/billing/credit-store.d.ts +64 -0
- package/dist/cloud/billing/credit-store.js +168 -0
- package/dist/cloud/billing/index.d.ts +4 -0
- package/dist/cloud/billing/index.js +2 -0
- package/dist/cloud/billing/usage-store.d.ts +42 -0
- package/dist/cloud/billing/usage-store.js +85 -0
- package/dist/cloud/billing/usage-tracker.d.ts +38 -0
- package/dist/cloud/billing/usage-tracker.js +95 -0
- package/dist/cloud/build-pipeline.d.ts +39 -0
- package/dist/cloud/build-pipeline.js +310 -0
- package/dist/cloud/build-queue.d.ts +30 -0
- package/dist/cloud/build-queue.js +70 -0
- package/dist/cloud/caddy-manager.d.ts +18 -0
- package/dist/cloud/caddy-manager.js +97 -0
- package/dist/cloud/container-backend.d.ts +62 -0
- package/dist/cloud/container-backend.js +59 -0
- package/dist/cloud/container-manager.d.ts +64 -0
- package/dist/cloud/container-manager.js +301 -0
- package/dist/cloud/crypto.d.ts +27 -0
- package/dist/cloud/crypto.js +63 -0
- package/dist/cloud/db/index.d.ts +27 -0
- package/dist/cloud/db/index.js +53 -0
- package/dist/cloud/db/migrations.d.ts +12 -0
- package/dist/cloud/db/migrations.js +329 -0
- package/dist/cloud/db/pg-store.d.ts +45 -0
- package/dist/cloud/db/pg-store.js +336 -0
- package/dist/cloud/failure-tracker.d.ts +51 -0
- package/dist/cloud/failure-tracker.js +102 -0
- package/dist/cloud/idle-monitor.d.ts +30 -0
- package/dist/cloud/idle-monitor.js +70 -0
- package/dist/cloud/mailer.d.ts +21 -0
- package/dist/cloud/mailer.js +193 -0
- package/dist/cloud/mcp-proxy.d.ts +58 -0
- package/dist/cloud/mcp-proxy.js +203 -0
- package/dist/cloud/metric-samples.d.ts +43 -0
- package/dist/cloud/metric-samples.js +85 -0
- package/dist/cloud/metrics.d.ts +26 -0
- package/dist/cloud/metrics.js +59 -0
- package/dist/cloud/multipart.d.ts +26 -0
- package/dist/cloud/multipart.js +132 -0
- package/dist/cloud/observability.d.ts +27 -0
- package/dist/cloud/observability.js +98 -0
- package/dist/cloud/rate-limiter.d.ts +31 -0
- package/dist/cloud/rate-limiter.js +58 -0
- package/dist/cloud/request-security.d.ts +5 -0
- package/dist/cloud/request-security.js +74 -0
- package/dist/cloud/resource-monitor.d.ts +69 -0
- package/dist/cloud/resource-monitor.js +130 -0
- package/dist/cloud/secret-store.d.ts +38 -0
- package/dist/cloud/secret-store.js +103 -0
- package/dist/cloud/security.d.ts +26 -0
- package/dist/cloud/security.js +142 -0
- package/dist/cloud/server.d.ts +21 -0
- package/dist/cloud/server.js +1079 -0
- package/dist/cloud/shared-state.d.ts +72 -0
- package/dist/cloud/shared-state.js +159 -0
- package/dist/cloud/ssrf.d.ts +43 -0
- package/dist/cloud/ssrf.js +150 -0
- package/dist/cloud/store.d.ts +41 -0
- package/dist/cloud/store.js +75 -0
- package/dist/cloud/stripe.d.ts +78 -0
- package/dist/cloud/stripe.js +317 -0
- package/dist/cloud/telemetry-store.d.ts +53 -0
- package/dist/cloud/telemetry-store.js +108 -0
- package/dist/cloud/web/auth.d.ts +225 -0
- package/dist/cloud/web/auth.js +555 -0
- package/dist/cloud/web/charts.d.ts +70 -0
- package/dist/cloud/web/charts.js +178 -0
- package/dist/cloud/web/csrf.d.ts +14 -0
- package/dist/cloud/web/csrf.js +22 -0
- package/dist/cloud/web/docs.d.ts +40 -0
- package/dist/cloud/web/docs.js +174 -0
- package/dist/cloud/web/router.d.ts +25 -0
- package/dist/cloud/web/router.js +1921 -0
- package/dist/cloud/web/static/alpine.min.js +5 -0
- package/dist/cloud/web/static/favicon.svg +4 -0
- package/dist/cloud/web/static/htmx-sse.js +290 -0
- package/dist/cloud/web/static/htmx.min.js +1 -0
- package/dist/cloud/web/static/style.css +2683 -0
- package/dist/cloud/web/static-server.d.ts +13 -0
- package/dist/cloud/web/static-server.js +73 -0
- package/dist/cloud/web/template-engine.d.ts +27 -0
- package/dist/cloud/web/template-engine.js +146 -0
- package/dist/cloud/web/templates/layouts/admin.hbs +57 -0
- package/dist/cloud/web/templates/layouts/auth.hbs +138 -0
- package/dist/cloud/web/templates/layouts/base.hbs +16 -0
- package/dist/cloud/web/templates/layouts/dashboard.hbs +39 -0
- package/dist/cloud/web/templates/layouts/landing.hbs +82 -0
- package/dist/cloud/web/templates/pages/admin/overview.hbs +123 -0
- package/dist/cloud/web/templates/pages/admin/servers.hbs +129 -0
- package/dist/cloud/web/templates/pages/admin/telemetry.hbs +39 -0
- package/dist/cloud/web/templates/pages/admin/user-edit.hbs +91 -0
- package/dist/cloud/web/templates/pages/admin/users.hbs +179 -0
- package/dist/cloud/web/templates/pages/auth/forgot-password.hbs +25 -0
- package/dist/cloud/web/templates/pages/auth/login.hbs +33 -0
- package/dist/cloud/web/templates/pages/auth/register.hbs +32 -0
- package/dist/cloud/web/templates/pages/auth/reset-password.hbs +34 -0
- package/dist/cloud/web/templates/pages/dashboard/billing.hbs +140 -0
- package/dist/cloud/web/templates/pages/dashboard/create.hbs +173 -0
- package/dist/cloud/web/templates/pages/dashboard/index.hbs +8 -0
- package/dist/cloud/web/templates/pages/dashboard/server-detail.hbs +280 -0
- package/dist/cloud/web/templates/pages/dashboard/server-logs.hbs +35 -0
- package/dist/cloud/web/templates/pages/dashboard/server-metrics.hbs +63 -0
- package/dist/cloud/web/templates/pages/dashboard/servers-partial.hbs +21 -0
- package/dist/cloud/web/templates/pages/dashboard/servers.hbs +44 -0
- package/dist/cloud/web/templates/pages/docs/show.hbs +16 -0
- package/dist/cloud/web/templates/pages/errors/404.hbs +9 -0
- package/dist/cloud/web/templates/pages/errors/500.hbs +8 -0
- package/dist/cloud/web/templates/pages/landing/index.hbs +223 -0
- package/dist/cloud/web/templates/pages/legal/privacy.hbs +71 -0
- package/dist/cloud/web/templates/pages/legal/terms.hbs +73 -0
- package/dist/cloud/web/templates/partials/admin-stats.hbs +52 -0
- package/dist/cloud/web/templates/partials/flash-message.hbs +6 -0
- package/dist/cloud/web/templates/partials/pricing-table.hbs +103 -0
- package/dist/cloud/web/templates/partials/server-card.hbs +19 -0
- package/dist/cloud/web/templates/partials/status-badge.hbs +1 -0
- package/dist/commands/bundle.d.ts +18 -0
- package/dist/commands/bundle.js +82 -0
- package/dist/commands/ci.d.ts +25 -0
- package/dist/commands/ci.js +149 -0
- package/dist/commands/deploy.d.ts +24 -0
- package/dist/commands/deploy.js +145 -0
- package/dist/commands/diff.d.ts +18 -0
- package/dist/commands/diff.js +185 -0
- package/dist/commands/from/describe.d.ts +65 -0
- package/dist/commands/from/describe.js +173 -0
- package/dist/commands/from/har.d.ts +81 -0
- package/dist/commands/from/har.js +255 -0
- package/dist/commands/from/openapi.d.ts +105 -0
- package/dist/commands/from/openapi.js +302 -0
- package/dist/commands/from/postman.d.ts +51 -0
- package/dist/commands/from/postman.js +146 -0
- package/dist/commands/from/target-support.d.ts +11 -0
- package/dist/commands/from/target-support.js +33 -0
- package/dist/commands/from/url.d.ts +75 -0
- package/dist/commands/from/url.js +244 -0
- package/dist/commands/from/website.d.ts +75 -0
- package/dist/commands/from/website.js +284 -0
- package/dist/commands/lint.d.ts +24 -0
- package/dist/commands/lint.js +184 -0
- package/dist/commands/merge.d.ts +18 -0
- package/dist/commands/merge.js +161 -0
- package/dist/commands/publish.d.ts +27 -0
- package/dist/commands/publish.js +334 -0
- package/dist/commands/rescan.d.ts +40 -0
- package/dist/commands/rescan.js +255 -0
- package/dist/commands/update.d.ts +14 -0
- package/dist/commands/update.js +87 -0
- package/dist/commands/verify.d.ts +14 -0
- package/dist/commands/verify.js +71 -0
- package/dist/config/configurable-command.d.ts +13 -0
- package/dist/config/configurable-command.js +70 -0
- package/dist/config/mcpmake-config.d.ts +68 -0
- package/dist/config/mcpmake-config.js +207 -0
- package/dist/docs/cli.md +400 -0
- package/dist/docs/mcp-2026-07-28-migration.md +78 -0
- package/dist/docs/migrate-from-stainless.md +94 -0
- package/dist/docs/quickstart.md +166 -0
- package/dist/docs/show-hn.md +26 -0
- package/dist/docs/website-servers.md +169 -0
- package/dist/emitter/code-writer.d.ts +8 -0
- package/dist/emitter/code-writer.js +25 -0
- package/dist/emitter/index.d.ts +32 -0
- package/dist/emitter/index.js +280 -0
- package/dist/emitter/mcpb-bundler.d.ts +31 -0
- package/dist/emitter/mcpb-bundler.js +172 -0
- package/dist/emitter/project-scaffolder.d.ts +4 -0
- package/dist/emitter/project-scaffolder.js +89 -0
- package/dist/emitter/python-template-loader.d.ts +4 -0
- package/dist/emitter/python-template-loader.js +30 -0
- package/dist/emitter/python-templates/dockerfile.hbs +14 -0
- package/dist/emitter/python-templates/env.example.hbs +6 -0
- package/dist/emitter/python-templates/requirements.txt.hbs +4 -0
- package/dist/emitter/python-templates/server.py.hbs +77 -0
- package/dist/emitter/site-scaffolder.d.ts +13 -0
- package/dist/emitter/site-scaffolder.js +70 -0
- package/dist/emitter/site-template-loader.d.ts +5 -0
- package/dist/emitter/site-template-loader.js +47 -0
- package/dist/emitter/site-templates/browser-manager.ts.hbs +233 -0
- package/dist/emitter/site-templates/config.ts.hbs +28 -0
- package/dist/emitter/site-templates/dockerfile.hbs +31 -0
- package/dist/emitter/site-templates/env.example.hbs +19 -0
- package/dist/emitter/site-templates/package.json.hbs +26 -0
- package/dist/emitter/site-templates/server-main-http.ts.hbs +108 -0
- package/dist/emitter/site-templates/server-main.ts.hbs +23 -0
- package/dist/emitter/site-templates/tool-handler-action.ts.hbs +86 -0
- package/dist/emitter/site-templates/tool-handler-form.ts.hbs +116 -0
- package/dist/emitter/site-templates/tool-handler-lifecycle.ts.hbs +146 -0
- package/dist/emitter/site-templates/tool-index.ts.hbs +11 -0
- package/dist/emitter/template-loader.d.ts +1 -0
- package/dist/emitter/template-loader.js +27 -0
- package/dist/emitter/templates/auth-provider.ts.hbs +57 -0
- package/dist/emitter/templates/config.ts.hbs +63 -0
- package/dist/emitter/templates/discovery.ts.hbs +301 -0
- package/dist/emitter/templates/dockerfile.hbs +34 -0
- package/dist/emitter/templates/env.example.hbs +28 -0
- package/dist/emitter/templates/gitignore.hbs +5 -0
- package/dist/emitter/templates/http-executor.ts.hbs +117 -0
- package/dist/emitter/templates/oauth.ts.hbs +188 -0
- package/dist/emitter/templates/package.json.hbs +25 -0
- package/dist/emitter/templates/prompts.ts.hbs +22 -0
- package/dist/emitter/templates/readme.md.hbs +123 -0
- package/dist/emitter/templates/resources.ts.hbs +63 -0
- package/dist/emitter/templates/server-main-http.ts.hbs +407 -0
- package/dist/emitter/templates/server-main.ts.hbs +40 -0
- package/dist/emitter/templates/task-handlers.ts.hbs +189 -0
- package/dist/emitter/templates/task-manager.ts.hbs +139 -0
- package/dist/emitter/templates/task-sse.ts.hbs +105 -0
- package/dist/emitter/templates/tool-handler.ts.hbs +124 -0
- package/dist/emitter/templates/tool-index.ts.hbs +11 -0
- package/dist/emitter/templates/tool-test.ts.hbs +57 -0
- package/dist/emitter/templates/trace.ts.hbs +79 -0
- package/dist/emitter/templates/tsconfig.json.hbs +16 -0
- package/dist/emitter/templates/types.ts.hbs +5 -0
- package/dist/emitter/worker-template-loader.d.ts +5 -0
- package/dist/emitter/worker-template-loader.js +33 -0
- package/dist/emitter/worker-templates/config.ts.hbs +54 -0
- package/dist/emitter/worker-templates/dev-vars.example.hbs +10 -0
- package/dist/emitter/worker-templates/gitignore.hbs +6 -0
- package/dist/emitter/worker-templates/package.json.hbs +24 -0
- package/dist/emitter/worker-templates/readme.md.hbs +53 -0
- package/dist/emitter/worker-templates/server.test.ts.hbs +20 -0
- package/dist/emitter/worker-templates/tool-handler.ts.hbs +85 -0
- package/dist/emitter/worker-templates/tool-index.ts.hbs +28 -0
- package/dist/emitter/worker-templates/tsconfig.json.hbs +17 -0
- package/dist/emitter/worker-templates/worker.ts.hbs +242 -0
- package/dist/emitter/worker-templates/wrangler.toml.hbs +19 -0
- package/dist/generator/spec-generator.d.ts +6 -0
- package/dist/generator/spec-generator.js +50 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +64 -0
- package/dist/parser/har-filter.d.ts +8 -0
- package/dist/parser/har-filter.js +71 -0
- package/dist/parser/har-loader.d.ts +2 -0
- package/dist/parser/har-loader.js +14 -0
- package/dist/parser/har-normalizer.d.ts +20 -0
- package/dist/parser/har-normalizer.js +78 -0
- package/dist/parser/index.d.ts +10 -0
- package/dist/parser/index.js +6 -0
- package/dist/parser/openapi-loader.d.ts +6 -0
- package/dist/parser/openapi-loader.js +308 -0
- package/dist/parser/operation-extractor.d.ts +13 -0
- package/dist/parser/operation-extractor.js +155 -0
- package/dist/parser/overlay-loader.d.ts +10 -0
- package/dist/parser/overlay-loader.js +184 -0
- package/dist/parser/postman-loader.d.ts +9 -0
- package/dist/parser/postman-loader.js +106 -0
- package/dist/parser/schema-converter.d.ts +12 -0
- package/dist/parser/schema-converter.js +117 -0
- package/dist/plugins/adapter.d.ts +40 -0
- package/dist/plugins/adapter.js +15 -0
- package/dist/plugins/loader.d.ts +25 -0
- package/dist/plugins/loader.js +58 -0
- package/dist/pricing.d.ts +55 -0
- package/dist/pricing.js +133 -0
- package/dist/providers/index.d.ts +15 -0
- package/dist/providers/index.js +56 -0
- package/dist/recorder/browser-recorder.d.ts +22 -0
- package/dist/recorder/browser-recorder.js +205 -0
- package/dist/registry/official-registry.d.ts +90 -0
- package/dist/registry/official-registry.js +129 -0
- package/dist/rescan/diff-engine.d.ts +5 -0
- package/dist/rescan/diff-engine.js +312 -0
- package/dist/rescan/index.d.ts +3 -0
- package/dist/rescan/index.js +2 -0
- package/dist/rescan/rescan-runner.d.ts +42 -0
- package/dist/rescan/rescan-runner.js +69 -0
- package/dist/rescan/rescan-scheduler.d.ts +41 -0
- package/dist/rescan/rescan-scheduler.js +179 -0
- package/dist/site-transformer/browser-tools.d.ts +10 -0
- package/dist/site-transformer/browser-tools.js +59 -0
- package/dist/site-transformer/index.d.ts +2 -0
- package/dist/site-transformer/index.js +2 -0
- package/dist/site-transformer/selector-healer.d.ts +8 -0
- package/dist/site-transformer/selector-healer.js +106 -0
- package/dist/site-transformer/tool-generator.d.ts +13 -0
- package/dist/site-transformer/tool-generator.js +245 -0
- package/dist/transformer/auth-detector.d.ts +13 -0
- package/dist/transformer/auth-detector.js +90 -0
- package/dist/transformer/catalog-builder.d.ts +18 -0
- package/dist/transformer/catalog-builder.js +56 -0
- package/dist/transformer/client-compat.d.ts +6 -0
- package/dist/transformer/client-compat.js +44 -0
- package/dist/transformer/har-clusterer.d.ts +9 -0
- package/dist/transformer/har-clusterer.js +27 -0
- package/dist/transformer/har-dedup.d.ts +10 -0
- package/dist/transformer/har-dedup.js +81 -0
- package/dist/transformer/har-schema-inferrer.d.ts +15 -0
- package/dist/transformer/har-schema-inferrer.js +90 -0
- package/dist/transformer/har-to-operations.d.ts +13 -0
- package/dist/transformer/har-to-operations.js +192 -0
- package/dist/transformer/index.d.ts +8 -0
- package/dist/transformer/index.js +6 -0
- package/dist/transformer/llm-namer.d.ts +6 -0
- package/dist/transformer/llm-namer.js +59 -0
- package/dist/transformer/naming.d.ts +4 -0
- package/dist/transformer/naming.js +30 -0
- package/dist/transformer/operation-filter.d.ts +13 -0
- package/dist/transformer/operation-filter.js +52 -0
- package/dist/transformer/resource-builder.d.ts +12 -0
- package/dist/transformer/resource-builder.js +80 -0
- package/dist/transformer/schema-merger.d.ts +14 -0
- package/dist/transformer/schema-merger.js +65 -0
- package/dist/transformer/tool-builder.d.ts +3 -0
- package/dist/transformer/tool-builder.js +114 -0
- package/dist/types/index.d.ts +131 -0
- package/dist/types/index.js +1 -0
- package/dist/types/site.d.ts +284 -0
- package/dist/types/site.js +8 -0
- package/dist/utils/fail.d.ts +48 -0
- package/dist/utils/fail.js +204 -0
- package/dist/utils/fs.d.ts +5 -0
- package/dist/utils/fs.js +28 -0
- package/dist/utils/interactive.d.ts +6 -0
- package/dist/utils/interactive.js +30 -0
- package/dist/utils/logger.d.ts +1 -0
- package/dist/utils/logger.js +2 -0
- package/dist/utils/sanitize.d.ts +28 -0
- package/dist/utils/sanitize.js +44 -0
- package/dist/utils/watcher.d.ts +11 -0
- package/dist/utils/watcher.js +36 -0
- package/package.json +65 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static file server for web assets.
|
|
3
|
+
*
|
|
4
|
+
* Serves files from the `static/` directory with appropriate
|
|
5
|
+
* Content-Type headers, caching policy, and security headers.
|
|
6
|
+
*/
|
|
7
|
+
import http from 'node:http';
|
|
8
|
+
/**
|
|
9
|
+
* Serve a static file if the request path starts with `/static/`.
|
|
10
|
+
*
|
|
11
|
+
* @returns `true` if the request was handled, `false` otherwise.
|
|
12
|
+
*/
|
|
13
|
+
export declare function serveStatic(req: http.IncomingMessage, res: http.ServerResponse): Promise<boolean>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static file server for web assets.
|
|
3
|
+
*
|
|
4
|
+
* Serves files from the `static/` directory with appropriate
|
|
5
|
+
* Content-Type headers, caching policy, and security headers.
|
|
6
|
+
*/
|
|
7
|
+
import { readFile } from 'node:fs/promises';
|
|
8
|
+
import { resolve, dirname, extname } from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const STATIC_DIR = resolve(__dirname, 'static');
|
|
12
|
+
const MIME_TYPES = {
|
|
13
|
+
'.js': 'application/javascript',
|
|
14
|
+
'.css': 'text/css',
|
|
15
|
+
'.svg': 'image/svg+xml',
|
|
16
|
+
'.png': 'image/png',
|
|
17
|
+
'.ico': 'image/x-icon',
|
|
18
|
+
'.json': 'application/json',
|
|
19
|
+
'.woff': 'font/woff',
|
|
20
|
+
'.woff2': 'font/woff2',
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Serve a static file if the request path starts with `/static/`.
|
|
24
|
+
*
|
|
25
|
+
* @returns `true` if the request was handled, `false` otherwise.
|
|
26
|
+
*/
|
|
27
|
+
export async function serveStatic(req, res) {
|
|
28
|
+
const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
|
|
29
|
+
const pathname = url.pathname;
|
|
30
|
+
if (!pathname.startsWith('/static/')) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
// Strip "/static/" prefix and resolve against the static directory
|
|
34
|
+
const relativePath = pathname.slice('/static/'.length);
|
|
35
|
+
const filePath = resolve(STATIC_DIR, relativePath);
|
|
36
|
+
// Path traversal guard: resolved path must remain inside STATIC_DIR
|
|
37
|
+
if (!filePath.startsWith(STATIC_DIR + '/')) {
|
|
38
|
+
res.writeHead(403, { 'X-Content-Type-Options': 'nosniff' });
|
|
39
|
+
res.end('Forbidden');
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
let data;
|
|
43
|
+
try {
|
|
44
|
+
data = await readFile(filePath);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// File not found — let the caller handle 404
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const ext = extname(filePath).toLowerCase();
|
|
51
|
+
const contentType = MIME_TYPES[ext] ?? 'application/octet-stream';
|
|
52
|
+
// Cache policy
|
|
53
|
+
let cacheControl;
|
|
54
|
+
if (ext === '.js') {
|
|
55
|
+
// Vendored JS files — long-lived immutable cache
|
|
56
|
+
cacheControl = 'public, max-age=31536000, immutable';
|
|
57
|
+
}
|
|
58
|
+
else if (ext === '.css') {
|
|
59
|
+
// CSS changes during dev
|
|
60
|
+
cacheControl = 'public, max-age=3600';
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
cacheControl = 'no-cache';
|
|
64
|
+
}
|
|
65
|
+
res.writeHead(200, {
|
|
66
|
+
'Content-Type': contentType,
|
|
67
|
+
'Content-Length': data.length,
|
|
68
|
+
'Cache-Control': cacheControl,
|
|
69
|
+
'X-Content-Type-Options': 'nosniff',
|
|
70
|
+
});
|
|
71
|
+
res.end(data);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web template engine — Handlebars configured for HTML rendering.
|
|
3
|
+
*
|
|
4
|
+
* Uses a SEPARATE Handlebars instance from the code-gen template loader
|
|
5
|
+
* so that HTML escaping remains enabled (the default).
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Render a page template inside a layout.
|
|
9
|
+
*
|
|
10
|
+
* 1. Render the page template with `data` -> produces content HTML.
|
|
11
|
+
* 2. Render the layout template with `{...data, content: pageContent}` -> full HTML document.
|
|
12
|
+
*
|
|
13
|
+
* @param page - Template name like "pages/landing/index" (no .hbs extension)
|
|
14
|
+
* @param layout - Layout name like "layouts/landing" (no .hbs extension)
|
|
15
|
+
* @param data - Template context data
|
|
16
|
+
* @returns Full HTML string
|
|
17
|
+
*/
|
|
18
|
+
export declare function renderPage(page: string, layout: string, data: Record<string, unknown>): string;
|
|
19
|
+
/**
|
|
20
|
+
* Render a template without a layout wrapper.
|
|
21
|
+
* Useful for htmx partial responses and fragments.
|
|
22
|
+
*
|
|
23
|
+
* @param name - Template name like "pages/dashboard/servers-partial" (no .hbs extension)
|
|
24
|
+
* @param data - Template context data
|
|
25
|
+
* @returns HTML string (no full document wrapper)
|
|
26
|
+
*/
|
|
27
|
+
export declare function renderTemplate(name: string, data: Record<string, unknown>): string;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web template engine — Handlebars configured for HTML rendering.
|
|
3
|
+
*
|
|
4
|
+
* Uses a SEPARATE Handlebars instance from the code-gen template loader
|
|
5
|
+
* so that HTML escaping remains enabled (the default).
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, readdirSync, statSync } from 'node:fs';
|
|
8
|
+
import { resolve, dirname, relative } from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
import Handlebars from 'handlebars';
|
|
11
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const TEMPLATE_DIR = resolve(__dirname, 'templates');
|
|
13
|
+
// Isolated Handlebars instance — HTML escaping ON (default behavior)
|
|
14
|
+
const hbs = Handlebars.create();
|
|
15
|
+
const templateCache = new Map();
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Helpers
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
hbs.registerHelper('eq', function (a, b) {
|
|
20
|
+
return a === b;
|
|
21
|
+
});
|
|
22
|
+
hbs.registerHelper('capitalize', function (str) {
|
|
23
|
+
if (!str)
|
|
24
|
+
return str;
|
|
25
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
26
|
+
});
|
|
27
|
+
hbs.registerHelper('formatDate', function (isoString) {
|
|
28
|
+
if (!isoString)
|
|
29
|
+
return '';
|
|
30
|
+
const date = new Date(isoString);
|
|
31
|
+
if (isNaN(date.getTime()))
|
|
32
|
+
return isoString;
|
|
33
|
+
return date.toLocaleDateString('en-US', {
|
|
34
|
+
month: 'short',
|
|
35
|
+
day: 'numeric',
|
|
36
|
+
year: 'numeric',
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
hbs.registerHelper('statusColor', function (status) {
|
|
40
|
+
switch (status) {
|
|
41
|
+
case 'running':
|
|
42
|
+
return 'green';
|
|
43
|
+
case 'stopped':
|
|
44
|
+
return 'gray';
|
|
45
|
+
case 'error':
|
|
46
|
+
return 'red';
|
|
47
|
+
case 'building':
|
|
48
|
+
return 'yellow';
|
|
49
|
+
default:
|
|
50
|
+
return 'gray';
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
hbs.registerHelper('truncate', function (str, len) {
|
|
54
|
+
if (!str)
|
|
55
|
+
return '';
|
|
56
|
+
if (typeof len !== 'number' || len <= 0)
|
|
57
|
+
return str;
|
|
58
|
+
if (str.length <= len)
|
|
59
|
+
return str;
|
|
60
|
+
return str.slice(0, len) + '...';
|
|
61
|
+
});
|
|
62
|
+
hbs.registerHelper('json', function (data) {
|
|
63
|
+
// Escape </script> and <!-- to prevent XSS when embedded in <script> tags
|
|
64
|
+
return JSON.stringify(data).replace(/</g, '\\u003c').replace(/>/g, '\\u003e');
|
|
65
|
+
});
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// Partial auto-registration
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
function registerPartials(dir) {
|
|
70
|
+
let entries;
|
|
71
|
+
try {
|
|
72
|
+
entries = readdirSync(dir);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// partials directory may not exist yet
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
for (const entry of entries) {
|
|
79
|
+
const fullPath = resolve(dir, entry);
|
|
80
|
+
const stat = statSync(fullPath);
|
|
81
|
+
if (stat.isDirectory()) {
|
|
82
|
+
registerPartials(fullPath);
|
|
83
|
+
}
|
|
84
|
+
else if (entry.endsWith('.hbs')) {
|
|
85
|
+
// Use the relative path from partials dir (without extension) as the partial name.
|
|
86
|
+
// For flat files: "nav.hbs" -> "nav"
|
|
87
|
+
// For nested: "common/header.hbs" -> "common/header"
|
|
88
|
+
const partialsDir = resolve(TEMPLATE_DIR, 'partials');
|
|
89
|
+
const rel = relative(partialsDir, fullPath);
|
|
90
|
+
const partialName = rel.replace(/\.hbs$/, '').replace(/\\/g, '/');
|
|
91
|
+
const content = readFileSync(fullPath, 'utf-8');
|
|
92
|
+
hbs.registerPartial(partialName, content);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Register partials on module load
|
|
97
|
+
registerPartials(resolve(TEMPLATE_DIR, 'partials'));
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// Template loading & caching
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
function loadTemplate(name) {
|
|
102
|
+
if (templateCache.has(name)) {
|
|
103
|
+
return templateCache.get(name);
|
|
104
|
+
}
|
|
105
|
+
const templatePath = resolve(TEMPLATE_DIR, `${name}.hbs`);
|
|
106
|
+
// Path traversal guard
|
|
107
|
+
if (!templatePath.startsWith(TEMPLATE_DIR + '/')) {
|
|
108
|
+
throw new Error(`Invalid template name: ${name}`);
|
|
109
|
+
}
|
|
110
|
+
const raw = readFileSync(templatePath, 'utf-8');
|
|
111
|
+
const compiled = hbs.compile(raw);
|
|
112
|
+
templateCache.set(name, compiled);
|
|
113
|
+
return compiled;
|
|
114
|
+
}
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// Public API
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
/**
|
|
119
|
+
* Render a page template inside a layout.
|
|
120
|
+
*
|
|
121
|
+
* 1. Render the page template with `data` -> produces content HTML.
|
|
122
|
+
* 2. Render the layout template with `{...data, content: pageContent}` -> full HTML document.
|
|
123
|
+
*
|
|
124
|
+
* @param page - Template name like "pages/landing/index" (no .hbs extension)
|
|
125
|
+
* @param layout - Layout name like "layouts/landing" (no .hbs extension)
|
|
126
|
+
* @param data - Template context data
|
|
127
|
+
* @returns Full HTML string
|
|
128
|
+
*/
|
|
129
|
+
export function renderPage(page, layout, data) {
|
|
130
|
+
const pageTemplate = loadTemplate(page);
|
|
131
|
+
const pageContent = pageTemplate(data);
|
|
132
|
+
const layoutTemplate = loadTemplate(layout);
|
|
133
|
+
return layoutTemplate({ ...data, content: pageContent });
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Render a template without a layout wrapper.
|
|
137
|
+
* Useful for htmx partial responses and fragments.
|
|
138
|
+
*
|
|
139
|
+
* @param name - Template name like "pages/dashboard/servers-partial" (no .hbs extension)
|
|
140
|
+
* @param data - Template context data
|
|
141
|
+
* @returns HTML string (no full document wrapper)
|
|
142
|
+
*/
|
|
143
|
+
export function renderTemplate(name, data) {
|
|
144
|
+
const template = loadTemplate(name);
|
|
145
|
+
return template(data);
|
|
146
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
{{#if metaTitle}}<title>{{metaTitle}}</title>{{else}}<title>Admin — mcpmake Cloud</title>{{/if}}
|
|
7
|
+
<link rel="icon" href="/static/favicon.svg" type="image/svg+xml">
|
|
8
|
+
<link rel="stylesheet" href="/static/style.css">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<a href="#main-content" class="skip-to-content">Skip to content</a>
|
|
12
|
+
<div class="admin-shell">
|
|
13
|
+
<aside class="admin-sidebar" role="complementary" aria-label="Admin sidebar">
|
|
14
|
+
<div class="admin-sidebar-header">
|
|
15
|
+
<a href="/" class="admin-sidebar-logo" aria-label="mcpmake home">mcpmake</a>
|
|
16
|
+
<span class="admin-sidebar-label">Admin</span>
|
|
17
|
+
</div>
|
|
18
|
+
<nav class="admin-sidebar-nav" aria-label="Admin navigation">
|
|
19
|
+
<a href="/admin" class="admin-nav-link{{#if (eq activePage 'overview')}} active{{/if}}"{{#if (eq activePage 'overview')}} aria-current="page"{{/if}}>
|
|
20
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></svg>
|
|
21
|
+
Overview
|
|
22
|
+
</a>
|
|
23
|
+
<a href="/admin/servers" class="admin-nav-link{{#if (eq activePage 'servers')}} active{{/if}}"{{#if (eq activePage 'servers')}} aria-current="page"{{/if}}>
|
|
24
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="2" width="20" height="8" rx="2"/><rect x="2" y="14" width="20" height="8" rx="2"/><line x1="6" y1="6" x2="6.01" y2="6"/><line x1="6" y1="18" x2="6.01" y2="18"/></svg>
|
|
25
|
+
Servers
|
|
26
|
+
</a>
|
|
27
|
+
<a href="/admin/users" class="admin-nav-link{{#if (eq activePage 'users')}} active{{/if}}"{{#if (eq activePage 'users')}} aria-current="page"{{/if}}>
|
|
28
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
|
|
29
|
+
Users
|
|
30
|
+
</a>
|
|
31
|
+
<a href="/admin/telemetry" class="admin-nav-link{{#if (eq activePage 'telemetry')}} active{{/if}}"{{#if (eq activePage 'telemetry')}} aria-current="page"{{/if}}>
|
|
32
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
|
|
33
|
+
Telemetry
|
|
34
|
+
</a>
|
|
35
|
+
</nav>
|
|
36
|
+
<div class="admin-sidebar-footer">
|
|
37
|
+
<a href="/dashboard" class="admin-nav-link admin-nav-link--back">
|
|
38
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>
|
|
39
|
+
Back to Dashboard
|
|
40
|
+
</a>
|
|
41
|
+
<div class="admin-sidebar-user">
|
|
42
|
+
<span class="admin-sidebar-email" title="{{user.email}}">{{user.email}}</span>
|
|
43
|
+
<form method="POST" action="/logout">
|
|
44
|
+
<input type="hidden" name="_csrf" value="{{csrfToken}}">
|
|
45
|
+
<button type="submit" class="admin-signout-btn">Sign out</button>
|
|
46
|
+
</form>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</aside>
|
|
50
|
+
<main id="main-content" class="admin-main">
|
|
51
|
+
{{{content}}}
|
|
52
|
+
</main>
|
|
53
|
+
</div>
|
|
54
|
+
<script src="/static/htmx.min.js" defer></script>
|
|
55
|
+
<script src="/static/alpine.min.js" defer></script>
|
|
56
|
+
</body>
|
|
57
|
+
</html>
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
{{#if metaTitle}}<title>{{metaTitle}}</title>{{else}}<title>mcpmake Cloud</title>{{/if}}
|
|
7
|
+
<link rel="icon" href="/static/favicon.svg" type="image/svg+xml">
|
|
8
|
+
<link rel="stylesheet" href="/static/style.css">
|
|
9
|
+
<style>
|
|
10
|
+
.auth-page {
|
|
11
|
+
min-height: 100vh;
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
align-items: center;
|
|
15
|
+
justify-content: center;
|
|
16
|
+
padding: 2rem 1rem;
|
|
17
|
+
}
|
|
18
|
+
.auth-card {
|
|
19
|
+
width: 100%;
|
|
20
|
+
max-width: 420px;
|
|
21
|
+
background: var(--color-card-bg, #18181b);
|
|
22
|
+
border: 1px solid var(--color-border, #27272a);
|
|
23
|
+
border-radius: 12px;
|
|
24
|
+
padding: 2rem;
|
|
25
|
+
}
|
|
26
|
+
.auth-card h1 {
|
|
27
|
+
font-size: 1.5rem;
|
|
28
|
+
margin-bottom: 0.25rem;
|
|
29
|
+
text-align: center;
|
|
30
|
+
}
|
|
31
|
+
.auth-card .auth-subtitle {
|
|
32
|
+
color: var(--color-text-muted, #a1a1aa);
|
|
33
|
+
text-align: center;
|
|
34
|
+
margin-bottom: 1.5rem;
|
|
35
|
+
font-size: 0.9rem;
|
|
36
|
+
}
|
|
37
|
+
.auth-logo {
|
|
38
|
+
display: block;
|
|
39
|
+
text-align: center;
|
|
40
|
+
font-weight: 700;
|
|
41
|
+
font-size: 1.1rem;
|
|
42
|
+
margin-bottom: 1.5rem;
|
|
43
|
+
color: var(--color-text-dark, #e4e4e7);
|
|
44
|
+
}
|
|
45
|
+
.auth-logo:hover {
|
|
46
|
+
color: var(--color-primary, #6366f1);
|
|
47
|
+
}
|
|
48
|
+
.form-group {
|
|
49
|
+
margin-bottom: 1rem;
|
|
50
|
+
}
|
|
51
|
+
.form-group label {
|
|
52
|
+
display: block;
|
|
53
|
+
font-size: 0.85rem;
|
|
54
|
+
font-weight: 500;
|
|
55
|
+
margin-bottom: 0.35rem;
|
|
56
|
+
color: var(--color-text-dark, #e4e4e7);
|
|
57
|
+
}
|
|
58
|
+
.form-group input {
|
|
59
|
+
width: 100%;
|
|
60
|
+
padding: 0.6rem 0.75rem;
|
|
61
|
+
border: 1px solid var(--color-border, #27272a);
|
|
62
|
+
border-radius: 6px;
|
|
63
|
+
background: var(--color-bg-dark, #0a0a0f);
|
|
64
|
+
color: var(--color-text-dark, #e4e4e7);
|
|
65
|
+
font-size: 0.95rem;
|
|
66
|
+
outline: none;
|
|
67
|
+
transition: border-color 0.15s;
|
|
68
|
+
}
|
|
69
|
+
.form-group input:focus {
|
|
70
|
+
border-color: var(--color-primary, #6366f1);
|
|
71
|
+
}
|
|
72
|
+
.form-hint {
|
|
73
|
+
font-size: 0.8rem;
|
|
74
|
+
color: var(--color-text-muted, #a1a1aa);
|
|
75
|
+
margin-top: 0.25rem;
|
|
76
|
+
}
|
|
77
|
+
.auth-error {
|
|
78
|
+
background: rgba(239, 68, 68, 0.1);
|
|
79
|
+
border: 1px solid rgba(239, 68, 68, 0.3);
|
|
80
|
+
color: #fca5a5;
|
|
81
|
+
padding: 0.6rem 0.75rem;
|
|
82
|
+
border-radius: 6px;
|
|
83
|
+
font-size: 0.875rem;
|
|
84
|
+
margin-bottom: 1rem;
|
|
85
|
+
}
|
|
86
|
+
.auth-error a {
|
|
87
|
+
color: #fca5a5;
|
|
88
|
+
text-decoration: underline;
|
|
89
|
+
}
|
|
90
|
+
.auth-success {
|
|
91
|
+
background: rgba(34, 197, 94, 0.1);
|
|
92
|
+
border: 1px solid rgba(34, 197, 94, 0.3);
|
|
93
|
+
color: #86efac;
|
|
94
|
+
padding: 0.6rem 0.75rem;
|
|
95
|
+
border-radius: 6px;
|
|
96
|
+
font-size: 0.875rem;
|
|
97
|
+
margin-bottom: 1rem;
|
|
98
|
+
}
|
|
99
|
+
.auth-submit {
|
|
100
|
+
width: 100%;
|
|
101
|
+
padding: 0.65rem;
|
|
102
|
+
border: none;
|
|
103
|
+
border-radius: 6px;
|
|
104
|
+
background: var(--color-primary, #6366f1);
|
|
105
|
+
color: #fff;
|
|
106
|
+
font-size: 0.95rem;
|
|
107
|
+
font-weight: 600;
|
|
108
|
+
cursor: pointer;
|
|
109
|
+
transition: background 0.15s;
|
|
110
|
+
margin-top: 0.5rem;
|
|
111
|
+
}
|
|
112
|
+
.auth-submit:hover {
|
|
113
|
+
background: var(--color-primary-hover, #818cf8);
|
|
114
|
+
}
|
|
115
|
+
.auth-footer {
|
|
116
|
+
text-align: center;
|
|
117
|
+
margin-top: 1.25rem;
|
|
118
|
+
font-size: 0.875rem;
|
|
119
|
+
color: var(--color-text-muted, #a1a1aa);
|
|
120
|
+
}
|
|
121
|
+
.auth-footer a {
|
|
122
|
+
color: var(--color-primary, #6366f1);
|
|
123
|
+
}
|
|
124
|
+
.auth-footer a:hover {
|
|
125
|
+
text-decoration: underline;
|
|
126
|
+
}
|
|
127
|
+
</style>
|
|
128
|
+
</head>
|
|
129
|
+
<body>
|
|
130
|
+
<a href="#main-content" class="skip-to-content">Skip to content</a>
|
|
131
|
+
<main id="main-content" class="auth-page">
|
|
132
|
+
<a href="/" class="auth-logo" aria-label="mcpmake home">mcpmake</a>
|
|
133
|
+
<div class="auth-card">
|
|
134
|
+
{{{content}}}
|
|
135
|
+
</div>
|
|
136
|
+
</main>
|
|
137
|
+
</body>
|
|
138
|
+
</html>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
{{#if metaDescription}}<meta name="description" content="{{metaDescription}}">{{/if}}
|
|
7
|
+
{{#if metaTitle}}<title>{{metaTitle}}</title>{{else}}<title>mcpmake Cloud</title>{{/if}}
|
|
8
|
+
<link rel="icon" href="/static/favicon.svg" type="image/svg+xml">
|
|
9
|
+
<link rel="stylesheet" href="/static/style.css">
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
{{{body}}}
|
|
13
|
+
<script src="/static/htmx.min.js" defer></script>
|
|
14
|
+
<script src="/static/alpine.min.js" defer></script>
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>{{#if metaTitle}}{{metaTitle}}{{else}}Dashboard — mcpmake Cloud{{/if}}</title>
|
|
7
|
+
<link rel="icon" href="/static/favicon.svg" type="image/svg+xml">
|
|
8
|
+
<link rel="stylesheet" href="/static/style.css">
|
|
9
|
+
</head>
|
|
10
|
+
<body class="dashboard-body">
|
|
11
|
+
<a href="#main-content" class="skip-to-content">Skip to content</a>
|
|
12
|
+
<aside class="sidebar" role="complementary" aria-label="Dashboard sidebar">
|
|
13
|
+
<a href="/dashboard" class="sidebar-logo" aria-label="mcpmake dashboard home">mcpmake</a>
|
|
14
|
+
<nav class="sidebar-nav" aria-label="Dashboard navigation">
|
|
15
|
+
<a href="/dashboard" class="sidebar-link {{#if (eq activePage 'servers')}}active{{/if}}"{{#if (eq activePage 'servers')}} aria-current="page"{{/if}}>Servers</a>
|
|
16
|
+
<a href="/dashboard/create" class="sidebar-link {{#if (eq activePage 'create')}}active{{/if}}"{{#if (eq activePage 'create')}} aria-current="page"{{/if}}>New Server</a>
|
|
17
|
+
<a href="/dashboard/billing" class="sidebar-link {{#if (eq activePage 'billing')}}active{{/if}}"{{#if (eq activePage 'billing')}} aria-current="page"{{/if}}>Billing</a>
|
|
18
|
+
<a href="/docs" class="sidebar-link">Docs</a>
|
|
19
|
+
{{#if user.isAdmin}}
|
|
20
|
+
<hr class="sidebar-divider">
|
|
21
|
+
<a href="/admin" class="sidebar-link {{#if (eq activePage 'admin')}}active{{/if}}"{{#if (eq activePage 'admin')}} aria-current="page"{{/if}}>Admin</a>
|
|
22
|
+
{{/if}}
|
|
23
|
+
</nav>
|
|
24
|
+
<div class="sidebar-footer">
|
|
25
|
+
<span class="sidebar-email" title="{{user.email}}">{{user.email}}</span>
|
|
26
|
+
<form method="POST" action="/logout">
|
|
27
|
+
<input type="hidden" name="_csrf" value="{{csrfToken}}">
|
|
28
|
+
<button type="submit" class="sidebar-logout">Sign out</button>
|
|
29
|
+
</form>
|
|
30
|
+
</div>
|
|
31
|
+
</aside>
|
|
32
|
+
<main id="main-content" class="dashboard-main">
|
|
33
|
+
{{{content}}}
|
|
34
|
+
</main>
|
|
35
|
+
<script src="/static/htmx.min.js" defer></script>
|
|
36
|
+
<script src="/static/htmx-sse.js" defer></script>
|
|
37
|
+
<script src="/static/alpine.min.js" defer></script>
|
|
38
|
+
</body>
|
|
39
|
+
</html>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<meta name="description" content="{{#if metaDescription}}{{metaDescription}}{{else}}Generate and host MCP servers from your API specs. Upload an OpenAPI spec or HAR file, get a running MCP server in 30 seconds. Free to start.{{/if}}">
|
|
7
|
+
<title>{{#if metaTitle}}{{metaTitle}}{{else}}mcpmake Cloud — Your API as an MCP server in 30 seconds{{/if}}</title>
|
|
8
|
+
|
|
9
|
+
<!-- Open Graph -->
|
|
10
|
+
<meta property="og:type" content="website">
|
|
11
|
+
<meta property="og:title" content="{{#if metaTitle}}{{metaTitle}}{{else}}mcpmake Cloud — Your API as an MCP server in 30 seconds{{/if}}">
|
|
12
|
+
<meta property="og:description" content="{{#if metaDescription}}{{metaDescription}}{{else}}Generate and host MCP servers from your API specs. Upload an OpenAPI spec or HAR file, get a running MCP server in 30 seconds. Free to start.{{/if}}">
|
|
13
|
+
<meta property="og:url" content="https://mcpmake.io/">
|
|
14
|
+
|
|
15
|
+
<!-- Canonical -->
|
|
16
|
+
<link rel="canonical" href="https://mcpmake.io/">
|
|
17
|
+
|
|
18
|
+
<!-- Structured Data -->
|
|
19
|
+
<script type="application/ld+json">
|
|
20
|
+
{
|
|
21
|
+
"@context": "https://schema.org",
|
|
22
|
+
"@type": "SoftwareApplication",
|
|
23
|
+
"name": "mcpmake Cloud",
|
|
24
|
+
"applicationCategory": "DeveloperApplication",
|
|
25
|
+
"operatingSystem": "Web",
|
|
26
|
+
"description": "Generate and host MCP servers from your API specs. Upload an OpenAPI spec or HAR file, get a running MCP server in 30 seconds.",
|
|
27
|
+
"url": "https://mcpmake.io/",
|
|
28
|
+
"offers": {
|
|
29
|
+
"@type": "Offer",
|
|
30
|
+
"price": "0",
|
|
31
|
+
"priceCurrency": "USD"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<link rel="icon" href="/static/favicon.svg" type="image/svg+xml">
|
|
37
|
+
<link rel="stylesheet" href="/static/style.css">
|
|
38
|
+
</head>
|
|
39
|
+
<body>
|
|
40
|
+
<a href="#main-content" class="skip-to-content">Skip to content</a>
|
|
41
|
+
<header class="nav" role="banner">
|
|
42
|
+
<div class="nav-inner">
|
|
43
|
+
<a href="/" class="nav-logo" aria-label="mcpmake home">mcpmake</a>
|
|
44
|
+
<nav class="nav-links" aria-label="Main navigation">
|
|
45
|
+
<a href="#features">Features</a>
|
|
46
|
+
<a href="#pricing">Pricing</a>
|
|
47
|
+
<a href="/docs">Docs</a>
|
|
48
|
+
<a href="/login" class="nav-link-subtle">Sign in</a>
|
|
49
|
+
<a href="/register" class="btn btn-primary btn-sm">Deploy free</a>
|
|
50
|
+
</nav>
|
|
51
|
+
</div>
|
|
52
|
+
</header>
|
|
53
|
+
<main id="main-content">
|
|
54
|
+
{{{content}}}
|
|
55
|
+
</main>
|
|
56
|
+
<footer class="footer">
|
|
57
|
+
<div class="footer-inner">
|
|
58
|
+
<div class="footer-col">
|
|
59
|
+
<h4>Product</h4>
|
|
60
|
+
<a href="#pricing">Pricing</a>
|
|
61
|
+
<a href="#features">Features</a>
|
|
62
|
+
<a href="/login">Dashboard</a>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="footer-col">
|
|
65
|
+
<h4>Resources</h4>
|
|
66
|
+
<a href="/docs">Docs</a>
|
|
67
|
+
<a href="/docs/cli">CLI reference</a>
|
|
68
|
+
<a href="/docs/quickstart">Quickstart</a>
|
|
69
|
+
<a href="https://modelcontextprotocol.io" target="_blank" rel="noopener">MCP Spec</a>
|
|
70
|
+
</div>
|
|
71
|
+
<div class="footer-col">
|
|
72
|
+
<h4>Legal</h4>
|
|
73
|
+
<a href="/privacy">Privacy</a>
|
|
74
|
+
<a href="/terms">Terms</a>
|
|
75
|
+
</div>
|
|
76
|
+
<p class="footer-copy">© {{year}} mcpmake. All rights reserved.</p>
|
|
77
|
+
</div>
|
|
78
|
+
</footer>
|
|
79
|
+
<script src="/static/htmx.min.js" defer></script>
|
|
80
|
+
<script src="/static/alpine.min.js" defer></script>
|
|
81
|
+
</body>
|
|
82
|
+
</html>
|