@teneo-protocol/sdk 1.0.0

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 (281) hide show
  1. package/.dockerignore +14 -0
  2. package/.env.test.example +14 -0
  3. package/.eslintrc.json +26 -0
  4. package/.github/workflows/claude-code-review.yml +78 -0
  5. package/.github/workflows/claude-reviewer.yml +64 -0
  6. package/.github/workflows/publish-npm.yml +38 -0
  7. package/.github/workflows/push-to-main.yml +23 -0
  8. package/.node-version +1 -0
  9. package/.prettierrc +11 -0
  10. package/Dockerfile +25 -0
  11. package/LICENCE +661 -0
  12. package/README.md +709 -0
  13. package/dist/constants.d.ts +42 -0
  14. package/dist/constants.d.ts.map +1 -0
  15. package/dist/constants.js +45 -0
  16. package/dist/constants.js.map +1 -0
  17. package/dist/core/websocket-client.d.ts +261 -0
  18. package/dist/core/websocket-client.d.ts.map +1 -0
  19. package/dist/core/websocket-client.js +875 -0
  20. package/dist/core/websocket-client.js.map +1 -0
  21. package/dist/formatters/response-formatter.d.ts +354 -0
  22. package/dist/formatters/response-formatter.d.ts.map +1 -0
  23. package/dist/formatters/response-formatter.js +575 -0
  24. package/dist/formatters/response-formatter.js.map +1 -0
  25. package/dist/handlers/message-handler-registry.d.ts +155 -0
  26. package/dist/handlers/message-handler-registry.d.ts.map +1 -0
  27. package/dist/handlers/message-handler-registry.js +216 -0
  28. package/dist/handlers/message-handler-registry.js.map +1 -0
  29. package/dist/handlers/message-handlers/agent-selected-handler.d.ts +112 -0
  30. package/dist/handlers/message-handlers/agent-selected-handler.d.ts.map +1 -0
  31. package/dist/handlers/message-handlers/agent-selected-handler.js +40 -0
  32. package/dist/handlers/message-handlers/agent-selected-handler.js.map +1 -0
  33. package/dist/handlers/message-handlers/agents-list-handler.d.ts +14 -0
  34. package/dist/handlers/message-handlers/agents-list-handler.d.ts.map +1 -0
  35. package/dist/handlers/message-handlers/agents-list-handler.js +25 -0
  36. package/dist/handlers/message-handlers/agents-list-handler.js.map +1 -0
  37. package/dist/handlers/message-handlers/auth-error-handler.d.ts +71 -0
  38. package/dist/handlers/message-handlers/auth-error-handler.d.ts.map +1 -0
  39. package/dist/handlers/message-handlers/auth-error-handler.js +30 -0
  40. package/dist/handlers/message-handlers/auth-error-handler.js.map +1 -0
  41. package/dist/handlers/message-handlers/auth-message-handler.d.ts +18 -0
  42. package/dist/handlers/message-handlers/auth-message-handler.d.ts.map +1 -0
  43. package/dist/handlers/message-handlers/auth-message-handler.js +60 -0
  44. package/dist/handlers/message-handlers/auth-message-handler.js.map +1 -0
  45. package/dist/handlers/message-handlers/auth-required-handler.d.ts +76 -0
  46. package/dist/handlers/message-handlers/auth-required-handler.d.ts.map +1 -0
  47. package/dist/handlers/message-handlers/auth-required-handler.js +23 -0
  48. package/dist/handlers/message-handlers/auth-required-handler.js.map +1 -0
  49. package/dist/handlers/message-handlers/auth-success-handler.d.ts +18 -0
  50. package/dist/handlers/message-handlers/auth-success-handler.d.ts.map +1 -0
  51. package/dist/handlers/message-handlers/auth-success-handler.js +51 -0
  52. package/dist/handlers/message-handlers/auth-success-handler.js.map +1 -0
  53. package/dist/handlers/message-handlers/base-handler.d.ts +55 -0
  54. package/dist/handlers/message-handlers/base-handler.d.ts.map +1 -0
  55. package/dist/handlers/message-handlers/base-handler.js +83 -0
  56. package/dist/handlers/message-handlers/base-handler.js.map +1 -0
  57. package/dist/handlers/message-handlers/challenge-handler.d.ts +73 -0
  58. package/dist/handlers/message-handlers/challenge-handler.d.ts.map +1 -0
  59. package/dist/handlers/message-handlers/challenge-handler.js +47 -0
  60. package/dist/handlers/message-handlers/challenge-handler.js.map +1 -0
  61. package/dist/handlers/message-handlers/error-message-handler.d.ts +76 -0
  62. package/dist/handlers/message-handlers/error-message-handler.d.ts.map +1 -0
  63. package/dist/handlers/message-handlers/error-message-handler.js +29 -0
  64. package/dist/handlers/message-handlers/error-message-handler.js.map +1 -0
  65. package/dist/handlers/message-handlers/index.d.ts +28 -0
  66. package/dist/handlers/message-handlers/index.d.ts.map +1 -0
  67. package/dist/handlers/message-handlers/index.js +100 -0
  68. package/dist/handlers/message-handlers/index.js.map +1 -0
  69. package/dist/handlers/message-handlers/list-rooms-response-handler.d.ts +122 -0
  70. package/dist/handlers/message-handlers/list-rooms-response-handler.d.ts.map +1 -0
  71. package/dist/handlers/message-handlers/list-rooms-response-handler.js +30 -0
  72. package/dist/handlers/message-handlers/list-rooms-response-handler.js.map +1 -0
  73. package/dist/handlers/message-handlers/ping-pong-handler.d.ts +104 -0
  74. package/dist/handlers/message-handlers/ping-pong-handler.d.ts.map +1 -0
  75. package/dist/handlers/message-handlers/ping-pong-handler.js +36 -0
  76. package/dist/handlers/message-handlers/ping-pong-handler.js.map +1 -0
  77. package/dist/handlers/message-handlers/regular-message-handler.d.ts +56 -0
  78. package/dist/handlers/message-handlers/regular-message-handler.d.ts.map +1 -0
  79. package/dist/handlers/message-handlers/regular-message-handler.js +59 -0
  80. package/dist/handlers/message-handlers/regular-message-handler.js.map +1 -0
  81. package/dist/handlers/message-handlers/subscribe-response-handler.d.ts +81 -0
  82. package/dist/handlers/message-handlers/subscribe-response-handler.d.ts.map +1 -0
  83. package/dist/handlers/message-handlers/subscribe-response-handler.js +48 -0
  84. package/dist/handlers/message-handlers/subscribe-response-handler.js.map +1 -0
  85. package/dist/handlers/message-handlers/task-response-handler.d.ts +14 -0
  86. package/dist/handlers/message-handlers/task-response-handler.d.ts.map +1 -0
  87. package/dist/handlers/message-handlers/task-response-handler.js +44 -0
  88. package/dist/handlers/message-handlers/task-response-handler.js.map +1 -0
  89. package/dist/handlers/message-handlers/types.d.ts +51 -0
  90. package/dist/handlers/message-handlers/types.d.ts.map +1 -0
  91. package/dist/handlers/message-handlers/types.js +7 -0
  92. package/dist/handlers/message-handlers/types.js.map +1 -0
  93. package/dist/handlers/message-handlers/unsubscribe-response-handler.d.ts +81 -0
  94. package/dist/handlers/message-handlers/unsubscribe-response-handler.d.ts.map +1 -0
  95. package/dist/handlers/message-handlers/unsubscribe-response-handler.js +48 -0
  96. package/dist/handlers/message-handlers/unsubscribe-response-handler.js.map +1 -0
  97. package/dist/handlers/webhook-handler.d.ts +202 -0
  98. package/dist/handlers/webhook-handler.d.ts.map +1 -0
  99. package/dist/handlers/webhook-handler.js +511 -0
  100. package/dist/handlers/webhook-handler.js.map +1 -0
  101. package/dist/index.d.ts +71 -0
  102. package/dist/index.d.ts.map +1 -0
  103. package/dist/index.js +217 -0
  104. package/dist/index.js.map +1 -0
  105. package/dist/managers/agent-registry.d.ts +173 -0
  106. package/dist/managers/agent-registry.d.ts.map +1 -0
  107. package/dist/managers/agent-registry.js +310 -0
  108. package/dist/managers/agent-registry.js.map +1 -0
  109. package/dist/managers/connection-manager.d.ts +134 -0
  110. package/dist/managers/connection-manager.d.ts.map +1 -0
  111. package/dist/managers/connection-manager.js +176 -0
  112. package/dist/managers/connection-manager.js.map +1 -0
  113. package/dist/managers/index.d.ts +9 -0
  114. package/dist/managers/index.d.ts.map +1 -0
  115. package/dist/managers/index.js +16 -0
  116. package/dist/managers/index.js.map +1 -0
  117. package/dist/managers/message-router.d.ts +112 -0
  118. package/dist/managers/message-router.d.ts.map +1 -0
  119. package/dist/managers/message-router.js +260 -0
  120. package/dist/managers/message-router.js.map +1 -0
  121. package/dist/managers/room-manager.d.ts +165 -0
  122. package/dist/managers/room-manager.d.ts.map +1 -0
  123. package/dist/managers/room-manager.js +227 -0
  124. package/dist/managers/room-manager.js.map +1 -0
  125. package/dist/teneo-sdk.d.ts +703 -0
  126. package/dist/teneo-sdk.d.ts.map +1 -0
  127. package/dist/teneo-sdk.js +907 -0
  128. package/dist/teneo-sdk.js.map +1 -0
  129. package/dist/types/config.d.ts +1047 -0
  130. package/dist/types/config.d.ts.map +1 -0
  131. package/dist/types/config.js +720 -0
  132. package/dist/types/config.js.map +1 -0
  133. package/dist/types/error-codes.d.ts +29 -0
  134. package/dist/types/error-codes.d.ts.map +1 -0
  135. package/dist/types/error-codes.js +41 -0
  136. package/dist/types/error-codes.js.map +1 -0
  137. package/dist/types/events.d.ts +616 -0
  138. package/dist/types/events.d.ts.map +1 -0
  139. package/dist/types/events.js +261 -0
  140. package/dist/types/events.js.map +1 -0
  141. package/dist/types/health.d.ts +40 -0
  142. package/dist/types/health.d.ts.map +1 -0
  143. package/dist/types/health.js +6 -0
  144. package/dist/types/health.js.map +1 -0
  145. package/dist/types/index.d.ts +10 -0
  146. package/dist/types/index.d.ts.map +1 -0
  147. package/dist/types/index.js +123 -0
  148. package/dist/types/index.js.map +1 -0
  149. package/dist/types/messages.d.ts +3734 -0
  150. package/dist/types/messages.d.ts.map +1 -0
  151. package/dist/types/messages.js +482 -0
  152. package/dist/types/messages.js.map +1 -0
  153. package/dist/types/validation.d.ts +81 -0
  154. package/dist/types/validation.d.ts.map +1 -0
  155. package/dist/types/validation.js +115 -0
  156. package/dist/types/validation.js.map +1 -0
  157. package/dist/utils/bounded-queue.d.ts +127 -0
  158. package/dist/utils/bounded-queue.d.ts.map +1 -0
  159. package/dist/utils/bounded-queue.js +181 -0
  160. package/dist/utils/bounded-queue.js.map +1 -0
  161. package/dist/utils/circuit-breaker.d.ts +141 -0
  162. package/dist/utils/circuit-breaker.d.ts.map +1 -0
  163. package/dist/utils/circuit-breaker.js +215 -0
  164. package/dist/utils/circuit-breaker.js.map +1 -0
  165. package/dist/utils/deduplication-cache.d.ts +110 -0
  166. package/dist/utils/deduplication-cache.d.ts.map +1 -0
  167. package/dist/utils/deduplication-cache.js +177 -0
  168. package/dist/utils/deduplication-cache.js.map +1 -0
  169. package/dist/utils/event-waiter.d.ts +101 -0
  170. package/dist/utils/event-waiter.d.ts.map +1 -0
  171. package/dist/utils/event-waiter.js +118 -0
  172. package/dist/utils/event-waiter.js.map +1 -0
  173. package/dist/utils/index.d.ts +51 -0
  174. package/dist/utils/index.d.ts.map +1 -0
  175. package/dist/utils/index.js +72 -0
  176. package/dist/utils/index.js.map +1 -0
  177. package/dist/utils/logger.d.ts +22 -0
  178. package/dist/utils/logger.d.ts.map +1 -0
  179. package/dist/utils/logger.js +91 -0
  180. package/dist/utils/logger.js.map +1 -0
  181. package/dist/utils/rate-limiter.d.ts +122 -0
  182. package/dist/utils/rate-limiter.d.ts.map +1 -0
  183. package/dist/utils/rate-limiter.js +190 -0
  184. package/dist/utils/rate-limiter.js.map +1 -0
  185. package/dist/utils/retry-policy.d.ts +191 -0
  186. package/dist/utils/retry-policy.d.ts.map +1 -0
  187. package/dist/utils/retry-policy.js +225 -0
  188. package/dist/utils/retry-policy.js.map +1 -0
  189. package/dist/utils/secure-private-key.d.ts +113 -0
  190. package/dist/utils/secure-private-key.d.ts.map +1 -0
  191. package/dist/utils/secure-private-key.js +188 -0
  192. package/dist/utils/secure-private-key.js.map +1 -0
  193. package/dist/utils/signature-verifier.d.ts +143 -0
  194. package/dist/utils/signature-verifier.d.ts.map +1 -0
  195. package/dist/utils/signature-verifier.js +238 -0
  196. package/dist/utils/signature-verifier.js.map +1 -0
  197. package/dist/utils/ssrf-validator.d.ts +36 -0
  198. package/dist/utils/ssrf-validator.d.ts.map +1 -0
  199. package/dist/utils/ssrf-validator.js +195 -0
  200. package/dist/utils/ssrf-validator.js.map +1 -0
  201. package/examples/.env.example +17 -0
  202. package/examples/basic-usage.ts +211 -0
  203. package/examples/production-dashboard/.env.example +153 -0
  204. package/examples/production-dashboard/package.json +39 -0
  205. package/examples/production-dashboard/public/dashboard.html +642 -0
  206. package/examples/production-dashboard/server.ts +753 -0
  207. package/examples/webhook-integration.ts +239 -0
  208. package/examples/x-influencer-battle-redesign.html +1065 -0
  209. package/examples/x-influencer-battle-server.ts +217 -0
  210. package/examples/x-influencer-battle.html +787 -0
  211. package/package.json +65 -0
  212. package/src/constants.ts +43 -0
  213. package/src/core/websocket-client.test.ts +512 -0
  214. package/src/core/websocket-client.ts +1056 -0
  215. package/src/formatters/response-formatter.test.ts +571 -0
  216. package/src/formatters/response-formatter.ts +677 -0
  217. package/src/handlers/message-handler-registry.ts +239 -0
  218. package/src/handlers/message-handlers/agent-selected-handler.ts +40 -0
  219. package/src/handlers/message-handlers/agents-list-handler.ts +26 -0
  220. package/src/handlers/message-handlers/auth-error-handler.ts +31 -0
  221. package/src/handlers/message-handlers/auth-message-handler.ts +66 -0
  222. package/src/handlers/message-handlers/auth-required-handler.ts +23 -0
  223. package/src/handlers/message-handlers/auth-success-handler.ts +57 -0
  224. package/src/handlers/message-handlers/base-handler.ts +101 -0
  225. package/src/handlers/message-handlers/challenge-handler.ts +57 -0
  226. package/src/handlers/message-handlers/error-message-handler.ts +27 -0
  227. package/src/handlers/message-handlers/index.ts +77 -0
  228. package/src/handlers/message-handlers/list-rooms-response-handler.ts +28 -0
  229. package/src/handlers/message-handlers/ping-pong-handler.ts +30 -0
  230. package/src/handlers/message-handlers/regular-message-handler.ts +65 -0
  231. package/src/handlers/message-handlers/subscribe-response-handler.ts +47 -0
  232. package/src/handlers/message-handlers/task-response-handler.ts +45 -0
  233. package/src/handlers/message-handlers/types.ts +77 -0
  234. package/src/handlers/message-handlers/unsubscribe-response-handler.ts +47 -0
  235. package/src/handlers/webhook-handler.test.ts +789 -0
  236. package/src/handlers/webhook-handler.ts +576 -0
  237. package/src/index.ts +269 -0
  238. package/src/managers/agent-registry.test.ts +466 -0
  239. package/src/managers/agent-registry.ts +347 -0
  240. package/src/managers/connection-manager.ts +195 -0
  241. package/src/managers/index.ts +9 -0
  242. package/src/managers/message-router.ts +349 -0
  243. package/src/managers/room-manager.ts +248 -0
  244. package/src/teneo-sdk.ts +1022 -0
  245. package/src/types/config.test.ts +325 -0
  246. package/src/types/config.ts +799 -0
  247. package/src/types/error-codes.ts +44 -0
  248. package/src/types/events.test.ts +302 -0
  249. package/src/types/events.ts +382 -0
  250. package/src/types/health.ts +46 -0
  251. package/src/types/index.ts +199 -0
  252. package/src/types/messages.test.ts +660 -0
  253. package/src/types/messages.ts +570 -0
  254. package/src/types/validation.ts +123 -0
  255. package/src/utils/bounded-queue.test.ts +356 -0
  256. package/src/utils/bounded-queue.ts +205 -0
  257. package/src/utils/circuit-breaker.test.ts +394 -0
  258. package/src/utils/circuit-breaker.ts +262 -0
  259. package/src/utils/deduplication-cache.test.ts +380 -0
  260. package/src/utils/deduplication-cache.ts +198 -0
  261. package/src/utils/event-waiter.test.ts +381 -0
  262. package/src/utils/event-waiter.ts +172 -0
  263. package/src/utils/index.ts +74 -0
  264. package/src/utils/logger.ts +87 -0
  265. package/src/utils/rate-limiter.test.ts +341 -0
  266. package/src/utils/rate-limiter.ts +211 -0
  267. package/src/utils/retry-policy.test.ts +558 -0
  268. package/src/utils/retry-policy.ts +272 -0
  269. package/src/utils/secure-private-key.test.ts +356 -0
  270. package/src/utils/secure-private-key.ts +205 -0
  271. package/src/utils/signature-verifier.test.ts +464 -0
  272. package/src/utils/signature-verifier.ts +298 -0
  273. package/src/utils/ssrf-validator.test.ts +372 -0
  274. package/src/utils/ssrf-validator.ts +224 -0
  275. package/tests/integration/real-server.test.ts +740 -0
  276. package/tests/integration/websocket.test.ts +381 -0
  277. package/tests/integration-setup.ts +16 -0
  278. package/tests/setup.ts +34 -0
  279. package/tsconfig.json +32 -0
  280. package/vitest.config.ts +42 -0
  281. package/vitest.integration.config.ts +23 -0
@@ -0,0 +1,642 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Teneo SDK - Production Dashboard</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <style>
9
+ .status-dot {
10
+ animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
11
+ }
12
+ @keyframes pulse {
13
+ 0%, 100% { opacity: 1; }
14
+ 50% { opacity: .5; }
15
+ }
16
+ .event-item {
17
+ animation: slideIn 0.3s ease-out;
18
+ }
19
+ @keyframes slideIn {
20
+ from {
21
+ opacity: 0;
22
+ transform: translateY(-10px);
23
+ }
24
+ to {
25
+ opacity: 1;
26
+ transform: translateY(0);
27
+ }
28
+ }
29
+ .scrollbar-thin::-webkit-scrollbar {
30
+ width: 6px;
31
+ }
32
+ .scrollbar-thin::-webkit-scrollbar-track {
33
+ background: #1f2937;
34
+ }
35
+ .scrollbar-thin::-webkit-scrollbar-thumb {
36
+ background: #4b5563;
37
+ border-radius: 3px;
38
+ }
39
+ </style>
40
+ </head>
41
+ <body class="bg-gray-900 text-gray-100">
42
+ <div class="container mx-auto px-4 py-6 max-w-7xl">
43
+ <!-- Header -->
44
+ <div class="mb-8">
45
+ <h1 class="text-4xl font-bold mb-2 bg-gradient-to-r from-blue-400 to-purple-500 bg-clip-text text-transparent">
46
+ Teneo SDK Production Dashboard
47
+ </h1>
48
+ <p class="text-gray-400">Comprehensive example showcasing all SDK features</p>
49
+ </div>
50
+
51
+ <!-- Status Grid -->
52
+ <div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-6">
53
+ <!-- Connection Status -->
54
+ <div class="bg-gray-800 rounded-lg p-4 border border-gray-700">
55
+ <div class="flex items-center justify-between mb-2">
56
+ <span class="text-gray-400 text-sm">Connection</span>
57
+ <div id="connection-dot" class="status-dot w-3 h-3 rounded-full bg-gray-500"></div>
58
+ </div>
59
+ <div id="connection-status" class="text-2xl font-bold text-gray-500">Connecting...</div>
60
+ </div>
61
+
62
+ <!-- Auth Status -->
63
+ <div class="bg-gray-800 rounded-lg p-4 border border-gray-700">
64
+ <div class="flex items-center justify-between mb-2">
65
+ <span class="text-gray-400 text-sm">Authentication</span>
66
+ <div id="auth-dot" class="status-dot w-3 h-3 rounded-full bg-gray-500"></div>
67
+ </div>
68
+ <div id="auth-status" class="text-2xl font-bold text-gray-500">Pending</div>
69
+ </div>
70
+
71
+ <!-- Agents Count -->
72
+ <div class="bg-gray-800 rounded-lg p-4 border border-gray-700">
73
+ <div class="flex items-center justify-between mb-2">
74
+ <span class="text-gray-400 text-sm">Agents</span>
75
+ <svg class="w-5 h-5 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
76
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path>
77
+ </svg>
78
+ </div>
79
+ <div id="agents-count" class="text-2xl font-bold">0</div>
80
+ </div>
81
+
82
+ <!-- Messages Count -->
83
+ <div class="bg-gray-800 rounded-lg p-4 border border-gray-700">
84
+ <div class="flex items-center justify-between mb-2">
85
+ <span class="text-gray-400 text-sm">Messages</span>
86
+ <svg class="w-5 h-5 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
87
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
88
+ </svg>
89
+ </div>
90
+ <div id="messages-count" class="text-2xl font-bold">0</div>
91
+ </div>
92
+ </div>
93
+
94
+ <!-- Main Content Grid -->
95
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
96
+ <!-- Send Message Panel -->
97
+ <div class="bg-gray-800 rounded-lg p-6 border border-gray-700">
98
+ <h2 class="text-xl font-bold mb-4 flex items-center">
99
+ <svg class="w-6 h-6 mr-2 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
100
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"></path>
101
+ </svg>
102
+ Send Message
103
+ </h2>
104
+ <textarea id="message-input"
105
+ class="w-full bg-gray-700 rounded-lg p-3 mb-3 text-gray-100 border border-gray-600 focus:border-blue-500 focus:outline-none resize-none"
106
+ rows="3"
107
+ placeholder="Enter your message to agents..."></textarea>
108
+ <div class="flex gap-3">
109
+ <button id="send-message-btn"
110
+ class="flex-1 bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-lg transition disabled:opacity-50 disabled:cursor-not-allowed">
111
+ Send Message
112
+ </button>
113
+ <button id="send-wait-btn"
114
+ class="flex-1 bg-purple-600 hover:bg-purple-700 text-white font-semibold py-2 px-4 rounded-lg transition disabled:opacity-50 disabled:cursor-not-allowed">
115
+ Send & Wait
116
+ </button>
117
+ </div>
118
+ </div>
119
+
120
+ <!-- Health Status -->
121
+ <div class="bg-gray-800 rounded-lg p-6 border border-gray-700">
122
+ <h2 class="text-xl font-bold mb-4 flex items-center">
123
+ <svg class="w-6 h-6 mr-2 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
124
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
125
+ </svg>
126
+ System Health
127
+ </h2>
128
+ <div id="health-status" class="space-y-2">
129
+ <div class="flex justify-between items-center">
130
+ <span class="text-gray-400">Overall Status</span>
131
+ <span id="health-overall" class="text-gray-500">Loading...</span>
132
+ </div>
133
+ <div class="flex justify-between items-center">
134
+ <span class="text-gray-400">Webhook Circuit</span>
135
+ <span id="health-circuit" class="text-gray-500">-</span>
136
+ </div>
137
+ <div class="flex justify-between items-center">
138
+ <span class="text-gray-400">Rate Limiter</span>
139
+ <span id="health-ratelimit" class="text-gray-500">-</span>
140
+ </div>
141
+ <div class="flex justify-between items-center">
142
+ <span class="text-gray-400">Uptime</span>
143
+ <span id="health-uptime" class="text-gray-500">-</span>
144
+ </div>
145
+ </div>
146
+ </div>
147
+ </div>
148
+
149
+ <!-- Tabs -->
150
+ <div class="bg-gray-800 rounded-lg border border-gray-700 overflow-hidden">
151
+ <div class="flex border-b border-gray-700">
152
+ <button class="tab-btn active px-6 py-3 font-semibold" data-tab="agents">Agents</button>
153
+ <button class="tab-btn px-6 py-3 font-semibold" data-tab="rooms">Rooms</button>
154
+ <button class="tab-btn px-6 py-3 font-semibold" data-tab="messages">Messages</button>
155
+ <button class="tab-btn px-6 py-3 font-semibold" data-tab="webhooks">Webhooks</button>
156
+ <button class="tab-btn px-6 py-3 font-semibold" data-tab="events">Events</button>
157
+ </div>
158
+
159
+ <div class="p-6">
160
+ <!-- Agents Tab -->
161
+ <div id="agents-tab" class="tab-content">
162
+ <div id="agents-list" class="space-y-3 max-h-96 overflow-y-auto scrollbar-thin">
163
+ <p class="text-gray-500">Loading agents...</p>
164
+ </div>
165
+ </div>
166
+
167
+ <!-- Rooms Tab -->
168
+ <div id="rooms-tab" class="tab-content hidden">
169
+ <div class="mb-4">
170
+ <input id="room-id-input"
171
+ type="text"
172
+ class="bg-gray-700 rounded-lg p-2 text-gray-100 border border-gray-600 focus:border-blue-500 focus:outline-none"
173
+ placeholder="Room ID">
174
+ <button id="subscribe-room-btn" class="ml-2 bg-green-600 hover:bg-green-700 text-white font-semibold py-2 px-4 rounded-lg transition">
175
+ Subscribe
176
+ </button>
177
+ </div>
178
+ <div id="rooms-list" class="space-y-3 max-h-80 overflow-y-auto scrollbar-thin">
179
+ <p class="text-gray-500">Loading rooms...</p>
180
+ </div>
181
+ </div>
182
+
183
+ <!-- Messages Tab -->
184
+ <div id="messages-tab" class="tab-content hidden">
185
+ <div id="messages-list" class="space-y-4 max-h-96 overflow-y-auto scrollbar-thin">
186
+ <p class="text-gray-500">No messages yet. Send a message to see it here!</p>
187
+ </div>
188
+ </div>
189
+
190
+ <!-- Webhooks Tab -->
191
+ <div id="webhooks-tab" class="tab-content hidden">
192
+ <div id="webhooks-list" class="space-y-3 max-h-96 overflow-y-auto scrollbar-thin">
193
+ <p class="text-gray-500">No webhooks received yet.</p>
194
+ </div>
195
+ </div>
196
+
197
+ <!-- Events Tab -->
198
+ <div id="events-tab" class="tab-content hidden">
199
+ <div id="events-list" class="space-y-2 max-h-96 overflow-y-auto scrollbar-thin">
200
+ <p class="text-gray-500">Waiting for events...</p>
201
+ </div>
202
+ </div>
203
+ </div>
204
+ </div>
205
+ </div>
206
+
207
+ <script>
208
+ // State
209
+ let eventSource = null;
210
+ let connectionStatus = 'disconnected';
211
+ let authStatus = 'pending';
212
+
213
+ // Initialize
214
+ document.addEventListener('DOMContentLoaded', () => {
215
+ setupTabs();
216
+ setupEventSource();
217
+ loadInitialData();
218
+ setupMessageSending();
219
+ setupRoomManagement();
220
+ startHealthCheck();
221
+ });
222
+
223
+ // Tab management
224
+ function setupTabs() {
225
+ document.querySelectorAll('.tab-btn').forEach(btn => {
226
+ btn.addEventListener('click', () => {
227
+ const tab = btn.dataset.tab;
228
+ document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active', 'bg-gray-700', 'text-blue-400'));
229
+ document.querySelectorAll('.tab-content').forEach(c => c.classList.add('hidden'));
230
+ btn.classList.add('active', 'bg-gray-700', 'text-blue-400');
231
+ document.getElementById(`${tab}-tab`).classList.remove('hidden');
232
+ });
233
+ });
234
+ }
235
+
236
+ // Server-Sent Events
237
+ function setupEventSource() {
238
+ eventSource = new EventSource('/api/sse');
239
+
240
+ eventSource.addEventListener('message', (e) => {
241
+ try {
242
+ const data = JSON.parse(e.data);
243
+ handleSSEEvent(data);
244
+ } catch (error) {
245
+ console.error('SSE parse error:', error);
246
+ }
247
+ });
248
+
249
+ eventSource.addEventListener('error', () => {
250
+ console.error('SSE connection error');
251
+ setTimeout(setupEventSource, 5000);
252
+ });
253
+ }
254
+
255
+ function handleSSEEvent(data) {
256
+ switch (data.type) {
257
+ case 'connection':
258
+ updateConnectionStatus(data.status);
259
+ break;
260
+ case 'auth':
261
+ updateAuthStatus(data.status);
262
+ break;
263
+ case 'agent:selected':
264
+ addEventItem(`Agent Selected: ${data.data.agentName}`, 'blue');
265
+ break;
266
+ case 'agent:response':
267
+ addEventItem(`Agent Response from ${data.response.agentName}`, 'green');
268
+ loadMessages();
269
+ break;
270
+ case 'message:updated':
271
+ addEventItem(`Message Updated: Full response received`, 'green');
272
+ loadMessages();
273
+ break;
274
+ case 'agent:list':
275
+ loadAgents();
276
+ break;
277
+ case 'room:subscribed':
278
+ addEventItem(`Subscribed to room: ${data.data.roomId}`, 'green');
279
+ loadRooms();
280
+ break;
281
+ case 'room:unsubscribed':
282
+ addEventItem(`Unsubscribed from room: ${data.data.roomId}`, 'yellow');
283
+ loadRooms();
284
+ break;
285
+ case 'room:list':
286
+ addEventItem(`Room list updated (${data.rooms.length} rooms)`, 'blue');
287
+ break;
288
+ case 'webhook:received':
289
+ addEventItem(`Webhook: ${data.payload.event}`, 'purple');
290
+ loadWebhooks();
291
+ break;
292
+ case 'error':
293
+ addEventItem(`Error: ${data.error.message}`, 'red');
294
+ break;
295
+ }
296
+ }
297
+
298
+ // Load initial data
299
+ async function loadInitialData() {
300
+ await Promise.all([
301
+ loadAgents(),
302
+ loadRooms(),
303
+ loadMessages(),
304
+ loadWebhooks(),
305
+ loadEvents(),
306
+ loadMetrics()
307
+ ]);
308
+ }
309
+
310
+ // Load agents
311
+ async function loadAgents() {
312
+ try {
313
+ const response = await fetch('/api/agents');
314
+ const agents = await response.json();
315
+ document.getElementById('agents-count').textContent = agents.length;
316
+
317
+ const list = document.getElementById('agents-list');
318
+ if (agents.length === 0) {
319
+ list.innerHTML = '<p class="text-gray-500">No agents available</p>';
320
+ return;
321
+ }
322
+
323
+ list.innerHTML = agents.map(agent => `
324
+ <div class="bg-gray-700 rounded-lg p-4 border border-gray-600">
325
+ <div class="flex items-center justify-between mb-2">
326
+ <span class="font-semibold">${agent.name}</span>
327
+ <span class="text-xs px-2 py-1 rounded ${agent.status === 'online' ? 'bg-green-600' : 'bg-gray-600'}">${agent.status || 'unknown'}</span>
328
+ </div>
329
+ <p class="text-sm text-gray-400">${agent.description || 'No description'}</p>
330
+ ${agent.capabilities ? `
331
+ <div class="mt-2 flex flex-wrap gap-1">
332
+ ${agent.capabilities.map(cap => `<span class="text-xs px-2 py-1 bg-blue-900 rounded">${cap.name}</span>`).join('')}
333
+ </div>
334
+ ` : ''}
335
+ </div>
336
+ `).join('');
337
+ } catch (error) {
338
+ console.error('Failed to load agents:', error);
339
+ }
340
+ }
341
+
342
+ // Load rooms
343
+ async function loadRooms() {
344
+ try {
345
+ const response = await fetch('/api/rooms');
346
+ const rooms = await response.json();
347
+
348
+ const list = document.getElementById('rooms-list');
349
+ if (rooms.length === 0) {
350
+ list.innerHTML = '<p class="text-gray-500">No rooms available</p>';
351
+ return;
352
+ }
353
+
354
+ list.innerHTML = rooms.map(room => `
355
+ <div class="bg-gray-700 rounded-lg p-4 border border-gray-600">
356
+ <div class="flex items-center justify-between">
357
+ <div>
358
+ <span class="font-semibold">${room.name || room.id}</span>
359
+ <p class="text-sm text-gray-400">${room.id}</p>
360
+ </div>
361
+ <button onclick="unsubscribeRoom('${room.id}')" class="bg-red-600 hover:bg-red-700 text-white text-sm py-1 px-3 rounded transition">
362
+ Unsubscribe
363
+ </button>
364
+ </div>
365
+ </div>
366
+ `).join('');
367
+ } catch (error) {
368
+ console.error('Failed to load rooms:', error);
369
+ }
370
+ }
371
+
372
+ // Load messages
373
+ async function loadMessages() {
374
+ try {
375
+ const response = await fetch('/api/messages');
376
+ const messages = await response.json();
377
+ document.getElementById('messages-count').textContent = messages.length;
378
+
379
+ const list = document.getElementById('messages-list');
380
+ if (messages.length === 0) {
381
+ list.innerHTML = '<p class="text-gray-500">No messages yet</p>';
382
+ return;
383
+ }
384
+
385
+ list.innerHTML = messages.map(msg => `
386
+ <div class="bg-gray-700 rounded-lg p-4 border border-gray-600">
387
+ <div class="flex items-center justify-between mb-2">
388
+ <span class="text-sm text-gray-400">${new Date(msg.timestamp).toLocaleTimeString()}</span>
389
+ <span class="text-xs px-2 py-1 rounded ${msg.response ? 'bg-green-600' : 'bg-yellow-600'}">
390
+ ${msg.response ? 'Responded' : 'Pending'}
391
+ </span>
392
+ </div>
393
+ <p class="text-sm mb-2">${msg.content}</p>
394
+ ${msg.response ? `
395
+ <div class="mt-3 p-3 bg-gray-800 rounded border-l-4 border-green-500">
396
+ <p class="text-xs text-gray-400 mb-1">Response from ${msg.response.agentName}:</p>
397
+ <p class="text-sm">${msg.response.humanized || msg.response.content}</p>
398
+ </div>
399
+ ` : ''}
400
+ </div>
401
+ `).join('');
402
+ } catch (error) {
403
+ console.error('Failed to load messages:', error);
404
+ }
405
+ }
406
+
407
+ // Load webhooks
408
+ async function loadWebhooks() {
409
+ try {
410
+ const response = await fetch('/api/webhooks');
411
+ const webhooks = await response.json();
412
+
413
+ const list = document.getElementById('webhooks-list');
414
+ if (webhooks.length === 0) {
415
+ list.innerHTML = '<p class="text-gray-500">No webhooks received yet</p>';
416
+ return;
417
+ }
418
+
419
+ list.innerHTML = webhooks.map(wh => `
420
+ <div class="bg-gray-700 rounded-lg p-3 border border-gray-600">
421
+ <div class="flex items-center justify-between mb-1">
422
+ <span class="font-mono text-sm text-purple-400">${wh.event}</span>
423
+ <span class="text-xs text-gray-400">${new Date(wh.receivedAt).toLocaleTimeString()}</span>
424
+ </div>
425
+ <pre class="text-xs text-gray-400 overflow-x-auto">${JSON.stringify(wh.data, null, 2)}</pre>
426
+ </div>
427
+ `).join('');
428
+ } catch (error) {
429
+ console.error('Failed to load webhooks:', error);
430
+ }
431
+ }
432
+
433
+ // Load events
434
+ async function loadEvents() {
435
+ try {
436
+ const response = await fetch('/api/events');
437
+ const events = await response.json();
438
+
439
+ const list = document.getElementById('events-list');
440
+ if (events.length === 0) {
441
+ list.innerHTML = '<p class="text-gray-500">No events yet</p>';
442
+ return;
443
+ }
444
+
445
+ list.innerHTML = events.map(evt => `
446
+ <div class="event-item bg-gray-700 rounded p-2 border border-gray-600">
447
+ <div class="flex items-center justify-between">
448
+ <span class="font-mono text-xs text-blue-400">${evt.type}</span>
449
+ <span class="text-xs text-gray-400">${new Date(evt.timestamp).toLocaleTimeString()}</span>
450
+ </div>
451
+ <p class="text-xs text-gray-400 mt-1">${JSON.stringify(evt.data)}</p>
452
+ </div>
453
+ `).join('');
454
+ } catch (error) {
455
+ console.error('Failed to load events:', error);
456
+ }
457
+ }
458
+
459
+ // Load metrics
460
+ async function loadMetrics() {
461
+ try {
462
+ const response = await fetch('/metrics');
463
+ const metrics = await response.json();
464
+
465
+ document.getElementById('health-ratelimit').textContent = metrics.messages?.sent || 0;
466
+ } catch (error) {
467
+ console.error('Failed to load metrics:', error);
468
+ }
469
+ }
470
+
471
+ // Message sending
472
+ function setupMessageSending() {
473
+ document.getElementById('send-message-btn').addEventListener('click', () => sendMessage(false));
474
+ document.getElementById('send-wait-btn').addEventListener('click', () => sendMessage(true));
475
+ }
476
+
477
+ async function sendMessage(waitForResponse) {
478
+ const input = document.getElementById('message-input');
479
+ const content = input.value.trim();
480
+
481
+ if (!content) return;
482
+
483
+ try {
484
+ const response = await fetch('/api/message', {
485
+ method: 'POST',
486
+ headers: { 'Content-Type': 'application/json' },
487
+ body: JSON.stringify({ content, waitForResponse })
488
+ });
489
+
490
+ if (response.ok) {
491
+ input.value = '';
492
+ addEventItem(`Sent: ${content}`, 'green');
493
+ setTimeout(loadMessages, 500);
494
+ } else {
495
+ addEventItem('Failed to send message', 'red');
496
+ }
497
+ } catch (error) {
498
+ console.error('Send error:', error);
499
+ addEventItem('Error sending message', 'red');
500
+ }
501
+ }
502
+
503
+ // Room management
504
+ function setupRoomManagement() {
505
+ document.getElementById('subscribe-room-btn').addEventListener('click', async () => {
506
+ const input = document.getElementById('room-id-input');
507
+ const roomId = input.value.trim();
508
+
509
+ if (!roomId) return;
510
+
511
+ try {
512
+ const response = await fetch('/api/room/join', {
513
+ method: 'POST',
514
+ headers: { 'Content-Type': 'application/json' },
515
+ body: JSON.stringify({ roomId })
516
+ });
517
+
518
+ if (response.ok) {
519
+ input.value = '';
520
+ addEventItem(`Subscribing to room: ${roomId}`, 'green');
521
+ setTimeout(loadRooms, 500);
522
+ }
523
+ } catch (error) {
524
+ console.error('Subscribe room error:', error);
525
+ }
526
+ });
527
+ }
528
+
529
+ async function unsubscribeRoom(roomId) {
530
+ try {
531
+ const response = await fetch('/api/room/leave', {
532
+ method: 'POST',
533
+ headers: { 'Content-Type': 'application/json' },
534
+ body: JSON.stringify({ roomId })
535
+ });
536
+
537
+ if (response.ok) {
538
+ addEventItem(`Unsubscribing from room: ${roomId}`, 'yellow');
539
+ setTimeout(loadRooms, 500);
540
+ }
541
+ } catch (error) {
542
+ console.error('Unsubscribe room error:', error);
543
+ }
544
+ }
545
+
546
+ // Update status displays
547
+ function updateConnectionStatus(status) {
548
+ connectionStatus = status;
549
+ const dot = document.getElementById('connection-dot');
550
+ const text = document.getElementById('connection-status');
551
+
552
+ if (status === 'connected') {
553
+ dot.className = 'status-dot w-3 h-3 rounded-full bg-green-500';
554
+ text.textContent = 'Connected';
555
+ text.className = 'text-2xl font-bold text-green-500';
556
+ document.getElementById('send-message-btn').disabled = false;
557
+ document.getElementById('send-wait-btn').disabled = false;
558
+ } else if (status === 'reconnecting') {
559
+ dot.className = 'status-dot w-3 h-3 rounded-full bg-yellow-500';
560
+ text.textContent = 'Reconnecting';
561
+ text.className = 'text-2xl font-bold text-yellow-500';
562
+ } else {
563
+ dot.className = 'status-dot w-3 h-3 rounded-full bg-red-500';
564
+ text.textContent = 'Disconnected';
565
+ text.className = 'text-2xl font-bold text-red-500';
566
+ document.getElementById('send-message-btn').disabled = true;
567
+ document.getElementById('send-wait-btn').disabled = true;
568
+ }
569
+ }
570
+
571
+ function updateAuthStatus(status) {
572
+ authStatus = status;
573
+ const dot = document.getElementById('auth-dot');
574
+ const text = document.getElementById('auth-status');
575
+
576
+ if (status === 'success') {
577
+ dot.className = 'status-dot w-3 h-3 rounded-full bg-green-500';
578
+ text.textContent = 'Authenticated';
579
+ text.className = 'text-2xl font-bold text-green-500';
580
+ } else {
581
+ dot.className = 'status-dot w-3 h-3 rounded-full bg-yellow-500';
582
+ text.textContent = 'Pending';
583
+ text.className = 'text-2xl font-bold text-yellow-500';
584
+ }
585
+ }
586
+
587
+ // Health check
588
+ function startHealthCheck() {
589
+ setInterval(async () => {
590
+ try {
591
+ const response = await fetch('/health');
592
+ const health = await response.json();
593
+
594
+ document.getElementById('health-overall').textContent = health.status;
595
+ document.getElementById('health-overall').className = health.status === 'healthy' ? 'text-green-500' : 'text-yellow-500';
596
+ document.getElementById('health-circuit').textContent = health.webhook?.circuitState || 'N/A';
597
+ document.getElementById('health-uptime').textContent = formatUptime(health.timestamp);
598
+ } catch (error) {
599
+ console.error('Health check failed:', error);
600
+ }
601
+ }, 5000);
602
+ }
603
+
604
+ function formatUptime(timestamp) {
605
+ const seconds = Math.floor((Date.now() - new Date(timestamp).getTime()) / 1000);
606
+ const hours = Math.floor(seconds / 3600);
607
+ const minutes = Math.floor((seconds % 3600) / 60);
608
+ return `${hours}h ${minutes}m`;
609
+ }
610
+
611
+ function addEventItem(message, color) {
612
+ const list = document.getElementById('events-list');
613
+ const colorClass = {
614
+ 'blue': 'border-blue-500',
615
+ 'green': 'border-green-500',
616
+ 'red': 'border-red-500',
617
+ 'yellow': 'border-yellow-500',
618
+ 'purple': 'border-purple-500'
619
+ }[color] || 'border-gray-500';
620
+
621
+ const item = document.createElement('div');
622
+ item.className = `event-item bg-gray-700 rounded p-2 border-l-4 ${colorClass}`;
623
+ item.innerHTML = `
624
+ <div class="flex items-center justify-between">
625
+ <span class="text-sm">${message}</span>
626
+ <span class="text-xs text-gray-400">${new Date().toLocaleTimeString()}</span>
627
+ </div>
628
+ `;
629
+
630
+ if (list.firstChild && list.firstChild.textContent.includes('Waiting for events')) {
631
+ list.innerHTML = '';
632
+ }
633
+
634
+ list.insertBefore(item, list.firstChild);
635
+
636
+ if (list.children.length > 50) {
637
+ list.removeChild(list.lastChild);
638
+ }
639
+ }
640
+ </script>
641
+ </body>
642
+ </html>