@dexto/server 1.2.5
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/LICENSE +44 -0
- package/dist/a2a/adapters/index.cjs +42 -0
- package/dist/a2a/adapters/index.d.ts +10 -0
- package/dist/a2a/adapters/index.d.ts.map +1 -0
- package/dist/a2a/adapters/index.js +12 -0
- package/dist/a2a/adapters/message.cjs +193 -0
- package/dist/a2a/adapters/message.d.ts +50 -0
- package/dist/a2a/adapters/message.d.ts.map +1 -0
- package/dist/a2a/adapters/message.js +167 -0
- package/dist/a2a/adapters/state.cjs +57 -0
- package/dist/a2a/adapters/state.d.ts +36 -0
- package/dist/a2a/adapters/state.d.ts.map +1 -0
- package/dist/a2a/adapters/state.js +32 -0
- package/dist/a2a/adapters/task-view.cjs +85 -0
- package/dist/a2a/adapters/task-view.d.ts +58 -0
- package/dist/a2a/adapters/task-view.d.ts.map +1 -0
- package/dist/a2a/adapters/task-view.js +60 -0
- package/dist/a2a/index.cjs +51 -0
- package/dist/a2a/index.d.ts +15 -0
- package/dist/a2a/index.d.ts.map +1 -0
- package/dist/a2a/index.js +30 -0
- package/dist/a2a/jsonrpc/index.cjs +38 -0
- package/dist/a2a/jsonrpc/index.d.ts +11 -0
- package/dist/a2a/jsonrpc/index.d.ts.map +1 -0
- package/dist/a2a/jsonrpc/index.js +10 -0
- package/dist/a2a/jsonrpc/methods.cjs +183 -0
- package/dist/a2a/jsonrpc/methods.d.ts +110 -0
- package/dist/a2a/jsonrpc/methods.d.ts.map +1 -0
- package/dist/a2a/jsonrpc/methods.js +159 -0
- package/dist/a2a/jsonrpc/server.cjs +199 -0
- package/dist/a2a/jsonrpc/server.d.ts +100 -0
- package/dist/a2a/jsonrpc/server.d.ts.map +1 -0
- package/dist/a2a/jsonrpc/server.js +175 -0
- package/dist/a2a/jsonrpc/types.cjs +47 -0
- package/dist/a2a/jsonrpc/types.d.ts +91 -0
- package/dist/a2a/jsonrpc/types.d.ts.map +1 -0
- package/dist/a2a/jsonrpc/types.js +21 -0
- package/dist/a2a/types.cjs +16 -0
- package/dist/a2a/types.d.ts +250 -0
- package/dist/a2a/types.d.ts.map +1 -0
- package/dist/a2a/types.js +0 -0
- package/dist/approval/approval-coordinator.cjs +87 -0
- package/dist/approval/approval-coordinator.d.ts +52 -0
- package/dist/approval/approval-coordinator.d.ts.map +1 -0
- package/dist/approval/approval-coordinator.js +63 -0
- package/dist/approval/manual-approval-handler.cjs +100 -0
- package/dist/approval/manual-approval-handler.d.ts +32 -0
- package/dist/approval/manual-approval-handler.d.ts.map +1 -0
- package/dist/approval/manual-approval-handler.js +76 -0
- package/dist/events/a2a-sse-subscriber.cjs +271 -0
- package/dist/events/a2a-sse-subscriber.d.ts +94 -0
- package/dist/events/a2a-sse-subscriber.d.ts.map +1 -0
- package/dist/events/a2a-sse-subscriber.js +247 -0
- package/dist/events/types.cjs +16 -0
- package/dist/events/types.d.ts +15 -0
- package/dist/events/types.d.ts.map +1 -0
- package/dist/events/types.js +0 -0
- package/dist/events/webhook-subscriber.cjs +301 -0
- package/dist/events/webhook-subscriber.d.ts +64 -0
- package/dist/events/webhook-subscriber.d.ts.map +1 -0
- package/dist/events/webhook-subscriber.js +269 -0
- package/dist/events/webhook-types.cjs +16 -0
- package/dist/events/webhook-types.d.ts +91 -0
- package/dist/events/webhook-types.d.ts.map +1 -0
- package/dist/events/webhook-types.js +0 -0
- package/dist/hono/__tests__/test-fixtures.cjs +236 -0
- package/dist/hono/__tests__/test-fixtures.d.ts +65 -0
- package/dist/hono/__tests__/test-fixtures.d.ts.map +1 -0
- package/dist/hono/__tests__/test-fixtures.js +197 -0
- package/dist/hono/index.cjs +166 -0
- package/dist/hono/index.d.ts +2783 -0
- package/dist/hono/index.d.ts.map +1 -0
- package/dist/hono/index.js +141 -0
- package/dist/hono/middleware/auth.cjs +75 -0
- package/dist/hono/middleware/auth.d.ts +3 -0
- package/dist/hono/middleware/auth.d.ts.map +1 -0
- package/dist/hono/middleware/auth.js +51 -0
- package/dist/hono/middleware/cors.cjs +57 -0
- package/dist/hono/middleware/cors.d.ts +9 -0
- package/dist/hono/middleware/cors.d.ts.map +1 -0
- package/dist/hono/middleware/cors.js +33 -0
- package/dist/hono/middleware/error.cjs +131 -0
- package/dist/hono/middleware/error.d.ts +5 -0
- package/dist/hono/middleware/error.d.ts.map +1 -0
- package/dist/hono/middleware/error.js +105 -0
- package/dist/hono/middleware/redaction.cjs +45 -0
- package/dist/hono/middleware/redaction.d.ts +4 -0
- package/dist/hono/middleware/redaction.d.ts.map +1 -0
- package/dist/hono/middleware/redaction.js +20 -0
- package/dist/hono/node/index.cjs +139 -0
- package/dist/hono/node/index.d.ts +19 -0
- package/dist/hono/node/index.d.ts.map +1 -0
- package/dist/hono/node/index.js +115 -0
- package/dist/hono/routes/a2a-jsonrpc.cjs +119 -0
- package/dist/hono/routes/a2a-jsonrpc.d.ts +46 -0
- package/dist/hono/routes/a2a-jsonrpc.d.ts.map +1 -0
- package/dist/hono/routes/a2a-jsonrpc.js +95 -0
- package/dist/hono/routes/a2a-tasks.cjs +315 -0
- package/dist/hono/routes/a2a-tasks.d.ts +530 -0
- package/dist/hono/routes/a2a-tasks.d.ts.map +1 -0
- package/dist/hono/routes/a2a-tasks.js +291 -0
- package/dist/hono/routes/a2a.cjs +36 -0
- package/dist/hono/routes/a2a.d.ts +4 -0
- package/dist/hono/routes/a2a.d.ts.map +1 -0
- package/dist/hono/routes/a2a.js +12 -0
- package/dist/hono/routes/agents.cjs +735 -0
- package/dist/hono/routes/agents.d.ts +650 -0
- package/dist/hono/routes/agents.d.ts.map +1 -0
- package/dist/hono/routes/agents.js +711 -0
- package/dist/hono/routes/approvals.cjs +125 -0
- package/dist/hono/routes/approvals.d.ts +89 -0
- package/dist/hono/routes/approvals.d.ts.map +1 -0
- package/dist/hono/routes/approvals.js +101 -0
- package/dist/hono/routes/greeting.cjs +60 -0
- package/dist/hono/routes/greeting.d.ts +19 -0
- package/dist/hono/routes/greeting.d.ts.map +1 -0
- package/dist/hono/routes/greeting.js +36 -0
- package/dist/hono/routes/health.cjs +45 -0
- package/dist/hono/routes/health.d.ts +17 -0
- package/dist/hono/routes/health.d.ts.map +1 -0
- package/dist/hono/routes/health.js +21 -0
- package/dist/hono/routes/llm.cjs +298 -0
- package/dist/hono/routes/llm.d.ts +294 -0
- package/dist/hono/routes/llm.d.ts.map +1 -0
- package/dist/hono/routes/llm.js +287 -0
- package/dist/hono/routes/mcp.cjs +356 -0
- package/dist/hono/routes/mcp.d.ts +246 -0
- package/dist/hono/routes/mcp.d.ts.map +1 -0
- package/dist/hono/routes/mcp.js +332 -0
- package/dist/hono/routes/memory.cjs +192 -0
- package/dist/hono/routes/memory.d.ts +146 -0
- package/dist/hono/routes/memory.d.ts.map +1 -0
- package/dist/hono/routes/memory.js +168 -0
- package/dist/hono/routes/messages.cjs +320 -0
- package/dist/hono/routes/messages.d.ts +163 -0
- package/dist/hono/routes/messages.d.ts.map +1 -0
- package/dist/hono/routes/messages.js +296 -0
- package/dist/hono/routes/prompts.cjs +228 -0
- package/dist/hono/routes/prompts.d.ts +150 -0
- package/dist/hono/routes/prompts.d.ts.map +1 -0
- package/dist/hono/routes/prompts.js +204 -0
- package/dist/hono/routes/resources.cjs +110 -0
- package/dist/hono/routes/resources.d.ts +76 -0
- package/dist/hono/routes/resources.d.ts.map +1 -0
- package/dist/hono/routes/resources.js +86 -0
- package/dist/hono/routes/search.cjs +109 -0
- package/dist/hono/routes/search.d.ts +137 -0
- package/dist/hono/routes/search.d.ts.map +1 -0
- package/dist/hono/routes/search.js +85 -0
- package/dist/hono/routes/sessions.cjs +366 -0
- package/dist/hono/routes/sessions.d.ts +229 -0
- package/dist/hono/routes/sessions.d.ts.map +1 -0
- package/dist/hono/routes/sessions.js +342 -0
- package/dist/hono/routes/webhooks.cjs +228 -0
- package/dist/hono/routes/webhooks.d.ts +127 -0
- package/dist/hono/routes/webhooks.d.ts.map +1 -0
- package/dist/hono/routes/webhooks.js +204 -0
- package/dist/hono/schemas/responses.cjs +276 -0
- package/dist/hono/schemas/responses.d.ts +1418 -0
- package/dist/hono/schemas/responses.d.ts.map +1 -0
- package/dist/hono/schemas/responses.js +227 -0
- package/dist/hono/types.cjs +16 -0
- package/dist/hono/types.d.ts +6 -0
- package/dist/hono/types.d.ts.map +1 -0
- package/dist/hono/types.js +0 -0
- package/dist/index.cjs +38 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/mcp/mcp-handler.cjs +145 -0
- package/dist/mcp/mcp-handler.d.ts +14 -0
- package/dist/mcp/mcp-handler.d.ts.map +1 -0
- package/dist/mcp/mcp-handler.js +118 -0
- package/package.json +59 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var redaction_exports = {};
|
|
20
|
+
__export(redaction_exports, {
|
|
21
|
+
prettyJsonMiddleware: () => prettyJsonMiddleware,
|
|
22
|
+
redactionMiddleware: () => redactionMiddleware
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(redaction_exports);
|
|
25
|
+
var import_pretty_json = require("hono/pretty-json");
|
|
26
|
+
var import_core = require("@dexto/core");
|
|
27
|
+
const prettyJsonMiddleware = (0, import_pretty_json.prettyJSON)();
|
|
28
|
+
const redactionMiddleware = async (ctx, next) => {
|
|
29
|
+
const originalJson = ctx.json.bind(ctx);
|
|
30
|
+
ctx.json = ((data, status, headers) => {
|
|
31
|
+
const redacted = (0, import_core.redactSensitiveData)(data);
|
|
32
|
+
return originalJson(redacted, status, headers);
|
|
33
|
+
});
|
|
34
|
+
const originalBody = ctx.body.bind(ctx);
|
|
35
|
+
ctx.body = ((data, status, headers) => {
|
|
36
|
+
const payload = typeof data === "string" ? (0, import_core.redactSensitiveData)(data) : data;
|
|
37
|
+
return originalBody(payload, status, headers);
|
|
38
|
+
});
|
|
39
|
+
await next();
|
|
40
|
+
};
|
|
41
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
42
|
+
0 && (module.exports = {
|
|
43
|
+
prettyJsonMiddleware,
|
|
44
|
+
redactionMiddleware
|
|
45
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../../../src/hono/middleware/redaction.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAG9C,eAAO,MAAM,oBAAoB,mBAAe,CAAC;AAEjD,eAAO,MAAM,mBAAmB,EAAE,iBAejC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { prettyJSON } from "hono/pretty-json";
|
|
2
|
+
import { redactSensitiveData } from "@dexto/core";
|
|
3
|
+
const prettyJsonMiddleware = prettyJSON();
|
|
4
|
+
const redactionMiddleware = async (ctx, next) => {
|
|
5
|
+
const originalJson = ctx.json.bind(ctx);
|
|
6
|
+
ctx.json = ((data, status, headers) => {
|
|
7
|
+
const redacted = redactSensitiveData(data);
|
|
8
|
+
return originalJson(redacted, status, headers);
|
|
9
|
+
});
|
|
10
|
+
const originalBody = ctx.body.bind(ctx);
|
|
11
|
+
ctx.body = ((data, status, headers) => {
|
|
12
|
+
const payload = typeof data === "string" ? redactSensitiveData(data) : data;
|
|
13
|
+
return originalBody(payload, status, headers);
|
|
14
|
+
});
|
|
15
|
+
await next();
|
|
16
|
+
};
|
|
17
|
+
export {
|
|
18
|
+
prettyJsonMiddleware,
|
|
19
|
+
redactionMiddleware
|
|
20
|
+
};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var node_exports = {};
|
|
20
|
+
__export(node_exports, {
|
|
21
|
+
createNodeServer: () => createNodeServer
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(node_exports);
|
|
24
|
+
var import_node_http = require("node:http");
|
|
25
|
+
var import_node_stream = require("node:stream");
|
|
26
|
+
var import_core = require("@dexto/core");
|
|
27
|
+
function createNodeServer(app, options) {
|
|
28
|
+
const { getAgent: _getAgent } = options;
|
|
29
|
+
const webhookSubscriber = app.webhookSubscriber;
|
|
30
|
+
const server = (0, import_node_http.createServer)(async (req, res) => {
|
|
31
|
+
try {
|
|
32
|
+
if (options.mcpHandlers && req.url?.startsWith("/mcp")) {
|
|
33
|
+
if (req.method === "GET") {
|
|
34
|
+
await options.mcpHandlers.handleGet(req, res);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (req.method === "POST") {
|
|
38
|
+
req.setEncoding("utf8");
|
|
39
|
+
let body = "";
|
|
40
|
+
const MAX_BODY_SIZE = 10 * 1024 * 1024;
|
|
41
|
+
req.on("data", (chunk) => {
|
|
42
|
+
body += chunk;
|
|
43
|
+
if (body.length > MAX_BODY_SIZE) {
|
|
44
|
+
req.destroy();
|
|
45
|
+
res.statusCode = 413;
|
|
46
|
+
res.end("Payload too large");
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
req.on("end", async () => {
|
|
50
|
+
try {
|
|
51
|
+
const parsed = body.length > 0 ? JSON.parse(body) : void 0;
|
|
52
|
+
await options.mcpHandlers.handlePost(req, res, parsed);
|
|
53
|
+
} catch (err) {
|
|
54
|
+
import_core.logger.error(`Failed to process MCP POST body: ${String(err)}`);
|
|
55
|
+
res.statusCode = 400;
|
|
56
|
+
res.end("Invalid JSON body");
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
req.on("error", (err) => {
|
|
60
|
+
import_core.logger.error(`Error reading MCP POST body: ${String(err)}`);
|
|
61
|
+
res.statusCode = 500;
|
|
62
|
+
res.end("Failed to read request body");
|
|
63
|
+
});
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const request = await toRequest(req);
|
|
68
|
+
const response = await app.fetch(request);
|
|
69
|
+
await sendNodeResponse(res, response);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
72
|
+
import_core.logger.error(`Unhandled error in Node bridge: ${message}`, { error });
|
|
73
|
+
res.statusCode = 500;
|
|
74
|
+
res.end("Internal Server Error");
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
server.on("close", () => {
|
|
78
|
+
webhookSubscriber?.cleanup?.();
|
|
79
|
+
});
|
|
80
|
+
if (typeof options.port === "number") {
|
|
81
|
+
const hostname = options.hostname ?? "0.0.0.0";
|
|
82
|
+
server.listen(options.port, hostname, () => {
|
|
83
|
+
import_core.logger.info(`Hono Node bridge listening on http://${hostname}:${options.port}`);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const result = {
|
|
87
|
+
server
|
|
88
|
+
};
|
|
89
|
+
if (webhookSubscriber) {
|
|
90
|
+
result.webhookSubscriber = webhookSubscriber;
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
async function toRequest(req) {
|
|
95
|
+
const protocol = req.socket?.encrypted ? "https" : "http";
|
|
96
|
+
const host = req.headers.host ?? "localhost";
|
|
97
|
+
const url = new URL(req.url ?? "/", `${protocol}://${host}`);
|
|
98
|
+
const headers = new globalThis.Headers();
|
|
99
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
100
|
+
if (value === void 0) continue;
|
|
101
|
+
if (Array.isArray(value)) {
|
|
102
|
+
value.forEach((entry) => headers.append(key, entry));
|
|
103
|
+
} else {
|
|
104
|
+
headers.set(key, value);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const method = req.method ?? "GET";
|
|
108
|
+
const body = method === "GET" || method === "HEAD" ? null : req;
|
|
109
|
+
return new globalThis.Request(url, {
|
|
110
|
+
method,
|
|
111
|
+
headers,
|
|
112
|
+
body: body ?? void 0,
|
|
113
|
+
duplex: body ? "half" : void 0
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
async function sendNodeResponse(res, response) {
|
|
117
|
+
res.statusCode = response.status;
|
|
118
|
+
response.headers.forEach((value, key) => {
|
|
119
|
+
if (key.toLowerCase() === "content-length") {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
res.setHeader(key, value);
|
|
123
|
+
});
|
|
124
|
+
if (!response.body) {
|
|
125
|
+
res.end();
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const webStream = response.body;
|
|
129
|
+
const readable = import_node_stream.Readable.fromWeb(webStream);
|
|
130
|
+
await new Promise((resolve, reject) => {
|
|
131
|
+
readable.on("error", reject);
|
|
132
|
+
res.on("finish", resolve);
|
|
133
|
+
readable.pipe(res);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
137
|
+
0 && (module.exports = {
|
|
138
|
+
createNodeServer
|
|
139
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';
|
|
2
|
+
import type { DextoApp } from '../types.js';
|
|
3
|
+
import type { DextoAgent } from '@dexto/core';
|
|
4
|
+
import type { WebhookEventSubscriber } from '../../events/webhook-subscriber.js';
|
|
5
|
+
export type NodeBridgeOptions = {
|
|
6
|
+
getAgent: () => DextoAgent;
|
|
7
|
+
port?: number;
|
|
8
|
+
hostname?: string;
|
|
9
|
+
mcpHandlers?: {
|
|
10
|
+
handlePost: (req: IncomingMessage, res: ServerResponse, body: unknown) => Promise<void> | void;
|
|
11
|
+
handleGet: (req: IncomingMessage, res: ServerResponse) => Promise<void> | void;
|
|
12
|
+
} | null;
|
|
13
|
+
};
|
|
14
|
+
export type NodeBridgeResult = {
|
|
15
|
+
server: ReturnType<typeof createServer>;
|
|
16
|
+
webhookSubscriber?: WebhookEventSubscriber;
|
|
17
|
+
};
|
|
18
|
+
export declare function createNodeServer(app: DextoApp, options: NodeBridgeOptions): NodeBridgeResult;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hono/node/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAGpF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAKjF,MAAM,MAAM,iBAAiB,GAAG;IAC5B,QAAQ,EAAE,MAAM,UAAU,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE;QACV,UAAU,EAAE,CACR,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,OAAO,KACZ,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QAC1B,SAAS,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;KAClF,GAAG,IAAI,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC3B,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;IACxC,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;CAC9C,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAyE5F"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { Readable } from "node:stream";
|
|
3
|
+
import { logger } from "@dexto/core";
|
|
4
|
+
function createNodeServer(app, options) {
|
|
5
|
+
const { getAgent: _getAgent } = options;
|
|
6
|
+
const webhookSubscriber = app.webhookSubscriber;
|
|
7
|
+
const server = createServer(async (req, res) => {
|
|
8
|
+
try {
|
|
9
|
+
if (options.mcpHandlers && req.url?.startsWith("/mcp")) {
|
|
10
|
+
if (req.method === "GET") {
|
|
11
|
+
await options.mcpHandlers.handleGet(req, res);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (req.method === "POST") {
|
|
15
|
+
req.setEncoding("utf8");
|
|
16
|
+
let body = "";
|
|
17
|
+
const MAX_BODY_SIZE = 10 * 1024 * 1024;
|
|
18
|
+
req.on("data", (chunk) => {
|
|
19
|
+
body += chunk;
|
|
20
|
+
if (body.length > MAX_BODY_SIZE) {
|
|
21
|
+
req.destroy();
|
|
22
|
+
res.statusCode = 413;
|
|
23
|
+
res.end("Payload too large");
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
req.on("end", async () => {
|
|
27
|
+
try {
|
|
28
|
+
const parsed = body.length > 0 ? JSON.parse(body) : void 0;
|
|
29
|
+
await options.mcpHandlers.handlePost(req, res, parsed);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
logger.error(`Failed to process MCP POST body: ${String(err)}`);
|
|
32
|
+
res.statusCode = 400;
|
|
33
|
+
res.end("Invalid JSON body");
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
req.on("error", (err) => {
|
|
37
|
+
logger.error(`Error reading MCP POST body: ${String(err)}`);
|
|
38
|
+
res.statusCode = 500;
|
|
39
|
+
res.end("Failed to read request body");
|
|
40
|
+
});
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const request = await toRequest(req);
|
|
45
|
+
const response = await app.fetch(request);
|
|
46
|
+
await sendNodeResponse(res, response);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
49
|
+
logger.error(`Unhandled error in Node bridge: ${message}`, { error });
|
|
50
|
+
res.statusCode = 500;
|
|
51
|
+
res.end("Internal Server Error");
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
server.on("close", () => {
|
|
55
|
+
webhookSubscriber?.cleanup?.();
|
|
56
|
+
});
|
|
57
|
+
if (typeof options.port === "number") {
|
|
58
|
+
const hostname = options.hostname ?? "0.0.0.0";
|
|
59
|
+
server.listen(options.port, hostname, () => {
|
|
60
|
+
logger.info(`Hono Node bridge listening on http://${hostname}:${options.port}`);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const result = {
|
|
64
|
+
server
|
|
65
|
+
};
|
|
66
|
+
if (webhookSubscriber) {
|
|
67
|
+
result.webhookSubscriber = webhookSubscriber;
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
async function toRequest(req) {
|
|
72
|
+
const protocol = req.socket?.encrypted ? "https" : "http";
|
|
73
|
+
const host = req.headers.host ?? "localhost";
|
|
74
|
+
const url = new URL(req.url ?? "/", `${protocol}://${host}`);
|
|
75
|
+
const headers = new globalThis.Headers();
|
|
76
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
77
|
+
if (value === void 0) continue;
|
|
78
|
+
if (Array.isArray(value)) {
|
|
79
|
+
value.forEach((entry) => headers.append(key, entry));
|
|
80
|
+
} else {
|
|
81
|
+
headers.set(key, value);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const method = req.method ?? "GET";
|
|
85
|
+
const body = method === "GET" || method === "HEAD" ? null : req;
|
|
86
|
+
return new globalThis.Request(url, {
|
|
87
|
+
method,
|
|
88
|
+
headers,
|
|
89
|
+
body: body ?? void 0,
|
|
90
|
+
duplex: body ? "half" : void 0
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
async function sendNodeResponse(res, response) {
|
|
94
|
+
res.statusCode = response.status;
|
|
95
|
+
response.headers.forEach((value, key) => {
|
|
96
|
+
if (key.toLowerCase() === "content-length") {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
res.setHeader(key, value);
|
|
100
|
+
});
|
|
101
|
+
if (!response.body) {
|
|
102
|
+
res.end();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const webStream = response.body;
|
|
106
|
+
const readable = Readable.fromWeb(webStream);
|
|
107
|
+
await new Promise((resolve, reject) => {
|
|
108
|
+
readable.on("error", reject);
|
|
109
|
+
res.on("finish", resolve);
|
|
110
|
+
readable.pipe(res);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
export {
|
|
114
|
+
createNodeServer
|
|
115
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var a2a_jsonrpc_exports = {};
|
|
20
|
+
__export(a2a_jsonrpc_exports, {
|
|
21
|
+
createA2AJsonRpcRouter: () => createA2AJsonRpcRouter
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(a2a_jsonrpc_exports);
|
|
24
|
+
var import_hono = require("hono");
|
|
25
|
+
var import_server = require("../../a2a/jsonrpc/server.js");
|
|
26
|
+
var import_methods = require("../../a2a/jsonrpc/methods.js");
|
|
27
|
+
var import_core = require("@dexto/core");
|
|
28
|
+
var import_message = require("../../a2a/adapters/message.js");
|
|
29
|
+
function createA2AJsonRpcRouter(getAgent, sseSubscriber) {
|
|
30
|
+
const app = new import_hono.Hono();
|
|
31
|
+
app.post("/jsonrpc", async (ctx) => {
|
|
32
|
+
try {
|
|
33
|
+
const agent = getAgent();
|
|
34
|
+
const requestBody = await ctx.req.json();
|
|
35
|
+
const isStreamingRequest = !Array.isArray(requestBody) && requestBody.method === "message/stream";
|
|
36
|
+
if (isStreamingRequest) {
|
|
37
|
+
import_core.logger.info("JSON-RPC streaming request: message/stream");
|
|
38
|
+
const params = requestBody.params;
|
|
39
|
+
if (!params?.message) {
|
|
40
|
+
return ctx.json({
|
|
41
|
+
jsonrpc: "2.0",
|
|
42
|
+
error: {
|
|
43
|
+
code: -32602,
|
|
44
|
+
message: "Invalid params: message is required"
|
|
45
|
+
},
|
|
46
|
+
id: requestBody.id
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const taskId = params.message.taskId;
|
|
50
|
+
const session = await agent.createSession(taskId);
|
|
51
|
+
const stream = sseSubscriber.createStream(session.id);
|
|
52
|
+
const { text, image, file } = (0, import_message.a2aToInternalMessage)(params.message);
|
|
53
|
+
agent.run(text, image, file, session.id).catch((error) => {
|
|
54
|
+
import_core.logger.error(`Error in streaming task ${session.id}: ${error}`);
|
|
55
|
+
});
|
|
56
|
+
import_core.logger.info(`JSON-RPC SSE stream opened for task ${session.id}`);
|
|
57
|
+
return new Response(stream, {
|
|
58
|
+
headers: {
|
|
59
|
+
"Content-Type": "text/event-stream",
|
|
60
|
+
"Cache-Control": "no-cache",
|
|
61
|
+
Connection: "keep-alive",
|
|
62
|
+
"X-Accel-Buffering": "no"
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
const handlers = new import_methods.A2AMethodHandlers(agent);
|
|
67
|
+
const rpcServer = new import_server.JsonRpcServer({
|
|
68
|
+
methods: handlers.getMethods(),
|
|
69
|
+
onError: (error, request) => {
|
|
70
|
+
import_core.logger.error(`JSON-RPC error for method ${request?.method}: ${error.message}`, {
|
|
71
|
+
error,
|
|
72
|
+
request
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
import_core.logger.debug(`A2A JSON-RPC request received`, {
|
|
77
|
+
method: Array.isArray(requestBody) ? `batch(${requestBody.length})` : requestBody.method
|
|
78
|
+
});
|
|
79
|
+
const response = await rpcServer.handle(requestBody);
|
|
80
|
+
return ctx.json(response);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
import_core.logger.error(`Failed to process JSON-RPC request: ${error}`, { error });
|
|
83
|
+
return ctx.json({
|
|
84
|
+
jsonrpc: "2.0",
|
|
85
|
+
error: {
|
|
86
|
+
code: -32700,
|
|
87
|
+
message: "Parse error",
|
|
88
|
+
data: error instanceof Error ? error.message : String(error)
|
|
89
|
+
},
|
|
90
|
+
id: null
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
app.get("/jsonrpc", (ctx) => {
|
|
95
|
+
const agent = getAgent();
|
|
96
|
+
const handlers = new import_methods.A2AMethodHandlers(agent);
|
|
97
|
+
return ctx.json({
|
|
98
|
+
service: "A2A JSON-RPC 2.0",
|
|
99
|
+
version: "0.3.0",
|
|
100
|
+
endpoint: "/jsonrpc",
|
|
101
|
+
methods: Object.keys(handlers.getMethods()),
|
|
102
|
+
usage: {
|
|
103
|
+
method: "POST",
|
|
104
|
+
contentType: "application/json",
|
|
105
|
+
example: {
|
|
106
|
+
jsonrpc: "2.0",
|
|
107
|
+
method: "agent.getInfo",
|
|
108
|
+
params: {},
|
|
109
|
+
id: 1
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
return app;
|
|
115
|
+
}
|
|
116
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
117
|
+
0 && (module.exports = {
|
|
118
|
+
createA2AJsonRpcRouter
|
|
119
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2A JSON-RPC HTTP Endpoint
|
|
3
|
+
*
|
|
4
|
+
* Exposes A2A Protocol JSON-RPC methods via HTTP POST endpoint.
|
|
5
|
+
* Implements JSON-RPC 2.0 over HTTP transport.
|
|
6
|
+
*/
|
|
7
|
+
import { Hono } from 'hono';
|
|
8
|
+
import type { DextoAgent } from '@dexto/core';
|
|
9
|
+
import type { A2ASseEventSubscriber } from '../../events/a2a-sse-subscriber.js';
|
|
10
|
+
/**
|
|
11
|
+
* Create A2A JSON-RPC router
|
|
12
|
+
*
|
|
13
|
+
* Exposes POST /jsonrpc endpoint for A2A Protocol communication.
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const a2aRouter = createA2AJsonRpcRouter(getAgent, sseSubscriber);
|
|
18
|
+
* app.route('/', a2aRouter);
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* Example request:
|
|
22
|
+
* ```json
|
|
23
|
+
* POST /jsonrpc
|
|
24
|
+
* Content-Type: application/json
|
|
25
|
+
*
|
|
26
|
+
* {
|
|
27
|
+
* "jsonrpc": "2.0",
|
|
28
|
+
* "method": "message/send",
|
|
29
|
+
* "params": {
|
|
30
|
+
* "message": {
|
|
31
|
+
* "role": "user",
|
|
32
|
+
* "parts": [{ "kind": "text", "text": "Hello!" }],
|
|
33
|
+
* "messageId": "msg-123",
|
|
34
|
+
* "kind": "message"
|
|
35
|
+
* }
|
|
36
|
+
* },
|
|
37
|
+
* "id": 1
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @param getAgent Function to get current DextoAgent instance
|
|
42
|
+
* @param sseSubscriber SSE event subscriber for streaming methods
|
|
43
|
+
* @returns Hono router with /jsonrpc endpoint
|
|
44
|
+
*/
|
|
45
|
+
export declare function createA2AJsonRpcRouter(getAgent: () => DextoAgent, sseSubscriber: A2ASseEventSubscriber): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
46
|
+
//# sourceMappingURL=a2a-jsonrpc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2a-jsonrpc.d.ts","sourceRoot":"","sources":["../../../src/hono/routes/a2a-jsonrpc.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI9C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAGhF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,sBAAsB,CAClC,QAAQ,EAAE,MAAM,UAAU,EAC1B,aAAa,EAAE,qBAAqB,8EA4HvC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { JsonRpcServer } from "../../a2a/jsonrpc/server.js";
|
|
3
|
+
import { A2AMethodHandlers } from "../../a2a/jsonrpc/methods.js";
|
|
4
|
+
import { logger } from "@dexto/core";
|
|
5
|
+
import { a2aToInternalMessage } from "../../a2a/adapters/message.js";
|
|
6
|
+
function createA2AJsonRpcRouter(getAgent, sseSubscriber) {
|
|
7
|
+
const app = new Hono();
|
|
8
|
+
app.post("/jsonrpc", async (ctx) => {
|
|
9
|
+
try {
|
|
10
|
+
const agent = getAgent();
|
|
11
|
+
const requestBody = await ctx.req.json();
|
|
12
|
+
const isStreamingRequest = !Array.isArray(requestBody) && requestBody.method === "message/stream";
|
|
13
|
+
if (isStreamingRequest) {
|
|
14
|
+
logger.info("JSON-RPC streaming request: message/stream");
|
|
15
|
+
const params = requestBody.params;
|
|
16
|
+
if (!params?.message) {
|
|
17
|
+
return ctx.json({
|
|
18
|
+
jsonrpc: "2.0",
|
|
19
|
+
error: {
|
|
20
|
+
code: -32602,
|
|
21
|
+
message: "Invalid params: message is required"
|
|
22
|
+
},
|
|
23
|
+
id: requestBody.id
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
const taskId = params.message.taskId;
|
|
27
|
+
const session = await agent.createSession(taskId);
|
|
28
|
+
const stream = sseSubscriber.createStream(session.id);
|
|
29
|
+
const { text, image, file } = a2aToInternalMessage(params.message);
|
|
30
|
+
agent.run(text, image, file, session.id).catch((error) => {
|
|
31
|
+
logger.error(`Error in streaming task ${session.id}: ${error}`);
|
|
32
|
+
});
|
|
33
|
+
logger.info(`JSON-RPC SSE stream opened for task ${session.id}`);
|
|
34
|
+
return new Response(stream, {
|
|
35
|
+
headers: {
|
|
36
|
+
"Content-Type": "text/event-stream",
|
|
37
|
+
"Cache-Control": "no-cache",
|
|
38
|
+
Connection: "keep-alive",
|
|
39
|
+
"X-Accel-Buffering": "no"
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
const handlers = new A2AMethodHandlers(agent);
|
|
44
|
+
const rpcServer = new JsonRpcServer({
|
|
45
|
+
methods: handlers.getMethods(),
|
|
46
|
+
onError: (error, request) => {
|
|
47
|
+
logger.error(`JSON-RPC error for method ${request?.method}: ${error.message}`, {
|
|
48
|
+
error,
|
|
49
|
+
request
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
logger.debug(`A2A JSON-RPC request received`, {
|
|
54
|
+
method: Array.isArray(requestBody) ? `batch(${requestBody.length})` : requestBody.method
|
|
55
|
+
});
|
|
56
|
+
const response = await rpcServer.handle(requestBody);
|
|
57
|
+
return ctx.json(response);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
logger.error(`Failed to process JSON-RPC request: ${error}`, { error });
|
|
60
|
+
return ctx.json({
|
|
61
|
+
jsonrpc: "2.0",
|
|
62
|
+
error: {
|
|
63
|
+
code: -32700,
|
|
64
|
+
message: "Parse error",
|
|
65
|
+
data: error instanceof Error ? error.message : String(error)
|
|
66
|
+
},
|
|
67
|
+
id: null
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
app.get("/jsonrpc", (ctx) => {
|
|
72
|
+
const agent = getAgent();
|
|
73
|
+
const handlers = new A2AMethodHandlers(agent);
|
|
74
|
+
return ctx.json({
|
|
75
|
+
service: "A2A JSON-RPC 2.0",
|
|
76
|
+
version: "0.3.0",
|
|
77
|
+
endpoint: "/jsonrpc",
|
|
78
|
+
methods: Object.keys(handlers.getMethods()),
|
|
79
|
+
usage: {
|
|
80
|
+
method: "POST",
|
|
81
|
+
contentType: "application/json",
|
|
82
|
+
example: {
|
|
83
|
+
jsonrpc: "2.0",
|
|
84
|
+
method: "agent.getInfo",
|
|
85
|
+
params: {},
|
|
86
|
+
id: 1
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
return app;
|
|
92
|
+
}
|
|
93
|
+
export {
|
|
94
|
+
createA2AJsonRpcRouter
|
|
95
|
+
};
|