@generacy-ai/orchestrator 0.0.0-preview-20260304013206
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 +191 -0
- package/dist/auth/api-key.d.ts +63 -0
- package/dist/auth/api-key.d.ts.map +1 -0
- package/dist/auth/api-key.js +102 -0
- package/dist/auth/api-key.js.map +1 -0
- package/dist/auth/github-oauth.d.ts +29 -0
- package/dist/auth/github-oauth.d.ts.map +1 -0
- package/dist/auth/github-oauth.js +136 -0
- package/dist/auth/github-oauth.js.map +1 -0
- package/dist/auth/index.d.ts +5 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +9 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/jwt.d.ts +34 -0
- package/dist/auth/jwt.d.ts.map +1 -0
- package/dist/auth/jwt.js +74 -0
- package/dist/auth/jwt.js.map +1 -0
- package/dist/auth/middleware.d.ts +43 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +101 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +5 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +21 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +295 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +733 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +174 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +30 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/error-handler.js +173 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/index.d.ts +4 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +4 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/rate-limit.d.ts +32 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -0
- package/dist/middleware/rate-limit.js +92 -0
- package/dist/middleware/rate-limit.js.map +1 -0
- package/dist/middleware/request-logger.d.ts +31 -0
- package/dist/middleware/request-logger.d.ts.map +1 -0
- package/dist/middleware/request-logger.js +89 -0
- package/dist/middleware/request-logger.js.map +1 -0
- package/dist/routes/agents.d.ts +7 -0
- package/dist/routes/agents.d.ts.map +1 -0
- package/dist/routes/agents.js +78 -0
- package/dist/routes/agents.js.map +1 -0
- package/dist/routes/dispatch.d.ts +8 -0
- package/dist/routes/dispatch.d.ts.map +1 -0
- package/dist/routes/dispatch.js +46 -0
- package/dist/routes/dispatch.js.map +1 -0
- package/dist/routes/events.d.ts +14 -0
- package/dist/routes/events.d.ts.map +1 -0
- package/dist/routes/events.js +240 -0
- package/dist/routes/events.js.map +1 -0
- package/dist/routes/health.d.ts +14 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +132 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/index.d.ts +36 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +34 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/integrations.d.ts +34 -0
- package/dist/routes/integrations.d.ts.map +1 -0
- package/dist/routes/integrations.js +81 -0
- package/dist/routes/integrations.js.map +1 -0
- package/dist/routes/metrics.d.ts +31 -0
- package/dist/routes/metrics.d.ts.map +1 -0
- package/dist/routes/metrics.js +157 -0
- package/dist/routes/metrics.js.map +1 -0
- package/dist/routes/pr-webhooks.d.ts +15 -0
- package/dist/routes/pr-webhooks.d.ts.map +1 -0
- package/dist/routes/pr-webhooks.js +114 -0
- package/dist/routes/pr-webhooks.js.map +1 -0
- package/dist/routes/queue.d.ts +7 -0
- package/dist/routes/queue.d.ts.map +1 -0
- package/dist/routes/queue.js +94 -0
- package/dist/routes/queue.js.map +1 -0
- package/dist/routes/webhooks.d.ts +15 -0
- package/dist/routes/webhooks.d.ts.map +1 -0
- package/dist/routes/webhooks.js +117 -0
- package/dist/routes/webhooks.js.map +1 -0
- package/dist/routes/workflows.d.ts +7 -0
- package/dist/routes/workflows.d.ts.map +1 -0
- package/dist/routes/workflows.js +138 -0
- package/dist/routes/workflows.js.map +1 -0
- package/dist/server.d.ts +35 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +264 -0
- package/dist/server.js.map +1 -0
- package/dist/services/agent-registry.d.ts +89 -0
- package/dist/services/agent-registry.d.ts.map +1 -0
- package/dist/services/agent-registry.js +173 -0
- package/dist/services/agent-registry.js.map +1 -0
- package/dist/services/epic-completion-monitor-service.d.ts +69 -0
- package/dist/services/epic-completion-monitor-service.d.ts.map +1 -0
- package/dist/services/epic-completion-monitor-service.js +200 -0
- package/dist/services/epic-completion-monitor-service.js.map +1 -0
- package/dist/services/identity.d.ts +41 -0
- package/dist/services/identity.d.ts.map +1 -0
- package/dist/services/identity.js +91 -0
- package/dist/services/identity.js.map +1 -0
- package/dist/services/index.d.ts +13 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +13 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/label-monitor-service.d.ts +95 -0
- package/dist/services/label-monitor-service.d.ts.map +1 -0
- package/dist/services/label-monitor-service.js +414 -0
- package/dist/services/label-monitor-service.js.map +1 -0
- package/dist/services/label-sync-service.d.ts +76 -0
- package/dist/services/label-sync-service.d.ts.map +1 -0
- package/dist/services/label-sync-service.js +108 -0
- package/dist/services/label-sync-service.js.map +1 -0
- package/dist/services/phase-tracker-service.d.ts +32 -0
- package/dist/services/phase-tracker-service.d.ts.map +1 -0
- package/dist/services/phase-tracker-service.js +82 -0
- package/dist/services/phase-tracker-service.js.map +1 -0
- package/dist/services/pr-feedback-monitor-service.d.ts +86 -0
- package/dist/services/pr-feedback-monitor-service.d.ts.map +1 -0
- package/dist/services/pr-feedback-monitor-service.js +423 -0
- package/dist/services/pr-feedback-monitor-service.js.map +1 -0
- package/dist/services/queue-service.d.ts +62 -0
- package/dist/services/queue-service.d.ts.map +1 -0
- package/dist/services/queue-service.js +147 -0
- package/dist/services/queue-service.js.map +1 -0
- package/dist/services/redis-queue-adapter.d.ts +35 -0
- package/dist/services/redis-queue-adapter.d.ts.map +1 -0
- package/dist/services/redis-queue-adapter.js +218 -0
- package/dist/services/redis-queue-adapter.js.map +1 -0
- package/dist/services/smee-receiver.d.ts +87 -0
- package/dist/services/smee-receiver.d.ts.map +1 -0
- package/dist/services/smee-receiver.js +225 -0
- package/dist/services/smee-receiver.js.map +1 -0
- package/dist/services/webhook-setup-service.d.ts +253 -0
- package/dist/services/webhook-setup-service.d.ts.map +1 -0
- package/dist/services/webhook-setup-service.js +369 -0
- package/dist/services/webhook-setup-service.js.map +1 -0
- package/dist/services/worker-dispatcher.d.ts +57 -0
- package/dist/services/worker-dispatcher.d.ts.map +1 -0
- package/dist/services/worker-dispatcher.js +211 -0
- package/dist/services/worker-dispatcher.js.map +1 -0
- package/dist/services/workflow-service.d.ts +65 -0
- package/dist/services/workflow-service.d.ts.map +1 -0
- package/dist/services/workflow-service.js +164 -0
- package/dist/services/workflow-service.js.map +1 -0
- package/dist/sse/events.d.ts +50 -0
- package/dist/sse/events.d.ts.map +1 -0
- package/dist/sse/events.js +152 -0
- package/dist/sse/events.js.map +1 -0
- package/dist/sse/index.d.ts +4 -0
- package/dist/sse/index.d.ts.map +1 -0
- package/dist/sse/index.js +7 -0
- package/dist/sse/index.js.map +1 -0
- package/dist/sse/stream.d.ts +109 -0
- package/dist/sse/stream.d.ts.map +1 -0
- package/dist/sse/stream.js +239 -0
- package/dist/sse/stream.js.map +1 -0
- package/dist/sse/subscriptions.d.ts +91 -0
- package/dist/sse/subscriptions.d.ts.map +1 -0
- package/dist/sse/subscriptions.js +299 -0
- package/dist/sse/subscriptions.js.map +1 -0
- package/dist/types/api.d.ts +651 -0
- package/dist/types/api.d.ts.map +1 -0
- package/dist/types/api.js +169 -0
- package/dist/types/api.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +27 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/monitor.d.ts +243 -0
- package/dist/types/monitor.d.ts.map +1 -0
- package/dist/types/monitor.js +2 -0
- package/dist/types/monitor.js.map +1 -0
- package/dist/types/problem-details.d.ts +63 -0
- package/dist/types/problem-details.d.ts.map +1 -0
- package/dist/types/problem-details.js +37 -0
- package/dist/types/problem-details.js.map +1 -0
- package/dist/types/sse.d.ts +224 -0
- package/dist/types/sse.d.ts.map +1 -0
- package/dist/types/sse.js +103 -0
- package/dist/types/sse.js.map +1 -0
- package/dist/types/webhook.d.ts +59 -0
- package/dist/types/webhook.d.ts.map +1 -0
- package/dist/types/webhook.js +2 -0
- package/dist/types/webhook.js.map +1 -0
- package/dist/utils/correlation.d.ts +30 -0
- package/dist/utils/correlation.d.ts.map +1 -0
- package/dist/utils/correlation.js +34 -0
- package/dist/utils/correlation.js.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/shutdown.d.ts +28 -0
- package/dist/utils/shutdown.d.ts.map +1 -0
- package/dist/utils/shutdown.js +86 -0
- package/dist/utils/shutdown.js.map +1 -0
- package/dist/worker/claude-cli-worker.d.ts +61 -0
- package/dist/worker/claude-cli-worker.d.ts.map +1 -0
- package/dist/worker/claude-cli-worker.js +330 -0
- package/dist/worker/claude-cli-worker.js.map +1 -0
- package/dist/worker/cli-spawner.d.ts +42 -0
- package/dist/worker/cli-spawner.d.ts.map +1 -0
- package/dist/worker/cli-spawner.js +183 -0
- package/dist/worker/cli-spawner.js.map +1 -0
- package/dist/worker/config.d.ts +76 -0
- package/dist/worker/config.d.ts.map +1 -0
- package/dist/worker/config.js +39 -0
- package/dist/worker/config.js.map +1 -0
- package/dist/worker/epic-post-tasks.d.ts +73 -0
- package/dist/worker/epic-post-tasks.d.ts.map +1 -0
- package/dist/worker/epic-post-tasks.js +266 -0
- package/dist/worker/epic-post-tasks.js.map +1 -0
- package/dist/worker/gate-checker.d.ts +22 -0
- package/dist/worker/gate-checker.d.ts.map +1 -0
- package/dist/worker/gate-checker.js +41 -0
- package/dist/worker/gate-checker.js.map +1 -0
- package/dist/worker/index.d.ts +13 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +19 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/label-manager.d.ts +89 -0
- package/dist/worker/label-manager.d.ts.map +1 -0
- package/dist/worker/label-manager.js +200 -0
- package/dist/worker/label-manager.js.map +1 -0
- package/dist/worker/output-capture.d.ts +58 -0
- package/dist/worker/output-capture.d.ts.map +1 -0
- package/dist/worker/output-capture.js +153 -0
- package/dist/worker/output-capture.js.map +1 -0
- package/dist/worker/phase-loop.d.ts +64 -0
- package/dist/worker/phase-loop.d.ts.map +1 -0
- package/dist/worker/phase-loop.js +185 -0
- package/dist/worker/phase-loop.js.map +1 -0
- package/dist/worker/phase-resolver.d.ts +62 -0
- package/dist/worker/phase-resolver.d.ts.map +1 -0
- package/dist/worker/phase-resolver.js +144 -0
- package/dist/worker/phase-resolver.js.map +1 -0
- package/dist/worker/pr-feedback-handler.d.ts +105 -0
- package/dist/worker/pr-feedback-handler.d.ts.map +1 -0
- package/dist/worker/pr-feedback-handler.js +391 -0
- package/dist/worker/pr-feedback-handler.js.map +1 -0
- package/dist/worker/pr-linker.d.ts +69 -0
- package/dist/worker/pr-linker.d.ts.map +1 -0
- package/dist/worker/pr-linker.js +108 -0
- package/dist/worker/pr-linker.js.map +1 -0
- package/dist/worker/pr-manager.d.ts +61 -0
- package/dist/worker/pr-manager.d.ts.map +1 -0
- package/dist/worker/pr-manager.js +140 -0
- package/dist/worker/pr-manager.js.map +1 -0
- package/dist/worker/repo-checkout.d.ts +63 -0
- package/dist/worker/repo-checkout.d.ts.map +1 -0
- package/dist/worker/repo-checkout.js +160 -0
- package/dist/worker/repo-checkout.js.map +1 -0
- package/dist/worker/stage-comment-manager.d.ts +34 -0
- package/dist/worker/stage-comment-manager.d.ts.map +1 -0
- package/dist/worker/stage-comment-manager.js +114 -0
- package/dist/worker/stage-comment-manager.js.map +1 -0
- package/dist/worker/types.d.ts +192 -0
- package/dist/worker/types.d.ts.map +1 -0
- package/dist/worker/types.js +53 -0
- package/dist/worker/types.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
import { DEFAULT_SSE_CONFIG, parseChannels, parseEventId } from '../types/sse.js';
|
|
3
|
+
import { formatSSEEvent, formatHeartbeat, createConnectedEvent } from './events.js';
|
|
4
|
+
/**
|
|
5
|
+
* SSE Stream Manager
|
|
6
|
+
* Manages individual SSE connections with heartbeat and event delivery
|
|
7
|
+
*/
|
|
8
|
+
export class SSEStream {
|
|
9
|
+
connection;
|
|
10
|
+
config;
|
|
11
|
+
closed = false;
|
|
12
|
+
constructor(response, request, userId, options = {}, config = {}) {
|
|
13
|
+
this.config = { ...DEFAULT_SSE_CONFIG, ...config };
|
|
14
|
+
const connectionId = `conn_${randomUUID().slice(0, 8)}`;
|
|
15
|
+
const channels = options.channels || parseChannels();
|
|
16
|
+
this.connection = {
|
|
17
|
+
id: connectionId,
|
|
18
|
+
response,
|
|
19
|
+
request: request.raw,
|
|
20
|
+
userId,
|
|
21
|
+
subscription: {
|
|
22
|
+
channels: new Set(channels),
|
|
23
|
+
filters: options.filters || {},
|
|
24
|
+
lastEventId: options.lastEventId,
|
|
25
|
+
},
|
|
26
|
+
connectedAt: new Date(),
|
|
27
|
+
sequenceCounter: 0,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get connection ID
|
|
32
|
+
*/
|
|
33
|
+
get id() {
|
|
34
|
+
return this.connection.id;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get user ID
|
|
38
|
+
*/
|
|
39
|
+
get userId() {
|
|
40
|
+
return this.connection.userId;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get subscribed channels
|
|
44
|
+
*/
|
|
45
|
+
get channels() {
|
|
46
|
+
return Array.from(this.connection.subscription.channels);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get subscription filters
|
|
50
|
+
*/
|
|
51
|
+
get filters() {
|
|
52
|
+
return this.connection.subscription.filters;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Check if connection is closed
|
|
56
|
+
*/
|
|
57
|
+
get isClosed() {
|
|
58
|
+
return this.closed;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Get last event ID
|
|
62
|
+
*/
|
|
63
|
+
get lastEventId() {
|
|
64
|
+
return this.connection.subscription.lastEventId;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get next sequence number
|
|
68
|
+
*/
|
|
69
|
+
nextSequence() {
|
|
70
|
+
return ++this.connection.sequenceCounter;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Start the SSE stream
|
|
74
|
+
* Sets up headers, sends initial connected event, and starts heartbeat
|
|
75
|
+
*/
|
|
76
|
+
start() {
|
|
77
|
+
if (this.closed)
|
|
78
|
+
return;
|
|
79
|
+
const res = this.connection.response;
|
|
80
|
+
// SSE headers
|
|
81
|
+
res.setHeader('Content-Type', 'text/event-stream');
|
|
82
|
+
res.setHeader('Cache-Control', 'no-cache, no-transform');
|
|
83
|
+
res.setHeader('Connection', 'keep-alive');
|
|
84
|
+
res.setHeader('X-Accel-Buffering', 'no'); // Disable nginx buffering
|
|
85
|
+
// Prevent compression which can buffer events
|
|
86
|
+
res.setHeader('Content-Encoding', 'identity');
|
|
87
|
+
// Send initial connected event
|
|
88
|
+
const connectedEvent = createConnectedEvent(this.connection.id, this.channels, this.nextSequence());
|
|
89
|
+
this.sendRaw(formatSSEEvent(connectedEvent));
|
|
90
|
+
// Start heartbeat
|
|
91
|
+
this.startHeartbeat();
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Send an SSE event
|
|
95
|
+
*/
|
|
96
|
+
send(event) {
|
|
97
|
+
if (this.closed)
|
|
98
|
+
return false;
|
|
99
|
+
return this.sendRaw(formatSSEEvent(event));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Send raw SSE data
|
|
103
|
+
*/
|
|
104
|
+
sendRaw(data) {
|
|
105
|
+
if (this.closed)
|
|
106
|
+
return false;
|
|
107
|
+
try {
|
|
108
|
+
const res = this.connection.response;
|
|
109
|
+
if (res.writableEnded) {
|
|
110
|
+
this.closed = true;
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
res.write(data);
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
this.closed = true;
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Send heartbeat
|
|
123
|
+
*/
|
|
124
|
+
sendHeartbeat() {
|
|
125
|
+
return this.sendRaw(formatHeartbeat());
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Start heartbeat timer
|
|
129
|
+
*/
|
|
130
|
+
startHeartbeat() {
|
|
131
|
+
if (this.connection.heartbeatTimer) {
|
|
132
|
+
clearInterval(this.connection.heartbeatTimer);
|
|
133
|
+
}
|
|
134
|
+
this.connection.heartbeatTimer = setInterval(() => {
|
|
135
|
+
if (!this.sendHeartbeat()) {
|
|
136
|
+
this.close();
|
|
137
|
+
}
|
|
138
|
+
}, this.config.heartbeatInterval);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Stop heartbeat timer
|
|
142
|
+
*/
|
|
143
|
+
stopHeartbeat() {
|
|
144
|
+
if (this.connection.heartbeatTimer) {
|
|
145
|
+
clearInterval(this.connection.heartbeatTimer);
|
|
146
|
+
this.connection.heartbeatTimer = undefined;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Check if connection is subscribed to a channel
|
|
151
|
+
*/
|
|
152
|
+
isSubscribedTo(channel) {
|
|
153
|
+
return this.connection.subscription.channels.has(channel);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Check if event matches subscription filters
|
|
157
|
+
*/
|
|
158
|
+
matchesFilters(workflowId, tags) {
|
|
159
|
+
const filters = this.connection.subscription.filters;
|
|
160
|
+
// No filters = receive all
|
|
161
|
+
if (!filters.workflowId && (!filters.tags || filters.tags.length === 0)) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
// Match workflow ID if filter is set
|
|
165
|
+
if (filters.workflowId && workflowId !== filters.workflowId) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
// Match tags if filter is set
|
|
169
|
+
if (filters.tags && filters.tags.length > 0 && tags) {
|
|
170
|
+
const hasMatchingTag = filters.tags.some((tag) => tags.includes(tag));
|
|
171
|
+
if (!hasMatchingTag) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Update subscription channels
|
|
179
|
+
*/
|
|
180
|
+
updateChannels(channels) {
|
|
181
|
+
this.connection.subscription.channels = new Set(channels);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Update subscription filters
|
|
185
|
+
*/
|
|
186
|
+
updateFilters(filters) {
|
|
187
|
+
this.connection.subscription.filters = { ...this.connection.subscription.filters, ...filters };
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Close the connection
|
|
191
|
+
*/
|
|
192
|
+
close() {
|
|
193
|
+
if (this.closed)
|
|
194
|
+
return;
|
|
195
|
+
this.closed = true;
|
|
196
|
+
this.stopHeartbeat();
|
|
197
|
+
try {
|
|
198
|
+
if (!this.connection.response.writableEnded) {
|
|
199
|
+
this.connection.response.end();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
// Ignore errors during close
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Get connection info for logging
|
|
208
|
+
*/
|
|
209
|
+
getInfo() {
|
|
210
|
+
return {
|
|
211
|
+
id: this.connection.id,
|
|
212
|
+
userId: this.connection.userId,
|
|
213
|
+
channels: this.channels,
|
|
214
|
+
connectedAt: this.connection.connectedAt,
|
|
215
|
+
filters: this.connection.subscription.filters,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Create SSE response and return stream manager
|
|
221
|
+
*/
|
|
222
|
+
export function createSSEStream(reply, request, userId, options = {}, config = {}) {
|
|
223
|
+
// Access raw response - mark reply as sent to prevent Fastify from handling it
|
|
224
|
+
const response = reply.raw;
|
|
225
|
+
// Create stream manager
|
|
226
|
+
const stream = new SSEStream(response, request, userId, options, config);
|
|
227
|
+
return stream;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Parse Last-Event-ID header for reconnection support
|
|
231
|
+
*/
|
|
232
|
+
export function parseLastEventId(request) {
|
|
233
|
+
const lastEventId = request.headers['last-event-id'];
|
|
234
|
+
if (!lastEventId || typeof lastEventId !== 'string') {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
return parseEventId(lastEventId);
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/sse/stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { SSEChannel, SSEFilters, SSEEvent, WorkflowSSEEvent, SSEStreamConfig } from '../types/sse.js';
|
|
2
|
+
import { SSEStream } from './stream.js';
|
|
3
|
+
/**
|
|
4
|
+
* SSE Subscription Manager
|
|
5
|
+
* Manages SSE connections, channel subscriptions, and event broadcasting
|
|
6
|
+
*/
|
|
7
|
+
export declare class SSESubscriptionManager {
|
|
8
|
+
private connections;
|
|
9
|
+
private channelSubscribers;
|
|
10
|
+
private userConnections;
|
|
11
|
+
private eventBuffer;
|
|
12
|
+
private config;
|
|
13
|
+
constructor(config?: Partial<SSEStreamConfig>);
|
|
14
|
+
/**
|
|
15
|
+
* Add a new SSE connection
|
|
16
|
+
*/
|
|
17
|
+
addConnection(stream: SSEStream): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Remove an SSE connection
|
|
20
|
+
*/
|
|
21
|
+
removeConnection(connectionId: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* Get connection by ID
|
|
24
|
+
*/
|
|
25
|
+
getConnection(connectionId: string): SSEStream | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Get all connections for a user
|
|
28
|
+
*/
|
|
29
|
+
getUserConnections(userId: string): SSEStream[];
|
|
30
|
+
/**
|
|
31
|
+
* Get subscribers for a channel
|
|
32
|
+
*/
|
|
33
|
+
getChannelSubscribers(channel: SSEChannel): SSEStream[];
|
|
34
|
+
/**
|
|
35
|
+
* Broadcast event to all subscribers of a channel
|
|
36
|
+
*/
|
|
37
|
+
broadcast<T>(channel: SSEChannel, event: SSEEvent<T>): number;
|
|
38
|
+
/**
|
|
39
|
+
* Broadcast event with filter matching
|
|
40
|
+
*/
|
|
41
|
+
broadcastFiltered<T>(channel: SSEChannel, event: SSEEvent<T>, matcher: (filters: SSEFilters) => boolean): number;
|
|
42
|
+
/**
|
|
43
|
+
* Broadcast workflow event with filter matching
|
|
44
|
+
*/
|
|
45
|
+
broadcastWorkflowEvent(event: WorkflowSSEEvent): number;
|
|
46
|
+
/**
|
|
47
|
+
* Send event to a specific connection
|
|
48
|
+
*/
|
|
49
|
+
send<T>(connectionId: string, event: SSEEvent<T>): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Buffer event for reconnection replay
|
|
52
|
+
*/
|
|
53
|
+
private bufferEvent;
|
|
54
|
+
/**
|
|
55
|
+
* Get missed events since last event ID for reconnection
|
|
56
|
+
*/
|
|
57
|
+
getMissedEvents(lastEventId: string, channels: SSEChannel[]): SSEEvent<unknown>[];
|
|
58
|
+
/**
|
|
59
|
+
* Replay missed events to a connection
|
|
60
|
+
*/
|
|
61
|
+
replayMissedEvents(stream: SSEStream): number;
|
|
62
|
+
/**
|
|
63
|
+
* Get total connection count
|
|
64
|
+
*/
|
|
65
|
+
getTotalConnections(): number;
|
|
66
|
+
/**
|
|
67
|
+
* Get connection count per channel
|
|
68
|
+
*/
|
|
69
|
+
getChannelCounts(): Record<SSEChannel, number>;
|
|
70
|
+
/**
|
|
71
|
+
* Get connection count per user
|
|
72
|
+
*/
|
|
73
|
+
getUserCounts(): Map<string, number>;
|
|
74
|
+
/**
|
|
75
|
+
* Close all connections
|
|
76
|
+
*/
|
|
77
|
+
closeAll(): void;
|
|
78
|
+
/**
|
|
79
|
+
* Clear all (for testing)
|
|
80
|
+
*/
|
|
81
|
+
clear(): void;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get the SSE subscription manager instance
|
|
85
|
+
*/
|
|
86
|
+
export declare function getSSESubscriptionManager(): SSESubscriptionManager;
|
|
87
|
+
/**
|
|
88
|
+
* Reset SSE subscription manager (for testing)
|
|
89
|
+
*/
|
|
90
|
+
export declare function resetSSESubscriptionManager(): void;
|
|
91
|
+
//# sourceMappingURL=subscriptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../../src/sse/subscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,QAAQ,EACR,gBAAgB,EAChB,eAAe,EAChB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAWxC;;;GAGG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,WAAW,CAAqC;IACxD,OAAO,CAAC,kBAAkB,CAA2C;IACrE,OAAO,CAAC,eAAe,CAAuC;IAC9D,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,MAAM,CAAkB;gBAEpB,MAAM,GAAE,OAAO,CAAC,eAAe,CAAM;IASjD;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO;IAyBzC;;OAEG;IACH,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAuB5C;;OAEG;IACH,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAI1D;;OAEG;IACH,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE;IAS/C;;OAEG;IACH,qBAAqB,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,EAAE;IAOvD;;OAEG;IACH,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,MAAM;IAmB7D;;OAEG;IACH,iBAAiB,CAAC,CAAC,EACjB,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,EAClB,OAAO,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,OAAO,GACxC,MAAM;IAuBT;;OAEG;IACH,sBAAsB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM;IAiBvD;;OAEG;IACH,IAAI,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,OAAO;IAY1D;;OAEG;IACH,OAAO,CAAC,WAAW;IA2BnB;;OAEG;IACH,eAAe,CACb,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,UAAU,EAAE,GACrB,QAAQ,CAAC,OAAO,CAAC,EAAE;IAyBtB;;OAEG;IACH,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM;IAkB7C;;OAEG;IACH,mBAAmB,IAAI,MAAM;IAI7B;;OAEG;IACH,gBAAgB,IAAI,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC;IAQ9C;;OAEG;IACH,aAAa,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAQpC;;OAEG;IACH,QAAQ,IAAI,IAAI;IAYhB;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd;AAKD;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,sBAAsB,CAKlE;AAED;;GAEG;AACH,wBAAgB,2BAA2B,IAAI,IAAI,CAGlD"}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { DEFAULT_SSE_CONFIG } from '../types/sse.js';
|
|
2
|
+
/**
|
|
3
|
+
* SSE Subscription Manager
|
|
4
|
+
* Manages SSE connections, channel subscriptions, and event broadcasting
|
|
5
|
+
*/
|
|
6
|
+
export class SSESubscriptionManager {
|
|
7
|
+
connections = new Map();
|
|
8
|
+
channelSubscribers = new Map();
|
|
9
|
+
userConnections = new Map();
|
|
10
|
+
eventBuffer = [];
|
|
11
|
+
config;
|
|
12
|
+
constructor(config = {}) {
|
|
13
|
+
this.config = { ...DEFAULT_SSE_CONFIG, ...config };
|
|
14
|
+
// Initialize channel sets
|
|
15
|
+
this.channelSubscribers.set('workflows', new Set());
|
|
16
|
+
this.channelSubscribers.set('queue', new Set());
|
|
17
|
+
this.channelSubscribers.set('agents', new Set());
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Add a new SSE connection
|
|
21
|
+
*/
|
|
22
|
+
addConnection(stream) {
|
|
23
|
+
const connectionId = stream.id;
|
|
24
|
+
const userId = stream.userId;
|
|
25
|
+
// Check per-user connection limit
|
|
26
|
+
const userConns = this.userConnections.get(userId) || new Set();
|
|
27
|
+
if (userConns.size >= this.config.maxConnectionsPerClient) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
// Store connection
|
|
31
|
+
this.connections.set(connectionId, stream);
|
|
32
|
+
// Track per-user
|
|
33
|
+
userConns.add(connectionId);
|
|
34
|
+
this.userConnections.set(userId, userConns);
|
|
35
|
+
// Subscribe to channels
|
|
36
|
+
for (const channel of stream.channels) {
|
|
37
|
+
this.channelSubscribers.get(channel)?.add(connectionId);
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Remove an SSE connection
|
|
43
|
+
*/
|
|
44
|
+
removeConnection(connectionId) {
|
|
45
|
+
const stream = this.connections.get(connectionId);
|
|
46
|
+
if (!stream)
|
|
47
|
+
return;
|
|
48
|
+
// Remove from channel sets
|
|
49
|
+
for (const channel of stream.channels) {
|
|
50
|
+
this.channelSubscribers.get(channel)?.delete(connectionId);
|
|
51
|
+
}
|
|
52
|
+
// Remove from user tracking
|
|
53
|
+
const userConns = this.userConnections.get(stream.userId);
|
|
54
|
+
if (userConns) {
|
|
55
|
+
userConns.delete(connectionId);
|
|
56
|
+
if (userConns.size === 0) {
|
|
57
|
+
this.userConnections.delete(stream.userId);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Close stream and remove
|
|
61
|
+
stream.close();
|
|
62
|
+
this.connections.delete(connectionId);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get connection by ID
|
|
66
|
+
*/
|
|
67
|
+
getConnection(connectionId) {
|
|
68
|
+
return this.connections.get(connectionId);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get all connections for a user
|
|
72
|
+
*/
|
|
73
|
+
getUserConnections(userId) {
|
|
74
|
+
const connectionIds = this.userConnections.get(userId);
|
|
75
|
+
if (!connectionIds)
|
|
76
|
+
return [];
|
|
77
|
+
return Array.from(connectionIds)
|
|
78
|
+
.map((id) => this.connections.get(id))
|
|
79
|
+
.filter((stream) => stream !== undefined);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get subscribers for a channel
|
|
83
|
+
*/
|
|
84
|
+
getChannelSubscribers(channel) {
|
|
85
|
+
const connectionIds = this.channelSubscribers.get(channel) || new Set();
|
|
86
|
+
return Array.from(connectionIds)
|
|
87
|
+
.map((id) => this.connections.get(id))
|
|
88
|
+
.filter((stream) => stream !== undefined && !stream.isClosed);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Broadcast event to all subscribers of a channel
|
|
92
|
+
*/
|
|
93
|
+
broadcast(channel, event) {
|
|
94
|
+
const subscribers = this.getChannelSubscribers(channel);
|
|
95
|
+
let sentCount = 0;
|
|
96
|
+
for (const stream of subscribers) {
|
|
97
|
+
if (stream.send(event)) {
|
|
98
|
+
sentCount++;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
// Connection closed, remove it
|
|
102
|
+
this.removeConnection(stream.id);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Buffer event for reconnection replay
|
|
106
|
+
this.bufferEvent(event, channel);
|
|
107
|
+
return sentCount;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Broadcast event with filter matching
|
|
111
|
+
*/
|
|
112
|
+
broadcastFiltered(channel, event, matcher) {
|
|
113
|
+
const subscribers = this.getChannelSubscribers(channel);
|
|
114
|
+
let sentCount = 0;
|
|
115
|
+
for (const stream of subscribers) {
|
|
116
|
+
// Apply filter matching
|
|
117
|
+
if (!matcher(stream.filters)) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (stream.send(event)) {
|
|
121
|
+
sentCount++;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
this.removeConnection(stream.id);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Buffer event for reconnection replay
|
|
128
|
+
this.bufferEvent(event, channel);
|
|
129
|
+
return sentCount;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Broadcast workflow event with filter matching
|
|
133
|
+
*/
|
|
134
|
+
broadcastWorkflowEvent(event) {
|
|
135
|
+
return this.broadcastFiltered('workflows', event, (filters) => {
|
|
136
|
+
// No filters = receive all
|
|
137
|
+
if (!filters.workflowId && (!filters.tags || filters.tags.length === 0)) {
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
// Match workflow ID
|
|
141
|
+
if (filters.workflowId && filters.workflowId !== event.data.workflowId) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
// Tags would need to be in the message payload - for now, pass if workflow matches
|
|
145
|
+
return true;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Send event to a specific connection
|
|
150
|
+
*/
|
|
151
|
+
send(connectionId, event) {
|
|
152
|
+
const stream = this.connections.get(connectionId);
|
|
153
|
+
if (!stream || stream.isClosed) {
|
|
154
|
+
if (stream) {
|
|
155
|
+
this.removeConnection(connectionId);
|
|
156
|
+
}
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
return stream.send(event);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Buffer event for reconnection replay
|
|
163
|
+
*/
|
|
164
|
+
bufferEvent(event, channel) {
|
|
165
|
+
const now = Date.now();
|
|
166
|
+
// Add to buffer
|
|
167
|
+
this.eventBuffer.push({
|
|
168
|
+
event: event,
|
|
169
|
+
timestamp: now,
|
|
170
|
+
channel,
|
|
171
|
+
});
|
|
172
|
+
// Trim buffer by size
|
|
173
|
+
while (this.eventBuffer.length > this.config.eventBufferSize) {
|
|
174
|
+
this.eventBuffer.shift();
|
|
175
|
+
}
|
|
176
|
+
// Trim buffer by age
|
|
177
|
+
const cutoff = now - this.config.eventRetentionMs;
|
|
178
|
+
while (this.eventBuffer.length > 0) {
|
|
179
|
+
const oldest = this.eventBuffer[0];
|
|
180
|
+
if (oldest && oldest.timestamp < cutoff) {
|
|
181
|
+
this.eventBuffer.shift();
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Get missed events since last event ID for reconnection
|
|
190
|
+
*/
|
|
191
|
+
getMissedEvents(lastEventId, channels) {
|
|
192
|
+
// Parse the last event ID to get timestamp
|
|
193
|
+
const parts = lastEventId.split('_');
|
|
194
|
+
if (parts.length < 1)
|
|
195
|
+
return [];
|
|
196
|
+
const firstPart = parts[0];
|
|
197
|
+
if (!firstPart)
|
|
198
|
+
return [];
|
|
199
|
+
const lastTimestamp = parseInt(firstPart, 10);
|
|
200
|
+
if (isNaN(lastTimestamp))
|
|
201
|
+
return [];
|
|
202
|
+
// Find events after the last received
|
|
203
|
+
return this.eventBuffer
|
|
204
|
+
.filter((buffered) => {
|
|
205
|
+
// Must be after last event
|
|
206
|
+
if (buffered.timestamp <= lastTimestamp)
|
|
207
|
+
return false;
|
|
208
|
+
// Must be in subscribed channels
|
|
209
|
+
if (!channels.includes(buffered.channel))
|
|
210
|
+
return false;
|
|
211
|
+
return true;
|
|
212
|
+
})
|
|
213
|
+
.map((buffered) => buffered.event);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Replay missed events to a connection
|
|
217
|
+
*/
|
|
218
|
+
replayMissedEvents(stream) {
|
|
219
|
+
const lastEventId = stream.lastEventId;
|
|
220
|
+
if (!lastEventId)
|
|
221
|
+
return 0;
|
|
222
|
+
const missedEvents = this.getMissedEvents(lastEventId, stream.channels);
|
|
223
|
+
let replayedCount = 0;
|
|
224
|
+
for (const event of missedEvents) {
|
|
225
|
+
if (stream.send(event)) {
|
|
226
|
+
replayedCount++;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return replayedCount;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Get total connection count
|
|
236
|
+
*/
|
|
237
|
+
getTotalConnections() {
|
|
238
|
+
return this.connections.size;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Get connection count per channel
|
|
242
|
+
*/
|
|
243
|
+
getChannelCounts() {
|
|
244
|
+
return {
|
|
245
|
+
workflows: this.channelSubscribers.get('workflows')?.size || 0,
|
|
246
|
+
queue: this.channelSubscribers.get('queue')?.size || 0,
|
|
247
|
+
agents: this.channelSubscribers.get('agents')?.size || 0,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Get connection count per user
|
|
252
|
+
*/
|
|
253
|
+
getUserCounts() {
|
|
254
|
+
const counts = new Map();
|
|
255
|
+
for (const [userId, connections] of this.userConnections) {
|
|
256
|
+
counts.set(userId, connections.size);
|
|
257
|
+
}
|
|
258
|
+
return counts;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Close all connections
|
|
262
|
+
*/
|
|
263
|
+
closeAll() {
|
|
264
|
+
for (const stream of this.connections.values()) {
|
|
265
|
+
stream.close();
|
|
266
|
+
}
|
|
267
|
+
this.connections.clear();
|
|
268
|
+
this.userConnections.clear();
|
|
269
|
+
this.channelSubscribers.get('workflows')?.clear();
|
|
270
|
+
this.channelSubscribers.get('queue')?.clear();
|
|
271
|
+
this.channelSubscribers.get('agents')?.clear();
|
|
272
|
+
this.eventBuffer = [];
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Clear all (for testing)
|
|
276
|
+
*/
|
|
277
|
+
clear() {
|
|
278
|
+
this.closeAll();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
// Singleton instance
|
|
282
|
+
let subscriptionManager = null;
|
|
283
|
+
/**
|
|
284
|
+
* Get the SSE subscription manager instance
|
|
285
|
+
*/
|
|
286
|
+
export function getSSESubscriptionManager() {
|
|
287
|
+
if (!subscriptionManager) {
|
|
288
|
+
subscriptionManager = new SSESubscriptionManager();
|
|
289
|
+
}
|
|
290
|
+
return subscriptionManager;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Reset SSE subscription manager (for testing)
|
|
294
|
+
*/
|
|
295
|
+
export function resetSSESubscriptionManager() {
|
|
296
|
+
subscriptionManager?.clear();
|
|
297
|
+
subscriptionManager = null;
|
|
298
|
+
}
|
|
299
|
+
//# sourceMappingURL=subscriptions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscriptions.js","sourceRoot":"","sources":["../../src/sse/subscriptions.ts"],"names":[],"mappings":"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"}
|