frontmcp 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package.json +4 -3
- package/src/commands/build/adapters/lambda.d.ts +7 -1
- package/src/commands/build/adapters/lambda.js +15 -3
- package/src/commands/build/adapters/lambda.js.map +1 -1
- package/src/commands/build/adapters/vercel.d.ts +7 -1
- package/src/commands/build/adapters/vercel.js +17 -5
- package/src/commands/build/adapters/vercel.js.map +1 -1
- package/src/commands/build/bundler.d.ts +9 -0
- package/src/commands/build/bundler.js +68 -0
- package/src/commands/build/bundler.js.map +1 -0
- package/src/commands/build/index.js +16 -0
- package/src/commands/build/index.js.map +1 -1
- package/src/commands/build/types.d.ts +16 -0
- package/src/commands/build/types.js.map +1 -1
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ _Made with ❤️ for TypeScript developers_
|
|
|
14
14
|
[](https://www.npmjs.com/package/@frontmcp/sdk)
|
|
15
15
|
[](https://nodejs.org)
|
|
16
16
|
[](https://github.com/agentfront/frontmcp/blob/main/LICENSE)
|
|
17
|
+
[](https://snyk.io/test/github/agentfront/frontmcp)
|
|
17
18
|
|
|
18
19
|
</div>
|
|
19
20
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frontmcp",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "FrontMCP command line interface",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"homepage": "https://docs.agentfront.dev",
|
|
@@ -26,13 +26,14 @@
|
|
|
26
26
|
"frontmcp": "./src/cli.js"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"tslib": "^2.3.0"
|
|
29
|
+
"tslib": "^2.3.0",
|
|
30
|
+
"@rspack/core": "^1.3.12"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
33
|
"typescript": "^5.5.3",
|
|
33
34
|
"tsx": "^4.20.6",
|
|
34
35
|
"@types/node": "^24.0.0",
|
|
35
|
-
"@modelcontextprotocol/inspector": "^0.
|
|
36
|
+
"@modelcontextprotocol/inspector": "^0.18.0"
|
|
36
37
|
},
|
|
37
38
|
"types": "./src/index.d.ts",
|
|
38
39
|
"type": "commonjs"
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { AdapterTemplate } from '../types';
|
|
2
2
|
/**
|
|
3
3
|
* AWS Lambda adapter - serverless deployment on AWS Lambda.
|
|
4
|
-
* Compiles to ESM
|
|
4
|
+
* Compiles to ESM, bundles with rspack to CJS for maximum compatibility.
|
|
5
5
|
*
|
|
6
6
|
* Prerequisites:
|
|
7
7
|
* npm install @codegenie/serverless-express
|
|
8
8
|
*
|
|
9
|
+
* The build process:
|
|
10
|
+
* 1. TypeScript compiles to ESM in dist/
|
|
11
|
+
* 2. serverless-setup.js is generated (sets FRONTMCP_SERVERLESS=1)
|
|
12
|
+
* 3. index.js imports setup first, then main module
|
|
13
|
+
* 4. rspack bundles everything into handler.cjs
|
|
14
|
+
*
|
|
9
15
|
* @see https://github.com/codegenie/serverless-express
|
|
10
16
|
*/
|
|
11
17
|
export declare const lambdaAdapter: AdapterTemplate;
|
|
@@ -3,23 +3,35 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.lambdaAdapter = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* AWS Lambda adapter - serverless deployment on AWS Lambda.
|
|
6
|
-
* Compiles to ESM
|
|
6
|
+
* Compiles to ESM, bundles with rspack to CJS for maximum compatibility.
|
|
7
7
|
*
|
|
8
8
|
* Prerequisites:
|
|
9
9
|
* npm install @codegenie/serverless-express
|
|
10
10
|
*
|
|
11
|
+
* The build process:
|
|
12
|
+
* 1. TypeScript compiles to ESM in dist/
|
|
13
|
+
* 2. serverless-setup.js is generated (sets FRONTMCP_SERVERLESS=1)
|
|
14
|
+
* 3. index.js imports setup first, then main module
|
|
15
|
+
* 4. rspack bundles everything into handler.cjs
|
|
16
|
+
*
|
|
11
17
|
* @see https://github.com/codegenie/serverless-express
|
|
12
18
|
*/
|
|
13
19
|
exports.lambdaAdapter = {
|
|
14
20
|
moduleFormat: 'esnext',
|
|
21
|
+
shouldBundle: true,
|
|
22
|
+
bundleOutput: 'handler.cjs',
|
|
23
|
+
getSetupTemplate: () => `// Serverless environment setup - MUST be imported first
|
|
24
|
+
// This sets FRONTMCP_SERVERLESS before any decorators run
|
|
25
|
+
// Required because ESM hoists imports before other statements
|
|
26
|
+
process.env.FRONTMCP_SERVERLESS = '1';
|
|
27
|
+
`,
|
|
15
28
|
getEntryTemplate: (mainModulePath) => `// Auto-generated AWS Lambda entry point
|
|
16
29
|
// Generated by: frontmcp build --adapter lambda
|
|
17
30
|
//
|
|
18
31
|
// IMPORTANT: This adapter requires @codegenie/serverless-express
|
|
19
32
|
// Install it with: npm install @codegenie/serverless-express
|
|
20
33
|
//
|
|
21
|
-
|
|
22
|
-
|
|
34
|
+
import './serverless-setup.js';
|
|
23
35
|
import '${mainModulePath}';
|
|
24
36
|
import { getServerlessHandlerAsync } from '@frontmcp/sdk';
|
|
25
37
|
import serverlessExpress from '@codegenie/serverless-express';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lambda.js","sourceRoot":"","sources":["../../../../../src/commands/build/adapters/lambda.ts"],"names":[],"mappings":";;;AAEA
|
|
1
|
+
{"version":3,"file":"lambda.js","sourceRoot":"","sources":["../../../../../src/commands/build/adapters/lambda.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;GAcG;AACU,QAAA,aAAa,GAAoB;IAC5C,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,IAAI;IAClB,YAAY,EAAE,aAAa;IAE3B,gBAAgB,EAAE,GAAG,EAAE,CAAC;;;;CAIzB;IAEC,gBAAgB,EAAE,CAAC,cAAsB,EAAE,EAAE,CAAC;;;;;;;UAOtC,cAAc;;;;;;;;;;;;;;;;;CAiBvB;IAEC,qEAAqE;CACtE,CAAC","sourcesContent":["import { AdapterTemplate } from '../types';\n\n/**\n * AWS Lambda adapter - serverless deployment on AWS Lambda.\n * Compiles to ESM, bundles with rspack to CJS for maximum compatibility.\n *\n * Prerequisites:\n * npm install @codegenie/serverless-express\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 *\n * @see https://github.com/codegenie/serverless-express\n */\nexport const lambdaAdapter: 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 AWS Lambda entry point\n// Generated by: frontmcp build --adapter lambda\n//\n// IMPORTANT: This adapter requires @codegenie/serverless-express\n// Install it with: npm install @codegenie/serverless-express\n//\nimport './serverless-setup.js';\nimport '${mainModulePath}';\nimport { getServerlessHandlerAsync } from '@frontmcp/sdk';\nimport serverlessExpress from '@codegenie/serverless-express';\n\nlet serverlessExpressInstance = null;\n\nasync function setup() {\n const app = await getServerlessHandlerAsync();\n serverlessExpressInstance = serverlessExpress({ app });\n}\n\nexport const handler = async (event, context) => {\n if (!serverlessExpressInstance) {\n await setup();\n }\n return serverlessExpressInstance(event, context);\n};\n`,\n\n // No config file - user manages serverless.yml, SAM template, or CDK\n};\n"]}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { AdapterTemplate } from '../types';
|
|
2
2
|
/**
|
|
3
3
|
* Vercel adapter - serverless deployment on Vercel.
|
|
4
|
-
* Compiles to ESM
|
|
4
|
+
* Compiles to ESM, bundles with rspack to CJS for maximum compatibility.
|
|
5
|
+
*
|
|
6
|
+
* The build process:
|
|
7
|
+
* 1. TypeScript compiles to ESM in dist/
|
|
8
|
+
* 2. serverless-setup.js is generated (sets FRONTMCP_SERVERLESS=1)
|
|
9
|
+
* 3. index.js imports setup first, then main module
|
|
10
|
+
* 4. rspack bundles everything into handler.cjs
|
|
5
11
|
*
|
|
6
12
|
* @see https://vercel.com/docs/frameworks/express
|
|
7
13
|
*/
|
|
@@ -3,16 +3,28 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.vercelAdapter = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Vercel adapter - serverless deployment on Vercel.
|
|
6
|
-
* Compiles to ESM
|
|
6
|
+
* Compiles to ESM, bundles with rspack to CJS for maximum compatibility.
|
|
7
|
+
*
|
|
8
|
+
* The build process:
|
|
9
|
+
* 1. TypeScript compiles to ESM in dist/
|
|
10
|
+
* 2. serverless-setup.js is generated (sets FRONTMCP_SERVERLESS=1)
|
|
11
|
+
* 3. index.js imports setup first, then main module
|
|
12
|
+
* 4. rspack bundles everything into handler.cjs
|
|
7
13
|
*
|
|
8
14
|
* @see https://vercel.com/docs/frameworks/express
|
|
9
15
|
*/
|
|
10
16
|
exports.vercelAdapter = {
|
|
11
17
|
moduleFormat: 'esnext',
|
|
18
|
+
shouldBundle: true,
|
|
19
|
+
bundleOutput: 'handler.cjs',
|
|
20
|
+
getSetupTemplate: () => `// Serverless environment setup - MUST be imported first
|
|
21
|
+
// This sets FRONTMCP_SERVERLESS before any decorators run
|
|
22
|
+
// Required because ESM hoists imports before other statements
|
|
23
|
+
process.env.FRONTMCP_SERVERLESS = '1';
|
|
24
|
+
`,
|
|
12
25
|
getEntryTemplate: (mainModulePath) => `// Auto-generated Vercel entry point
|
|
13
26
|
// Generated by: frontmcp build --adapter vercel
|
|
14
|
-
|
|
15
|
-
|
|
27
|
+
import './serverless-setup.js';
|
|
16
28
|
import '${mainModulePath}';
|
|
17
29
|
import { getServerlessHandlerAsync } from '@frontmcp/sdk';
|
|
18
30
|
|
|
@@ -28,8 +40,8 @@ export default async function handler(req, res) {
|
|
|
28
40
|
`,
|
|
29
41
|
getConfig: () => ({
|
|
30
42
|
version: 2,
|
|
31
|
-
builds: [{ src: 'dist/
|
|
32
|
-
routes: [{ src: '/(.*)', dest: '/dist/
|
|
43
|
+
builds: [{ src: 'dist/handler.cjs', use: '@vercel/node' }],
|
|
44
|
+
routes: [{ src: '/(.*)', dest: '/dist/handler.cjs' }],
|
|
33
45
|
}),
|
|
34
46
|
configFileName: 'vercel.json',
|
|
35
47
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vercel.js","sourceRoot":"","sources":["../../../../../src/commands/build/adapters/vercel.ts"],"names":[],"mappings":";;;AAEA
|
|
1
|
+
{"version":3,"file":"vercel.js","sourceRoot":"","sources":["../../../../../src/commands/build/adapters/vercel.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;GAWG;AACU,QAAA,aAAa,GAAoB;IAC5C,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,IAAI;IAClB,YAAY,EAAE,aAAa;IAE3B,gBAAgB,EAAE,GAAG,EAAE,CAAC;;;;CAIzB;IAEC,gBAAgB,EAAE,CAAC,cAAsB,EAAE,EAAE,CAAC;;;UAGtC,cAAc;;;;;;;;;;;;CAYvB;IAEC,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;QAChB,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC;QAC1D,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC;KACtD,CAAC;IAEF,cAAc,EAAE,aAAa;CAC9B,CAAC","sourcesContent":["import { AdapterTemplate } from '../types';\n\n/**\n * Vercel adapter - serverless deployment on Vercel.\n * Compiles to ESM, bundles with rspack to CJS for maximum compatibility.\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 *\n * @see https://vercel.com/docs/frameworks/express\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 getConfig: () => ({\n version: 2,\n builds: [{ src: 'dist/handler.cjs', use: '@vercel/node' }],\n routes: [{ src: '/(.*)', dest: '/dist/handler.cjs' }],\n }),\n\n configFileName: 'vercel.json',\n};\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundle the serverless entry point into a single CJS file using rspack.
|
|
3
|
+
* This resolves ESM/CJS compatibility issues and dynamic import problems.
|
|
4
|
+
*
|
|
5
|
+
* @param entryPath - Absolute path to the entry file (e.g., dist/index.js)
|
|
6
|
+
* @param outDir - Output directory for the bundled file
|
|
7
|
+
* @param outputFilename - Name of the output bundle (e.g., 'handler.cjs')
|
|
8
|
+
*/
|
|
9
|
+
export declare function bundleForServerless(entryPath: string, outDir: string, outputFilename: string): Promise<void>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bundleForServerless = bundleForServerless;
|
|
4
|
+
const core_1 = require("@rspack/core");
|
|
5
|
+
const colors_1 = require("../../colors");
|
|
6
|
+
/**
|
|
7
|
+
* Bundle the serverless entry point into a single CJS file using rspack.
|
|
8
|
+
* This resolves ESM/CJS compatibility issues and dynamic import problems.
|
|
9
|
+
*
|
|
10
|
+
* @param entryPath - Absolute path to the entry file (e.g., dist/index.js)
|
|
11
|
+
* @param outDir - Output directory for the bundled file
|
|
12
|
+
* @param outputFilename - Name of the output bundle (e.g., 'handler.cjs')
|
|
13
|
+
*/
|
|
14
|
+
async function bundleForServerless(entryPath, outDir, outputFilename) {
|
|
15
|
+
const compiler = (0, core_1.rspack)({
|
|
16
|
+
mode: 'production',
|
|
17
|
+
target: 'node',
|
|
18
|
+
entry: entryPath,
|
|
19
|
+
output: {
|
|
20
|
+
path: outDir,
|
|
21
|
+
filename: outputFilename,
|
|
22
|
+
library: { type: 'commonjs2' },
|
|
23
|
+
clean: false,
|
|
24
|
+
},
|
|
25
|
+
// Use node externals preset for built-in modules
|
|
26
|
+
externalsPresets: { node: true },
|
|
27
|
+
// Exclude problematic optional dependencies
|
|
28
|
+
externals: {
|
|
29
|
+
'@swc/core': '@swc/core',
|
|
30
|
+
fsevents: 'fsevents',
|
|
31
|
+
esbuild: 'esbuild',
|
|
32
|
+
},
|
|
33
|
+
resolve: {
|
|
34
|
+
extensions: ['.js', '.mjs', '.cjs', '.json'],
|
|
35
|
+
},
|
|
36
|
+
// Don't minimize to preserve readability for debugging
|
|
37
|
+
optimization: {
|
|
38
|
+
minimize: false,
|
|
39
|
+
},
|
|
40
|
+
// Suppress verbose output
|
|
41
|
+
stats: 'errors-warnings',
|
|
42
|
+
});
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
compiler.run((err, stats) => {
|
|
45
|
+
if (err) {
|
|
46
|
+
return reject(err);
|
|
47
|
+
}
|
|
48
|
+
if (stats?.hasErrors()) {
|
|
49
|
+
const info = stats.toJson();
|
|
50
|
+
const errorMessages = info.errors?.map((e) => e.message).join('\n') || 'Unknown error';
|
|
51
|
+
return reject(new Error(`Bundle failed:\n${errorMessages}`));
|
|
52
|
+
}
|
|
53
|
+
if (stats?.hasWarnings()) {
|
|
54
|
+
const info = stats.toJson();
|
|
55
|
+
info.warnings?.forEach((w) => {
|
|
56
|
+
console.log((0, colors_1.c)('yellow', ` Warning: ${w.message}`));
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
compiler.close((closeErr) => {
|
|
60
|
+
if (closeErr) {
|
|
61
|
+
console.log((0, colors_1.c)('yellow', ` Warning closing compiler: ${closeErr.message}`));
|
|
62
|
+
}
|
|
63
|
+
resolve();
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=bundler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundler.js","sourceRoot":"","sources":["../../../../src/commands/build/bundler.ts"],"names":[],"mappings":";;AAWA,kDA0DC;AArED,uCAAsC;AACtC,yCAAiC;AAEjC;;;;;;;GAOG;AACI,KAAK,UAAU,mBAAmB,CACvC,SAAiB,EACjB,MAAc,EACd,cAAsB;IAEtB,MAAM,QAAQ,GAAG,IAAA,aAAM,EAAC;QACtB,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,MAAM;QACd,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE;YACN,IAAI,EAAE,MAAM;YACZ,QAAQ,EAAE,cAAc;YACxB,OAAO,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;YAC9B,KAAK,EAAE,KAAK;SACb;QACD,iDAAiD;QACjD,gBAAgB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;QAChC,4CAA4C;QAC5C,SAAS,EAAE;YACT,WAAW,EAAE,WAAW;YACxB,QAAQ,EAAE,UAAU;YACpB,OAAO,EAAE,SAAS;SACnB;QACD,OAAO,EAAE;YACP,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC;SAC7C;QACD,uDAAuD;QACvD,YAAY,EAAE;YACZ,QAAQ,EAAE,KAAK;SAChB;QACD,0BAA0B;QAC1B,KAAK,EAAE,iBAAiB;KACzB,CAAC,CAAC;IAEH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YAC1B,IAAI,GAAG,EAAE,CAAC;gBACR,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;YACrB,CAAC;YACD,IAAI,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC;gBACvB,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;gBAC5B,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC;gBACvF,OAAO,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,aAAa,EAAE,CAAC,CAAC,CAAC;YAC/D,CAAC;YACD,IAAI,KAAK,EAAE,WAAW,EAAE,EAAE,CAAC;gBACzB,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;gBAC5B,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;oBAC3B,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBACtD,CAAC,CAAC,CAAC;YACL,CAAC;YACD,QAAQ,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,EAAE;gBAC1B,IAAI,QAAQ,EAAE,CAAC;oBACb,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,QAAQ,EAAE,+BAA+B,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBAC9E,CAAC;gBACD,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC","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\n externals: {\n '@swc/core': '@swc/core',\n fsevents: 'fsevents',\n esbuild: 'esbuild',\n },\n resolve: {\n extensions: ['.js', '.mjs', '.cjs', '.json'],\n },\n // Don't minimize to preserve readability for debugging\n optimization: {\n minimize: false,\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"]}
|
|
@@ -7,6 +7,7 @@ const colors_1 = require("../../colors");
|
|
|
7
7
|
const fs_1 = require("../../utils/fs");
|
|
8
8
|
const tsconfig_1 = require("../../tsconfig");
|
|
9
9
|
const adapters_1 = require("./adapters");
|
|
10
|
+
const bundler_1 = require("./bundler");
|
|
10
11
|
function isTsLike(p) {
|
|
11
12
|
return /\.tsx?$/i.test(p);
|
|
12
13
|
}
|
|
@@ -15,6 +16,14 @@ function isTsLike(p) {
|
|
|
15
16
|
*/
|
|
16
17
|
async function generateAdapterFiles(adapter, outDir, entryBasename, cwd) {
|
|
17
18
|
const template = adapters_1.ADAPTERS[adapter];
|
|
19
|
+
// Generate serverless setup file first (if adapter has one)
|
|
20
|
+
// This file sets FRONTMCP_SERVERLESS=1 before any imports run
|
|
21
|
+
if (template.getSetupTemplate) {
|
|
22
|
+
const setupContent = template.getSetupTemplate();
|
|
23
|
+
const setupPath = path.join(outDir, 'serverless-setup.js');
|
|
24
|
+
await fs_1.fsp.writeFile(setupPath, setupContent, 'utf8');
|
|
25
|
+
console.log((0, colors_1.c)('green', ` Generated serverless setup at ${path.relative(cwd, setupPath)}`));
|
|
26
|
+
}
|
|
18
27
|
// Generate index.js entry point
|
|
19
28
|
const mainModuleName = entryBasename.replace(/\.tsx?$/, '.js');
|
|
20
29
|
const entryContent = template.getEntryTemplate(`./${mainModuleName}`);
|
|
@@ -24,6 +33,13 @@ async function generateAdapterFiles(adapter, outDir, entryBasename, cwd) {
|
|
|
24
33
|
await fs_1.fsp.writeFile(entryPath, entryContent, 'utf8');
|
|
25
34
|
console.log((0, colors_1.c)('green', ` Generated ${adapter} entry at ${path.relative(cwd, entryPath)}`));
|
|
26
35
|
}
|
|
36
|
+
// Bundle if adapter requires it (creates single CJS file for serverless)
|
|
37
|
+
if (template.shouldBundle && template.bundleOutput) {
|
|
38
|
+
console.log((0, colors_1.c)('cyan', `[build] Bundling for ${adapter}...`));
|
|
39
|
+
const entryPath = path.join(outDir, 'index.js');
|
|
40
|
+
await (0, bundler_1.bundleForServerless)(entryPath, outDir, template.bundleOutput);
|
|
41
|
+
console.log((0, colors_1.c)('green', ` Created bundle: ${template.bundleOutput}`));
|
|
42
|
+
}
|
|
27
43
|
// Generate config file if adapter has one (skip if already exists)
|
|
28
44
|
if (template.getConfig && template.configFileName) {
|
|
29
45
|
const configPath = path.join(cwd, template.configFileName);
|
|
@@ -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';\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 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 // 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();\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, 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\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();\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"]}
|
|
@@ -12,6 +12,22 @@ export type AdapterTemplate = {
|
|
|
12
12
|
* @returns The content for index.js, or empty string if no wrapper needed
|
|
13
13
|
*/
|
|
14
14
|
getEntryTemplate: (mainModulePath: string) => string;
|
|
15
|
+
/**
|
|
16
|
+
* Generate the serverless setup file content.
|
|
17
|
+
* This file is imported first to set environment variables before decorators run.
|
|
18
|
+
* @returns The content for serverless-setup.js, or undefined if not needed
|
|
19
|
+
*/
|
|
20
|
+
getSetupTemplate?: () => string;
|
|
21
|
+
/**
|
|
22
|
+
* Whether to bundle the output with rspack.
|
|
23
|
+
* Recommended for serverless deployments to avoid ESM/CJS issues.
|
|
24
|
+
*/
|
|
25
|
+
shouldBundle?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Output filename for the bundled file (e.g., 'handler.cjs').
|
|
28
|
+
* Only used when shouldBundle is true.
|
|
29
|
+
*/
|
|
30
|
+
bundleOutput?: string;
|
|
15
31
|
/**
|
|
16
32
|
* Generate the deployment platform config file content.
|
|
17
33
|
* @returns Object (for JSON) or string (for TOML/YAML)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/commands/build/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Configuration for a deployment adapter.\n * Each adapter defines how to compile and package the FrontMCP server\n * for a specific deployment target.\n */\nexport type AdapterTemplate = {\n /** Module format for TypeScript compilation */\n moduleFormat: 'commonjs' | 'esnext';\n\n /**\n * Generate the entry point file content.\n * @param mainModulePath - Relative path to the compiled main module (e.g., './main.js')\n * @returns The content for index.js, or empty string if no wrapper needed\n */\n getEntryTemplate: (mainModulePath: string) => string;\n\n /**\n * Generate the deployment platform config file content.\n * @returns Object (for JSON) or string (for TOML/YAML)\n */\n getConfig?: () => object | string;\n\n /** Name of the config file (e.g., 'vercel.json', 'wrangler.toml') */\n configFileName?: string;\n};\n\nexport type AdapterName = 'node' | 'vercel' | 'lambda' | 'cloudflare';\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/commands/build/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Configuration for a deployment adapter.\n * Each adapter defines how to compile and package the FrontMCP server\n * for a specific deployment target.\n */\nexport type AdapterTemplate = {\n /** Module format for TypeScript compilation */\n moduleFormat: 'commonjs' | 'esnext';\n\n /**\n * Generate the entry point file content.\n * @param mainModulePath - Relative path to the compiled main module (e.g., './main.js')\n * @returns The content for index.js, or empty string if no wrapper needed\n */\n getEntryTemplate: (mainModulePath: string) => string;\n\n /**\n * Generate the serverless setup file content.\n * This file is imported first to set environment variables before decorators run.\n * @returns The content for serverless-setup.js, or undefined if not needed\n */\n getSetupTemplate?: () => string;\n\n /**\n * Whether to bundle the output with rspack.\n * Recommended for serverless deployments to avoid ESM/CJS issues.\n */\n shouldBundle?: boolean;\n\n /**\n * Output filename for the bundled file (e.g., 'handler.cjs').\n * Only used when shouldBundle is true.\n */\n bundleOutput?: string;\n\n /**\n * Generate the deployment platform config file content.\n * @returns Object (for JSON) or string (for TOML/YAML)\n */\n getConfig?: () => object | string;\n\n /** Name of the config file (e.g., 'vercel.json', 'wrangler.toml') */\n configFileName?: string;\n};\n\nexport type AdapterName = 'node' | 'vercel' | 'lambda' | 'cloudflare';\n"]}
|