@relaycast/engine 4.2.0 → 5.0.1

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 (255) hide show
  1. package/dist/adapters/node/index.d.ts.map +1 -1
  2. package/dist/adapters/node/index.js +23 -1
  3. package/dist/adapters/node/index.js.map +1 -1
  4. package/dist/adapters/node/presence.d.ts +7 -3
  5. package/dist/adapters/node/presence.d.ts.map +1 -1
  6. package/dist/adapters/node/presence.js +10 -8
  7. package/dist/adapters/node/presence.js.map +1 -1
  8. package/dist/adapters/node/realtime.d.ts +9 -1
  9. package/dist/adapters/node/realtime.d.ts.map +1 -1
  10. package/dist/adapters/node/realtime.js +72 -10
  11. package/dist/adapters/node/realtime.js.map +1 -1
  12. package/dist/auth/index.d.ts.map +1 -1
  13. package/dist/auth/index.js +31 -9
  14. package/dist/auth/index.js.map +1 -1
  15. package/dist/auth/tokenKind.d.ts +40 -0
  16. package/dist/auth/tokenKind.d.ts.map +1 -0
  17. package/dist/auth/tokenKind.js +89 -0
  18. package/dist/auth/tokenKind.js.map +1 -0
  19. package/dist/bin/serve.js +2 -4
  20. package/dist/bin/serve.js.map +1 -1
  21. package/dist/db/migrations/0021_node_delivery_contracts.sql +70 -0
  22. package/dist/db/migrations/0022_http_push_redrive.sql +13 -0
  23. package/dist/db/migrations/0023_direct_ws_nodes.sql +124 -0
  24. package/dist/db/migrations/0024_binding_workspace_constraints.sql +109 -0
  25. package/dist/db/migrations/0025_node_kind_role_adapter.sql +45 -0
  26. package/dist/db/migrations/0026_observer_tokens.sql +32 -0
  27. package/dist/db/schema.d.ts +727 -59
  28. package/dist/db/schema.d.ts.map +1 -1
  29. package/dist/db/schema.js +78 -2
  30. package/dist/db/schema.js.map +1 -1
  31. package/dist/engine/action.d.ts +2 -9
  32. package/dist/engine/action.d.ts.map +1 -1
  33. package/dist/engine/action.js +182 -14
  34. package/dist/engine/action.js.map +1 -1
  35. package/dist/engine/activity.d.ts +6 -0
  36. package/dist/engine/activity.d.ts.map +1 -1
  37. package/dist/engine/activity.js +9 -2
  38. package/dist/engine/activity.js.map +1 -1
  39. package/dist/engine/agent.d.ts +0 -33
  40. package/dist/engine/agent.d.ts.map +1 -1
  41. package/dist/engine/agent.js +4 -153
  42. package/dist/engine/agent.js.map +1 -1
  43. package/dist/engine/attachments.d.ts +6 -0
  44. package/dist/engine/attachments.d.ts.map +1 -1
  45. package/dist/engine/attachments.js +37 -0
  46. package/dist/engine/attachments.js.map +1 -1
  47. package/dist/engine/console.d.ts +78 -1
  48. package/dist/engine/console.d.ts.map +1 -1
  49. package/dist/engine/console.js +175 -19
  50. package/dist/engine/console.js.map +1 -1
  51. package/dist/engine/delivery.d.ts +26 -0
  52. package/dist/engine/delivery.d.ts.map +1 -1
  53. package/dist/engine/delivery.js +194 -74
  54. package/dist/engine/delivery.js.map +1 -1
  55. package/dist/engine/deliveryWire.d.ts +4 -0
  56. package/dist/engine/deliveryWire.d.ts.map +1 -1
  57. package/dist/engine/deliveryWire.js +2 -0
  58. package/dist/engine/deliveryWire.js.map +1 -1
  59. package/dist/engine/deliveryWrites.d.ts +6 -0
  60. package/dist/engine/deliveryWrites.d.ts.map +1 -1
  61. package/dist/engine/deliveryWrites.js +58 -13
  62. package/dist/engine/deliveryWrites.js.map +1 -1
  63. package/dist/engine/dm.d.ts.map +1 -1
  64. package/dist/engine/dm.js +11 -33
  65. package/dist/engine/dm.js.map +1 -1
  66. package/dist/engine/dmAll.d.ts.map +1 -1
  67. package/dist/engine/dmAll.js +2 -0
  68. package/dist/engine/dmAll.js.map +1 -1
  69. package/dist/engine/groupDm.d.ts +2 -3
  70. package/dist/engine/groupDm.d.ts.map +1 -1
  71. package/dist/engine/groupDm.js +8 -26
  72. package/dist/engine/groupDm.js.map +1 -1
  73. package/dist/engine/invocationCompletion.d.ts +1 -1
  74. package/dist/engine/invocationCompletion.d.ts.map +1 -1
  75. package/dist/engine/invocationCompletion.js +10 -18
  76. package/dist/engine/invocationCompletion.js.map +1 -1
  77. package/dist/engine/message.d.ts.map +1 -1
  78. package/dist/engine/message.js +16 -44
  79. package/dist/engine/message.js.map +1 -1
  80. package/dist/engine/node.d.ts +97 -0
  81. package/dist/engine/node.d.ts.map +1 -1
  82. package/dist/engine/node.js +555 -27
  83. package/dist/engine/node.js.map +1 -1
  84. package/dist/engine/nodeContext.d.ts +22 -0
  85. package/dist/engine/nodeContext.d.ts.map +1 -0
  86. package/dist/engine/nodeContext.js +80 -0
  87. package/dist/engine/nodeContext.js.map +1 -0
  88. package/dist/engine/nodeDeliver.d.ts +23 -0
  89. package/dist/engine/nodeDeliver.d.ts.map +1 -0
  90. package/dist/engine/nodeDeliver.js +81 -0
  91. package/dist/engine/nodeDeliver.js.map +1 -0
  92. package/dist/engine/observerToken.d.ts +110 -0
  93. package/dist/engine/observerToken.d.ts.map +1 -0
  94. package/dist/engine/observerToken.js +528 -0
  95. package/dist/engine/observerToken.js.map +1 -0
  96. package/dist/engine/search.d.ts +4 -0
  97. package/dist/engine/search.d.ts.map +1 -1
  98. package/dist/engine/search.js +6 -1
  99. package/dist/engine/search.js.map +1 -1
  100. package/dist/engine/thread.d.ts +4 -3
  101. package/dist/engine/thread.d.ts.map +1 -1
  102. package/dist/engine/thread.js +45 -17
  103. package/dist/engine/thread.js.map +1 -1
  104. package/dist/engine/wsAuth.d.ts +32 -0
  105. package/dist/engine/wsAuth.d.ts.map +1 -0
  106. package/dist/engine/wsAuth.js +65 -0
  107. package/dist/engine/wsAuth.js.map +1 -0
  108. package/dist/engine/wsTransform.d.ts.map +1 -1
  109. package/dist/engine/wsTransform.js +52 -36
  110. package/dist/engine/wsTransform.js.map +1 -1
  111. package/dist/engine.d.ts.map +1 -1
  112. package/dist/engine.js +37 -86
  113. package/dist/engine.js.map +1 -1
  114. package/dist/entrypoints/node.d.ts.map +1 -1
  115. package/dist/entrypoints/node.js +20 -57
  116. package/dist/entrypoints/node.js.map +1 -1
  117. package/dist/env.d.ts +3 -1
  118. package/dist/env.d.ts.map +1 -1
  119. package/dist/index.d.ts +1 -0
  120. package/dist/index.d.ts.map +1 -1
  121. package/dist/index.js +5 -0
  122. package/dist/index.js.map +1 -1
  123. package/dist/lib/httpError.d.ts +5 -1
  124. package/dist/lib/httpError.d.ts.map +1 -1
  125. package/dist/lib/httpError.js +5 -2
  126. package/dist/lib/httpError.js.map +1 -1
  127. package/dist/lib/httpQuery.d.ts +28 -0
  128. package/dist/lib/httpQuery.d.ts.map +1 -0
  129. package/dist/lib/httpQuery.js +32 -0
  130. package/dist/lib/httpQuery.js.map +1 -0
  131. package/dist/lib/httpResponse.d.ts +15 -2
  132. package/dist/lib/httpResponse.d.ts.map +1 -1
  133. package/dist/lib/httpResponse.js +35 -7
  134. package/dist/lib/httpResponse.js.map +1 -1
  135. package/dist/middleware/auth.d.ts +8 -0
  136. package/dist/middleware/auth.d.ts.map +1 -1
  137. package/dist/middleware/auth.js +65 -2
  138. package/dist/middleware/auth.js.map +1 -1
  139. package/dist/middleware/idempotency.d.ts +30 -0
  140. package/dist/middleware/idempotency.d.ts.map +1 -1
  141. package/dist/middleware/idempotency.js +14 -0
  142. package/dist/middleware/idempotency.js.map +1 -1
  143. package/dist/middleware/logger.d.ts.map +1 -1
  144. package/dist/middleware/logger.js +4 -4
  145. package/dist/middleware/logger.js.map +1 -1
  146. package/dist/middleware/planLimits.d.ts.map +1 -1
  147. package/dist/middleware/planLimits.js +11 -9
  148. package/dist/middleware/planLimits.js.map +1 -1
  149. package/dist/middleware/rateLimit.d.ts.map +1 -1
  150. package/dist/middleware/rateLimit.js +15 -8
  151. package/dist/middleware/rateLimit.js.map +1 -1
  152. package/dist/middleware/usageTracker.d.ts.map +1 -1
  153. package/dist/middleware/usageTracker.js +2 -1
  154. package/dist/middleware/usageTracker.js.map +1 -1
  155. package/dist/ports/auth.d.ts +6 -2
  156. package/dist/ports/auth.d.ts.map +1 -1
  157. package/dist/ports/entitlements.d.ts +3 -1
  158. package/dist/ports/entitlements.d.ts.map +1 -1
  159. package/dist/ports/index.d.ts +0 -14
  160. package/dist/ports/index.d.ts.map +1 -1
  161. package/dist/ports/realtime.d.ts +4 -1
  162. package/dist/ports/realtime.d.ts.map +1 -1
  163. package/dist/providers/static-entitlements.js +4 -4
  164. package/dist/providers/static-entitlements.js.map +1 -1
  165. package/dist/routes/a2a.d.ts.map +1 -1
  166. package/dist/routes/a2a.js +41 -83
  167. package/dist/routes/a2a.js.map +1 -1
  168. package/dist/routes/action.d.ts.map +1 -1
  169. package/dist/routes/action.js +45 -42
  170. package/dist/routes/action.js.map +1 -1
  171. package/dist/routes/agent.d.ts.map +1 -1
  172. package/dist/routes/agent.js +172 -120
  173. package/dist/routes/agent.js.map +1 -1
  174. package/dist/routes/certify.d.ts.map +1 -1
  175. package/dist/routes/certify.js +21 -35
  176. package/dist/routes/certify.js.map +1 -1
  177. package/dist/routes/channel.d.ts.map +1 -1
  178. package/dist/routes/channel.js +69 -81
  179. package/dist/routes/channel.js.map +1 -1
  180. package/dist/routes/console.d.ts.map +1 -1
  181. package/dist/routes/console.js +60 -40
  182. package/dist/routes/console.js.map +1 -1
  183. package/dist/routes/delivery.d.ts.map +1 -1
  184. package/dist/routes/delivery.js +22 -54
  185. package/dist/routes/delivery.js.map +1 -1
  186. package/dist/routes/deliveryRouting.d.ts +6 -0
  187. package/dist/routes/deliveryRouting.d.ts.map +1 -1
  188. package/dist/routes/deliveryRouting.js +297 -34
  189. package/dist/routes/deliveryRouting.js.map +1 -1
  190. package/dist/routes/directory.d.ts.map +1 -1
  191. package/dist/routes/directory.js +47 -63
  192. package/dist/routes/directory.js.map +1 -1
  193. package/dist/routes/dm.d.ts.map +1 -1
  194. package/dist/routes/dm.js +21 -42
  195. package/dist/routes/dm.js.map +1 -1
  196. package/dist/routes/fanout.d.ts +2 -1
  197. package/dist/routes/fanout.d.ts.map +1 -1
  198. package/dist/routes/fanout.js +38 -20
  199. package/dist/routes/fanout.js.map +1 -1
  200. package/dist/routes/file.d.ts.map +1 -1
  201. package/dist/routes/file.js +48 -44
  202. package/dist/routes/file.js.map +1 -1
  203. package/dist/routes/groupDm.d.ts.map +1 -1
  204. package/dist/routes/groupDm.js +23 -48
  205. package/dist/routes/groupDm.js.map +1 -1
  206. package/dist/routes/inboundWebhook.d.ts.map +1 -1
  207. package/dist/routes/inboundWebhook.js +17 -35
  208. package/dist/routes/inboundWebhook.js.map +1 -1
  209. package/dist/routes/inbox.d.ts.map +1 -1
  210. package/dist/routes/inbox.js +2 -1
  211. package/dist/routes/inbox.js.map +1 -1
  212. package/dist/routes/message.d.ts.map +1 -1
  213. package/dist/routes/message.js +60 -53
  214. package/dist/routes/message.js.map +1 -1
  215. package/dist/routes/node.d.ts.map +1 -1
  216. package/dist/routes/node.js +173 -10
  217. package/dist/routes/node.js.map +1 -1
  218. package/dist/routes/observerToken.d.ts +4 -0
  219. package/dist/routes/observerToken.d.ts.map +1 -0
  220. package/dist/routes/observerToken.js +105 -0
  221. package/dist/routes/observerToken.js.map +1 -0
  222. package/dist/routes/presence.d.ts.map +1 -1
  223. package/dist/routes/presence.js +10 -6
  224. package/dist/routes/presence.js.map +1 -1
  225. package/dist/routes/reaction.d.ts.map +1 -1
  226. package/dist/routes/reaction.js +69 -28
  227. package/dist/routes/reaction.js.map +1 -1
  228. package/dist/routes/receipt.d.ts.map +1 -1
  229. package/dist/routes/receipt.js +20 -3
  230. package/dist/routes/receipt.js.map +1 -1
  231. package/dist/routes/routing.d.ts.map +1 -1
  232. package/dist/routes/routing.js +38 -51
  233. package/dist/routes/routing.js.map +1 -1
  234. package/dist/routes/search.d.ts.map +1 -1
  235. package/dist/routes/search.js +21 -15
  236. package/dist/routes/search.js.map +1 -1
  237. package/dist/routes/thread.d.ts.map +1 -1
  238. package/dist/routes/thread.js +36 -37
  239. package/dist/routes/thread.js.map +1 -1
  240. package/dist/routes/workspace.d.ts.map +1 -1
  241. package/dist/routes/workspace.js +57 -225
  242. package/dist/routes/workspace.js.map +1 -1
  243. package/package.json +3 -3
  244. package/dist/lib/fleetNodes.d.ts +0 -9
  245. package/dist/lib/fleetNodes.d.ts.map +0 -1
  246. package/dist/lib/fleetNodes.js +0 -66
  247. package/dist/lib/fleetNodes.js.map +0 -1
  248. package/dist/lib/workspaceStream.d.ts +0 -9
  249. package/dist/lib/workspaceStream.d.ts.map +0 -1
  250. package/dist/lib/workspaceStream.js +0 -53
  251. package/dist/lib/workspaceStream.js.map +0 -1
  252. package/dist/middleware/fleetNodes.d.ts +0 -10
  253. package/dist/middleware/fleetNodes.d.ts.map +0 -1
  254. package/dist/middleware/fleetNodes.js +0 -18
  255. package/dist/middleware/fleetNodes.js.map +0 -1
@@ -1,61 +1,324 @@
1
- import { and, eq, inArray } from 'drizzle-orm';
1
+ import { and, eq, inArray, sql } from 'drizzle-orm';
2
2
  import * as deliveryEngine from '../engine/delivery.js';
3
3
  import { buildDeliverFrame, buildDeliverPayload } from '../engine/deliveryWire.js';
4
- import { agents } from '../db/schema.js';
4
+ import { agents, agentNodeBindings, deliveries as deliveryRows, nodes } from '../db/schema.js';
5
+ import { hmacSha256Hex } from '../lib/crypto.js';
6
+ import { isSafeExternalUrl } from '../lib/ssrf.js';
7
+ import { transformForClient } from '../engine/wsTransform.js';
5
8
  import { fanoutToAgents } from './fanout.js';
9
+ const HTTP_PUSH_RETRY_DELAY_MS = 30_000;
10
+ function routingContextFromHono(c) {
11
+ return {
12
+ db: c.get('db'),
13
+ workspaceId: c.get('workspace').id,
14
+ engine: c.get('engine'),
15
+ };
16
+ }
6
17
  function wireMode(mode) {
7
18
  return mode === 'next-tool-call' ? 'steer' : 'wait';
8
19
  }
9
- async function resolveLiveLocations(c, workspaceId, deliveries) {
20
+ function strictExternalUrl(engine) {
21
+ return engine.config?.environment !== 'test';
22
+ }
23
+ function buildEvent(type, workspaceId, data) {
24
+ return {
25
+ type,
26
+ workspace_id: workspaceId,
27
+ data,
28
+ timestamp: new Date().toISOString(),
29
+ };
30
+ }
31
+ async function fanoutToAgentsForContext(ctx, agentIds, type, data) {
32
+ const payload = transformForClient(buildEvent(type, ctx.workspaceId, data));
33
+ const unique = [...new Set(agentIds)];
34
+ const tasks = [
35
+ ctx.engine.realtime.deliverToAgents({ workspaceId: ctx.workspaceId, agentIds: unique, event: payload }),
36
+ ctx.engine.realtime.publishToWorkspaceStream({ workspaceId: ctx.workspaceId, event: payload }),
37
+ ];
38
+ await Promise.allSettled(tasks);
39
+ }
40
+ async function resolveLiveLocations(ctx, deliveries) {
10
41
  const uniqueAgentIds = [...new Set(deliveries.map((delivery) => delivery.agentId))];
11
42
  if (uniqueAgentIds.length === 0)
12
43
  return new Map();
13
- const rows = await c.get('db')
44
+ const bindings = await ctx.db
45
+ .select({
46
+ agentId: agentNodeBindings.agentId,
47
+ nodeId: agentNodeBindings.nodeId,
48
+ nodeKind: nodes.kind,
49
+ nodeRole: nodes.role,
50
+ deliveryAdapter: nodes.deliveryAdapter,
51
+ deliveryConfig: nodes.deliveryConfig,
52
+ })
53
+ .from(agentNodeBindings)
54
+ .innerJoin(agents, and(eq(agentNodeBindings.agentId, agents.id), eq(agents.locationType, 'via_node'), eq(agents.locationNodeId, agentNodeBindings.nodeId)))
55
+ .innerJoin(nodes, eq(agentNodeBindings.nodeId, nodes.id))
56
+ .where(and(eq(agentNodeBindings.workspaceId, ctx.workspaceId), eq(agentNodeBindings.status, 'active'), inArray(agentNodeBindings.agentId, uniqueAgentIds)))
57
+ .orderBy(sql `${agentNodeBindings.priority} DESC`, agentNodeBindings.createdAt);
58
+ const byAgent = new Map();
59
+ for (const binding of bindings) {
60
+ if (byAgent.has(binding.agentId))
61
+ continue;
62
+ byAgent.set(binding.agentId, {
63
+ locationType: 'via_node',
64
+ locationNodeId: binding.nodeId,
65
+ nodeKind: binding.nodeKind,
66
+ nodeRole: binding.nodeRole,
67
+ deliveryAdapter: binding.deliveryAdapter,
68
+ deliveryConfig: binding.deliveryConfig,
69
+ });
70
+ }
71
+ const fallbackRows = await ctx.db
14
72
  .select({
15
73
  id: agents.id,
16
74
  locationType: agents.locationType,
17
75
  locationNodeId: agents.locationNodeId,
76
+ nodeKind: nodes.kind,
77
+ nodeRole: nodes.role,
78
+ deliveryAdapter: nodes.deliveryAdapter,
79
+ deliveryConfig: nodes.deliveryConfig,
18
80
  })
19
81
  .from(agents)
20
- .where(and(eq(agents.workspaceId, workspaceId), inArray(agents.id, uniqueAgentIds)));
21
- return new Map(rows.map((row) => [row.id, {
82
+ .leftJoin(nodes, eq(agents.locationNodeId, nodes.id))
83
+ .where(and(eq(agents.workspaceId, ctx.workspaceId), inArray(agents.id, uniqueAgentIds)));
84
+ for (const row of fallbackRows) {
85
+ if (byAgent.has(row.id))
86
+ continue;
87
+ byAgent.set(row.id, {
22
88
  locationType: row.locationType,
23
89
  locationNodeId: row.locationNodeId,
24
- }]));
90
+ nodeKind: row.nodeKind ?? (row.locationNodeId ? 'ws' : null),
91
+ nodeRole: row.nodeRole ?? (row.locationNodeId ? 'broker' : null),
92
+ deliveryAdapter: row.deliveryAdapter ?? (row.locationNodeId ? 'ws.node.v1' : null),
93
+ deliveryConfig: row.deliveryConfig,
94
+ });
95
+ }
96
+ return byAgent;
25
97
  }
26
- export async function routeDeliveryOutcomes(c, deliveries, eventType, eventData) {
27
- if (deliveries.length === 0)
28
- return;
29
- const workspaceId = c.get('workspace').id;
30
- const db = c.get('db');
31
- const deliveredIds = [];
32
- const liveLocations = await resolveLiveLocations(c, workspaceId, deliveries);
98
+ async function resolveRecordedTargets(ctx, deliveries) {
99
+ const routeNodeIds = [...new Set(deliveries.flatMap((delivery) => (delivery.routeNodeId ? [delivery.routeNodeId] : [])))];
100
+ const nodesById = new Map();
101
+ if (routeNodeIds.length > 0) {
102
+ const rows = await ctx.db
103
+ .select()
104
+ .from(nodes)
105
+ .where(and(eq(nodes.workspaceId, ctx.workspaceId), inArray(nodes.id, routeNodeIds)));
106
+ for (const row of rows) {
107
+ nodesById.set(row.id, row);
108
+ }
109
+ }
110
+ const byDelivery = new Map();
33
111
  for (const delivery of deliveries) {
34
- const liveLocation = liveLocations.get(delivery.agentId);
35
- const locationType = liveLocation?.locationType ?? delivery.locationType;
36
- const locationNodeId = liveLocation?.locationNodeId ?? delivery.locationNodeId;
37
- if (locationType === 'via_node' && locationNodeId) {
38
- const sent = await c.get('engine').nodeConnections.sendToNode(workspaceId, locationNodeId, buildDeliverFrame({
39
- agent: delivery.agentName,
40
- msg_id: delivery.messageId,
41
- seq: delivery.seq,
42
- mode: wireMode(delivery.mode),
43
- payload: buildDeliverPayload(eventType, eventData),
44
- }));
45
- if (sent)
46
- deliveredIds.push(delivery.id);
112
+ if (!delivery.routeNodeId)
47
113
  continue;
114
+ const node = nodesById.get(delivery.routeNodeId);
115
+ byDelivery.set(delivery.id, {
116
+ locationType: 'via_node',
117
+ locationNodeId: delivery.routeNodeId,
118
+ nodeKind: delivery.routeNodeKind ?? node?.kind ?? null,
119
+ nodeRole: delivery.routeNodeRole ?? node?.role ?? null,
120
+ deliveryAdapter: delivery.deliveryAdapter ?? node?.deliveryAdapter ?? null,
121
+ deliveryConfig: node?.deliveryConfig ?? null,
122
+ });
123
+ }
124
+ return byDelivery;
125
+ }
126
+ function normalizeDeliveryAdapter(adapter, nodeKind) {
127
+ if (adapter === 'fleet.ws.v1' || adapter === 'direct.ws.v1')
128
+ return 'ws.node.v1';
129
+ if (adapter)
130
+ return adapter;
131
+ if (nodeKind === 'ws' || nodeKind === 'fleet_ws' || nodeKind === 'direct_ws')
132
+ return 'ws.node.v1';
133
+ if (nodeKind === 'http_push')
134
+ return 'http.basic.v1';
135
+ return null;
136
+ }
137
+ function publicHeaders(headers) {
138
+ if (!headers)
139
+ return {};
140
+ const result = {};
141
+ for (const [name, value] of Object.entries(headers)) {
142
+ if (typeof value === 'string')
143
+ result[name] = value;
144
+ }
145
+ return result;
146
+ }
147
+ async function recordHttpPushRetry(ctx, deliveryId, error, opts = {}) {
148
+ await ctx.db
149
+ .update(deliveryRows)
150
+ .set({
151
+ ...(opts.incrementAttempts ? { dispatchAttempts: sql `coalesce(${deliveryRows.dispatchAttempts}, 0) + 1` } : {}),
152
+ lastDispatchError: error,
153
+ nextAttemptAt: new Date(Date.now() + HTTP_PUSH_RETRY_DELAY_MS),
154
+ updatedAt: new Date(),
155
+ })
156
+ .where(and(eq(deliveryRows.workspaceId, ctx.workspaceId), eq(deliveryRows.id, deliveryId), eq(deliveryRows.status, 'queued')));
157
+ }
158
+ async function dispatchHttpPush(args) {
159
+ const config = args.target.deliveryConfig ?? {};
160
+ const url = typeof config.url === 'string' ? config.url : null;
161
+ if (!url) {
162
+ await recordHttpPushRetry(args.ctx, args.delivery.id, 'invalid http_push delivery config: missing url', { incrementAttempts: true });
163
+ return 'failed';
164
+ }
165
+ if (!isSafeExternalUrl(url, { strict: strictExternalUrl(args.ctx.engine) })) {
166
+ await recordHttpPushRetry(args.ctx, args.delivery.id, 'unsafe http_push delivery url', { incrementAttempts: true });
167
+ return 'failed';
168
+ }
169
+ const ackMode = config.ack_mode === 'on_2xx' || config.ack_mode === 'response'
170
+ ? config.ack_mode
171
+ : 'manual';
172
+ const timestamp = new Date().toISOString();
173
+ const body = JSON.stringify({
174
+ type: args.eventType,
175
+ workspace_id: args.ctx.workspaceId,
176
+ delivery_id: args.delivery.id,
177
+ message_id: args.delivery.messageId,
178
+ agent_id: args.delivery.agentId,
179
+ agent_name: args.delivery.agentName,
180
+ seq: args.delivery.seq,
181
+ mode: wireMode(args.delivery.mode),
182
+ timestamp,
183
+ data: args.eventData,
184
+ });
185
+ const auth = config.auth && typeof config.auth === 'object' && !Array.isArray(config.auth)
186
+ ? config.auth
187
+ : { type: 'none' };
188
+ const headers = {
189
+ 'Content-Type': 'application/json',
190
+ 'X-Relaycast-Event': args.eventType,
191
+ 'X-Relaycast-Delivery': args.delivery.id,
192
+ };
193
+ if (auth.type === 'bearer' && typeof auth.token === 'string') {
194
+ headers.Authorization = `Bearer ${auth.token}`;
195
+ }
196
+ else if (auth.type === 'static_headers') {
197
+ Object.assign(headers, publicHeaders(auth.headers));
198
+ }
199
+ else if (auth.type === 'hmac_sha256' && typeof auth.secret === 'string') {
200
+ const timestampHeader = typeof auth.timestamp_header === 'string' ? auth.timestamp_header : 'X-Relaycast-Timestamp';
201
+ const signatureHeader = typeof auth.signature_header === 'string' ? auth.signature_header : 'X-Relaycast-Signature';
202
+ const prefix = typeof auth.prefix === 'string' ? auth.prefix : 'sha256=';
203
+ const signedPayload = auth.signed_payload === 'body' ? body : `${timestamp}.${body}`;
204
+ headers[timestampHeader] = timestamp;
205
+ headers[signatureHeader] = `${prefix}${await hmacSha256Hex(signedPayload, auth.secret)}`;
206
+ }
207
+ try {
208
+ const claimConditions = [
209
+ eq(deliveryRows.workspaceId, args.ctx.workspaceId),
210
+ eq(deliveryRows.id, args.delivery.id),
211
+ eq(deliveryRows.status, 'queued'),
212
+ ];
213
+ if (args.delivery.nextAttemptAt) {
214
+ claimConditions.push(eq(deliveryRows.nextAttemptAt, args.delivery.nextAttemptAt));
215
+ }
216
+ const started = await args.ctx.db
217
+ .update(deliveryRows)
218
+ .set({
219
+ dispatchAttempts: sql `coalesce(${deliveryRows.dispatchAttempts}, 0) + 1`,
220
+ lastDispatchError: null,
221
+ nextAttemptAt: new Date(Date.now() + HTTP_PUSH_RETRY_DELAY_MS),
222
+ updatedAt: new Date(),
223
+ })
224
+ .where(and(...claimConditions))
225
+ .returning({ id: deliveryRows.id });
226
+ if (started.length === 0)
227
+ return 'failed';
228
+ const response = await globalThis.fetch(url, {
229
+ method: 'POST',
230
+ headers,
231
+ body,
232
+ redirect: 'error',
233
+ signal: AbortSignal.timeout(10_000),
234
+ });
235
+ if (!response.ok) {
236
+ await recordHttpPushRetry(args.ctx, args.delivery.id, `HTTP ${response.status}`);
237
+ return 'failed';
238
+ }
239
+ if (ackMode === 'on_2xx') {
240
+ const acked = await deliveryEngine.ackDelivery(args.ctx.db, args.ctx.workspaceId, args.delivery.agentId, args.delivery.id);
241
+ if (acked?.changed) {
242
+ await fanoutToAgentsForContext(args.ctx, [args.delivery.agentId], 'delivery.delivered', {
243
+ delivery_id: args.delivery.id,
244
+ message_id: args.delivery.messageId,
245
+ });
246
+ }
247
+ return 'acked';
248
+ }
249
+ if (ackMode === 'response') {
250
+ const contentType = response.headers.get('content-type') ?? '';
251
+ if (contentType.includes('application/json')) {
252
+ const responseBody = await response.json().catch(() => null);
253
+ if (responseBody?.ack === true || responseBody?.delivery_status === 'acked') {
254
+ const acked = await deliveryEngine.ackDelivery(args.ctx.db, args.ctx.workspaceId, args.delivery.agentId, args.delivery.id);
255
+ if (acked?.changed) {
256
+ await fanoutToAgentsForContext(args.ctx, [args.delivery.agentId], 'delivery.delivered', {
257
+ delivery_id: args.delivery.id,
258
+ message_id: args.delivery.messageId,
259
+ });
260
+ }
261
+ return 'acked';
262
+ }
263
+ }
264
+ await recordHttpPushRetry(args.ctx, args.delivery.id, 'response ack not signaled');
265
+ return 'failed';
48
266
  }
49
- deliveredIds.push(delivery.id);
50
- await fanoutToAgents(c, [delivery.agentId], 'delivery.accepted', {
267
+ return 'delivered';
268
+ }
269
+ catch (err) {
270
+ await recordHttpPushRetry(args.ctx, args.delivery.id, err instanceof Error ? err.message : 'HTTP delivery failed');
271
+ return 'failed';
272
+ }
273
+ }
274
+ async function routeOneDeliveryOutcome(ctx, liveLocations, recordedTargets, delivery, eventType, eventData) {
275
+ const recordedTarget = recordedTargets.get(delivery.id);
276
+ const liveLocation = liveLocations.get(delivery.agentId);
277
+ const target = recordedTarget ?? liveLocation;
278
+ const locationType = target?.locationType ?? delivery.locationType;
279
+ const locationNodeId = target?.locationNodeId ?? delivery.locationNodeId;
280
+ const nodeKind = target?.nodeKind ?? (locationNodeId ? 'ws' : null);
281
+ const deliveryAdapter = normalizeDeliveryAdapter(target?.deliveryAdapter ?? delivery.deliveryAdapter, nodeKind);
282
+ if (locationType === 'via_node' && locationNodeId && deliveryAdapter === 'ws.node.v1') {
283
+ const sent = await ctx.engine.nodeConnections.sendToNode(ctx.workspaceId, locationNodeId, buildDeliverFrame({
51
284
  delivery_id: delivery.id,
52
- message_id: delivery.messageId,
53
- channel_id: eventData.channel_id ?? null,
54
- reason: delivery.reason,
285
+ agent_id: delivery.agentId,
286
+ agent: delivery.agentName,
287
+ msg_id: delivery.messageId,
55
288
  seq: delivery.seq,
56
- });
289
+ mode: wireMode(delivery.mode),
290
+ payload: buildDeliverPayload(eventType, eventData),
291
+ }));
292
+ if (sent) {
293
+ await deliveryEngine.markDeliveriesDelivered(ctx.db, ctx.workspaceId, [delivery.id]);
294
+ }
295
+ return;
296
+ }
297
+ if (locationType === 'via_node' && locationNodeId && nodeKind === 'http_push' && target) {
298
+ const result = await dispatchHttpPush({ ctx, delivery, target, eventType, eventData });
299
+ if (result === 'delivered') {
300
+ await deliveryEngine.markDeliveriesDelivered(ctx.db, ctx.workspaceId, [delivery.id]);
301
+ }
302
+ return;
57
303
  }
58
- await deliveryEngine.markDeliveriesDelivered(db, workspaceId, deliveredIds);
304
+ // No agent-owned realtime socket exists anymore. If a legacy/unbound row
305
+ // reaches this point, leave it queued so a later node binding/replay can
306
+ // deliver it instead of falsely marking it delivered.
307
+ }
308
+ async function routeDeliveryOutcomesForContext(ctx, deliveries, eventType, eventData) {
309
+ if (deliveries.length === 0)
310
+ return;
311
+ const liveLocations = await resolveLiveLocations(ctx, deliveries);
312
+ const recordedTargets = await resolveRecordedTargets(ctx, deliveries);
313
+ await Promise.allSettled(deliveries.map((delivery) => (routeOneDeliveryOutcome(ctx, liveLocations, recordedTargets, delivery, eventType, eventData))));
314
+ }
315
+ export async function routeDeliveryOutcomes(c, deliveries, eventType, eventData) {
316
+ await routeDeliveryOutcomesForContext(routingContextFromHono(c), deliveries, eventType, eventData);
317
+ }
318
+ export async function sweepDueHttpPushDeliveries(engine, opts = {}) {
319
+ const due = await deliveryEngine.fetchDueHttpPushDeliveryEvents(engine.db, opts);
320
+ await Promise.allSettled(due.map((event) => (routeDeliveryOutcomesForContext({ db: engine.db, workspaceId: event.workspaceId, engine }, [event.delivery], event.eventType, event.eventData))));
321
+ return due.length;
59
322
  }
60
323
  export async function notifyDeliveryRejections(c, senderAgentId, rejections) {
61
324
  if (rejections.length === 0)
@@ -1 +1 @@
1
- {"version":3,"file":"deliveryRouting.js","sourceRoot":"","sources":["../../src/routes/deliveryRouting.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deliveryRouting.js","sourceRoot":"","sources":["../../src/routes/deliveryRouting.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"directory.d.ts","sourceRoot":"","sources":["../../src/routes/directory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAG1C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAOxC,eAAO,MAAM,eAAe,qDAAqB,CAAC"}
1
+ {"version":3,"file":"directory.d.ts","sourceRoot":"","sources":["../../src/routes/directory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAE1C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAkBxC,eAAO,MAAM,eAAe,qDAAqB,CAAC"}
@@ -4,7 +4,9 @@ import * as directoryEngine from '../engine/directory.js';
4
4
  import { requireAuth, requireWorkspaceKey } from '../middleware/auth.js';
5
5
  import { rateLimit } from '../middleware/rateLimit.js';
6
6
  import { emitServerEvent } from '../lib/serverTelemetry.js';
7
- import { asCodedError } from '../lib/httpError.js';
7
+ import { errorResponse } from '../lib/httpError.js';
8
+ import { jsonCreated, jsonError, jsonInvalidRequest, jsonNoContent, jsonNotFound, jsonOk, parseJsonBody, parseQueryParams, } from '../lib/httpResponse.js';
9
+ import { LimitQuerySchema } from '../lib/httpQuery.js';
8
10
  export const directoryRoutes = new Hono();
9
11
  const skillSchema = z.object({
10
12
  id: z.string().min(1).optional(),
@@ -47,6 +49,14 @@ const ratingSchema = z.object({
47
49
  score: z.number().int().min(1).max(5),
48
50
  review: z.string().max(4000).optional(),
49
51
  });
52
+ const listDirectoryAgentsQuerySchema = LimitQuerySchema.extend({
53
+ status: z.string().optional(),
54
+ });
55
+ const searchDirectoryQuerySchema = LimitQuerySchema.extend({
56
+ q: z.string().optional(),
57
+ tags: z.string().optional(),
58
+ status: z.string().optional(),
59
+ });
50
60
  function parseTagsParam(value) {
51
61
  if (!value)
52
62
  return undefined;
@@ -54,22 +64,13 @@ function parseTagsParam(value) {
54
64
  return tags.length ? tags : undefined;
55
65
  }
56
66
  function handleError(c, err) {
57
- const error = asCodedError(err);
58
- const cause = error.cause instanceof Error ? error.cause.message : (error.cause ? String(error.cause) : '');
59
- const message = cause ? `${error.message} [cause: ${cause}]` : error.message;
60
- return c.json({
61
- ok: false,
62
- error: { code: error.code || 'internal_error', message },
63
- }, (error.status || 500));
67
+ return errorResponse(c, err);
64
68
  }
65
69
  directoryRoutes.post('/directory/agents', requireWorkspaceKey, rateLimit, async (c) => {
66
70
  try {
67
- const parsed = createDirectoryAgentSchema.safeParse(await c.req.json());
68
- if (!parsed.success) {
69
- return c.json({
70
- ok: false,
71
- error: { code: 'invalid_request', message: 'name is required' },
72
- }, 400);
71
+ const parsed = await parseJsonBody(c, createDirectoryAgentSchema, 'name is required');
72
+ if (!parsed.ok) {
73
+ return parsed.response;
73
74
  }
74
75
  const workspace = c.get('workspace');
75
76
  const result = await directoryEngine.createDirectoryAgent(c.get('db'), workspace.id, parsed.data);
@@ -77,7 +78,7 @@ directoryRoutes.post('/directory/agents', requireWorkspaceKey, rateLimit, async
77
78
  slug: result?.slug,
78
79
  skill_count: result?.skills.length ?? 0,
79
80
  });
80
- return c.json({ ok: true, data: result }, 201);
81
+ return jsonCreated(c, result);
81
82
  }
82
83
  catch (err) {
83
84
  return handleError(c, err);
@@ -86,12 +87,16 @@ directoryRoutes.post('/directory/agents', requireWorkspaceKey, rateLimit, async
86
87
  directoryRoutes.get('/directory/agents', requireAuth, rateLimit, async (c) => {
87
88
  try {
88
89
  const workspace = c.get('workspace');
89
- const limit = c.req.query('limit') ? parseInt(c.req.query('limit'), 10) : undefined;
90
+ const parsed = parseQueryParams(c, listDirectoryAgentsQuerySchema, 'Invalid directory agent query');
91
+ if (!parsed.ok) {
92
+ return parsed.response;
93
+ }
94
+ const { status, limit } = parsed.data;
90
95
  const result = await directoryEngine.listDirectoryAgents(c.get('db'), workspace.id, {
91
- status: c.req.query('status') || undefined,
96
+ status: status || undefined,
92
97
  limit,
93
98
  });
94
- return c.json({ ok: true, data: result });
99
+ return jsonOk(c, result);
95
100
  }
96
101
  catch (err) {
97
102
  return handleError(c, err);
@@ -100,19 +105,19 @@ directoryRoutes.get('/directory/agents', requireAuth, rateLimit, async (c) => {
100
105
  directoryRoutes.get('/directory/search', requireAuth, rateLimit, async (c) => {
101
106
  try {
102
107
  const workspace = c.get('workspace');
103
- const q = c.req.query('q') || undefined;
104
- const tags = parseTagsParam(c.req.query('tags'));
108
+ const parsed = parseQueryParams(c, searchDirectoryQuerySchema, 'Invalid directory search query');
109
+ if (!parsed.ok) {
110
+ return parsed.response;
111
+ }
112
+ const { q, tags: tagsParam, status, limit } = parsed.data;
113
+ const tags = parseTagsParam(tagsParam);
105
114
  if ((!q || !q.trim()) && (!tags || tags.length === 0)) {
106
- return c.json({
107
- ok: false,
108
- error: { code: 'invalid_request', message: 'q or tags is required' },
109
- }, 400);
115
+ return jsonInvalidRequest(c, 'q or tags is required');
110
116
  }
111
- const limit = c.req.query('limit') ? parseInt(c.req.query('limit'), 10) : undefined;
112
117
  const result = await directoryEngine.searchDirectory(c.get('db'), workspace.id, {
113
118
  q,
114
119
  tags,
115
- status: c.req.query('status') || undefined,
120
+ status: status || undefined,
116
121
  limit,
117
122
  });
118
123
  emitServerEvent(c, workspace.id, 'relaycast_server_directory_search_executed', {
@@ -120,7 +125,7 @@ directoryRoutes.get('/directory/search', requireAuth, rateLimit, async (c) => {
120
125
  tag_count: tags?.length || 0,
121
126
  result_count: result.length,
122
127
  });
123
- return c.json({ ok: true, data: result });
128
+ return jsonOk(c, result);
124
129
  }
125
130
  catch (err) {
126
131
  return handleError(c, err);
@@ -131,12 +136,9 @@ directoryRoutes.get('/directory/agents/:slug', requireAuth, rateLimit, async (c)
131
136
  const workspace = c.get('workspace');
132
137
  const result = await directoryEngine.getDirectoryAgent(c.get('db'), workspace.id, c.req.param('slug'));
133
138
  if (!result) {
134
- return c.json({
135
- ok: false,
136
- error: { code: 'directory_agent_not_found', message: 'Directory agent not found' },
137
- }, 404);
139
+ return jsonNotFound(c, 'directory_agent_not_found', 'Directory agent not found');
138
140
  }
139
- return c.json({ ok: true, data: result });
141
+ return jsonOk(c, result);
140
142
  }
141
143
  catch (err) {
142
144
  return handleError(c, err);
@@ -144,26 +146,20 @@ directoryRoutes.get('/directory/agents/:slug', requireAuth, rateLimit, async (c)
144
146
  });
145
147
  directoryRoutes.patch('/directory/agents/:slug', requireWorkspaceKey, rateLimit, async (c) => {
146
148
  try {
147
- const parsed = updateDirectoryAgentSchema.safeParse(await c.req.json());
148
- if (!parsed.success) {
149
- return c.json({
150
- ok: false,
151
- error: { code: 'invalid_request', message: 'invalid directory agent update body' },
152
- }, 400);
149
+ const parsed = await parseJsonBody(c, updateDirectoryAgentSchema, 'invalid directory agent update body');
150
+ if (!parsed.ok) {
151
+ return parsed.response;
153
152
  }
154
153
  const workspace = c.get('workspace');
155
154
  const result = await directoryEngine.updateDirectoryAgent(c.get('db'), workspace.id, c.req.param('slug'), parsed.data);
156
155
  if (!result) {
157
- return c.json({
158
- ok: false,
159
- error: { code: 'directory_agent_not_found', message: 'Directory agent not found' },
160
- }, 404);
156
+ return jsonNotFound(c, 'directory_agent_not_found', 'Directory agent not found');
161
157
  }
162
158
  emitServerEvent(c, workspace.id, 'relaycast_server_directory_agent_updated', {
163
159
  slug: result.slug,
164
160
  status: result.status,
165
161
  });
166
- return c.json({ ok: true, data: result });
162
+ return jsonOk(c, result);
167
163
  }
168
164
  catch (err) {
169
165
  return handleError(c, err);
@@ -174,15 +170,12 @@ directoryRoutes.delete('/directory/agents/:slug', requireWorkspaceKey, rateLimit
174
170
  const workspace = c.get('workspace');
175
171
  const deleted = await directoryEngine.deleteDirectoryAgent(c.get('db'), workspace.id, c.req.param('slug'));
176
172
  if (!deleted) {
177
- return c.json({
178
- ok: false,
179
- error: { code: 'directory_agent_not_found', message: 'Directory agent not found' },
180
- }, 404);
173
+ return jsonNotFound(c, 'directory_agent_not_found', 'Directory agent not found');
181
174
  }
182
175
  emitServerEvent(c, workspace.id, 'relaycast_server_directory_agent_deleted', {
183
176
  slug: c.req.param('slug'),
184
177
  });
185
- return c.body(null, 204);
178
+ return jsonNoContent(c);
186
179
  }
187
180
  catch (err) {
188
181
  return handleError(c, err);
@@ -192,7 +185,7 @@ directoryRoutes.get('/directory/agents/:slug/ratings', requireAuth, rateLimit, a
192
185
  try {
193
186
  const workspace = c.get('workspace');
194
187
  const result = await directoryEngine.listDirectoryRatings(c.get('db'), workspace.id, c.req.param('slug'));
195
- return c.json({ ok: true, data: result });
188
+ return jsonOk(c, result);
196
189
  }
197
190
  catch (err) {
198
191
  return handleError(c, err);
@@ -200,22 +193,13 @@ directoryRoutes.get('/directory/agents/:slug/ratings', requireAuth, rateLimit, a
200
193
  });
201
194
  directoryRoutes.post('/directory/agents/:slug/ratings', requireAuth, rateLimit, async (c) => {
202
195
  try {
203
- const parsed = ratingSchema.safeParse(await c.req.json());
204
- if (!parsed.success) {
205
- return c.json({
206
- ok: false,
207
- error: { code: 'invalid_request', message: 'score must be an integer between 1 and 5' },
208
- }, 400);
196
+ const parsed = await parseJsonBody(c, ratingSchema, 'score must be an integer between 1 and 5');
197
+ if (!parsed.ok) {
198
+ return parsed.response;
209
199
  }
210
200
  const agent = c.get('agent');
211
201
  if (!agent?.id) {
212
- return c.json({
213
- ok: false,
214
- error: {
215
- code: 'agent_token_required',
216
- message: 'Agent token required to submit ratings',
217
- },
218
- }, 403);
202
+ return jsonError(c, 'agent_token_required', 'Agent token required to submit ratings', 403);
219
203
  }
220
204
  const workspace = c.get('workspace');
221
205
  const result = await directoryEngine.upsertDirectoryRating(c.get('db'), workspace.id, c.req.param('slug'), {
@@ -228,7 +212,7 @@ directoryRoutes.post('/directory/agents/:slug/ratings', requireAuth, rateLimit,
228
212
  score: result.score,
229
213
  rater_agent_id: agent.id,
230
214
  });
231
- return c.json({ ok: true, data: result }, 201);
215
+ return jsonCreated(c, result);
232
216
  }
233
217
  catch (err) {
234
218
  return handleError(c, err);