@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.
- package/.dockerignore +14 -0
- package/.env.test.example +14 -0
- package/.eslintrc.json +26 -0
- package/.github/workflows/claude-code-review.yml +78 -0
- package/.github/workflows/claude-reviewer.yml +64 -0
- package/.github/workflows/publish-npm.yml +38 -0
- package/.github/workflows/push-to-main.yml +23 -0
- package/.node-version +1 -0
- package/.prettierrc +11 -0
- package/Dockerfile +25 -0
- package/LICENCE +661 -0
- package/README.md +709 -0
- package/dist/constants.d.ts +42 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +45 -0
- package/dist/constants.js.map +1 -0
- package/dist/core/websocket-client.d.ts +261 -0
- package/dist/core/websocket-client.d.ts.map +1 -0
- package/dist/core/websocket-client.js +875 -0
- package/dist/core/websocket-client.js.map +1 -0
- package/dist/formatters/response-formatter.d.ts +354 -0
- package/dist/formatters/response-formatter.d.ts.map +1 -0
- package/dist/formatters/response-formatter.js +575 -0
- package/dist/formatters/response-formatter.js.map +1 -0
- package/dist/handlers/message-handler-registry.d.ts +155 -0
- package/dist/handlers/message-handler-registry.d.ts.map +1 -0
- package/dist/handlers/message-handler-registry.js +216 -0
- package/dist/handlers/message-handler-registry.js.map +1 -0
- package/dist/handlers/message-handlers/agent-selected-handler.d.ts +112 -0
- package/dist/handlers/message-handlers/agent-selected-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/agent-selected-handler.js +40 -0
- package/dist/handlers/message-handlers/agent-selected-handler.js.map +1 -0
- package/dist/handlers/message-handlers/agents-list-handler.d.ts +14 -0
- package/dist/handlers/message-handlers/agents-list-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/agents-list-handler.js +25 -0
- package/dist/handlers/message-handlers/agents-list-handler.js.map +1 -0
- package/dist/handlers/message-handlers/auth-error-handler.d.ts +71 -0
- package/dist/handlers/message-handlers/auth-error-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/auth-error-handler.js +30 -0
- package/dist/handlers/message-handlers/auth-error-handler.js.map +1 -0
- package/dist/handlers/message-handlers/auth-message-handler.d.ts +18 -0
- package/dist/handlers/message-handlers/auth-message-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/auth-message-handler.js +60 -0
- package/dist/handlers/message-handlers/auth-message-handler.js.map +1 -0
- package/dist/handlers/message-handlers/auth-required-handler.d.ts +76 -0
- package/dist/handlers/message-handlers/auth-required-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/auth-required-handler.js +23 -0
- package/dist/handlers/message-handlers/auth-required-handler.js.map +1 -0
- package/dist/handlers/message-handlers/auth-success-handler.d.ts +18 -0
- package/dist/handlers/message-handlers/auth-success-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/auth-success-handler.js +51 -0
- package/dist/handlers/message-handlers/auth-success-handler.js.map +1 -0
- package/dist/handlers/message-handlers/base-handler.d.ts +55 -0
- package/dist/handlers/message-handlers/base-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/base-handler.js +83 -0
- package/dist/handlers/message-handlers/base-handler.js.map +1 -0
- package/dist/handlers/message-handlers/challenge-handler.d.ts +73 -0
- package/dist/handlers/message-handlers/challenge-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/challenge-handler.js +47 -0
- package/dist/handlers/message-handlers/challenge-handler.js.map +1 -0
- package/dist/handlers/message-handlers/error-message-handler.d.ts +76 -0
- package/dist/handlers/message-handlers/error-message-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/error-message-handler.js +29 -0
- package/dist/handlers/message-handlers/error-message-handler.js.map +1 -0
- package/dist/handlers/message-handlers/index.d.ts +28 -0
- package/dist/handlers/message-handlers/index.d.ts.map +1 -0
- package/dist/handlers/message-handlers/index.js +100 -0
- package/dist/handlers/message-handlers/index.js.map +1 -0
- package/dist/handlers/message-handlers/list-rooms-response-handler.d.ts +122 -0
- package/dist/handlers/message-handlers/list-rooms-response-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/list-rooms-response-handler.js +30 -0
- package/dist/handlers/message-handlers/list-rooms-response-handler.js.map +1 -0
- package/dist/handlers/message-handlers/ping-pong-handler.d.ts +104 -0
- package/dist/handlers/message-handlers/ping-pong-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/ping-pong-handler.js +36 -0
- package/dist/handlers/message-handlers/ping-pong-handler.js.map +1 -0
- package/dist/handlers/message-handlers/regular-message-handler.d.ts +56 -0
- package/dist/handlers/message-handlers/regular-message-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/regular-message-handler.js +59 -0
- package/dist/handlers/message-handlers/regular-message-handler.js.map +1 -0
- package/dist/handlers/message-handlers/subscribe-response-handler.d.ts +81 -0
- package/dist/handlers/message-handlers/subscribe-response-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/subscribe-response-handler.js +48 -0
- package/dist/handlers/message-handlers/subscribe-response-handler.js.map +1 -0
- package/dist/handlers/message-handlers/task-response-handler.d.ts +14 -0
- package/dist/handlers/message-handlers/task-response-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/task-response-handler.js +44 -0
- package/dist/handlers/message-handlers/task-response-handler.js.map +1 -0
- package/dist/handlers/message-handlers/types.d.ts +51 -0
- package/dist/handlers/message-handlers/types.d.ts.map +1 -0
- package/dist/handlers/message-handlers/types.js +7 -0
- package/dist/handlers/message-handlers/types.js.map +1 -0
- package/dist/handlers/message-handlers/unsubscribe-response-handler.d.ts +81 -0
- package/dist/handlers/message-handlers/unsubscribe-response-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/unsubscribe-response-handler.js +48 -0
- package/dist/handlers/message-handlers/unsubscribe-response-handler.js.map +1 -0
- package/dist/handlers/webhook-handler.d.ts +202 -0
- package/dist/handlers/webhook-handler.d.ts.map +1 -0
- package/dist/handlers/webhook-handler.js +511 -0
- package/dist/handlers/webhook-handler.js.map +1 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +217 -0
- package/dist/index.js.map +1 -0
- package/dist/managers/agent-registry.d.ts +173 -0
- package/dist/managers/agent-registry.d.ts.map +1 -0
- package/dist/managers/agent-registry.js +310 -0
- package/dist/managers/agent-registry.js.map +1 -0
- package/dist/managers/connection-manager.d.ts +134 -0
- package/dist/managers/connection-manager.d.ts.map +1 -0
- package/dist/managers/connection-manager.js +176 -0
- package/dist/managers/connection-manager.js.map +1 -0
- package/dist/managers/index.d.ts +9 -0
- package/dist/managers/index.d.ts.map +1 -0
- package/dist/managers/index.js +16 -0
- package/dist/managers/index.js.map +1 -0
- package/dist/managers/message-router.d.ts +112 -0
- package/dist/managers/message-router.d.ts.map +1 -0
- package/dist/managers/message-router.js +260 -0
- package/dist/managers/message-router.js.map +1 -0
- package/dist/managers/room-manager.d.ts +165 -0
- package/dist/managers/room-manager.d.ts.map +1 -0
- package/dist/managers/room-manager.js +227 -0
- package/dist/managers/room-manager.js.map +1 -0
- package/dist/teneo-sdk.d.ts +703 -0
- package/dist/teneo-sdk.d.ts.map +1 -0
- package/dist/teneo-sdk.js +907 -0
- package/dist/teneo-sdk.js.map +1 -0
- package/dist/types/config.d.ts +1047 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +720 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/error-codes.d.ts +29 -0
- package/dist/types/error-codes.d.ts.map +1 -0
- package/dist/types/error-codes.js +41 -0
- package/dist/types/error-codes.js.map +1 -0
- package/dist/types/events.d.ts +616 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +261 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/health.d.ts +40 -0
- package/dist/types/health.d.ts.map +1 -0
- package/dist/types/health.js +6 -0
- package/dist/types/health.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +123 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/messages.d.ts +3734 -0
- package/dist/types/messages.d.ts.map +1 -0
- package/dist/types/messages.js +482 -0
- package/dist/types/messages.js.map +1 -0
- package/dist/types/validation.d.ts +81 -0
- package/dist/types/validation.d.ts.map +1 -0
- package/dist/types/validation.js +115 -0
- package/dist/types/validation.js.map +1 -0
- package/dist/utils/bounded-queue.d.ts +127 -0
- package/dist/utils/bounded-queue.d.ts.map +1 -0
- package/dist/utils/bounded-queue.js +181 -0
- package/dist/utils/bounded-queue.js.map +1 -0
- package/dist/utils/circuit-breaker.d.ts +141 -0
- package/dist/utils/circuit-breaker.d.ts.map +1 -0
- package/dist/utils/circuit-breaker.js +215 -0
- package/dist/utils/circuit-breaker.js.map +1 -0
- package/dist/utils/deduplication-cache.d.ts +110 -0
- package/dist/utils/deduplication-cache.d.ts.map +1 -0
- package/dist/utils/deduplication-cache.js +177 -0
- package/dist/utils/deduplication-cache.js.map +1 -0
- package/dist/utils/event-waiter.d.ts +101 -0
- package/dist/utils/event-waiter.d.ts.map +1 -0
- package/dist/utils/event-waiter.js +118 -0
- package/dist/utils/event-waiter.js.map +1 -0
- package/dist/utils/index.d.ts +51 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +72 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +22 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +91 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts +122 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +190 -0
- package/dist/utils/rate-limiter.js.map +1 -0
- package/dist/utils/retry-policy.d.ts +191 -0
- package/dist/utils/retry-policy.d.ts.map +1 -0
- package/dist/utils/retry-policy.js +225 -0
- package/dist/utils/retry-policy.js.map +1 -0
- package/dist/utils/secure-private-key.d.ts +113 -0
- package/dist/utils/secure-private-key.d.ts.map +1 -0
- package/dist/utils/secure-private-key.js +188 -0
- package/dist/utils/secure-private-key.js.map +1 -0
- package/dist/utils/signature-verifier.d.ts +143 -0
- package/dist/utils/signature-verifier.d.ts.map +1 -0
- package/dist/utils/signature-verifier.js +238 -0
- package/dist/utils/signature-verifier.js.map +1 -0
- package/dist/utils/ssrf-validator.d.ts +36 -0
- package/dist/utils/ssrf-validator.d.ts.map +1 -0
- package/dist/utils/ssrf-validator.js +195 -0
- package/dist/utils/ssrf-validator.js.map +1 -0
- package/examples/.env.example +17 -0
- package/examples/basic-usage.ts +211 -0
- package/examples/production-dashboard/.env.example +153 -0
- package/examples/production-dashboard/package.json +39 -0
- package/examples/production-dashboard/public/dashboard.html +642 -0
- package/examples/production-dashboard/server.ts +753 -0
- package/examples/webhook-integration.ts +239 -0
- package/examples/x-influencer-battle-redesign.html +1065 -0
- package/examples/x-influencer-battle-server.ts +217 -0
- package/examples/x-influencer-battle.html +787 -0
- package/package.json +65 -0
- package/src/constants.ts +43 -0
- package/src/core/websocket-client.test.ts +512 -0
- package/src/core/websocket-client.ts +1056 -0
- package/src/formatters/response-formatter.test.ts +571 -0
- package/src/formatters/response-formatter.ts +677 -0
- package/src/handlers/message-handler-registry.ts +239 -0
- package/src/handlers/message-handlers/agent-selected-handler.ts +40 -0
- package/src/handlers/message-handlers/agents-list-handler.ts +26 -0
- package/src/handlers/message-handlers/auth-error-handler.ts +31 -0
- package/src/handlers/message-handlers/auth-message-handler.ts +66 -0
- package/src/handlers/message-handlers/auth-required-handler.ts +23 -0
- package/src/handlers/message-handlers/auth-success-handler.ts +57 -0
- package/src/handlers/message-handlers/base-handler.ts +101 -0
- package/src/handlers/message-handlers/challenge-handler.ts +57 -0
- package/src/handlers/message-handlers/error-message-handler.ts +27 -0
- package/src/handlers/message-handlers/index.ts +77 -0
- package/src/handlers/message-handlers/list-rooms-response-handler.ts +28 -0
- package/src/handlers/message-handlers/ping-pong-handler.ts +30 -0
- package/src/handlers/message-handlers/regular-message-handler.ts +65 -0
- package/src/handlers/message-handlers/subscribe-response-handler.ts +47 -0
- package/src/handlers/message-handlers/task-response-handler.ts +45 -0
- package/src/handlers/message-handlers/types.ts +77 -0
- package/src/handlers/message-handlers/unsubscribe-response-handler.ts +47 -0
- package/src/handlers/webhook-handler.test.ts +789 -0
- package/src/handlers/webhook-handler.ts +576 -0
- package/src/index.ts +269 -0
- package/src/managers/agent-registry.test.ts +466 -0
- package/src/managers/agent-registry.ts +347 -0
- package/src/managers/connection-manager.ts +195 -0
- package/src/managers/index.ts +9 -0
- package/src/managers/message-router.ts +349 -0
- package/src/managers/room-manager.ts +248 -0
- package/src/teneo-sdk.ts +1022 -0
- package/src/types/config.test.ts +325 -0
- package/src/types/config.ts +799 -0
- package/src/types/error-codes.ts +44 -0
- package/src/types/events.test.ts +302 -0
- package/src/types/events.ts +382 -0
- package/src/types/health.ts +46 -0
- package/src/types/index.ts +199 -0
- package/src/types/messages.test.ts +660 -0
- package/src/types/messages.ts +570 -0
- package/src/types/validation.ts +123 -0
- package/src/utils/bounded-queue.test.ts +356 -0
- package/src/utils/bounded-queue.ts +205 -0
- package/src/utils/circuit-breaker.test.ts +394 -0
- package/src/utils/circuit-breaker.ts +262 -0
- package/src/utils/deduplication-cache.test.ts +380 -0
- package/src/utils/deduplication-cache.ts +198 -0
- package/src/utils/event-waiter.test.ts +381 -0
- package/src/utils/event-waiter.ts +172 -0
- package/src/utils/index.ts +74 -0
- package/src/utils/logger.ts +87 -0
- package/src/utils/rate-limiter.test.ts +341 -0
- package/src/utils/rate-limiter.ts +211 -0
- package/src/utils/retry-policy.test.ts +558 -0
- package/src/utils/retry-policy.ts +272 -0
- package/src/utils/secure-private-key.test.ts +356 -0
- package/src/utils/secure-private-key.ts +205 -0
- package/src/utils/signature-verifier.test.ts +464 -0
- package/src/utils/signature-verifier.ts +298 -0
- package/src/utils/ssrf-validator.test.ts +372 -0
- package/src/utils/ssrf-validator.ts +224 -0
- package/tests/integration/real-server.test.ts +740 -0
- package/tests/integration/websocket.test.ts +381 -0
- package/tests/integration-setup.ts +16 -0
- package/tests/setup.ts +34 -0
- package/tsconfig.json +32 -0
- package/vitest.config.ts +42 -0
- 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
|
+
}
|
package/vitest.config.ts
ADDED
|
@@ -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
|
+
});
|