@forklaunch/express 0.5.34 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -39,6 +39,8 @@ module.exports = __toCommonJS(index_exports);
39
39
  // src/expressApplication.ts
40
40
  var import_common3 = require("@forklaunch/common");
41
41
  var import_http3 = require("@forklaunch/core/http");
42
+ var import_zod = require("@forklaunch/validator/zod");
43
+ var import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
42
44
  var import_express_api_reference = require("@scalar/express-api-reference");
43
45
  var import_crypto = __toESM(require("crypto"));
44
46
  var import_express2 = __toESM(require("express"));
@@ -75,7 +77,15 @@ function contentParse(options2) {
75
77
  case "text":
76
78
  return textParser(req, res, next);
77
79
  case "file":
78
- return rawParser(req, res, next);
80
+ return rawParser(req, res, async (err) => {
81
+ if (err) {
82
+ return next(err);
83
+ }
84
+ if (req.body instanceof Buffer) {
85
+ req.body = req.body.toString("utf-8");
86
+ }
87
+ next();
88
+ });
79
89
  case "multipart": {
80
90
  const bb = (0, import_busboy.default)({
81
91
  headers: req.headers,
@@ -88,8 +98,8 @@ function contentParse(options2) {
88
98
  chunks.push(chunk);
89
99
  });
90
100
  file.on("end", () => {
91
- const fileBuffer = Uint8Array.from(chunks.flat());
92
- body[fieldname] = fileBuffer.toString();
101
+ const fileString = chunks.map((chunk) => chunk.toString()).join("");
102
+ body[fieldname] = fileString;
93
103
  });
94
104
  });
95
105
  bb.on("field", (fieldname, value) => {
@@ -175,11 +185,63 @@ var Application = class extends import_http3.ForklaunchExpressLikeApplication {
175
185
  }
176
186
  listen(...args) {
177
187
  const port = typeof args[0] === "number" ? args[0] : Number(process.env.PORT);
188
+ const host = typeof args[1] === "string" ? args[1] : process.env.HOST ?? "localhost";
189
+ const protocol = process.env.PROTOCOL ?? "http";
178
190
  const openApi = (0, import_http3.generateSwaggerDocument)(
179
191
  this.schemaValidator,
192
+ protocol,
193
+ host,
180
194
  port,
181
195
  this.routers
182
196
  );
197
+ if (this.schemaValidator instanceof import_zod.ZodSchemaValidator) {
198
+ const zodSchemaValidator = this.schemaValidator;
199
+ const routers = this.routers;
200
+ this.internal.get("/mcp", async (_req, res) => {
201
+ const server = (0, import_http3.generateMcpServer)(
202
+ zodSchemaValidator,
203
+ protocol,
204
+ host,
205
+ port,
206
+ "1.0.0",
207
+ routers
208
+ );
209
+ res.json(server);
210
+ });
211
+ this.internal.post("/mcp", async (req, res) => {
212
+ try {
213
+ const server = (0, import_http3.generateMcpServer)(
214
+ zodSchemaValidator,
215
+ protocol,
216
+ host,
217
+ port,
218
+ "1.0.0",
219
+ routers
220
+ );
221
+ const transport = new import_streamableHttp.StreamableHTTPServerTransport({
222
+ sessionIdGenerator: void 0
223
+ });
224
+ res.on("close", () => {
225
+ transport.close();
226
+ server.close();
227
+ });
228
+ await server.connect(transport);
229
+ await transport.handleRequest(req, res, req.body);
230
+ } catch (error) {
231
+ console.error("Error handling MCP request:", error);
232
+ if (!res.headersSent) {
233
+ res.status(500).json({
234
+ jsonrpc: "2.0",
235
+ error: {
236
+ code: -32603,
237
+ message: "Internal server error"
238
+ },
239
+ id: null
240
+ });
241
+ }
242
+ }
243
+ });
244
+ }
183
245
  if (this.docsConfiguration == null || this.docsConfiguration.type === "scalar") {
184
246
  this.internal.use(
185
247
  `/api/${process.env.VERSION ?? "v1"}${process.env.DOCS_PATH ?? "/docs"}`,
@@ -218,14 +280,14 @@ var Application = class extends import_http3.ForklaunchExpressLikeApplication {
218
280
  const errorHandler = (err, req, res, _next) => {
219
281
  const statusCode = Number(res.statusCode);
220
282
  res.locals.errorMessage = err.message;
221
- console.log(err);
283
+ console.error(err);
222
284
  res.type("text/plain");
223
285
  res.status(statusCode >= 400 ? statusCode : 500).send(
224
286
  `Internal server error:
225
287
 
226
288
  Correlation id: ${(0, import_http3.isForklaunchRequest)(req) ? req.context.correlationId : "No correlation ID"}`
227
289
  );
228
- (0, import_http3.logger)("error").error(
290
+ this.openTelemetryCollector.error(
229
291
  err.stack ?? err.message,
230
292
  (0, import_http3.meta)({
231
293
  [import_http3.ATTR_HTTP_RESPONSE_STATUS_CODE]: statusCode
@@ -240,8 +302,7 @@ Correlation id: ${(0, import_http3.isForklaunchRequest)(req) ? req.context.corre
240
302
  // src/expressRouter.ts
241
303
  var import_http4 = require("@forklaunch/core/http");
242
304
  var import_express3 = __toESM(require("express"));
243
- var Router = class extends import_http4.ForklaunchExpressLikeRouter {
244
- // implements ForklaunchRouter<SV>
305
+ var Router = class _Router extends import_http4.ForklaunchExpressLikeRouter {
245
306
  /**
246
307
  * Creates an instance of Router.
247
308
  *
@@ -260,7 +321,9 @@ var Router = class extends import_http4.ForklaunchExpressLikeRouter {
260
321
  openTelemetryCollector
261
322
  );
262
323
  this.basePath = basePath;
324
+ this.configOptions = options2;
263
325
  }
326
+ configOptions;
264
327
  route(path) {
265
328
  this.internal.route(path);
266
329
  return this;
@@ -429,6 +492,16 @@ var Router = class extends import_http4.ForklaunchExpressLikeRouter {
429
492
  ...middlewareOrMiddlewareWithTypedHandler
430
493
  );
431
494
  };
495
+ clone() {
496
+ const clone = new _Router(
497
+ this.basePath,
498
+ this.schemaValidator,
499
+ this.openTelemetryCollector,
500
+ this.configOptions
501
+ );
502
+ this.cloneInternals(clone);
503
+ return clone;
504
+ }
432
505
  };
433
506
 
434
507
  // src/handlers/checkout.ts
package/lib/index.mjs CHANGED
@@ -3,11 +3,13 @@ import { safeStringify as safeStringify2 } from "@forklaunch/common";
3
3
  import {
4
4
  ATTR_HTTP_RESPONSE_STATUS_CODE,
5
5
  ForklaunchExpressLikeApplication,
6
+ generateMcpServer,
6
7
  generateSwaggerDocument,
7
8
  isForklaunchRequest,
8
- logger,
9
9
  meta
10
10
  } from "@forklaunch/core/http";
11
+ import { ZodSchemaValidator } from "@forklaunch/validator/zod";
12
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
11
13
  import { apiReference } from "@scalar/express-api-reference";
12
14
  import crypto from "crypto";
13
15
  import express2 from "express";
@@ -44,7 +46,15 @@ function contentParse(options2) {
44
46
  case "text":
45
47
  return textParser(req, res, next);
46
48
  case "file":
47
- return rawParser(req, res, next);
49
+ return rawParser(req, res, async (err) => {
50
+ if (err) {
51
+ return next(err);
52
+ }
53
+ if (req.body instanceof Buffer) {
54
+ req.body = req.body.toString("utf-8");
55
+ }
56
+ next();
57
+ });
48
58
  case "multipart": {
49
59
  const bb = Busboy({
50
60
  headers: req.headers,
@@ -57,8 +67,8 @@ function contentParse(options2) {
57
67
  chunks.push(chunk);
58
68
  });
59
69
  file.on("end", () => {
60
- const fileBuffer = Uint8Array.from(chunks.flat());
61
- body[fieldname] = fileBuffer.toString();
70
+ const fileString = chunks.map((chunk) => chunk.toString()).join("");
71
+ body[fieldname] = fileString;
62
72
  });
63
73
  });
64
74
  bb.on("field", (fieldname, value) => {
@@ -146,11 +156,63 @@ var Application = class extends ForklaunchExpressLikeApplication {
146
156
  }
147
157
  listen(...args) {
148
158
  const port = typeof args[0] === "number" ? args[0] : Number(process.env.PORT);
159
+ const host = typeof args[1] === "string" ? args[1] : process.env.HOST ?? "localhost";
160
+ const protocol = process.env.PROTOCOL ?? "http";
149
161
  const openApi = generateSwaggerDocument(
150
162
  this.schemaValidator,
163
+ protocol,
164
+ host,
151
165
  port,
152
166
  this.routers
153
167
  );
168
+ if (this.schemaValidator instanceof ZodSchemaValidator) {
169
+ const zodSchemaValidator = this.schemaValidator;
170
+ const routers = this.routers;
171
+ this.internal.get("/mcp", async (_req, res) => {
172
+ const server = generateMcpServer(
173
+ zodSchemaValidator,
174
+ protocol,
175
+ host,
176
+ port,
177
+ "1.0.0",
178
+ routers
179
+ );
180
+ res.json(server);
181
+ });
182
+ this.internal.post("/mcp", async (req, res) => {
183
+ try {
184
+ const server = generateMcpServer(
185
+ zodSchemaValidator,
186
+ protocol,
187
+ host,
188
+ port,
189
+ "1.0.0",
190
+ routers
191
+ );
192
+ const transport = new StreamableHTTPServerTransport({
193
+ sessionIdGenerator: void 0
194
+ });
195
+ res.on("close", () => {
196
+ transport.close();
197
+ server.close();
198
+ });
199
+ await server.connect(transport);
200
+ await transport.handleRequest(req, res, req.body);
201
+ } catch (error) {
202
+ console.error("Error handling MCP request:", error);
203
+ if (!res.headersSent) {
204
+ res.status(500).json({
205
+ jsonrpc: "2.0",
206
+ error: {
207
+ code: -32603,
208
+ message: "Internal server error"
209
+ },
210
+ id: null
211
+ });
212
+ }
213
+ }
214
+ });
215
+ }
154
216
  if (this.docsConfiguration == null || this.docsConfiguration.type === "scalar") {
155
217
  this.internal.use(
156
218
  `/api/${process.env.VERSION ?? "v1"}${process.env.DOCS_PATH ?? "/docs"}`,
@@ -189,14 +251,14 @@ var Application = class extends ForklaunchExpressLikeApplication {
189
251
  const errorHandler = (err, req, res, _next) => {
190
252
  const statusCode = Number(res.statusCode);
191
253
  res.locals.errorMessage = err.message;
192
- console.log(err);
254
+ console.error(err);
193
255
  res.type("text/plain");
194
256
  res.status(statusCode >= 400 ? statusCode : 500).send(
195
257
  `Internal server error:
196
258
 
197
259
  Correlation id: ${isForklaunchRequest(req) ? req.context.correlationId : "No correlation ID"}`
198
260
  );
199
- logger("error").error(
261
+ this.openTelemetryCollector.error(
200
262
  err.stack ?? err.message,
201
263
  meta({
202
264
  [ATTR_HTTP_RESPONSE_STATUS_CODE]: statusCode
@@ -213,8 +275,7 @@ import {
213
275
  ForklaunchExpressLikeRouter
214
276
  } from "@forklaunch/core/http";
215
277
  import express3 from "express";
216
- var Router = class extends ForklaunchExpressLikeRouter {
217
- // implements ForklaunchRouter<SV>
278
+ var Router = class _Router extends ForklaunchExpressLikeRouter {
218
279
  /**
219
280
  * Creates an instance of Router.
220
281
  *
@@ -233,7 +294,9 @@ var Router = class extends ForklaunchExpressLikeRouter {
233
294
  openTelemetryCollector
234
295
  );
235
296
  this.basePath = basePath;
297
+ this.configOptions = options2;
236
298
  }
299
+ configOptions;
237
300
  route(path) {
238
301
  this.internal.route(path);
239
302
  return this;
@@ -402,6 +465,16 @@ var Router = class extends ForklaunchExpressLikeRouter {
402
465
  ...middlewareOrMiddlewareWithTypedHandler
403
466
  );
404
467
  };
468
+ clone() {
469
+ const clone = new _Router(
470
+ this.basePath,
471
+ this.schemaValidator,
472
+ this.openTelemetryCollector,
473
+ this.configOptions
474
+ );
475
+ this.cloneInternals(clone);
476
+ return clone;
477
+ }
405
478
  };
406
479
 
407
480
  // src/handlers/checkout.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forklaunch/express",
3
- "version": "0.5.34",
3
+ "version": "0.6.0",
4
4
  "description": "Forklaunch framework for express.",
5
5
  "homepage": "https://github.com/forklaunch/forklaunch-js#readme",
6
6
  "bugs": {
@@ -25,7 +25,8 @@
25
25
  "lib/**"
26
26
  ],
27
27
  "dependencies": {
28
- "@scalar/express-api-reference": "^0.8.5",
28
+ "@modelcontextprotocol/sdk": "^1.13.2",
29
+ "@scalar/express-api-reference": "^0.8.7",
29
30
  "@types/multer": "^1.4.13",
30
31
  "body-parser": "^2.2.0",
31
32
  "busboy": "^1.6.0",
@@ -34,12 +35,12 @@
34
35
  "multer": "2.0.1",
35
36
  "qs": "^6.14.0",
36
37
  "swagger-ui-express": "^5.0.1",
37
- "@forklaunch/common": "0.3.14",
38
- "@forklaunch/core": "0.9.22",
39
- "@forklaunch/validator": "0.6.16"
38
+ "@forklaunch/common": "0.4.0",
39
+ "@forklaunch/validator": "0.7.0",
40
+ "@forklaunch/core": "0.10.0"
40
41
  },
41
42
  "devDependencies": {
42
- "@eslint/js": "^9.29.0",
43
+ "@eslint/js": "^9.30.0",
43
44
  "@types/body-parser": "^1.19.6",
44
45
  "@types/busboy": "^1.5.4",
45
46
  "@types/cors": "^2.8.19",
@@ -48,16 +49,16 @@
48
49
  "@types/jest": "^30.0.0",
49
50
  "@types/qs": "^6.14.0",
50
51
  "@types/swagger-ui-express": "^4.1.8",
51
- "@typescript/native-preview": "7.0.0-dev.20250619.1",
52
- "jest": "^30.0.2",
52
+ "@typescript/native-preview": "7.0.0-dev.20250630.1",
53
+ "jest": "^30.0.3",
53
54
  "kill-port-process": "^3.2.1",
54
- "prettier": "^3.5.3",
55
+ "prettier": "^3.6.2",
55
56
  "ts-jest": "^29.4.0",
56
57
  "ts-node": "^10.9.2",
57
58
  "tsup": "^8.5.0",
58
- "typedoc": "^0.28.5",
59
+ "typedoc": "^0.28.7",
59
60
  "typescript": "^5.8.3",
60
- "typescript-eslint": "^8.34.1"
61
+ "typescript-eslint": "^8.35.1"
61
62
  },
62
63
  "scripts": {
63
64
  "build": "tsgo --noEmit && tsup index.ts --format cjs,esm --no-splitting --tsconfig tsconfig.json --outDir lib --dts --clean",