@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,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Circuit Breaker Pattern Implementation
|
|
4
|
+
* Provides fault tolerance by preventing cascading failures
|
|
5
|
+
*
|
|
6
|
+
* States:
|
|
7
|
+
* - CLOSED: Normal operation, requests pass through
|
|
8
|
+
* - OPEN: Failure threshold exceeded, requests fail fast
|
|
9
|
+
* - HALF_OPEN: Testing if service recovered, limited requests allowed
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.CircuitBreaker = exports.CircuitBreakerError = void 0;
|
|
13
|
+
/**
|
|
14
|
+
* Error thrown when circuit is open
|
|
15
|
+
*/
|
|
16
|
+
class CircuitBreakerError extends Error {
|
|
17
|
+
constructor(message, state) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.state = state;
|
|
20
|
+
this.name = "CircuitBreakerError";
|
|
21
|
+
if (Error.captureStackTrace) {
|
|
22
|
+
Error.captureStackTrace(this, CircuitBreakerError);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.CircuitBreakerError = CircuitBreakerError;
|
|
27
|
+
/**
|
|
28
|
+
* Circuit breaker for fault tolerance
|
|
29
|
+
* Prevents cascading failures by failing fast when errors are detected
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const breaker = new CircuitBreaker({
|
|
34
|
+
* failureThreshold: 5,
|
|
35
|
+
* timeout: 60000
|
|
36
|
+
* });
|
|
37
|
+
*
|
|
38
|
+
* try {
|
|
39
|
+
* await breaker.execute(async () => {
|
|
40
|
+
* return await fetch('https://api.example.com/data');
|
|
41
|
+
* });
|
|
42
|
+
* } catch (error) {
|
|
43
|
+
* if (error instanceof CircuitBreakerError) {
|
|
44
|
+
* console.log('Circuit is open, failing fast');
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
class CircuitBreaker {
|
|
50
|
+
/**
|
|
51
|
+
* Creates a new circuit breaker
|
|
52
|
+
*
|
|
53
|
+
* @param options - Configuration options
|
|
54
|
+
* @throws {Error} If thresholds are less than 1
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const breaker = new CircuitBreaker({
|
|
59
|
+
* failureThreshold: 5, // Open after 5 failures
|
|
60
|
+
* successThreshold: 2, // Close after 2 successes
|
|
61
|
+
* timeout: 60000, // Wait 60s before trying again
|
|
62
|
+
* windowSize: 60000 // Track failures in 60s window
|
|
63
|
+
* });
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
constructor(options = {}) {
|
|
67
|
+
this.state = "CLOSED";
|
|
68
|
+
this.failureCount = 0;
|
|
69
|
+
this.successCount = 0;
|
|
70
|
+
this.failures = []; // Timestamps of failures
|
|
71
|
+
this.failureThreshold = options.failureThreshold ?? 5;
|
|
72
|
+
this.successThreshold = options.successThreshold ?? 2;
|
|
73
|
+
this.timeout = options.timeout ?? 60000;
|
|
74
|
+
this.windowSize = options.windowSize ?? 60000;
|
|
75
|
+
if (this.failureThreshold < 1) {
|
|
76
|
+
throw new Error("CircuitBreaker failureThreshold must be at least 1");
|
|
77
|
+
}
|
|
78
|
+
if (this.successThreshold < 1) {
|
|
79
|
+
throw new Error("CircuitBreaker successThreshold must be at least 1");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Execute an operation through the circuit breaker
|
|
84
|
+
*
|
|
85
|
+
* @template T - Return type of the operation
|
|
86
|
+
* @param operation - Async operation to execute
|
|
87
|
+
* @returns Promise resolving to operation result
|
|
88
|
+
* @throws {CircuitBreakerError} If circuit is open
|
|
89
|
+
* @throws Operation error if operation fails
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* const result = await breaker.execute(async () => {
|
|
94
|
+
* const response = await fetch(url);
|
|
95
|
+
* return await response.json();
|
|
96
|
+
* });
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
async execute(operation) {
|
|
100
|
+
// Check if we should try to close the circuit
|
|
101
|
+
this.tryTransitionToHalfOpen();
|
|
102
|
+
// If circuit is open, fail fast
|
|
103
|
+
if (this.state === "OPEN") {
|
|
104
|
+
throw new CircuitBreakerError("Circuit breaker is OPEN", this.state);
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
const result = await operation();
|
|
108
|
+
this.onSuccess();
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
this.onFailure();
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Get current circuit breaker state and metrics
|
|
118
|
+
*
|
|
119
|
+
* @returns State object with status and counters
|
|
120
|
+
*/
|
|
121
|
+
getState() {
|
|
122
|
+
return {
|
|
123
|
+
state: this.state,
|
|
124
|
+
failureCount: this.failureCount,
|
|
125
|
+
successCount: this.successCount,
|
|
126
|
+
lastFailureTime: this.lastFailureTime,
|
|
127
|
+
nextAttemptTime: this.nextAttemptTime
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get circuit breaker configuration
|
|
132
|
+
*/
|
|
133
|
+
getConfig() {
|
|
134
|
+
return {
|
|
135
|
+
failureThreshold: this.failureThreshold,
|
|
136
|
+
successThreshold: this.successThreshold,
|
|
137
|
+
timeout: this.timeout,
|
|
138
|
+
windowSize: this.windowSize
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Manually reset the circuit breaker to CLOSED state
|
|
143
|
+
* Useful for recovery scenarios or testing
|
|
144
|
+
*/
|
|
145
|
+
reset() {
|
|
146
|
+
this.state = "CLOSED";
|
|
147
|
+
this.failureCount = 0;
|
|
148
|
+
this.successCount = 0;
|
|
149
|
+
this.lastFailureTime = undefined;
|
|
150
|
+
this.nextAttemptTime = undefined;
|
|
151
|
+
this.failures.length = 0;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Try to transition from OPEN to HALF_OPEN if timeout has passed
|
|
155
|
+
*/
|
|
156
|
+
tryTransitionToHalfOpen() {
|
|
157
|
+
if (this.state === "OPEN" && this.nextAttemptTime) {
|
|
158
|
+
if (Date.now() >= this.nextAttemptTime) {
|
|
159
|
+
this.state = "HALF_OPEN";
|
|
160
|
+
this.successCount = 0;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Handle successful operation
|
|
166
|
+
*/
|
|
167
|
+
onSuccess() {
|
|
168
|
+
if (this.state === "HALF_OPEN") {
|
|
169
|
+
this.successCount++;
|
|
170
|
+
if (this.successCount >= this.successThreshold) {
|
|
171
|
+
// Close the circuit - service has recovered
|
|
172
|
+
this.state = "CLOSED";
|
|
173
|
+
this.failureCount = 0;
|
|
174
|
+
this.successCount = 0;
|
|
175
|
+
this.failures.length = 0;
|
|
176
|
+
this.lastFailureTime = undefined;
|
|
177
|
+
this.nextAttemptTime = undefined;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
else if (this.state === "CLOSED") {
|
|
181
|
+
// Reset failure count on success in CLOSED state
|
|
182
|
+
this.failureCount = Math.max(0, this.failureCount - 1);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Handle failed operation
|
|
187
|
+
*/
|
|
188
|
+
onFailure() {
|
|
189
|
+
const now = Date.now();
|
|
190
|
+
this.lastFailureTime = now;
|
|
191
|
+
if (this.state === "HALF_OPEN") {
|
|
192
|
+
// Failed while testing - reopen circuit
|
|
193
|
+
this.state = "OPEN";
|
|
194
|
+
this.nextAttemptTime = now + this.timeout;
|
|
195
|
+
this.successCount = 0;
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
// Track failure with timestamp
|
|
199
|
+
this.failures.push(now);
|
|
200
|
+
// Remove failures outside the window
|
|
201
|
+
const windowStart = now - this.windowSize;
|
|
202
|
+
while (this.failures.length > 0 && this.failures[0] < windowStart) {
|
|
203
|
+
this.failures.shift();
|
|
204
|
+
}
|
|
205
|
+
// Count failures in current window
|
|
206
|
+
this.failureCount = this.failures.length;
|
|
207
|
+
// Open circuit if threshold exceeded
|
|
208
|
+
if (this.failureCount >= this.failureThreshold) {
|
|
209
|
+
this.state = "OPEN";
|
|
210
|
+
this.nextAttemptTime = now + this.timeout;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
exports.CircuitBreaker = CircuitBreaker;
|
|
215
|
+
//# sourceMappingURL=circuit-breaker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuit-breaker.js","sourceRoot":"","sources":["../../src/utils/circuit-breaker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deduplication Cache with TTL
|
|
3
|
+
* Prevents duplicate processing of messages/events
|
|
4
|
+
*
|
|
5
|
+
* Uses time-to-live (TTL) for automatic cleanup of old entries
|
|
6
|
+
* without requiring external cleanup timers.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* TTL-based cache for detecting duplicates
|
|
10
|
+
* Automatically expires entries after configured TTL
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const cache = new DeduplicationCache(60000); // 60 second TTL
|
|
15
|
+
*
|
|
16
|
+
* // Check and add in one operation
|
|
17
|
+
* if (!cache.has('message-123')) {
|
|
18
|
+
* cache.add('message-123');
|
|
19
|
+
* // Process message
|
|
20
|
+
* } else {
|
|
21
|
+
* // Duplicate - skip processing
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare class DeduplicationCache {
|
|
26
|
+
private readonly ttl;
|
|
27
|
+
private readonly maxSize;
|
|
28
|
+
private cache;
|
|
29
|
+
/**
|
|
30
|
+
* Creates a new deduplication cache
|
|
31
|
+
*
|
|
32
|
+
* @param ttl - Time-to-live in milliseconds (default: 300000 / 5 minutes)
|
|
33
|
+
* @param maxSize - Maximum cache size before cleanup (default: 10000)
|
|
34
|
+
* @throws {Error} If TTL is less than 1000ms or maxSize is less than 1
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* // 5 minute TTL, max 10k entries
|
|
39
|
+
* const cache = new DeduplicationCache(300000, 10000);
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
constructor(ttl?: number, maxSize?: number);
|
|
43
|
+
/**
|
|
44
|
+
* Check if a key exists and hasn't expired
|
|
45
|
+
*
|
|
46
|
+
* @param key - Key to check
|
|
47
|
+
* @returns true if key exists and is not expired, false otherwise
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* if (cache.has('message-id')) {
|
|
52
|
+
* console.log('Duplicate message detected');
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
has(key: string): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Add a key to the cache with current timestamp
|
|
59
|
+
*
|
|
60
|
+
* @param key - Key to add
|
|
61
|
+
* @returns true if added, false if already exists
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* if (cache.add('message-id')) {
|
|
66
|
+
* // Process message
|
|
67
|
+
* } else {
|
|
68
|
+
* // Already processed
|
|
69
|
+
* }
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
add(key: string): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Remove a specific key from the cache
|
|
75
|
+
*
|
|
76
|
+
* @param key - Key to remove
|
|
77
|
+
* @returns true if key was removed, false if didn't exist
|
|
78
|
+
*/
|
|
79
|
+
delete(key: string): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Clear all entries from the cache
|
|
82
|
+
*/
|
|
83
|
+
clear(): void;
|
|
84
|
+
/**
|
|
85
|
+
* Get current cache size
|
|
86
|
+
*
|
|
87
|
+
* @returns Number of entries in cache
|
|
88
|
+
*/
|
|
89
|
+
size(): number;
|
|
90
|
+
/**
|
|
91
|
+
* Get cache configuration
|
|
92
|
+
*/
|
|
93
|
+
getConfig(): {
|
|
94
|
+
ttl: number;
|
|
95
|
+
maxSize: number;
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Clean up expired entries if cache is getting large
|
|
99
|
+
* Called automatically by has() and add()
|
|
100
|
+
*/
|
|
101
|
+
private cleanupIfNeeded;
|
|
102
|
+
/**
|
|
103
|
+
* Force cleanup of all expired entries
|
|
104
|
+
* Usually not needed as cleanup is automatic
|
|
105
|
+
*
|
|
106
|
+
* @returns Number of entries removed
|
|
107
|
+
*/
|
|
108
|
+
cleanup(): number;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=deduplication-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deduplication-cache.d.ts","sourceRoot":"","sources":["../../src/utils/deduplication-cache.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,kBAAkB;IAiB3B,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAjB1B,OAAO,CAAC,KAAK,CAAiC;IAE9C;;;;;;;;;;;;OAYG;gBAEgB,GAAG,GAAE,MAAe,EACpB,OAAO,GAAE,MAAc;IAU1C;;;;;;;;;;;;OAYG;IACI,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAiBhC;;;;;;;;;;;;;;OAcG;IACI,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAahC;;;;;OAKG;IACI,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAInC;;OAEG;IACI,KAAK,IAAI,IAAI;IAIpB;;;;OAIG;IACI,IAAI,IAAI,MAAM;IAIrB;;OAEG;IACI,SAAS,IAAI;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAOpD;;;OAGG;IACH,OAAO,CAAC,eAAe;IAoBvB;;;;;OAKG;IACI,OAAO,IAAI,MAAM;CAgBzB"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Deduplication Cache with TTL
|
|
4
|
+
* Prevents duplicate processing of messages/events
|
|
5
|
+
*
|
|
6
|
+
* Uses time-to-live (TTL) for automatic cleanup of old entries
|
|
7
|
+
* without requiring external cleanup timers.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.DeduplicationCache = void 0;
|
|
11
|
+
/**
|
|
12
|
+
* TTL-based cache for detecting duplicates
|
|
13
|
+
* Automatically expires entries after configured TTL
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const cache = new DeduplicationCache(60000); // 60 second TTL
|
|
18
|
+
*
|
|
19
|
+
* // Check and add in one operation
|
|
20
|
+
* if (!cache.has('message-123')) {
|
|
21
|
+
* cache.add('message-123');
|
|
22
|
+
* // Process message
|
|
23
|
+
* } else {
|
|
24
|
+
* // Duplicate - skip processing
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
class DeduplicationCache {
|
|
29
|
+
/**
|
|
30
|
+
* Creates a new deduplication cache
|
|
31
|
+
*
|
|
32
|
+
* @param ttl - Time-to-live in milliseconds (default: 300000 / 5 minutes)
|
|
33
|
+
* @param maxSize - Maximum cache size before cleanup (default: 10000)
|
|
34
|
+
* @throws {Error} If TTL is less than 1000ms or maxSize is less than 1
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* // 5 minute TTL, max 10k entries
|
|
39
|
+
* const cache = new DeduplicationCache(300000, 10000);
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
constructor(ttl = 300000, maxSize = 10000) {
|
|
43
|
+
this.ttl = ttl;
|
|
44
|
+
this.maxSize = maxSize;
|
|
45
|
+
this.cache = new Map();
|
|
46
|
+
if (ttl < 1000) {
|
|
47
|
+
throw new Error("DeduplicationCache TTL must be at least 1000ms");
|
|
48
|
+
}
|
|
49
|
+
if (maxSize < 1) {
|
|
50
|
+
throw new Error("DeduplicationCache maxSize must be at least 1");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Check if a key exists and hasn't expired
|
|
55
|
+
*
|
|
56
|
+
* @param key - Key to check
|
|
57
|
+
* @returns true if key exists and is not expired, false otherwise
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* if (cache.has('message-id')) {
|
|
62
|
+
* console.log('Duplicate message detected');
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
has(key) {
|
|
67
|
+
this.cleanupIfNeeded();
|
|
68
|
+
const entry = this.cache.get(key);
|
|
69
|
+
if (!entry) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
// Check if expired
|
|
73
|
+
if (Date.now() - entry.timestamp > this.ttl) {
|
|
74
|
+
this.cache.delete(key);
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Add a key to the cache with current timestamp
|
|
81
|
+
*
|
|
82
|
+
* @param key - Key to add
|
|
83
|
+
* @returns true if added, false if already exists
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* if (cache.add('message-id')) {
|
|
88
|
+
* // Process message
|
|
89
|
+
* } else {
|
|
90
|
+
* // Already processed
|
|
91
|
+
* }
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
add(key) {
|
|
95
|
+
if (this.has(key)) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
this.cache.set(key, {
|
|
99
|
+
timestamp: Date.now()
|
|
100
|
+
});
|
|
101
|
+
this.cleanupIfNeeded();
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Remove a specific key from the cache
|
|
106
|
+
*
|
|
107
|
+
* @param key - Key to remove
|
|
108
|
+
* @returns true if key was removed, false if didn't exist
|
|
109
|
+
*/
|
|
110
|
+
delete(key) {
|
|
111
|
+
return this.cache.delete(key);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Clear all entries from the cache
|
|
115
|
+
*/
|
|
116
|
+
clear() {
|
|
117
|
+
this.cache.clear();
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get current cache size
|
|
121
|
+
*
|
|
122
|
+
* @returns Number of entries in cache
|
|
123
|
+
*/
|
|
124
|
+
size() {
|
|
125
|
+
return this.cache.size;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get cache configuration
|
|
129
|
+
*/
|
|
130
|
+
getConfig() {
|
|
131
|
+
return {
|
|
132
|
+
ttl: this.ttl,
|
|
133
|
+
maxSize: this.maxSize
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Clean up expired entries if cache is getting large
|
|
138
|
+
* Called automatically by has() and add()
|
|
139
|
+
*/
|
|
140
|
+
cleanupIfNeeded() {
|
|
141
|
+
// Only cleanup if approaching max size
|
|
142
|
+
if (this.cache.size < this.maxSize * 0.9) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const now = Date.now();
|
|
146
|
+
const keysToDelete = [];
|
|
147
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
148
|
+
if (now - entry.timestamp > this.ttl) {
|
|
149
|
+
keysToDelete.push(key);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
for (const key of keysToDelete) {
|
|
153
|
+
this.cache.delete(key);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Force cleanup of all expired entries
|
|
158
|
+
* Usually not needed as cleanup is automatic
|
|
159
|
+
*
|
|
160
|
+
* @returns Number of entries removed
|
|
161
|
+
*/
|
|
162
|
+
cleanup() {
|
|
163
|
+
const now = Date.now();
|
|
164
|
+
const keysToDelete = [];
|
|
165
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
166
|
+
if (now - entry.timestamp > this.ttl) {
|
|
167
|
+
keysToDelete.push(key);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
for (const key of keysToDelete) {
|
|
171
|
+
this.cache.delete(key);
|
|
172
|
+
}
|
|
173
|
+
return keysToDelete.length;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
exports.DeduplicationCache = DeduplicationCache;
|
|
177
|
+
//# sourceMappingURL=deduplication-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deduplication-cache.js","sourceRoot":"","sources":["../../src/utils/deduplication-cache.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAMH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAa,kBAAkB;IAG7B;;;;;;;;;;;;OAYG;IACH,YACmB,MAAc,MAAM,EACpB,UAAkB,KAAK;QADvB,QAAG,GAAH,GAAG,CAAiB;QACpB,YAAO,GAAP,OAAO,CAAgB;QAjBlC,UAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;QAmB5C,IAAI,GAAG,GAAG,IAAI,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACpE,CAAC;QACD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;OAYG;IACI,GAAG,CAAC,GAAW;QACpB,IAAI,CAAC,eAAe,EAAE,CAAC;QAEvB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,KAAK,CAAC;QACf,CAAC;QAED,mBAAmB;QACnB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC5C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACI,GAAG,CAAC,GAAW;QACpB,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAClB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAClB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC,CAAC;QAEH,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,GAAW;QACvB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAED;;OAEG;IACI,KAAK;QACV,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED;;;;OAIG;IACI,IAAI;QACT,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;IAED;;OAEG;IACI,SAAS;QACd,OAAO;YACL,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,eAAe;QACrB,uCAAuC;QACvC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC;YACzC,OAAO;QACT,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,YAAY,GAAa,EAAE,CAAC;QAElC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAChD,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACrC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QAED,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;YAC/B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACI,OAAO;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,YAAY,GAAa,EAAE,CAAC;QAElC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAChD,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACrC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QAED,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;YAC/B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;QAED,OAAO,YAAY,CAAC,MAAM,CAAC;IAC7B,CAAC;CACF;AAxKD,gDAwKC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Waiter Utility
|
|
3
|
+
* Provides a clean Promise-based API for waiting for events with timeout and filtering
|
|
4
|
+
* Eliminates callback hell and ensures proper cleanup of listeners and timers
|
|
5
|
+
*/
|
|
6
|
+
import { EventEmitter } from "eventemitter3";
|
|
7
|
+
/**
|
|
8
|
+
* Options for waiting for an event
|
|
9
|
+
*/
|
|
10
|
+
export interface WaitForEventOptions<T> {
|
|
11
|
+
/**
|
|
12
|
+
* Timeout in milliseconds
|
|
13
|
+
*/
|
|
14
|
+
timeout: number;
|
|
15
|
+
/**
|
|
16
|
+
* Optional filter function to match specific events
|
|
17
|
+
* If provided, only events that pass the filter will resolve the promise
|
|
18
|
+
*
|
|
19
|
+
* @param data - The event data
|
|
20
|
+
* @returns true if this is the event we're waiting for, false to keep waiting
|
|
21
|
+
*/
|
|
22
|
+
filter?: (data: T) => boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Optional custom timeout error message
|
|
25
|
+
* If not provided, a default message will be used
|
|
26
|
+
*/
|
|
27
|
+
timeoutMessage?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Wait for an event to be emitted with automatic timeout and cleanup
|
|
31
|
+
*
|
|
32
|
+
* This utility encapsulates the complex pattern of:
|
|
33
|
+
* - Setting up event listeners
|
|
34
|
+
* - Managing timeouts
|
|
35
|
+
* - Cleaning up listeners and timers in all code paths
|
|
36
|
+
* - Filtering events
|
|
37
|
+
*
|
|
38
|
+
* All cleanup is guaranteed to happen, preventing memory leaks.
|
|
39
|
+
*
|
|
40
|
+
* @param emitter - The EventEmitter to listen to
|
|
41
|
+
* @param eventName - The name of the event to wait for
|
|
42
|
+
* @param options - Configuration options
|
|
43
|
+
* @returns Promise that resolves with the event data or rejects on timeout
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* // Simple usage: wait for any 'data' event
|
|
48
|
+
* const data = await waitForEvent(emitter, 'data', { timeout: 5000 });
|
|
49
|
+
*
|
|
50
|
+
* // With filter: wait for specific event
|
|
51
|
+
* const response = await waitForEvent(wsClient, 'agent:response', {
|
|
52
|
+
* timeout: 30000,
|
|
53
|
+
* filter: (r) => r.taskId === myTaskId,
|
|
54
|
+
* timeoutMessage: 'Agent did not respond in time'
|
|
55
|
+
* });
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare function waitForEvent<T = any>(emitter: EventEmitter, eventName: string, options: WaitForEventOptions<T>): Promise<T>;
|
|
59
|
+
/**
|
|
60
|
+
* Wait for multiple events simultaneously (race condition)
|
|
61
|
+
* Resolves with the first event that fires and matches its filter
|
|
62
|
+
*
|
|
63
|
+
* @param waiters - Array of event waiter configurations
|
|
64
|
+
* @returns Promise that resolves with the first matching event
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* // Wait for either success or error
|
|
69
|
+
* const result = await waitForAnyEvent([
|
|
70
|
+
* { emitter: client, eventName: 'auth:success', options: { timeout: 5000 } },
|
|
71
|
+
* { emitter: client, eventName: 'auth:error', options: { timeout: 5000 } }
|
|
72
|
+
* ]);
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export declare function waitForAnyEvent<T = any>(waiters: Array<{
|
|
76
|
+
emitter: EventEmitter;
|
|
77
|
+
eventName: string;
|
|
78
|
+
options: WaitForEventOptions<T>;
|
|
79
|
+
}>): Promise<T>;
|
|
80
|
+
/**
|
|
81
|
+
* Wait for all events to fire (all must complete)
|
|
82
|
+
* Useful when you need multiple events to occur before proceeding
|
|
83
|
+
*
|
|
84
|
+
* @param waiters - Array of event waiter configurations
|
|
85
|
+
* @returns Promise that resolves with array of all event data
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* // Wait for both auth and connection
|
|
90
|
+
* const [authState, connState] = await waitForAllEvents([
|
|
91
|
+
* { emitter: client, eventName: 'auth:success', options: { timeout: 5000 } },
|
|
92
|
+
* { emitter: client, eventName: 'connection:open', options: { timeout: 5000 } }
|
|
93
|
+
* ]);
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare function waitForAllEvents<T = any>(waiters: Array<{
|
|
97
|
+
emitter: EventEmitter;
|
|
98
|
+
eventName: string;
|
|
99
|
+
options: WaitForEventOptions<T>;
|
|
100
|
+
}>): Promise<T[]>;
|
|
101
|
+
//# sourceMappingURL=event-waiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-waiter.d.ts","sourceRoot":"","sources":["../../src/utils/event-waiter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC;IACpC;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;IAE9B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,YAAY,CAAC,CAAC,GAAG,GAAG,EACxC,OAAO,EAAE,YAAY,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAC9B,OAAO,CAAC,CAAC,CAAC,CA6CZ;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,eAAe,CAAC,CAAC,GAAG,GAAG,EAC3C,OAAO,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,YAAY,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC;CACjC,CAAC,GACD,OAAO,CAAC,CAAC,CAAC,CAMZ;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,GAAG,GAAG,EAC5C,OAAO,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,YAAY,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC;CACjC,CAAC,GACD,OAAO,CAAC,CAAC,EAAE,CAAC,CAMd"}
|