@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,660 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
AgentsListMessageSchema,
|
|
4
|
+
AuthMessageSchema,
|
|
5
|
+
AuthSuccessMessageSchema,
|
|
6
|
+
BaseMessageSchema,
|
|
7
|
+
ErrorMessageSchema,
|
|
8
|
+
MessageTypeSchema,
|
|
9
|
+
RoomSchema,
|
|
10
|
+
TaskResponseMessageSchema,
|
|
11
|
+
isAgentSelected,
|
|
12
|
+
isAuthError,
|
|
13
|
+
isAuthSuccess,
|
|
14
|
+
isChallenge,
|
|
15
|
+
isError,
|
|
16
|
+
isTaskResponse,
|
|
17
|
+
safeParseMessage
|
|
18
|
+
} from "./messages";
|
|
19
|
+
|
|
20
|
+
describe("stringToBoolean transform", () => {
|
|
21
|
+
// Test stringToBoolean indirectly through RoomSchema which uses it for is_public and is_active
|
|
22
|
+
|
|
23
|
+
const createTestRoom = (is_public: any, is_active: any) => ({
|
|
24
|
+
id: "room-1",
|
|
25
|
+
name: "Test Room",
|
|
26
|
+
is_public,
|
|
27
|
+
is_active,
|
|
28
|
+
created_by: "user-1",
|
|
29
|
+
created_at: "2024-01-01T00:00:00Z",
|
|
30
|
+
updated_at: "2024-01-01T00:00:00Z"
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("valid truthy values", () => {
|
|
34
|
+
it("should accept boolean true", () => {
|
|
35
|
+
const room = createTestRoom(true, true);
|
|
36
|
+
const result = RoomSchema.safeParse(room);
|
|
37
|
+
expect(result.success).toBe(true);
|
|
38
|
+
if (result.success) {
|
|
39
|
+
expect(result.data.is_public).toBe(true);
|
|
40
|
+
expect(result.data.is_active).toBe(true);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should accept "true" string', () => {
|
|
45
|
+
const room = createTestRoom("true", "true");
|
|
46
|
+
const result = RoomSchema.safeParse(room);
|
|
47
|
+
expect(result.success).toBe(true);
|
|
48
|
+
if (result.success) {
|
|
49
|
+
expect(result.data.is_public).toBe(true);
|
|
50
|
+
expect(result.data.is_active).toBe(true);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should accept "1" string', () => {
|
|
55
|
+
const room = createTestRoom("1", "1");
|
|
56
|
+
const result = RoomSchema.safeParse(room);
|
|
57
|
+
expect(result.success).toBe(true);
|
|
58
|
+
if (result.success) {
|
|
59
|
+
expect(result.data.is_public).toBe(true);
|
|
60
|
+
expect(result.data.is_active).toBe(true);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should accept "yes" string', () => {
|
|
65
|
+
const room = createTestRoom("yes", "yes");
|
|
66
|
+
const result = RoomSchema.safeParse(room);
|
|
67
|
+
expect(result.success).toBe(true);
|
|
68
|
+
if (result.success) {
|
|
69
|
+
expect(result.data.is_public).toBe(true);
|
|
70
|
+
expect(result.data.is_active).toBe(true);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("should accept case variations (TRUE, Yes, YES)", () => {
|
|
75
|
+
const testCases = ["TRUE", "Yes", "YES"];
|
|
76
|
+
testCases.forEach((value) => {
|
|
77
|
+
const room = createTestRoom(value, value);
|
|
78
|
+
const result = RoomSchema.safeParse(room);
|
|
79
|
+
expect(result.success).toBe(true);
|
|
80
|
+
if (result.success) {
|
|
81
|
+
expect(result.data.is_public).toBe(true);
|
|
82
|
+
expect(result.data.is_active).toBe(true);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should trim whitespace for truthy values", () => {
|
|
88
|
+
const room = createTestRoom(" true ", "\t1\n");
|
|
89
|
+
const result = RoomSchema.safeParse(room);
|
|
90
|
+
expect(result.success).toBe(true);
|
|
91
|
+
if (result.success) {
|
|
92
|
+
expect(result.data.is_public).toBe(true);
|
|
93
|
+
expect(result.data.is_active).toBe(true);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe("valid falsy values", () => {
|
|
99
|
+
it("should accept boolean false", () => {
|
|
100
|
+
const room = createTestRoom(false, false);
|
|
101
|
+
const result = RoomSchema.safeParse(room);
|
|
102
|
+
expect(result.success).toBe(true);
|
|
103
|
+
if (result.success) {
|
|
104
|
+
expect(result.data.is_public).toBe(false);
|
|
105
|
+
expect(result.data.is_active).toBe(false);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should accept "false" string', () => {
|
|
110
|
+
const room = createTestRoom("false", "false");
|
|
111
|
+
const result = RoomSchema.safeParse(room);
|
|
112
|
+
expect(result.success).toBe(true);
|
|
113
|
+
if (result.success) {
|
|
114
|
+
expect(result.data.is_public).toBe(false);
|
|
115
|
+
expect(result.data.is_active).toBe(false);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should accept "0" string', () => {
|
|
120
|
+
const room = createTestRoom("0", "0");
|
|
121
|
+
const result = RoomSchema.safeParse(room);
|
|
122
|
+
expect(result.success).toBe(true);
|
|
123
|
+
if (result.success) {
|
|
124
|
+
expect(result.data.is_public).toBe(false);
|
|
125
|
+
expect(result.data.is_active).toBe(false);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should accept "no" string', () => {
|
|
130
|
+
const room = createTestRoom("no", "no");
|
|
131
|
+
const result = RoomSchema.safeParse(room);
|
|
132
|
+
expect(result.success).toBe(true);
|
|
133
|
+
if (result.success) {
|
|
134
|
+
expect(result.data.is_public).toBe(false);
|
|
135
|
+
expect(result.data.is_active).toBe(false);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("should accept case variations (FALSE, No, NO)", () => {
|
|
140
|
+
const testCases = ["FALSE", "No", "NO"];
|
|
141
|
+
testCases.forEach((value) => {
|
|
142
|
+
const room = createTestRoom(value, value);
|
|
143
|
+
const result = RoomSchema.safeParse(room);
|
|
144
|
+
expect(result.success).toBe(true);
|
|
145
|
+
if (result.success) {
|
|
146
|
+
expect(result.data.is_public).toBe(false);
|
|
147
|
+
expect(result.data.is_active).toBe(false);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("should trim whitespace for falsy values", () => {
|
|
153
|
+
const room = createTestRoom(" false ", "\t0\n");
|
|
154
|
+
const result = RoomSchema.safeParse(room);
|
|
155
|
+
expect(result.success).toBe(true);
|
|
156
|
+
if (result.success) {
|
|
157
|
+
expect(result.data.is_public).toBe(false);
|
|
158
|
+
expect(result.data.is_active).toBe(false);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe("invalid values (should throw)", () => {
|
|
164
|
+
it('should reject "maybe"', () => {
|
|
165
|
+
const room = createTestRoom("maybe", true);
|
|
166
|
+
const result = RoomSchema.safeParse(room);
|
|
167
|
+
expect(result.success).toBe(false);
|
|
168
|
+
if (!result.success) {
|
|
169
|
+
expect(result.error.message).toContain("Invalid boolean value");
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("should reject empty string", () => {
|
|
174
|
+
const room = createTestRoom("", true);
|
|
175
|
+
const result = RoomSchema.safeParse(room);
|
|
176
|
+
expect(result.success).toBe(false);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('should reject "invalid"', () => {
|
|
180
|
+
const room = createTestRoom("invalid", true);
|
|
181
|
+
const result = RoomSchema.safeParse(room);
|
|
182
|
+
expect(result.success).toBe(false);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("should reject random strings", () => {
|
|
186
|
+
const room = createTestRoom("randomstring", true);
|
|
187
|
+
const result = RoomSchema.safeParse(room);
|
|
188
|
+
expect(result.success).toBe(false);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("should reject numeric strings other than 0/1", () => {
|
|
192
|
+
const invalidNumbers = ["2", "42", "-1", "3.14"];
|
|
193
|
+
invalidNumbers.forEach((value) => {
|
|
194
|
+
const room = createTestRoom(value, true);
|
|
195
|
+
const result = RoomSchema.safeParse(room);
|
|
196
|
+
expect(result.success).toBe(false);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("should include helpful error message", () => {
|
|
201
|
+
const room = createTestRoom("maybe", true);
|
|
202
|
+
const result = RoomSchema.safeParse(room);
|
|
203
|
+
expect(result.success).toBe(false);
|
|
204
|
+
if (!result.success) {
|
|
205
|
+
const errorMessage = result.error.message;
|
|
206
|
+
expect(errorMessage).toContain("Invalid boolean value");
|
|
207
|
+
expect(errorMessage).toContain("maybe");
|
|
208
|
+
expect(errorMessage).toContain("true/false");
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
describe("optional usage (common pattern)", () => {
|
|
214
|
+
// Test with AuthSuccessMessageSchema which has optional boolean fields
|
|
215
|
+
it("should accept undefined for optional boolean fields", () => {
|
|
216
|
+
const message = {
|
|
217
|
+
type: "auth_success" as const,
|
|
218
|
+
data: {
|
|
219
|
+
id: "client-123",
|
|
220
|
+
type: "user" as const,
|
|
221
|
+
address: "0x1234567890123456789012345678901234567890"
|
|
222
|
+
// nft_verified, is_whitelisted, cached_auth are optional - not included
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
const result = AuthSuccessMessageSchema.safeParse(message);
|
|
226
|
+
expect(result.success).toBe(true);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it("should validate when optional boolean field is present and valid", () => {
|
|
230
|
+
const message = {
|
|
231
|
+
type: "auth_success" as const,
|
|
232
|
+
data: {
|
|
233
|
+
id: "client-123",
|
|
234
|
+
type: "user" as const,
|
|
235
|
+
address: "0x1234567890123456789012345678901234567890",
|
|
236
|
+
nft_verified: "true",
|
|
237
|
+
is_whitelisted: "1",
|
|
238
|
+
cached_auth: "yes"
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
const result = AuthSuccessMessageSchema.safeParse(message);
|
|
242
|
+
expect(result.success).toBe(true);
|
|
243
|
+
if (result.success) {
|
|
244
|
+
expect(result.data.data.nft_verified).toBe(true);
|
|
245
|
+
expect(result.data.data.is_whitelisted).toBe(true);
|
|
246
|
+
expect(result.data.data.cached_auth).toBe(true);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it("should reject when optional boolean field has invalid value", () => {
|
|
251
|
+
const message = {
|
|
252
|
+
type: "auth_success" as const,
|
|
253
|
+
data: {
|
|
254
|
+
id: "client-123",
|
|
255
|
+
type: "user" as const,
|
|
256
|
+
address: "0x1234567890123456789012345678901234567890",
|
|
257
|
+
nft_verified: "invalid_value"
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
const result = AuthSuccessMessageSchema.safeParse(message);
|
|
261
|
+
expect(result.success).toBe(false);
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
describe("Message Type Schemas", () => {
|
|
267
|
+
describe("MessageTypeSchema", () => {
|
|
268
|
+
it("should validate all valid message types", () => {
|
|
269
|
+
const validTypes = [
|
|
270
|
+
"request_challenge",
|
|
271
|
+
"challenge",
|
|
272
|
+
"check_cached_auth",
|
|
273
|
+
"auth",
|
|
274
|
+
"auth_required",
|
|
275
|
+
"auth_success",
|
|
276
|
+
"auth_error",
|
|
277
|
+
"register",
|
|
278
|
+
"registration_success",
|
|
279
|
+
"message",
|
|
280
|
+
"task",
|
|
281
|
+
"task_response",
|
|
282
|
+
"agent_selected",
|
|
283
|
+
"agents",
|
|
284
|
+
"error",
|
|
285
|
+
"ping",
|
|
286
|
+
"pong",
|
|
287
|
+
"capabilities",
|
|
288
|
+
"subscribe",
|
|
289
|
+
"unsubscribe",
|
|
290
|
+
"list_rooms"
|
|
291
|
+
];
|
|
292
|
+
|
|
293
|
+
validTypes.forEach((type) => {
|
|
294
|
+
const result = MessageTypeSchema.safeParse(type);
|
|
295
|
+
expect(result.success).toBe(true);
|
|
296
|
+
if (result.success) {
|
|
297
|
+
expect(result.data).toBe(type);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("should reject invalid message types", () => {
|
|
303
|
+
const invalidTypes = ["invalid", "auth_request", "MESSAGE", "", null, undefined, 123];
|
|
304
|
+
|
|
305
|
+
invalidTypes.forEach((type) => {
|
|
306
|
+
const result = MessageTypeSchema.safeParse(type);
|
|
307
|
+
expect(result.success).toBe(false);
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
describe("BaseMessageSchema", () => {
|
|
313
|
+
it("should validate a minimal base message", () => {
|
|
314
|
+
const message = {
|
|
315
|
+
type: "ping"
|
|
316
|
+
};
|
|
317
|
+
const result = BaseMessageSchema.safeParse(message);
|
|
318
|
+
expect(result.success).toBe(true);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it("should validate a base message with all optional fields", () => {
|
|
322
|
+
const message = {
|
|
323
|
+
type: "ping",
|
|
324
|
+
id: "msg-123",
|
|
325
|
+
timestamp: "2024-01-01T00:00:00Z"
|
|
326
|
+
};
|
|
327
|
+
const result = BaseMessageSchema.safeParse(message);
|
|
328
|
+
expect(result.success).toBe(true);
|
|
329
|
+
if (result.success) {
|
|
330
|
+
expect(result.data.id).toBe("msg-123");
|
|
331
|
+
expect(result.data.timestamp).toBe("2024-01-01T00:00:00Z");
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it("should reject messages without type", () => {
|
|
336
|
+
const message = { id: "msg-123" };
|
|
337
|
+
const result = BaseMessageSchema.safeParse(message);
|
|
338
|
+
expect(result.success).toBe(false);
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
describe("AuthMessageSchema", () => {
|
|
343
|
+
it("should validate a valid auth message", () => {
|
|
344
|
+
const message = {
|
|
345
|
+
type: "auth",
|
|
346
|
+
data: {
|
|
347
|
+
address: "0x1234567890123456789012345678901234567890",
|
|
348
|
+
signature: "0xsignature",
|
|
349
|
+
message: "challenge-string",
|
|
350
|
+
userType: "user"
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
const result = AuthMessageSchema.safeParse(message);
|
|
354
|
+
expect(result.success).toBe(true);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it("should validate auth message with optional fields", () => {
|
|
358
|
+
const message = {
|
|
359
|
+
type: "auth",
|
|
360
|
+
data: {
|
|
361
|
+
address: "0x1234567890123456789012345678901234567890",
|
|
362
|
+
signature: "0xsignature",
|
|
363
|
+
message: "challenge-string",
|
|
364
|
+
userType: "user"
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
const result = AuthMessageSchema.safeParse(message);
|
|
368
|
+
expect(result.success).toBe(true); // All fields in data are optional
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it("should accept auth message with minimal or no data fields", () => {
|
|
372
|
+
const validMessages = [
|
|
373
|
+
{ type: "auth" },
|
|
374
|
+
{ type: "auth", data: {} },
|
|
375
|
+
{ type: "auth", data: { address: "0x123" } },
|
|
376
|
+
{ type: "auth", data: { signature: "0xsig" } }
|
|
377
|
+
];
|
|
378
|
+
|
|
379
|
+
validMessages.forEach((msg) => {
|
|
380
|
+
const result = AuthMessageSchema.safeParse(msg);
|
|
381
|
+
expect(result.success).toBe(true); // Schema is permissive - all fields are optional
|
|
382
|
+
});
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
describe("AuthSuccessMessageSchema", () => {
|
|
387
|
+
it("should validate auth success message", () => {
|
|
388
|
+
const message = {
|
|
389
|
+
type: "auth_success",
|
|
390
|
+
data: {
|
|
391
|
+
id: "client-123",
|
|
392
|
+
type: "user",
|
|
393
|
+
address: "0x1234567890123456789012345678901234567890",
|
|
394
|
+
is_whitelisted: true,
|
|
395
|
+
rooms: [],
|
|
396
|
+
nft_verified: false
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
const result = AuthSuccessMessageSchema.safeParse(message);
|
|
400
|
+
expect(result.success).toBe(true);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it("should validate auth success with minimal fields", () => {
|
|
404
|
+
const message = {
|
|
405
|
+
type: "auth_success",
|
|
406
|
+
data: {
|
|
407
|
+
id: "client-123",
|
|
408
|
+
type: "user",
|
|
409
|
+
address: "0x1234567890123456789012345678901234567890"
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
const result = AuthSuccessMessageSchema.safeParse(message);
|
|
413
|
+
expect(result.success).toBe(true);
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
describe("ErrorMessageSchema", () => {
|
|
418
|
+
it("should validate error message", () => {
|
|
419
|
+
const message = {
|
|
420
|
+
type: "error",
|
|
421
|
+
content: "Something went wrong",
|
|
422
|
+
from: "system",
|
|
423
|
+
data: {
|
|
424
|
+
code: 500,
|
|
425
|
+
message: "Internal server error",
|
|
426
|
+
details: { field: "value" }
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
const result = ErrorMessageSchema.safeParse(message);
|
|
430
|
+
expect(result.success).toBe(true);
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
it("should validate error with minimal fields", () => {
|
|
434
|
+
const message = {
|
|
435
|
+
type: "error",
|
|
436
|
+
content: "Something went wrong",
|
|
437
|
+
from: "system",
|
|
438
|
+
data: {
|
|
439
|
+
code: 400,
|
|
440
|
+
message: "Bad request"
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
const result = ErrorMessageSchema.safeParse(message);
|
|
444
|
+
expect(result.success).toBe(true);
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
describe("TaskResponseMessageSchema", () => {
|
|
449
|
+
it("should validate task response message", () => {
|
|
450
|
+
const message = {
|
|
451
|
+
type: "task_response",
|
|
452
|
+
content: "Task completed successfully",
|
|
453
|
+
content_type: "text/plain",
|
|
454
|
+
from: "agent-1",
|
|
455
|
+
data: {
|
|
456
|
+
task_id: "task-123",
|
|
457
|
+
success: true,
|
|
458
|
+
agent_name: "Test Agent",
|
|
459
|
+
format: "text" as const
|
|
460
|
+
},
|
|
461
|
+
requestId: "req-123",
|
|
462
|
+
timestamp: "2024-01-01T00:00:00Z"
|
|
463
|
+
};
|
|
464
|
+
const result = TaskResponseMessageSchema.safeParse(message);
|
|
465
|
+
expect(result.success).toBe(true);
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
describe("AgentsListMessageSchema", () => {
|
|
470
|
+
it("should validate agents list message", () => {
|
|
471
|
+
const message = {
|
|
472
|
+
type: "agents",
|
|
473
|
+
from: "system",
|
|
474
|
+
data: [
|
|
475
|
+
{
|
|
476
|
+
id: "agent-1",
|
|
477
|
+
name: "Agent 1",
|
|
478
|
+
room: "room-1",
|
|
479
|
+
status: "online"
|
|
480
|
+
}
|
|
481
|
+
]
|
|
482
|
+
};
|
|
483
|
+
const result = AgentsListMessageSchema.safeParse(message);
|
|
484
|
+
expect(result.success).toBe(true);
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
it("should validate empty agents list", () => {
|
|
488
|
+
const message = {
|
|
489
|
+
type: "agents",
|
|
490
|
+
from: "system",
|
|
491
|
+
data: []
|
|
492
|
+
};
|
|
493
|
+
const result = AgentsListMessageSchema.safeParse(message);
|
|
494
|
+
expect(result.success).toBe(true);
|
|
495
|
+
});
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
describe("Message Type Guards", () => {
|
|
500
|
+
describe("isAuthSuccess", () => {
|
|
501
|
+
it("should identify auth success messages", () => {
|
|
502
|
+
const message = {
|
|
503
|
+
type: "auth_success",
|
|
504
|
+
data: {
|
|
505
|
+
id: "client-123",
|
|
506
|
+
type: "user",
|
|
507
|
+
address: "0x123"
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
expect(isAuthSuccess(message)).toBe(true);
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
it("should reject non-auth success messages", () => {
|
|
514
|
+
expect(isAuthSuccess({ type: "auth_error", data: { message: "error" } })).toBe(false);
|
|
515
|
+
expect(isAuthSuccess({ type: "challenge", data: { challenge: "ch" } })).toBe(false);
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
describe("isAuthError", () => {
|
|
520
|
+
it("should identify auth error messages", () => {
|
|
521
|
+
const message = {
|
|
522
|
+
type: "auth_error",
|
|
523
|
+
data: { error: "Authentication failed" }
|
|
524
|
+
};
|
|
525
|
+
expect(isAuthError(message)).toBe(true);
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
it("should reject non-auth error messages", () => {
|
|
529
|
+
expect(
|
|
530
|
+
isAuthError({
|
|
531
|
+
type: "auth_success",
|
|
532
|
+
data: { id: "id", type: "user", address: "0x" }
|
|
533
|
+
})
|
|
534
|
+
).toBe(false);
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
describe("isChallenge", () => {
|
|
539
|
+
it("should identify challenge messages", () => {
|
|
540
|
+
const message = {
|
|
541
|
+
type: "challenge",
|
|
542
|
+
data: { challenge: "challenge-string", timestamp: Date.now() }
|
|
543
|
+
};
|
|
544
|
+
expect(isChallenge(message)).toBe(true);
|
|
545
|
+
});
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
describe("isError", () => {
|
|
549
|
+
it("should identify error messages", () => {
|
|
550
|
+
const message = {
|
|
551
|
+
type: "error",
|
|
552
|
+
content: "Something went wrong",
|
|
553
|
+
from: "system",
|
|
554
|
+
data: {
|
|
555
|
+
code: 500,
|
|
556
|
+
message: "Internal error"
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
expect(isError(message)).toBe(true);
|
|
560
|
+
});
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
describe("isTaskResponse", () => {
|
|
564
|
+
it("should identify task response", () => {
|
|
565
|
+
const message = {
|
|
566
|
+
type: "task_response",
|
|
567
|
+
content: "Task completed",
|
|
568
|
+
content_type: "text/plain",
|
|
569
|
+
from: "agent-1",
|
|
570
|
+
data: {
|
|
571
|
+
task_id: "task-123",
|
|
572
|
+
success: true
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
expect(isTaskResponse(message)).toBe(true);
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
describe("isAgentSelected", () => {
|
|
580
|
+
it("should identify agent selected messages", () => {
|
|
581
|
+
const message = {
|
|
582
|
+
type: "agent_selected",
|
|
583
|
+
content: "Agent selected",
|
|
584
|
+
from: "coordinator",
|
|
585
|
+
reasoning: "Best match",
|
|
586
|
+
data: {
|
|
587
|
+
agent_id: "agent-1",
|
|
588
|
+
agent_name: "Test Agent",
|
|
589
|
+
user_request: "help"
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
expect(isAgentSelected(message)).toBe(true);
|
|
593
|
+
});
|
|
594
|
+
});
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
describe("safeParseMessage", () => {
|
|
598
|
+
it("should parse valid messages", () => {
|
|
599
|
+
const validMessage = {
|
|
600
|
+
type: "ping",
|
|
601
|
+
id: "msg-123"
|
|
602
|
+
};
|
|
603
|
+
const result = safeParseMessage(validMessage);
|
|
604
|
+
expect(result.success).toBe(true);
|
|
605
|
+
if (result.success && result.data) {
|
|
606
|
+
expect(result.data.type).toBe("ping");
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
it("should accept 'message' without room", () => {
|
|
611
|
+
const msg = {
|
|
612
|
+
type: "message" as const,
|
|
613
|
+
content: "hello"
|
|
614
|
+
};
|
|
615
|
+
const result = safeParseMessage(msg);
|
|
616
|
+
expect(result.success).toBe(true);
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
it("should handle invalid messages", () => {
|
|
620
|
+
const invalidMessages = [
|
|
621
|
+
{ type: "invalid_type" },
|
|
622
|
+
{ no_type: "field" },
|
|
623
|
+
"not an object",
|
|
624
|
+
null,
|
|
625
|
+
undefined,
|
|
626
|
+
123
|
|
627
|
+
];
|
|
628
|
+
|
|
629
|
+
invalidMessages.forEach((msg) => {
|
|
630
|
+
const result = safeParseMessage(msg);
|
|
631
|
+
expect(result.success).toBe(false);
|
|
632
|
+
});
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
it("should parse complex task response", () => {
|
|
636
|
+
const complexMessage = {
|
|
637
|
+
type: "task_response",
|
|
638
|
+
content: "Here is my response",
|
|
639
|
+
content_type: "text/plain",
|
|
640
|
+
from: "agent-1",
|
|
641
|
+
data: {
|
|
642
|
+
task_id: "task-123",
|
|
643
|
+
agent_name: "Complex Agent",
|
|
644
|
+
success: true,
|
|
645
|
+
error: undefined
|
|
646
|
+
},
|
|
647
|
+
requestId: "req-complex-123",
|
|
648
|
+
timestamp: "2024-01-01T12:00:00Z"
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
const result = safeParseMessage(complexMessage);
|
|
652
|
+
expect(result.success).toBe(true);
|
|
653
|
+
if (result.success && result.data && result.data.type === "task_response") {
|
|
654
|
+
expect(result.data.data.task_id).toBe("task-123");
|
|
655
|
+
expect(result.data.data.agent_name).toBe("Complex Agent");
|
|
656
|
+
expect(result.data.data.success).toBe(true);
|
|
657
|
+
expect(result.data.content).toBe("Here is my response");
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
});
|