notif-agent 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,729 @@
1
+ // src/client/EventEmitter.ts
2
+ var EventEmitter = class {
3
+ listeners = /* @__PURE__ */ new Map();
4
+ globalListeners = /* @__PURE__ */ new Set();
5
+ /**
6
+ * Bind a callback to a specific event name.
7
+ */
8
+ bind(event, callback) {
9
+ if (!this.listeners.has(event)) {
10
+ this.listeners.set(event, /* @__PURE__ */ new Set());
11
+ }
12
+ this.listeners.get(event).add(callback);
13
+ return this;
14
+ }
15
+ /**
16
+ * Unbind a callback from a specific event name, or all callbacks if callback is omitted.
17
+ * If both event and callback are omitted, all listeners are removed.
18
+ */
19
+ unbind(event, callback) {
20
+ if (!event) {
21
+ this.listeners.clear();
22
+ return this;
23
+ }
24
+ if (!callback) {
25
+ this.listeners.delete(event);
26
+ return this;
27
+ }
28
+ const set = this.listeners.get(event);
29
+ if (set) {
30
+ set.delete(callback);
31
+ if (set.size === 0) {
32
+ this.listeners.delete(event);
33
+ }
34
+ }
35
+ return this;
36
+ }
37
+ /**
38
+ * Bind a callback to ALL incoming events on this emitter.
39
+ */
40
+ bind_global(callback) {
41
+ this.globalListeners.add(callback);
42
+ return this;
43
+ }
44
+ /**
45
+ * Unbind a global callback, or all global callbacks if callback is omitted.
46
+ */
47
+ unbind_global(callback) {
48
+ if (!callback) {
49
+ this.globalListeners.clear();
50
+ return this;
51
+ }
52
+ this.globalListeners.delete(callback);
53
+ return this;
54
+ }
55
+ /**
56
+ * Emit an event to registered listeners and global listeners.
57
+ */
58
+ emit(event, data, metadata) {
59
+ const set = this.listeners.get(event);
60
+ if (set) {
61
+ for (const cb of Array.from(set)) {
62
+ try {
63
+ cb(data, metadata);
64
+ } catch (err) {
65
+ console.error(`[notif-agent] Error in listener for event "${event}":`, err);
66
+ }
67
+ }
68
+ }
69
+ for (const globalCb of Array.from(this.globalListeners)) {
70
+ try {
71
+ globalCb(event, data, metadata);
72
+ } catch (err) {
73
+ console.error(`[notif-agent] Error in global listener for event "${event}":`, err);
74
+ }
75
+ }
76
+ }
77
+ /**
78
+ * Clear all listeners.
79
+ */
80
+ clear() {
81
+ this.listeners.clear();
82
+ this.globalListeners.clear();
83
+ }
84
+ };
85
+
86
+ // src/client/Channel.ts
87
+ var Channel = class {
88
+ name;
89
+ state = "subscribing";
90
+ emitter = new EventEmitter();
91
+ constructor(name) {
92
+ this.name = name;
93
+ }
94
+ /**
95
+ * Whether the channel is currently successfully subscribed.
96
+ */
97
+ get subscribed() {
98
+ return this.state === "subscribed";
99
+ }
100
+ /**
101
+ * Bind an event listener to this channel.
102
+ *
103
+ * Example:
104
+ * ```ts
105
+ * channel.bind('new-comment', (data) => {
106
+ * console.log(data);
107
+ * });
108
+ * ```
109
+ */
110
+ bind(event, callback) {
111
+ this.emitter.bind(event, callback);
112
+ return this;
113
+ }
114
+ /**
115
+ * Unbind an event listener from this channel.
116
+ */
117
+ unbind(event, callback) {
118
+ this.emitter.unbind(event, callback);
119
+ return this;
120
+ }
121
+ /**
122
+ * Bind a global listener to all events received on this channel.
123
+ *
124
+ * Example:
125
+ * ```ts
126
+ * channel.bind_global((eventName, data) => {
127
+ * console.log(`Event ${eventName}:`, data);
128
+ * });
129
+ * ```
130
+ */
131
+ bind_global(callback) {
132
+ this.emitter.bind_global(callback);
133
+ return this;
134
+ }
135
+ /**
136
+ * Unbind a global listener from this channel.
137
+ */
138
+ unbind_global(callback) {
139
+ this.emitter.unbind_global(callback);
140
+ return this;
141
+ }
142
+ /**
143
+ * Internal method to dispatch an event onto this channel.
144
+ */
145
+ handleEvent(event, data, metadata) {
146
+ this.emitter.emit(event, data, {
147
+ ...metadata,
148
+ event,
149
+ channel: this.name
150
+ });
151
+ }
152
+ /**
153
+ * Internal method to update subscription status and fire Pusher-compatible subscription events.
154
+ */
155
+ setSubscribed(data) {
156
+ this.state = "subscribed";
157
+ this.handleEvent("subscription_succeeded", data ?? {});
158
+ this.handleEvent("pusher:subscription_succeeded", data ?? {});
159
+ }
160
+ /**
161
+ * Internal method to set subscription error.
162
+ */
163
+ setSubscriptionError(error) {
164
+ this.state = "error";
165
+ this.handleEvent("subscription_error", error);
166
+ this.handleEvent("pusher:subscription_error", error);
167
+ }
168
+ /**
169
+ * Internal method called when channel is unsubscribed.
170
+ */
171
+ setUnsubscribed() {
172
+ this.state = "unsubscribed";
173
+ this.emitter.clear();
174
+ }
175
+ };
176
+
177
+ // src/client/ConnectionManager.ts
178
+ var ConnectionManager = class {
179
+ state = "initialized";
180
+ clientId = null;
181
+ /**
182
+ * Pusher-compatible alias for clientId.
183
+ */
184
+ get socket_id() {
185
+ return this.clientId;
186
+ }
187
+ emitter = new EventEmitter();
188
+ options;
189
+ eventSource = null;
190
+ abortController = null;
191
+ reconnectAttempts = 0;
192
+ reconnectTimer = null;
193
+ heartbeatTimer = null;
194
+ isManuallyClosed = false;
195
+ constructor(url, options = {}) {
196
+ this.options = {
197
+ url,
198
+ headers: options.headers,
199
+ queryParams: options.queryParams,
200
+ withCredentials: options.withCredentials ?? false,
201
+ transport: options.transport ?? "auto",
202
+ reconnectBaseDelay: options.reconnectBaseDelay ?? 1e3,
203
+ reconnectMaxDelay: options.reconnectMaxDelay ?? 3e4,
204
+ maxReconnectAttempts: options.maxReconnectAttempts ?? Infinity,
205
+ heartbeatTimeout: options.heartbeatTimeout ?? 45e3,
206
+ autoConnect: options.autoConnect ?? true,
207
+ debug: options.debug ?? false
208
+ };
209
+ if (this.options.autoConnect) {
210
+ setTimeout(() => {
211
+ if (!this.isManuallyClosed && this.state === "initialized") {
212
+ this.connect();
213
+ }
214
+ }, 0);
215
+ }
216
+ }
217
+ bind(event, callback) {
218
+ this.emitter.bind(event, callback);
219
+ return this;
220
+ }
221
+ unbind(event, callback) {
222
+ this.emitter.unbind(event, callback);
223
+ return this;
224
+ }
225
+ connect() {
226
+ this.isManuallyClosed = false;
227
+ this.clearTimers();
228
+ if (this.state === "connected" || this.state === "connecting") {
229
+ return;
230
+ }
231
+ this.transition("connecting");
232
+ this.establishConnection();
233
+ }
234
+ disconnect() {
235
+ this.isManuallyClosed = true;
236
+ this.clientId = null;
237
+ this.clearTimers();
238
+ this.closeActiveTransport();
239
+ this.transition("disconnected");
240
+ }
241
+ transition(nextState) {
242
+ if (this.state === nextState) return;
243
+ const previous = this.state;
244
+ this.state = nextState;
245
+ this.log(`State transition: ${previous} -> ${nextState}`);
246
+ const payload = { previous, current: nextState };
247
+ this.emitter.emit("state_change", payload);
248
+ this.emitter.emit(nextState, payload);
249
+ }
250
+ async establishConnection() {
251
+ try {
252
+ const headers = await this.resolveHeaders();
253
+ const hasCustomHeaders = headers && Object.keys(headers).length > 0;
254
+ const shouldUseFetch = this.options.transport === "fetch" || this.options.transport === "auto" && (hasCustomHeaders || typeof EventSource === "undefined");
255
+ const fullUrl = this.buildUrl();
256
+ if (shouldUseFetch) {
257
+ this.log(`Connecting via Fetch SSE stream: ${fullUrl}`);
258
+ this.connectViaFetch(fullUrl, headers);
259
+ } else {
260
+ this.log(`Connecting via native EventSource: ${fullUrl}`);
261
+ this.connectViaEventSource(fullUrl);
262
+ }
263
+ } catch (err) {
264
+ this.handleConnectionFailure(err);
265
+ }
266
+ }
267
+ connectViaEventSource(url) {
268
+ this.closeActiveTransport();
269
+ try {
270
+ const es = new EventSource(url, {
271
+ withCredentials: this.options.withCredentials
272
+ });
273
+ this.eventSource = es;
274
+ es.onopen = () => {
275
+ this.handleConnectionSuccess();
276
+ };
277
+ es.onmessage = (e) => {
278
+ this.resetHeartbeat();
279
+ this.parseAndDispatchMessage("message", e.data, e.lastEventId);
280
+ };
281
+ es.onerror = (err) => {
282
+ this.log("EventSource error occurred", err);
283
+ if (es.readyState === EventSource.CLOSED) {
284
+ this.handleConnectionFailure(err);
285
+ } else {
286
+ this.transition("unavailable");
287
+ }
288
+ };
289
+ } catch (err) {
290
+ this.handleConnectionFailure(err);
291
+ }
292
+ }
293
+ async connectViaFetch(url, headers) {
294
+ this.closeActiveTransport();
295
+ this.abortController = new AbortController();
296
+ try {
297
+ const requestHeaders = {
298
+ Accept: "text/event-stream",
299
+ "Cache-Control": "no-cache",
300
+ ...headers
301
+ };
302
+ const response = await fetch(url, {
303
+ method: "GET",
304
+ headers: requestHeaders,
305
+ credentials: this.options.withCredentials ? "include" : "same-origin",
306
+ signal: this.abortController.signal
307
+ });
308
+ if (!response.ok) {
309
+ throw new Error(`SSE connection failed with HTTP status ${response.status}: ${response.statusText}`);
310
+ }
311
+ if (!response.body) {
312
+ throw new Error("Response body is null or stream reading is not supported");
313
+ }
314
+ this.handleConnectionSuccess();
315
+ const reader = response.body.getReader();
316
+ const decoder = new TextDecoder("utf-8");
317
+ let buffer = "";
318
+ while (true) {
319
+ const { done, value } = await reader.read();
320
+ if (done) break;
321
+ this.resetHeartbeat();
322
+ buffer += decoder.decode(value, { stream: true });
323
+ const parts = buffer.split(/\r\n\r\n|\n\n/);
324
+ buffer = parts.pop() ?? "";
325
+ for (const part of parts) {
326
+ if (part.trim().length > 0) {
327
+ this.processSSEFrame(part);
328
+ }
329
+ }
330
+ }
331
+ if (!this.isManuallyClosed) {
332
+ this.handleConnectionFailure(new Error("SSE stream ended by server"));
333
+ }
334
+ } catch (err) {
335
+ if (err.name === "AbortError" || this.isManuallyClosed) {
336
+ return;
337
+ }
338
+ this.handleConnectionFailure(err);
339
+ }
340
+ }
341
+ processSSEFrame(frame) {
342
+ const lines = frame.split(/\r\n|\r|\n/);
343
+ let event = "message";
344
+ let data = "";
345
+ let id;
346
+ for (const line of lines) {
347
+ if (line.startsWith(":")) {
348
+ this.resetHeartbeat();
349
+ continue;
350
+ }
351
+ if (line.startsWith("event:")) {
352
+ event = line.slice(6).trim();
353
+ } else if (line.startsWith("data:")) {
354
+ const value = line.slice(5).trim();
355
+ data += (data ? "\n" : "") + value;
356
+ } else if (line.startsWith("id:")) {
357
+ id = line.slice(3).trim();
358
+ } else if (line.startsWith("retry:")) {
359
+ const retryMs = parseInt(line.slice(6).trim(), 10);
360
+ if (!isNaN(retryMs)) {
361
+ this.options.reconnectBaseDelay = retryMs;
362
+ }
363
+ }
364
+ }
365
+ if (data || event !== "message") {
366
+ this.parseAndDispatchMessage(event, data, id);
367
+ }
368
+ }
369
+ parseAndDispatchMessage(sseEvent, rawData, id) {
370
+ let parsedData = rawData;
371
+ let channel;
372
+ let eventName = sseEvent;
373
+ if (rawData) {
374
+ try {
375
+ const json = JSON.parse(rawData);
376
+ if (typeof json === "object" && json !== null) {
377
+ if (json.channel && typeof json.channel === "string") {
378
+ channel = json.channel;
379
+ }
380
+ if (json.event && typeof json.event === "string") {
381
+ eventName = json.event;
382
+ }
383
+ if ("data" in json) {
384
+ parsedData = json.data;
385
+ } else {
386
+ parsedData = json;
387
+ }
388
+ } else {
389
+ parsedData = json;
390
+ }
391
+ } catch {
392
+ parsedData = rawData;
393
+ }
394
+ }
395
+ if (eventName === "connected" && parsedData && typeof parsedData === "object" && parsedData.clientId) {
396
+ this.clientId = parsedData.clientId;
397
+ this.emitter.emit("handshake", parsedData);
398
+ }
399
+ if (eventName === "ping" || eventName === "heartbeat" || eventName === ":ping") {
400
+ this.resetHeartbeat();
401
+ return;
402
+ }
403
+ const payload = {
404
+ channel,
405
+ event: eventName,
406
+ data: parsedData,
407
+ id,
408
+ timestamp: Date.now()
409
+ };
410
+ this.emitter.emit("message", payload);
411
+ }
412
+ handleConnectionSuccess() {
413
+ this.reconnectAttempts = 0;
414
+ this.transition("connected");
415
+ this.resetHeartbeat();
416
+ }
417
+ handleConnectionFailure(error) {
418
+ this.log("Connection failed or dropped", error);
419
+ this.closeActiveTransport();
420
+ this.clearHeartbeat();
421
+ if (this.isManuallyClosed) {
422
+ return;
423
+ }
424
+ this.emitter.emit("error", error);
425
+ this.reconnectAttempts++;
426
+ if (this.reconnectAttempts > this.options.maxReconnectAttempts) {
427
+ this.log(`Max reconnect attempts (${this.options.maxReconnectAttempts}) exceeded. State -> failed`);
428
+ this.transition("failed");
429
+ return;
430
+ }
431
+ this.transition("unavailable");
432
+ this.scheduleReconnect();
433
+ }
434
+ scheduleReconnect() {
435
+ if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
436
+ const delay = Math.min(
437
+ this.options.reconnectBaseDelay * Math.pow(1.5, this.reconnectAttempts - 1),
438
+ this.options.reconnectMaxDelay
439
+ );
440
+ const jitter = delay * 0.2 * (Math.random() - 0.5);
441
+ const totalDelay = Math.max(100, Math.round(delay + jitter));
442
+ this.log(`Scheduling reconnect in ${totalDelay}ms (attempt #${this.reconnectAttempts})`);
443
+ this.reconnectTimer = setTimeout(() => {
444
+ if (!this.isManuallyClosed && this.state !== "connected") {
445
+ this.transition("connecting");
446
+ this.establishConnection();
447
+ }
448
+ }, totalDelay);
449
+ }
450
+ resetHeartbeat() {
451
+ this.clearHeartbeat();
452
+ if (this.options.heartbeatTimeout <= 0) return;
453
+ this.heartbeatTimer = setTimeout(() => {
454
+ this.log(`Heartbeat timeout (${this.options.heartbeatTimeout}ms) exceeded. Connection dropped.`);
455
+ this.handleConnectionFailure(new Error("Heartbeat timeout"));
456
+ }, this.options.heartbeatTimeout);
457
+ }
458
+ clearHeartbeat() {
459
+ if (this.heartbeatTimer) {
460
+ clearTimeout(this.heartbeatTimer);
461
+ this.heartbeatTimer = null;
462
+ }
463
+ }
464
+ clearTimers() {
465
+ this.clearHeartbeat();
466
+ if (this.reconnectTimer) {
467
+ clearTimeout(this.reconnectTimer);
468
+ this.reconnectTimer = null;
469
+ }
470
+ }
471
+ closeActiveTransport() {
472
+ if (this.eventSource) {
473
+ try {
474
+ this.eventSource.close();
475
+ } catch {
476
+ }
477
+ this.eventSource = null;
478
+ }
479
+ if (this.abortController) {
480
+ try {
481
+ this.abortController.abort();
482
+ } catch {
483
+ }
484
+ this.abortController = null;
485
+ }
486
+ }
487
+ buildUrl() {
488
+ const url = new URL(this.options.url, typeof window !== "undefined" ? window.location.href : "http://localhost");
489
+ if (this.options.queryParams) {
490
+ for (const [key, value] of Object.entries(this.options.queryParams)) {
491
+ if (value !== void 0 && value !== null) {
492
+ url.searchParams.set(key, String(value));
493
+ }
494
+ }
495
+ }
496
+ return url.toString();
497
+ }
498
+ async resolveHeaders() {
499
+ if (!this.options.headers) return void 0;
500
+ if (typeof this.options.headers === "function") {
501
+ return await this.options.headers();
502
+ }
503
+ return this.options.headers;
504
+ }
505
+ log(...args) {
506
+ if (this.options.debug) {
507
+ console.log("[notif-agent:connection]", ...args);
508
+ }
509
+ }
510
+ };
511
+
512
+ // src/client/NotifAgent.ts
513
+ var NotifAgent = class {
514
+ connection;
515
+ options;
516
+ channels = /* @__PURE__ */ new Map();
517
+ globalEmitter = new EventEmitter();
518
+ /**
519
+ * Unique client connection ID provided by NotifServer handshake.
520
+ */
521
+ get clientId() {
522
+ return this.connection.clientId;
523
+ }
524
+ /**
525
+ * Pusher-compatible alias for clientId.
526
+ */
527
+ get socket_id() {
528
+ return this.connection.clientId;
529
+ }
530
+ constructor(urlOrOptions, maybeOptions) {
531
+ let options;
532
+ if (typeof urlOrOptions === "string") {
533
+ options = { ...maybeOptions ?? {}, url: urlOrOptions };
534
+ } else {
535
+ options = urlOrOptions;
536
+ }
537
+ if (!options.url) {
538
+ throw new Error("[notif-agent] SSE URL must be specified");
539
+ }
540
+ this.options = options;
541
+ this.connection = new ConnectionManager(options.url, options);
542
+ this.connection.bind("message", (payload) => {
543
+ this.routeMessage(payload);
544
+ });
545
+ const triggerChannelSubscriptions = () => {
546
+ for (const channel of this.channels.values()) {
547
+ const isPrivate = channel.name.startsWith("private-") || channel.name.startsWith("presence-");
548
+ if (isPrivate && this.options.authEndpoint) {
549
+ this.authorizeChannel(channel);
550
+ } else {
551
+ channel.setSubscribed();
552
+ }
553
+ }
554
+ };
555
+ this.connection.bind("handshake", () => {
556
+ triggerChannelSubscriptions();
557
+ });
558
+ this.connection.bind("connected", () => {
559
+ if (this.connection.clientId || !this.options.authEndpoint) {
560
+ triggerChannelSubscriptions();
561
+ }
562
+ });
563
+ }
564
+ /**
565
+ * Subscribe to a channel.
566
+ *
567
+ * Example:
568
+ * ```ts
569
+ * const channel = agent.subscribe('orders');
570
+ * channel.bind('created', (order) => { ... });
571
+ * ```
572
+ */
573
+ subscribe(channelName) {
574
+ if (!channelName) {
575
+ throw new Error("[notif-agent] Channel name cannot be empty");
576
+ }
577
+ let channel = this.channels.get(channelName);
578
+ if (!channel) {
579
+ channel = new Channel(channelName);
580
+ this.channels.set(channelName, channel);
581
+ if (this.connection.state === "connected") {
582
+ setTimeout(() => {
583
+ const isPrivate = channelName.startsWith("private-") || channelName.startsWith("presence-");
584
+ if (isPrivate && this.options.authEndpoint) {
585
+ this.authorizeChannel(channel);
586
+ } else {
587
+ channel?.setSubscribed();
588
+ }
589
+ }, 0);
590
+ }
591
+ }
592
+ return channel;
593
+ }
594
+ /**
595
+ * Internal authorization helper for private/presence channels.
596
+ */
597
+ async authorizeChannel(channel) {
598
+ if (!this.options.authEndpoint) {
599
+ channel.setSubscribed();
600
+ return;
601
+ }
602
+ try {
603
+ let customHeaders = {};
604
+ if (typeof this.options.auth?.headers === "function") {
605
+ customHeaders = await this.options.auth.headers();
606
+ } else if (this.options.auth?.headers) {
607
+ customHeaders = this.options.auth.headers;
608
+ }
609
+ const body = {
610
+ clientId: this.connection.clientId,
611
+ socket_id: this.connection.clientId,
612
+ channel: channel.name,
613
+ ...this.options.auth?.params ?? {}
614
+ };
615
+ const response = await fetch(this.options.authEndpoint, {
616
+ method: "POST",
617
+ headers: {
618
+ "Content-Type": "application/json",
619
+ ...customHeaders
620
+ },
621
+ body: JSON.stringify(body)
622
+ });
623
+ if (!response.ok) {
624
+ const errorText = await response.text();
625
+ throw new Error(`[notif-agent] Authorization failed (${response.status}): ${errorText}`);
626
+ }
627
+ const authData = await response.json().catch(() => ({}));
628
+ channel.setSubscribed(authData);
629
+ } catch (err) {
630
+ channel.setSubscriptionError(err);
631
+ }
632
+ }
633
+ /**
634
+ * Unsubscribe from a channel.
635
+ */
636
+ unsubscribe(channelName) {
637
+ const channel = this.channels.get(channelName);
638
+ if (channel) {
639
+ channel.setUnsubscribed();
640
+ this.channels.delete(channelName);
641
+ }
642
+ }
643
+ /**
644
+ * Get an existing subscribed channel by name, if any.
645
+ */
646
+ channel(channelName) {
647
+ return this.channels.get(channelName);
648
+ }
649
+ /**
650
+ * Return all currently subscribed channels.
651
+ */
652
+ allChannels() {
653
+ return Array.from(this.channels.values());
654
+ }
655
+ /**
656
+ * Bind to an event across all channels or global events.
657
+ *
658
+ * Example:
659
+ * ```ts
660
+ * agent.bind('system-alert', (data) => console.log(data));
661
+ * ```
662
+ */
663
+ bind(event, callback) {
664
+ this.globalEmitter.bind(event, callback);
665
+ return this;
666
+ }
667
+ /**
668
+ * Unbind an event listener.
669
+ */
670
+ unbind(event, callback) {
671
+ this.globalEmitter.unbind(event, callback);
672
+ return this;
673
+ }
674
+ /**
675
+ * Bind to all events regardless of name.
676
+ */
677
+ bind_global(callback) {
678
+ this.globalEmitter.bind_global(callback);
679
+ return this;
680
+ }
681
+ /**
682
+ * Unbind a global event listener.
683
+ */
684
+ unbind_global(callback) {
685
+ this.globalEmitter.unbind_global(callback);
686
+ return this;
687
+ }
688
+ /**
689
+ * Connect to the SSE endpoint.
690
+ */
691
+ connect() {
692
+ this.connection.connect();
693
+ }
694
+ /**
695
+ * Disconnect from the SSE endpoint.
696
+ */
697
+ disconnect() {
698
+ this.connection.disconnect();
699
+ }
700
+ /**
701
+ * Route incoming SSE message to global emitters and specific channels.
702
+ */
703
+ routeMessage(payload) {
704
+ const metadata = {
705
+ channel: payload.channel,
706
+ event: payload.event,
707
+ id: payload.id,
708
+ timestamp: payload.timestamp
709
+ };
710
+ this.globalEmitter.emit(payload.event, payload.data, metadata);
711
+ if (payload.channel) {
712
+ const targetChannel = this.channels.get(payload.channel);
713
+ if (targetChannel) {
714
+ targetChannel.handleEvent(payload.event, payload.data, metadata);
715
+ }
716
+ } else {
717
+ for (const ch of this.channels.values()) {
718
+ ch.handleEvent(payload.event, payload.data, metadata);
719
+ }
720
+ }
721
+ }
722
+ };
723
+
724
+ // src/index.ts
725
+ var src_default = NotifAgent;
726
+
727
+ export { Channel, ConnectionManager, EventEmitter, NotifAgent, src_default as default };
728
+ //# sourceMappingURL=index.mjs.map
729
+ //# sourceMappingURL=index.mjs.map