@tangle-network/agent-core 0.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/LICENSE +21 -0
- package/README.md +35 -0
- package/dist/auth/browser.d.ts +22 -0
- package/dist/auth/browser.d.ts.map +1 -0
- package/dist/auth/browser.js +43 -0
- package/dist/auth/browser.js.map +1 -0
- package/dist/auth/index.d.ts +430 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +841 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/computer-use/index.d.ts +122 -0
- package/dist/computer-use/index.d.ts.map +1 -0
- package/dist/computer-use/index.js +422 -0
- package/dist/computer-use/index.js.map +1 -0
- package/dist/errors-DJ6U6cHY.js +146 -0
- package/dist/errors-DJ6U6cHY.js.map +1 -0
- package/dist/events/index.d.ts +2 -0
- package/dist/events/index.js +2 -0
- package/dist/events-CUWh9qrv.js +263 -0
- package/dist/events-CUWh9qrv.js.map +1 -0
- package/dist/index-CFA8kgHJ.d.ts +352 -0
- package/dist/index-CFA8kgHJ.d.ts.map +1 -0
- package/dist/index-CtebBodu.d.ts +108 -0
- package/dist/index-CtebBodu.d.ts.map +1 -0
- package/dist/index-DiQX9bjq.d.ts +55 -0
- package/dist/index-DiQX9bjq.d.ts.map +1 -0
- package/dist/index-DlPznmKA.d.ts +158 -0
- package/dist/index-DlPznmKA.d.ts.map +1 -0
- package/dist/index-z2wPdzFb.d.ts +133 -0
- package/dist/index-z2wPdzFb.d.ts.map +1 -0
- package/dist/index.d.ts +565 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +822 -0
- package/dist/index.js.map +1 -0
- package/dist/resilience/index.d.ts +2 -0
- package/dist/resilience/index.js +2 -0
- package/dist/resilience-BQzDfw_C.js +221 -0
- package/dist/resilience-BQzDfw_C.js.map +1 -0
- package/dist/sse/index.d.ts +174 -0
- package/dist/sse/index.d.ts.map +1 -0
- package/dist/sse/index.js +303 -0
- package/dist/sse/index.js.map +1 -0
- package/dist/transport/index.d.ts +2 -0
- package/dist/transport/index.js +2 -0
- package/dist/transport-mKLoQep5.js +427 -0
- package/dist/transport-mKLoQep5.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types-D5VLaol0.js +31 -0
- package/dist/types-D5VLaol0.js.map +1 -0
- package/dist/types-DC6OJ1um.js +331 -0
- package/dist/types-DC6OJ1um.js.map +1 -0
- package/dist/types-DiDSGM8K.d.ts +320 -0
- package/dist/types-DiDSGM8K.d.ts.map +1 -0
- package/package.json +132 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
//#region src/events/buffer.ts
|
|
2
|
+
const DEFAULT_CONFIG$2 = {
|
|
3
|
+
maxSize: 1e3,
|
|
4
|
+
ttlMs: 3e5,
|
|
5
|
+
overflowStrategy: "drop-oldest"
|
|
6
|
+
};
|
|
7
|
+
var EventBuffer = class {
|
|
8
|
+
config;
|
|
9
|
+
events = [];
|
|
10
|
+
seenIds = /* @__PURE__ */ new Set();
|
|
11
|
+
cleanupTimer;
|
|
12
|
+
constructor(config = {}) {
|
|
13
|
+
this.config = {
|
|
14
|
+
...DEFAULT_CONFIG$2,
|
|
15
|
+
...config
|
|
16
|
+
};
|
|
17
|
+
this.startCleanup();
|
|
18
|
+
}
|
|
19
|
+
/** Add an event to the buffer (deduplicates by ID) */
|
|
20
|
+
push(id, data, eventType) {
|
|
21
|
+
if (this.seenIds.has(id)) return;
|
|
22
|
+
const event = {
|
|
23
|
+
id,
|
|
24
|
+
data,
|
|
25
|
+
timestamp: Date.now(),
|
|
26
|
+
eventType
|
|
27
|
+
};
|
|
28
|
+
if (this.events.length >= this.config.maxSize) if (this.config.overflowStrategy === "drop-oldest") {
|
|
29
|
+
const removed = this.events.shift();
|
|
30
|
+
if (removed) this.seenIds.delete(removed.id);
|
|
31
|
+
} else return;
|
|
32
|
+
this.events.push(event);
|
|
33
|
+
this.seenIds.add(id);
|
|
34
|
+
}
|
|
35
|
+
/** Get all buffered events */
|
|
36
|
+
getAll() {
|
|
37
|
+
this.pruneExpired();
|
|
38
|
+
return [...this.events];
|
|
39
|
+
}
|
|
40
|
+
/** Get events since a specific event ID */
|
|
41
|
+
getSince(lastEventId) {
|
|
42
|
+
this.pruneExpired();
|
|
43
|
+
const index = this.events.findIndex((e) => e.id === lastEventId);
|
|
44
|
+
if (index === -1) return [...this.events];
|
|
45
|
+
return this.events.slice(index + 1);
|
|
46
|
+
}
|
|
47
|
+
/** Get events after a timestamp */
|
|
48
|
+
getSinceTimestamp(timestamp) {
|
|
49
|
+
this.pruneExpired();
|
|
50
|
+
return this.events.filter((e) => e.timestamp > timestamp);
|
|
51
|
+
}
|
|
52
|
+
/** Clear all buffered events */
|
|
53
|
+
clear() {
|
|
54
|
+
this.events = [];
|
|
55
|
+
this.seenIds.clear();
|
|
56
|
+
}
|
|
57
|
+
/** Get current buffer size */
|
|
58
|
+
size() {
|
|
59
|
+
return this.events.length;
|
|
60
|
+
}
|
|
61
|
+
/** Check if buffer is empty */
|
|
62
|
+
isEmpty() {
|
|
63
|
+
return this.events.length === 0;
|
|
64
|
+
}
|
|
65
|
+
/** Check if buffer is full */
|
|
66
|
+
isFull() {
|
|
67
|
+
return this.events.length >= this.config.maxSize;
|
|
68
|
+
}
|
|
69
|
+
/** Dispose of the buffer and cleanup resources */
|
|
70
|
+
dispose() {
|
|
71
|
+
if (this.cleanupTimer) {
|
|
72
|
+
clearInterval(this.cleanupTimer);
|
|
73
|
+
this.cleanupTimer = void 0;
|
|
74
|
+
}
|
|
75
|
+
this.clear();
|
|
76
|
+
}
|
|
77
|
+
pruneExpired() {
|
|
78
|
+
const cutoff = Date.now() - this.config.ttlMs;
|
|
79
|
+
const expired = this.events.filter((e) => e.timestamp <= cutoff);
|
|
80
|
+
for (const e of expired) this.seenIds.delete(e.id);
|
|
81
|
+
this.events = this.events.filter((e) => e.timestamp > cutoff);
|
|
82
|
+
}
|
|
83
|
+
startCleanup() {
|
|
84
|
+
this.cleanupTimer = setInterval(() => this.pruneExpired(), 6e4);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/events/channel.ts
|
|
89
|
+
const DEFAULT_CONFIG$1 = {
|
|
90
|
+
maxSubscribersPerTopic: 100,
|
|
91
|
+
enableWildcards: true
|
|
92
|
+
};
|
|
93
|
+
var EventChannel = class {
|
|
94
|
+
config;
|
|
95
|
+
subscribers = [];
|
|
96
|
+
constructor(config = {}) {
|
|
97
|
+
this.config = {
|
|
98
|
+
...DEFAULT_CONFIG$1,
|
|
99
|
+
...config
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Subscribe to a topic or pattern.
|
|
104
|
+
*
|
|
105
|
+
* Patterns:
|
|
106
|
+
* - "exact.topic" - matches only "exact.topic"
|
|
107
|
+
* - "prefix.*" - matches "prefix.foo", "prefix.bar", etc.
|
|
108
|
+
* - "prefix.**" - matches "prefix.foo", "prefix.foo.bar", etc.
|
|
109
|
+
* - "**" - matches all topics
|
|
110
|
+
*
|
|
111
|
+
* Returns an unsubscribe function.
|
|
112
|
+
*/
|
|
113
|
+
subscribe(pattern, handler) {
|
|
114
|
+
const subscriber = {
|
|
115
|
+
pattern,
|
|
116
|
+
handler,
|
|
117
|
+
regex: this.config.enableWildcards ? this.patternToRegex(pattern) : void 0
|
|
118
|
+
};
|
|
119
|
+
this.subscribers.push(subscriber);
|
|
120
|
+
return () => {
|
|
121
|
+
const index = this.subscribers.indexOf(subscriber);
|
|
122
|
+
if (index !== -1) this.subscribers.splice(index, 1);
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Publish a message to a topic.
|
|
127
|
+
* Delivers to all matching subscribers.
|
|
128
|
+
*/
|
|
129
|
+
publish(topic, message) {
|
|
130
|
+
let delivered = 0;
|
|
131
|
+
for (const subscriber of this.subscribers) if (this.matches(subscriber, topic)) try {
|
|
132
|
+
subscriber.handler(message, topic);
|
|
133
|
+
delivered++;
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.error(`Error in channel handler for ${topic}:`, error);
|
|
136
|
+
}
|
|
137
|
+
return delivered;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Check if any subscribers are listening to a topic.
|
|
141
|
+
*/
|
|
142
|
+
hasSubscribers(topic) {
|
|
143
|
+
return this.subscribers.some((s) => this.matches(s, topic));
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Get the number of subscribers for a topic.
|
|
147
|
+
*/
|
|
148
|
+
subscriberCount(topic) {
|
|
149
|
+
return this.subscribers.filter((s) => this.matches(s, topic)).length;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Get all unique patterns being subscribed to.
|
|
153
|
+
*/
|
|
154
|
+
getPatterns() {
|
|
155
|
+
return [...new Set(this.subscribers.map((s) => s.pattern))];
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Clear all subscribers.
|
|
159
|
+
*/
|
|
160
|
+
clear() {
|
|
161
|
+
this.subscribers.length = 0;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get total subscriber count.
|
|
165
|
+
*/
|
|
166
|
+
size() {
|
|
167
|
+
return this.subscribers.length;
|
|
168
|
+
}
|
|
169
|
+
matches(subscriber, topic) {
|
|
170
|
+
if (!this.config.enableWildcards || !subscriber.regex) return subscriber.pattern === topic;
|
|
171
|
+
return subscriber.regex.test(topic);
|
|
172
|
+
}
|
|
173
|
+
patternToRegex(pattern) {
|
|
174
|
+
if (pattern === "**") return /^.*$/;
|
|
175
|
+
let escaped = pattern.replace(/[+?^${}()|[\]\\]/g, "\\$&");
|
|
176
|
+
escaped = escaped.replace(/\*\*/g, "<<<GLOBSTAR>>>");
|
|
177
|
+
escaped = escaped.replace(/\*/g, "[^.]+");
|
|
178
|
+
escaped = escaped.replace(/<<<GLOBSTAR>>>/g, ".*");
|
|
179
|
+
return new RegExp(`^${escaped}$`);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region src/events/deduplication.ts
|
|
184
|
+
const DEFAULT_CONFIG = {
|
|
185
|
+
maxSize: 1e4,
|
|
186
|
+
windowMs: 6e4
|
|
187
|
+
};
|
|
188
|
+
var EventDeduplicator = class {
|
|
189
|
+
config;
|
|
190
|
+
seen = /* @__PURE__ */ new Map();
|
|
191
|
+
cleanupTimer;
|
|
192
|
+
constructor(config = {}) {
|
|
193
|
+
this.config = {
|
|
194
|
+
...DEFAULT_CONFIG,
|
|
195
|
+
...config
|
|
196
|
+
};
|
|
197
|
+
this.startCleanup();
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Check if an event has been seen and mark it as seen.
|
|
201
|
+
* Returns true if this is a duplicate, false if it's new.
|
|
202
|
+
*/
|
|
203
|
+
isDuplicate(eventId) {
|
|
204
|
+
const now = Date.now();
|
|
205
|
+
const existing = this.seen.get(eventId);
|
|
206
|
+
if (existing && now - existing.timestamp < this.config.windowMs) return true;
|
|
207
|
+
if (this.seen.size >= this.config.maxSize) this.evictOldest();
|
|
208
|
+
this.seen.set(eventId, { timestamp: now });
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Mark an event as seen without checking for duplicates.
|
|
213
|
+
*/
|
|
214
|
+
markSeen(eventId) {
|
|
215
|
+
if (this.seen.size >= this.config.maxSize) this.evictOldest();
|
|
216
|
+
this.seen.set(eventId, { timestamp: Date.now() });
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Check if an event has been seen (without marking).
|
|
220
|
+
*/
|
|
221
|
+
hasSeen(eventId) {
|
|
222
|
+
const existing = this.seen.get(eventId);
|
|
223
|
+
if (!existing) return false;
|
|
224
|
+
return Date.now() - existing.timestamp < this.config.windowMs;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Clear all tracked events.
|
|
228
|
+
*/
|
|
229
|
+
clear() {
|
|
230
|
+
this.seen.clear();
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Get the number of tracked events.
|
|
234
|
+
*/
|
|
235
|
+
size() {
|
|
236
|
+
return this.seen.size;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Dispose of the deduplicator and cleanup resources.
|
|
240
|
+
*/
|
|
241
|
+
dispose() {
|
|
242
|
+
if (this.cleanupTimer) {
|
|
243
|
+
clearInterval(this.cleanupTimer);
|
|
244
|
+
this.cleanupTimer = void 0;
|
|
245
|
+
}
|
|
246
|
+
this.clear();
|
|
247
|
+
}
|
|
248
|
+
evictOldest() {
|
|
249
|
+
const firstKey = this.seen.keys().next().value;
|
|
250
|
+
if (firstKey !== void 0) this.seen.delete(firstKey);
|
|
251
|
+
}
|
|
252
|
+
pruneExpired() {
|
|
253
|
+
const cutoff = Date.now() - this.config.windowMs;
|
|
254
|
+
for (const [id, entry] of this.seen) if (entry.timestamp < cutoff) this.seen.delete(id);
|
|
255
|
+
}
|
|
256
|
+
startCleanup() {
|
|
257
|
+
this.cleanupTimer = setInterval(() => this.pruneExpired(), 3e4);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
//#endregion
|
|
261
|
+
export { EventChannel as n, EventBuffer as r, EventDeduplicator as t };
|
|
262
|
+
|
|
263
|
+
//# sourceMappingURL=events-CUWh9qrv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events-CUWh9qrv.js","names":["DEFAULT_CONFIG","DEFAULT_CONFIG"],"sources":["../src/events/buffer.ts","../src/events/channel.ts","../src/events/deduplication.ts"],"sourcesContent":["/**\n * Event Buffer\n *\n * Buffers events during disconnections for replay on reconnect.\n * Implements overflow handling with configurable strategies.\n */\n\nexport interface EventBufferConfig {\n /** Maximum number of events to buffer (default: 1000) */\n maxSize: number;\n /** Time-to-live in milliseconds for buffered events (default: 300000 = 5min) */\n ttlMs: number;\n /** Strategy when buffer is full: \"drop-oldest\" or \"drop-newest\" */\n overflowStrategy: \"drop-oldest\" | \"drop-newest\";\n}\n\nexport interface BufferedEvent<T = unknown> {\n id: string;\n data: T;\n timestamp: number;\n eventType?: string;\n}\n\nconst DEFAULT_CONFIG: EventBufferConfig = {\n maxSize: 1000,\n ttlMs: 300000,\n overflowStrategy: \"drop-oldest\",\n};\n\nexport class EventBuffer<T = unknown> {\n private readonly config: EventBufferConfig;\n private events: BufferedEvent<T>[] = [];\n private seenIds: Set<string> = new Set();\n private cleanupTimer?: ReturnType<typeof setInterval>;\n\n constructor(config: Partial<EventBufferConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.startCleanup();\n }\n\n /** Add an event to the buffer (deduplicates by ID) */\n push(id: string, data: T, eventType?: string): void {\n // Deduplicate by event ID to prevent duplicate events during replay\n if (this.seenIds.has(id)) {\n return;\n }\n\n const event: BufferedEvent<T> = {\n id,\n data,\n timestamp: Date.now(),\n eventType,\n };\n\n if (this.events.length >= this.config.maxSize) {\n if (this.config.overflowStrategy === \"drop-oldest\") {\n const removed = this.events.shift();\n if (removed) {\n this.seenIds.delete(removed.id);\n }\n } else {\n return; // drop-newest: don't add\n }\n }\n\n this.events.push(event);\n this.seenIds.add(id);\n }\n\n /** Get all buffered events */\n getAll(): BufferedEvent<T>[] {\n this.pruneExpired();\n return [...this.events];\n }\n\n /** Get events since a specific event ID */\n getSince(lastEventId: string): BufferedEvent<T>[] {\n this.pruneExpired();\n const index = this.events.findIndex((e) => e.id === lastEventId);\n if (index === -1) {\n return [...this.events];\n }\n return this.events.slice(index + 1);\n }\n\n /** Get events after a timestamp */\n getSinceTimestamp(timestamp: number): BufferedEvent<T>[] {\n this.pruneExpired();\n return this.events.filter((e) => e.timestamp > timestamp);\n }\n\n /** Clear all buffered events */\n clear(): void {\n this.events = [];\n this.seenIds.clear();\n }\n\n /** Get current buffer size */\n size(): number {\n return this.events.length;\n }\n\n /** Check if buffer is empty */\n isEmpty(): boolean {\n return this.events.length === 0;\n }\n\n /** Check if buffer is full */\n isFull(): boolean {\n return this.events.length >= this.config.maxSize;\n }\n\n /** Dispose of the buffer and cleanup resources */\n dispose(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n this.clear();\n }\n\n private pruneExpired(): void {\n const cutoff = Date.now() - this.config.ttlMs;\n const expired = this.events.filter((e) => e.timestamp <= cutoff);\n for (const e of expired) {\n this.seenIds.delete(e.id);\n }\n this.events = this.events.filter((e) => e.timestamp > cutoff);\n }\n\n private startCleanup(): void {\n // Run cleanup every minute\n this.cleanupTimer = setInterval(() => this.pruneExpired(), 60000);\n }\n}\n","/**\n * Channel Pub/Sub\n *\n * Topic-based event distribution with wildcard pattern matching.\n * Supports patterns like \"message.*\", \"**\", and exact matches.\n */\n\nexport type ChannelHandler<T = unknown> = (message: T, topic: string) => void;\n\nexport interface ChannelConfig {\n /** Maximum number of subscribers per topic (default: 100) */\n maxSubscribersPerTopic: number;\n /** Enable wildcard patterns (default: true) */\n enableWildcards: boolean;\n}\n\ninterface Subscriber<T> {\n pattern: string;\n handler: ChannelHandler<T>;\n regex?: RegExp;\n}\n\nconst DEFAULT_CONFIG: ChannelConfig = {\n maxSubscribersPerTopic: 100,\n enableWildcards: true,\n};\n\nexport class EventChannel<T = unknown> {\n private readonly config: ChannelConfig;\n private readonly subscribers: Subscriber<T>[] = [];\n\n constructor(config: Partial<ChannelConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n /**\n * Subscribe to a topic or pattern.\n *\n * Patterns:\n * - \"exact.topic\" - matches only \"exact.topic\"\n * - \"prefix.*\" - matches \"prefix.foo\", \"prefix.bar\", etc.\n * - \"prefix.**\" - matches \"prefix.foo\", \"prefix.foo.bar\", etc.\n * - \"**\" - matches all topics\n *\n * Returns an unsubscribe function.\n */\n subscribe(pattern: string, handler: ChannelHandler<T>): () => void {\n const subscriber: Subscriber<T> = {\n pattern,\n handler,\n regex: this.config.enableWildcards\n ? this.patternToRegex(pattern)\n : undefined,\n };\n\n this.subscribers.push(subscriber);\n\n return () => {\n const index = this.subscribers.indexOf(subscriber);\n if (index !== -1) {\n this.subscribers.splice(index, 1);\n }\n };\n }\n\n /**\n * Publish a message to a topic.\n * Delivers to all matching subscribers.\n */\n publish(topic: string, message: T): number {\n let delivered = 0;\n\n for (const subscriber of this.subscribers) {\n if (this.matches(subscriber, topic)) {\n try {\n subscriber.handler(message, topic);\n delivered++;\n } catch (error) {\n console.error(`Error in channel handler for ${topic}:`, error);\n }\n }\n }\n\n return delivered;\n }\n\n /**\n * Check if any subscribers are listening to a topic.\n */\n hasSubscribers(topic: string): boolean {\n return this.subscribers.some((s) => this.matches(s, topic));\n }\n\n /**\n * Get the number of subscribers for a topic.\n */\n subscriberCount(topic: string): number {\n return this.subscribers.filter((s) => this.matches(s, topic)).length;\n }\n\n /**\n * Get all unique patterns being subscribed to.\n */\n getPatterns(): string[] {\n return [...new Set(this.subscribers.map((s) => s.pattern))];\n }\n\n /**\n * Clear all subscribers.\n */\n clear(): void {\n this.subscribers.length = 0;\n }\n\n /**\n * Get total subscriber count.\n */\n size(): number {\n return this.subscribers.length;\n }\n\n private matches(subscriber: Subscriber<T>, topic: string): boolean {\n if (!this.config.enableWildcards || !subscriber.regex) {\n return subscriber.pattern === topic;\n }\n return subscriber.regex.test(topic);\n }\n\n private patternToRegex(pattern: string): RegExp {\n // Handle special patterns\n if (pattern === \"**\") {\n return /^.*$/;\n }\n\n // Escape special regex characters except * and .\n let escaped = pattern.replace(/[+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\n // Replace ** with match-all\n escaped = escaped.replace(/\\*\\*/g, \"<<<GLOBSTAR>>>\");\n\n // Replace * with single-segment match\n escaped = escaped.replace(/\\*/g, \"[^.]+\");\n\n // Restore globstar\n escaped = escaped.replace(/<<<GLOBSTAR>>>/g, \".*\");\n\n return new RegExp(`^${escaped}$`);\n }\n}\n","/**\n * Event Deduplication\n *\n * LRU-bounded set for tracking seen event IDs.\n * Prevents duplicate event processing during reconnections.\n */\n\nexport interface DeduplicatorConfig {\n /** Maximum number of event IDs to track (default: 10000) */\n maxSize: number;\n /** Time window in milliseconds for deduplication (default: 60000 = 1min) */\n windowMs: number;\n}\n\ninterface TrackedEvent {\n timestamp: number;\n}\n\nconst DEFAULT_CONFIG: DeduplicatorConfig = {\n maxSize: 10000,\n windowMs: 60000,\n};\n\nexport class EventDeduplicator {\n private readonly config: DeduplicatorConfig;\n private readonly seen: Map<string, TrackedEvent> = new Map();\n private cleanupTimer?: ReturnType<typeof setInterval>;\n\n constructor(config: Partial<DeduplicatorConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.startCleanup();\n }\n\n /**\n * Check if an event has been seen and mark it as seen.\n * Returns true if this is a duplicate, false if it's new.\n */\n isDuplicate(eventId: string): boolean {\n const now = Date.now();\n const existing = this.seen.get(eventId);\n\n if (existing && now - existing.timestamp < this.config.windowMs) {\n return true;\n }\n\n // Evict oldest if at capacity\n if (this.seen.size >= this.config.maxSize) {\n this.evictOldest();\n }\n\n this.seen.set(eventId, { timestamp: now });\n return false;\n }\n\n /**\n * Mark an event as seen without checking for duplicates.\n */\n markSeen(eventId: string): void {\n if (this.seen.size >= this.config.maxSize) {\n this.evictOldest();\n }\n this.seen.set(eventId, { timestamp: Date.now() });\n }\n\n /**\n * Check if an event has been seen (without marking).\n */\n hasSeen(eventId: string): boolean {\n const existing = this.seen.get(eventId);\n if (!existing) return false;\n return Date.now() - existing.timestamp < this.config.windowMs;\n }\n\n /**\n * Clear all tracked events.\n */\n clear(): void {\n this.seen.clear();\n }\n\n /**\n * Get the number of tracked events.\n */\n size(): number {\n return this.seen.size;\n }\n\n /**\n * Dispose of the deduplicator and cleanup resources.\n */\n dispose(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n this.clear();\n }\n\n private evictOldest(): void {\n // Map maintains insertion order, so first entry is oldest\n const firstKey = this.seen.keys().next().value;\n if (firstKey !== undefined) {\n this.seen.delete(firstKey);\n }\n }\n\n private pruneExpired(): void {\n const cutoff = Date.now() - this.config.windowMs;\n for (const [id, entry] of this.seen) {\n if (entry.timestamp < cutoff) {\n this.seen.delete(id);\n }\n }\n }\n\n private startCleanup(): void {\n // Run cleanup every 30 seconds\n this.cleanupTimer = setInterval(() => this.pruneExpired(), 30000);\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
//#region src/transport/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Transport Types
|
|
4
|
+
*
|
|
5
|
+
* Core type definitions for the transport layer abstraction.
|
|
6
|
+
*/
|
|
7
|
+
/** Connection lifecycle states */
|
|
8
|
+
type ConnectionState = "disconnected" | "connecting" | "connected" | "reconnecting" | "failed";
|
|
9
|
+
/** Connection quality levels for monitoring */
|
|
10
|
+
type ConnectionQuality = "excellent" | "good" | "degraded" | "poor";
|
|
11
|
+
/**
|
|
12
|
+
* Transport mode for event delivery.
|
|
13
|
+
*
|
|
14
|
+
* - 'websocket': WebSocket via SessionGatewayClient (default, traditional server)
|
|
15
|
+
* - 'sse': HTTP SSE (serverless/Cloudflare Workers)
|
|
16
|
+
*/
|
|
17
|
+
type TransportMode = "websocket" | "sse";
|
|
18
|
+
/** SSE event from server */
|
|
19
|
+
interface SSEEvent {
|
|
20
|
+
id?: string;
|
|
21
|
+
event?: string;
|
|
22
|
+
data: string;
|
|
23
|
+
retry?: number;
|
|
24
|
+
}
|
|
25
|
+
/** Request options for HTTP calls */
|
|
26
|
+
interface RequestOptions {
|
|
27
|
+
method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
28
|
+
path: string;
|
|
29
|
+
body?: unknown;
|
|
30
|
+
headers?: Record<string, string>;
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
timeout?: number;
|
|
33
|
+
}
|
|
34
|
+
/** Stream subscription options */
|
|
35
|
+
interface StreamOptions {
|
|
36
|
+
/** HTTP method (default: GET, use POST for streaming endpoints that accept a body) */
|
|
37
|
+
method?: "GET" | "POST";
|
|
38
|
+
path: string;
|
|
39
|
+
/** Request body (for POST requests) */
|
|
40
|
+
body?: unknown;
|
|
41
|
+
headers?: Record<string, string>;
|
|
42
|
+
/** Last event ID for resumption */
|
|
43
|
+
lastEventId?: string;
|
|
44
|
+
/** Reconnection configuration */
|
|
45
|
+
reconnect?: ReconnectionConfig;
|
|
46
|
+
/** Abort signal */
|
|
47
|
+
signal?: AbortSignal;
|
|
48
|
+
}
|
|
49
|
+
/** Reconnection configuration with exponential backoff */
|
|
50
|
+
interface ReconnectionConfig {
|
|
51
|
+
/** Initial delay in milliseconds (default: 1000) */
|
|
52
|
+
initialDelayMs?: number;
|
|
53
|
+
/** Maximum delay in milliseconds (default: 30000) */
|
|
54
|
+
maxDelayMs?: number;
|
|
55
|
+
/** Backoff multiplier (default: 1.5) */
|
|
56
|
+
multiplier?: number;
|
|
57
|
+
/** Jitter factor 0-1 (default: 0.2) */
|
|
58
|
+
jitter?: number;
|
|
59
|
+
/** Maximum reconnection attempts (default: 10, -1 for infinite) */
|
|
60
|
+
maxAttempts?: number;
|
|
61
|
+
}
|
|
62
|
+
/** Default reconnection config */
|
|
63
|
+
declare const DEFAULT_RECONNECTION_CONFIG: Required<ReconnectionConfig>;
|
|
64
|
+
/** Transport quality metrics */
|
|
65
|
+
interface TransportMetrics {
|
|
66
|
+
/** Total requests made */
|
|
67
|
+
requestCount: number;
|
|
68
|
+
/** Failed requests */
|
|
69
|
+
failedRequests: number;
|
|
70
|
+
/** Average latency in ms */
|
|
71
|
+
avgLatencyMs: number;
|
|
72
|
+
/** Current reconnection attempt (0 if connected) */
|
|
73
|
+
reconnectionAttempt: number;
|
|
74
|
+
/** Total reconnection attempts since start */
|
|
75
|
+
totalReconnections: number;
|
|
76
|
+
/** Missed heartbeats in current connection */
|
|
77
|
+
missedHeartbeats: number;
|
|
78
|
+
/** Last successful request timestamp */
|
|
79
|
+
lastRequestAt?: number;
|
|
80
|
+
/** Connection uptime in ms */
|
|
81
|
+
uptimeMs: number;
|
|
82
|
+
}
|
|
83
|
+
/** Transport event types */
|
|
84
|
+
interface TransportEvents {
|
|
85
|
+
/** Connection state changed */
|
|
86
|
+
stateChange: (state: ConnectionState) => void;
|
|
87
|
+
/** Error occurred */
|
|
88
|
+
error: (error: Error) => void;
|
|
89
|
+
/** Reconnecting with attempt count */
|
|
90
|
+
reconnecting: (attempt: number, maxAttempts: number) => void;
|
|
91
|
+
/** Successfully reconnected */
|
|
92
|
+
reconnected: () => void;
|
|
93
|
+
/** Quality changed */
|
|
94
|
+
qualityChange: (quality: ConnectionQuality) => void;
|
|
95
|
+
/** Heartbeat received */
|
|
96
|
+
heartbeat: (timestamp: number) => void;
|
|
97
|
+
}
|
|
98
|
+
/** Base transport configuration */
|
|
99
|
+
interface TransportConfig {
|
|
100
|
+
/** Base URL for requests */
|
|
101
|
+
baseUrl: string;
|
|
102
|
+
/** Default headers for all requests */
|
|
103
|
+
headers?: Record<string, string>;
|
|
104
|
+
/** Request timeout in ms (default: 30000) */
|
|
105
|
+
timeout?: number;
|
|
106
|
+
/** Heartbeat interval in ms for quality monitoring (default: 30000) */
|
|
107
|
+
heartbeatIntervalMs?: number;
|
|
108
|
+
/** Enable automatic reconnection (default: true) */
|
|
109
|
+
autoReconnect?: boolean;
|
|
110
|
+
/** Reconnection config */
|
|
111
|
+
reconnection?: ReconnectionConfig;
|
|
112
|
+
}
|
|
113
|
+
/** Subscription state */
|
|
114
|
+
type SubscriptionState = "active" | "paused" | "closed";
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region src/transport/connection-manager.d.ts
|
|
117
|
+
interface ConnectionManagerConfig extends ReconnectionConfig {
|
|
118
|
+
onReconnecting?: (attempt: number, maxAttempts: number) => void;
|
|
119
|
+
onReconnected?: () => void;
|
|
120
|
+
onFailed?: (error: Error) => void;
|
|
121
|
+
}
|
|
122
|
+
declare class ConnectionManager {
|
|
123
|
+
private readonly config;
|
|
124
|
+
private attempt;
|
|
125
|
+
private aborted;
|
|
126
|
+
private readonly callbacks;
|
|
127
|
+
constructor(config?: ConnectionManagerConfig);
|
|
128
|
+
/**
|
|
129
|
+
* Calculate delay for current attempt with exponential backoff and jitter.
|
|
130
|
+
*/
|
|
131
|
+
private calculateDelay;
|
|
132
|
+
/**
|
|
133
|
+
* Wait for the calculated delay.
|
|
134
|
+
*/
|
|
135
|
+
private wait;
|
|
136
|
+
/**
|
|
137
|
+
* Check if more reconnection attempts are allowed.
|
|
138
|
+
*/
|
|
139
|
+
canRetry(): boolean;
|
|
140
|
+
/**
|
|
141
|
+
* Get current attempt number.
|
|
142
|
+
*/
|
|
143
|
+
getAttempt(): number;
|
|
144
|
+
/**
|
|
145
|
+
* Reset the connection manager state.
|
|
146
|
+
*/
|
|
147
|
+
reset(): void;
|
|
148
|
+
/**
|
|
149
|
+
* Abort any pending reconnection attempts.
|
|
150
|
+
*/
|
|
151
|
+
abort(): void;
|
|
152
|
+
/**
|
|
153
|
+
* Execute a reconnection attempt with the provided connect function.
|
|
154
|
+
* Returns true if connection succeeded, false if should retry.
|
|
155
|
+
*/
|
|
156
|
+
reconnect(connectFn: () => Promise<void>): Promise<boolean>;
|
|
157
|
+
/**
|
|
158
|
+
* Run reconnection loop until success or max attempts.
|
|
159
|
+
*/
|
|
160
|
+
runReconnectionLoop(connectFn: () => Promise<void>): Promise<boolean>;
|
|
161
|
+
}
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region src/transport/interface.d.ts
|
|
164
|
+
/**
|
|
165
|
+
* SSE Subscription handle for consuming server-sent events.
|
|
166
|
+
* Supports pause/resume, async iteration, and event callbacks.
|
|
167
|
+
*/
|
|
168
|
+
interface Subscription {
|
|
169
|
+
/** Unique identifier for this subscription */
|
|
170
|
+
readonly streamId: string;
|
|
171
|
+
/** Current subscription state */
|
|
172
|
+
readonly state: SubscriptionState;
|
|
173
|
+
/** Pause event processing (events may still be buffered) */
|
|
174
|
+
pause(): void;
|
|
175
|
+
/** Resume event processing */
|
|
176
|
+
resume(): void;
|
|
177
|
+
/** Close the subscription and release resources */
|
|
178
|
+
close(): void;
|
|
179
|
+
/** Register callback for each event */
|
|
180
|
+
onEvent(callback: (event: SSEEvent) => void): () => void;
|
|
181
|
+
/** Register callback for errors */
|
|
182
|
+
onError(callback: (error: Error) => void): () => void;
|
|
183
|
+
/** Register callback for reconnection attempts */
|
|
184
|
+
onReconnect(callback: (lastEventId: string | undefined) => void): () => void;
|
|
185
|
+
/** Async iterator for event consumption */
|
|
186
|
+
[Symbol.asyncIterator](): AsyncIterator<SSEEvent>;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Transport Adapter - core abstraction for network communication.
|
|
190
|
+
*
|
|
191
|
+
* Implementations provide HTTP request/response and SSE streaming
|
|
192
|
+
* with connection management, reconnection, and quality monitoring.
|
|
193
|
+
*/
|
|
194
|
+
interface TransportAdapter {
|
|
195
|
+
/** Current connection state */
|
|
196
|
+
readonly state: ConnectionState;
|
|
197
|
+
/** Connect to the server */
|
|
198
|
+
connect(): Promise<void>;
|
|
199
|
+
/** Disconnect from the server */
|
|
200
|
+
disconnect(): Promise<void>;
|
|
201
|
+
/** Check if currently connected */
|
|
202
|
+
isConnected(): boolean;
|
|
203
|
+
/**
|
|
204
|
+
* Make an HTTP request.
|
|
205
|
+
* Routes through the transport layer for connection management.
|
|
206
|
+
*/
|
|
207
|
+
request<T>(options: RequestOptions): Promise<T>;
|
|
208
|
+
/**
|
|
209
|
+
* Subscribe to an SSE stream.
|
|
210
|
+
* Handles reconnection and Last-Event-ID resumption.
|
|
211
|
+
*/
|
|
212
|
+
subscribe(options: StreamOptions): Subscription;
|
|
213
|
+
/** Register event listener, returns unsubscribe function */
|
|
214
|
+
on<K extends keyof TransportEvents>(event: K, listener: TransportEvents[K]): () => void;
|
|
215
|
+
/** Get current transport metrics */
|
|
216
|
+
getMetrics(): TransportMetrics;
|
|
217
|
+
/** Get current connection quality */
|
|
218
|
+
getQuality(): ConnectionQuality;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Base class for transport adapters with shared functionality.
|
|
222
|
+
* Handles event emission, metrics tracking, and connection state.
|
|
223
|
+
*/
|
|
224
|
+
declare abstract class BaseTransportAdapter implements TransportAdapter {
|
|
225
|
+
protected _state: ConnectionState;
|
|
226
|
+
protected _quality: ConnectionQuality;
|
|
227
|
+
protected readonly config: Required<TransportConfig>;
|
|
228
|
+
protected readonly listeners: Map<keyof TransportEvents, Set<(...args: never[]) => unknown>>;
|
|
229
|
+
protected metrics: TransportMetrics;
|
|
230
|
+
protected connectionStartTime?: number;
|
|
231
|
+
private latencySum;
|
|
232
|
+
constructor(config: TransportConfig);
|
|
233
|
+
get state(): ConnectionState;
|
|
234
|
+
abstract connect(): Promise<void>;
|
|
235
|
+
abstract disconnect(): Promise<void>;
|
|
236
|
+
abstract request<T>(options: RequestOptions): Promise<T>;
|
|
237
|
+
abstract subscribe(options: StreamOptions): Subscription;
|
|
238
|
+
isConnected(): boolean;
|
|
239
|
+
on<K extends keyof TransportEvents>(event: K, listener: TransportEvents[K]): () => void;
|
|
240
|
+
getMetrics(): TransportMetrics;
|
|
241
|
+
getQuality(): ConnectionQuality;
|
|
242
|
+
protected emit<K extends keyof TransportEvents>(event: K, ...args: Parameters<TransportEvents[K]>): void;
|
|
243
|
+
protected setState(state: ConnectionState): void;
|
|
244
|
+
protected setQuality(quality: ConnectionQuality): void;
|
|
245
|
+
protected recordRequest(durationMs: number, failed: boolean): void;
|
|
246
|
+
protected recordReconnection(): void;
|
|
247
|
+
protected recordMissedHeartbeat(): void;
|
|
248
|
+
protected resetHeartbeatCounter(): void;
|
|
249
|
+
private updateQuality;
|
|
250
|
+
protected buildUrl(path: string): string;
|
|
251
|
+
protected buildHeaders(extra?: Record<string, string>): Record<string, string>;
|
|
252
|
+
}
|
|
253
|
+
//#endregion
|
|
254
|
+
//#region src/transport/mock.d.ts
|
|
255
|
+
/** Recorded request for verification */
|
|
256
|
+
interface RecordedRequest {
|
|
257
|
+
method: string;
|
|
258
|
+
path: string;
|
|
259
|
+
body?: unknown;
|
|
260
|
+
headers?: Record<string, string>;
|
|
261
|
+
timestamp: number;
|
|
262
|
+
}
|
|
263
|
+
/** Mock response configuration */
|
|
264
|
+
interface MockResponse<T = unknown> {
|
|
265
|
+
status?: number;
|
|
266
|
+
data?: T;
|
|
267
|
+
error?: Error;
|
|
268
|
+
delay?: number;
|
|
269
|
+
}
|
|
270
|
+
/** Mock stream event */
|
|
271
|
+
interface MockStreamEvent {
|
|
272
|
+
event?: string;
|
|
273
|
+
data: string;
|
|
274
|
+
id?: string;
|
|
275
|
+
delay?: number;
|
|
276
|
+
}
|
|
277
|
+
/** Mock subscription for testing */
|
|
278
|
+
declare class MockSubscription implements Subscription {
|
|
279
|
+
readonly streamId: string;
|
|
280
|
+
private _state;
|
|
281
|
+
private eventCallbacks;
|
|
282
|
+
private errorCallbacks;
|
|
283
|
+
private reconnectCallbacks;
|
|
284
|
+
private events;
|
|
285
|
+
private eventIndex;
|
|
286
|
+
private closed;
|
|
287
|
+
constructor(streamId: string, events?: MockStreamEvent[]);
|
|
288
|
+
get state(): SubscriptionState;
|
|
289
|
+
pause(): void;
|
|
290
|
+
resume(): void;
|
|
291
|
+
close(): void;
|
|
292
|
+
onEvent(callback: (event: SSEEvent) => void): () => void;
|
|
293
|
+
onError(callback: (error: Error) => void): () => void;
|
|
294
|
+
onReconnect(callback: (lastEventId: string | undefined) => void): () => void;
|
|
295
|
+
[Symbol.asyncIterator](): AsyncIterator<SSEEvent>;
|
|
296
|
+
/** Push a new event to the stream (for testing) */
|
|
297
|
+
pushEvent(event: SSEEvent): void;
|
|
298
|
+
/** Simulate an error (for testing) */
|
|
299
|
+
simulateError(error: Error): void;
|
|
300
|
+
/** Simulate reconnection (for testing) */
|
|
301
|
+
simulateReconnect(lastEventId?: string): void;
|
|
302
|
+
private deliverPending;
|
|
303
|
+
/** Start delivering events automatically */
|
|
304
|
+
startDelivery(): void;
|
|
305
|
+
}
|
|
306
|
+
/** Configuration for MockTransportAdapter */
|
|
307
|
+
interface MockTransportConfig extends Partial<TransportConfig> {
|
|
308
|
+
/** Auto-connect on creation (default: true) */
|
|
309
|
+
autoConnect?: boolean;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Mock transport adapter for testing.
|
|
313
|
+
* Provides full control over responses and streams.
|
|
314
|
+
*/
|
|
315
|
+
declare class MockTransportAdapter extends BaseTransportAdapter {
|
|
316
|
+
private readonly responses;
|
|
317
|
+
private readonly streams;
|
|
318
|
+
private readonly subscriptions;
|
|
319
|
+
readonly requests: RecordedRequest[];
|
|
320
|
+
constructor(config?: MockTransportConfig);
|
|
321
|
+
connect(): Promise<void>;
|
|
322
|
+
disconnect(): Promise<void>;
|
|
323
|
+
request<T>(options: RequestOptions): Promise<T>;
|
|
324
|
+
subscribe(options: StreamOptions): Subscription;
|
|
325
|
+
/** Mock a response for a specific path */
|
|
326
|
+
mockResponse<T>(path: string, response: MockResponse<T>): void;
|
|
327
|
+
/** Mock a response for a specific method and path */
|
|
328
|
+
mockMethodResponse<T>(method: string, path: string, response: MockResponse<T>): void;
|
|
329
|
+
/** Mock a stream with events */
|
|
330
|
+
mockStream(path: string, events: MockStreamEvent[]): void;
|
|
331
|
+
/** Get a subscription by stream ID */
|
|
332
|
+
getSubscription(streamId: string): MockSubscription | undefined;
|
|
333
|
+
/** Get all active subscriptions */
|
|
334
|
+
getActiveSubscriptions(): MockSubscription[];
|
|
335
|
+
/** Push an event to all subscriptions for a path */
|
|
336
|
+
pushEventToPath(_path: string, event: SSEEvent): void;
|
|
337
|
+
/** Clear all recorded requests */
|
|
338
|
+
clearRequests(): void;
|
|
339
|
+
/** Clear all mocked responses */
|
|
340
|
+
clearMocks(): void;
|
|
341
|
+
/** Get requests matching a path pattern */
|
|
342
|
+
getRequestsForPath(path: string): RecordedRequest[];
|
|
343
|
+
/** Get the last request made */
|
|
344
|
+
getLastRequest(): RecordedRequest | undefined;
|
|
345
|
+
/** Simulate connection failure */
|
|
346
|
+
simulateDisconnect(): void;
|
|
347
|
+
/** Simulate reconnection */
|
|
348
|
+
simulateReconnect(): void;
|
|
349
|
+
}
|
|
350
|
+
//#endregion
|
|
351
|
+
export { TransportMode as S, StreamOptions as _, RecordedRequest as a, TransportEvents as b, TransportAdapter as c, ConnectionQuality as d, ConnectionState as f, SSEEvent as g, RequestOptions as h, MockTransportConfig as i, ConnectionManager as l, ReconnectionConfig as m, MockStreamEvent as n, BaseTransportAdapter as o, DEFAULT_RECONNECTION_CONFIG as p, MockTransportAdapter as r, Subscription as s, MockResponse as t, ConnectionManagerConfig as u, SubscriptionState as v, TransportMetrics as x, TransportConfig as y };
|
|
352
|
+
//# sourceMappingURL=index-CFA8kgHJ.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-CFA8kgHJ.d.ts","names":[],"sources":["../src/transport/types.ts","../src/transport/connection-manager.ts","../src/transport/interface.ts","../src/transport/mock.ts"],"mappings":"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"}
|