@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,381 @@
1
+ import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } from "vitest";
2
+ import WebSocket, { WebSocketServer } from "ws";
3
+ import { TeneoSDK } from "../../src";
4
+ import { SDKConfigBuilder } from "../../src/types";
5
+ import { privateKeyToAccount } from "viem/accounts";
6
+ import { generatePrivateKey } from "viem/accounts";
7
+
8
+ describe("WebSocket Integration Tests", () => {
9
+ let server: WebSocketServer;
10
+ let sdk: TeneoSDK;
11
+ let serverPort: number;
12
+ let privateKey: string;
13
+ let walletAddress: string;
14
+
15
+ // Mock server to simulate Teneo WebSocket server
16
+ beforeAll(() => {
17
+ serverPort = 8081;
18
+ privateKey = generatePrivateKey();
19
+ const account = privateKeyToAccount(privateKey);
20
+ walletAddress = account.address;
21
+
22
+ // Create WebSocket server
23
+ server = new WebSocketServer({ port: serverPort });
24
+
25
+ server.on("connection", (ws) => {
26
+ const subscribedRooms = new Set<string>();
27
+
28
+ ws.on("message", (data) => {
29
+ const message = JSON.parse(data.toString());
30
+
31
+ // Handle different message types
32
+ switch (message.type) {
33
+ case "request_challenge":
34
+ ws.send(
35
+ JSON.stringify({
36
+ type: "challenge",
37
+ data: {
38
+ challenge: "test-challenge-" + Date.now(),
39
+ timestamp: Date.now()
40
+ }
41
+ })
42
+ );
43
+ break;
44
+
45
+ case "auth":
46
+ ws.send(
47
+ JSON.stringify({
48
+ type: "auth_success",
49
+ data: {
50
+ id: "client-123",
51
+ type: "user",
52
+ address: message.data.address,
53
+ nft_verified: false,
54
+ is_whitelisted: true,
55
+ rooms: []
56
+ }
57
+ })
58
+ );
59
+ break;
60
+
61
+ case "message":
62
+ // Echo back as task response
63
+ ws.send(
64
+ JSON.stringify({
65
+ type: "task_response",
66
+ content: `Response to: ${message.content}`,
67
+ content_type: "text/plain",
68
+ from: "test-agent",
69
+ data: {
70
+ task_id: "task-" + Date.now(),
71
+ agent_name: "Test Agent",
72
+ success: true
73
+ }
74
+ })
75
+ );
76
+ break;
77
+
78
+ case "ping":
79
+ ws.send(JSON.stringify({ type: "pong" }));
80
+ break;
81
+
82
+ case "subscribe":
83
+ // Add room to subscribed rooms
84
+ subscribedRooms.add(message.data.room_id);
85
+ // Send subscribe response with updated subscriptions list
86
+ ws.send(
87
+ JSON.stringify({
88
+ type: "subscribe",
89
+ data: {
90
+ room_id: message.data.room_id,
91
+ success: true,
92
+ message: "Subscribed successfully",
93
+ subscriptions: Array.from(subscribedRooms)
94
+ }
95
+ })
96
+ );
97
+ // Also send agents list for the room
98
+ ws.send(
99
+ JSON.stringify({
100
+ type: "agents",
101
+ from: "system",
102
+ data: [
103
+ {
104
+ id: "agent-1",
105
+ name: "Test Agent 1",
106
+ room: message.data.room_id,
107
+ status: "online"
108
+ }
109
+ ]
110
+ })
111
+ );
112
+ break;
113
+
114
+ case "unsubscribe":
115
+ // Remove room from subscribed rooms
116
+ subscribedRooms.delete(message.data.room_id);
117
+ // Send unsubscribe response with updated subscriptions list
118
+ ws.send(
119
+ JSON.stringify({
120
+ type: "unsubscribe",
121
+ data: {
122
+ room_id: message.data.room_id,
123
+ success: true,
124
+ message: "Unsubscribed successfully",
125
+ subscriptions: Array.from(subscribedRooms)
126
+ }
127
+ })
128
+ );
129
+ break;
130
+ }
131
+ });
132
+
133
+ ws.on("close", () => {
134
+ // Handle client disconnect
135
+ });
136
+ });
137
+ });
138
+
139
+ afterAll(async () => {
140
+ return new Promise<void>((resolve) => {
141
+ server.close(() => {
142
+ resolve();
143
+ });
144
+ });
145
+ });
146
+
147
+ beforeEach(() => {
148
+ const config = new SDKConfigBuilder()
149
+ .withWebSocketUrl(`ws://localhost:${serverPort}`)
150
+ .withAuthentication(privateKey)
151
+ .withReconnection(false) // Disable for tests
152
+ .withAutoJoinRooms(["test-room"]) // Auto-join test room
153
+ .build();
154
+
155
+ sdk = new TeneoSDK(config);
156
+ });
157
+
158
+ afterEach(async () => {
159
+ await sdk.disconnect();
160
+ });
161
+
162
+ describe("Connection and Authentication", () => {
163
+ it("should connect to WebSocket server", async () => {
164
+ await sdk.connect();
165
+ const state = sdk.getConnectionState();
166
+ expect(state.connected).toBe(true);
167
+ }, 15000);
168
+
169
+ it("should authenticate successfully", async () => {
170
+ const authPromise = new Promise((resolve) => {
171
+ sdk.on("auth:success", resolve);
172
+ });
173
+
174
+ await sdk.connect();
175
+ await authPromise;
176
+
177
+ const state = sdk.getConnectionState();
178
+ expect(state.authenticated).toBe(true);
179
+ }, 15000);
180
+
181
+ it("should handle challenge-response authentication flow", async () => {
182
+ const challengeReceived = new Promise((resolve) => {
183
+ sdk.on("auth:challenge", resolve);
184
+ });
185
+
186
+ const authSuccess = new Promise((resolve) => {
187
+ sdk.on("auth:success", resolve);
188
+ });
189
+
190
+ await sdk.connect();
191
+ await challengeReceived;
192
+ await authSuccess;
193
+
194
+ expect(sdk.getConnectionState().authenticated).toBe(true);
195
+ }, 15000);
196
+ });
197
+
198
+ describe("Message Exchange", () => {
199
+ beforeEach(async () => {
200
+ const authPromise = new Promise((resolve) => {
201
+ sdk.on("auth:success", resolve);
202
+ });
203
+ await sdk.connect();
204
+ await authPromise;
205
+ });
206
+
207
+ it("should send message and receive response", async () => {
208
+ const responsePromise = new Promise((resolve) => {
209
+ sdk.on("agent:response", resolve);
210
+ });
211
+
212
+ await sdk.sendMessage("Hello, test message", { room: "test-room" });
213
+ const response = await responsePromise;
214
+
215
+ expect(response).toBeDefined();
216
+ expect(response).toHaveProperty("content");
217
+ }, 15000);
218
+
219
+ it.skip("should handle formatted responses", async () => {
220
+ const response = await sdk.sendMessage("Test message", {
221
+ room: "test-room",
222
+ waitForResponse: true
223
+ });
224
+ expect(response).toContain("Response to: Test message");
225
+ }, 15000);
226
+ });
227
+
228
+ describe("Room Management", () => {
229
+ beforeEach(async () => {
230
+ const authPromise = new Promise((resolve) => {
231
+ sdk.on("auth:success", resolve);
232
+ });
233
+ await sdk.connect();
234
+ await authPromise;
235
+ });
236
+
237
+ it.skip("should join room and receive agents list", async () => {
238
+ const agentsPromise = new Promise((resolve) => {
239
+ sdk.on("agent:list", resolve);
240
+ });
241
+
242
+ await sdk.subscribeToRoom("test-room");
243
+ const agents = await agentsPromise;
244
+
245
+ expect(agents).toBeDefined();
246
+ expect(Array.isArray(agents)).toBe(true);
247
+ }, 15000);
248
+
249
+ it("should track subscribed rooms", async () => {
250
+ const subscribePromise = new Promise((resolve, reject) => {
251
+ sdk.on("room:subscribed", resolve);
252
+ sdk.on("error", reject);
253
+ sdk.on("message:error", reject);
254
+
255
+ // Set a timeout
256
+ setTimeout(() => reject(new Error("Event timeout")), 10000);
257
+ });
258
+
259
+ await sdk.subscribeToRoom("test-room-2"); // Use different room to avoid auto-join conflicts
260
+ await subscribePromise;
261
+
262
+ expect(sdk.getSubscribedRooms()).toContain("test-room-2");
263
+ }, 15000);
264
+ });
265
+
266
+ describe("Error Handling", () => {
267
+ it.skip("should handle connection errors", async () => {
268
+ const badSdk = new TeneoSDK(
269
+ new SDKConfigBuilder()
270
+ .withWebSocketUrl("wss://nonexistent.local:443") // Valid URL, will fail to connect
271
+ .withAuthentication(privateKey)
272
+ .withReconnection(false)
273
+ .build()
274
+ );
275
+
276
+ await expect(badSdk.connect()).rejects.toThrow();
277
+ });
278
+
279
+ it("should handle message send when not connected", async () => {
280
+ await expect(sdk.sendMessage("Test", { room: "test-room" })).rejects.toThrow("Not connected");
281
+ });
282
+ });
283
+
284
+ describe("Webhook Integration", () => {
285
+ it("should trigger webhook on message response", async () => {
286
+ // Configure webhook
287
+ const webhookSdk = new TeneoSDK(
288
+ new SDKConfigBuilder()
289
+ .withWebSocketUrl(`ws://localhost:${serverPort}`)
290
+ .withAuthentication(privateKey)
291
+ .withWebhook("http://localhost:3001/webhook")
292
+ .withReconnection(false)
293
+ .build()
294
+ );
295
+
296
+ const authPromise = new Promise((resolve) => {
297
+ webhookSdk.on("auth:success", resolve);
298
+ });
299
+
300
+ await webhookSdk.connect();
301
+ await authPromise;
302
+
303
+ // Webhook would be triggered but we can't test actual HTTP without a server
304
+ // Just verify the handler is set up
305
+ expect(webhookSdk).toBeDefined();
306
+
307
+ await webhookSdk.disconnect();
308
+ }, 15000);
309
+ });
310
+ });
311
+
312
+ describe("Integration with Real Server", () => {
313
+ const REAL_SERVER_URL = "wss://dev-rooms-websocket-ai-core-o9fmb.ondigitalocean.app/ws";
314
+ let sdk: TeneoSDK;
315
+ let privateKey: string;
316
+
317
+ beforeEach(() => {
318
+ privateKey = generatePrivateKey();
319
+ const config = new SDKConfigBuilder()
320
+ .withWebSocketUrl(REAL_SERVER_URL)
321
+ .withAuthentication(privateKey)
322
+ .withReconnection(false)
323
+ .build();
324
+
325
+ sdk = new TeneoSDK(config);
326
+ });
327
+
328
+ afterEach(async () => {
329
+ await sdk.disconnect();
330
+ });
331
+
332
+ // Skip these tests by default - only run when explicitly testing against real server
333
+ it.skip("should connect to real Teneo server", async () => {
334
+ await sdk.connect();
335
+ expect(sdk.getConnectionState().connected).toBe(true);
336
+ });
337
+
338
+ it.skip("should authenticate with real server", async () => {
339
+ await sdk.connect();
340
+
341
+ const authSuccess = new Promise((resolve, reject) => {
342
+ sdk.on("auth:success", resolve);
343
+ sdk.on("auth:error", reject);
344
+ setTimeout(() => reject(new Error("Auth timeout")), 10000);
345
+ });
346
+
347
+ const result = await authSuccess;
348
+ expect(result).toBeDefined();
349
+ });
350
+
351
+ it.skip("should receive agent list from real server", async () => {
352
+ await sdk.connect();
353
+
354
+ await new Promise((resolve) => {
355
+ sdk.on("auth:success", resolve);
356
+ });
357
+
358
+ const agents = await sdk.getAgents();
359
+ expect(Array.isArray(agents)).toBe(true);
360
+ });
361
+
362
+ it.skip("should send message to real coordinator", async () => {
363
+ await sdk.connect();
364
+
365
+ await new Promise((resolve) => {
366
+ sdk.on("auth:success", resolve);
367
+ });
368
+
369
+ const responsePromise = new Promise((resolve, reject) => {
370
+ sdk.on("agent:selected", resolve);
371
+ sdk.on("error", reject);
372
+ setTimeout(() => reject(new Error("Response timeout")), 15000);
373
+ });
374
+
375
+ await sdk.sendMessage("Hello, can you help me?", { room: "test-room" });
376
+ const response = await responsePromise;
377
+
378
+ expect(response).toBeDefined();
379
+ expect(response).toHaveProperty("data");
380
+ });
381
+ });
@@ -0,0 +1,16 @@
1
+ import { TextEncoder, TextDecoder } from "util";
2
+ import { config } from "dotenv";
3
+ import { resolve } from "path";
4
+
5
+ // Load .env.test file for integration tests
6
+ config({ path: resolve(__dirname, "../.env.test") });
7
+
8
+ // Polyfill TextEncoder/TextDecoder for Node.js environment
9
+ global.TextEncoder = TextEncoder as any;
10
+ global.TextDecoder = TextDecoder as any;
11
+
12
+ // Set test environment variables
13
+ process.env.NODE_ENV = "test";
14
+
15
+ // For integration tests, we need REAL timers and REAL console output
16
+ // Do NOT mock console or timers for integration tests
package/tests/setup.ts ADDED
@@ -0,0 +1,34 @@
1
+ import { vi, afterEach, afterAll } from "vitest";
2
+ import { TextEncoder, TextDecoder } from "util";
3
+
4
+ // Polyfill TextEncoder/TextDecoder for Node.js environment
5
+ global.TextEncoder = TextEncoder as any;
6
+ global.TextDecoder = TextDecoder as any;
7
+
8
+ // Mock console methods to reduce test output noise
9
+ global.console = {
10
+ ...console,
11
+ log: vi.fn(),
12
+ debug: vi.fn(),
13
+ info: vi.fn(),
14
+ warn: vi.fn(),
15
+ // Keep error for debugging failed tests
16
+ error: console.error
17
+ };
18
+
19
+ // Set test environment variables
20
+ process.env.NODE_ENV = "test";
21
+
22
+ // Mock timers for testing reconnection logic
23
+ vi.useFakeTimers({ shouldAdvanceTime: true });
24
+
25
+ // Clean up after each test
26
+ afterEach(() => {
27
+ vi.clearAllMocks();
28
+ vi.clearAllTimers();
29
+ });
30
+
31
+ // Restore real timers after all tests
32
+ afterAll(() => {
33
+ vi.useRealTimers();
34
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "lib": ["ES2020"],
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ "sourceMap": true,
15
+ "resolveJsonModule": true,
16
+ "moduleResolution": "node",
17
+ "allowSyntheticDefaultImports": true,
18
+ "noImplicitAny": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "noImplicitReturns": true,
22
+ "noFallthroughCasesInSwitch": true,
23
+ "strictNullChecks": true,
24
+ "strictFunctionTypes": true,
25
+ "strictBindCallApply": true,
26
+ "strictPropertyInitialization": true,
27
+ "noImplicitThis": true,
28
+ "alwaysStrict": true
29
+ },
30
+ "include": ["src/**/*"],
31
+ "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
32
+ }
@@ -0,0 +1,42 @@
1
+ import { defineConfig } from "vitest/config";
2
+ import path from "path";
3
+
4
+ export default defineConfig({
5
+ test: {
6
+ globals: true,
7
+ environment: "node",
8
+ coverage: {
9
+ provider: "v8",
10
+ reporter: ["text", "json", "html", "lcov"],
11
+ exclude: [
12
+ "node_modules/**",
13
+ "dist/**",
14
+ "examples/**",
15
+ "**/*.test.ts",
16
+ "**/*.spec.ts",
17
+ "**/index.ts",
18
+ "vitest.config.ts"
19
+ ],
20
+ thresholds: {
21
+ lines: 80,
22
+ functions: 80,
23
+ branches: 80,
24
+ statements: 80
25
+ }
26
+ },
27
+ include: ["src/**/*.test.ts", "src/**/*.spec.ts", "tests/**/*.test.ts", "tests/**/*.spec.ts"],
28
+ setupFiles: ["./tests/setup.ts"],
29
+ testTimeout: 10000,
30
+ hookTimeout: 10000
31
+ },
32
+ resolve: {
33
+ alias: {
34
+ "@": path.resolve(__dirname, "./src"),
35
+ "@types": path.resolve(__dirname, "./src/types"),
36
+ "@core": path.resolve(__dirname, "./src/core"),
37
+ "@handlers": path.resolve(__dirname, "./src/handlers"),
38
+ "@formatters": path.resolve(__dirname, "./src/formatters"),
39
+ "@utils": path.resolve(__dirname, "./src/utils")
40
+ }
41
+ }
42
+ });
@@ -0,0 +1,23 @@
1
+ import { defineConfig } from "vitest/config";
2
+ import path from "path";
3
+
4
+ export default defineConfig({
5
+ test: {
6
+ globals: true,
7
+ environment: "node",
8
+ include: ["tests/integration/**/*.test.ts"],
9
+ setupFiles: ["./tests/integration-setup.ts"],
10
+ testTimeout: 60000,
11
+ hookTimeout: 60000
12
+ },
13
+ resolve: {
14
+ alias: {
15
+ "@": path.resolve(__dirname, "./src"),
16
+ "@types": path.resolve(__dirname, "./src/types"),
17
+ "@core": path.resolve(__dirname, "./src/core"),
18
+ "@handlers": path.resolve(__dirname, "./src/handlers"),
19
+ "@formatters": path.resolve(__dirname, "./src/formatters"),
20
+ "@utils": path.resolve(__dirname, "./src/utils")
21
+ }
22
+ }
23
+ });