@radaros/transport 0.3.26 → 0.3.28

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/dist/index.cjs CHANGED
@@ -168,7 +168,7 @@ function createA2AServer(app, opts) {
168
168
  app.get("/.well-known/agent.json", (_req, res) => {
169
169
  res.json(agentCard);
170
170
  });
171
- app.use(basePath, express.json());
171
+ app.use(basePath, express.json({ limit: "1mb" }));
172
172
  app.post(basePath, async (req, res) => {
173
173
  const body = req.body;
174
174
  if (!body || body.jsonrpc !== "2.0" || !body.method) {
@@ -530,9 +530,14 @@ function createAdminRouter(opts) {
530
530
  if (opts?.middleware) {
531
531
  for (const mw of opts.middleware) router.use(mw);
532
532
  }
533
- if (!opts?.middleware?.length && process.env.NODE_ENV === "production") {
533
+ if (!opts?.middleware?.length) {
534
+ if (process.env.NODE_ENV === "production") {
535
+ throw new Error(
536
+ "[admin-router] Admin routes cannot be mounted without authentication middleware in production. Pass middleware in AdminRouterOptions to secure them."
537
+ );
538
+ }
534
539
  console.warn(
535
- "[admin-router] WARNING: Admin routes mounted without authentication middleware. These endpoints can add MCP servers, execute tools, and modify configurations. Pass middleware in AdminRouterOptions to secure them."
540
+ "[admin-router] WARNING: Admin routes mounted without authentication middleware. These endpoints can add MCP servers, execute tools, and modify configurations. This is allowed in development only. Pass middleware in AdminRouterOptions to secure them."
536
541
  );
537
542
  }
538
543
  router.get("/mcp", (_req, res) => {
@@ -699,7 +704,7 @@ function filesToContentParts(files) {
699
704
  type: partType,
700
705
  data: base64,
701
706
  mimeType: file.mimetype,
702
- ...partType === "file" ? { fileName: file.originalname } : {}
707
+ ...partType === "file" ? { fileName: (file.originalname ?? "attachment").replace(/.*[/\\]/, "").replace(/[^a-zA-Z0-9._-]/g, "_") } : {}
703
708
  };
704
709
  });
705
710
  }
@@ -721,15 +726,18 @@ function errorHandler(options) {
721
726
  const log = options?.logger ?? console;
722
727
  return (err, _req, res, _next) => {
723
728
  log.error("[radaros:transport] Error:", err.message);
724
- res.status(err.statusCode ?? 500).json({
725
- error: err.message ?? "Internal server error"
729
+ const statusCode = err.statusCode ?? 500;
730
+ const isClientError = statusCode >= 400 && statusCode < 500;
731
+ res.status(statusCode).json({
732
+ error: isClientError ? err.message ?? "Bad request" : "Internal server error"
726
733
  });
727
734
  };
728
735
  }
729
736
  function requestLogger(options) {
730
737
  const log = options?.logger ?? console;
731
738
  return (req, _res, next) => {
732
- log.log(`[radaros:transport] ${req.method} ${req.path}`);
739
+ const safePath = String(req.path).replace(/[\x00-\x1f\x7f]/g, "");
740
+ log.log(`[radaros:transport] ${req.method} ${safePath}`);
733
741
  next();
734
742
  };
735
743
  }
@@ -1211,6 +1219,13 @@ function rateLimitMiddleware(config = {}) {
1211
1219
  const windowMs = config.windowMs ?? 6e4;
1212
1220
  const max = config.max ?? 100;
1213
1221
  const hits = /* @__PURE__ */ new Map();
1222
+ const cleanup = setInterval(() => {
1223
+ const now = Date.now();
1224
+ for (const [key, record] of hits) {
1225
+ if (now > record.resetTime) hits.delete(key);
1226
+ }
1227
+ }, windowMs);
1228
+ cleanup.unref();
1214
1229
  return (req, res, next) => {
1215
1230
  const key = req.ip ?? req.socket?.remoteAddress ?? "unknown";
1216
1231
  const now = Date.now();
@@ -1595,7 +1610,8 @@ function createAgentRouter(opts) {
1595
1610
  if (opts.admin) {
1596
1611
  const adminOpts = typeof opts.admin === "object" ? opts.admin : {};
1597
1612
  const { router: adminRouter } = createAdminRouter({
1598
- mcpManager: adminOpts.mcpManager
1613
+ mcpManager: adminOpts.mcpManager,
1614
+ middleware: adminOpts.middleware ?? opts.middleware
1599
1615
  });
1600
1616
  router.use("/admin", adminRouter);
1601
1617
  }
@@ -1977,11 +1993,17 @@ function createVoiceGateway(opts) {
1977
1993
  socket.on("voice.audio", (data) => {
1978
1994
  const session = activeSessions.get(socket.id);
1979
1995
  if (!session) return;
1980
- session.sendAudio(Buffer.from(data.data, "base64"));
1996
+ if (typeof data?.data !== "string" || data.data.length > 1e6) return;
1997
+ try {
1998
+ session.sendAudio(Buffer.from(data.data, "base64"));
1999
+ } catch {
2000
+ socket.emit("voice.error", { error: "Invalid audio data" });
2001
+ }
1981
2002
  });
1982
2003
  socket.on("voice.text", (data) => {
1983
2004
  const session = activeSessions.get(socket.id);
1984
2005
  if (!session) return;
2006
+ if (typeof data?.text !== "string" || data.text.length > 1e4) return;
1985
2007
  session.sendText(data.text);
1986
2008
  });
1987
2009
  socket.on("voice.interrupt", () => {
@@ -1992,7 +2014,11 @@ function createVoiceGateway(opts) {
1992
2014
  socket.on("voice.stop", async () => {
1993
2015
  const session = activeSessions.get(socket.id);
1994
2016
  if (!session) return;
1995
- await session.close();
2017
+ try {
2018
+ await session.close();
2019
+ } catch (err) {
2020
+ console.warn("[voice-gateway] Error closing session:", err);
2021
+ }
1996
2022
  activeSessions.delete(socket.id);
1997
2023
  socket.emit("voice.stopped");
1998
2024
  });
package/dist/index.d.cts CHANGED
@@ -199,6 +199,7 @@ interface RouterOptions {
199
199
  */
200
200
  admin?: boolean | {
201
201
  mcpManager?: MCPManager;
202
+ middleware?: any[];
202
203
  };
203
204
  }
204
205
 
package/dist/index.d.ts CHANGED
@@ -199,6 +199,7 @@ interface RouterOptions {
199
199
  */
200
200
  admin?: boolean | {
201
201
  mcpManager?: MCPManager;
202
+ middleware?: any[];
202
203
  };
203
204
  }
204
205
 
package/dist/index.js CHANGED
@@ -125,7 +125,7 @@ function createA2AServer(app, opts) {
125
125
  app.get("/.well-known/agent.json", (_req, res) => {
126
126
  res.json(agentCard);
127
127
  });
128
- app.use(basePath, express.json());
128
+ app.use(basePath, express.json({ limit: "1mb" }));
129
129
  app.post(basePath, async (req, res) => {
130
130
  const body = req.body;
131
131
  if (!body || body.jsonrpc !== "2.0" || !body.method) {
@@ -487,9 +487,14 @@ function createAdminRouter(opts) {
487
487
  if (opts?.middleware) {
488
488
  for (const mw of opts.middleware) router.use(mw);
489
489
  }
490
- if (!opts?.middleware?.length && process.env.NODE_ENV === "production") {
490
+ if (!opts?.middleware?.length) {
491
+ if (process.env.NODE_ENV === "production") {
492
+ throw new Error(
493
+ "[admin-router] Admin routes cannot be mounted without authentication middleware in production. Pass middleware in AdminRouterOptions to secure them."
494
+ );
495
+ }
491
496
  console.warn(
492
- "[admin-router] WARNING: Admin routes mounted without authentication middleware. These endpoints can add MCP servers, execute tools, and modify configurations. Pass middleware in AdminRouterOptions to secure them."
497
+ "[admin-router] WARNING: Admin routes mounted without authentication middleware. These endpoints can add MCP servers, execute tools, and modify configurations. This is allowed in development only. Pass middleware in AdminRouterOptions to secure them."
493
498
  );
494
499
  }
495
500
  router.get("/mcp", (_req, res) => {
@@ -656,7 +661,7 @@ function filesToContentParts(files) {
656
661
  type: partType,
657
662
  data: base64,
658
663
  mimeType: file.mimetype,
659
- ...partType === "file" ? { fileName: file.originalname } : {}
664
+ ...partType === "file" ? { fileName: (file.originalname ?? "attachment").replace(/.*[/\\]/, "").replace(/[^a-zA-Z0-9._-]/g, "_") } : {}
660
665
  };
661
666
  });
662
667
  }
@@ -678,15 +683,18 @@ function errorHandler(options) {
678
683
  const log = options?.logger ?? console;
679
684
  return (err, _req, res, _next) => {
680
685
  log.error("[radaros:transport] Error:", err.message);
681
- res.status(err.statusCode ?? 500).json({
682
- error: err.message ?? "Internal server error"
686
+ const statusCode = err.statusCode ?? 500;
687
+ const isClientError = statusCode >= 400 && statusCode < 500;
688
+ res.status(statusCode).json({
689
+ error: isClientError ? err.message ?? "Bad request" : "Internal server error"
683
690
  });
684
691
  };
685
692
  }
686
693
  function requestLogger(options) {
687
694
  const log = options?.logger ?? console;
688
695
  return (req, _res, next) => {
689
- log.log(`[radaros:transport] ${req.method} ${req.path}`);
696
+ const safePath = String(req.path).replace(/[\x00-\x1f\x7f]/g, "");
697
+ log.log(`[radaros:transport] ${req.method} ${safePath}`);
690
698
  next();
691
699
  };
692
700
  }
@@ -1168,6 +1176,13 @@ function rateLimitMiddleware(config = {}) {
1168
1176
  const windowMs = config.windowMs ?? 6e4;
1169
1177
  const max = config.max ?? 100;
1170
1178
  const hits = /* @__PURE__ */ new Map();
1179
+ const cleanup = setInterval(() => {
1180
+ const now = Date.now();
1181
+ for (const [key, record] of hits) {
1182
+ if (now > record.resetTime) hits.delete(key);
1183
+ }
1184
+ }, windowMs);
1185
+ cleanup.unref();
1171
1186
  return (req, res, next) => {
1172
1187
  const key = req.ip ?? req.socket?.remoteAddress ?? "unknown";
1173
1188
  const now = Date.now();
@@ -1552,7 +1567,8 @@ function createAgentRouter(opts) {
1552
1567
  if (opts.admin) {
1553
1568
  const adminOpts = typeof opts.admin === "object" ? opts.admin : {};
1554
1569
  const { router: adminRouter } = createAdminRouter({
1555
- mcpManager: adminOpts.mcpManager
1570
+ mcpManager: adminOpts.mcpManager,
1571
+ middleware: adminOpts.middleware ?? opts.middleware
1556
1572
  });
1557
1573
  router.use("/admin", adminRouter);
1558
1574
  }
@@ -1934,11 +1950,17 @@ function createVoiceGateway(opts) {
1934
1950
  socket.on("voice.audio", (data) => {
1935
1951
  const session = activeSessions.get(socket.id);
1936
1952
  if (!session) return;
1937
- session.sendAudio(Buffer.from(data.data, "base64"));
1953
+ if (typeof data?.data !== "string" || data.data.length > 1e6) return;
1954
+ try {
1955
+ session.sendAudio(Buffer.from(data.data, "base64"));
1956
+ } catch {
1957
+ socket.emit("voice.error", { error: "Invalid audio data" });
1958
+ }
1938
1959
  });
1939
1960
  socket.on("voice.text", (data) => {
1940
1961
  const session = activeSessions.get(socket.id);
1941
1962
  if (!session) return;
1963
+ if (typeof data?.text !== "string" || data.text.length > 1e4) return;
1942
1964
  session.sendText(data.text);
1943
1965
  });
1944
1966
  socket.on("voice.interrupt", () => {
@@ -1949,7 +1971,11 @@ function createVoiceGateway(opts) {
1949
1971
  socket.on("voice.stop", async () => {
1950
1972
  const session = activeSessions.get(socket.id);
1951
1973
  if (!session) return;
1952
- await session.close();
1974
+ try {
1975
+ await session.close();
1976
+ } catch (err) {
1977
+ console.warn("[voice-gateway] Error closing session:", err);
1978
+ }
1953
1979
  activeSessions.delete(socket.id);
1954
1980
  socket.emit("voice.stopped");
1955
1981
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radaros/transport",
3
- "version": "0.3.26",
3
+ "version": "0.3.28",
4
4
  "description": "HTTP and WebSocket transport layer for RadarOS agents",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -42,7 +42,7 @@
42
42
  "typescript": "^5.6.0"
43
43
  },
44
44
  "peerDependencies": {
45
- "@radaros/core": "^0.3.26",
45
+ "@radaros/core": "^0.3.28",
46
46
  "@types/express": "^4.0.0 || ^5.0.0",
47
47
  "express": "^4.0.0 || ^5.0.0",
48
48
  "multer": ">=2.0.0",