@radaros/transport 0.3.12 → 0.3.13
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 +45 -0
- package/dist/index.d.ts +15 -2
- package/dist/index.js +86 -5
- package/package.json +17 -2
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# @radaros/transport
|
|
2
|
+
|
|
3
|
+
HTTP and WebSocket transport layer for deploying RadarOS agents as APIs.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @radaros/transport
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import express from "express";
|
|
15
|
+
import { Agent, openai } from "@radaros/core";
|
|
16
|
+
import { createAgentRouter } from "@radaros/transport";
|
|
17
|
+
|
|
18
|
+
const app = express();
|
|
19
|
+
app.use(express.json());
|
|
20
|
+
|
|
21
|
+
const agent = new Agent({
|
|
22
|
+
name: "assistant",
|
|
23
|
+
model: openai("gpt-4o"),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
app.use("/api", createAgentRouter({ agents: { assistant: agent } }));
|
|
27
|
+
app.listen(3000);
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Features
|
|
31
|
+
|
|
32
|
+
- **Express Router** — REST API with streaming support
|
|
33
|
+
- **Socket.IO Gateway** — Real-time WebSocket communication
|
|
34
|
+
- **A2A Server** — Agent-to-Agent protocol support
|
|
35
|
+
- **CORS & Rate Limiting** — Built-in security middleware
|
|
36
|
+
- **Swagger** — Auto-generated API documentation
|
|
37
|
+
- **File Upload** — Multipart form data support
|
|
38
|
+
|
|
39
|
+
## Documentation
|
|
40
|
+
|
|
41
|
+
Full docs at [radaros.mintlify.dev](https://radaros.mintlify.dev)
|
|
42
|
+
|
|
43
|
+
## License
|
|
44
|
+
|
|
45
|
+
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -42,8 +42,12 @@ interface FileUploadOptions {
|
|
|
42
42
|
declare function createFileUploadMiddleware(opts?: FileUploadOptions): any;
|
|
43
43
|
declare function buildMultiModalInput(body: any, files?: any[]): string | any[];
|
|
44
44
|
|
|
45
|
-
declare function errorHandler(
|
|
46
|
-
|
|
45
|
+
declare function errorHandler(options?: {
|
|
46
|
+
logger?: Pick<Console, "error">;
|
|
47
|
+
}): (err: any, _req: any, res: any, _next: any) => void;
|
|
48
|
+
declare function requestLogger(options?: {
|
|
49
|
+
logger?: Pick<Console, "log">;
|
|
50
|
+
}): (req: any, _res: any, next: any) => void;
|
|
47
51
|
|
|
48
52
|
interface SwaggerOptions {
|
|
49
53
|
/** Enable Swagger UI at /docs. Default: false */
|
|
@@ -75,6 +79,13 @@ interface RouterOptions {
|
|
|
75
79
|
swagger?: SwaggerOptions;
|
|
76
80
|
/** File upload configuration for multi-modal inputs */
|
|
77
81
|
fileUpload?: boolean | FileUploadOptions;
|
|
82
|
+
/** CORS configuration. Pass true or '*' for permissive, a string for a single origin, or an array for multiple origins. */
|
|
83
|
+
cors?: string | string[] | boolean;
|
|
84
|
+
/** Rate limiting configuration. Pass true for defaults (100 req/min), or an object to customize. */
|
|
85
|
+
rateLimit?: {
|
|
86
|
+
windowMs?: number;
|
|
87
|
+
max?: number;
|
|
88
|
+
} | boolean;
|
|
78
89
|
}
|
|
79
90
|
|
|
80
91
|
declare function createAgentRouter(opts: RouterOptions): any;
|
|
@@ -169,6 +180,8 @@ interface GatewayOptions {
|
|
|
169
180
|
io: any;
|
|
170
181
|
namespace?: string;
|
|
171
182
|
authMiddleware?: (socket: any, next: (err?: Error) => void) => void;
|
|
183
|
+
/** Max requests per minute per socket. Default: 60 */
|
|
184
|
+
maxRequestsPerMinute?: number;
|
|
172
185
|
}
|
|
173
186
|
|
|
174
187
|
declare function createAgentGateway(opts: GatewayOptions): void;
|
package/dist/index.js
CHANGED
|
@@ -412,17 +412,19 @@ function buildMultiModalInput(body, files) {
|
|
|
412
412
|
}
|
|
413
413
|
|
|
414
414
|
// src/express/middleware.ts
|
|
415
|
-
function errorHandler() {
|
|
415
|
+
function errorHandler(options) {
|
|
416
|
+
const log = options?.logger ?? console;
|
|
416
417
|
return (err, _req, res, _next) => {
|
|
417
|
-
|
|
418
|
+
log.error("[radaros:transport] Error:", err.message);
|
|
418
419
|
res.status(err.statusCode ?? 500).json({
|
|
419
420
|
error: err.message ?? "Internal server error"
|
|
420
421
|
});
|
|
421
422
|
};
|
|
422
423
|
}
|
|
423
|
-
function requestLogger() {
|
|
424
|
+
function requestLogger(options) {
|
|
425
|
+
const log = options?.logger ?? console;
|
|
424
426
|
return (req, _res, next) => {
|
|
425
|
-
|
|
427
|
+
log.log(`[radaros:transport] ${req.method} ${req.path}`);
|
|
426
428
|
next();
|
|
427
429
|
};
|
|
428
430
|
}
|
|
@@ -873,6 +875,53 @@ function serveSwaggerUI(spec) {
|
|
|
873
875
|
|
|
874
876
|
// src/express/router-factory.ts
|
|
875
877
|
var _require4 = createRequire4(import.meta.url);
|
|
878
|
+
function corsMiddleware(origins) {
|
|
879
|
+
return (req, res, next) => {
|
|
880
|
+
const origin = req.headers.origin;
|
|
881
|
+
let allowed = false;
|
|
882
|
+
if (origins === true || origins === "*") {
|
|
883
|
+
allowed = true;
|
|
884
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
885
|
+
} else if (typeof origins === "string") {
|
|
886
|
+
allowed = origin === origins;
|
|
887
|
+
if (allowed) res.setHeader("Access-Control-Allow-Origin", origin);
|
|
888
|
+
} else if (Array.isArray(origins)) {
|
|
889
|
+
allowed = origins.includes(origin);
|
|
890
|
+
if (allowed) res.setHeader("Access-Control-Allow-Origin", origin);
|
|
891
|
+
}
|
|
892
|
+
if (allowed) {
|
|
893
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
|
|
894
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-API-Key");
|
|
895
|
+
res.setHeader("Access-Control-Max-Age", "86400");
|
|
896
|
+
}
|
|
897
|
+
if (req.method === "OPTIONS") {
|
|
898
|
+
res.status(204).end();
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
next();
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
function rateLimitMiddleware(config = {}) {
|
|
905
|
+
const windowMs = config.windowMs ?? 6e4;
|
|
906
|
+
const max = config.max ?? 100;
|
|
907
|
+
const hits = /* @__PURE__ */ new Map();
|
|
908
|
+
return (req, res, next) => {
|
|
909
|
+
const key = req.ip ?? req.socket?.remoteAddress ?? "unknown";
|
|
910
|
+
const now = Date.now();
|
|
911
|
+
const record = hits.get(key);
|
|
912
|
+
if (!record || now > record.resetTime) {
|
|
913
|
+
hits.set(key, { count: 1, resetTime: now + windowMs });
|
|
914
|
+
next();
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
record.count++;
|
|
918
|
+
if (record.count > max) {
|
|
919
|
+
res.status(429).json({ error: "Too many requests, please try again later" });
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
next();
|
|
923
|
+
};
|
|
924
|
+
}
|
|
876
925
|
var API_KEY_HEADERS = {
|
|
877
926
|
"x-openai-api-key": "openai",
|
|
878
927
|
"x-google-api-key": "google",
|
|
@@ -913,6 +962,13 @@ function createAgentRouter(opts) {
|
|
|
913
962
|
throw new Error("express is required for createAgentRouter. Install it: npm install express");
|
|
914
963
|
}
|
|
915
964
|
const router = express.Router();
|
|
965
|
+
if (opts.cors) {
|
|
966
|
+
router.use(corsMiddleware(opts.cors));
|
|
967
|
+
}
|
|
968
|
+
if (opts.rateLimit) {
|
|
969
|
+
const config = opts.rateLimit === true ? {} : opts.rateLimit;
|
|
970
|
+
router.use(rateLimitMiddleware(config));
|
|
971
|
+
}
|
|
916
972
|
if (opts.middleware) {
|
|
917
973
|
for (const mw of opts.middleware) {
|
|
918
974
|
router.use(mw);
|
|
@@ -1205,13 +1261,34 @@ function createBrowserGateway(opts) {
|
|
|
1205
1261
|
}
|
|
1206
1262
|
|
|
1207
1263
|
// src/socketio/gateway.ts
|
|
1264
|
+
function createSocketRateLimiter(maxPerMinute = 60) {
|
|
1265
|
+
return () => {
|
|
1266
|
+
let count = 0;
|
|
1267
|
+
let resetTime = Date.now() + 6e4;
|
|
1268
|
+
return () => {
|
|
1269
|
+
const now = Date.now();
|
|
1270
|
+
if (now > resetTime) {
|
|
1271
|
+
count = 0;
|
|
1272
|
+
resetTime = now + 6e4;
|
|
1273
|
+
}
|
|
1274
|
+
count++;
|
|
1275
|
+
return count <= maxPerMinute;
|
|
1276
|
+
};
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1208
1279
|
function createAgentGateway(opts) {
|
|
1209
1280
|
const ns = opts.io.of(opts.namespace ?? "/radaros");
|
|
1210
1281
|
if (opts.authMiddleware) {
|
|
1211
1282
|
ns.use(opts.authMiddleware);
|
|
1212
1283
|
}
|
|
1284
|
+
const rateLimiterFactory = createSocketRateLimiter(opts.maxRequestsPerMinute ?? 60);
|
|
1213
1285
|
ns.on("connection", (socket) => {
|
|
1286
|
+
const checkRate = rateLimiterFactory();
|
|
1214
1287
|
socket.on("agent.run", async (data) => {
|
|
1288
|
+
if (!checkRate()) {
|
|
1289
|
+
socket.emit("agent.error", { error: "Rate limit exceeded" });
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1215
1292
|
if (!data || typeof data.input !== "string" || !data.input.trim()) {
|
|
1216
1293
|
socket.emit("agent.error", { error: "Invalid input: must be a non-empty string" });
|
|
1217
1294
|
return;
|
|
@@ -1380,7 +1457,11 @@ function createVoiceGateway(opts) {
|
|
|
1380
1457
|
if (session) {
|
|
1381
1458
|
try {
|
|
1382
1459
|
await session.close();
|
|
1383
|
-
} catch {
|
|
1460
|
+
} catch (err) {
|
|
1461
|
+
console.warn(
|
|
1462
|
+
"[radaros/voice-gateway] Error closing session on disconnect:",
|
|
1463
|
+
err instanceof Error ? err.message : err
|
|
1464
|
+
);
|
|
1384
1465
|
}
|
|
1385
1466
|
activeSessions.delete(socket.id);
|
|
1386
1467
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@radaros/transport",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.13",
|
|
4
|
+
"description": "HTTP and WebSocket transport layer for RadarOS agents",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/xhipment/agentOs.git",
|
|
9
|
+
"directory": "packages/transport"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"ai",
|
|
13
|
+
"agents",
|
|
14
|
+
"express",
|
|
15
|
+
"socketio",
|
|
16
|
+
"api",
|
|
17
|
+
"transport"
|
|
18
|
+
],
|
|
4
19
|
"type": "module",
|
|
5
20
|
"main": "./dist/index.js",
|
|
6
21
|
"types": "./dist/index.d.ts",
|
|
@@ -24,7 +39,7 @@
|
|
|
24
39
|
"typescript": "^5.6.0"
|
|
25
40
|
},
|
|
26
41
|
"peerDependencies": {
|
|
27
|
-
"@radaros/core": "^0.3.
|
|
42
|
+
"@radaros/core": "^0.3.13",
|
|
28
43
|
"@types/express": "^4.0.0 || ^5.0.0",
|
|
29
44
|
"express": "^4.0.0 || ^5.0.0",
|
|
30
45
|
"multer": ">=2.0.0",
|