@teneo-protocol/sdk 1.0.1 → 2.2.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/.eslintrc.json +11 -2
- package/.github/CODEOWNERS +2 -0
- package/.github/ISSUE_TEMPLATE/01-bug.yml +85 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
- package/.github/workflows/claude-code-review.yml +8 -3
- package/.github/workflows/claude-reviewer.yml +6 -4
- package/.github/workflows/publish-npm.yml +9 -6
- package/.github/workflows/push-to-main.yml +1 -1
- package/.github/workflows/top-issue.yml +102 -0
- package/CHANGELOG.md +334 -0
- package/CONCEPTS.md +747 -0
- package/README.md +577 -54
- package/dist/constants.js +8 -8
- package/dist/constants.js.map +1 -1
- package/dist/core/websocket-client.d.ts +25 -1
- package/dist/core/websocket-client.d.ts.map +1 -1
- package/dist/core/websocket-client.js +74 -15
- package/dist/core/websocket-client.js.map +1 -1
- package/dist/formatters/response-formatter.js +4 -0
- package/dist/formatters/response-formatter.js.map +1 -1
- package/dist/handlers/message-handler-registry.js +2 -1
- package/dist/handlers/message-handler-registry.js.map +1 -1
- package/dist/handlers/message-handlers/agent-details-response-handler.d.ts +1666 -0
- package/dist/handlers/message-handlers/agent-details-response-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/agent-details-response-handler.js +38 -0
- package/dist/handlers/message-handlers/agent-details-response-handler.js.map +1 -0
- package/dist/handlers/message-handlers/agent-room-operation-response-handler.d.ts +76 -0
- package/dist/handlers/message-handlers/agent-room-operation-response-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/agent-room-operation-response-handler.js +67 -0
- package/dist/handlers/message-handlers/agent-room-operation-response-handler.js.map +1 -0
- package/dist/handlers/message-handlers/agent-selected-handler.d.ts +92 -38
- package/dist/handlers/message-handlers/agent-selected-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/agent-selected-handler.js +2 -5
- package/dist/handlers/message-handlers/agent-selected-handler.js.map +1 -1
- package/dist/handlers/message-handlers/agent-status-update-handler.d.ts +1687 -0
- package/dist/handlers/message-handlers/agent-status-update-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/agent-status-update-handler.js +48 -0
- package/dist/handlers/message-handlers/agent-status-update-handler.js.map +1 -0
- package/dist/handlers/message-handlers/agents-list-handler.js +2 -5
- package/dist/handlers/message-handlers/agents-list-handler.js.map +1 -1
- package/dist/handlers/message-handlers/all-agents-response-handler.d.ts +439 -0
- package/dist/handlers/message-handlers/all-agents-response-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/all-agents-response-handler.js +36 -0
- package/dist/handlers/message-handlers/all-agents-response-handler.js.map +1 -0
- package/dist/handlers/message-handlers/auth-error-handler.d.ts +45 -31
- package/dist/handlers/message-handlers/auth-error-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/auth-error-handler.js +2 -5
- package/dist/handlers/message-handlers/auth-error-handler.js.map +1 -1
- package/dist/handlers/message-handlers/auth-message-handler.d.ts +6 -0
- package/dist/handlers/message-handlers/auth-message-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/auth-message-handler.js +71 -10
- package/dist/handlers/message-handlers/auth-message-handler.js.map +1 -1
- package/dist/handlers/message-handlers/auth-required-handler.d.ts +49 -31
- package/dist/handlers/message-handlers/auth-required-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/auth-required-handler.js +2 -5
- package/dist/handlers/message-handlers/auth-required-handler.js.map +1 -1
- package/dist/handlers/message-handlers/auth-success-handler.d.ts +6 -0
- package/dist/handlers/message-handlers/auth-success-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/auth-success-handler.js +52 -9
- package/dist/handlers/message-handlers/auth-success-handler.js.map +1 -1
- package/dist/handlers/message-handlers/base-handler.d.ts +4 -4
- package/dist/handlers/message-handlers/base-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/base-handler.js +3 -1
- package/dist/handlers/message-handlers/base-handler.js.map +1 -1
- package/dist/handlers/message-handlers/challenge-handler.d.ts +45 -31
- package/dist/handlers/message-handlers/challenge-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/challenge-handler.js +3 -2
- package/dist/handlers/message-handlers/challenge-handler.js.map +1 -1
- package/dist/handlers/message-handlers/error-message-handler.d.ts +49 -31
- package/dist/handlers/message-handlers/error-message-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/error-message-handler.js +2 -5
- package/dist/handlers/message-handlers/error-message-handler.js.map +1 -1
- package/dist/handlers/message-handlers/index.d.ts +11 -0
- package/dist/handlers/message-handlers/index.d.ts.map +1 -1
- package/dist/handlers/message-handlers/index.js +55 -1
- package/dist/handlers/message-handlers/index.js.map +1 -1
- package/dist/handlers/message-handlers/list-available-agents-handler.d.ts +1660 -0
- package/dist/handlers/message-handlers/list-available-agents-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/list-available-agents-handler.js +35 -0
- package/dist/handlers/message-handlers/list-available-agents-handler.js.map +1 -0
- package/dist/handlers/message-handlers/list-room-agents-handler.d.ts +1669 -0
- package/dist/handlers/message-handlers/list-room-agents-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/list-room-agents-handler.js +48 -0
- package/dist/handlers/message-handlers/list-room-agents-handler.js.map +1 -0
- package/dist/handlers/message-handlers/list-rooms-response-handler.d.ts +2 -110
- package/dist/handlers/message-handlers/list-rooms-response-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/list-rooms-response-handler.js +4 -6
- package/dist/handlers/message-handlers/list-rooms-response-handler.js.map +1 -1
- package/dist/handlers/message-handlers/ping-pong-handler.d.ts +62 -58
- package/dist/handlers/message-handlers/ping-pong-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/ping-pong-handler.js +4 -10
- package/dist/handlers/message-handlers/ping-pong-handler.js.map +1 -1
- package/dist/handlers/message-handlers/rate-limit-notification-handler.d.ts +94 -0
- package/dist/handlers/message-handlers/rate-limit-notification-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/rate-limit-notification-handler.js +35 -0
- package/dist/handlers/message-handlers/rate-limit-notification-handler.js.map +1 -0
- package/dist/handlers/message-handlers/regular-message-handler.d.ts +31 -29
- package/dist/handlers/message-handlers/regular-message-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/regular-message-handler.js +4 -6
- package/dist/handlers/message-handlers/regular-message-handler.js.map +1 -1
- package/dist/handlers/message-handlers/room-operation-response-handler.d.ts +328 -0
- package/dist/handlers/message-handlers/room-operation-response-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/room-operation-response-handler.js +89 -0
- package/dist/handlers/message-handlers/room-operation-response-handler.js.map +1 -0
- package/dist/handlers/message-handlers/subscribe-response-handler.d.ts +53 -31
- package/dist/handlers/message-handlers/subscribe-response-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/subscribe-response-handler.js +4 -6
- package/dist/handlers/message-handlers/subscribe-response-handler.js.map +1 -1
- package/dist/handlers/message-handlers/task-quote-handler.d.ts +14 -0
- package/dist/handlers/message-handlers/task-quote-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/task-quote-handler.js +29 -0
- package/dist/handlers/message-handlers/task-quote-handler.js.map +1 -0
- package/dist/handlers/message-handlers/task-response-handler.js +2 -5
- package/dist/handlers/message-handlers/task-response-handler.js.map +1 -1
- package/dist/handlers/message-handlers/types.d.ts +21 -7
- package/dist/handlers/message-handlers/types.d.ts.map +1 -1
- package/dist/handlers/message-handlers/unsubscribe-response-handler.d.ts +53 -31
- package/dist/handlers/message-handlers/unsubscribe-response-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/unsubscribe-response-handler.js +4 -6
- package/dist/handlers/message-handlers/unsubscribe-response-handler.js.map +1 -1
- package/dist/handlers/message-handlers/user-authenticated-handler.d.ts +40 -0
- package/dist/handlers/message-handlers/user-authenticated-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/user-authenticated-handler.js +28 -0
- package/dist/handlers/message-handlers/user-authenticated-handler.js.map +1 -0
- package/dist/handlers/message-handlers/user-count-handler.d.ts +49 -0
- package/dist/handlers/message-handlers/user-count-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/user-count-handler.js +31 -0
- package/dist/handlers/message-handlers/user-count-handler.js.map +1 -0
- package/dist/handlers/webhook-handler.d.ts +1 -1
- package/dist/handlers/webhook-handler.d.ts.map +1 -1
- package/dist/handlers/webhook-handler.js +14 -5
- package/dist/handlers/webhook-handler.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -2
- package/dist/index.js.map +1 -1
- package/dist/managers/admin-manager.d.ts +116 -0
- package/dist/managers/admin-manager.d.ts.map +1 -0
- package/dist/managers/admin-manager.js +169 -0
- package/dist/managers/admin-manager.js.map +1 -0
- package/dist/managers/agent-registry.d.ts +52 -1
- package/dist/managers/agent-registry.d.ts.map +1 -1
- package/dist/managers/agent-registry.js +145 -6
- package/dist/managers/agent-registry.js.map +1 -1
- package/dist/managers/agent-room-manager.d.ts +216 -0
- package/dist/managers/agent-room-manager.d.ts.map +1 -0
- package/dist/managers/agent-room-manager.js +555 -0
- package/dist/managers/agent-room-manager.js.map +1 -0
- package/dist/managers/connection-manager.js +2 -0
- package/dist/managers/connection-manager.js.map +1 -1
- package/dist/managers/index.d.ts +4 -1
- package/dist/managers/index.d.ts.map +1 -1
- package/dist/managers/index.js +7 -1
- package/dist/managers/index.js.map +1 -1
- package/dist/managers/message-router.d.ts +56 -5
- package/dist/managers/message-router.d.ts.map +1 -1
- package/dist/managers/message-router.js +155 -8
- package/dist/managers/message-router.js.map +1 -1
- package/dist/managers/room-management-manager.d.ts +213 -0
- package/dist/managers/room-management-manager.d.ts.map +1 -0
- package/dist/managers/room-management-manager.js +442 -0
- package/dist/managers/room-management-manager.js.map +1 -0
- package/dist/managers/room-manager.d.ts +11 -9
- package/dist/managers/room-manager.d.ts.map +1 -1
- package/dist/managers/room-manager.js +14 -10
- package/dist/managers/room-manager.js.map +1 -1
- package/dist/payments/index.d.ts +5 -0
- package/dist/payments/index.d.ts.map +1 -0
- package/dist/payments/index.js +21 -0
- package/dist/payments/index.js.map +1 -0
- package/dist/payments/payment-client.d.ts +74 -0
- package/dist/payments/payment-client.d.ts.map +1 -0
- package/dist/payments/payment-client.js +207 -0
- package/dist/payments/payment-client.js.map +1 -0
- package/dist/teneo-sdk.d.ts +467 -33
- package/dist/teneo-sdk.d.ts.map +1 -1
- package/dist/teneo-sdk.js +735 -26
- package/dist/teneo-sdk.js.map +1 -1
- package/dist/types/categories.d.ts +22 -0
- package/dist/types/categories.d.ts.map +1 -0
- package/dist/types/categories.js +40 -0
- package/dist/types/categories.js.map +1 -0
- package/dist/types/config.d.ts +134 -54
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +70 -9
- package/dist/types/config.js.map +1 -1
- package/dist/types/error-codes.d.ts +10 -0
- package/dist/types/error-codes.d.ts.map +1 -1
- package/dist/types/error-codes.js +12 -0
- package/dist/types/error-codes.js.map +1 -1
- package/dist/types/events.d.ts +176 -68
- package/dist/types/events.d.ts.map +1 -1
- package/dist/types/events.js +19 -1
- package/dist/types/events.js.map +1 -1
- package/dist/types/index.d.ts +3 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +57 -2
- package/dist/types/index.js.map +1 -1
- package/dist/types/messages.d.ts +22225 -2592
- package/dist/types/messages.d.ts.map +1 -1
- package/dist/types/messages.js +537 -28
- package/dist/types/messages.js.map +1 -1
- package/dist/utils/bounded-queue.d.ts.map +1 -1
- package/dist/utils/bounded-queue.js +5 -2
- package/dist/utils/bounded-queue.js.map +1 -1
- package/dist/utils/circuit-breaker.js +11 -4
- package/dist/utils/circuit-breaker.js.map +1 -1
- package/dist/utils/deduplication-cache.js +3 -1
- package/dist/utils/deduplication-cache.js.map +1 -1
- package/dist/utils/event-waiter.d.ts +3 -3
- package/dist/utils/event-waiter.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +4 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/pricing-resolver.d.ts +26 -0
- package/dist/utils/pricing-resolver.d.ts.map +1 -0
- package/dist/utils/pricing-resolver.js +85 -0
- package/dist/utils/pricing-resolver.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -1
- package/dist/utils/rate-limiter.js +6 -0
- package/dist/utils/rate-limiter.js.map +1 -1
- package/dist/utils/retry-policy.js +1 -0
- package/dist/utils/retry-policy.js.map +1 -1
- package/dist/utils/secure-private-key.js +3 -1
- package/dist/utils/secure-private-key.js.map +1 -1
- package/dist/utils/signature-verifier.d.ts.map +1 -1
- package/dist/utils/signature-verifier.js +3 -1
- package/dist/utils/signature-verifier.js.map +1 -1
- package/examples/.env.example +2 -2
- package/examples/agent-room-management-example.ts +335 -0
- package/examples/basic-usage.ts +3 -4
- package/examples/claude-agent-x-follower/.env.example +3 -3
- package/examples/claude-agent-x-follower/QUICKSTART.md +3 -3
- package/examples/claude-agent-x-follower/README.md +3 -3
- package/examples/claude-agent-x-follower/index.ts +120 -96
- package/examples/n8n-teneo/.env.example +3 -3
- package/examples/n8n-teneo/README.md +2 -2
- package/examples/n8n-teneo/index.ts +54 -44
- package/examples/nestjs-dashboard/.env.example +11 -0
- package/examples/nestjs-dashboard/README.md +297 -0
- package/examples/nestjs-dashboard/nest-cli.json +10 -0
- package/examples/nestjs-dashboard/package.json +44 -0
- package/examples/nestjs-dashboard/pnpm-lock.yaml +3079 -0
- package/examples/nestjs-dashboard/src/app.controller.ts +24 -0
- package/examples/nestjs-dashboard/src/app.module.ts +15 -0
- package/examples/nestjs-dashboard/src/main.ts +32 -0
- package/examples/nestjs-dashboard/src/public/dashboard.html +1144 -0
- package/examples/nestjs-dashboard/src/teneo/agents.controller.ts +54 -0
- package/examples/nestjs-dashboard/src/teneo/events.controller.ts +65 -0
- package/examples/nestjs-dashboard/src/teneo/messages.controller.ts +47 -0
- package/examples/nestjs-dashboard/src/teneo/rooms.controller.ts +258 -0
- package/examples/nestjs-dashboard/src/teneo/teneo.module.ts +13 -0
- package/examples/nestjs-dashboard/src/teneo/teneo.service.ts +484 -0
- package/examples/nestjs-dashboard/tsconfig.json +22 -0
- package/examples/openai-teneo/.env.example +3 -3
- package/examples/openai-teneo/README.md +3 -3
- package/examples/openai-teneo/index.ts +82 -71
- package/examples/production-dashboard/.env.example +3 -3
- package/examples/production-dashboard/README.md +90 -13
- package/examples/production-dashboard/public/dashboard.html +1173 -601
- package/examples/production-dashboard/server.ts +349 -7
- package/examples/room-management-example.ts +282 -0
- package/examples/usage/.env.example +2 -2
- package/examples/usage/01-connect.ts +3 -4
- package/examples/usage/02-list-agents.ts +2 -3
- package/examples/usage/03-pick-agent.ts +2 -3
- package/examples/usage/04-find-by-capability.ts +2 -3
- package/examples/usage/05-webhook-example.ts +2 -3
- package/examples/usage/06-simple-api-server.ts +2 -3
- package/examples/usage/07-event-listener.ts +2 -3
- package/examples/usage/README.md +1 -1
- package/examples/webhook-integration.ts +1 -1
- package/examples/x-influencer-battle-server.ts +2 -2
- package/package.json +12 -1
- package/src/core/websocket-client.test.ts +8 -3
- package/src/core/websocket-client.ts +58 -4
- package/src/formatters/response-formatter.test.ts +2 -0
- package/src/formatters/response-formatter.ts +3 -3
- package/src/handlers/message-handlers/agent-details-response-handler.ts +42 -0
- package/src/handlers/message-handlers/agent-room-operation-response-handler.ts +77 -0
- package/src/handlers/message-handlers/agent-status-update-handler.ts +52 -0
- package/src/handlers/message-handlers/all-agents-response-handler.ts +39 -0
- package/src/handlers/message-handlers/auth-message-handler.ts +78 -5
- package/src/handlers/message-handlers/auth-success-handler.ts +63 -6
- package/src/handlers/message-handlers/base-handler.ts +20 -7
- package/src/handlers/message-handlers/index.ts +53 -0
- package/src/handlers/message-handlers/list-available-agents-handler.ts +41 -0
- package/src/handlers/message-handlers/list-room-agents-handler.ts +58 -0
- package/src/handlers/message-handlers/list-rooms-response-handler.ts +4 -2
- package/src/handlers/message-handlers/rate-limit-notification-handler.ts +45 -0
- package/src/handlers/message-handlers/regular-message-handler.ts +3 -2
- package/src/handlers/message-handlers/room-operation-response-handler.ts +102 -0
- package/src/handlers/message-handlers/subscribe-response-handler.ts +12 -2
- package/src/handlers/message-handlers/task-quote-handler.ts +31 -0
- package/src/handlers/message-handlers/types.ts +41 -7
- package/src/handlers/message-handlers/unsubscribe-response-handler.ts +12 -2
- package/src/handlers/message-handlers/user-authenticated-handler.ts +31 -0
- package/src/handlers/message-handlers/user-count-handler.ts +34 -0
- package/src/handlers/webhook-handler.test.ts +3 -2
- package/src/handlers/webhook-handler.ts +13 -7
- package/src/index.ts +21 -0
- package/src/managers/admin-manager.ts +249 -0
- package/src/managers/agent-registry.test.ts +2 -1
- package/src/managers/agent-registry.ts +170 -2
- package/src/managers/agent-room-manager.ts +665 -0
- package/src/managers/index.ts +15 -1
- package/src/managers/message-router.ts +215 -17
- package/src/managers/room-management-manager.ts +520 -0
- package/src/managers/room-manager.ts +15 -20
- package/src/payments/index.ts +22 -0
- package/src/payments/payment-client.ts +240 -0
- package/src/teneo-sdk.ts +806 -30
- package/src/types/categories.ts +45 -0
- package/src/types/config.ts +80 -7
- package/src/types/error-codes.ts +14 -0
- package/src/types/events.test.ts +1 -0
- package/src/types/events.ts +67 -0
- package/src/types/index.ts +111 -0
- package/src/types/messages.test.ts +2 -1
- package/src/types/messages.ts +677 -42
- package/src/utils/bounded-queue.test.ts +1 -1
- package/src/utils/bounded-queue.ts +2 -1
- package/src/utils/circuit-breaker.test.ts +1 -1
- package/src/utils/deduplication-cache.test.ts +1 -1
- package/src/utils/event-waiter.test.ts +1 -1
- package/src/utils/event-waiter.ts +3 -3
- package/src/utils/index.ts +7 -0
- package/src/utils/logger.ts +8 -8
- package/src/utils/pricing-resolver.ts +128 -0
- package/src/utils/rate-limiter.test.ts +1 -1
- package/src/utils/rate-limiter.ts +1 -0
- package/src/utils/signature-verifier.test.ts +2 -2
- package/src/utils/signature-verifier.ts +3 -2
- package/tests/.env.example +7 -0
- package/tests/direct-agent-test.ts +151 -0
- package/tests/integration/real-server.test.ts +2 -0
- package/tests/integration/room-management.test.ts +516 -0
- package/tests/integration/websocket.test.ts +5 -2
- package/tests/payment-flow-test.ts +147 -0
- package/tests/unit/handlers/agent-room-operation-response-handler.test.ts +382 -0
- package/tests/unit/handlers/agent-status-update-handler.test.ts +403 -0
- package/tests/unit/handlers/auth-success-handler-rooms.test.ts +697 -0
- package/tests/unit/handlers/list-available-agents-handler.test.ts +248 -0
- package/tests/unit/handlers/list-room-agents-handler.test.ts +290 -0
- package/tests/unit/handlers/room-operation-response-handler.test.ts +500 -0
- package/tests/unit/managers/agent-room-manager.test.ts +527 -0
- package/tests/unit/managers/room-management-manager.test.ts +420 -0
- package/tsconfig.json +2 -2
- package/vitest.config.ts +1 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for ListAvailableAgentsHandler
|
|
3
|
+
* Tests response handling for available agents list
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
7
|
+
import { ListAvailableAgentsHandler } from "../../../src/handlers/message-handlers/list-available-agents-handler";
|
|
8
|
+
import { HandlerContext } from "../../../src/handlers/message-handlers/types";
|
|
9
|
+
import { Logger } from "../../../src/types";
|
|
10
|
+
|
|
11
|
+
describe("ListAvailableAgentsHandler", () => {
|
|
12
|
+
let handler: ListAvailableAgentsHandler;
|
|
13
|
+
let mockContext: HandlerContext;
|
|
14
|
+
let mockLogger: Logger;
|
|
15
|
+
let emitSpy: ReturnType<typeof vi.fn>;
|
|
16
|
+
let sendWebhookSpy: ReturnType<typeof vi.fn>;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
// Create mock logger
|
|
20
|
+
mockLogger = {
|
|
21
|
+
debug: vi.fn(),
|
|
22
|
+
info: vi.fn(),
|
|
23
|
+
warn: vi.fn(),
|
|
24
|
+
error: vi.fn()
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Create spies
|
|
28
|
+
emitSpy = vi.fn();
|
|
29
|
+
sendWebhookSpy = vi.fn().mockResolvedValue(undefined);
|
|
30
|
+
|
|
31
|
+
// Create mock context
|
|
32
|
+
mockContext = {
|
|
33
|
+
emit: emitSpy,
|
|
34
|
+
sendWebhook: sendWebhookSpy,
|
|
35
|
+
logger: mockLogger,
|
|
36
|
+
getConnectionState: vi.fn(),
|
|
37
|
+
getAuthState: vi.fn(),
|
|
38
|
+
updateConnectionState: vi.fn(),
|
|
39
|
+
updateAuthState: vi.fn(),
|
|
40
|
+
sendMessage: vi.fn()
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Create handler instance
|
|
44
|
+
handler = new ListAvailableAgentsHandler();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("Handler Metadata", () => {
|
|
48
|
+
it("should have correct type", () => {
|
|
49
|
+
expect(handler.type).toBe("available_agents_response");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("should have schema defined", () => {
|
|
53
|
+
expect(handler.schema).toBeDefined();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should identify messages it can handle", () => {
|
|
57
|
+
const message = { type: "available_agents_response", data: {} };
|
|
58
|
+
expect(handler.canHandle(message as any)).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should not handle other message types", () => {
|
|
62
|
+
const message = { type: "other_type", data: {} };
|
|
63
|
+
expect(handler.canHandle(message as any)).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe("Response Handling", () => {
|
|
68
|
+
it("should handle available agents list with agents", async () => {
|
|
69
|
+
const agents = [
|
|
70
|
+
{ agent_id: "agent-3", agent_name: "Agent 3", status: "online" },
|
|
71
|
+
{ agent_id: "agent-4", agent_name: "Agent 4", status: "online" }
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
const message = {
|
|
75
|
+
type: "available_agents_response" as const,
|
|
76
|
+
data: {
|
|
77
|
+
agents
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
await handler.handle(message, mockContext);
|
|
82
|
+
|
|
83
|
+
// Should emit event
|
|
84
|
+
expect(emitSpy).toHaveBeenCalledWith("agent_room:available_agents_listed", agents);
|
|
85
|
+
|
|
86
|
+
// Should send webhook
|
|
87
|
+
expect(sendWebhookSpy).toHaveBeenCalledWith(
|
|
88
|
+
"available_agents_listed",
|
|
89
|
+
expect.objectContaining({
|
|
90
|
+
agents
|
|
91
|
+
}),
|
|
92
|
+
undefined
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// Should log
|
|
96
|
+
expect(mockLogger.info).toHaveBeenCalledWith(
|
|
97
|
+
"Available agents listed",
|
|
98
|
+
expect.objectContaining({
|
|
99
|
+
count: 2
|
|
100
|
+
})
|
|
101
|
+
);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("should handle empty agents list", async () => {
|
|
105
|
+
const message = {
|
|
106
|
+
type: "available_agents_response" as const,
|
|
107
|
+
data: {
|
|
108
|
+
agents: []
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
await handler.handle(message, mockContext);
|
|
113
|
+
|
|
114
|
+
// Should emit event with empty array
|
|
115
|
+
expect(emitSpy).toHaveBeenCalledWith("agent_room:available_agents_listed", []);
|
|
116
|
+
|
|
117
|
+
// Should log
|
|
118
|
+
expect(mockLogger.info).toHaveBeenCalledWith(
|
|
119
|
+
"Available agents listed",
|
|
120
|
+
expect.objectContaining({
|
|
121
|
+
count: 0
|
|
122
|
+
})
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("should handle undefined agents as empty array", async () => {
|
|
127
|
+
const message = {
|
|
128
|
+
type: "available_agents_response" as const,
|
|
129
|
+
data: {
|
|
130
|
+
// agents is undefined
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
await handler.handle(message, mockContext);
|
|
135
|
+
|
|
136
|
+
// Should emit event with empty array
|
|
137
|
+
expect(emitSpy).toHaveBeenCalledWith("agent_room:available_agents_listed", []);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("should handle agents with full details", async () => {
|
|
141
|
+
const agents = [
|
|
142
|
+
{
|
|
143
|
+
agent_id: "agent-1",
|
|
144
|
+
agent_name: "Weather Agent",
|
|
145
|
+
description: "Provides weather information",
|
|
146
|
+
capabilities: [{ name: "weather-forecast", description: "Get weather forecasts" }],
|
|
147
|
+
commands: [{ trigger: "weather", description: "Check weather" }],
|
|
148
|
+
image: "https://example.com/agent.png",
|
|
149
|
+
status: "online"
|
|
150
|
+
}
|
|
151
|
+
];
|
|
152
|
+
|
|
153
|
+
const message = {
|
|
154
|
+
type: "available_agents_response" as const,
|
|
155
|
+
data: {
|
|
156
|
+
agents
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
await handler.handle(message, mockContext);
|
|
161
|
+
|
|
162
|
+
// Should emit event with full agent details
|
|
163
|
+
expect(emitSpy).toHaveBeenCalledWith("agent_room:available_agents_listed", agents);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe("Webhook Errors", () => {
|
|
168
|
+
it("should handle webhook failures gracefully", async () => {
|
|
169
|
+
const webhookError = new Error("Webhook failed");
|
|
170
|
+
sendWebhookSpy.mockRejectedValueOnce(webhookError);
|
|
171
|
+
|
|
172
|
+
const agents = [{ agent_id: "agent-1", agent_name: "Agent 1" }];
|
|
173
|
+
const message = {
|
|
174
|
+
type: "available_agents_response" as const,
|
|
175
|
+
data: {
|
|
176
|
+
agents
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// Should not throw
|
|
181
|
+
await handler.handle(message, mockContext);
|
|
182
|
+
|
|
183
|
+
// Should still emit event
|
|
184
|
+
expect(emitSpy).toHaveBeenCalledWith("agent_room:available_agents_listed", agents);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
describe("Message Validation", () => {
|
|
189
|
+
it("should handle invalid message structure", async () => {
|
|
190
|
+
const invalidMessage = {
|
|
191
|
+
type: "available_agents_response"
|
|
192
|
+
// Missing data field
|
|
193
|
+
} as any;
|
|
194
|
+
|
|
195
|
+
await handler.handle(invalidMessage, mockContext);
|
|
196
|
+
|
|
197
|
+
// Should log error
|
|
198
|
+
expect(mockLogger.error).toHaveBeenCalledWith(
|
|
199
|
+
expect.stringContaining("Error handling available_agents_response"),
|
|
200
|
+
expect.any(Error)
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
// Should emit message:error event
|
|
204
|
+
expect(emitSpy).toHaveBeenCalledWith("message:error", expect.any(Error), invalidMessage);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("should accept valid message with extra fields", async () => {
|
|
208
|
+
const agents = [{ agent_id: "agent-1", agent_name: "Agent 1" }];
|
|
209
|
+
const message = {
|
|
210
|
+
type: "available_agents_response" as const,
|
|
211
|
+
data: {
|
|
212
|
+
agents,
|
|
213
|
+
extra_field: "should be ignored",
|
|
214
|
+
another_extra: 123
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// Should not throw
|
|
219
|
+
await handler.handle(message, mockContext);
|
|
220
|
+
|
|
221
|
+
expect(emitSpy).toHaveBeenCalledWith("agent_room:available_agents_listed", agents);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
describe("Debug Logging", () => {
|
|
226
|
+
it("should log debug info", async () => {
|
|
227
|
+
const agents = [
|
|
228
|
+
{ agent_id: "agent-1", agent_name: "Agent 1" },
|
|
229
|
+
{ agent_id: "agent-2", agent_name: "Agent 2" }
|
|
230
|
+
];
|
|
231
|
+
const message = {
|
|
232
|
+
type: "available_agents_response" as const,
|
|
233
|
+
data: {
|
|
234
|
+
agents
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
await handler.handle(message, mockContext);
|
|
239
|
+
|
|
240
|
+
expect(mockLogger.debug).toHaveBeenCalledWith(
|
|
241
|
+
"Handling available_agents_response",
|
|
242
|
+
expect.objectContaining({
|
|
243
|
+
agentCount: 2
|
|
244
|
+
})
|
|
245
|
+
);
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
});
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for ListRoomAgentsHandler
|
|
3
|
+
* Tests response handling for room agents list
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
7
|
+
import { ListRoomAgentsHandler } from "../../../src/handlers/message-handlers/list-room-agents-handler";
|
|
8
|
+
import { HandlerContext } from "../../../src/handlers/message-handlers/types";
|
|
9
|
+
import { Logger } from "../../../src/types";
|
|
10
|
+
|
|
11
|
+
describe("ListRoomAgentsHandler", () => {
|
|
12
|
+
let handler: ListRoomAgentsHandler;
|
|
13
|
+
let mockContext: HandlerContext;
|
|
14
|
+
let mockLogger: Logger;
|
|
15
|
+
let mockAgentRoomManager: any;
|
|
16
|
+
let emitSpy: ReturnType<typeof vi.fn>;
|
|
17
|
+
let sendWebhookSpy: ReturnType<typeof vi.fn>;
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
// Create mock logger
|
|
21
|
+
mockLogger = {
|
|
22
|
+
debug: vi.fn(),
|
|
23
|
+
info: vi.fn(),
|
|
24
|
+
warn: vi.fn(),
|
|
25
|
+
error: vi.fn()
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Create mock agent room manager
|
|
29
|
+
mockAgentRoomManager = {
|
|
30
|
+
cacheRoomAgents: vi.fn()
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Create spies
|
|
34
|
+
emitSpy = vi.fn();
|
|
35
|
+
sendWebhookSpy = vi.fn().mockResolvedValue(undefined);
|
|
36
|
+
|
|
37
|
+
// Create mock context
|
|
38
|
+
mockContext = {
|
|
39
|
+
emit: emitSpy,
|
|
40
|
+
sendWebhook: sendWebhookSpy,
|
|
41
|
+
logger: mockLogger,
|
|
42
|
+
getConnectionState: vi.fn(),
|
|
43
|
+
getAuthState: vi.fn(),
|
|
44
|
+
updateConnectionState: vi.fn(),
|
|
45
|
+
updateAuthState: vi.fn(),
|
|
46
|
+
sendMessage: vi.fn(),
|
|
47
|
+
agentRoomManager: mockAgentRoomManager
|
|
48
|
+
} as any;
|
|
49
|
+
|
|
50
|
+
// Create handler instance
|
|
51
|
+
handler = new ListRoomAgentsHandler();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("Handler Metadata", () => {
|
|
55
|
+
it("should have correct type", () => {
|
|
56
|
+
expect(handler.type).toBe("room_agents_response");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("should have schema defined", () => {
|
|
60
|
+
expect(handler.schema).toBeDefined();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("should identify messages it can handle", () => {
|
|
64
|
+
const message = { type: "room_agents_response", data: {} };
|
|
65
|
+
expect(handler.canHandle(message as any)).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("should not handle other message types", () => {
|
|
69
|
+
const message = { type: "other_type", data: {} };
|
|
70
|
+
expect(handler.canHandle(message as any)).toBe(false);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("Response Handling", () => {
|
|
75
|
+
it("should handle room agents list with agents", async () => {
|
|
76
|
+
const agents = [
|
|
77
|
+
{ agent_id: "agent-1", agent_name: "Agent 1", status: "online" },
|
|
78
|
+
{ agent_id: "agent-2", agent_name: "Agent 2", status: "offline" }
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
const message = {
|
|
82
|
+
type: "room_agents_response" as const,
|
|
83
|
+
data: {
|
|
84
|
+
room_id: "room-123",
|
|
85
|
+
agents
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
await handler.handle(message, mockContext);
|
|
90
|
+
|
|
91
|
+
// Should cache via agent room manager
|
|
92
|
+
expect(mockAgentRoomManager.cacheRoomAgents).toHaveBeenCalledWith("room-123", agents);
|
|
93
|
+
|
|
94
|
+
// Should emit event
|
|
95
|
+
expect(emitSpy).toHaveBeenCalledWith("agent_room:agents_listed", "room-123", agents);
|
|
96
|
+
|
|
97
|
+
// Should send webhook
|
|
98
|
+
expect(sendWebhookSpy).toHaveBeenCalledWith(
|
|
99
|
+
"room_agents_listed",
|
|
100
|
+
expect.objectContaining({
|
|
101
|
+
room_id: "room-123",
|
|
102
|
+
agents
|
|
103
|
+
}),
|
|
104
|
+
undefined
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
// Should log
|
|
108
|
+
expect(mockLogger.info).toHaveBeenCalledWith(
|
|
109
|
+
"Room agents listed",
|
|
110
|
+
expect.objectContaining({
|
|
111
|
+
roomId: "room-123",
|
|
112
|
+
count: 2
|
|
113
|
+
})
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("should handle empty agents list", async () => {
|
|
118
|
+
const message = {
|
|
119
|
+
type: "room_agents_response" as const,
|
|
120
|
+
data: {
|
|
121
|
+
room_id: "room-456",
|
|
122
|
+
agents: []
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
await handler.handle(message, mockContext);
|
|
127
|
+
|
|
128
|
+
// Should cache empty array
|
|
129
|
+
expect(mockAgentRoomManager.cacheRoomAgents).toHaveBeenCalledWith("room-456", []);
|
|
130
|
+
|
|
131
|
+
// Should emit event with empty array
|
|
132
|
+
expect(emitSpy).toHaveBeenCalledWith("agent_room:agents_listed", "room-456", []);
|
|
133
|
+
|
|
134
|
+
// Should log
|
|
135
|
+
expect(mockLogger.info).toHaveBeenCalledWith(
|
|
136
|
+
"Room agents listed",
|
|
137
|
+
expect.objectContaining({
|
|
138
|
+
roomId: "room-456",
|
|
139
|
+
count: 0
|
|
140
|
+
})
|
|
141
|
+
);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("should handle undefined agents as empty array", async () => {
|
|
145
|
+
const message = {
|
|
146
|
+
type: "room_agents_response" as const,
|
|
147
|
+
data: {
|
|
148
|
+
room_id: "room-789"
|
|
149
|
+
// agents is undefined
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
await handler.handle(message, mockContext);
|
|
154
|
+
|
|
155
|
+
// Should cache empty array
|
|
156
|
+
expect(mockAgentRoomManager.cacheRoomAgents).toHaveBeenCalledWith("room-789", []);
|
|
157
|
+
|
|
158
|
+
// Should emit event with empty array
|
|
159
|
+
expect(emitSpy).toHaveBeenCalledWith("agent_room:agents_listed", "room-789", []);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("should work without agentRoomManager in context", async () => {
|
|
163
|
+
const contextWithoutManager = { ...mockContext, agentRoomManager: undefined };
|
|
164
|
+
const agents = [{ agent_id: "agent-1", agent_name: "Agent 1" }];
|
|
165
|
+
|
|
166
|
+
const message = {
|
|
167
|
+
type: "room_agents_response" as const,
|
|
168
|
+
data: {
|
|
169
|
+
room_id: "room-123",
|
|
170
|
+
agents
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
await handler.handle(message, contextWithoutManager);
|
|
175
|
+
|
|
176
|
+
// Should still emit event
|
|
177
|
+
expect(emitSpy).toHaveBeenCalledWith("agent_room:agents_listed", "room-123", agents);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("should work with agentRoomManager without cacheRoomAgents method", async () => {
|
|
181
|
+
const invalidManager = { someOtherMethod: vi.fn() };
|
|
182
|
+
const contextWithInvalidManager = {
|
|
183
|
+
...mockContext,
|
|
184
|
+
agentRoomManager: invalidManager
|
|
185
|
+
};
|
|
186
|
+
const agents = [{ agent_id: "agent-1", agent_name: "Agent 1" }];
|
|
187
|
+
|
|
188
|
+
const message = {
|
|
189
|
+
type: "room_agents_response" as const,
|
|
190
|
+
data: {
|
|
191
|
+
room_id: "room-123",
|
|
192
|
+
agents
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
// Should not throw
|
|
197
|
+
await handler.handle(message, contextWithInvalidManager);
|
|
198
|
+
|
|
199
|
+
// Should still emit event
|
|
200
|
+
expect(emitSpy).toHaveBeenCalledWith("agent_room:agents_listed", "room-123", agents);
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
describe("Webhook Errors", () => {
|
|
205
|
+
it("should handle webhook failures gracefully", async () => {
|
|
206
|
+
const webhookError = new Error("Webhook failed");
|
|
207
|
+
sendWebhookSpy.mockRejectedValueOnce(webhookError);
|
|
208
|
+
|
|
209
|
+
const agents = [{ agent_id: "agent-1", agent_name: "Agent 1" }];
|
|
210
|
+
const message = {
|
|
211
|
+
type: "room_agents_response" as const,
|
|
212
|
+
data: {
|
|
213
|
+
room_id: "room-123",
|
|
214
|
+
agents
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// Should not throw
|
|
219
|
+
await handler.handle(message, mockContext);
|
|
220
|
+
|
|
221
|
+
// Should still emit event and cache
|
|
222
|
+
expect(emitSpy).toHaveBeenCalledWith("agent_room:agents_listed", "room-123", agents);
|
|
223
|
+
expect(mockAgentRoomManager.cacheRoomAgents).toHaveBeenCalledWith("room-123", agents);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
describe("Message Validation", () => {
|
|
228
|
+
it("should handle invalid message structure", async () => {
|
|
229
|
+
const invalidMessage = {
|
|
230
|
+
type: "room_agents_response"
|
|
231
|
+
// Missing data field
|
|
232
|
+
} as any;
|
|
233
|
+
|
|
234
|
+
await handler.handle(invalidMessage, mockContext);
|
|
235
|
+
|
|
236
|
+
// Should log error
|
|
237
|
+
expect(mockLogger.error).toHaveBeenCalledWith(
|
|
238
|
+
expect.stringContaining("Error handling room_agents_response"),
|
|
239
|
+
expect.any(Error)
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
// Should emit message:error event
|
|
243
|
+
expect(emitSpy).toHaveBeenCalledWith("message:error", expect.any(Error), invalidMessage);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it("should accept valid message with extra fields", async () => {
|
|
247
|
+
const agents = [{ agent_id: "agent-1", agent_name: "Agent 1" }];
|
|
248
|
+
const message = {
|
|
249
|
+
type: "room_agents_response" as const,
|
|
250
|
+
data: {
|
|
251
|
+
room_id: "room-123",
|
|
252
|
+
agents,
|
|
253
|
+
extra_field: "should be ignored",
|
|
254
|
+
another_extra: 123
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// Should not throw
|
|
259
|
+
await handler.handle(message, mockContext);
|
|
260
|
+
|
|
261
|
+
expect(emitSpy).toHaveBeenCalledWith("agent_room:agents_listed", "room-123", agents);
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
describe("Debug Logging", () => {
|
|
266
|
+
it("should log debug info", async () => {
|
|
267
|
+
const agents = [
|
|
268
|
+
{ agent_id: "agent-1", agent_name: "Agent 1" },
|
|
269
|
+
{ agent_id: "agent-2", agent_name: "Agent 2" }
|
|
270
|
+
];
|
|
271
|
+
const message = {
|
|
272
|
+
type: "room_agents_response" as const,
|
|
273
|
+
data: {
|
|
274
|
+
room_id: "room-123",
|
|
275
|
+
agents
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
await handler.handle(message, mockContext);
|
|
280
|
+
|
|
281
|
+
expect(mockLogger.debug).toHaveBeenCalledWith(
|
|
282
|
+
"Handling room_agents_response",
|
|
283
|
+
expect.objectContaining({
|
|
284
|
+
roomId: "room-123",
|
|
285
|
+
agentCount: 2
|
|
286
|
+
})
|
|
287
|
+
);
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
});
|