@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.
Files changed (174) hide show
  1. package/LICENSE +44 -0
  2. package/dist/a2a/adapters/index.cjs +42 -0
  3. package/dist/a2a/adapters/index.d.ts +10 -0
  4. package/dist/a2a/adapters/index.d.ts.map +1 -0
  5. package/dist/a2a/adapters/index.js +12 -0
  6. package/dist/a2a/adapters/message.cjs +193 -0
  7. package/dist/a2a/adapters/message.d.ts +50 -0
  8. package/dist/a2a/adapters/message.d.ts.map +1 -0
  9. package/dist/a2a/adapters/message.js +167 -0
  10. package/dist/a2a/adapters/state.cjs +57 -0
  11. package/dist/a2a/adapters/state.d.ts +36 -0
  12. package/dist/a2a/adapters/state.d.ts.map +1 -0
  13. package/dist/a2a/adapters/state.js +32 -0
  14. package/dist/a2a/adapters/task-view.cjs +85 -0
  15. package/dist/a2a/adapters/task-view.d.ts +58 -0
  16. package/dist/a2a/adapters/task-view.d.ts.map +1 -0
  17. package/dist/a2a/adapters/task-view.js +60 -0
  18. package/dist/a2a/index.cjs +51 -0
  19. package/dist/a2a/index.d.ts +15 -0
  20. package/dist/a2a/index.d.ts.map +1 -0
  21. package/dist/a2a/index.js +30 -0
  22. package/dist/a2a/jsonrpc/index.cjs +38 -0
  23. package/dist/a2a/jsonrpc/index.d.ts +11 -0
  24. package/dist/a2a/jsonrpc/index.d.ts.map +1 -0
  25. package/dist/a2a/jsonrpc/index.js +10 -0
  26. package/dist/a2a/jsonrpc/methods.cjs +183 -0
  27. package/dist/a2a/jsonrpc/methods.d.ts +110 -0
  28. package/dist/a2a/jsonrpc/methods.d.ts.map +1 -0
  29. package/dist/a2a/jsonrpc/methods.js +159 -0
  30. package/dist/a2a/jsonrpc/server.cjs +199 -0
  31. package/dist/a2a/jsonrpc/server.d.ts +100 -0
  32. package/dist/a2a/jsonrpc/server.d.ts.map +1 -0
  33. package/dist/a2a/jsonrpc/server.js +175 -0
  34. package/dist/a2a/jsonrpc/types.cjs +47 -0
  35. package/dist/a2a/jsonrpc/types.d.ts +91 -0
  36. package/dist/a2a/jsonrpc/types.d.ts.map +1 -0
  37. package/dist/a2a/jsonrpc/types.js +21 -0
  38. package/dist/a2a/types.cjs +16 -0
  39. package/dist/a2a/types.d.ts +250 -0
  40. package/dist/a2a/types.d.ts.map +1 -0
  41. package/dist/a2a/types.js +0 -0
  42. package/dist/approval/approval-coordinator.cjs +87 -0
  43. package/dist/approval/approval-coordinator.d.ts +52 -0
  44. package/dist/approval/approval-coordinator.d.ts.map +1 -0
  45. package/dist/approval/approval-coordinator.js +63 -0
  46. package/dist/approval/manual-approval-handler.cjs +100 -0
  47. package/dist/approval/manual-approval-handler.d.ts +32 -0
  48. package/dist/approval/manual-approval-handler.d.ts.map +1 -0
  49. package/dist/approval/manual-approval-handler.js +76 -0
  50. package/dist/events/a2a-sse-subscriber.cjs +271 -0
  51. package/dist/events/a2a-sse-subscriber.d.ts +94 -0
  52. package/dist/events/a2a-sse-subscriber.d.ts.map +1 -0
  53. package/dist/events/a2a-sse-subscriber.js +247 -0
  54. package/dist/events/types.cjs +16 -0
  55. package/dist/events/types.d.ts +15 -0
  56. package/dist/events/types.d.ts.map +1 -0
  57. package/dist/events/types.js +0 -0
  58. package/dist/events/webhook-subscriber.cjs +301 -0
  59. package/dist/events/webhook-subscriber.d.ts +64 -0
  60. package/dist/events/webhook-subscriber.d.ts.map +1 -0
  61. package/dist/events/webhook-subscriber.js +269 -0
  62. package/dist/events/webhook-types.cjs +16 -0
  63. package/dist/events/webhook-types.d.ts +91 -0
  64. package/dist/events/webhook-types.d.ts.map +1 -0
  65. package/dist/events/webhook-types.js +0 -0
  66. package/dist/hono/__tests__/test-fixtures.cjs +236 -0
  67. package/dist/hono/__tests__/test-fixtures.d.ts +65 -0
  68. package/dist/hono/__tests__/test-fixtures.d.ts.map +1 -0
  69. package/dist/hono/__tests__/test-fixtures.js +197 -0
  70. package/dist/hono/index.cjs +166 -0
  71. package/dist/hono/index.d.ts +2783 -0
  72. package/dist/hono/index.d.ts.map +1 -0
  73. package/dist/hono/index.js +141 -0
  74. package/dist/hono/middleware/auth.cjs +75 -0
  75. package/dist/hono/middleware/auth.d.ts +3 -0
  76. package/dist/hono/middleware/auth.d.ts.map +1 -0
  77. package/dist/hono/middleware/auth.js +51 -0
  78. package/dist/hono/middleware/cors.cjs +57 -0
  79. package/dist/hono/middleware/cors.d.ts +9 -0
  80. package/dist/hono/middleware/cors.d.ts.map +1 -0
  81. package/dist/hono/middleware/cors.js +33 -0
  82. package/dist/hono/middleware/error.cjs +131 -0
  83. package/dist/hono/middleware/error.d.ts +5 -0
  84. package/dist/hono/middleware/error.d.ts.map +1 -0
  85. package/dist/hono/middleware/error.js +105 -0
  86. package/dist/hono/middleware/redaction.cjs +45 -0
  87. package/dist/hono/middleware/redaction.d.ts +4 -0
  88. package/dist/hono/middleware/redaction.d.ts.map +1 -0
  89. package/dist/hono/middleware/redaction.js +20 -0
  90. package/dist/hono/node/index.cjs +139 -0
  91. package/dist/hono/node/index.d.ts +19 -0
  92. package/dist/hono/node/index.d.ts.map +1 -0
  93. package/dist/hono/node/index.js +115 -0
  94. package/dist/hono/routes/a2a-jsonrpc.cjs +119 -0
  95. package/dist/hono/routes/a2a-jsonrpc.d.ts +46 -0
  96. package/dist/hono/routes/a2a-jsonrpc.d.ts.map +1 -0
  97. package/dist/hono/routes/a2a-jsonrpc.js +95 -0
  98. package/dist/hono/routes/a2a-tasks.cjs +315 -0
  99. package/dist/hono/routes/a2a-tasks.d.ts +530 -0
  100. package/dist/hono/routes/a2a-tasks.d.ts.map +1 -0
  101. package/dist/hono/routes/a2a-tasks.js +291 -0
  102. package/dist/hono/routes/a2a.cjs +36 -0
  103. package/dist/hono/routes/a2a.d.ts +4 -0
  104. package/dist/hono/routes/a2a.d.ts.map +1 -0
  105. package/dist/hono/routes/a2a.js +12 -0
  106. package/dist/hono/routes/agents.cjs +735 -0
  107. package/dist/hono/routes/agents.d.ts +650 -0
  108. package/dist/hono/routes/agents.d.ts.map +1 -0
  109. package/dist/hono/routes/agents.js +711 -0
  110. package/dist/hono/routes/approvals.cjs +125 -0
  111. package/dist/hono/routes/approvals.d.ts +89 -0
  112. package/dist/hono/routes/approvals.d.ts.map +1 -0
  113. package/dist/hono/routes/approvals.js +101 -0
  114. package/dist/hono/routes/greeting.cjs +60 -0
  115. package/dist/hono/routes/greeting.d.ts +19 -0
  116. package/dist/hono/routes/greeting.d.ts.map +1 -0
  117. package/dist/hono/routes/greeting.js +36 -0
  118. package/dist/hono/routes/health.cjs +45 -0
  119. package/dist/hono/routes/health.d.ts +17 -0
  120. package/dist/hono/routes/health.d.ts.map +1 -0
  121. package/dist/hono/routes/health.js +21 -0
  122. package/dist/hono/routes/llm.cjs +298 -0
  123. package/dist/hono/routes/llm.d.ts +294 -0
  124. package/dist/hono/routes/llm.d.ts.map +1 -0
  125. package/dist/hono/routes/llm.js +287 -0
  126. package/dist/hono/routes/mcp.cjs +356 -0
  127. package/dist/hono/routes/mcp.d.ts +246 -0
  128. package/dist/hono/routes/mcp.d.ts.map +1 -0
  129. package/dist/hono/routes/mcp.js +332 -0
  130. package/dist/hono/routes/memory.cjs +192 -0
  131. package/dist/hono/routes/memory.d.ts +146 -0
  132. package/dist/hono/routes/memory.d.ts.map +1 -0
  133. package/dist/hono/routes/memory.js +168 -0
  134. package/dist/hono/routes/messages.cjs +320 -0
  135. package/dist/hono/routes/messages.d.ts +163 -0
  136. package/dist/hono/routes/messages.d.ts.map +1 -0
  137. package/dist/hono/routes/messages.js +296 -0
  138. package/dist/hono/routes/prompts.cjs +228 -0
  139. package/dist/hono/routes/prompts.d.ts +150 -0
  140. package/dist/hono/routes/prompts.d.ts.map +1 -0
  141. package/dist/hono/routes/prompts.js +204 -0
  142. package/dist/hono/routes/resources.cjs +110 -0
  143. package/dist/hono/routes/resources.d.ts +76 -0
  144. package/dist/hono/routes/resources.d.ts.map +1 -0
  145. package/dist/hono/routes/resources.js +86 -0
  146. package/dist/hono/routes/search.cjs +109 -0
  147. package/dist/hono/routes/search.d.ts +137 -0
  148. package/dist/hono/routes/search.d.ts.map +1 -0
  149. package/dist/hono/routes/search.js +85 -0
  150. package/dist/hono/routes/sessions.cjs +366 -0
  151. package/dist/hono/routes/sessions.d.ts +229 -0
  152. package/dist/hono/routes/sessions.d.ts.map +1 -0
  153. package/dist/hono/routes/sessions.js +342 -0
  154. package/dist/hono/routes/webhooks.cjs +228 -0
  155. package/dist/hono/routes/webhooks.d.ts +127 -0
  156. package/dist/hono/routes/webhooks.d.ts.map +1 -0
  157. package/dist/hono/routes/webhooks.js +204 -0
  158. package/dist/hono/schemas/responses.cjs +276 -0
  159. package/dist/hono/schemas/responses.d.ts +1418 -0
  160. package/dist/hono/schemas/responses.d.ts.map +1 -0
  161. package/dist/hono/schemas/responses.js +227 -0
  162. package/dist/hono/types.cjs +16 -0
  163. package/dist/hono/types.d.ts +6 -0
  164. package/dist/hono/types.d.ts.map +1 -0
  165. package/dist/hono/types.js +0 -0
  166. package/dist/index.cjs +38 -0
  167. package/dist/index.d.ts +11 -0
  168. package/dist/index.d.ts.map +1 -0
  169. package/dist/index.js +9 -0
  170. package/dist/mcp/mcp-handler.cjs +145 -0
  171. package/dist/mcp/mcp-handler.d.ts +14 -0
  172. package/dist/mcp/mcp-handler.d.ts.map +1 -0
  173. package/dist/mcp/mcp-handler.js +118 -0
  174. package/package.json +59 -0
@@ -0,0 +1,247 @@
1
+ import { setMaxListeners } from "events";
2
+ import { logger } from "@dexto/core";
3
+ class A2ASseEventSubscriber {
4
+ connections = /* @__PURE__ */ new Map();
5
+ eventBus;
6
+ globalAbortController;
7
+ /**
8
+ * Subscribe to agent event bus.
9
+ * Sets up global event listeners that broadcast to all SSE connections.
10
+ *
11
+ * @param eventBus Agent event bus to subscribe to
12
+ */
13
+ subscribe(eventBus) {
14
+ this.globalAbortController?.abort();
15
+ this.globalAbortController = new AbortController();
16
+ const { signal } = this.globalAbortController;
17
+ const MAX_SHARED_SIGNAL_LISTENERS = 20;
18
+ setMaxListeners(MAX_SHARED_SIGNAL_LISTENERS, signal);
19
+ this.eventBus = eventBus;
20
+ eventBus.on(
21
+ "llm:thinking",
22
+ (payload) => {
23
+ this.broadcastToTask(payload.sessionId, "task.thinking", {
24
+ taskId: payload.sessionId
25
+ });
26
+ },
27
+ { signal }
28
+ );
29
+ eventBus.on(
30
+ "llm:chunk",
31
+ (payload) => {
32
+ this.broadcastToTask(payload.sessionId, "task.chunk", {
33
+ taskId: payload.sessionId,
34
+ type: payload.chunkType,
35
+ content: payload.content,
36
+ isComplete: payload.isComplete
37
+ });
38
+ },
39
+ { signal }
40
+ );
41
+ eventBus.on(
42
+ "llm:tool-call",
43
+ (payload) => {
44
+ this.broadcastToTask(payload.sessionId, "task.toolCall", {
45
+ taskId: payload.sessionId,
46
+ toolName: payload.toolName,
47
+ args: payload.args,
48
+ callId: payload.callId
49
+ });
50
+ },
51
+ { signal }
52
+ );
53
+ eventBus.on(
54
+ "llm:tool-result",
55
+ (payload) => {
56
+ const data = {
57
+ taskId: payload.sessionId,
58
+ toolName: payload.toolName,
59
+ callId: payload.callId,
60
+ success: payload.success,
61
+ sanitized: payload.sanitized
62
+ };
63
+ if (payload.rawResult !== void 0) {
64
+ data.rawResult = payload.rawResult;
65
+ }
66
+ this.broadcastToTask(payload.sessionId, "task.toolResult", data);
67
+ },
68
+ { signal }
69
+ );
70
+ eventBus.on(
71
+ "llm:response",
72
+ (payload) => {
73
+ this.broadcastToTask(payload.sessionId, "task.message", {
74
+ taskId: payload.sessionId,
75
+ message: {
76
+ role: "agent",
77
+ content: [{ type: "text", text: payload.content }],
78
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
79
+ },
80
+ tokenUsage: payload.tokenUsage,
81
+ provider: payload.provider,
82
+ model: payload.model
83
+ });
84
+ },
85
+ { signal }
86
+ );
87
+ eventBus.on(
88
+ "llm:error",
89
+ (payload) => {
90
+ this.broadcastToTask(payload.sessionId, "task.error", {
91
+ taskId: payload.sessionId,
92
+ error: {
93
+ message: payload.error.message,
94
+ recoverable: payload.recoverable
95
+ }
96
+ });
97
+ },
98
+ { signal }
99
+ );
100
+ eventBus.on(
101
+ "session:reset",
102
+ (payload) => {
103
+ this.broadcastToTask(payload.sessionId, "task.reset", {
104
+ taskId: payload.sessionId
105
+ });
106
+ },
107
+ { signal }
108
+ );
109
+ logger.debug("A2ASseEventSubscriber subscribed to agent events");
110
+ }
111
+ /**
112
+ * Create a new SSE stream for a specific task.
113
+ *
114
+ * Returns a ReadableStream that emits SSE events for the task.
115
+ *
116
+ * @param taskId Task/Session ID to stream events for
117
+ * @returns ReadableStream for SSE connection
118
+ */
119
+ createStream(taskId) {
120
+ const connectionId = `${taskId}-${Date.now()}`;
121
+ return new ReadableStream({
122
+ start: (controller) => {
123
+ const connection = {
124
+ taskId,
125
+ controller,
126
+ abortController: new AbortController(),
127
+ connectedAt: Date.now()
128
+ };
129
+ this.connections.set(connectionId, connection);
130
+ logger.debug(`SSE connection opened for task ${taskId}`);
131
+ this.sendSSEEvent(controller, "connected", {
132
+ taskId,
133
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
134
+ });
135
+ const keepaliveInterval = setInterval(() => {
136
+ try {
137
+ this.sendSSEComment(controller, "keepalive");
138
+ } catch (_error) {
139
+ clearInterval(keepaliveInterval);
140
+ }
141
+ }, 3e4);
142
+ connection.abortController.signal.addEventListener("abort", () => {
143
+ clearInterval(keepaliveInterval);
144
+ });
145
+ },
146
+ cancel: () => {
147
+ const connection = this.connections.get(connectionId);
148
+ if (connection) {
149
+ connection.abortController.abort();
150
+ this.connections.delete(connectionId);
151
+ logger.debug(`SSE connection closed for task ${taskId}`);
152
+ }
153
+ }
154
+ });
155
+ }
156
+ /**
157
+ * Broadcast an event to a specific task's SSE connections.
158
+ *
159
+ * @param taskId Task ID to broadcast to
160
+ * @param eventName SSE event name
161
+ * @param data Event data
162
+ */
163
+ broadcastToTask(taskId, eventName, data) {
164
+ let sent = 0;
165
+ for (const [connectionId, connection] of this.connections.entries()) {
166
+ if (connection.taskId === taskId) {
167
+ try {
168
+ this.sendSSEEvent(connection.controller, eventName, data);
169
+ sent++;
170
+ } catch (error) {
171
+ const errorMessage = error instanceof Error ? error.message : String(error);
172
+ logger.warn(`Failed to send SSE event to ${connectionId}: ${errorMessage}`);
173
+ connection.abortController.abort();
174
+ this.connections.delete(connectionId);
175
+ }
176
+ }
177
+ }
178
+ if (sent > 0) {
179
+ logger.debug(`Broadcast ${eventName} to ${sent} SSE connection(s) for task ${taskId}`);
180
+ }
181
+ }
182
+ /**
183
+ * Send an SSE event to a specific controller.
184
+ *
185
+ * Format: event: name\ndata: json\n\n
186
+ *
187
+ * @param controller Stream controller
188
+ * @param eventName Event name
189
+ * @param data Event data
190
+ */
191
+ sendSSEEvent(controller, eventName, data) {
192
+ const event = `event: ${eventName}
193
+ data: ${JSON.stringify(data)}
194
+
195
+ `;
196
+ controller.enqueue(new TextEncoder().encode(event));
197
+ }
198
+ /**
199
+ * Send an SSE comment (for keepalive).
200
+ *
201
+ * Format: : comment\n
202
+ *
203
+ * @param controller Stream controller
204
+ * @param comment Comment text
205
+ */
206
+ sendSSEComment(controller, comment) {
207
+ const line = `: ${comment}
208
+ `;
209
+ controller.enqueue(new TextEncoder().encode(line));
210
+ }
211
+ /**
212
+ * Close all connections and cleanup.
213
+ */
214
+ cleanup() {
215
+ logger.debug(`Cleaning up ${this.connections.size} SSE connections`);
216
+ for (const [_connectionId, connection] of this.connections.entries()) {
217
+ connection.abortController.abort();
218
+ try {
219
+ connection.controller.close();
220
+ } catch (_error) {
221
+ }
222
+ }
223
+ this.connections.clear();
224
+ this.globalAbortController?.abort();
225
+ }
226
+ /**
227
+ * Get active connection count.
228
+ */
229
+ getConnectionCount() {
230
+ return this.connections.size;
231
+ }
232
+ /**
233
+ * Get connection count for a specific task.
234
+ */
235
+ getTaskConnectionCount(taskId) {
236
+ let count = 0;
237
+ for (const connection of this.connections.values()) {
238
+ if (connection.taskId === taskId) {
239
+ count++;
240
+ }
241
+ }
242
+ return count;
243
+ }
244
+ }
245
+ export {
246
+ A2ASseEventSubscriber
247
+ };
@@ -0,0 +1,16 @@
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 __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+ var types_exports = {};
16
+ module.exports = __toCommonJS(types_exports);
@@ -0,0 +1,15 @@
1
+ import { AgentEventBus } from '@dexto/core';
2
+ /**
3
+ * Generic interface for subscribing to core events.
4
+ */
5
+ export interface EventSubscriber {
6
+ /**
7
+ * Attach event handlers to the given event bus.
8
+ */
9
+ subscribe(eventBus: AgentEventBus): void;
10
+ /**
11
+ * Clean up event listeners and resources.
12
+ */
13
+ cleanup?(): void;
14
+ }
15
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/events/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAEzC;;OAEG;IACH,OAAO,CAAC,IAAI,IAAI,CAAC;CACpB"}
File without changes
@@ -0,0 +1,301 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var webhook_subscriber_exports = {};
30
+ __export(webhook_subscriber_exports, {
31
+ WebhookEventSubscriber: () => WebhookEventSubscriber
32
+ });
33
+ module.exports = __toCommonJS(webhook_subscriber_exports);
34
+ var import_crypto = __toESM(require("crypto"), 1);
35
+ var import_events = require("events");
36
+ var import_core = require("@dexto/core");
37
+ var import_core2 = require("@dexto/core");
38
+ const DEFAULT_DELIVERY_OPTIONS = {
39
+ maxRetries: 3,
40
+ timeout: 1e4,
41
+ // 10 seconds
42
+ includeSignature: true
43
+ };
44
+ class WebhookEventSubscriber {
45
+ webhooks = /* @__PURE__ */ new Map();
46
+ abortController;
47
+ deliveryOptions;
48
+ fetchFn;
49
+ constructor({
50
+ fetchFn,
51
+ ...deliveryOptions
52
+ } = {}) {
53
+ this.deliveryOptions = { ...DEFAULT_DELIVERY_OPTIONS, ...deliveryOptions };
54
+ this.fetchFn = fetchFn || fetch;
55
+ import_core2.logger.debug("WebhookEventSubscriber initialized");
56
+ }
57
+ /**
58
+ * Subscribe to agent events and deliver them to registered webhooks
59
+ */
60
+ subscribe(eventBus) {
61
+ this.abortController?.abort();
62
+ this.abortController = new AbortController();
63
+ const { signal } = this.abortController;
64
+ const MAX_SHARED_SIGNAL_LISTENERS = 20;
65
+ (0, import_events.setMaxListeners)(MAX_SHARED_SIGNAL_LISTENERS, signal);
66
+ import_core.INTEGRATION_EVENTS.forEach((eventName) => {
67
+ eventBus.on(
68
+ eventName,
69
+ (payload) => {
70
+ this.deliverEvent(eventName, payload);
71
+ },
72
+ { signal }
73
+ );
74
+ });
75
+ import_core2.logger.info(`Webhook subscriber active with ${this.webhooks.size} registered webhooks`);
76
+ }
77
+ /**
78
+ * Register a new webhook endpoint
79
+ */
80
+ addWebhook(webhook) {
81
+ this.webhooks.set(webhook.id, webhook);
82
+ import_core2.logger.info(`Webhook registered: ${webhook.id} -> ${webhook.url}`);
83
+ }
84
+ /**
85
+ * Remove a webhook endpoint
86
+ */
87
+ removeWebhook(webhookId) {
88
+ const removed = this.webhooks.delete(webhookId);
89
+ if (removed) {
90
+ import_core2.logger.info(`Webhook removed: ${webhookId}`);
91
+ } else {
92
+ import_core2.logger.warn(`Attempted to remove non-existent webhook: ${webhookId}`);
93
+ }
94
+ return removed;
95
+ }
96
+ /**
97
+ * Get all registered webhooks
98
+ */
99
+ getWebhooks() {
100
+ return Array.from(this.webhooks.values());
101
+ }
102
+ /**
103
+ * Get a specific webhook by ID
104
+ */
105
+ getWebhook(webhookId) {
106
+ return this.webhooks.get(webhookId);
107
+ }
108
+ /**
109
+ * Test a webhook by sending a sample event
110
+ */
111
+ async testWebhook(webhookId) {
112
+ const webhook = this.webhooks.get(webhookId);
113
+ if (!webhook) {
114
+ throw new Error(`Webhook not found: ${webhookId}`);
115
+ }
116
+ const testEvent = {
117
+ id: `evt_test_${Date.now()}`,
118
+ type: "tools:available-updated",
119
+ data: {
120
+ tools: ["test-tool"],
121
+ source: "mcp"
122
+ },
123
+ created: (/* @__PURE__ */ new Date()).toISOString(),
124
+ apiVersion: "2025-07-03"
125
+ };
126
+ return this.deliverToWebhook(webhook, testEvent);
127
+ }
128
+ /**
129
+ * Clean up event listeners and resources
130
+ */
131
+ cleanup() {
132
+ if (this.abortController) {
133
+ this.abortController.abort();
134
+ delete this.abortController;
135
+ }
136
+ this.webhooks.clear();
137
+ import_core2.logger.debug("Webhook event subscriber cleaned up");
138
+ }
139
+ /**
140
+ * Unsubscribe from current event bus without clearing registered webhooks
141
+ */
142
+ unsubscribe() {
143
+ if (this.abortController) {
144
+ const controller = this.abortController;
145
+ delete this.abortController;
146
+ try {
147
+ controller.abort();
148
+ } catch (error) {
149
+ import_core2.logger.debug(
150
+ `Error aborting controller during unsubscribe: ${error instanceof Error ? error.message : String(error)}`,
151
+ {
152
+ location: "WebhookEventSubscriber.unsubscribe",
153
+ ...error instanceof Error ? { stack: error.stack } : { value: String(error) }
154
+ }
155
+ );
156
+ }
157
+ }
158
+ }
159
+ /**
160
+ * Deliver an event to all registered webhooks
161
+ */
162
+ async deliverEvent(eventType, eventData) {
163
+ if (this.webhooks.size === 0) {
164
+ return;
165
+ }
166
+ const webhookEvent = {
167
+ id: `evt_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`,
168
+ type: eventType,
169
+ data: eventData,
170
+ created: (/* @__PURE__ */ new Date()).toISOString(),
171
+ apiVersion: "2025-07-03"
172
+ };
173
+ import_core2.logger.debug(`Delivering webhook event: ${eventType} to ${this.webhooks.size} webhooks`);
174
+ const deliveryPromises = Array.from(this.webhooks.values()).map((webhook) => ({
175
+ webhook,
176
+ promise: this.deliverToWebhook(webhook, webhookEvent)
177
+ }));
178
+ const handleSettled = (results) => {
179
+ results.forEach((result, i) => {
180
+ if (result.status === "rejected") {
181
+ const webhook = deliveryPromises[i]?.webhook;
182
+ if (webhook) {
183
+ import_core2.logger.error(
184
+ `Webhook delivery failed for ${webhook.id}: ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`
185
+ );
186
+ }
187
+ }
188
+ });
189
+ };
190
+ if (process.env.NODE_ENV === "test") {
191
+ const results = await Promise.allSettled(deliveryPromises.map((p) => p.promise));
192
+ handleSettled(results);
193
+ } else {
194
+ Promise.allSettled(deliveryPromises.map((p) => p.promise)).then(handleSettled);
195
+ }
196
+ }
197
+ /**
198
+ * Deliver an event to a specific webhook with retry logic
199
+ */
200
+ async deliverToWebhook(webhook, event) {
201
+ const startTime = Date.now();
202
+ let lastError;
203
+ let lastStatusCode;
204
+ for (let attempt = 1; attempt <= this.deliveryOptions.maxRetries; attempt++) {
205
+ try {
206
+ const result2 = await this.sendWebhookRequest(webhook, event, attempt);
207
+ if (result2.success) {
208
+ return result2;
209
+ }
210
+ lastError = new Error(result2.error || `HTTP ${result2.statusCode}`);
211
+ lastStatusCode = result2.statusCode;
212
+ } catch (error) {
213
+ lastError = error instanceof Error ? error : new Error(String(error));
214
+ import_core2.logger.warn(
215
+ `Webhook delivery attempt ${attempt}/${this.deliveryOptions.maxRetries} failed for ${webhook.id}: ${lastError.message}`
216
+ );
217
+ }
218
+ if (attempt < this.deliveryOptions.maxRetries) {
219
+ const baseDelay = process.env.NODE_ENV === "test" ? 1 : 1e3;
220
+ const exp = baseDelay * Math.pow(2, attempt - 1);
221
+ const jitter = exp * 0.2 * Math.random();
222
+ const backoffMs = Math.min(exp + jitter, 1e4);
223
+ await new Promise((resolve) => setTimeout(resolve, backoffMs));
224
+ }
225
+ }
226
+ const totalTime = Date.now() - startTime;
227
+ const result = {
228
+ success: false,
229
+ error: lastError?.message || "Unknown error",
230
+ responseTime: totalTime,
231
+ attempt: this.deliveryOptions.maxRetries,
232
+ ...lastStatusCode !== void 0 && { statusCode: lastStatusCode }
233
+ };
234
+ import_core2.logger.error(
235
+ `Webhook delivery failed after ${this.deliveryOptions.maxRetries} attempts for ${webhook.id}: ${result.error}`
236
+ );
237
+ return result;
238
+ }
239
+ /**
240
+ * Send HTTP request to webhook endpoint
241
+ */
242
+ async sendWebhookRequest(webhook, event, attempt) {
243
+ const startTime = Date.now();
244
+ const payload = JSON.stringify(event);
245
+ const headers = {
246
+ "Content-Type": "application/json",
247
+ "User-Agent": "DextoAgent/1.0",
248
+ "X-Dexto-Event-Type": event.type,
249
+ "X-Dexto-Event-Id": event.id,
250
+ "X-Dexto-Delivery-Attempt": attempt.toString()
251
+ };
252
+ if (webhook.secret && this.deliveryOptions.includeSignature) {
253
+ const signature = this.generateSignature(payload, webhook.secret);
254
+ headers["X-Dexto-Signature-256"] = signature;
255
+ }
256
+ try {
257
+ const response = await this.fetchFn(webhook.url, {
258
+ method: "POST",
259
+ headers,
260
+ body: payload,
261
+ signal: AbortSignal.timeout(this.deliveryOptions.timeout)
262
+ });
263
+ const responseTime = Date.now() - startTime;
264
+ const success = response.ok;
265
+ const result = {
266
+ success,
267
+ statusCode: response.status,
268
+ responseTime,
269
+ attempt
270
+ };
271
+ if (!success) {
272
+ result.error = `HTTP ${response.status}: ${response.statusText}`;
273
+ }
274
+ import_core2.logger.debug(
275
+ `Webhook delivery ${success ? "succeeded" : "failed"} for ${webhook.id}: ${response.status} in ${responseTime}ms`
276
+ );
277
+ return result;
278
+ } catch (error) {
279
+ const responseTime = Date.now() - startTime;
280
+ const errorMessage = error instanceof Error ? error.message : String(error);
281
+ return {
282
+ success: false,
283
+ error: errorMessage,
284
+ responseTime,
285
+ attempt
286
+ };
287
+ }
288
+ }
289
+ /**
290
+ * Generate HMAC signature for webhook verification
291
+ */
292
+ generateSignature(payload, secret) {
293
+ const hmac = import_crypto.default.createHmac("sha256", secret);
294
+ hmac.update(payload, "utf8");
295
+ return `sha256=${hmac.digest("hex")}`;
296
+ }
297
+ }
298
+ // Annotate the CommonJS export names for ESM import in node:
299
+ 0 && (module.exports = {
300
+ WebhookEventSubscriber
301
+ });
@@ -0,0 +1,64 @@
1
+ import { AgentEventBus } from '@dexto/core';
2
+ import { EventSubscriber } from './types.js';
3
+ import { type WebhookConfig, type WebhookDeliveryResult, type WebhookDeliveryOptions } from './webhook-types.js';
4
+ /**
5
+ * Webhook event subscriber that delivers agent events via HTTP POST
6
+ */
7
+ export declare class WebhookEventSubscriber implements EventSubscriber {
8
+ private webhooks;
9
+ private abortController?;
10
+ private deliveryOptions;
11
+ private fetchFn;
12
+ constructor({ fetchFn, ...deliveryOptions }?: WebhookDeliveryOptions & {
13
+ fetchFn?: typeof globalThis.fetch;
14
+ });
15
+ /**
16
+ * Subscribe to agent events and deliver them to registered webhooks
17
+ */
18
+ subscribe(eventBus: AgentEventBus): void;
19
+ /**
20
+ * Register a new webhook endpoint
21
+ */
22
+ addWebhook(webhook: WebhookConfig): void;
23
+ /**
24
+ * Remove a webhook endpoint
25
+ */
26
+ removeWebhook(webhookId: string): boolean;
27
+ /**
28
+ * Get all registered webhooks
29
+ */
30
+ getWebhooks(): WebhookConfig[];
31
+ /**
32
+ * Get a specific webhook by ID
33
+ */
34
+ getWebhook(webhookId: string): WebhookConfig | undefined;
35
+ /**
36
+ * Test a webhook by sending a sample event
37
+ */
38
+ testWebhook(webhookId: string): Promise<WebhookDeliveryResult>;
39
+ /**
40
+ * Clean up event listeners and resources
41
+ */
42
+ cleanup(): void;
43
+ /**
44
+ * Unsubscribe from current event bus without clearing registered webhooks
45
+ */
46
+ unsubscribe(): void;
47
+ /**
48
+ * Deliver an event to all registered webhooks
49
+ */
50
+ private deliverEvent;
51
+ /**
52
+ * Deliver an event to a specific webhook with retry logic
53
+ */
54
+ private deliverToWebhook;
55
+ /**
56
+ * Send HTTP request to webhook endpoint
57
+ */
58
+ private sendWebhookRequest;
59
+ /**
60
+ * Generate HMAC signature for webhook verification
61
+ */
62
+ private generateSignature;
63
+ }
64
+ //# sourceMappingURL=webhook-subscriber.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-subscriber.d.ts","sourceRoot":"","sources":["../../src/events/webhook-subscriber.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,aAAa,EAIhB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EACH,KAAK,aAAa,EAElB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC9B,MAAM,oBAAoB,CAAC;AAW5B;;GAEG;AACH,qBAAa,sBAAuB,YAAW,eAAe;IAC1D,OAAO,CAAC,QAAQ,CAAyC;IACzD,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,eAAe,CAAmC;IAC1D,OAAO,CAAC,OAAO,CAA0B;gBAE7B,EACR,OAAO,EACP,GAAG,eAAe,EACrB,GAAE,sBAAsB,GAAG;QAAE,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;KAAO;IAOtE;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI;IA4BxC;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAKxC;;OAEG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAUzC;;OAEG;IACH,WAAW,IAAI,aAAa,EAAE;IAI9B;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIxD;;OAEG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAoBpE;;OAEG;IACH,OAAO,IAAI,IAAI;IAUf;;OAEG;IACH,WAAW,IAAI,IAAI;IAsBnB;;OAEG;YACW,YAAY;IA+C1B;;OAEG;YACW,gBAAgB;IAoD9B;;OAEG;YACW,kBAAkB;IA+DhC;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAK5B"}