frontmcp 1.1.0 → 1.1.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/package.json +5 -5
- package/src/commands/build/adapters/cloudflare.js +29 -1
- package/src/commands/build/adapters/cloudflare.js.map +1 -1
- package/src/commands/build/adapters/distributed.js +4 -1
- package/src/commands/build/adapters/distributed.js.map +1 -1
- package/src/commands/build/exec/cli-runtime/extract-public-message.snippet.d.ts +18 -0
- package/src/commands/build/exec/cli-runtime/extract-public-message.snippet.js +58 -0
- package/src/commands/build/exec/cli-runtime/extract-public-message.snippet.js.map +1 -0
- package/src/commands/build/exec/cli-runtime/generate-cli-entry.d.ts +2 -2
- package/src/commands/build/exec/cli-runtime/generate-cli-entry.js +165 -47
- package/src/commands/build/exec/cli-runtime/generate-cli-entry.js.map +1 -1
- package/src/commands/build/exec/cli-runtime/schema-extractor.d.ts +7 -0
- package/src/commands/build/exec/cli-runtime/schema-extractor.js +17 -1
- package/src/commands/build/exec/cli-runtime/schema-extractor.js.map +1 -1
- package/src/commands/build/exec/index.d.ts +11 -0
- package/src/commands/build/exec/index.js +68 -20
- package/src/commands/build/exec/index.js.map +1 -1
- package/src/commands/build/exec/installer-script.d.ts +8 -2
- package/src/commands/build/exec/installer-script.js +34 -15
- package/src/commands/build/exec/installer-script.js.map +1 -1
- package/src/commands/build/exec/manifest.d.ts +16 -3
- package/src/commands/build/exec/manifest.js +17 -5
- package/src/commands/build/exec/manifest.js.map +1 -1
- package/src/commands/build/exec/runner-script.d.ts +9 -1
- package/src/commands/build/exec/runner-script.js +60 -2
- package/src/commands/build/exec/runner-script.js.map +1 -1
- package/src/commands/build/index.js +80 -18
- package/src/commands/build/index.js.map +1 -1
- package/src/commands/build/load-entry-config.d.ts +5 -0
- package/src/commands/build/load-entry-config.js +96 -0
- package/src/commands/build/load-entry-config.js.map +1 -0
- package/src/commands/build/mcpb/manifest.d.ts +14 -0
- package/src/commands/build/mcpb/manifest.js +29 -0
- package/src/commands/build/mcpb/manifest.js.map +1 -1
- package/src/commands/build/types.d.ts +19 -0
- package/src/commands/build/types.js.map +1 -1
- package/src/commands/dev/doctor.js +7 -3
- package/src/commands/dev/doctor.js.map +1 -1
- package/src/commands/package/install.d.ts +1 -1
- package/src/commands/package/install.js +10 -8
- package/src/commands/package/install.js.map +1 -1
- package/src/commands/package/types.d.ts +2 -1
- package/src/commands/package/types.js.map +1 -1
- package/src/config/frontmcp-config.loader.d.ts +20 -0
- package/src/config/frontmcp-config.loader.js +124 -5
- package/src/config/frontmcp-config.loader.js.map +1 -1
- package/src/config/index.d.ts +1 -1
- package/src/config/index.js +2 -1
- package/src/config/index.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner-script.js","sourceRoot":"","sources":["../../../../../src/commands/build/exec/runner-script.ts"],"names":[],"mappings":";AAAA;;;GAGG;;
|
|
1
|
+
{"version":3,"file":"runner-script.js","sourceRoot":"","sources":["../../../../../src/commands/build/exec/runner-script.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAWH,oDAGC;AAED,oDA6IC;AAzJD;;;;;;GAMG;AACH,SAAgB,oBAAoB,CAAC,KAAa;IAChD,0EAA0E;IAC1E,OAAO,KAAK,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;AACjD,CAAC;AAED,SAAgB,oBAAoB,CAAC,MAA0B,EAAE,OAAiB,EAAE,OAAiB;IACnG,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACzB,MAAM,OAAO,GAAG,oBAAoB,CAAC,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,CAAC;IAEhE,yEAAyE;IACzE,6EAA6E;IAC7E,wEAAwE;IACxE,wEAAwE;IACxE,wBAAwB;IACxB,MAAM,eAAe,GAAG,CAAC,OAAO;QAC9B,CAAC,CAAC;;;;;EAKJ,IAAI,KAAK,OAAO;;;;;IAKd,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;;;;;;;;;;YAUI,IAAI,IAAI,OAAO;;;;0BAID,IAAI;;;;;;;;;;CAU7B;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,0DAA0D;IAC1D,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC;QAC3D,MAAM,OAAO,GAAG,OAAO;YACrB,CAAC,CAAC,KAAK,IAAI,qCAAqC;YAChD,CAAC,CAAC,KAAK,IAAI,wCAAwC,CAAC;QAEtD,OAAO;;;EAGT,OAAO;yCACgC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM;;;yBAGxC,MAAM;;;;;;EAM7B,eAAe;;;;;;;;;;;CAWhB,CAAC;IACA,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,UAAU,CAAC;IACrD,MAAM,YAAY,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAElD,MAAM,MAAM,GAAG,OAAO;QACpB,CAAC,CAAC,kBAAkB,IAAI,gBAAgB;QACxC,CAAC,CAAC,kBAAkB,IAAI,YAAY,CAAC;IAEvC,MAAM,OAAO,GAAG,OAAO;QACrB,CAAC,CAAC,KAAK,IAAI,4BAA4B;QACvC,CAAC,CAAC,KAAK,IAAI,2BAA2B,CAAC;IAEzC,OAAO;;;EAGP,OAAO;yCACgC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM;;;UAG5D,MAAM;EACd,eAAe;;;;0BAIS,WAAW;;;;;6BAKR,YAAY;yBAChB,WAAW;;;;;;;uCAOG,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM;;;;;;;;;;;;;;8CActB,IAAI;;;;;;CAMjD,CAAC;AACF,CAAC;AAED,SAAS,eAAe,CAAC,OAAe;IACtC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC7C,CAAC","sourcesContent":["/**\n * Bash runner script generation.\n * The runner checks Node.js, loads .env, and runs the bundle.\n */\n\nimport { type FrontmcpExecConfig } from './config';\n\n/**\n * Defense-in-depth: scrub anything outside `[a-zA-Z0-9._+-]` from values that\n * the runner / installer scripts interpolate into bash. The user owns\n * `frontmcp.config`, so a malicious value would be self-inflicted, but the\n * generated scripts are committed into repos and downloaded by end-users —\n * so we keep them safe to copy/paste regardless of upstream config hygiene.\n */\nexport function sanitizeShellLiteral(value: string): string {\n // `-` placed last in the character class is literal, so no escape needed.\n return value.replace(/[^A-Za-z0-9._+-]/g, '_');\n}\n\nexport function generateRunnerScript(config: FrontmcpExecConfig, cliMode?: boolean, seaMode?: boolean): string {\n const name = config.name;\n const version = sanitizeShellLiteral(config.version || '0.0.0');\n\n // #377 — `--target node` runner used to silently exec the bundle for any\n // flag, so `./frontegg-bin --help` quietly booted the HTTP server. Intercept\n // help/version here so server-mode runners behave like a normal CLI for\n // those flags. CLI-mode runners pass everything through to the bundle's\n // own commander parser.\n const helpInterceptor = !cliMode\n ? `\n# Intercept standard CLI flags before booting the long-running server.\ncase \"\\${1:-}\" in\n -h|--help)\n cat <<EOF\n${name} v${version} — FrontMCP server\n\nThis binary starts a long-running MCP HTTP server.\n\nUsage:\n ${name} Start the server\n ${name} --help Show this help\n ${name} --version Show version\n ${name} --print-manifest Print the deployment manifest as JSON\n\nConfigure via environment variables, .env, or frontmcp.config.\n\nFor a CLI-style binary that exposes tools/resources/prompts as subcommands,\nbuild with: frontmcp build --target cli\nEOF\n exit 0\n ;;\n --version)\n echo \"${name} ${version}\"\n exit 0\n ;;\n --print-manifest)\n cat \"\\${SCRIPT_DIR}/${name}.manifest.json\"\n exit 0\n ;;\n --*)\n echo \"Error: unsupported flag '\\${1}' on the server runner.\"\n echo \"This binary is a long-running HTTP server; flag-style invocation is reserved.\" >&2\n echo \"Run with no args to start, or build with --target cli for a CLI binary.\" >&2\n exit 2\n ;;\nesac\n`\n : '';\n\n // SEA mode: binary is self-contained, no Node.js required\n if (seaMode) {\n const binary = cliMode ? `${name}-cli-bin` : `${name}-bin`;\n const comment = cliMode\n ? `# ${name} — FrontMCP CLI (single executable)`\n : `# ${name} — FrontMCP Server (single executable)`;\n\n return `#!/usr/bin/env bash\nset -euo pipefail\n\n${comment}\n# Generated by frontmcp build --target ${cliMode ? 'cli' : 'node'}\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nBINARY=\"\\${SCRIPT_DIR}/${binary}\"\n\nif [ ! -f \"\\${BINARY}\" ]; then\n echo \"Error: Binary not found at \\${BINARY}\"\n exit 1\nfi\n${helpInterceptor}\n# Load .env if present\nENV_FILE=\"\\${SCRIPT_DIR}/.env\"\nif [ -f \"\\${ENV_FILE}\" ]; then\n set -a\n # shellcheck disable=SC1090\n source \"\\${ENV_FILE}\"\n set +a\nfi\n\nexec \"\\${BINARY}\" \"$@\"\n`;\n }\n\n const nodeVersion = config.nodeVersion || '>=22.0.0';\n const minNodeMajor = extractMinMajor(nodeVersion);\n\n const bundle = cliMode\n ? `\\${SCRIPT_DIR}/${name}-cli.bundle.js`\n : `\\${SCRIPT_DIR}/${name}.bundle.js`;\n\n const comment = cliMode\n ? `# ${name} — FrontMCP CLI Executable`\n : `# ${name} — FrontMCP Server Runner`;\n\n return `#!/usr/bin/env bash\nset -euo pipefail\n\n${comment}\n# Generated by frontmcp build --target ${cliMode ? 'cli --js' : 'node'}\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nBUNDLE=\"${bundle}\"\n${helpInterceptor}\n# Check Node.js\nif ! command -v node &> /dev/null; then\n echo \"Error: Node.js is required but not installed.\"\n echo \"Install Node.js ${nodeVersion}: https://nodejs.org\"\n exit 1\nfi\n\nNODE_MAJOR=$(node -e \"console.log(process.versions.node.split('.')[0])\")\nif [ \"\\${NODE_MAJOR}\" -lt \"${minNodeMajor}\" ]; then\n echo \"Error: Node.js ${nodeVersion} required, found v$(node -v)\"\n exit 1\nfi\n\n# Check bundle exists\nif [ ! -f \"\\${BUNDLE}\" ]; then\n echo \"Error: Bundle not found at \\${BUNDLE}\"\n echo \"Run 'frontmcp build --target ${cliMode ? 'cli --js' : 'node'}' to create it.\"\n exit 1\nfi\n\n# Load .env if present\nENV_FILE=\"\\${SCRIPT_DIR}/.env\"\nif [ -f \"\\${ENV_FILE}\" ]; then\n set -a\n # shellcheck disable=SC1090\n source \"\\${ENV_FILE}\"\n set +a\nfi\n\n# Enable Node.js compile cache for faster startup on warm runs\nCOMPILE_CACHE_DIR=\"\\${HOME}/.cache/frontmcp/${name}\"\nmkdir -p \"\\${COMPILE_CACHE_DIR}\" 2>/dev/null || true\nexport NODE_COMPILE_CACHE=\"\\${COMPILE_CACHE_DIR}\"\n\n# Run\nexec node \"\\${BUNDLE}\" \"$@\"\n`;\n}\n\nfunction extractMinMajor(version: string): number {\n const match = version.match(/(\\d+)/);\n return match ? parseInt(match[1], 10) : 22;\n}\n"]}
|
|
@@ -34,6 +34,15 @@ async function generateAdapterFiles(adapter, outDir, entryBasename, cwd) {
|
|
|
34
34
|
const entryPath = path.join(outDir, 'index.js');
|
|
35
35
|
await fs_1.fsp.writeFile(entryPath, entryContent, 'utf8');
|
|
36
36
|
console.log((0, colors_1.c)('green', ` Generated ${adapter} entry at ${path.relative(cwd, entryPath)}`));
|
|
37
|
+
// ESM adapters (vercel, lambda) emit `import` syntax in the entry. The
|
|
38
|
+
// user's project may be `"type": "commonjs"`, in which case Node and
|
|
39
|
+
// rspack treat the .js file as CJS and parsing fails on `import`.
|
|
40
|
+
// Drop a sibling package.json with `"type": "module"` so the dist
|
|
41
|
+
// directory is always interpreted correctly regardless of the parent.
|
|
42
|
+
if (template.moduleFormat === 'esnext') {
|
|
43
|
+
const pkgPath = path.join(outDir, 'package.json');
|
|
44
|
+
await fs_1.fsp.writeFile(pkgPath, JSON.stringify({ type: 'module' }, null, 2), 'utf8');
|
|
45
|
+
}
|
|
37
46
|
}
|
|
38
47
|
// Bundle if adapter requires it (creates single CJS file for serverless)
|
|
39
48
|
if (template.shouldBundle && template.bundleOutput) {
|
|
@@ -48,24 +57,34 @@ async function generateAdapterFiles(adapter, outDir, entryBasename, cwd) {
|
|
|
48
57
|
console.log((0, colors_1.c)('green', ` Created deployment output structure`));
|
|
49
58
|
}
|
|
50
59
|
}
|
|
51
|
-
// Generate config file if adapter has one
|
|
60
|
+
// Generate config file if adapter has one. By default we preserve an
|
|
61
|
+
// existing user-edited file. Adapters that mark `alwaysWriteConfig` (e.g.,
|
|
62
|
+
// cloudflare's wrangler.toml) overwrite it on every build so the
|
|
63
|
+
// generated `main = ...` path always matches the actual build output —
|
|
64
|
+
// see #374.
|
|
52
65
|
if (template.getConfig && template.configFileName) {
|
|
53
66
|
const configPath = path.join(cwd, template.configFileName);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
else {
|
|
58
|
-
const configContent = template.getConfig(cwd);
|
|
67
|
+
const exists = await (0, utils_1.fileExists)(configPath);
|
|
68
|
+
const configContent = template.getConfig(cwd);
|
|
69
|
+
const writeIt = async () => {
|
|
59
70
|
if (typeof configContent === 'string') {
|
|
60
|
-
// Write as plain text (e.g., TOML for wrangler.toml)
|
|
61
71
|
await fs_1.fsp.writeFile(configPath, configContent, 'utf8');
|
|
62
72
|
}
|
|
63
73
|
else {
|
|
64
|
-
// Write as JSON
|
|
65
74
|
await (0, utils_1.writeJSON)(configPath, configContent);
|
|
66
75
|
}
|
|
76
|
+
};
|
|
77
|
+
if (!exists) {
|
|
78
|
+
await writeIt();
|
|
67
79
|
console.log((0, colors_1.c)('green', ` Generated ${template.configFileName}`));
|
|
68
80
|
}
|
|
81
|
+
else if (template.alwaysWriteConfig) {
|
|
82
|
+
await writeIt();
|
|
83
|
+
console.log((0, colors_1.c)('green', ` Updated ${template.configFileName} (build output reference)`));
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
console.log((0, colors_1.c)('yellow', ` ${template.configFileName} already exists (skipping)`));
|
|
87
|
+
}
|
|
69
88
|
}
|
|
70
89
|
}
|
|
71
90
|
/** Map target names to internal adapter names. */
|
|
@@ -92,14 +111,17 @@ const TARGET_TO_ADAPTER = {
|
|
|
92
111
|
*/
|
|
93
112
|
async function runBuild(opts) {
|
|
94
113
|
const cwd = process.cwd();
|
|
95
|
-
// Try loading frontmcp.config for multi-target support
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
114
|
+
// Try loading frontmcp.config for multi-target support.
|
|
115
|
+
//
|
|
116
|
+
// #365 — `tryLoadFrontMcpConfig` differentiates between recoverable cases:
|
|
117
|
+
// - no config file present → returns undefined
|
|
118
|
+
// - config exists but doesn't match the new schema → returns undefined
|
|
119
|
+
// (legacy top-level `cli`/`sea`/`esbuild` shape — picked up later by
|
|
120
|
+
// the exec-build's own `loadExecConfig`)
|
|
121
|
+
// …and hard failures:
|
|
122
|
+
// - file exists but can't be parsed (TS syntax error, broken require)
|
|
123
|
+
// → the error propagates, no silent-default regression.
|
|
124
|
+
const config = await (0, config_1.tryLoadFrontMcpConfig)(cwd);
|
|
103
125
|
// If no -t flag and config has deployments, build all targets from config
|
|
104
126
|
if (!opts.buildTarget && config && config.deployments.length > 0) {
|
|
105
127
|
const targets = (0, config_1.getDeploymentTargets)(config);
|
|
@@ -128,14 +150,44 @@ async function buildSingleTarget(target, opts, config) {
|
|
|
128
150
|
// Merge entry from config if not provided via CLI
|
|
129
151
|
const entry = opts.entry || config?.entry;
|
|
130
152
|
const targetOpts = { ...opts, outDir: targetOutDir, entry };
|
|
153
|
+
// #370: forward `build.storage` and per-deployment `cli.outputDefault` from
|
|
154
|
+
// the FrontMcp config into the exec build so the manifest reflects them.
|
|
155
|
+
// The exec build has its own loader (`loadExecConfig`) that doesn't see
|
|
156
|
+
// the deployment-level shape; passing these via opts merges them in
|
|
157
|
+
// `normalizeConfig` before the manifest is generated.
|
|
158
|
+
//
|
|
159
|
+
// Only the cli deployment shape carries a `cli` block; map it down to the
|
|
160
|
+
// narrow exec-config shape (outputDefault / description / authRequired) so
|
|
161
|
+
// the result is a clean object, never `false`.
|
|
162
|
+
const cliDeploymentConfig = deployment?.target === 'cli' ? deployment.cli : undefined;
|
|
163
|
+
const execOverrides = {
|
|
164
|
+
storage: config?.build?.storage,
|
|
165
|
+
cli: cliDeploymentConfig
|
|
166
|
+
? {
|
|
167
|
+
...(cliDeploymentConfig.outputDefault ? { outputDefault: cliDeploymentConfig.outputDefault } : {}),
|
|
168
|
+
...(cliDeploymentConfig.description ? { description: cliDeploymentConfig.description } : {}),
|
|
169
|
+
...(typeof cliDeploymentConfig.authRequired === 'boolean'
|
|
170
|
+
? { authRequired: cliDeploymentConfig.authRequired }
|
|
171
|
+
: {}),
|
|
172
|
+
}
|
|
173
|
+
: undefined,
|
|
174
|
+
};
|
|
131
175
|
switch (target) {
|
|
132
176
|
case 'cli': {
|
|
133
177
|
const { buildExec } = await import('./exec/index.js');
|
|
134
|
-
return buildExec({
|
|
178
|
+
return buildExec({
|
|
179
|
+
...targetOpts,
|
|
180
|
+
cli: true,
|
|
181
|
+
sea: !opts.js,
|
|
182
|
+
execOverrides,
|
|
183
|
+
});
|
|
135
184
|
}
|
|
136
185
|
case 'node': {
|
|
137
186
|
const { buildExec } = await import('./exec/index.js');
|
|
138
|
-
return buildExec(
|
|
187
|
+
return buildExec({
|
|
188
|
+
...targetOpts,
|
|
189
|
+
execOverrides,
|
|
190
|
+
});
|
|
139
191
|
}
|
|
140
192
|
case 'sdk': {
|
|
141
193
|
const { buildSdk } = await import('./sdk/index.js');
|
|
@@ -176,6 +228,16 @@ async function runAdapterBuild(opts, adapter) {
|
|
|
176
228
|
if (adapter === 'cloudflare') {
|
|
177
229
|
console.log((0, colors_1.c)('yellow', 'Cloudflare Workers adapter is experimental. See docs for limitations.'));
|
|
178
230
|
}
|
|
231
|
+
// #375 — adapter-level pre-validation: read the entry's @FrontMcp() config
|
|
232
|
+
// metadata and let the adapter reject incompatible features
|
|
233
|
+
// (sqlite/redis on Workers, etc.) before emitting an unrunnable bundle.
|
|
234
|
+
// `loadEntryDecoratorConfig` handles both compiled-JS and raw-TS entries
|
|
235
|
+
// (TS goes through esbuild + Module._compile so we don't need a tsc pass).
|
|
236
|
+
if (template.validate) {
|
|
237
|
+
const { loadEntryDecoratorConfig } = await import('./load-entry-config.js');
|
|
238
|
+
const decoratorConfig = await loadEntryDecoratorConfig(entry);
|
|
239
|
+
template.validate(decoratorConfig);
|
|
240
|
+
}
|
|
179
241
|
const moduleFormat = template.moduleFormat;
|
|
180
242
|
console.log(`${(0, colors_1.c)('cyan', '[build]')} entry: ${path.relative(cwd, entry)}`);
|
|
181
243
|
console.log(`${(0, colors_1.c)('cyan', '[build]')} outDir: ${path.relative(cwd, outDir)}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/commands/build/index.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { type ParsedArgs } from '../../core/args';\nimport { c } from '../../core/colors';\nimport { ensureDir, fileExists, runCmd, writeJSON } from '@frontmcp/utils';\nimport { fsp, resolveEntry } from '../../shared/fs';\nimport { REQUIRED_DECORATOR_FIELDS } from '../../core/tsconfig';\nimport { ADAPTERS } from './adapters';\nimport { type AdapterName } from './types';\nimport { bundleForServerless } from './bundler';\nimport { findDeployment, type FrontMcpConfigParsed, getDeploymentTargets, loadFrontMcpConfig } from '../../config';\n\nfunction isTsLike(p: string): boolean {\n return /\\.tsx?$/i.test(p);\n}\n\n/**\n * Generate adapter-specific entry point and config files.\n */\nasync function generateAdapterFiles(\n adapter: AdapterName,\n outDir: string,\n entryBasename: string,\n cwd: string,\n): Promise<void> {\n const template = ADAPTERS[adapter];\n\n // Generate serverless setup file first (if adapter has one)\n // This file sets FRONTMCP_SERVERLESS=1 before any imports run\n if (template.getSetupTemplate) {\n const setupContent = template.getSetupTemplate();\n const setupPath = path.join(outDir, 'serverless-setup.js');\n await fsp.writeFile(setupPath, setupContent, 'utf8');\n console.log(c('green', ` Generated serverless setup at ${path.relative(cwd, setupPath)}`));\n }\n\n // Generate index.js entry point\n const mainModuleName = entryBasename.replace(/\\.tsx?$/, '.js');\n const entryContent = template.getEntryTemplate(`./${mainModuleName}`);\n\n // Skip if no entry template (e.g., node adapter)\n if (entryContent) {\n const entryPath = path.join(outDir, 'index.js');\n await fsp.writeFile(entryPath, entryContent, 'utf8');\n console.log(c('green', ` Generated ${adapter} entry at ${path.relative(cwd, entryPath)}`));\n }\n\n // Bundle if adapter requires it (creates single CJS file for serverless)\n if (template.shouldBundle && template.bundleOutput) {\n console.log(c('cyan', `[build] Bundling for ${adapter}...`));\n const entryPath = path.join(outDir, 'index.js');\n await bundleForServerless(entryPath, outDir, template.bundleOutput);\n console.log(c('green', ` Created bundle: ${template.bundleOutput}`));\n\n // Run post-bundle hook if defined (e.g., create Build Output API structure)\n if (template.postBundle) {\n console.log(c('cyan', `[build] Creating ${adapter} deployment structure...`));\n await template.postBundle(outDir, cwd, template.bundleOutput);\n console.log(c('green', ` Created deployment output structure`));\n }\n }\n\n // Generate config file if adapter has one (skip if already exists)\n if (template.getConfig && template.configFileName) {\n const configPath = path.join(cwd, template.configFileName);\n\n if (await fileExists(configPath)) {\n console.log(c('yellow', ` ${template.configFileName} already exists (skipping)`));\n } else {\n const configContent = template.getConfig(cwd);\n\n if (typeof configContent === 'string') {\n // Write as plain text (e.g., TOML for wrangler.toml)\n await fsp.writeFile(configPath, configContent, 'utf8');\n } else {\n // Write as JSON\n await writeJSON(configPath, configContent);\n }\n console.log(c('green', ` Generated ${template.configFileName}`));\n }\n }\n}\n\n/** Map target names to internal adapter names. */\nconst TARGET_TO_ADAPTER: Record<string, AdapterName> = {\n 'vercel': 'vercel',\n 'lambda': 'lambda',\n 'cloudflare': 'cloudflare',\n 'distributed': 'distributed',\n};\n\n/**\n * Build the FrontMCP server for a specific deployment target.\n *\n * @example\n * ```bash\n * frontmcp build --target node # Node.js server bundle\n * frontmcp build --target cli # CLI with SEA binary\n * frontmcp build --target cli --js # CLI without SEA\n * frontmcp build --target sdk # Library (CJS+ESM+types)\n * frontmcp build --target browser # Browser ESM bundle\n * frontmcp build --target vercel # Vercel serverless\n * frontmcp build --target lambda # AWS Lambda\n * frontmcp build --target cloudflare # Cloudflare Workers\n * ```\n */\nexport async function runBuild(opts: ParsedArgs): Promise<void> {\n const cwd = process.cwd();\n\n // Try loading frontmcp.config for multi-target support\n let config: FrontMcpConfigParsed | undefined;\n try {\n config = await loadFrontMcpConfig(cwd);\n } catch {\n // No config file — fall back to CLI flags only\n }\n\n // If no -t flag and config has deployments, build all targets from config\n if (!opts.buildTarget && config && config.deployments.length > 0) {\n const targets = getDeploymentTargets(config);\n console.log(c('cyan', `[build] Building ${targets.length} target(s) from frontmcp.config: ${targets.join(', ')}`));\n\n for (const targetName of targets) {\n console.log(c('cyan', `\\n[build] ═══ ${targetName} ═══`));\n await buildSingleTarget(targetName, opts, config);\n }\n return;\n }\n\n // Single target build (from -t flag or default 'node')\n const target = opts.buildTarget ?? 'node';\n await buildSingleTarget(target, opts, config);\n}\n\n/**\n * Build a single deployment target.\n * Merges per-target config (from frontmcp.config) with CLI opts.\n */\nasync function buildSingleTarget(\n target: string,\n opts: ParsedArgs,\n config?: FrontMcpConfigParsed,\n): Promise<void> {\n const deployment = config ? findDeployment(config, target) : undefined;\n\n // Resolve output directory: deployment.outDir > CLI --out-dir > dist/{target}\n const baseOutDir = path.resolve(process.cwd(), opts.outDir || 'dist');\n const targetOutDir = deployment?.outDir\n ? path.resolve(process.cwd(), deployment.outDir)\n : path.join(baseOutDir, target);\n\n // Merge entry from config if not provided via CLI\n const entry = opts.entry || config?.entry;\n const targetOpts = { ...opts, outDir: targetOutDir, entry };\n\n switch (target) {\n case 'cli': {\n const { buildExec } = await import('./exec/index.js');\n return buildExec({ ...targetOpts, cli: true, sea: !opts.js } as ParsedArgs & { cli: boolean; sea: boolean });\n }\n case 'node': {\n const { buildExec } = await import('./exec/index.js');\n return buildExec(targetOpts);\n }\n case 'sdk': {\n const { buildSdk } = await import('./sdk/index.js');\n return buildSdk(targetOpts);\n }\n case 'browser': {\n const { buildBrowser } = await import('./browser/index.js');\n return buildBrowser(targetOpts);\n }\n case 'mcpb': {\n const { buildMcpb } = await import('./mcpb/index.js');\n return buildMcpb(targetOpts, config);\n }\n case 'vercel':\n case 'lambda':\n case 'cloudflare':\n case 'distributed': {\n const adapter = TARGET_TO_ADAPTER[target];\n return runAdapterBuild(targetOpts, adapter);\n }\n default:\n throw new Error(`Unknown build target: ${target}. Available: cli, node, sdk, browser, cloudflare, vercel, lambda, distributed, mcpb`);\n }\n}\n\n/**\n * Build using a deployment adapter (serverless platforms).\n */\nasync function runAdapterBuild(opts: ParsedArgs, adapter: AdapterName): Promise<void> {\n const cwd = process.cwd();\n const entry = await resolveEntry(cwd, opts.entry);\n const outDir = path.resolve(cwd, opts.outDir || 'dist');\n await ensureDir(outDir);\n\n const template = ADAPTERS[adapter];\n if (!template) {\n const available = Object.keys(ADAPTERS).join(', ');\n throw new Error(`Unknown adapter: ${adapter}. Available: ${available}`);\n }\n\n if (adapter === 'cloudflare') {\n console.log(\n c('yellow', 'Cloudflare Workers adapter is experimental. See docs for limitations.'),\n );\n }\n\n const moduleFormat = template.moduleFormat;\n\n console.log(`${c('cyan', '[build]')} entry: ${path.relative(cwd, entry)}`);\n console.log(`${c('cyan', '[build]')} outDir: ${path.relative(cwd, outDir)}`);\n console.log(`${c('cyan', '[build]')} target: ${adapter} (${moduleFormat})`);\n\n const tsconfigPath = path.join(cwd, 'tsconfig.json');\n const hasTsconfig = await fileExists(tsconfigPath);\n const args: string[] = ['-y', 'tsc'];\n\n if (hasTsconfig) {\n console.log(c('gray', `[build] tsconfig.json detected — compiling with project settings`));\n args.push('--project', tsconfigPath);\n } else {\n args.push(entry);\n args.push('--rootDir', path.dirname(entry));\n if (!isTsLike(entry)) {\n args.push('--allowJs');\n console.log(c('yellow', '[build] Entry is not TypeScript; enabling --allowJs'));\n }\n args.push('--experimentalDecorators', '--emitDecoratorMetadata');\n args.push('--target', REQUIRED_DECORATOR_FIELDS.target);\n }\n\n args.push('--module', moduleFormat);\n args.push('--outDir', outDir);\n args.push('--skipLibCheck');\n\n await runCmd('npx', args);\n\n if (adapter !== 'node') {\n console.log(c('cyan', `[build] Generating ${adapter} deployment files...`));\n const entryBasename = path.basename(entry);\n await generateAdapterFiles(adapter, outDir, entryBasename, cwd);\n }\n\n console.log(c('green', 'Build completed.'));\n console.log(c('gray', `Output placed in ${path.relative(cwd, outDir)}`));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/commands/build/index.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { type ParsedArgs } from '../../core/args';\nimport { c } from '../../core/colors';\nimport { ensureDir, fileExists, runCmd, writeJSON } from '@frontmcp/utils';\nimport { fsp, resolveEntry } from '../../shared/fs';\nimport { REQUIRED_DECORATOR_FIELDS } from '../../core/tsconfig';\nimport { ADAPTERS } from './adapters';\nimport { type AdapterName } from './types';\nimport { bundleForServerless } from './bundler';\nimport {\n type DeploymentTarget,\n findDeployment,\n type FrontMcpConfigParsed,\n getDeploymentTargets,\n tryLoadFrontMcpConfig,\n} from '../../config';\n\nfunction isTsLike(p: string): boolean {\n return /\\.tsx?$/i.test(p);\n}\n\n/**\n * Generate adapter-specific entry point and config files.\n */\nasync function generateAdapterFiles(\n adapter: AdapterName,\n outDir: string,\n entryBasename: string,\n cwd: string,\n): Promise<void> {\n const template = ADAPTERS[adapter];\n\n // Generate serverless setup file first (if adapter has one)\n // This file sets FRONTMCP_SERVERLESS=1 before any imports run\n if (template.getSetupTemplate) {\n const setupContent = template.getSetupTemplate();\n const setupPath = path.join(outDir, 'serverless-setup.js');\n await fsp.writeFile(setupPath, setupContent, 'utf8');\n console.log(c('green', ` Generated serverless setup at ${path.relative(cwd, setupPath)}`));\n }\n\n // Generate index.js entry point\n const mainModuleName = entryBasename.replace(/\\.tsx?$/, '.js');\n const entryContent = template.getEntryTemplate(`./${mainModuleName}`);\n\n // Skip if no entry template (e.g., node adapter)\n if (entryContent) {\n const entryPath = path.join(outDir, 'index.js');\n await fsp.writeFile(entryPath, entryContent, 'utf8');\n console.log(c('green', ` Generated ${adapter} entry at ${path.relative(cwd, entryPath)}`));\n\n // ESM adapters (vercel, lambda) emit `import` syntax in the entry. The\n // user's project may be `\"type\": \"commonjs\"`, in which case Node and\n // rspack treat the .js file as CJS and parsing fails on `import`.\n // Drop a sibling package.json with `\"type\": \"module\"` so the dist\n // directory is always interpreted correctly regardless of the parent.\n if (template.moduleFormat === 'esnext') {\n const pkgPath = path.join(outDir, 'package.json');\n await fsp.writeFile(pkgPath, JSON.stringify({ type: 'module' }, null, 2), 'utf8');\n }\n }\n\n // Bundle if adapter requires it (creates single CJS file for serverless)\n if (template.shouldBundle && template.bundleOutput) {\n console.log(c('cyan', `[build] Bundling for ${adapter}...`));\n const entryPath = path.join(outDir, 'index.js');\n await bundleForServerless(entryPath, outDir, template.bundleOutput);\n console.log(c('green', ` Created bundle: ${template.bundleOutput}`));\n\n // Run post-bundle hook if defined (e.g., create Build Output API structure)\n if (template.postBundle) {\n console.log(c('cyan', `[build] Creating ${adapter} deployment structure...`));\n await template.postBundle(outDir, cwd, template.bundleOutput);\n console.log(c('green', ` Created deployment output structure`));\n }\n }\n\n // Generate config file if adapter has one. By default we preserve an\n // existing user-edited file. Adapters that mark `alwaysWriteConfig` (e.g.,\n // cloudflare's wrangler.toml) overwrite it on every build so the\n // generated `main = ...` path always matches the actual build output —\n // see #374.\n if (template.getConfig && template.configFileName) {\n const configPath = path.join(cwd, template.configFileName);\n const exists = await fileExists(configPath);\n\n const configContent = template.getConfig(cwd);\n const writeIt = async (): Promise<void> => {\n if (typeof configContent === 'string') {\n await fsp.writeFile(configPath, configContent, 'utf8');\n } else {\n await writeJSON(configPath, configContent);\n }\n };\n\n if (!exists) {\n await writeIt();\n console.log(c('green', ` Generated ${template.configFileName}`));\n } else if (template.alwaysWriteConfig) {\n await writeIt();\n console.log(c('green', ` Updated ${template.configFileName} (build output reference)`));\n } else {\n console.log(c('yellow', ` ${template.configFileName} already exists (skipping)`));\n }\n }\n}\n\n/** Map target names to internal adapter names. */\nconst TARGET_TO_ADAPTER: Record<string, AdapterName> = {\n 'vercel': 'vercel',\n 'lambda': 'lambda',\n 'cloudflare': 'cloudflare',\n 'distributed': 'distributed',\n};\n\n/**\n * Build the FrontMCP server for a specific deployment target.\n *\n * @example\n * ```bash\n * frontmcp build --target node # Node.js server bundle\n * frontmcp build --target cli # CLI with SEA binary\n * frontmcp build --target cli --js # CLI without SEA\n * frontmcp build --target sdk # Library (CJS+ESM+types)\n * frontmcp build --target browser # Browser ESM bundle\n * frontmcp build --target vercel # Vercel serverless\n * frontmcp build --target lambda # AWS Lambda\n * frontmcp build --target cloudflare # Cloudflare Workers\n * ```\n */\nexport async function runBuild(opts: ParsedArgs): Promise<void> {\n const cwd = process.cwd();\n\n // Try loading frontmcp.config for multi-target support.\n //\n // #365 — `tryLoadFrontMcpConfig` differentiates between recoverable cases:\n // - no config file present → returns undefined\n // - config exists but doesn't match the new schema → returns undefined\n // (legacy top-level `cli`/`sea`/`esbuild` shape — picked up later by\n // the exec-build's own `loadExecConfig`)\n // …and hard failures:\n // - file exists but can't be parsed (TS syntax error, broken require)\n // → the error propagates, no silent-default regression.\n const config: FrontMcpConfigParsed | undefined = await tryLoadFrontMcpConfig(cwd);\n\n // If no -t flag and config has deployments, build all targets from config\n if (!opts.buildTarget && config && config.deployments.length > 0) {\n const targets = getDeploymentTargets(config);\n console.log(c('cyan', `[build] Building ${targets.length} target(s) from frontmcp.config: ${targets.join(', ')}`));\n\n for (const targetName of targets) {\n console.log(c('cyan', `\\n[build] ═══ ${targetName} ═══`));\n await buildSingleTarget(targetName, opts, config);\n }\n return;\n }\n\n // Single target build (from -t flag or default 'node')\n const target = opts.buildTarget ?? 'node';\n await buildSingleTarget(target, opts, config);\n}\n\n/**\n * Build a single deployment target.\n * Merges per-target config (from frontmcp.config) with CLI opts.\n */\nasync function buildSingleTarget(\n target: string,\n opts: ParsedArgs,\n config?: FrontMcpConfigParsed,\n): Promise<void> {\n const deployment:DeploymentTarget | undefined = config ? findDeployment(config, target) : undefined;\n\n // Resolve output directory: deployment.outDir > CLI --out-dir > dist/{target}\n const baseOutDir = path.resolve(process.cwd(), opts.outDir || 'dist');\n const targetOutDir = deployment?.outDir\n ? path.resolve(process.cwd(), deployment.outDir)\n : path.join(baseOutDir, target);\n\n // Merge entry from config if not provided via CLI\n const entry = opts.entry || config?.entry;\n const targetOpts = { ...opts, outDir: targetOutDir, entry };\n\n // #370: forward `build.storage` and per-deployment `cli.outputDefault` from\n // the FrontMcp config into the exec build so the manifest reflects them.\n // The exec build has its own loader (`loadExecConfig`) that doesn't see\n // the deployment-level shape; passing these via opts merges them in\n // `normalizeConfig` before the manifest is generated.\n //\n // Only the cli deployment shape carries a `cli` block; map it down to the\n // narrow exec-config shape (outputDefault / description / authRequired) so\n // the result is a clean object, never `false`.\n const cliDeploymentConfig = deployment?.target === 'cli' ? deployment.cli : undefined;\n const execOverrides: {\n storage?: { type: 'sqlite' | 'redis' | 'none'; required?: boolean };\n cli?: { outputDefault?: 'text' | 'json'; description?: string; authRequired?: boolean };\n } = {\n storage: config?.build?.storage,\n cli: cliDeploymentConfig\n ? {\n ...(cliDeploymentConfig.outputDefault ? { outputDefault: cliDeploymentConfig.outputDefault } : {}),\n ...(cliDeploymentConfig.description ? { description: cliDeploymentConfig.description } : {}),\n ...(typeof cliDeploymentConfig.authRequired === 'boolean'\n ? { authRequired: cliDeploymentConfig.authRequired }\n : {}),\n }\n : undefined,\n };\n\n switch (target) {\n case 'cli': {\n const { buildExec } = await import('./exec/index.js');\n return buildExec({\n ...targetOpts,\n cli: true,\n sea: !opts.js,\n execOverrides,\n } as ParsedArgs & { cli: boolean; sea: boolean; execOverrides?: typeof execOverrides });\n }\n case 'node': {\n const { buildExec } = await import('./exec/index.js');\n return buildExec({\n ...targetOpts,\n execOverrides,\n } as ParsedArgs & { execOverrides?: typeof execOverrides });\n }\n case 'sdk': {\n const { buildSdk } = await import('./sdk/index.js');\n return buildSdk(targetOpts);\n }\n case 'browser': {\n const { buildBrowser } = await import('./browser/index.js');\n return buildBrowser(targetOpts);\n }\n case 'mcpb': {\n const { buildMcpb } = await import('./mcpb/index.js');\n return buildMcpb(targetOpts, config);\n }\n case 'vercel':\n case 'lambda':\n case 'cloudflare':\n case 'distributed': {\n const adapter = TARGET_TO_ADAPTER[target];\n return runAdapterBuild(targetOpts, adapter);\n }\n default:\n throw new Error(`Unknown build target: ${target}. Available: cli, node, sdk, browser, cloudflare, vercel, lambda, distributed, mcpb`);\n }\n}\n\n/**\n * Build using a deployment adapter (serverless platforms).\n */\nasync function runAdapterBuild(opts: ParsedArgs, adapter: AdapterName): Promise<void> {\n const cwd = process.cwd();\n const entry = await resolveEntry(cwd, opts.entry);\n const outDir = path.resolve(cwd, opts.outDir || 'dist');\n await ensureDir(outDir);\n\n const template = ADAPTERS[adapter];\n if (!template) {\n const available = Object.keys(ADAPTERS).join(', ');\n throw new Error(`Unknown adapter: ${adapter}. Available: ${available}`);\n }\n\n if (adapter === 'cloudflare') {\n console.log(\n c('yellow', 'Cloudflare Workers adapter is experimental. See docs for limitations.'),\n );\n }\n\n // #375 — adapter-level pre-validation: read the entry's @FrontMcp() config\n // metadata and let the adapter reject incompatible features\n // (sqlite/redis on Workers, etc.) before emitting an unrunnable bundle.\n // `loadEntryDecoratorConfig` handles both compiled-JS and raw-TS entries\n // (TS goes through esbuild + Module._compile so we don't need a tsc pass).\n if (template.validate) {\n const { loadEntryDecoratorConfig } = await import('./load-entry-config.js');\n const decoratorConfig = await loadEntryDecoratorConfig(entry);\n template.validate(decoratorConfig);\n }\n\n const moduleFormat = template.moduleFormat;\n\n console.log(`${c('cyan', '[build]')} entry: ${path.relative(cwd, entry)}`);\n console.log(`${c('cyan', '[build]')} outDir: ${path.relative(cwd, outDir)}`);\n console.log(`${c('cyan', '[build]')} target: ${adapter} (${moduleFormat})`);\n\n const tsconfigPath = path.join(cwd, 'tsconfig.json');\n const hasTsconfig = await fileExists(tsconfigPath);\n const args: string[] = ['-y', 'tsc'];\n\n if (hasTsconfig) {\n console.log(c('gray', `[build] tsconfig.json detected — compiling with project settings`));\n args.push('--project', tsconfigPath);\n } else {\n args.push(entry);\n args.push('--rootDir', path.dirname(entry));\n if (!isTsLike(entry)) {\n args.push('--allowJs');\n console.log(c('yellow', '[build] Entry is not TypeScript; enabling --allowJs'));\n }\n args.push('--experimentalDecorators', '--emitDecoratorMetadata');\n args.push('--target', REQUIRED_DECORATOR_FIELDS.target);\n }\n\n args.push('--module', moduleFormat);\n args.push('--outDir', outDir);\n args.push('--skipLibCheck');\n\n await runCmd('npx', args);\n\n if (adapter !== 'node') {\n console.log(c('cyan', `[build] Generating ${adapter} deployment files...`));\n const entryBasename = path.basename(entry);\n await generateAdapterFiles(adapter, outDir, entryBasename, cwd);\n }\n\n console.log(c('green', 'Build completed.'));\n console.log(c('gray', `Output placed in ${path.relative(cwd, outDir)}`));\n}\n"]}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadEntryDecoratorConfig = loadEntryDecoratorConfig;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
/**
|
|
6
|
+
* Best-effort load of a user's `@FrontMcp()`-decorated entry to read its
|
|
7
|
+
* decorator config at build time.
|
|
8
|
+
*
|
|
9
|
+
* Why it exists: `runAdapterBuild` and the adapter `validate` hook need
|
|
10
|
+
* `@FrontMcp({ http, sqlite, redis })` *before* TypeScript compilation runs,
|
|
11
|
+
* but the entry itself is usually `./src/main.ts` — `require()` can't load it
|
|
12
|
+
* without a TS hook. Falling back to esbuild + `Module._compile` lets us
|
|
13
|
+
* read the metadata regardless of whether the entry is `.ts` or `.js`.
|
|
14
|
+
*
|
|
15
|
+
* Returns `undefined` when the entry can't be loaded or doesn't carry a
|
|
16
|
+
* decorator config (plain config object, missing decorator, etc.). Callers
|
|
17
|
+
* should treat that as "no metadata available" and not as a build failure.
|
|
18
|
+
*/
|
|
19
|
+
const fs = tslib_1.__importStar(require("fs"));
|
|
20
|
+
const path = tslib_1.__importStar(require("path"));
|
|
21
|
+
const FRONTMCP_CONFIG_METADATA_KEY = '__frontmcp:config';
|
|
22
|
+
function readDecoratorMetadata(target) {
|
|
23
|
+
if (typeof target !== 'function') {
|
|
24
|
+
if (target && typeof target === 'object') {
|
|
25
|
+
// Plain config object — return as-is so the validate() can inspect
|
|
26
|
+
// top-level fields like `sqlite`, `redis`, `http` directly.
|
|
27
|
+
return target;
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
const reflect = globalThis.Reflect;
|
|
32
|
+
if (!reflect?.getMetadata)
|
|
33
|
+
return undefined;
|
|
34
|
+
const config = reflect.getMetadata(FRONTMCP_CONFIG_METADATA_KEY, target);
|
|
35
|
+
return (config ?? undefined);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Load the entry, extract its `@FrontMcp` decorator config, and return it.
|
|
39
|
+
* Falls back to esbuild for TS entries.
|
|
40
|
+
*/
|
|
41
|
+
async function loadEntryDecoratorConfig(entry) {
|
|
42
|
+
const prev = process.env['FRONTMCP_SCHEMA_EXTRACT'];
|
|
43
|
+
process.env['FRONTMCP_SCHEMA_EXTRACT'] = '1';
|
|
44
|
+
try {
|
|
45
|
+
// Path 1: plain require() — works for compiled JS entries.
|
|
46
|
+
try {
|
|
47
|
+
const mod = require(entry);
|
|
48
|
+
const target = mod.default ?? mod;
|
|
49
|
+
const config = readDecoratorMetadata(target);
|
|
50
|
+
if (config)
|
|
51
|
+
return config;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// require failed (e.g., .ts entry without a hook); fall through to esbuild.
|
|
55
|
+
}
|
|
56
|
+
// Path 2: esbuild transpile + Module._compile, only if the entry is .ts/.tsx.
|
|
57
|
+
if (/\.tsx?$/i.test(entry)) {
|
|
58
|
+
try {
|
|
59
|
+
return await loadTsEntryViaEsbuild(entry);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// Anything throws (esbuild parse error, runtime error in the entry, etc.) —
|
|
63
|
+
// return undefined so the caller's validate() falls back to a no-op
|
|
64
|
+
// and the regular tsc compile produces the real error message.
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
if (prev === undefined)
|
|
70
|
+
delete process.env['FRONTMCP_SCHEMA_EXTRACT'];
|
|
71
|
+
else
|
|
72
|
+
process.env['FRONTMCP_SCHEMA_EXTRACT'] = prev;
|
|
73
|
+
}
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
async function loadTsEntryViaEsbuild(entryPath) {
|
|
77
|
+
const esbuild = require('esbuild');
|
|
78
|
+
const source = fs.readFileSync(entryPath, 'utf-8');
|
|
79
|
+
const transformed = esbuild.transformSync(source, {
|
|
80
|
+
loader: 'ts',
|
|
81
|
+
format: 'cjs',
|
|
82
|
+
target: 'es2022',
|
|
83
|
+
sourcefile: entryPath,
|
|
84
|
+
});
|
|
85
|
+
const Module = require('module');
|
|
86
|
+
const m = new Module(entryPath, module);
|
|
87
|
+
m.filename = entryPath;
|
|
88
|
+
// Resolve user `import { ... } from '@frontmcp/sdk'` against the user's
|
|
89
|
+
// node_modules, not the CLI's. Same trick as the config loader.
|
|
90
|
+
m.paths = Module._nodeModulePaths(path.dirname(entryPath));
|
|
91
|
+
m._compile(transformed.code, entryPath);
|
|
92
|
+
const exported = m.exports;
|
|
93
|
+
const target = exported.default ?? exported;
|
|
94
|
+
return readDecoratorMetadata(target);
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=load-entry-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-entry-config.js","sourceRoot":"","sources":["../../../../src/commands/build/load-entry-config.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Best-effort load of a user's `@FrontMcp()`-decorated entry to read its\n * decorator config at build time.\n *\n * Why it exists: `runAdapterBuild` and the adapter `validate` hook need\n * `@FrontMcp({ http, sqlite, redis })` *before* TypeScript compilation runs,\n * but the entry itself is usually `./src/main.ts` — `require()` can't load it\n * without a TS hook. Falling back to esbuild + `Module._compile` lets us\n * read the metadata regardless of whether the entry is `.ts` or `.js`.\n *\n * Returns `undefined` when the entry can't be loaded or doesn't carry a\n * decorator config (plain config object, missing decorator, etc.). Callers\n * should treat that as \"no metadata available\" and not as a build failure.\n */\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nconst FRONTMCP_CONFIG_METADATA_KEY = '__frontmcp:config';\n\ninterface ReflectLike {\n getMetadata?: (key: string, target: unknown) => unknown;\n}\n\nfunction readDecoratorMetadata(target: unknown): Record<string, unknown> | undefined {\n if (typeof target !== 'function') {\n if (target && typeof target === 'object') {\n // Plain config object — return as-is so the validate() can inspect\n // top-level fields like `sqlite`, `redis`, `http` directly.\n return target as Record<string, unknown>;\n }\n return undefined;\n }\n const reflect = (globalThis as { Reflect?: ReflectLike }).Reflect;\n if (!reflect?.getMetadata) return undefined;\n const config = reflect.getMetadata(FRONTMCP_CONFIG_METADATA_KEY, target);\n return (config ?? undefined) as Record<string, unknown> | undefined;\n}\n\n/**\n * Load the entry, extract its `@FrontMcp` decorator config, and return it.\n * Falls back to esbuild for TS entries.\n */\nexport async function loadEntryDecoratorConfig(entry: string): Promise<Record<string, unknown> | undefined> {\n const prev = process.env['FRONTMCP_SCHEMA_EXTRACT'];\n process.env['FRONTMCP_SCHEMA_EXTRACT'] = '1';\n try {\n // Path 1: plain require() — works for compiled JS entries.\n try {\n const mod = require(entry) as { default?: unknown } & Record<string, unknown>;\n const target = mod.default ?? mod;\n const config = readDecoratorMetadata(target);\n if (config) return config;\n } catch {\n // require failed (e.g., .ts entry without a hook); fall through to esbuild.\n }\n\n // Path 2: esbuild transpile + Module._compile, only if the entry is .ts/.tsx.\n if (/\\.tsx?$/i.test(entry)) {\n try {\n return await loadTsEntryViaEsbuild(entry);\n } catch {\n // Anything throws (esbuild parse error, runtime error in the entry, etc.) —\n // return undefined so the caller's validate() falls back to a no-op\n // and the regular tsc compile produces the real error message.\n }\n }\n } finally {\n if (prev === undefined) delete process.env['FRONTMCP_SCHEMA_EXTRACT'];\n else process.env['FRONTMCP_SCHEMA_EXTRACT'] = prev;\n }\n return undefined;\n}\n\nasync function loadTsEntryViaEsbuild(entryPath: string): Promise<Record<string, unknown> | undefined> {\n const esbuild = require('esbuild') as typeof import('esbuild');\n const source = fs.readFileSync(entryPath, 'utf-8');\n const transformed = esbuild.transformSync(source, {\n loader: 'ts',\n format: 'cjs',\n target: 'es2022',\n sourcefile: entryPath,\n });\n\n const Module = require('module') as typeof import('module');\n const m = new Module(entryPath, module);\n m.filename = entryPath;\n // Resolve user `import { ... } from '@frontmcp/sdk'` against the user's\n // node_modules, not the CLI's. Same trick as the config loader.\n m.paths = (Module as unknown as { _nodeModulePaths(p: string): string[] })._nodeModulePaths(\n path.dirname(entryPath),\n );\n \n (m as any)._compile(transformed.code, entryPath);\n \n const exported = (m as any).exports as { default?: unknown } & Record<string, unknown>;\n const target = exported.default ?? exported;\n return readDecoratorMetadata(target);\n}\n"]}
|
|
@@ -45,6 +45,13 @@ export interface McpbManifest {
|
|
|
45
45
|
description: string;
|
|
46
46
|
}>;
|
|
47
47
|
tools_generated?: boolean;
|
|
48
|
+
resources?: Array<{
|
|
49
|
+
name?: string;
|
|
50
|
+
uri: string;
|
|
51
|
+
description?: string;
|
|
52
|
+
mimeType?: string;
|
|
53
|
+
}>;
|
|
54
|
+
resources_generated?: boolean;
|
|
48
55
|
prompts?: Array<{
|
|
49
56
|
name: string;
|
|
50
57
|
description?: string;
|
|
@@ -103,6 +110,13 @@ export declare const mcpbManifestSchema: import("@frontmcp/lazy-zod").ZodObject<
|
|
|
103
110
|
description: import("@frontmcp/lazy-zod").ZodString;
|
|
104
111
|
}, import("zod/v4/core").$strict>>>;
|
|
105
112
|
tools_generated: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodBoolean>;
|
|
113
|
+
resources: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodArray<import("@frontmcp/lazy-zod").ZodObject<{
|
|
114
|
+
name: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodString>;
|
|
115
|
+
uri: import("@frontmcp/lazy-zod").ZodString;
|
|
116
|
+
description: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodString>;
|
|
117
|
+
mimeType: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodString>;
|
|
118
|
+
}, import("zod/v4/core").$strict>>>;
|
|
119
|
+
resources_generated: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodBoolean>;
|
|
106
120
|
prompts: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodArray<import("@frontmcp/lazy-zod").ZodObject<{
|
|
107
121
|
name: import("@frontmcp/lazy-zod").ZodString;
|
|
108
122
|
description: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodString>;
|
|
@@ -93,6 +93,17 @@ exports.mcpbManifestSchema = lazy_zod_1.z
|
|
|
93
93
|
.array(lazy_zod_1.z.object({ name: lazy_zod_1.z.string(), description: lazy_zod_1.z.string() }).strict())
|
|
94
94
|
.optional(),
|
|
95
95
|
tools_generated: lazy_zod_1.z.boolean().optional(),
|
|
96
|
+
resources: lazy_zod_1.z
|
|
97
|
+
.array(lazy_zod_1.z
|
|
98
|
+
.object({
|
|
99
|
+
name: lazy_zod_1.z.string().optional(),
|
|
100
|
+
uri: lazy_zod_1.z.string(),
|
|
101
|
+
description: lazy_zod_1.z.string().optional(),
|
|
102
|
+
mimeType: lazy_zod_1.z.string().optional(),
|
|
103
|
+
})
|
|
104
|
+
.strict())
|
|
105
|
+
.optional(),
|
|
106
|
+
resources_generated: lazy_zod_1.z.boolean().optional(),
|
|
96
107
|
prompts: lazy_zod_1.z
|
|
97
108
|
.array(lazy_zod_1.z
|
|
98
109
|
.object({ name: lazy_zod_1.z.string(), description: lazy_zod_1.z.string().optional() })
|
|
@@ -196,6 +207,15 @@ function generateMcpbManifest(input) {
|
|
|
196
207
|
const tools = schema.tools
|
|
197
208
|
.filter((t) => !schema_extractor_1.SYSTEM_TOOL_NAMES.has(t.name))
|
|
198
209
|
.map((t) => ({ name: t.name, description: t.description || '' }));
|
|
210
|
+
// #376 — emit resources alongside tools/prompts. The server runtime
|
|
211
|
+
// already registers @Resource entries, but the manifest writer was
|
|
212
|
+
// dropping them, so MCPB-aware clients had no way to discover them.
|
|
213
|
+
const resources = schema.resources.map((r) => ({
|
|
214
|
+
...(r.name ? { name: r.name } : {}),
|
|
215
|
+
uri: r.uri,
|
|
216
|
+
...(r.description ? { description: r.description } : {}),
|
|
217
|
+
...(r.mimeType ? { mimeType: r.mimeType } : {}),
|
|
218
|
+
}));
|
|
199
219
|
const prompts = schema.prompts.map((p) => ({
|
|
200
220
|
name: p.name,
|
|
201
221
|
...(p.description ? { description: p.description } : {}),
|
|
@@ -236,6 +256,15 @@ function generateMcpbManifest(input) {
|
|
|
236
256
|
},
|
|
237
257
|
tools,
|
|
238
258
|
tools_generated: false,
|
|
259
|
+
...(resources.length > 0
|
|
260
|
+
? {
|
|
261
|
+
resources,
|
|
262
|
+
// FrontMCP resources resolve dynamically (their bodies come from
|
|
263
|
+
// execute()/read()), so consumers should still query the server at
|
|
264
|
+
// runtime — but the static manifest now exposes name/uri/mimeType.
|
|
265
|
+
resources_generated: true,
|
|
266
|
+
}
|
|
267
|
+
: {}),
|
|
239
268
|
prompts,
|
|
240
269
|
// FrontMCP prompts resolve dynamically via execute() — MCPB's static `text`
|
|
241
270
|
// template cannot represent JS logic. Set generated:true so consumers query
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../../../src/commands/build/mcpb/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MCPB manifest generator + Zod schema for the emitted manifest.\n *\n * Source priority when resolving fields:\n * deployment.* (frontmcp.config) > package.json > hard defaults\n *\n * See https://github.com/modelcontextprotocol/mcpb/blob/main/MANIFEST.md\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { z } from '@frontmcp/lazy-zod';\nimport { type ExtractedSchema, SYSTEM_TOOL_NAMES } from '../exec/cli-runtime/schema-extractor';\nimport type {\n McpbAuthor,\n McpbCompatibility,\n McpbDeployment,\n McpbRepository,\n McpbUserConfigEntry,\n} from '../../../config/frontmcp-config.types';\nimport {\n DEFAULT_NODE_COMPAT,\n DEFAULT_PLATFORMS,\n MCPB_MANIFEST_VERSION,\n} from './constants';\n\n// ============================================\n// Emitted manifest shape (MCPB v0.3 subset we produce)\n// ============================================\n\nexport interface McpbMcpConfig {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n platform_overrides?: Record<string, McpbMcpConfig>;\n}\n\nexport interface McpbManifest {\n manifest_version: string;\n name: string;\n version: string;\n description: string;\n display_name?: string;\n long_description?: string;\n author: McpbAuthor;\n license?: string;\n homepage?: string;\n repository?: { type: string; url: string };\n documentation?: string;\n support?: string;\n icon?: string;\n keywords?: string[];\n privacy_policies?: string[];\n compatibility?: McpbCompatibility;\n server: {\n type: 'node' | 'python' | 'binary' | 'uv';\n entry_point: string;\n mcp_config: McpbMcpConfig;\n };\n tools?: Array<{ name: string; description: string }>;\n tools_generated?: boolean;\n prompts?: Array<{ name: string; description?: string }>;\n prompts_generated?: boolean;\n user_config?: Record<string, McpbUserConfigEntry>;\n _meta?: Record<string, unknown>;\n}\n\n// ============================================\n// Zod schema (used by validate.ts)\n// ============================================\n\nconst authorSchema = z\n .object({\n name: z.string(),\n email: z.string().optional(),\n url: z.string().optional(),\n })\n .strict();\n\nconst userConfigEntrySchema = z\n .object({\n type: z.enum(['string', 'number', 'boolean', 'directory', 'file']),\n title: z.string(),\n description: z.string().optional(),\n required: z.boolean().optional(),\n default: z.union([z.string(), z.number(), z.boolean()]).optional(),\n multiple: z.boolean().optional(),\n sensitive: z.boolean().optional(),\n min: z.number().optional(),\n max: z.number().optional(),\n })\n .strict();\n\nconst mcpConfigSchema: z.ZodType<McpbMcpConfig> = z.lazy(() =>\n z\n .object({\n command: z.string(),\n args: z.array(z.string()).optional(),\n env: z.record(z.string(), z.string()).optional(),\n platform_overrides: z.record(z.string(), mcpConfigSchema).optional(),\n })\n .strict(),\n);\n\nexport const mcpbManifestSchema = z\n .object({\n manifest_version: z.string(),\n name: z.string().min(1),\n version: z.string().min(1),\n description: z.string(),\n display_name: z.string().optional(),\n long_description: z.string().optional(),\n author: authorSchema,\n license: z.string().optional(),\n homepage: z.string().optional(),\n repository: z\n .object({ type: z.string(), url: z.string() })\n .strict()\n .optional(),\n documentation: z.string().optional(),\n support: z.string().optional(),\n icon: z.string().optional(),\n keywords: z.array(z.string()).optional(),\n privacy_policies: z.array(z.string()).optional(),\n compatibility: z\n .object({\n claude_desktop: z.string().optional(),\n platforms: z.array(z.enum(['darwin', 'win32', 'linux'])).optional(),\n runtimes: z\n .object({ node: z.string().optional(), python: z.string().optional() })\n .strict()\n .optional(),\n })\n .strict()\n .optional(),\n server: z\n .object({\n type: z.enum(['node', 'python', 'binary', 'uv']),\n entry_point: z.string(),\n mcp_config: mcpConfigSchema,\n })\n .strict(),\n tools: z\n .array(z.object({ name: z.string(), description: z.string() }).strict())\n .optional(),\n tools_generated: z.boolean().optional(),\n prompts: z\n .array(\n z\n .object({ name: z.string(), description: z.string().optional() })\n .strict(),\n )\n .optional(),\n prompts_generated: z.boolean().optional(),\n user_config: z.record(z.string(), userConfigEntrySchema).optional(),\n _meta: z.record(z.string(), z.unknown()).optional(),\n })\n .strict();\n\n// ============================================\n// Sources + helpers\n// ============================================\n\nexport interface PackageJsonMeta {\n name?: string;\n version?: string;\n description?: string;\n author?: string | McpbAuthor;\n license?: string;\n homepage?: string;\n repository?: string | { type?: string; url?: string };\n keywords?: string[];\n icon?: string;\n}\n\n/** Read and parse package.json from the given directory. Returns {} if absent. */\nexport function loadPackageJsonMeta(cwd: string): PackageJsonMeta {\n const pkgPath = path.join(cwd, 'package.json');\n if (!fs.existsSync(pkgPath)) return {};\n try {\n return JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as PackageJsonMeta;\n } catch {\n return {};\n }\n}\n\n/**\n * Parse npm-style \"Name <email> (url)\" into an McpbAuthor.\n * Falls back to `{ name: <raw> }` when parsing fails.\n */\nexport function parseAuthor(author: unknown): McpbAuthor {\n if (!author) return { name: 'unknown' };\n if (typeof author === 'object' && 'name' in author) {\n const a = author as McpbAuthor;\n return {\n name: a.name,\n ...(a.email ? { email: a.email } : {}),\n ...(a.url ? { url: a.url } : {}),\n };\n }\n if (typeof author !== 'string') {\n return { name: String(author) };\n }\n const match = author.match(/^([^<(]+?)(?:\\s*<([^>]+)>)?(?:\\s*\\(([^)]+)\\))?$/);\n if (!match || !match[1]) return { name: author };\n const [, name, email, url] = match;\n return {\n name: name.trim(),\n ...(email ? { email: email.trim() } : {}),\n ...(url ? { url: url.trim() } : {}),\n };\n}\n\n/** Normalize repository field (string → {type, url}). */\nexport function normalizeRepository(\n repo: McpbRepository | PackageJsonMeta['repository'] | undefined,\n): { type: string; url: string } | undefined {\n if (!repo) return undefined;\n if (typeof repo === 'string') {\n return { type: 'git', url: repo };\n }\n if (typeof repo === 'object' && repo.url) {\n return { type: repo.type || 'git', url: repo.url };\n }\n return undefined;\n}\n\n/** Resolve first-existing icon path. */\nexport function resolveIconPath(cwd: string, deploymentIcon?: string, pkgIcon?: string): string | undefined {\n const candidates = [deploymentIcon, pkgIcon, 'icon.png', 'assets/icon.png'].filter(\n (x): x is string => !!x,\n );\n for (const rel of candidates) {\n if (fs.existsSync(path.resolve(cwd, rel))) {\n return rel;\n }\n }\n return undefined;\n}\n\n// ============================================\n// Generator input + output\n// ============================================\n\nexport interface GenerateMcpbManifestInput {\n /** Resolved server name. */\n name: string;\n /** Resolved server version. */\n version: string;\n /** Optional resolved node version range (e.g., \">=22.0.0\"). */\n nodeVersion?: string;\n /** Project root. Used for icon resolution and package.json fallback. */\n cwd: string;\n /** Deployment config from frontmcp.config (may be undefined). */\n deployment?: McpbDeployment;\n /** Schema extracted from the compiled server bundle. */\n schema: ExtractedSchema;\n /** env → user_config reference map built by user-config.ts. */\n userConfigEnv: Record<string, string>;\n /** user_config entries built by user-config.ts. */\n userConfig: Record<string, McpbUserConfigEntry>;\n /** platform_overrides from binary.ts (may be empty). */\n platformOverrides?: Record<string, McpbMcpConfig>;\n /** Whether an icon was copied into the staged archive root. */\n hasIcon?: boolean;\n /** Tool name of the CLI version emitting this manifest (for _meta). */\n cliVersion?: string;\n}\n\n/** Produce the final MCPB manifest object. */\nexport function generateMcpbManifest(input: GenerateMcpbManifestInput): McpbManifest {\n const {\n name,\n version,\n cwd,\n deployment,\n schema,\n userConfig,\n userConfigEnv,\n platformOverrides,\n hasIcon,\n cliVersion,\n } = input;\n\n const pkg = loadPackageJsonMeta(cwd);\n\n const description = deployment?.longDescription?.split('\\n')[0]?.trim()\n || pkg.description\n || '';\n\n const author = deployment?.author || parseAuthor(pkg.author);\n const license = deployment?.license ?? pkg.license;\n const homepage = deployment?.homepage ?? pkg.homepage;\n const repository = normalizeRepository(deployment?.repository ?? pkg.repository);\n const keywords = deployment?.keywords ?? pkg.keywords;\n const icon = hasIcon ? 'icon.png' : undefined;\n\n const nodeVersion = deployment?.compatibility?.runtimes?.node\n ?? input.nodeVersion\n ?? DEFAULT_NODE_COMPAT;\n\n const compatibility: McpbCompatibility = {\n ...(deployment?.compatibility?.claude_desktop\n ? { claude_desktop: deployment.compatibility.claude_desktop }\n : {}),\n platforms: deployment?.compatibility?.platforms ?? [...DEFAULT_PLATFORMS],\n runtimes: {\n ...(deployment?.compatibility?.runtimes?.python\n ? { python: deployment.compatibility.runtimes.python }\n : {}),\n node: nodeVersion,\n },\n };\n\n const tools = schema.tools\n .filter((t) => !SYSTEM_TOOL_NAMES.has(t.name))\n .map((t) => ({ name: t.name, description: t.description || '' }));\n\n const prompts = schema.prompts.map((p) => ({\n name: p.name,\n ...(p.description ? { description: p.description } : {}),\n }));\n\n const mcpConfig: McpbMcpConfig = {\n command: 'node',\n args: ['${__dirname}/server/index.js'],\n ...(Object.keys(userConfigEnv).length > 0 ? { env: userConfigEnv } : {}),\n ...(platformOverrides && Object.keys(platformOverrides).length > 0\n ? { platform_overrides: platformOverrides }\n : {}),\n };\n\n const manifest: McpbManifest = {\n manifest_version: MCPB_MANIFEST_VERSION,\n name,\n version,\n description,\n ...(deployment?.displayName ? { display_name: deployment.displayName } : {}),\n ...(deployment?.longDescription\n ? { long_description: deployment.longDescription }\n : {}),\n author,\n ...(license ? { license } : {}),\n ...(homepage ? { homepage } : {}),\n ...(repository ? { repository } : {}),\n ...(deployment?.documentation ? { documentation: deployment.documentation } : {}),\n ...(deployment?.support ? { support: deployment.support } : {}),\n ...(icon ? { icon } : {}),\n ...(keywords && keywords.length > 0 ? { keywords } : {}),\n ...(deployment?.privacyPolicies && deployment.privacyPolicies.length > 0\n ? { privacy_policies: deployment.privacyPolicies }\n : {}),\n compatibility,\n server: {\n type: 'node',\n entry_point: 'server/index.js',\n mcp_config: mcpConfig,\n },\n tools,\n tools_generated: false,\n prompts,\n // FrontMCP prompts resolve dynamically via execute() — MCPB's static `text`\n // template cannot represent JS logic. Set generated:true so consumers query\n // the server at runtime while still getting name/description hints here.\n prompts_generated: true,\n ...(Object.keys(userConfig).length > 0 ? { user_config: userConfig } : {}),\n _meta: {\n 'dev.frontmcp.generator': cliVersion ? `frontmcp@${cliVersion}` : 'frontmcp',\n 'dev.frontmcp.capabilities': schema.capabilities,\n },\n };\n\n return manifest;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../../../src/commands/build/mcpb/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MCPB manifest generator + Zod schema for the emitted manifest.\n *\n * Source priority when resolving fields:\n * deployment.* (frontmcp.config) > package.json > hard defaults\n *\n * See https://github.com/modelcontextprotocol/mcpb/blob/main/MANIFEST.md\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { z } from '@frontmcp/lazy-zod';\nimport { type ExtractedSchema, SYSTEM_TOOL_NAMES } from '../exec/cli-runtime/schema-extractor';\nimport type {\n McpbAuthor,\n McpbCompatibility,\n McpbDeployment,\n McpbRepository,\n McpbUserConfigEntry,\n} from '../../../config/frontmcp-config.types';\nimport {\n DEFAULT_NODE_COMPAT,\n DEFAULT_PLATFORMS,\n MCPB_MANIFEST_VERSION,\n} from './constants';\n\n// ============================================\n// Emitted manifest shape (MCPB v0.3 subset we produce)\n// ============================================\n\nexport interface McpbMcpConfig {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n platform_overrides?: Record<string, McpbMcpConfig>;\n}\n\nexport interface McpbManifest {\n manifest_version: string;\n name: string;\n version: string;\n description: string;\n display_name?: string;\n long_description?: string;\n author: McpbAuthor;\n license?: string;\n homepage?: string;\n repository?: { type: string; url: string };\n documentation?: string;\n support?: string;\n icon?: string;\n keywords?: string[];\n privacy_policies?: string[];\n compatibility?: McpbCompatibility;\n server: {\n type: 'node' | 'python' | 'binary' | 'uv';\n entry_point: string;\n mcp_config: McpbMcpConfig;\n };\n tools?: Array<{ name: string; description: string }>;\n tools_generated?: boolean;\n resources?: Array<{ name?: string; uri: string; description?: string; mimeType?: string }>;\n resources_generated?: boolean;\n prompts?: Array<{ name: string; description?: string }>;\n prompts_generated?: boolean;\n user_config?: Record<string, McpbUserConfigEntry>;\n _meta?: Record<string, unknown>;\n}\n\n// ============================================\n// Zod schema (used by validate.ts)\n// ============================================\n\nconst authorSchema = z\n .object({\n name: z.string(),\n email: z.string().optional(),\n url: z.string().optional(),\n })\n .strict();\n\nconst userConfigEntrySchema = z\n .object({\n type: z.enum(['string', 'number', 'boolean', 'directory', 'file']),\n title: z.string(),\n description: z.string().optional(),\n required: z.boolean().optional(),\n default: z.union([z.string(), z.number(), z.boolean()]).optional(),\n multiple: z.boolean().optional(),\n sensitive: z.boolean().optional(),\n min: z.number().optional(),\n max: z.number().optional(),\n })\n .strict();\n\nconst mcpConfigSchema: z.ZodType<McpbMcpConfig> = z.lazy(() =>\n z\n .object({\n command: z.string(),\n args: z.array(z.string()).optional(),\n env: z.record(z.string(), z.string()).optional(),\n platform_overrides: z.record(z.string(), mcpConfigSchema).optional(),\n })\n .strict(),\n);\n\nexport const mcpbManifestSchema = z\n .object({\n manifest_version: z.string(),\n name: z.string().min(1),\n version: z.string().min(1),\n description: z.string(),\n display_name: z.string().optional(),\n long_description: z.string().optional(),\n author: authorSchema,\n license: z.string().optional(),\n homepage: z.string().optional(),\n repository: z\n .object({ type: z.string(), url: z.string() })\n .strict()\n .optional(),\n documentation: z.string().optional(),\n support: z.string().optional(),\n icon: z.string().optional(),\n keywords: z.array(z.string()).optional(),\n privacy_policies: z.array(z.string()).optional(),\n compatibility: z\n .object({\n claude_desktop: z.string().optional(),\n platforms: z.array(z.enum(['darwin', 'win32', 'linux'])).optional(),\n runtimes: z\n .object({ node: z.string().optional(), python: z.string().optional() })\n .strict()\n .optional(),\n })\n .strict()\n .optional(),\n server: z\n .object({\n type: z.enum(['node', 'python', 'binary', 'uv']),\n entry_point: z.string(),\n mcp_config: mcpConfigSchema,\n })\n .strict(),\n tools: z\n .array(z.object({ name: z.string(), description: z.string() }).strict())\n .optional(),\n tools_generated: z.boolean().optional(),\n resources: z\n .array(\n z\n .object({\n name: z.string().optional(),\n uri: z.string(),\n description: z.string().optional(),\n mimeType: z.string().optional(),\n })\n .strict(),\n )\n .optional(),\n resources_generated: z.boolean().optional(),\n prompts: z\n .array(\n z\n .object({ name: z.string(), description: z.string().optional() })\n .strict(),\n )\n .optional(),\n prompts_generated: z.boolean().optional(),\n user_config: z.record(z.string(), userConfigEntrySchema).optional(),\n _meta: z.record(z.string(), z.unknown()).optional(),\n })\n .strict();\n\n// ============================================\n// Sources + helpers\n// ============================================\n\nexport interface PackageJsonMeta {\n name?: string;\n version?: string;\n description?: string;\n author?: string | McpbAuthor;\n license?: string;\n homepage?: string;\n repository?: string | { type?: string; url?: string };\n keywords?: string[];\n icon?: string;\n}\n\n/** Read and parse package.json from the given directory. Returns {} if absent. */\nexport function loadPackageJsonMeta(cwd: string): PackageJsonMeta {\n const pkgPath = path.join(cwd, 'package.json');\n if (!fs.existsSync(pkgPath)) return {};\n try {\n return JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as PackageJsonMeta;\n } catch {\n return {};\n }\n}\n\n/**\n * Parse npm-style \"Name <email> (url)\" into an McpbAuthor.\n * Falls back to `{ name: <raw> }` when parsing fails.\n */\nexport function parseAuthor(author: unknown): McpbAuthor {\n if (!author) return { name: 'unknown' };\n if (typeof author === 'object' && 'name' in author) {\n const a = author as McpbAuthor;\n return {\n name: a.name,\n ...(a.email ? { email: a.email } : {}),\n ...(a.url ? { url: a.url } : {}),\n };\n }\n if (typeof author !== 'string') {\n return { name: String(author) };\n }\n const match = author.match(/^([^<(]+?)(?:\\s*<([^>]+)>)?(?:\\s*\\(([^)]+)\\))?$/);\n if (!match || !match[1]) return { name: author };\n const [, name, email, url] = match;\n return {\n name: name.trim(),\n ...(email ? { email: email.trim() } : {}),\n ...(url ? { url: url.trim() } : {}),\n };\n}\n\n/** Normalize repository field (string → {type, url}). */\nexport function normalizeRepository(\n repo: McpbRepository | PackageJsonMeta['repository'] | undefined,\n): { type: string; url: string } | undefined {\n if (!repo) return undefined;\n if (typeof repo === 'string') {\n return { type: 'git', url: repo };\n }\n if (typeof repo === 'object' && repo.url) {\n return { type: repo.type || 'git', url: repo.url };\n }\n return undefined;\n}\n\n/** Resolve first-existing icon path. */\nexport function resolveIconPath(cwd: string, deploymentIcon?: string, pkgIcon?: string): string | undefined {\n const candidates = [deploymentIcon, pkgIcon, 'icon.png', 'assets/icon.png'].filter(\n (x): x is string => !!x,\n );\n for (const rel of candidates) {\n if (fs.existsSync(path.resolve(cwd, rel))) {\n return rel;\n }\n }\n return undefined;\n}\n\n// ============================================\n// Generator input + output\n// ============================================\n\nexport interface GenerateMcpbManifestInput {\n /** Resolved server name. */\n name: string;\n /** Resolved server version. */\n version: string;\n /** Optional resolved node version range (e.g., \">=22.0.0\"). */\n nodeVersion?: string;\n /** Project root. Used for icon resolution and package.json fallback. */\n cwd: string;\n /** Deployment config from frontmcp.config (may be undefined). */\n deployment?: McpbDeployment;\n /** Schema extracted from the compiled server bundle. */\n schema: ExtractedSchema;\n /** env → user_config reference map built by user-config.ts. */\n userConfigEnv: Record<string, string>;\n /** user_config entries built by user-config.ts. */\n userConfig: Record<string, McpbUserConfigEntry>;\n /** platform_overrides from binary.ts (may be empty). */\n platformOverrides?: Record<string, McpbMcpConfig>;\n /** Whether an icon was copied into the staged archive root. */\n hasIcon?: boolean;\n /** Tool name of the CLI version emitting this manifest (for _meta). */\n cliVersion?: string;\n}\n\n/** Produce the final MCPB manifest object. */\nexport function generateMcpbManifest(input: GenerateMcpbManifestInput): McpbManifest {\n const {\n name,\n version,\n cwd,\n deployment,\n schema,\n userConfig,\n userConfigEnv,\n platformOverrides,\n hasIcon,\n cliVersion,\n } = input;\n\n const pkg = loadPackageJsonMeta(cwd);\n\n const description = deployment?.longDescription?.split('\\n')[0]?.trim()\n || pkg.description\n || '';\n\n const author = deployment?.author || parseAuthor(pkg.author);\n const license = deployment?.license ?? pkg.license;\n const homepage = deployment?.homepage ?? pkg.homepage;\n const repository = normalizeRepository(deployment?.repository ?? pkg.repository);\n const keywords = deployment?.keywords ?? pkg.keywords;\n const icon = hasIcon ? 'icon.png' : undefined;\n\n const nodeVersion = deployment?.compatibility?.runtimes?.node\n ?? input.nodeVersion\n ?? DEFAULT_NODE_COMPAT;\n\n const compatibility: McpbCompatibility = {\n ...(deployment?.compatibility?.claude_desktop\n ? { claude_desktop: deployment.compatibility.claude_desktop }\n : {}),\n platforms: deployment?.compatibility?.platforms ?? [...DEFAULT_PLATFORMS],\n runtimes: {\n ...(deployment?.compatibility?.runtimes?.python\n ? { python: deployment.compatibility.runtimes.python }\n : {}),\n node: nodeVersion,\n },\n };\n\n const tools = schema.tools\n .filter((t) => !SYSTEM_TOOL_NAMES.has(t.name))\n .map((t) => ({ name: t.name, description: t.description || '' }));\n\n // #376 — emit resources alongside tools/prompts. The server runtime\n // already registers @Resource entries, but the manifest writer was\n // dropping them, so MCPB-aware clients had no way to discover them.\n const resources = schema.resources.map((r) => ({\n ...(r.name ? { name: r.name } : {}),\n uri: r.uri,\n ...(r.description ? { description: r.description } : {}),\n ...(r.mimeType ? { mimeType: r.mimeType } : {}),\n }));\n\n const prompts = schema.prompts.map((p) => ({\n name: p.name,\n ...(p.description ? { description: p.description } : {}),\n }));\n\n const mcpConfig: McpbMcpConfig = {\n command: 'node',\n args: ['${__dirname}/server/index.js'],\n ...(Object.keys(userConfigEnv).length > 0 ? { env: userConfigEnv } : {}),\n ...(platformOverrides && Object.keys(platformOverrides).length > 0\n ? { platform_overrides: platformOverrides }\n : {}),\n };\n\n const manifest: McpbManifest = {\n manifest_version: MCPB_MANIFEST_VERSION,\n name,\n version,\n description,\n ...(deployment?.displayName ? { display_name: deployment.displayName } : {}),\n ...(deployment?.longDescription\n ? { long_description: deployment.longDescription }\n : {}),\n author,\n ...(license ? { license } : {}),\n ...(homepage ? { homepage } : {}),\n ...(repository ? { repository } : {}),\n ...(deployment?.documentation ? { documentation: deployment.documentation } : {}),\n ...(deployment?.support ? { support: deployment.support } : {}),\n ...(icon ? { icon } : {}),\n ...(keywords && keywords.length > 0 ? { keywords } : {}),\n ...(deployment?.privacyPolicies && deployment.privacyPolicies.length > 0\n ? { privacy_policies: deployment.privacyPolicies }\n : {}),\n compatibility,\n server: {\n type: 'node',\n entry_point: 'server/index.js',\n mcp_config: mcpConfig,\n },\n tools,\n tools_generated: false,\n ...(resources.length > 0\n ? {\n resources,\n // FrontMCP resources resolve dynamically (their bodies come from\n // execute()/read()), so consumers should still query the server at\n // runtime — but the static manifest now exposes name/uri/mimeType.\n resources_generated: true,\n }\n : {}),\n prompts,\n // FrontMCP prompts resolve dynamically via execute() — MCPB's static `text`\n // template cannot represent JS logic. Set generated:true so consumers query\n // the server at runtime while still getting name/description hints here.\n prompts_generated: true,\n ...(Object.keys(userConfig).length > 0 ? { user_config: userConfig } : {}),\n _meta: {\n 'dev.frontmcp.generator': cliVersion ? `frontmcp@${cliVersion}` : 'frontmcp',\n 'dev.frontmcp.capabilities': schema.capabilities,\n },\n };\n\n return manifest;\n}\n"]}
|
|
@@ -44,5 +44,24 @@ export type AdapterTemplate = {
|
|
|
44
44
|
* @param bundleOutput - Name of the bundled file (e.g., 'handler.cjs')
|
|
45
45
|
*/
|
|
46
46
|
postBundle?: (outDir: string, cwd: string, bundleOutput: string) => Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Pre-build validation hook. Runs after schema/decorator extraction but
|
|
49
|
+
* before TypeScript compilation. Allows the adapter to fail loudly when
|
|
50
|
+
* the user's config references runtime features that won't work on the
|
|
51
|
+
* target platform (e.g., sqlite on Cloudflare Workers).
|
|
52
|
+
*
|
|
53
|
+
* @param decoratorConfig - Best-effort `__frontmcp:config` metadata
|
|
54
|
+
* extracted from the entry's @FrontMcp() decorator. May be undefined
|
|
55
|
+
* when the entry exports a plain config object.
|
|
56
|
+
* @throws to abort the build with a user-facing message.
|
|
57
|
+
*/
|
|
58
|
+
validate?: (decoratorConfig: Record<string, unknown> | undefined) => void;
|
|
59
|
+
/**
|
|
60
|
+
* Whether `getConfig()` output should overwrite an existing config file
|
|
61
|
+
* (e.g., wrangler.toml) on every build. When false, an existing file is
|
|
62
|
+
* left untouched but its contents are diffed against the build output and
|
|
63
|
+
* the build fails on mismatch (#374). Default: false (preserve existing).
|
|
64
|
+
*/
|
|
65
|
+
alwaysWriteConfig?: boolean;
|
|
47
66
|
};
|
|
48
67
|
export type AdapterName = 'node' | 'vercel' | 'lambda' | 'cloudflare' | 'distributed';
|