frontmcp 0.6.2 → 0.7.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 +2 -1
- package/src/args.d.ts +1 -0
- package/src/args.js +2 -0
- package/src/args.js.map +1 -1
- package/src/cli.js +1 -0
- package/src/cli.js.map +1 -1
- package/src/commands/build/adapters/vercel.js +43 -10
- package/src/commands/build/adapters/vercel.js.map +1 -1
- package/src/commands/build/bundler.js +13 -1
- package/src/commands/build/bundler.js.map +1 -1
- package/src/commands/build/index.js +6 -5
- package/src/commands/build/index.js.map +1 -1
- package/src/commands/create.js +25 -14
- package/src/commands/create.js.map +1 -1
- package/src/commands/doctor.js +5 -5
- package/src/commands/doctor.js.map +1 -1
- package/src/commands/inspector.js +2 -2
- package/src/commands/inspector.js.map +1 -1
- package/src/commands/template.js +6 -6
- package/src/commands/template.js.map +1 -1
- package/src/commands/test.js +19 -3
- package/src/commands/test.js.map +1 -1
- package/src/tsconfig.js +4 -4
- package/src/tsconfig.js.map +1 -1
- package/src/utils/fs.d.ts +4 -8
- package/src/utils/fs.js +14 -57
- package/src/utils/fs.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frontmcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "FrontMCP command line interface",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"homepage": "https://docs.agentfront.dev",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"frontmcp": "./src/cli.js"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
+
"@frontmcp/utils": "0.7.1",
|
|
29
30
|
"tslib": "^2.3.0",
|
|
30
31
|
"@rspack/core": "^1.3.12"
|
|
31
32
|
},
|
package/src/args.d.ts
CHANGED
package/src/args.js
CHANGED
|
@@ -23,6 +23,8 @@ function parseArgs(argv) {
|
|
|
23
23
|
const parsed = parseInt(argv[++i], 10);
|
|
24
24
|
out.timeout = Number.isNaN(parsed) ? undefined : parsed;
|
|
25
25
|
}
|
|
26
|
+
else if (a === '--coverage' || a === '-c')
|
|
27
|
+
out.coverage = true;
|
|
26
28
|
// Create command flags
|
|
27
29
|
else if (a === '--yes' || a === '-y')
|
|
28
30
|
out.yes = true;
|
package/src/args.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/args.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/args.ts"],"names":[],"mappings":";;AAiCA,8BAwBC;AAxBD,SAAgB,SAAS,CAAC,IAAc;IACtC,MAAM,GAAG,GAAe,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACvD,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACzD,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,CAAsB,CAAC;aAClF,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;aAClD,IAAI,CAAC,KAAK,aAAa,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC;aAC5D,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC;aACpD,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;aACxD,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACvC,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;QAC1D,CAAC;aAAM,IAAI,CAAC,KAAK,YAAY,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC;QACjE,uBAAuB;aAClB,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC;aAChD,IAAI,CAAC,KAAK,UAAU;YAAE,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAsB,CAAC;aAClE,IAAI,CAAC,KAAK,SAAS;YAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAqB,CAAC;aAC/D,IAAI,CAAC,KAAK,QAAQ;YAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;aACpC,IAAI,CAAC,KAAK,WAAW;YAAE,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC;;YACxC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["export type Command =\n | 'dev'\n | 'build'\n | 'init'\n | 'doctor'\n | 'inspector'\n | 'create'\n | 'help'\n | 'template'\n | 'version'\n | 'test';\n\nexport type DeploymentAdapter = 'node' | 'vercel' | 'lambda' | 'cloudflare';\nexport type RedisSetupOption = 'docker' | 'existing' | 'none';\n\nexport interface ParsedArgs {\n _: string[];\n outDir?: string;\n entry?: string;\n help?: boolean;\n runInBand?: boolean;\n watch?: boolean;\n verbose?: boolean;\n timeout?: number;\n coverage?: boolean;\n adapter?: DeploymentAdapter;\n // Create command flags\n yes?: boolean;\n target?: DeploymentAdapter;\n redis?: RedisSetupOption;\n cicd?: boolean;\n}\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const out: ParsedArgs = { _: [] };\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === '--out-dir' || a === '-o') out.outDir = argv[++i];\n else if (a === '--entry' || a === '-e') out.entry = argv[++i];\n else if (a === '--adapter' || a === '-a') out.adapter = argv[++i] as DeploymentAdapter;\n else if (a === '--help' || a === '-h') out.help = true;\n else if (a === '--runInBand' || a === '-i') out.runInBand = true;\n else if (a === '--watch' || a === '-w') out.watch = true;\n else if (a === '--verbose' || a === '-v') out.verbose = true;\n else if (a === '--timeout' || a === '-t') {\n const parsed = parseInt(argv[++i], 10);\n out.timeout = Number.isNaN(parsed) ? undefined : parsed;\n } else if (a === '--coverage' || a === '-c') out.coverage = true;\n // Create command flags\n else if (a === '--yes' || a === '-y') out.yes = true;\n else if (a === '--target') out.target = argv[++i] as DeploymentAdapter;\n else if (a === '--redis') out.redis = argv[++i] as RedisSetupOption;\n else if (a === '--cicd') out.cicd = true;\n else if (a === '--no-cicd') out.cicd = false;\n else out._.push(a);\n }\n return out;\n}\n"]}
|
package/src/cli.js
CHANGED
|
@@ -48,6 +48,7 @@ ${(0, colors_1.c)('bold', 'Test Options')}
|
|
|
48
48
|
-w, --watch Run tests in watch mode
|
|
49
49
|
-v, --verbose Show verbose test output
|
|
50
50
|
-t, --timeout <ms> Set test timeout (default: 60000ms)
|
|
51
|
+
-c, --coverage Collect test coverage
|
|
51
52
|
|
|
52
53
|
${(0, colors_1.c)('bold', 'Examples')}
|
|
53
54
|
frontmcp dev
|
package/src/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":";;AACA;;GAEG;;AAEH,qCAA6B;AAC7B,iCAAwD;AACxD,wCAAwC;AACxC,4CAA4C;AAC5C,yCAAqC;AACrC,8CAA8C;AAC9C,oDAAoD;AACpD,8CAA8C;AAC9C,kDAAkD;AAClD,0CAA0C;AAE1C,SAAS,QAAQ;IACf,OAAO,CAAC,GAAG,CAAC;EACZ,IAAA,UAAC,EAAC,MAAM,EAAE,UAAU,CAAC;;EAErB,IAAA,UAAC,EAAC,MAAM,EAAE,OAAO,CAAC;;;EAGlB,IAAA,UAAC,EAAC,MAAM,EAAE,UAAU,CAAC;;;;;;;;;;;EAWrB,IAAA,UAAC,EAAC,MAAM,EAAE,SAAS,CAAC;;;;EAIpB,IAAA,UAAC,EAAC,MAAM,EAAE,gBAAgB,CAAC;;;;;;;EAO3B,IAAA,UAAC,EAAC,MAAM,EAAE,cAAc,CAAC
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/**\n * frontmcp - FrontMCP command line interface\n */\n\nimport { c } from './colors';\nimport { Command, ParsedArgs, parseArgs } from './args';\nimport { runDev } from './commands/dev';\nimport { runBuild } from './commands/build';\nimport { runInit } from './tsconfig';\nimport { runDoctor } from './commands/doctor';\nimport { runInspector } from './commands/inspector';\nimport { runCreate } from './commands/create';\nimport { runTemplate } from './commands/template';\nimport { runTest } from './commands/test';\n\nfunction showHelp(): void {\n console.log(`\n${c('bold', 'frontmcp')} — FrontMCP command line interface\n\n${c('bold', 'Usage')}\n frontmcp <command> [options]\n\n${c('bold', 'Commands')}\n dev Start in development mode (tsx --watch <entry> + async type-check)\n build Compile entry with TypeScript (tsc)\n test Run E2E tests with auto-injected Jest configuration\n init Create or fix a tsconfig.json suitable for FrontMCP\n doctor Check Node/npm versions and tsconfig requirements\n inspector Launch MCP Inspector (npx @modelcontextprotocol/inspector)\n create [name] Scaffold a new FrontMCP project (interactive if name omitted)\n template <type> Scaffold a template by type (e.g., \"3rd-party-integration\")\n help Show this help message\n\n${c('bold', 'Options')}\n -o, --out-dir <dir> Output directory (default: ./dist)\n -e, --entry <path> Manually specify entry file path\n\n${c('bold', 'Create Options')}\n -y, --yes Use defaults (non-interactive mode)\n --target <target> Deployment target: node, vercel, lambda, cloudflare\n --redis <setup> Redis setup: docker, existing, none (node target only)\n --cicd Enable GitHub Actions CI/CD\n --no-cicd Disable GitHub Actions CI/CD\n\n${c('bold', 'Test Options')}\n -i, --runInBand Run tests sequentially (recommended for E2E)\n -w, --watch Run tests in watch mode\n -v, --verbose Show verbose test output\n -t, --timeout <ms> Set test timeout (default: 60000ms)\n -c, --coverage Collect test coverage\n\n${c('bold', 'Examples')}\n frontmcp dev\n frontmcp build --out-dir build\n frontmcp test --runInBand\n frontmcp init\n frontmcp doctor\n frontmcp inspector\n npx frontmcp create # Interactive mode\n npx frontmcp create my-mcp --yes # Use defaults\n npx frontmcp create my-mcp --target vercel # Vercel deployment\n npx frontmcp template marketplace-3rd-tools\n`);\n}\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n const parsed: ParsedArgs = parseArgs(argv);\n const cmd = parsed._[0] as Command | undefined;\n\n if (parsed.help || !cmd) {\n showHelp();\n process.exit(0);\n }\n\n try {\n switch (cmd) {\n case 'dev':\n await runDev(parsed);\n break;\n case 'build':\n parsed.outDir = parsed.outDir || 'dist';\n await runBuild(parsed);\n break;\n case 'init':\n await runInit();\n break;\n case 'doctor':\n await runDoctor();\n break;\n case 'inspector':\n await runInspector();\n break;\n case 'create': {\n const projectName = parsed._[1];\n await runCreate(projectName, {\n yes: parsed.yes,\n target: parsed.target,\n redis: parsed.redis,\n cicd: parsed.cicd,\n });\n break;\n }\n case 'template': {\n const type = parsed._[1]; // e.g. \"3rd-party-integration\"\n await runTemplate(type);\n break;\n }\n case 'test':\n await runTest(parsed);\n break;\n case 'help':\n showHelp();\n break;\n default:\n console.error(c('red', `Unknown command: ${cmd}`));\n showHelp();\n process.exitCode = 1;\n }\n } catch (err: unknown) {\n console.error('\\n' + c('red', err instanceof Error ? err.stack || err.message : String(err)));\n process.exit(1);\n }\n}\n\nmain();\n"]}
|
|
@@ -3,8 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.vercelAdapter = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const path = tslib_1.__importStar(require("path"));
|
|
6
|
-
const fs = tslib_1.__importStar(require("fs/promises"));
|
|
7
6
|
const fs_1 = require("fs");
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const utils_1 = require("@frontmcp/utils");
|
|
8
9
|
const PACKAGE_MANAGERS = {
|
|
9
10
|
bun: { install: 'bun install', run: 'bun run build' },
|
|
10
11
|
pnpm: { install: 'pnpm install', run: 'pnpm run build' },
|
|
@@ -92,27 +93,59 @@ export default async function handler(req, res) {
|
|
|
92
93
|
* └── functions/
|
|
93
94
|
* └── index.func/
|
|
94
95
|
* ├── .vc-config.json (Node.js 22 runtime config)
|
|
95
|
-
*
|
|
96
|
+
* ├── handler.cjs (bundled handler + chunks)
|
|
97
|
+
* └── node_modules/ (runtime dependencies that can't be bundled)
|
|
96
98
|
*/
|
|
97
99
|
postBundle: async (outDir, cwd, bundleOutput) => {
|
|
98
100
|
const outputDir = path.join(cwd, '.vercel', 'output');
|
|
99
101
|
const funcDir = path.join(outputDir, 'functions', 'index.func');
|
|
100
102
|
// Create directories
|
|
101
|
-
await
|
|
103
|
+
await (0, utils_1.mkdir)(funcDir, { recursive: true });
|
|
102
104
|
// Copy all files from dist to the function directory
|
|
103
105
|
// This includes handler.cjs and any chunk files (*.handler.cjs)
|
|
104
|
-
const distFiles = await
|
|
106
|
+
const distFiles = await (0, utils_1.readdir)(outDir);
|
|
105
107
|
for (const file of distFiles) {
|
|
106
108
|
const srcPath = path.join(outDir, file);
|
|
107
109
|
const destPath = path.join(funcDir, file);
|
|
108
|
-
const
|
|
109
|
-
if (
|
|
110
|
+
const fileStat = await (0, utils_1.stat)(srcPath);
|
|
111
|
+
if (fileStat.isDirectory()) {
|
|
110
112
|
// Recursively copy directories
|
|
111
|
-
await
|
|
113
|
+
await (0, utils_1.cp)(srcPath, destPath, { recursive: true });
|
|
112
114
|
}
|
|
113
115
|
else {
|
|
114
116
|
// Copy files
|
|
115
|
-
await
|
|
117
|
+
await (0, utils_1.copyFile)(srcPath, destPath);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Install runtime dependencies that can't be statically bundled (dynamic requires)
|
|
121
|
+
// These are packages loaded via require() inside functions that rspack can't analyze
|
|
122
|
+
// We install them fresh to ensure correct platform binaries (linux-x64 for Vercel)
|
|
123
|
+
const runtimeDeps = ['@vercel/kv', 'esbuild', '@swc/core'];
|
|
124
|
+
// Read package.json to get the exact versions
|
|
125
|
+
const pkgJsonPath = path.join(cwd, 'package.json');
|
|
126
|
+
const pkgJson = JSON.parse(await (0, utils_1.readFile)(pkgJsonPath, 'utf-8'));
|
|
127
|
+
const allDeps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };
|
|
128
|
+
// Build list of deps with versions
|
|
129
|
+
const depsToInstall = [];
|
|
130
|
+
for (const dep of runtimeDeps) {
|
|
131
|
+
const version = allDeps[dep];
|
|
132
|
+
if (version) {
|
|
133
|
+
depsToInstall.push(`${dep}@${version}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (depsToInstall.length > 0) {
|
|
137
|
+
// Create package.json in function directory
|
|
138
|
+
const funcPkgJson = { name: 'index.func', private: true, dependencies: {} };
|
|
139
|
+
await (0, utils_1.writeFile)(path.join(funcDir, 'package.json'), JSON.stringify(funcPkgJson, null, 2));
|
|
140
|
+
// Install dependencies using npm (works on all platforms)
|
|
141
|
+
try {
|
|
142
|
+
(0, child_process_1.execSync)(`npm install ${depsToInstall.join(' ')} --omit=dev`, {
|
|
143
|
+
cwd: funcDir,
|
|
144
|
+
stdio: 'pipe',
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// Silently continue if install fails - the dep might not be needed
|
|
116
149
|
}
|
|
117
150
|
}
|
|
118
151
|
// Create function config (.vc-config.json)
|
|
@@ -121,13 +154,13 @@ export default async function handler(req, res) {
|
|
|
121
154
|
handler: bundleOutput,
|
|
122
155
|
launcherType: 'Nodejs',
|
|
123
156
|
};
|
|
124
|
-
await
|
|
157
|
+
await (0, utils_1.writeFile)(path.join(funcDir, '.vc-config.json'), JSON.stringify(vcConfig, null, 2));
|
|
125
158
|
// Create output config (config.json) with routing
|
|
126
159
|
const outputConfig = {
|
|
127
160
|
version: 3,
|
|
128
161
|
routes: [{ src: '/(.*)', dest: '/index' }],
|
|
129
162
|
};
|
|
130
|
-
await
|
|
163
|
+
await (0, utils_1.writeFile)(path.join(outputDir, 'config.json'), JSON.stringify(outputConfig, null, 2));
|
|
131
164
|
},
|
|
132
165
|
};
|
|
133
166
|
//# sourceMappingURL=vercel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vercel.js","sourceRoot":"","sources":["../../../../../src/commands/build/adapters/vercel.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport * as fs from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { AdapterTemplate } from '../types';\n\ntype PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun';\n\ninterface PackageManagerConfig {\n install: string;\n run: string;\n}\n\nconst PACKAGE_MANAGERS: Record<PackageManager, PackageManagerConfig> = {\n bun: { install: 'bun install', run: 'bun run build' },\n pnpm: { install: 'pnpm install', run: 'pnpm run build' },\n yarn: { install: 'yarn install', run: 'yarn build' },\n npm: { install: 'npm install', run: 'npm run build' },\n};\n\nconst LOCKFILE_TO_PM: Record<string, PackageManager> = {\n 'bun.lockb': 'bun',\n 'pnpm-lock.yaml': 'pnpm',\n 'yarn.lock': 'yarn',\n 'package-lock.json': 'npm',\n};\n\n/**\n * Detect package manager based on lockfile presence.\n * Priority: bun > pnpm > yarn > npm (fastest to slowest install times)\n */\nfunction detectPackageManager(cwd: string): PackageManager {\n for (const [lockfile, pm] of Object.entries(LOCKFILE_TO_PM)) {\n if (existsSync(path.join(cwd, lockfile))) {\n return pm;\n }\n }\n return 'npm'; // Default fallback\n}\n\n/**\n * Vercel adapter - serverless deployment on Vercel.\n * Compiles to ESM, bundles with rspack to CJS for maximum compatibility.\n *\n * Uses Vercel Build Output API for deployment:\n * - Creates .vercel/output/config.json with routing\n * - Creates .vercel/output/functions/index.func/ with handler\n *\n * The build process:\n * 1. TypeScript compiles to ESM in dist/\n * 2. serverless-setup.js is generated (sets FRONTMCP_SERVERLESS=1)\n * 3. index.js imports setup first, then main module\n * 4. rspack bundles everything into handler.cjs\n * 5. Build Output API structure is created in .vercel/output/\n *\n * @see https://vercel.com/docs/build-output-api/v3\n */\nexport const vercelAdapter: AdapterTemplate = {\n moduleFormat: 'esnext',\n shouldBundle: true,\n bundleOutput: 'handler.cjs',\n\n getSetupTemplate: () => `// Serverless environment setup - MUST be imported first\n// This sets FRONTMCP_SERVERLESS before any decorators run\n// Required because ESM hoists imports before other statements\nprocess.env.FRONTMCP_SERVERLESS = '1';\n`,\n\n getEntryTemplate: (mainModulePath: string) => `// Auto-generated Vercel entry point\n// Generated by: frontmcp build --adapter vercel\nimport './serverless-setup.js';\nimport '${mainModulePath}';\nimport { getServerlessHandlerAsync } from '@frontmcp/sdk';\n\nlet handlerPromise = null;\n\nexport default async function handler(req, res) {\n if (!handlerPromise) {\n handlerPromise = getServerlessHandlerAsync();\n }\n const app = await handlerPromise;\n return app(req, res);\n}\n`,\n\n // Detect package manager and generate appropriate vercel.json\n getConfig: (cwd: string) => {\n const pm = detectPackageManager(cwd);\n const config = PACKAGE_MANAGERS[pm];\n return {\n version: 2,\n buildCommand: config.run,\n installCommand: config.install,\n };\n },\n\n configFileName: 'vercel.json',\n\n /**\n * Create Vercel Build Output API structure after bundling.\n * This allows Vercel to deploy the function without needing an /api folder.\n *\n * Structure created:\n * .vercel/output/\n * ├── config.json (routes all requests to index function)\n * └── functions/\n * └── index.func/\n * ├── .vc-config.json (Node.js 22 runtime config)\n * └── handler.cjs (bundled handler + chunks)\n */\n postBundle: async (outDir: string, cwd: string, bundleOutput: string) => {\n const outputDir = path.join(cwd, '.vercel', 'output');\n const funcDir = path.join(outputDir, 'functions', 'index.func');\n\n // Create directories\n await fs.mkdir(funcDir, { recursive: true });\n\n // Copy all files from dist to the function directory\n // This includes handler.cjs and any chunk files (*.handler.cjs)\n const distFiles = await fs.readdir(outDir);\n for (const file of distFiles) {\n const srcPath = path.join(outDir, file);\n const destPath = path.join(funcDir, file);\n const stat = await fs.stat(srcPath);\n\n if (stat.isDirectory()) {\n // Recursively copy directories\n await fs.cp(srcPath, destPath, { recursive: true });\n } else {\n // Copy files\n await fs.copyFile(srcPath, destPath);\n }\n }\n\n // Create function config (.vc-config.json)\n const vcConfig = {\n runtime: 'nodejs22.x',\n handler: bundleOutput,\n launcherType: 'Nodejs',\n };\n await fs.writeFile(\n path.join(funcDir, '.vc-config.json'),\n JSON.stringify(vcConfig, null, 2),\n );\n\n // Create output config (config.json) with routing\n const outputConfig = {\n version: 3,\n routes: [{ src: '/(.*)', dest: '/index' }],\n };\n await fs.writeFile(\n path.join(outputDir, 'config.json'),\n JSON.stringify(outputConfig, null, 2),\n );\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"vercel.js","sourceRoot":"","sources":["../../../../../src/commands/build/adapters/vercel.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { existsSync } from 'fs';\nimport { execSync } from 'child_process';\nimport { mkdir, readdir, stat, cp, copyFile, readFile, writeFile } from '@frontmcp/utils';\nimport { AdapterTemplate } from '../types';\n\ntype PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun';\n\ninterface PackageManagerConfig {\n install: string;\n run: string;\n}\n\nconst PACKAGE_MANAGERS: Record<PackageManager, PackageManagerConfig> = {\n bun: { install: 'bun install', run: 'bun run build' },\n pnpm: { install: 'pnpm install', run: 'pnpm run build' },\n yarn: { install: 'yarn install', run: 'yarn build' },\n npm: { install: 'npm install', run: 'npm run build' },\n};\n\nconst LOCKFILE_TO_PM: Record<string, PackageManager> = {\n 'bun.lockb': 'bun',\n 'pnpm-lock.yaml': 'pnpm',\n 'yarn.lock': 'yarn',\n 'package-lock.json': 'npm',\n};\n\n/**\n * Detect package manager based on lockfile presence.\n * Priority: bun > pnpm > yarn > npm (fastest to slowest install times)\n */\nfunction detectPackageManager(cwd: string): PackageManager {\n for (const [lockfile, pm] of Object.entries(LOCKFILE_TO_PM)) {\n if (existsSync(path.join(cwd, lockfile))) {\n return pm;\n }\n }\n return 'npm'; // Default fallback\n}\n\n/**\n * Vercel adapter - serverless deployment on Vercel.\n * Compiles to ESM, bundles with rspack to CJS for maximum compatibility.\n *\n * Uses Vercel Build Output API for deployment:\n * - Creates .vercel/output/config.json with routing\n * - Creates .vercel/output/functions/index.func/ with handler\n *\n * The build process:\n * 1. TypeScript compiles to ESM in dist/\n * 2. serverless-setup.js is generated (sets FRONTMCP_SERVERLESS=1)\n * 3. index.js imports setup first, then main module\n * 4. rspack bundles everything into handler.cjs\n * 5. Build Output API structure is created in .vercel/output/\n *\n * @see https://vercel.com/docs/build-output-api/v3\n */\nexport const vercelAdapter: AdapterTemplate = {\n moduleFormat: 'esnext',\n shouldBundle: true,\n bundleOutput: 'handler.cjs',\n\n getSetupTemplate: () => `// Serverless environment setup - MUST be imported first\n// This sets FRONTMCP_SERVERLESS before any decorators run\n// Required because ESM hoists imports before other statements\nprocess.env.FRONTMCP_SERVERLESS = '1';\n`,\n\n getEntryTemplate: (mainModulePath: string) => `// Auto-generated Vercel entry point\n// Generated by: frontmcp build --adapter vercel\nimport './serverless-setup.js';\nimport '${mainModulePath}';\nimport { getServerlessHandlerAsync } from '@frontmcp/sdk';\n\nlet handlerPromise = null;\n\nexport default async function handler(req, res) {\n if (!handlerPromise) {\n handlerPromise = getServerlessHandlerAsync();\n }\n const app = await handlerPromise;\n return app(req, res);\n}\n`,\n\n // Detect package manager and generate appropriate vercel.json\n getConfig: (cwd: string) => {\n const pm = detectPackageManager(cwd);\n const config = PACKAGE_MANAGERS[pm];\n return {\n version: 2,\n buildCommand: config.run,\n installCommand: config.install,\n };\n },\n\n configFileName: 'vercel.json',\n\n /**\n * Create Vercel Build Output API structure after bundling.\n * This allows Vercel to deploy the function without needing an /api folder.\n *\n * Structure created:\n * .vercel/output/\n * ├── config.json (routes all requests to index function)\n * └── functions/\n * └── index.func/\n * ├── .vc-config.json (Node.js 22 runtime config)\n * ├── handler.cjs (bundled handler + chunks)\n * └── node_modules/ (runtime dependencies that can't be bundled)\n */\n postBundle: async (outDir: string, cwd: string, bundleOutput: string) => {\n const outputDir = path.join(cwd, '.vercel', 'output');\n const funcDir = path.join(outputDir, 'functions', 'index.func');\n\n // Create directories\n await mkdir(funcDir, { recursive: true });\n\n // Copy all files from dist to the function directory\n // This includes handler.cjs and any chunk files (*.handler.cjs)\n const distFiles = await readdir(outDir);\n for (const file of distFiles) {\n const srcPath = path.join(outDir, file);\n const destPath = path.join(funcDir, file);\n const fileStat = await stat(srcPath);\n\n if (fileStat.isDirectory()) {\n // Recursively copy directories\n await cp(srcPath, destPath, { recursive: true });\n } else {\n // Copy files\n await copyFile(srcPath, destPath);\n }\n }\n\n // Install runtime dependencies that can't be statically bundled (dynamic requires)\n // These are packages loaded via require() inside functions that rspack can't analyze\n // We install them fresh to ensure correct platform binaries (linux-x64 for Vercel)\n const runtimeDeps = ['@vercel/kv', 'esbuild', '@swc/core'];\n\n // Read package.json to get the exact versions\n const pkgJsonPath = path.join(cwd, 'package.json');\n const pkgJson = JSON.parse(await readFile(pkgJsonPath, 'utf-8'));\n const allDeps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };\n\n // Build list of deps with versions\n const depsToInstall: string[] = [];\n for (const dep of runtimeDeps) {\n const version = allDeps[dep];\n if (version) {\n depsToInstall.push(`${dep}@${version}`);\n }\n }\n\n if (depsToInstall.length > 0) {\n // Create package.json in function directory\n const funcPkgJson = { name: 'index.func', private: true, dependencies: {} };\n await writeFile(path.join(funcDir, 'package.json'), JSON.stringify(funcPkgJson, null, 2));\n\n // Install dependencies using npm (works on all platforms)\n try {\n execSync(`npm install ${depsToInstall.join(' ')} --omit=dev`, {\n cwd: funcDir,\n stdio: 'pipe',\n });\n } catch {\n // Silently continue if install fails - the dep might not be needed\n }\n }\n\n // Create function config (.vc-config.json)\n const vcConfig = {\n runtime: 'nodejs22.x',\n handler: bundleOutput,\n launcherType: 'Nodejs',\n };\n await writeFile(\n path.join(funcDir, '.vc-config.json'),\n JSON.stringify(vcConfig, null, 2),\n );\n\n // Create output config (config.json) with routing\n const outputConfig = {\n version: 3,\n routes: [{ src: '/(.*)', dest: '/index' }],\n };\n await writeFile(\n path.join(outputDir, 'config.json'),\n JSON.stringify(outputConfig, null, 2),\n );\n },\n};\n"]}
|
|
@@ -24,7 +24,7 @@ async function bundleForServerless(entryPath, outDir, outputFilename) {
|
|
|
24
24
|
},
|
|
25
25
|
// Use node externals preset for built-in modules
|
|
26
26
|
externalsPresets: { node: true },
|
|
27
|
-
// Exclude problematic optional dependencies
|
|
27
|
+
// Exclude problematic optional dependencies (native binaries that can't be bundled)
|
|
28
28
|
externals: {
|
|
29
29
|
'@swc/core': '@swc/core',
|
|
30
30
|
fsevents: 'fsevents',
|
|
@@ -40,6 +40,18 @@ async function bundleForServerless(entryPath, outDir, outputFilename) {
|
|
|
40
40
|
// Allow imports without file extensions (TypeScript compiles without .js but ESM requires them)
|
|
41
41
|
fullySpecified: false,
|
|
42
42
|
},
|
|
43
|
+
module: {
|
|
44
|
+
rules: [],
|
|
45
|
+
parser: {
|
|
46
|
+
javascript: {
|
|
47
|
+
// Handle dynamic requires like require('@vercel/kv') inside functions
|
|
48
|
+
// by wrapping them instead of externalizing them
|
|
49
|
+
dynamicImportMode: 'eager',
|
|
50
|
+
exprContextCritical: false,
|
|
51
|
+
unknownContextCritical: false,
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
43
55
|
// Don't minimize to preserve readability for debugging
|
|
44
56
|
optimization: {
|
|
45
57
|
minimize: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bundler.js","sourceRoot":"","sources":["../../../../src/commands/build/bundler.ts"],"names":[],"mappings":";;AAWA,
|
|
1
|
+
{"version":3,"file":"bundler.js","sourceRoot":"","sources":["../../../../src/commands/build/bundler.ts"],"names":[],"mappings":"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","sourcesContent":["import { rspack } from '@rspack/core';\nimport { c } from '../../colors';\n\n/**\n * Bundle the serverless entry point into a single CJS file using rspack.\n * This resolves ESM/CJS compatibility issues and dynamic import problems.\n *\n * @param entryPath - Absolute path to the entry file (e.g., dist/index.js)\n * @param outDir - Output directory for the bundled file\n * @param outputFilename - Name of the output bundle (e.g., 'handler.cjs')\n */\nexport async function bundleForServerless(\n entryPath: string,\n outDir: string,\n outputFilename: string,\n): Promise<void> {\n const compiler = rspack({\n mode: 'production',\n target: 'node',\n entry: entryPath,\n output: {\n path: outDir,\n filename: outputFilename,\n library: { type: 'commonjs2' },\n clean: false,\n },\n // Use node externals preset for built-in modules\n externalsPresets: { node: true },\n // Exclude problematic optional dependencies (native binaries that can't be bundled)\n externals: {\n '@swc/core': '@swc/core',\n fsevents: 'fsevents',\n esbuild: 'esbuild',\n // React is optional - only needed for MDX/JSX rendering\n react: 'react',\n 'react-dom': 'react-dom',\n 'react-dom/server': 'react-dom/server',\n 'react/jsx-runtime': 'react/jsx-runtime',\n },\n resolve: {\n extensions: ['.js', '.mjs', '.cjs', '.json'],\n // Allow imports without file extensions (TypeScript compiles without .js but ESM requires them)\n fullySpecified: false,\n },\n module: {\n rules: [],\n parser: {\n javascript: {\n // Handle dynamic requires like require('@vercel/kv') inside functions\n // by wrapping them instead of externalizing them\n dynamicImportMode: 'eager',\n exprContextCritical: false,\n unknownContextCritical: false,\n },\n },\n },\n // Don't minimize to preserve readability for debugging\n optimization: {\n minimize: false,\n },\n // Suppress known third-party library warnings that don't affect runtime\n ignoreWarnings: [\n // Express view engine dynamic require - expected behavior, harmless at runtime\n /Critical dependency: the request of a dependency is an expression/,\n // Handlebars require.extensions - deprecated Node.js API but works at runtime\n /require\\.extensions is not supported by Rspack/,\n ],\n // Suppress verbose output\n stats: 'errors-warnings',\n });\n\n return new Promise((resolve, reject) => {\n compiler.run((err, stats) => {\n if (err) {\n return reject(err);\n }\n if (stats?.hasErrors()) {\n const info = stats.toJson();\n const errorMessages = info.errors?.map((e) => e.message).join('\\n') || 'Unknown error';\n return reject(new Error(`Bundle failed:\\n${errorMessages}`));\n }\n if (stats?.hasWarnings()) {\n const info = stats.toJson();\n info.warnings?.forEach((w) => {\n console.log(c('yellow', ` Warning: ${w.message}`));\n });\n }\n compiler.close((closeErr) => {\n if (closeErr) {\n console.log(c('yellow', ` Warning closing compiler: ${closeErr.message}`));\n }\n resolve();\n });\n });\n });\n}\n"]}
|
|
@@ -4,6 +4,7 @@ exports.runBuild = runBuild;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const path = tslib_1.__importStar(require("path"));
|
|
6
6
|
const colors_1 = require("../../colors");
|
|
7
|
+
const utils_1 = require("@frontmcp/utils");
|
|
7
8
|
const fs_1 = require("../../utils/fs");
|
|
8
9
|
const tsconfig_1 = require("../../tsconfig");
|
|
9
10
|
const adapters_1 = require("./adapters");
|
|
@@ -49,7 +50,7 @@ async function generateAdapterFiles(adapter, outDir, entryBasename, cwd) {
|
|
|
49
50
|
// Generate config file if adapter has one (skip if already exists)
|
|
50
51
|
if (template.getConfig && template.configFileName) {
|
|
51
52
|
const configPath = path.join(cwd, template.configFileName);
|
|
52
|
-
if (await (0,
|
|
53
|
+
if (await (0, utils_1.fileExists)(configPath)) {
|
|
53
54
|
console.log((0, colors_1.c)('yellow', ` ${template.configFileName} already exists (skipping)`));
|
|
54
55
|
}
|
|
55
56
|
else {
|
|
@@ -60,7 +61,7 @@ async function generateAdapterFiles(adapter, outDir, entryBasename, cwd) {
|
|
|
60
61
|
}
|
|
61
62
|
else {
|
|
62
63
|
// Write as JSON
|
|
63
|
-
await (0,
|
|
64
|
+
await (0, utils_1.writeJSON)(configPath, configContent);
|
|
64
65
|
}
|
|
65
66
|
console.log((0, colors_1.c)('green', ` Generated ${template.configFileName}`));
|
|
66
67
|
}
|
|
@@ -91,7 +92,7 @@ async function runBuild(opts) {
|
|
|
91
92
|
const entry = await (0, fs_1.resolveEntry)(cwd, opts.entry);
|
|
92
93
|
const outDir = path.resolve(cwd, opts.outDir || 'dist');
|
|
93
94
|
const adapter = (opts.adapter || 'node');
|
|
94
|
-
await (0,
|
|
95
|
+
await (0, utils_1.ensureDir)(outDir);
|
|
95
96
|
// Validate adapter
|
|
96
97
|
const template = adapters_1.ADAPTERS[adapter];
|
|
97
98
|
if (!template) {
|
|
@@ -108,7 +109,7 @@ async function runBuild(opts) {
|
|
|
108
109
|
console.log(`${(0, colors_1.c)('cyan', '[build]')} adapter: ${adapter} (${moduleFormat})`);
|
|
109
110
|
// Build TypeScript compiler arguments
|
|
110
111
|
const tsconfigPath = path.join(cwd, 'tsconfig.json');
|
|
111
|
-
const hasTsconfig = await (0,
|
|
112
|
+
const hasTsconfig = await (0, utils_1.fileExists)(tsconfigPath);
|
|
112
113
|
const args = ['-y', 'tsc'];
|
|
113
114
|
if (hasTsconfig) {
|
|
114
115
|
console.log((0, colors_1.c)('gray', `[build] tsconfig.json detected — compiling with project settings`));
|
|
@@ -129,7 +130,7 @@ async function runBuild(opts) {
|
|
|
129
130
|
args.push('--outDir', outDir);
|
|
130
131
|
args.push('--skipLibCheck');
|
|
131
132
|
// Run TypeScript compiler
|
|
132
|
-
await (0,
|
|
133
|
+
await (0, utils_1.runCmd)('npx', args);
|
|
133
134
|
// Generate adapter-specific files
|
|
134
135
|
if (adapter !== 'node') {
|
|
135
136
|
console.log((0, colors_1.c)('cyan', `[build] Generating ${adapter} deployment files...`));
|
|
@@ -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 { ParsedArgs } from '../../args';\nimport { c } from '../../colors';\nimport { ensureDir, fileExists, fsp, runCmd, resolveEntry, writeJSON } from '../../utils/fs';\nimport { REQUIRED_DECORATOR_FIELDS } from '../../tsconfig';\nimport { ADAPTERS } from './adapters';\nimport { AdapterName } from './types';\nimport { bundleForServerless } from './bundler';\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/**\n * Build the FrontMCP server for a specific deployment target.\n *\n * @param opts - Build options from CLI arguments\n *\n * @example\n * ```bash\n * # Build for Node.js (default)\n * frontmcp build\n *\n * # Build for Vercel\n * frontmcp build --adapter vercel\n *\n * # Build for AWS Lambda\n * frontmcp build --adapter lambda\n *\n * # Build for Cloudflare Workers\n * frontmcp build --adapter cloudflare\n * ```\n */\nexport async function runBuild(opts: ParsedArgs): 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 const adapter = (opts.adapter || 'node') as AdapterName;\n await ensureDir(outDir);\n\n // Validate adapter\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 // Warn about experimental adapters\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]')} adapter: ${adapter} (${moduleFormat})`);\n\n // Build TypeScript compiler arguments\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 // Always pass module format to override tsconfig\n args.push('--module', moduleFormat);\n args.push('--outDir', outDir);\n args.push('--skipLibCheck');\n\n // Run TypeScript compiler\n await runCmd('npx', args);\n\n // Generate adapter-specific files\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 { ParsedArgs } from '../../args';\nimport { c } from '../../colors';\nimport { ensureDir, fileExists, runCmd, writeJSON } from '@frontmcp/utils';\nimport { fsp, resolveEntry } from '../../utils/fs';\nimport { REQUIRED_DECORATOR_FIELDS } from '../../tsconfig';\nimport { ADAPTERS } from './adapters';\nimport { AdapterName } from './types';\nimport { bundleForServerless } from './bundler';\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/**\n * Build the FrontMCP server for a specific deployment target.\n *\n * @param opts - Build options from CLI arguments\n *\n * @example\n * ```bash\n * # Build for Node.js (default)\n * frontmcp build\n *\n * # Build for Vercel\n * frontmcp build --adapter vercel\n *\n * # Build for AWS Lambda\n * frontmcp build --adapter lambda\n *\n * # Build for Cloudflare Workers\n * frontmcp build --adapter cloudflare\n * ```\n */\nexport async function runBuild(opts: ParsedArgs): 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 const adapter = (opts.adapter || 'node') as AdapterName;\n await ensureDir(outDir);\n\n // Validate adapter\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 // Warn about experimental adapters\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]')} adapter: ${adapter} (${moduleFormat})`);\n\n // Build TypeScript compiler arguments\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 // Always pass module format to override tsconfig\n args.push('--module', moduleFormat);\n args.push('--outDir', outDir);\n args.push('--skipLibCheck');\n\n // Run TypeScript compiler\n await runCmd('npx', args);\n\n // Generate adapter-specific files\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"]}
|
package/src/commands/create.js
CHANGED
|
@@ -6,10 +6,9 @@ const path = tslib_1.__importStar(require("path"));
|
|
|
6
6
|
const readline = tslib_1.__importStar(require("readline"));
|
|
7
7
|
const fs_1 = require("fs");
|
|
8
8
|
const colors_1 = require("../colors");
|
|
9
|
-
const
|
|
9
|
+
const utils_1 = require("@frontmcp/utils");
|
|
10
10
|
const tsconfig_1 = require("../tsconfig");
|
|
11
11
|
const version_1 = require("../version");
|
|
12
|
-
const fs_3 = require("../utils/fs");
|
|
13
12
|
function createPrompt() {
|
|
14
13
|
const rl = readline.createInterface({
|
|
15
14
|
input: process.stdin,
|
|
@@ -66,11 +65,11 @@ function pkgNameFromCwd(cwd) {
|
|
|
66
65
|
.toLowerCase() || 'frontmcp-app');
|
|
67
66
|
}
|
|
68
67
|
async function scaffoldFileIfMissing(baseDir, p, content) {
|
|
69
|
-
if (await (0,
|
|
68
|
+
if (await (0, utils_1.fileExists)(p)) {
|
|
70
69
|
console.log((0, colors_1.c)('gray', `skip: ${path.relative(baseDir, p)} already exists`));
|
|
71
70
|
return;
|
|
72
71
|
}
|
|
73
|
-
await (0,
|
|
72
|
+
await (0, utils_1.ensureDir)(path.dirname(p));
|
|
74
73
|
await fs_1.promises.writeFile(p, content.replace(/^\n/, ''), 'utf8');
|
|
75
74
|
console.log((0, colors_1.c)('green', `✓ created ${path.relative(baseDir, p)}`));
|
|
76
75
|
}
|
|
@@ -216,6 +215,15 @@ export default {
|
|
|
216
215
|
transformIgnorePatterns: ['node_modules/(?!(jose)/)'],
|
|
217
216
|
};
|
|
218
217
|
`;
|
|
218
|
+
const TEMPLATE_TSCONFIG_E2E = `
|
|
219
|
+
{
|
|
220
|
+
"extends": "./tsconfig.json",
|
|
221
|
+
"compilerOptions": {
|
|
222
|
+
"types": ["node", "jest"]
|
|
223
|
+
},
|
|
224
|
+
"include": ["e2e/**/*.ts", "jest.e2e.config.ts"]
|
|
225
|
+
}
|
|
226
|
+
`;
|
|
219
227
|
const TEMPLATE_DOCKER_COMPOSE = `
|
|
220
228
|
version: '3.8'
|
|
221
229
|
|
|
@@ -404,7 +412,8 @@ See the [Redis Setup Guide](https://docs.agentfront.dev/docs/deployment/redis-se
|
|
|
404
412
|
│ ├── calc.app.ts # Example app
|
|
405
413
|
│ └── tools/
|
|
406
414
|
│ └── add.tool.ts # Example tool
|
|
407
|
-
|
|
415
|
+
├── tsconfig.json # TypeScript config
|
|
416
|
+
└── tsconfig.e2e.json # TypeScript config for E2E tests
|
|
408
417
|
\`\`\`
|
|
409
418
|
|
|
410
419
|
## Learn More
|
|
@@ -1041,7 +1050,8 @@ No additional secrets required - uses \`GITHUB_TOKEN\` for GHCR.
|
|
|
1041
1050
|
│ ├── calc.app.ts # Example app
|
|
1042
1051
|
│ └── tools/
|
|
1043
1052
|
│ └── add.tool.ts # Example tool
|
|
1044
|
-
|
|
1053
|
+
├── tsconfig.json # TypeScript config
|
|
1054
|
+
└── tsconfig.e2e.json # TypeScript config for E2E tests
|
|
1045
1055
|
\`\`\`
|
|
1046
1056
|
|
|
1047
1057
|
## Learn More
|
|
@@ -1107,7 +1117,7 @@ async function scaffoldDeploymentFiles(targetDir, options) {
|
|
|
1107
1117
|
switch (deploymentTarget) {
|
|
1108
1118
|
case 'node': {
|
|
1109
1119
|
const ciDir = path.join(targetDir, 'ci');
|
|
1110
|
-
await (0,
|
|
1120
|
+
await (0, utils_1.ensureDir)(ciDir);
|
|
1111
1121
|
await scaffoldFileIfMissing(targetDir, path.join(ciDir, 'Dockerfile'), TEMPLATE_DOCKERFILE_CI);
|
|
1112
1122
|
const dockerCompose = redisSetup === 'docker' ? TEMPLATE_DOCKER_COMPOSE_WITH_REDIS : TEMPLATE_DOCKER_COMPOSE_NO_REDIS;
|
|
1113
1123
|
await scaffoldFileIfMissing(targetDir, path.join(ciDir, 'docker-compose.yml'), dockerCompose);
|
|
@@ -1119,7 +1129,7 @@ async function scaffoldDeploymentFiles(targetDir, options) {
|
|
|
1119
1129
|
break;
|
|
1120
1130
|
case 'lambda': {
|
|
1121
1131
|
const ciDir = path.join(targetDir, 'ci');
|
|
1122
|
-
await (0,
|
|
1132
|
+
await (0, utils_1.ensureDir)(ciDir);
|
|
1123
1133
|
await scaffoldFileIfMissing(targetDir, path.join(ciDir, 'template.yaml'), TEMPLATE_SAM_YAML(projectName));
|
|
1124
1134
|
break;
|
|
1125
1135
|
}
|
|
@@ -1139,7 +1149,7 @@ NODE_ENV=development
|
|
|
1139
1149
|
`;
|
|
1140
1150
|
async function scaffoldGitHubActions(targetDir, deploymentTarget) {
|
|
1141
1151
|
const workflowDir = path.join(targetDir, '.github', 'workflows');
|
|
1142
|
-
await (0,
|
|
1152
|
+
await (0, utils_1.ensureDir)(workflowDir);
|
|
1143
1153
|
// Always create CI and E2E workflows
|
|
1144
1154
|
await scaffoldFileIfMissing(targetDir, path.join(workflowDir, 'ci.yml'), TEMPLATE_GH_CI);
|
|
1145
1155
|
await scaffoldFileIfMissing(targetDir, path.join(workflowDir, 'e2e.yml'), TEMPLATE_GH_E2E);
|
|
@@ -1172,7 +1182,7 @@ async function scaffoldProject(options) {
|
|
|
1172
1182
|
console.log((0, colors_1.c)('gray', 'Pick a different project name or remove/rename the existing file.'));
|
|
1173
1183
|
process.exit(1);
|
|
1174
1184
|
}
|
|
1175
|
-
if (!(await (0,
|
|
1185
|
+
if (!(await (0, utils_1.isDirEmpty)(targetDir))) {
|
|
1176
1186
|
console.error((0, colors_1.c)('red', `Refusing to scaffold into non-empty directory: ${path.relative(process.cwd(), targetDir)}`));
|
|
1177
1187
|
console.log((0, colors_1.c)('gray', 'Pick a different name or start with an empty folder.'));
|
|
1178
1188
|
process.exit(1);
|
|
@@ -1180,7 +1190,7 @@ async function scaffoldProject(options) {
|
|
|
1180
1190
|
}
|
|
1181
1191
|
catch (e) {
|
|
1182
1192
|
if (e && typeof e === 'object' && 'code' in e && e.code === 'ENOENT') {
|
|
1183
|
-
await (0,
|
|
1193
|
+
await (0, utils_1.ensureDir)(targetDir);
|
|
1184
1194
|
}
|
|
1185
1195
|
else {
|
|
1186
1196
|
throw e;
|
|
@@ -1206,6 +1216,7 @@ async function scaffoldProject(options) {
|
|
|
1206
1216
|
// E2E scaffolding
|
|
1207
1217
|
await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'e2e', 'server.e2e.test.ts'), TEMPLATE_E2E_TEST_TS);
|
|
1208
1218
|
await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'jest.e2e.config.ts'), TEMPLATE_JEST_E2E_CONFIG);
|
|
1219
|
+
await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'tsconfig.e2e.json'), TEMPLATE_TSCONFIG_E2E);
|
|
1209
1220
|
// Git configuration
|
|
1210
1221
|
await scaffoldFileIfMissing(targetDir, path.join(targetDir, '.gitignore'), TEMPLATE_GITIGNORE);
|
|
1211
1222
|
// Deployment-specific files
|
|
@@ -1259,7 +1270,7 @@ function printNextSteps(folder, deploymentTarget, redisSetup, enableGitHubAction
|
|
|
1259
1270
|
// =============================================================================
|
|
1260
1271
|
async function upsertPackageJsonWithTarget(cwd, nameOverride, selfVersion, deploymentTarget) {
|
|
1261
1272
|
const pkgPath = path.join(cwd, 'package.json');
|
|
1262
|
-
const existing = await (0,
|
|
1273
|
+
const existing = await (0, utils_1.readJSON)(pkgPath);
|
|
1263
1274
|
const frontmcpLibRange = `~${selfVersion}`;
|
|
1264
1275
|
const baseScripts = {
|
|
1265
1276
|
dev: 'frontmcp dev',
|
|
@@ -1312,7 +1323,7 @@ async function upsertPackageJsonWithTarget(cwd, nameOverride, selfVersion, deplo
|
|
|
1312
1323
|
},
|
|
1313
1324
|
};
|
|
1314
1325
|
if (!existing) {
|
|
1315
|
-
await (0,
|
|
1326
|
+
await (0, utils_1.writeJSON)(pkgPath, base);
|
|
1316
1327
|
console.log((0, colors_1.c)('green', '✅ Created package.json (synced @frontmcp libs to CLI version + exact frontmcp)'));
|
|
1317
1328
|
return;
|
|
1318
1329
|
}
|
|
@@ -1338,7 +1349,7 @@ async function upsertPackageJsonWithTarget(cwd, nameOverride, selfVersion, deplo
|
|
|
1338
1349
|
...(existing.devDependencies || {}),
|
|
1339
1350
|
...base.devDependencies,
|
|
1340
1351
|
};
|
|
1341
|
-
await (0,
|
|
1352
|
+
await (0, utils_1.writeJSON)(pkgPath, merged);
|
|
1342
1353
|
console.log((0, colors_1.c)('green', '✅ Updated package.json (synced @frontmcp libs + frontmcp to current CLI version)'));
|
|
1343
1354
|
}
|
|
1344
1355
|
// =============================================================================
|