@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
@@ -0,0 +1,89 @@
1
+ import { z } from 'zod';
2
+ const tokenKindConfig = {
3
+ workspace: {
4
+ prefix: 'rk_live_',
5
+ requiredMessage: 'Workspace key required (rk_live_...)',
6
+ },
7
+ agent: {
8
+ prefix: 'at_live_',
9
+ requiredMessage: 'Agent token required (at_live_...)',
10
+ },
11
+ node: {
12
+ prefix: 'nt_live_',
13
+ requiredMessage: 'Node token required (nt_live_...)',
14
+ },
15
+ observer: {
16
+ prefix: 'ot_live_',
17
+ requiredMessage: 'Observer token required (ot_live_...)',
18
+ },
19
+ };
20
+ const workspaceTokenSchema = z
21
+ .string()
22
+ .startsWith(tokenKindConfig.workspace.prefix)
23
+ .transform((token) => ({ kind: 'workspace', token }));
24
+ const agentTokenSchema = z
25
+ .string()
26
+ .startsWith(tokenKindConfig.agent.prefix)
27
+ .transform((token) => ({ kind: 'agent', token }));
28
+ const nodeTokenSchema = z
29
+ .string()
30
+ .startsWith(tokenKindConfig.node.prefix)
31
+ .transform((token) => ({ kind: 'node', token }));
32
+ const observerTokenSchema = z
33
+ .string()
34
+ .startsWith(tokenKindConfig.observer.prefix)
35
+ .transform((token) => ({ kind: 'observer', token }));
36
+ export const authTokenSchema = z.union([
37
+ workspaceTokenSchema,
38
+ agentTokenSchema,
39
+ nodeTokenSchema,
40
+ observerTokenSchema,
41
+ ]);
42
+ export function parseAuthToken(token) {
43
+ const parsed = authTokenSchema.safeParse(token);
44
+ return parsed.success ? parsed.data : undefined;
45
+ }
46
+ export function getAuthTokenKind(token) {
47
+ return parseAuthToken(token)?.kind;
48
+ }
49
+ export function requiredTokenMessage(kind) {
50
+ return tokenKindConfig[kind].requiredMessage;
51
+ }
52
+ const allowedKindsByRequire = {
53
+ workspace: ['workspace'],
54
+ agent: ['agent'],
55
+ node: ['node'],
56
+ observer: ['observer'],
57
+ // `any` intentionally means user/workspace API credentials, not transport-only
58
+ // node credentials or scoped observer credentials.
59
+ any: ['workspace', 'agent'],
60
+ };
61
+ export function validateTokenRequirement(tokenKind, require) {
62
+ const allowedKinds = allowedKindsByRequire[require];
63
+ if (allowedKinds.includes(tokenKind)) {
64
+ return { ok: true };
65
+ }
66
+ if (tokenKind === 'node') {
67
+ return {
68
+ ok: false,
69
+ code: 'node_token_forbidden',
70
+ message: 'Node token cannot perform this operation',
71
+ };
72
+ }
73
+ if (tokenKind === 'observer') {
74
+ return {
75
+ ok: false,
76
+ code: 'observer_token_forbidden',
77
+ message: 'Observer token cannot perform this operation',
78
+ };
79
+ }
80
+ if (require === 'any') {
81
+ return { ok: false, code: 'unauthorized', message: 'Invalid token format' };
82
+ }
83
+ return {
84
+ ok: false,
85
+ code: 'unauthorized',
86
+ message: requiredTokenMessage(require),
87
+ };
88
+ }
89
+ //# sourceMappingURL=tokenKind.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenKind.js","sourceRoot":"","sources":["../../src/auth/tokenKind.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,eAAe,GAAG;IACtB,SAAS,EAAE;QACT,MAAM,EAAE,UAAU;QAClB,eAAe,EAAE,sCAAsC;KACxD;IACD,KAAK,EAAE;QACL,MAAM,EAAE,UAAU;QAClB,eAAe,EAAE,oCAAoC;KACtD;IACD,IAAI,EAAE;QACJ,MAAM,EAAE,UAAU;QAClB,eAAe,EAAE,mCAAmC;KACrD;IACD,QAAQ,EAAE;QACR,MAAM,EAAE,UAAU;QAClB,eAAe,EAAE,uCAAuC;KACzD;CACO,CAAC;AASX,MAAM,oBAAoB,GAAG,CAAC;KAC3B,MAAM,EAAE;KACR,UAAU,CAAC,eAAe,CAAC,SAAS,CAAC,MAAM,CAAC;KAC5C,SAAS,CAAC,CAAC,KAAK,EAA+B,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAErF,MAAM,gBAAgB,GAAG,CAAC;KACvB,MAAM,EAAE;KACR,UAAU,CAAC,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC;KACxC,SAAS,CAAC,CAAC,KAAK,EAA2B,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAE7E,MAAM,eAAe,GAAG,CAAC;KACtB,MAAM,EAAE;KACR,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC;KACvC,SAAS,CAAC,CAAC,KAAK,EAA0B,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAE3E,MAAM,mBAAmB,GAAG,CAAC;KAC1B,MAAM,EAAE;KACR,UAAU,CAAC,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC;KAC3C,SAAS,CAAC,CAAC,KAAK,EAA8B,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAEnF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC;IACrC,oBAAoB;IACpB,gBAAgB;IAChB,eAAe;IACf,mBAAmB;CACpB,CAAC,CAAC;AAIH,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,cAAc,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAiC;IACpE,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC;AAC/C,CAAC;AAED,MAAM,qBAAqB,GAAG;IAC5B,SAAS,EAAE,CAAC,WAAW,CAAC;IACxB,KAAK,EAAE,CAAC,OAAO,CAAC;IAChB,IAAI,EAAE,CAAC,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,UAAU,CAAC;IACtB,+EAA+E;IAC/E,mDAAmD;IACnD,GAAG,EAAE,CAAC,WAAW,EAAE,OAAO,CAAC;CACqC,CAAC;AAMnE,MAAM,UAAU,wBAAwB,CACtC,SAAwB,EACxB,OAAoB;IAEpB,MAAM,YAAY,GAA6B,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAC9E,IAAI,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAED,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QACzB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI,EAAE,sBAAsB;YAC5B,OAAO,EAAE,0CAA0C;SACpD,CAAC;IACJ,CAAC;IAED,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;QAC7B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI,EAAE,0BAA0B;YAChC,OAAO,EAAE,8CAA8C;SACxD,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACtB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC;IAC9E,CAAC;IAED,OAAO;QACL,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,oBAAoB,CAAC,OAAO,CAAC;KACvC,CAAC;AACJ,CAAC"}
package/dist/bin/serve.js CHANGED
@@ -50,9 +50,8 @@ async function main() {
50
50
  return;
51
51
  }
52
52
  const baseUrl = opts.baseUrl ?? `http://localhost:${opts.port}`;
53
- // Optional self-host tuning via env: the fleet rollout default and the bounded
54
- // mailbox TTL / depth cap. Lets operators (and the fleet E2E) configure a short
55
- // TTL / small depth cap without code changes.
53
+ // Optional self-host tuning via env: bounded mailbox TTL / depth cap. Lets
54
+ // operators configure a short TTL / small depth cap without code changes.
56
55
  const num = (v) => {
57
56
  if (v == null || v.trim() === '')
58
57
  return undefined;
@@ -69,7 +68,6 @@ async function main() {
69
68
  baseUrl,
70
69
  config: {
71
70
  environment: opts.environment,
72
- ...(process.env.RELAYCAST_FLEET_NODES_ENABLED === '1' ? { fleetNodesEnabled: true } : {}),
73
71
  ...(Object.keys(mailbox).length > 0 ? { mailbox } : {}),
74
72
  },
75
73
  });
@@ -1 +1 @@
1
- {"version":3,"file":"serve.js","sourceRoot":"","sources":["../../src/bin/serve.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"serve.js","sourceRoot":"","sources":["../../src/bin/serve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ -- Nodes as routeable delivery hosts, with explicit delivery contracts.
2
+
3
+ ALTER TABLE nodes ADD COLUMN kind TEXT NOT NULL DEFAULT 'fleet_ws';
4
+ ALTER TABLE nodes ADD COLUMN delivery_adapter TEXT NOT NULL DEFAULT 'fleet.ws.v1';
5
+ ALTER TABLE nodes ADD COLUMN delivery_config TEXT DEFAULT NULL;
6
+
7
+ CREATE TABLE IF NOT EXISTS agent_node_bindings (
8
+ id TEXT PRIMARY KEY,
9
+ workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
10
+ agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
11
+ node_id TEXT NOT NULL REFERENCES nodes(id) ON DELETE CASCADE,
12
+ status TEXT NOT NULL DEFAULT 'active',
13
+ session_ref TEXT,
14
+ priority INTEGER NOT NULL DEFAULT 0,
15
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
16
+ updated_at INTEGER,
17
+ UNIQUE(agent_id, node_id)
18
+ );
19
+
20
+ CREATE INDEX IF NOT EXISTS idx_agent_node_bindings_workspace
21
+ ON agent_node_bindings(workspace_id, status);
22
+
23
+ CREATE INDEX IF NOT EXISTS idx_agent_node_bindings_agent
24
+ ON agent_node_bindings(workspace_id, agent_id, status);
25
+
26
+ CREATE INDEX IF NOT EXISTS idx_agent_node_bindings_node
27
+ ON agent_node_bindings(workspace_id, node_id, status);
28
+
29
+ -- Backfill explicit bindings for existing fleet-hosted agents.
30
+ INSERT OR IGNORE INTO agent_node_bindings (
31
+ id,
32
+ workspace_id,
33
+ agent_id,
34
+ node_id,
35
+ status,
36
+ session_ref,
37
+ priority,
38
+ created_at
39
+ )
40
+ SELECT
41
+ 'anb_' || id,
42
+ workspace_id,
43
+ id,
44
+ location_node_id,
45
+ 'active',
46
+ session_ref,
47
+ 0,
48
+ unixepoch()
49
+ FROM agents
50
+ WHERE location_type = 'via_node'
51
+ AND location_node_id IS NOT NULL;
52
+
53
+ ALTER TABLE deliveries ADD COLUMN route_node_id TEXT DEFAULT NULL REFERENCES nodes(id) ON DELETE SET NULL;
54
+ ALTER TABLE deliveries ADD COLUMN route_node_kind TEXT DEFAULT NULL;
55
+ ALTER TABLE deliveries ADD COLUMN delivery_adapter TEXT DEFAULT NULL;
56
+ ALTER TABLE deliveries ADD COLUMN dispatch_attempts INTEGER NOT NULL DEFAULT 0;
57
+ ALTER TABLE deliveries ADD COLUMN next_attempt_at INTEGER DEFAULT NULL;
58
+ ALTER TABLE deliveries ADD COLUMN last_dispatch_error TEXT DEFAULT NULL;
59
+
60
+ UPDATE deliveries
61
+ SET
62
+ route_node_id = location_node_id,
63
+ route_node_kind = CASE WHEN location_node_id IS NOT NULL THEN 'fleet_ws' ELSE NULL END,
64
+ delivery_adapter = CASE WHEN location_node_id IS NOT NULL THEN 'fleet.ws.v1' ELSE NULL END;
65
+
66
+ CREATE INDEX IF NOT EXISTS idx_deliveries_route_node
67
+ ON deliveries(workspace_id, route_node_id, status, seq);
68
+
69
+ CREATE INDEX IF NOT EXISTS idx_deliveries_next_attempt
70
+ ON deliveries(workspace_id, status, next_attempt_at);
@@ -0,0 +1,13 @@
1
+ -- Keep due HTTP push retries cheap and reconcile binding-backed capacity counts.
2
+
3
+ CREATE INDEX IF NOT EXISTS idx_deliveries_http_push_due
4
+ ON deliveries(workspace_id, route_node_kind, status, next_attempt_at);
5
+
6
+ UPDATE nodes
7
+ SET active_agents = (
8
+ SELECT COUNT(*)
9
+ FROM agent_node_bindings b
10
+ WHERE b.workspace_id = nodes.workspace_id
11
+ AND b.node_id = nodes.id
12
+ AND b.status = 'active'
13
+ );
@@ -0,0 +1,124 @@
1
+ -- Every agent has exactly one node route. Backfill legacy self-connected agents
2
+ -- as implicit direct_ws nodes-of-one.
3
+
4
+ INSERT OR IGNORE INTO nodes (
5
+ id,
6
+ workspace_id,
7
+ name,
8
+ token_hash,
9
+ kind,
10
+ delivery_adapter,
11
+ delivery_config,
12
+ capabilities,
13
+ max_agents,
14
+ active_agents,
15
+ reserved_agents,
16
+ tags,
17
+ version,
18
+ status,
19
+ handlers_live,
20
+ load,
21
+ last_heartbeat_at,
22
+ created_at
23
+ )
24
+ SELECT
25
+ 'node_direct_' || a.id,
26
+ a.workspace_id,
27
+ 'direct-' || a.id,
28
+ 'implicit_direct:' || a.workspace_id || ':' || a.id,
29
+ 'direct_ws',
30
+ 'direct.ws.v1',
31
+ json_object('implicit', 1, 'agent_id', a.id, 'agent_name', a.name),
32
+ json_array(),
33
+ 1,
34
+ 1,
35
+ 0,
36
+ json_array('implicit', 'direct_ws'),
37
+ 'implicit',
38
+ CASE WHEN a.status IN ('active', 'online') THEN 'online' ELSE 'offline' END,
39
+ 0,
40
+ 0,
41
+ CASE WHEN a.status IN ('active', 'online') THEN unixepoch() ELSE NULL END,
42
+ unixepoch()
43
+ FROM agents a
44
+ WHERE NOT EXISTS (
45
+ SELECT 1
46
+ FROM agent_node_bindings b
47
+ WHERE b.workspace_id = a.workspace_id
48
+ AND b.agent_id = a.id
49
+ AND b.status = 'active'
50
+ );
51
+
52
+ INSERT OR IGNORE INTO agent_node_bindings (
53
+ id,
54
+ workspace_id,
55
+ agent_id,
56
+ node_id,
57
+ status,
58
+ session_ref,
59
+ priority,
60
+ created_at,
61
+ updated_at
62
+ )
63
+ SELECT
64
+ 'anb_direct_' || a.id,
65
+ a.workspace_id,
66
+ a.id,
67
+ 'node_direct_' || a.id,
68
+ 'active',
69
+ a.session_ref,
70
+ 0,
71
+ unixepoch(),
72
+ unixepoch()
73
+ FROM agents a
74
+ WHERE EXISTS (
75
+ SELECT 1
76
+ FROM nodes n
77
+ WHERE n.workspace_id = a.workspace_id
78
+ AND n.id = 'node_direct_' || a.id
79
+ AND n.kind = 'direct_ws'
80
+ )
81
+ AND NOT EXISTS (
82
+ SELECT 1
83
+ FROM agent_node_bindings b
84
+ WHERE b.workspace_id = a.workspace_id
85
+ AND b.agent_id = a.id
86
+ AND b.status = 'active'
87
+ );
88
+
89
+ UPDATE agents
90
+ SET
91
+ location_type = 'via_node',
92
+ location_node_id = 'node_direct_' || id,
93
+ origin_node_id = COALESCE(origin_node_id, 'node_direct_' || id)
94
+ WHERE EXISTS (
95
+ SELECT 1
96
+ FROM agent_node_bindings b
97
+ WHERE b.workspace_id = agents.workspace_id
98
+ AND b.agent_id = agents.id
99
+ AND b.node_id = 'node_direct_' || agents.id
100
+ AND b.status = 'active'
101
+ );
102
+
103
+ UPDATE deliveries
104
+ SET
105
+ route_node_id = 'node_direct_' || agent_id,
106
+ route_node_kind = 'direct_ws',
107
+ delivery_adapter = 'direct.ws.v1'
108
+ WHERE route_node_id IS NULL
109
+ AND EXISTS (
110
+ SELECT 1
111
+ FROM agents a
112
+ WHERE a.workspace_id = deliveries.workspace_id
113
+ AND a.id = deliveries.agent_id
114
+ AND a.location_node_id = 'node_direct_' || a.id
115
+ );
116
+
117
+ UPDATE nodes
118
+ SET active_agents = (
119
+ SELECT COUNT(*)
120
+ FROM agent_node_bindings b
121
+ WHERE b.workspace_id = nodes.workspace_id
122
+ AND b.node_id = nodes.id
123
+ AND b.status = 'active'
124
+ );
@@ -0,0 +1,109 @@
1
+ -- Additive follow-up for environments that already ran 0021 before
2
+ -- workspace-consistent binding constraints were introduced.
3
+
4
+ CREATE UNIQUE INDEX IF NOT EXISTS agents_workspace_id_unique
5
+ ON agents(workspace_id, id);
6
+
7
+ CREATE UNIQUE INDEX IF NOT EXISTS nodes_workspace_id_unique
8
+ ON nodes(workspace_id, id);
9
+
10
+ CREATE TABLE IF NOT EXISTS agent_node_bindings_constrained (
11
+ id TEXT PRIMARY KEY,
12
+ workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
13
+ agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
14
+ node_id TEXT NOT NULL REFERENCES nodes(id) ON DELETE CASCADE,
15
+ status TEXT NOT NULL DEFAULT 'active',
16
+ session_ref TEXT,
17
+ priority INTEGER NOT NULL DEFAULT 0,
18
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
19
+ updated_at INTEGER,
20
+ FOREIGN KEY(workspace_id, agent_id) REFERENCES agents(workspace_id, id) ON DELETE CASCADE,
21
+ FOREIGN KEY(workspace_id, node_id) REFERENCES nodes(workspace_id, id) ON DELETE CASCADE,
22
+ UNIQUE(agent_id, node_id)
23
+ );
24
+
25
+ INSERT OR IGNORE INTO agent_node_bindings_constrained (
26
+ id,
27
+ workspace_id,
28
+ agent_id,
29
+ node_id,
30
+ status,
31
+ session_ref,
32
+ priority,
33
+ created_at,
34
+ updated_at
35
+ )
36
+ SELECT
37
+ b.id,
38
+ b.workspace_id,
39
+ b.agent_id,
40
+ b.node_id,
41
+ b.status,
42
+ b.session_ref,
43
+ b.priority,
44
+ b.created_at,
45
+ b.updated_at
46
+ FROM agent_node_bindings b
47
+ INNER JOIN agents a
48
+ ON a.workspace_id = b.workspace_id
49
+ AND a.id = b.agent_id
50
+ INNER JOIN nodes n
51
+ ON n.workspace_id = b.workspace_id
52
+ AND n.id = b.node_id;
53
+
54
+ DROP TABLE agent_node_bindings;
55
+
56
+ ALTER TABLE agent_node_bindings_constrained RENAME TO agent_node_bindings;
57
+
58
+ CREATE INDEX IF NOT EXISTS idx_agent_node_bindings_workspace
59
+ ON agent_node_bindings(workspace_id, status);
60
+
61
+ CREATE INDEX IF NOT EXISTS idx_agent_node_bindings_agent
62
+ ON agent_node_bindings(workspace_id, agent_id, status);
63
+
64
+ CREATE INDEX IF NOT EXISTS idx_agent_node_bindings_node
65
+ ON agent_node_bindings(workspace_id, node_id, status);
66
+
67
+ CREATE TRIGGER IF NOT EXISTS agent_node_bindings_workspace_agent_insert
68
+ BEFORE INSERT ON agent_node_bindings
69
+ WHEN NOT EXISTS (
70
+ SELECT 1 FROM agents a
71
+ WHERE a.workspace_id = NEW.workspace_id
72
+ AND a.id = NEW.agent_id
73
+ )
74
+ BEGIN
75
+ SELECT RAISE(ABORT, 'agent_node_bindings workspace/agent mismatch');
76
+ END;
77
+
78
+ CREATE TRIGGER IF NOT EXISTS agent_node_bindings_workspace_node_insert
79
+ BEFORE INSERT ON agent_node_bindings
80
+ WHEN NOT EXISTS (
81
+ SELECT 1 FROM nodes n
82
+ WHERE n.workspace_id = NEW.workspace_id
83
+ AND n.id = NEW.node_id
84
+ )
85
+ BEGIN
86
+ SELECT RAISE(ABORT, 'agent_node_bindings workspace/node mismatch');
87
+ END;
88
+
89
+ CREATE TRIGGER IF NOT EXISTS agent_node_bindings_workspace_agent_update
90
+ BEFORE UPDATE OF workspace_id, agent_id ON agent_node_bindings
91
+ WHEN NOT EXISTS (
92
+ SELECT 1 FROM agents a
93
+ WHERE a.workspace_id = NEW.workspace_id
94
+ AND a.id = NEW.agent_id
95
+ )
96
+ BEGIN
97
+ SELECT RAISE(ABORT, 'agent_node_bindings workspace/agent mismatch');
98
+ END;
99
+
100
+ CREATE TRIGGER IF NOT EXISTS agent_node_bindings_workspace_node_update
101
+ BEFORE UPDATE OF workspace_id, node_id ON agent_node_bindings
102
+ WHEN NOT EXISTS (
103
+ SELECT 1 FROM nodes n
104
+ WHERE n.workspace_id = NEW.workspace_id
105
+ AND n.id = NEW.node_id
106
+ )
107
+ BEGIN
108
+ SELECT RAISE(ABORT, 'agent_node_bindings workspace/node mismatch');
109
+ END;
@@ -0,0 +1,45 @@
1
+ -- Split node kind (transport) from node role (ownership/capability) and
2
+ -- collapse WebSocket delivery onto one node envelope.
3
+
4
+ ALTER TABLE nodes ADD COLUMN role TEXT NOT NULL DEFAULT 'broker';
5
+ ALTER TABLE deliveries ADD COLUMN route_node_role TEXT DEFAULT NULL;
6
+
7
+ UPDATE nodes
8
+ SET
9
+ role = CASE
10
+ WHEN kind = 'direct_ws' THEN 'direct'
11
+ WHEN kind = 'fleet_ws' THEN 'broker'
12
+ WHEN kind = 'http_push' AND max_agents = 1 THEN 'direct'
13
+ WHEN kind = 'http_push' THEN 'broker'
14
+ ELSE role
15
+ END,
16
+ kind = CASE
17
+ WHEN kind IN ('direct_ws', 'fleet_ws') THEN 'ws'
18
+ ELSE kind
19
+ END,
20
+ delivery_adapter = CASE
21
+ WHEN delivery_adapter IN ('direct.ws.v1', 'fleet.ws.v1') THEN 'ws.node.v1'
22
+ ELSE delivery_adapter
23
+ END;
24
+
25
+ UPDATE deliveries
26
+ SET
27
+ route_node_role = CASE
28
+ WHEN route_node_kind = 'direct_ws' THEN 'direct'
29
+ WHEN route_node_kind = 'fleet_ws' THEN 'broker'
30
+ WHEN route_node_id IS NOT NULL THEN (
31
+ SELECT n.role
32
+ FROM nodes n
33
+ WHERE n.workspace_id = deliveries.workspace_id
34
+ AND n.id = deliveries.route_node_id
35
+ )
36
+ ELSE NULL
37
+ END,
38
+ route_node_kind = CASE
39
+ WHEN route_node_kind IN ('direct_ws', 'fleet_ws') THEN 'ws'
40
+ ELSE route_node_kind
41
+ END,
42
+ delivery_adapter = CASE
43
+ WHEN delivery_adapter IN ('direct.ws.v1', 'fleet.ws.v1') THEN 'ws.node.v1'
44
+ ELSE delivery_adapter
45
+ END;
@@ -0,0 +1,32 @@
1
+ -- Add scoped observer tokens for workspace realtime and read-only REST.
2
+
3
+ CREATE TABLE observer_tokens (
4
+ id TEXT PRIMARY KEY NOT NULL,
5
+ workspace_id TEXT NOT NULL,
6
+ name TEXT NOT NULL,
7
+ description TEXT,
8
+ token_hash TEXT NOT NULL,
9
+ scopes TEXT NOT NULL DEFAULT '[]',
10
+ filters TEXT NOT NULL DEFAULT '{}',
11
+ status TEXT NOT NULL DEFAULT 'active',
12
+ expires_at INTEGER,
13
+ created_by TEXT,
14
+ created_by_type TEXT NOT NULL DEFAULT 'workspace',
15
+ last_used_at INTEGER,
16
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
17
+ updated_at INTEGER,
18
+ revoked_at INTEGER,
19
+ FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE
20
+ );
21
+
22
+ CREATE UNIQUE INDEX observer_tokens_workspace_name_unique
23
+ ON observer_tokens (workspace_id, name);
24
+
25
+ CREATE UNIQUE INDEX observer_tokens_token_hash_unique
26
+ ON observer_tokens (token_hash);
27
+
28
+ CREATE INDEX idx_observer_tokens_workspace_status
29
+ ON observer_tokens (workspace_id, status);
30
+
31
+ CREATE INDEX idx_observer_tokens_expires_at
32
+ ON observer_tokens (expires_at);