@fencyai/js 0.1.192 → 0.1.194

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.
Files changed (60) hide show
  1. package/lib/api/createAgentTask.d.ts +2 -2
  2. package/lib/api/createAgentTask.d.ts.map +1 -1
  3. package/lib/index.d.ts +13 -1
  4. package/lib/index.d.ts.map +1 -1
  5. package/lib/index.js +12 -1
  6. package/lib/parsing/AgentTaskEventDataSchemas.d.ts +315 -0
  7. package/lib/parsing/AgentTaskEventDataSchemas.d.ts.map +1 -0
  8. package/lib/parsing/AgentTaskEventDataSchemas.js +415 -0
  9. package/lib/stream/StreamCacheManager.d.ts +41 -0
  10. package/lib/stream/StreamCacheManager.d.ts.map +1 -0
  11. package/lib/stream/StreamCacheManager.js +101 -0
  12. package/lib/stream/StreamEventManager.d.ts +52 -0
  13. package/lib/stream/StreamEventManager.d.ts.map +1 -0
  14. package/lib/stream/StreamEventManager.js +271 -0
  15. package/lib/stream/createStreamWorkerCode.d.ts +8 -0
  16. package/lib/stream/createStreamWorkerCode.d.ts.map +1 -0
  17. package/lib/stream/createStreamWorkerCode.js +152 -0
  18. package/lib/stream/toStreamData.d.ts +4 -0
  19. package/lib/stream/toStreamData.d.ts.map +1 -0
  20. package/lib/stream/toStreamData.js +61 -0
  21. package/lib/task/mapCreateAgentTaskParams.d.ts +18 -0
  22. package/lib/task/mapCreateAgentTaskParams.d.ts.map +1 -0
  23. package/lib/task/mapCreateAgentTaskParams.js +84 -0
  24. package/lib/task/progressItems.d.ts +5 -0
  25. package/lib/task/progressItems.d.ts.map +1 -0
  26. package/lib/task/progressItems.js +19 -0
  27. package/lib/task/taskReducer.d.ts +7 -0
  28. package/lib/task/taskReducer.d.ts.map +1 -0
  29. package/lib/task/taskReducer.js +89 -0
  30. package/lib/task/types.d.ts +40 -0
  31. package/lib/task/types.d.ts.map +1 -0
  32. package/lib/task/types.js +1 -0
  33. package/lib/types/AgentTask.d.ts +17 -7
  34. package/lib/types/AgentTask.d.ts.map +1 -1
  35. package/lib/types/AgentTask.js +1 -9
  36. package/lib/types/AgentTaskDto.d.ts +11 -0
  37. package/lib/types/AgentTaskDto.d.ts.map +1 -0
  38. package/lib/types/AgentTaskDto.js +11 -0
  39. package/lib/types/CreateAgentTaskApiResponse.d.ts +11 -0
  40. package/lib/types/CreateAgentTaskApiResponse.d.ts.map +1 -0
  41. package/lib/types/CreateAgentTaskApiResponse.js +1 -0
  42. package/lib/types/CreateAgentTaskParams.d.ts +47 -0
  43. package/lib/types/CreateAgentTaskParams.d.ts.map +1 -0
  44. package/lib/types/CreateAgentTaskParams.js +1 -0
  45. package/lib/types/CreateAgentTaskResponse.d.ts +17 -3
  46. package/lib/types/CreateAgentTaskResponse.d.ts.map +1 -1
  47. package/lib/types/StreamCache.d.ts +7 -0
  48. package/lib/types/StreamCache.d.ts.map +1 -0
  49. package/lib/types/StreamCache.js +1 -0
  50. package/lib/types/StreamData.d.ts +26 -0
  51. package/lib/types/StreamData.d.ts.map +1 -0
  52. package/lib/types/StreamData.js +1 -0
  53. package/lib/types/index.d.ts +5 -0
  54. package/lib/types/index.d.ts.map +1 -1
  55. package/lib/types/index.js +5 -0
  56. package/lib/utils/base64Decode.d.ts +6 -0
  57. package/lib/utils/base64Decode.d.ts.map +1 -0
  58. package/lib/utils/base64Decode.js +12 -0
  59. package/lib/utils/version.js +1 -1
  60. package/package.json +15 -3
@@ -0,0 +1,415 @@
1
+ import { z } from 'zod';
2
+ const messageSchema = z
3
+ .object({
4
+ role: z.enum(['SYSTEM', 'USER', 'ASSISTANT']),
5
+ content: z.string(),
6
+ })
7
+ .passthrough();
8
+ const memorySearchResultItemSchema = z
9
+ .object({
10
+ memoryId: z.string(),
11
+ memoryTitle: z.string(),
12
+ memoryTypeId: z.string(),
13
+ memoryTypeName: z.string(),
14
+ matchingChunkScore: z.number(),
15
+ matchingChunk: z
16
+ .object({
17
+ chunkNumber: z.number(),
18
+ pageNumbers: z.array(z.number()),
19
+ content: z.string(),
20
+ })
21
+ .passthrough(),
22
+ chunks: z.array(z
23
+ .object({
24
+ chunkNumber: z.number(),
25
+ pageNumbers: z.array(z.number()),
26
+ content: z.string(),
27
+ relation: z.enum([
28
+ 'MATCH',
29
+ 'CONTEXT_BEFORE',
30
+ 'CONTEXT_AFTER',
31
+ ]),
32
+ })
33
+ .passthrough()),
34
+ })
35
+ .passthrough();
36
+ const memoryRefSchema = z
37
+ .object({
38
+ memoryId: z.string(),
39
+ memoryTitle: z.string(),
40
+ })
41
+ .passthrough();
42
+ const streamingChatCompletionTextSchema = z
43
+ .object({
44
+ taskType: z.literal('StreamingChatCompletion'),
45
+ eventType: z.literal('Text'),
46
+ text: z.string(),
47
+ })
48
+ .passthrough();
49
+ const streamingChatCompletionCompletedSchema = z
50
+ .object({
51
+ taskType: z.literal('StreamingChatCompletion'),
52
+ eventType: z.literal('Completed'),
53
+ response: z
54
+ .object({
55
+ textResponse: z.string(),
56
+ messages: z.array(messageSchema),
57
+ })
58
+ .passthrough(),
59
+ })
60
+ .passthrough();
61
+ const streamingChatCompletionErrorSchema = z
62
+ .object({
63
+ taskType: z.literal('StreamingChatCompletion'),
64
+ eventType: z.literal('Error'),
65
+ message: z.string(),
66
+ })
67
+ .passthrough();
68
+ const structuredChatCompletionCompletedSchema = z
69
+ .object({
70
+ taskType: z.literal('StructuredChatCompletion'),
71
+ eventType: z.literal('Completed'),
72
+ response: z
73
+ .object({
74
+ jsonResponse: z.string(),
75
+ messages: z.array(messageSchema),
76
+ })
77
+ .passthrough(),
78
+ })
79
+ .passthrough();
80
+ const structuredChatCompletionErrorSchema = z
81
+ .object({
82
+ taskType: z.literal('StructuredChatCompletion'),
83
+ eventType: z.literal('Error'),
84
+ message: z.string(),
85
+ })
86
+ .passthrough();
87
+ const memoryChatTextSchema = z
88
+ .object({
89
+ taskType: z.literal('MemoryChat'),
90
+ eventType: z.literal('Text'),
91
+ text: z.string(),
92
+ })
93
+ .passthrough();
94
+ const memoryChatThinkingSchema = z
95
+ .object({
96
+ taskType: z.literal('MemoryChat'),
97
+ eventType: z.literal('Thinking'),
98
+ })
99
+ .passthrough();
100
+ const memoryChatSearchSchema = z
101
+ .object({
102
+ taskType: z.literal('MemoryChat'),
103
+ eventType: z.literal('Search'),
104
+ queryDescription: z.string(),
105
+ memories: z.array(memoryRefSchema).optional(),
106
+ })
107
+ .passthrough();
108
+ const memoryChatFindMemoriesSchema = z
109
+ .object({
110
+ taskType: z.literal('MemoryChat'),
111
+ eventType: z.literal('FindMemories'),
112
+ titles: z.array(z.string()),
113
+ })
114
+ .passthrough();
115
+ const memoryChatFindMemoriesResultSchema = z
116
+ .object({
117
+ taskType: z.literal('MemoryChat'),
118
+ eventType: z.literal('FindMemoriesResult'),
119
+ memories: z.array(memoryRefSchema),
120
+ })
121
+ .passthrough();
122
+ const scrapeWebsitesResultStatusSchema = z.enum([
123
+ 'downloading',
124
+ 'downloaded',
125
+ 'analyzing',
126
+ 'summarizing',
127
+ ]);
128
+ const memoryChatScrapeWebsitesSchema = z
129
+ .object({
130
+ taskType: z.literal('MemoryChat'),
131
+ eventType: z.literal('ScrapeWebsites'),
132
+ input: z
133
+ .object({
134
+ query: z.string(),
135
+ urls: z.array(z.string()),
136
+ })
137
+ .passthrough(),
138
+ results: z
139
+ .array(z
140
+ .object({
141
+ url: z.string(),
142
+ status: scrapeWebsitesResultStatusSchema.optional(),
143
+ summary: z.string().optional(),
144
+ error: z.string().optional(),
145
+ })
146
+ .passthrough())
147
+ .optional(),
148
+ })
149
+ .passthrough();
150
+ const memoryChatGoogleSearchSchema = z
151
+ .object({
152
+ taskType: z.literal('MemoryChat'),
153
+ eventType: z.literal('GoogleSearch'),
154
+ input: z
155
+ .object({
156
+ query: z.string(),
157
+ countryCode: z.string().optional(),
158
+ })
159
+ .passthrough(),
160
+ results: z
161
+ .array(z
162
+ .object({
163
+ rank: z.number(),
164
+ title: z.string(),
165
+ link: z.string(),
166
+ description: z.string(),
167
+ })
168
+ .passthrough())
169
+ .optional(),
170
+ })
171
+ .passthrough();
172
+ const memoryChatSearchMemoryChunksSchema = z
173
+ .object({
174
+ taskType: z.literal('MemoryChat'),
175
+ eventType: z.literal('SearchMemoryChunks'),
176
+ input: z
177
+ .object({
178
+ queryDescription: z.string(),
179
+ memories: z.array(memoryRefSchema).optional(),
180
+ })
181
+ .passthrough(),
182
+ items: z.array(memorySearchResultItemSchema).optional(),
183
+ })
184
+ .passthrough();
185
+ const memoryChatFindSourcesSchema = z
186
+ .object({
187
+ taskType: z.literal('MemoryChat'),
188
+ eventType: z.literal('FindSources'),
189
+ })
190
+ .passthrough();
191
+ const memoryChatExploreMemoriesSchema = z
192
+ .object({
193
+ taskType: z.literal('MemoryChat'),
194
+ eventType: z.literal('ExploreMemories'),
195
+ memories: z.array(z
196
+ .object({
197
+ memoryId: z.string(),
198
+ memoryTitle: z.string(),
199
+ result: z.string().optional(),
200
+ error: z.string().optional(),
201
+ })
202
+ .passthrough()),
203
+ })
204
+ .passthrough();
205
+ const memoryChatChunkResultsSchema = z
206
+ .object({
207
+ taskType: z.literal('MemoryChat'),
208
+ eventType: z.literal('ChunkResults'),
209
+ items: z.array(memorySearchResultItemSchema),
210
+ })
211
+ .passthrough();
212
+ const memoryChatSourcesResultSchema = z
213
+ .object({
214
+ taskType: z.literal('MemoryChat'),
215
+ eventType: z.literal('SourcesResult'),
216
+ sources: z.array(z
217
+ .object({
218
+ memoryId: z.string(),
219
+ memoryTitle: z.string(),
220
+ memoryTypeId: z.string(),
221
+ memoryTypeName: z.string(),
222
+ pageNumbers: z.array(z.number()),
223
+ })
224
+ .passthrough()),
225
+ })
226
+ .passthrough();
227
+ const memoryChatCompletedSchema = z
228
+ .object({
229
+ taskType: z.literal('MemoryChat'),
230
+ eventType: z.literal('Completed'),
231
+ response: z
232
+ .object({
233
+ textResponse: z.string(),
234
+ sources: z.array(z
235
+ .object({
236
+ memoryId: z.string(),
237
+ memoryTitle: z.string(),
238
+ memoryTypeId: z.string(),
239
+ memoryTypeName: z.string(),
240
+ pageNumbers: z.array(z.number()),
241
+ })
242
+ .passthrough()),
243
+ })
244
+ .passthrough(),
245
+ })
246
+ .passthrough();
247
+ const memoryChatGenerateReportSetupSchema = z
248
+ .object({
249
+ taskType: z.literal('MemoryChat'),
250
+ eventType: z.literal('GenerateReportSetup'),
251
+ userRequest: z.string(),
252
+ })
253
+ .passthrough();
254
+ const memoryChatGenerateReportExportingSchema = z
255
+ .object({
256
+ taskType: z.literal('MemoryChat'),
257
+ eventType: z.literal('GenerateReportExporting'),
258
+ fileCount: z.number(),
259
+ })
260
+ .passthrough();
261
+ const memoryChatGenerateReportRunCodeSchema = z
262
+ .object({
263
+ taskType: z.literal('MemoryChat'),
264
+ eventType: z.literal('GenerateReportRunCode'),
265
+ title: z.string(),
266
+ })
267
+ .passthrough();
268
+ const memoryChatGenerateReportRunCommandSchema = z
269
+ .object({
270
+ taskType: z.literal('MemoryChat'),
271
+ eventType: z.literal('GenerateReportRunCommand'),
272
+ title: z.string(),
273
+ })
274
+ .passthrough();
275
+ const memoryChatGenerateReportAssemblingSchema = z
276
+ .object({
277
+ taskType: z.literal('MemoryChat'),
278
+ eventType: z.literal('GenerateReportAssembling'),
279
+ reportTitle: z.string(),
280
+ })
281
+ .passthrough();
282
+ const memoryChatGenerateReportCompletedSchema = z
283
+ .object({
284
+ taskType: z.literal('MemoryChat'),
285
+ eventType: z.literal('GenerateReportCompleted'),
286
+ reportTitle: z.string(),
287
+ })
288
+ .passthrough();
289
+ const memoryChatErrorSchema = z
290
+ .object({
291
+ taskType: z.literal('MemoryChat'),
292
+ eventType: z.literal('Error'),
293
+ message: z.string(),
294
+ })
295
+ .passthrough();
296
+ const memorySearchGeneratingQueriesSchema = z
297
+ .object({
298
+ taskType: z.literal('MemorySearch'),
299
+ eventType: z.literal('GeneratingQueries'),
300
+ memoryTypes: z.array(z
301
+ .object({
302
+ memoryTypeId: z.string(),
303
+ memoryTypeName: z.string(),
304
+ reasoning: z.string().optional(),
305
+ reasoningCompleted: z.boolean().optional(),
306
+ queries: z
307
+ .array(z.object({ query: z.string() }).passthrough())
308
+ .optional(),
309
+ })
310
+ .passthrough()),
311
+ })
312
+ .passthrough();
313
+ const memorySearchExploreQueriesSchema = z
314
+ .object({
315
+ taskType: z.literal('MemorySearch'),
316
+ eventType: z.literal('ExploreQueries'),
317
+ queries: z.array(z
318
+ .object({
319
+ query: z.string(),
320
+ memoryTypeId: z.string(),
321
+ memoryTypeName: z.string(),
322
+ result: z
323
+ .object({
324
+ numberOfChunks: z.number(),
325
+ highestChunkScore: z.number(),
326
+ items: z.array(memorySearchResultItemSchema),
327
+ })
328
+ .passthrough()
329
+ .optional(),
330
+ error: z.string().optional(),
331
+ })
332
+ .passthrough()),
333
+ })
334
+ .passthrough();
335
+ const memorySearchSearchMemoryTypesSchema = z
336
+ .object({
337
+ taskType: z.literal('MemorySearch'),
338
+ eventType: z.literal('SearchMemoryTypes'),
339
+ memoryTypes: z.array(z
340
+ .object({
341
+ memoryTypeId: z.string(),
342
+ memoryTypeName: z.string(),
343
+ result: z
344
+ .object({
345
+ numberOfChunks: z.number(),
346
+ highestChunkScore: z.number(),
347
+ })
348
+ .passthrough()
349
+ .optional(),
350
+ error: z.string().optional(),
351
+ })
352
+ .passthrough()),
353
+ })
354
+ .passthrough();
355
+ const memorySearchCompletedSchema = z
356
+ .object({
357
+ taskType: z.literal('MemorySearch'),
358
+ eventType: z.literal('Completed'),
359
+ response: z
360
+ .object({
361
+ query: z.string(),
362
+ items: z.array(memorySearchResultItemSchema),
363
+ })
364
+ .passthrough(),
365
+ })
366
+ .passthrough();
367
+ const memorySearchErrorSchema = z
368
+ .object({
369
+ taskType: z.literal('MemorySearch'),
370
+ eventType: z.literal('Error'),
371
+ message: z.string(),
372
+ })
373
+ .passthrough();
374
+ /** Zod schema matching {@link AgentTaskEventData}; objects use `.passthrough()` for forward-compatible extra fields. @public */
375
+ export const AgentTaskEventDataSchema = z.union([
376
+ streamingChatCompletionTextSchema,
377
+ streamingChatCompletionCompletedSchema,
378
+ streamingChatCompletionErrorSchema,
379
+ structuredChatCompletionCompletedSchema,
380
+ structuredChatCompletionErrorSchema,
381
+ memoryChatTextSchema,
382
+ memoryChatThinkingSchema,
383
+ memoryChatSearchSchema,
384
+ memoryChatFindMemoriesSchema,
385
+ memoryChatFindMemoriesResultSchema,
386
+ memoryChatScrapeWebsitesSchema,
387
+ memoryChatGoogleSearchSchema,
388
+ memoryChatSearchMemoryChunksSchema,
389
+ memoryChatFindSourcesSchema,
390
+ memoryChatExploreMemoriesSchema,
391
+ memoryChatChunkResultsSchema,
392
+ memoryChatSourcesResultSchema,
393
+ memoryChatGenerateReportSetupSchema,
394
+ memoryChatGenerateReportExportingSchema,
395
+ memoryChatGenerateReportRunCodeSchema,
396
+ memoryChatGenerateReportRunCommandSchema,
397
+ memoryChatGenerateReportAssemblingSchema,
398
+ memoryChatGenerateReportCompletedSchema,
399
+ memoryChatCompletedSchema,
400
+ memoryChatErrorSchema,
401
+ memorySearchGeneratingQueriesSchema,
402
+ memorySearchExploreQueriesSchema,
403
+ memorySearchSearchMemoryTypesSchema,
404
+ memorySearchCompletedSchema,
405
+ memorySearchErrorSchema,
406
+ ]);
407
+ /** @public */
408
+ export function parseAgentTaskEventData(raw) {
409
+ const result = AgentTaskEventDataSchema.safeParse(raw);
410
+ if (!result.success) {
411
+ console.warn('[fency] Dropping unrecognized or malformed agent task event:', result.error.format(), raw);
412
+ return null;
413
+ }
414
+ return result.data;
415
+ }
@@ -0,0 +1,41 @@
1
+ import type { FencyInstance } from '../types/FencyInstance';
2
+ import type { Stream } from '../types/Stream';
3
+ import type { StreamCache } from '../types/StreamCache';
4
+ /** Stream lifecycle: 8 minutes — below backend SSE timeout (~10m). @public */
5
+ export declare const STREAM_MAX_LIFETIME = 480000;
6
+ /** Default reuse window for new agent tasks: 5 minutes. @public */
7
+ export declare const DEFAULT_STREAM_REUSE_MAX_AGE = 300000;
8
+ /** @public */
9
+ export interface StreamCacheManagerOptions {
10
+ maxLifetime?: number;
11
+ reuseMaxAge?: number;
12
+ }
13
+ /** @public */
14
+ export type StreamCacheChangeListener = (streams: StreamCache[]) => void;
15
+ /**
16
+ * Manages stream cache lifecycle: reuse, expiration, and creation with locking.
17
+ * @public
18
+ */
19
+ export declare class StreamCacheManager {
20
+ private fency;
21
+ private fetchClientToken;
22
+ private activeStreams;
23
+ private streamLock;
24
+ private listeners;
25
+ private readonly maxLifetime;
26
+ private readonly reuseMaxAge;
27
+ private cleanupInterval;
28
+ constructor(fency: FencyInstance, fetchClientToken: () => Promise<{
29
+ clientToken: string;
30
+ }>, options?: StreamCacheManagerOptions);
31
+ onChange(listener: StreamCacheChangeListener): () => void;
32
+ getActiveStreams(): StreamCache[];
33
+ getLatestStream(): StreamCache | null;
34
+ cleanupExpired(): StreamCache[];
35
+ startPeriodicCleanup(intervalMs?: number): void;
36
+ stopPeriodicCleanup(): void;
37
+ getOrCreateStream(maxAge?: number): Promise<Stream>;
38
+ destroy(): void;
39
+ private setStreams;
40
+ }
41
+ //# sourceMappingURL=StreamCacheManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StreamCacheManager.d.ts","sourceRoot":"","sources":["../../src/stream/StreamCacheManager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAEvD,8EAA8E;AAC9E,eAAO,MAAM,mBAAmB,SAAU,CAAA;AAE1C,mEAAmE;AACnE,eAAO,MAAM,4BAA4B,SAAU,CAAA;AAEnD,cAAc;AACd,MAAM,WAAW,yBAAyB;IACtC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,cAAc;AACd,MAAM,MAAM,yBAAyB,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,IAAI,CAAA;AAUxE;;;GAGG;AACH,qBAAa,kBAAkB;IASvB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,gBAAgB;IAT5B,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,SAAS,CAAuC;IACxD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,OAAO,CAAC,eAAe,CAA8C;gBAGzD,KAAK,EAAE,aAAa,EACpB,gBAAgB,EAAE,MAAM,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,EAChE,OAAO,CAAC,EAAE,yBAAyB;IAMvC,QAAQ,CAAC,QAAQ,EAAE,yBAAyB,GAAG,MAAM,IAAI;IAQzD,gBAAgB,IAAI,WAAW,EAAE;IAIjC,eAAe,IAAI,WAAW,GAAG,IAAI;IAKrC,cAAc,IAAI,WAAW,EAAE;IAS/B,oBAAoB,CAAC,UAAU,SAAS,GAAG,IAAI;IAO/C,mBAAmB,IAAI,IAAI;IAOrB,iBAAiB,CACnB,MAAM,GAAE,MAAyB,GAClC,OAAO,CAAC,MAAM,CAAC;IA8ClB,OAAO,IAAI,IAAI;IAOf,OAAO,CAAC,UAAU;CAIrB"}
@@ -0,0 +1,101 @@
1
+ import { createStream as createStreamApi } from '../api/createStream';
2
+ /** Stream lifecycle: 8 minutes — below backend SSE timeout (~10m). @public */
3
+ export const STREAM_MAX_LIFETIME = 480000;
4
+ /** Default reuse window for new agent tasks: 5 minutes. @public */
5
+ export const DEFAULT_STREAM_REUSE_MAX_AGE = 300000;
6
+ function cleanupOldStreams(streams, maxLifetime) {
7
+ const now = Date.now();
8
+ return streams.filter((cache) => now - cache.createdAt < maxLifetime);
9
+ }
10
+ /**
11
+ * Manages stream cache lifecycle: reuse, expiration, and creation with locking.
12
+ * @public
13
+ */
14
+ export class StreamCacheManager {
15
+ constructor(fency, fetchClientToken, options) {
16
+ this.fency = fency;
17
+ this.fetchClientToken = fetchClientToken;
18
+ this.activeStreams = [];
19
+ this.streamLock = null;
20
+ this.listeners = new Set();
21
+ this.cleanupInterval = null;
22
+ this.maxLifetime = options?.maxLifetime ?? STREAM_MAX_LIFETIME;
23
+ this.reuseMaxAge = options?.reuseMaxAge ?? DEFAULT_STREAM_REUSE_MAX_AGE;
24
+ }
25
+ onChange(listener) {
26
+ this.listeners.add(listener);
27
+ listener(this.activeStreams);
28
+ return () => {
29
+ this.listeners.delete(listener);
30
+ };
31
+ }
32
+ getActiveStreams() {
33
+ return [...this.activeStreams];
34
+ }
35
+ getLatestStream() {
36
+ if (this.activeStreams.length === 0)
37
+ return null;
38
+ return this.activeStreams[this.activeStreams.length - 1];
39
+ }
40
+ cleanupExpired() {
41
+ const before = this.activeStreams;
42
+ const cleaned = cleanupOldStreams(before, this.maxLifetime);
43
+ if (cleaned.length !== before.length) {
44
+ this.setStreams(cleaned);
45
+ }
46
+ return before.filter((s) => !cleaned.includes(s));
47
+ }
48
+ startPeriodicCleanup(intervalMs = 60000) {
49
+ this.stopPeriodicCleanup();
50
+ this.cleanupInterval = setInterval(() => {
51
+ this.cleanupExpired();
52
+ }, intervalMs);
53
+ }
54
+ stopPeriodicCleanup() {
55
+ if (this.cleanupInterval) {
56
+ clearInterval(this.cleanupInterval);
57
+ this.cleanupInterval = null;
58
+ }
59
+ }
60
+ async getOrCreateStream(maxAge = this.reuseMaxAge) {
61
+ if (this.streamLock) {
62
+ return this.streamLock;
63
+ }
64
+ const now = Date.now();
65
+ const latestStream = this.getLatestStream();
66
+ if (latestStream && now - latestStream.createdAt < maxAge) {
67
+ return latestStream.stream;
68
+ }
69
+ const streamPromise = (async () => {
70
+ const tokens = await this.fetchClientToken();
71
+ const response = await createStreamApi({
72
+ pk: this.fency.publishableKey,
73
+ baseUrl: this.fency.baseUrl,
74
+ clientToken: tokens?.clientToken ?? '',
75
+ });
76
+ if (response.type === 'success') {
77
+ const newStreamCache = {
78
+ stream: response.stream,
79
+ createdAt: Date.now(),
80
+ };
81
+ this.setStreams(cleanupOldStreams([...this.activeStreams, newStreamCache], this.maxLifetime));
82
+ this.streamLock = null;
83
+ return response.stream;
84
+ }
85
+ this.streamLock = null;
86
+ throw new Error('Failed to create stream');
87
+ })();
88
+ this.streamLock = streamPromise;
89
+ return streamPromise;
90
+ }
91
+ destroy() {
92
+ this.stopPeriodicCleanup();
93
+ this.listeners.clear();
94
+ this.activeStreams = [];
95
+ this.streamLock = null;
96
+ }
97
+ setStreams(streams) {
98
+ this.activeStreams = streams;
99
+ this.listeners.forEach((listener) => listener(streams));
100
+ }
101
+ }
@@ -0,0 +1,52 @@
1
+ import type { FencyInstance } from '../types/FencyInstance';
2
+ import { StreamCache } from '../types/StreamCache';
3
+ type EventCallback = (data: string, streamId: string) => void;
4
+ type ErrorCallback = (streamId: string, errorMessage?: string) => void;
5
+ /** @public */
6
+ export interface Subscription {
7
+ onMessage: EventCallback;
8
+ onError: ErrorCallback;
9
+ }
10
+ /**
11
+ * Centralized manager for EventSource connections to streams.
12
+ * Ensures only one connection per stream regardless of how many hooks subscribe.
13
+ *
14
+ * When a Web Worker is available, the main thread performs fetch (correct CORS origin)
15
+ * and transfers the response body to the worker for parsing, so the read loop is not
16
+ * stalled by background tab throttling. Otherwise falls back to fetchEventSource on
17
+ * the main thread with openWhenHidden so the connection is not aborted on tab switch.
18
+ * @public
19
+ */
20
+ export declare class StreamEventManager {
21
+ private activeConnections;
22
+ private subscribers;
23
+ private fency;
24
+ private worker;
25
+ private workerBlobUrl;
26
+ private workerSupported;
27
+ constructor(fency: FencyInstance);
28
+ private tryInitWorker;
29
+ private handleWorkerMessage;
30
+ /**
31
+ * Called by FencyProvider when activeStreams changes.
32
+ * Creates new connections and removes old ones.
33
+ */
34
+ updateStreams(streams: StreamCache[]): void;
35
+ private connectStream;
36
+ private connectStreamInWorker;
37
+ private startWorkerStream;
38
+ private connectStreamOnMainThread;
39
+ /**
40
+ * Subscribe to events from all active streams.
41
+ * Returns an unsubscribe function.
42
+ */
43
+ subscribe(subscriberId: string, callbacks: Subscription): () => void;
44
+ private broadcast;
45
+ private broadcastError;
46
+ /**
47
+ * Cleanup all connections and subscriptions
48
+ */
49
+ cleanup(): void;
50
+ }
51
+ export {};
52
+ //# sourceMappingURL=StreamEventManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StreamEventManager.d.ts","sourceRoot":"","sources":["../../src/stream/StreamEventManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAclD,KAAK,aAAa,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;AAC7D,KAAK,aAAa,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;AAEtE,cAAc;AACd,MAAM,WAAW,YAAY;IACzB,SAAS,EAAE,aAAa,CAAA;IACxB,OAAO,EAAE,aAAa,CAAA;CACzB;AAeD;;;;;;;;;GASG;AACH,qBAAa,kBAAkB;IAC3B,OAAO,CAAC,iBAAiB,CAA2C;IACpE,OAAO,CAAC,WAAW,CAAuC;IAC1D,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,eAAe,CAAQ;gBAEnB,KAAK,EAAE,aAAa;IAKhC,OAAO,CAAC,aAAa;IAkCrB,OAAO,CAAC,mBAAmB;IAuB3B;;;OAGG;IACH,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,IAAI;IAiB3C,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,qBAAqB;YAqBf,iBAAiB;IAoE/B,OAAO,CAAC,yBAAyB;IAgDjC;;;OAGG;IACH,SAAS,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,GAAG,MAAM,IAAI;IAQpE,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,cAAc;IAMtB;;OAEG;IACH,OAAO,IAAI,IAAI;CAqBlB"}