notif-agent 1.0.0 → 2.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/README.md +4 -0
- package/dist/index.js +2 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -6
- package/dist/index.mjs.map +1 -1
- package/dist/server.d.mts +8 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.js +56 -75
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +56 -75
- package/dist/server.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -79,6 +79,10 @@ const httpServer = http.createServer((req, res) => {
|
|
|
79
79
|
httpServer.listen(3000);
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
+
> **CORS:** `notif-agent` sets no CORS headers. If the client runs on another origin, set `Access-Control-Allow-Origin` yourself (a specific origin, not `*`, when using `withCredentials`).
|
|
83
|
+
>
|
|
84
|
+
> **Channels:** a client with no channel list gets every **public** channel. `private-*` and `presence-*` channels are only delivered after you grant them via `options.channels` or `server.subscribeClient()`.
|
|
85
|
+
|
|
82
86
|
#### Next.js App Router (`app/api/sse/route.ts`)
|
|
83
87
|
|
|
84
88
|
```typescript
|
package/dist/index.js
CHANGED
|
@@ -420,6 +420,7 @@ var ConnectionManager = class {
|
|
|
420
420
|
}
|
|
421
421
|
handleConnectionFailure(error) {
|
|
422
422
|
this.log("Connection failed or dropped", error);
|
|
423
|
+
this.clientId = null;
|
|
423
424
|
this.closeActiveTransport();
|
|
424
425
|
this.clearHeartbeat();
|
|
425
426
|
if (this.isManuallyClosed) {
|
|
@@ -559,11 +560,6 @@ var NotifAgent = class {
|
|
|
559
560
|
this.connection.bind("handshake", () => {
|
|
560
561
|
triggerChannelSubscriptions();
|
|
561
562
|
});
|
|
562
|
-
this.connection.bind("connected", () => {
|
|
563
|
-
if (this.connection.clientId || !this.options.authEndpoint) {
|
|
564
|
-
triggerChannelSubscriptions();
|
|
565
|
-
}
|
|
566
|
-
});
|
|
567
563
|
}
|
|
568
564
|
/**
|
|
569
565
|
* Subscribe to a channel.
|
|
@@ -582,7 +578,7 @@ var NotifAgent = class {
|
|
|
582
578
|
if (!channel) {
|
|
583
579
|
channel = new Channel(channelName);
|
|
584
580
|
this.channels.set(channelName, channel);
|
|
585
|
-
if (this.connection.state === "connected") {
|
|
581
|
+
if (this.connection.state === "connected" && this.connection.clientId) {
|
|
586
582
|
setTimeout(() => {
|
|
587
583
|
const isPrivate = channelName.startsWith("private-") || channelName.startsWith("presence-");
|
|
588
584
|
if (isPrivate && this.options.authEndpoint) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/EventEmitter.ts","../src/client/Channel.ts","../src/client/ConnectionManager.ts","../src/client/NotifAgent.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { EventCallback, GlobalEventCallback, EventMetadata } from './types';\n\nexport class EventEmitter {\n private listeners: Map<string, Set<EventCallback>> = new Map();\n private globalListeners: Set<GlobalEventCallback> = new Set();\n\n /**\n * Bind a callback to a specific event name.\n */\n public bind<T = any>(event: string, callback: EventCallback<T>): this {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(callback);\n return this;\n }\n\n /**\n * Unbind a callback from a specific event name, or all callbacks if callback is omitted.\n * If both event and callback are omitted, all listeners are removed.\n */\n public unbind<T = any>(event?: string, callback?: EventCallback<T>): this {\n if (!event) {\n this.listeners.clear();\n return this;\n }\n\n if (!callback) {\n this.listeners.delete(event);\n return this;\n }\n\n const set = this.listeners.get(event);\n if (set) {\n set.delete(callback);\n if (set.size === 0) {\n this.listeners.delete(event);\n }\n }\n\n return this;\n }\n\n /**\n * Bind a callback to ALL incoming events on this emitter.\n */\n public bind_global(callback: GlobalEventCallback): this {\n this.globalListeners.add(callback);\n return this;\n }\n\n /**\n * Unbind a global callback, or all global callbacks if callback is omitted.\n */\n public unbind_global(callback?: GlobalEventCallback): this {\n if (!callback) {\n this.globalListeners.clear();\n return this;\n }\n this.globalListeners.delete(callback);\n return this;\n }\n\n /**\n * Emit an event to registered listeners and global listeners.\n */\n public emit<T = any>(event: string, data: T, metadata?: EventMetadata): void {\n const set = this.listeners.get(event);\n if (set) {\n for (const cb of Array.from(set)) {\n try {\n cb(data, metadata);\n } catch (err) {\n console.error(`[notif-agent] Error in listener for event \"${event}\":`, err);\n }\n }\n }\n\n for (const globalCb of Array.from(this.globalListeners)) {\n try {\n globalCb(event, data, metadata);\n } catch (err) {\n console.error(`[notif-agent] Error in global listener for event \"${event}\":`, err);\n }\n }\n }\n\n /**\n * Clear all listeners.\n */\n public clear(): void {\n this.listeners.clear();\n this.globalListeners.clear();\n }\n}\n","import { EventEmitter } from './EventEmitter';\nimport { ChannelSubscriptionState, EventCallback, GlobalEventCallback, EventMetadata } from './types';\n\nexport class Channel {\n public readonly name: string;\n public state: ChannelSubscriptionState = 'subscribing';\n private emitter: EventEmitter = new EventEmitter();\n\n constructor(name: string) {\n this.name = name;\n }\n\n /**\n * Whether the channel is currently successfully subscribed.\n */\n public get subscribed(): boolean {\n return this.state === 'subscribed';\n }\n\n /**\n * Bind an event listener to this channel.\n *\n * Example:\n * ```ts\n * channel.bind('new-comment', (data) => {\n * console.log(data);\n * });\n * ```\n */\n public bind<T = any>(event: string, callback: EventCallback<T>): this {\n this.emitter.bind(event, callback);\n return this;\n }\n\n /**\n * Unbind an event listener from this channel.\n */\n public unbind<T = any>(event?: string, callback?: EventCallback<T>): this {\n this.emitter.unbind(event, callback);\n return this;\n }\n\n /**\n * Bind a global listener to all events received on this channel.\n *\n * Example:\n * ```ts\n * channel.bind_global((eventName, data) => {\n * console.log(`Event ${eventName}:`, data);\n * });\n * ```\n */\n public bind_global(callback: GlobalEventCallback): this {\n this.emitter.bind_global(callback);\n return this;\n }\n\n /**\n * Unbind a global listener from this channel.\n */\n public unbind_global(callback?: GlobalEventCallback): this {\n this.emitter.unbind_global(callback);\n return this;\n }\n\n /**\n * Internal method to dispatch an event onto this channel.\n */\n public handleEvent<T = any>(event: string, data: T, metadata?: EventMetadata): void {\n this.emitter.emit(event, data, {\n ...metadata,\n event,\n channel: this.name,\n });\n }\n\n /**\n * Internal method to update subscription status and fire Pusher-compatible subscription events.\n */\n public setSubscribed(data?: any): void {\n this.state = 'subscribed';\n // Pusher compatibility and standard notif-agent event\n this.handleEvent('subscription_succeeded', data ?? {});\n this.handleEvent('pusher:subscription_succeeded', data ?? {});\n }\n\n /**\n * Internal method to set subscription error.\n */\n public setSubscriptionError(error: any): void {\n this.state = 'error';\n this.handleEvent('subscription_error', error);\n this.handleEvent('pusher:subscription_error', error);\n }\n\n /**\n * Internal method called when channel is unsubscribed.\n */\n public setUnsubscribed(): void {\n this.state = 'unsubscribed';\n this.emitter.clear();\n }\n}\n","import { EventEmitter } from './EventEmitter';\nimport {\n ConnectionState,\n NotifAgentOptions,\n SSEMessagePayload,\n StateChangePayload,\n} from './types';\n\nexport class ConnectionManager {\n public state: ConnectionState = 'initialized';\n public clientId: string | null = null;\n\n /**\n * Pusher-compatible alias for clientId.\n */\n public get socket_id(): string | null {\n return this.clientId;\n }\n\n private emitter: EventEmitter = new EventEmitter();\n private options: Required<Omit<NotifAgentOptions, 'headers' | 'queryParams' | 'url' | 'authEndpoint' | 'auth'>> & {\n url: string;\n headers?: NotifAgentOptions['headers'];\n queryParams?: NotifAgentOptions['queryParams'];\n authEndpoint?: NotifAgentOptions['authEndpoint'];\n auth?: NotifAgentOptions['auth'];\n };\n\n private eventSource: EventSource | null = null;\n private abortController: AbortController | null = null;\n private reconnectAttempts = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private heartbeatTimer: ReturnType<typeof setTimeout> | null = null;\n private isManuallyClosed = false;\n\n constructor(url: string, options: NotifAgentOptions = {}) {\n this.options = {\n url,\n headers: options.headers,\n queryParams: options.queryParams,\n withCredentials: options.withCredentials ?? false,\n transport: options.transport ?? 'auto',\n reconnectBaseDelay: options.reconnectBaseDelay ?? 1000,\n reconnectMaxDelay: options.reconnectMaxDelay ?? 30000,\n maxReconnectAttempts: options.maxReconnectAttempts ?? Infinity,\n heartbeatTimeout: options.heartbeatTimeout ?? 45000,\n autoConnect: options.autoConnect ?? true,\n debug: options.debug ?? false,\n };\n\n if (this.options.autoConnect) {\n // Connect on next tick so callers have time to bind connection listeners\n setTimeout(() => {\n if (!this.isManuallyClosed && this.state === 'initialized') {\n this.connect();\n }\n }, 0);\n }\n }\n\n public bind<T = any>(event: string, callback: (data: T) => void): this {\n this.emitter.bind(event, callback);\n return this;\n }\n\n public unbind<T = any>(event?: string, callback?: (data: T) => void): this {\n this.emitter.unbind(event, callback);\n return this;\n }\n\n public connect(): void {\n this.isManuallyClosed = false;\n this.clearTimers();\n\n if (this.state === 'connected' || this.state === 'connecting') {\n return;\n }\n\n this.transition('connecting');\n this.establishConnection();\n }\n\n public disconnect(): void {\n this.isManuallyClosed = true;\n this.clientId = null;\n this.clearTimers();\n this.closeActiveTransport();\n this.transition('disconnected');\n }\n\n private transition(nextState: ConnectionState): void {\n if (this.state === nextState) return;\n\n const previous = this.state;\n this.state = nextState;\n\n this.log(`State transition: ${previous} -> ${nextState}`);\n\n const payload: StateChangePayload = { previous, current: nextState };\n this.emitter.emit('state_change', payload);\n this.emitter.emit(nextState, payload);\n }\n\n private async establishConnection(): Promise<void> {\n try {\n const headers = await this.resolveHeaders();\n const hasCustomHeaders = headers && Object.keys(headers).length > 0;\n const shouldUseFetch =\n this.options.transport === 'fetch' ||\n (this.options.transport === 'auto' && (hasCustomHeaders || typeof EventSource === 'undefined'));\n\n const fullUrl = this.buildUrl();\n\n if (shouldUseFetch) {\n this.log(`Connecting via Fetch SSE stream: ${fullUrl}`);\n this.connectViaFetch(fullUrl, headers);\n } else {\n this.log(`Connecting via native EventSource: ${fullUrl}`);\n this.connectViaEventSource(fullUrl);\n }\n } catch (err) {\n this.handleConnectionFailure(err);\n }\n }\n\n private connectViaEventSource(url: string): void {\n this.closeActiveTransport();\n\n try {\n const es = new EventSource(url, {\n withCredentials: this.options.withCredentials,\n });\n this.eventSource = es;\n\n es.onopen = () => {\n this.handleConnectionSuccess();\n };\n\n es.onmessage = (e: MessageEvent) => {\n this.resetHeartbeat();\n this.parseAndDispatchMessage('message', e.data, e.lastEventId);\n };\n\n es.onerror = (err) => {\n this.log('EventSource error occurred', err);\n if (es.readyState === EventSource.CLOSED) {\n this.handleConnectionFailure(err);\n } else {\n // EventSource is in CONNECTING state attempting internal reconnect\n this.transition('unavailable');\n }\n };\n } catch (err) {\n this.handleConnectionFailure(err);\n }\n }\n\n private async connectViaFetch(url: string, headers?: Record<string, string>): Promise<void> {\n this.closeActiveTransport();\n this.abortController = new AbortController();\n\n try {\n const requestHeaders: Record<string, string> = {\n Accept: 'text/event-stream',\n 'Cache-Control': 'no-cache',\n ...headers,\n };\n\n const response = await fetch(url, {\n method: 'GET',\n headers: requestHeaders,\n credentials: this.options.withCredentials ? 'include' : 'same-origin',\n signal: this.abortController.signal,\n });\n\n if (!response.ok) {\n throw new Error(`SSE connection failed with HTTP status ${response.status}: ${response.statusText}`);\n }\n\n if (!response.body) {\n throw new Error('Response body is null or stream reading is not supported');\n }\n\n this.handleConnectionSuccess();\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder('utf-8');\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n this.resetHeartbeat();\n buffer += decoder.decode(value, { stream: true });\n\n // Process SSE frames (blocks ending with double newline)\n const parts = buffer.split(/\\r\\n\\r\\n|\\n\\n/);\n buffer = parts.pop() ?? '';\n\n for (const part of parts) {\n if (part.trim().length > 0) {\n this.processSSEFrame(part);\n }\n }\n }\n\n // Stream closed normally from server\n if (!this.isManuallyClosed) {\n this.handleConnectionFailure(new Error('SSE stream ended by server'));\n }\n } catch (err: any) {\n if (err.name === 'AbortError' || this.isManuallyClosed) {\n // Expected cancellation\n return;\n }\n this.handleConnectionFailure(err);\n }\n }\n\n private processSSEFrame(frame: string): void {\n const lines = frame.split(/\\r\\n|\\r|\\n/);\n let event = 'message';\n let data = '';\n let id: string | undefined;\n\n for (const line of lines) {\n if (line.startsWith(':')) {\n // Comment / ping heartbeat\n this.resetHeartbeat();\n continue;\n }\n\n if (line.startsWith('event:')) {\n event = line.slice(6).trim();\n } else if (line.startsWith('data:')) {\n const value = line.slice(5).trim();\n data += (data ? '\\n' : '') + value;\n } else if (line.startsWith('id:')) {\n id = line.slice(3).trim();\n } else if (line.startsWith('retry:')) {\n const retryMs = parseInt(line.slice(6).trim(), 10);\n if (!isNaN(retryMs)) {\n this.options.reconnectBaseDelay = retryMs;\n }\n }\n }\n\n if (data || event !== 'message') {\n this.parseAndDispatchMessage(event, data, id);\n }\n }\n\n private parseAndDispatchMessage(sseEvent: string, rawData: string, id?: string): void {\n let parsedData: any = rawData;\n let channel: string | undefined;\n let eventName = sseEvent;\n\n if (rawData) {\n try {\n const json = JSON.parse(rawData);\n // Check if server packaged channel & event inside json payload\n if (typeof json === 'object' && json !== null) {\n if (json.channel && typeof json.channel === 'string') {\n channel = json.channel;\n }\n if (json.event && typeof json.event === 'string') {\n eventName = json.event;\n }\n if ('data' in json) {\n parsedData = json.data;\n } else {\n parsedData = json;\n }\n } else {\n parsedData = json;\n }\n } catch {\n parsedData = rawData;\n }\n }\n\n // Handle handshake event from NotifServer\n if (eventName === 'connected' && parsedData && typeof parsedData === 'object' && parsedData.clientId) {\n this.clientId = parsedData.clientId;\n this.emitter.emit('handshake', parsedData);\n }\n\n // Handle heartbeat pings\n if (eventName === 'ping' || eventName === 'heartbeat' || eventName === ':ping') {\n this.resetHeartbeat();\n return;\n }\n\n const payload: SSEMessagePayload = {\n channel,\n event: eventName,\n data: parsedData,\n id,\n timestamp: Date.now(),\n };\n\n this.emitter.emit('message', payload);\n }\n\n private handleConnectionSuccess(): void {\n this.reconnectAttempts = 0;\n this.transition('connected');\n this.resetHeartbeat();\n }\n\n private handleConnectionFailure(error: any): void {\n this.log('Connection failed or dropped', error);\n this.closeActiveTransport();\n this.clearHeartbeat();\n\n if (this.isManuallyClosed) {\n return;\n }\n\n this.emitter.emit('error', error);\n\n this.reconnectAttempts++;\n if (this.reconnectAttempts > this.options.maxReconnectAttempts) {\n this.log(`Max reconnect attempts (${this.options.maxReconnectAttempts}) exceeded. State -> failed`);\n this.transition('failed');\n return;\n }\n\n this.transition('unavailable');\n this.scheduleReconnect();\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n\n // Exponential backoff with jitter\n const delay = Math.min(\n this.options.reconnectBaseDelay * Math.pow(1.5, this.reconnectAttempts - 1),\n this.options.reconnectMaxDelay\n );\n const jitter = delay * 0.2 * (Math.random() - 0.5); // +/- 10%\n const totalDelay = Math.max(100, Math.round(delay + jitter));\n\n this.log(`Scheduling reconnect in ${totalDelay}ms (attempt #${this.reconnectAttempts})`);\n\n this.reconnectTimer = setTimeout(() => {\n if (!this.isManuallyClosed && this.state !== 'connected') {\n this.transition('connecting');\n this.establishConnection();\n }\n }, totalDelay);\n }\n\n private resetHeartbeat(): void {\n this.clearHeartbeat();\n\n if (this.options.heartbeatTimeout <= 0) return;\n\n this.heartbeatTimer = setTimeout(() => {\n this.log(`Heartbeat timeout (${this.options.heartbeatTimeout}ms) exceeded. Connection dropped.`);\n this.handleConnectionFailure(new Error('Heartbeat timeout'));\n }, this.options.heartbeatTimeout);\n }\n\n private clearHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearTimeout(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n private clearTimers(): void {\n this.clearHeartbeat();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n\n private closeActiveTransport(): void {\n if (this.eventSource) {\n try {\n this.eventSource.close();\n } catch {}\n this.eventSource = null;\n }\n\n if (this.abortController) {\n try {\n this.abortController.abort();\n } catch {}\n this.abortController = null;\n }\n }\n\n private buildUrl(): string {\n const url = new URL(this.options.url, typeof window !== 'undefined' ? window.location.href : 'http://localhost');\n if (this.options.queryParams) {\n for (const [key, value] of Object.entries(this.options.queryParams)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n return url.toString();\n }\n\n private async resolveHeaders(): Promise<Record<string, string> | undefined> {\n if (!this.options.headers) return undefined;\n if (typeof this.options.headers === 'function') {\n return await this.options.headers();\n }\n return this.options.headers;\n }\n\n private log(...args: any[]): void {\n if (this.options.debug) {\n console.log('[notif-agent:connection]', ...args);\n }\n }\n}\n","import { Channel } from './Channel';\nimport { ConnectionManager } from './ConnectionManager';\nimport { EventEmitter } from './EventEmitter';\nimport {\n EventCallback,\n GlobalEventCallback,\n NotifAgentOptions,\n SSEMessagePayload,\n} from './types';\n\nexport class NotifAgent {\n public readonly connection: ConnectionManager;\n private options: NotifAgentOptions;\n private channels: Map<string, Channel> = new Map();\n private globalEmitter: EventEmitter = new EventEmitter();\n\n /**\n * Unique client connection ID provided by NotifServer handshake.\n */\n public get clientId(): string | null {\n return this.connection.clientId;\n }\n\n /**\n * Pusher-compatible alias for clientId.\n */\n public get socket_id(): string | null {\n return this.connection.clientId;\n }\n\n constructor(urlOrOptions: string | NotifAgentOptions, maybeOptions?: NotifAgentOptions) {\n let options: NotifAgentOptions;\n\n if (typeof urlOrOptions === 'string') {\n options = { ...(maybeOptions ?? {}), url: urlOrOptions };\n } else {\n options = urlOrOptions;\n }\n\n if (!options.url) {\n throw new Error('[notif-agent] SSE URL must be specified');\n }\n\n this.options = options;\n this.connection = new ConnectionManager(options.url, options);\n\n // Listen to connection messages to route events\n this.connection.bind<SSEMessagePayload>('message', (payload) => {\n this.routeMessage(payload);\n });\n\n const triggerChannelSubscriptions = () => {\n for (const channel of this.channels.values()) {\n const isPrivate = channel.name.startsWith('private-') || channel.name.startsWith('presence-');\n if (isPrivate && this.options.authEndpoint) {\n this.authorizeChannel(channel);\n } else {\n channel.setSubscribed();\n }\n }\n };\n\n // On handshake with server clientId, authorize channels\n this.connection.bind('handshake', () => {\n triggerChannelSubscriptions();\n });\n\n // On reconnect / connected\n this.connection.bind('connected', () => {\n if (this.connection.clientId || !this.options.authEndpoint) {\n triggerChannelSubscriptions();\n }\n });\n }\n\n /**\n * Subscribe to a channel.\n *\n * Example:\n * ```ts\n * const channel = agent.subscribe('orders');\n * channel.bind('created', (order) => { ... });\n * ```\n */\n public subscribe(channelName: string): Channel {\n if (!channelName) {\n throw new Error('[notif-agent] Channel name cannot be empty');\n }\n\n let channel = this.channels.get(channelName);\n if (!channel) {\n channel = new Channel(channelName);\n this.channels.set(channelName, channel);\n\n // If already connected, mark channel as subscribed or authorize if private\n if (this.connection.state === 'connected') {\n setTimeout(() => {\n const isPrivate = channelName.startsWith('private-') || channelName.startsWith('presence-');\n if (isPrivate && this.options.authEndpoint) {\n this.authorizeChannel(channel!);\n } else {\n channel?.setSubscribed();\n }\n }, 0);\n }\n }\n\n return channel;\n }\n\n /**\n * Internal authorization helper for private/presence channels.\n */\n private async authorizeChannel(channel: Channel): Promise<void> {\n if (!this.options.authEndpoint) {\n channel.setSubscribed();\n return;\n }\n\n try {\n let customHeaders: Record<string, string> = {};\n if (typeof this.options.auth?.headers === 'function') {\n customHeaders = await this.options.auth.headers();\n } else if (this.options.auth?.headers) {\n customHeaders = this.options.auth.headers;\n }\n\n const body = {\n clientId: this.connection.clientId,\n socket_id: this.connection.clientId,\n channel: channel.name,\n ...(this.options.auth?.params ?? {}),\n };\n\n const response = await fetch(this.options.authEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...customHeaders,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`[notif-agent] Authorization failed (${response.status}): ${errorText}`);\n }\n\n const authData = await response.json().catch(() => ({}));\n channel.setSubscribed(authData);\n } catch (err) {\n channel.setSubscriptionError(err);\n }\n }\n\n /**\n * Unsubscribe from a channel.\n */\n public unsubscribe(channelName: string): void {\n const channel = this.channels.get(channelName);\n if (channel) {\n channel.setUnsubscribed();\n this.channels.delete(channelName);\n }\n }\n\n /**\n * Get an existing subscribed channel by name, if any.\n */\n public channel(channelName: string): Channel | undefined {\n return this.channels.get(channelName);\n }\n\n /**\n * Return all currently subscribed channels.\n */\n public allChannels(): Channel[] {\n return Array.from(this.channels.values());\n }\n\n /**\n * Bind to an event across all channels or global events.\n *\n * Example:\n * ```ts\n * agent.bind('system-alert', (data) => console.log(data));\n * ```\n */\n public bind<T = any>(event: string, callback: EventCallback<T>): this {\n this.globalEmitter.bind(event, callback);\n return this;\n }\n\n /**\n * Unbind an event listener.\n */\n public unbind<T = any>(event?: string, callback?: EventCallback<T>): this {\n this.globalEmitter.unbind(event, callback);\n return this;\n }\n\n /**\n * Bind to all events regardless of name.\n */\n public bind_global(callback: GlobalEventCallback): this {\n this.globalEmitter.bind_global(callback);\n return this;\n }\n\n /**\n * Unbind a global event listener.\n */\n public unbind_global(callback?: GlobalEventCallback): this {\n this.globalEmitter.unbind_global(callback);\n return this;\n }\n\n /**\n * Connect to the SSE endpoint.\n */\n public connect(): void {\n this.connection.connect();\n }\n\n /**\n * Disconnect from the SSE endpoint.\n */\n public disconnect(): void {\n this.connection.disconnect();\n }\n\n /**\n * Route incoming SSE message to global emitters and specific channels.\n */\n private routeMessage(payload: SSEMessagePayload): void {\n const metadata = {\n channel: payload.channel,\n event: payload.event,\n id: payload.id,\n timestamp: payload.timestamp,\n };\n\n // 1. Dispatch to global agent emitter\n this.globalEmitter.emit(payload.event, payload.data, metadata);\n\n // 2. Dispatch to specific channel if message contains a channel\n if (payload.channel) {\n const targetChannel = this.channels.get(payload.channel);\n if (targetChannel) {\n targetChannel.handleEvent(payload.event, payload.data, metadata);\n }\n } else {\n // If message has no channel specified, notify all active channels\n for (const ch of this.channels.values()) {\n ch.handleEvent(payload.event, payload.data, metadata);\n }\n }\n }\n}\n","import { NotifAgent } from './client/NotifAgent';\n\nexport { NotifAgent } from './client/NotifAgent';\nexport { Channel } from './client/Channel';\nexport { ConnectionManager } from './client/ConnectionManager';\nexport { EventEmitter } from './client/EventEmitter';\nexport * from './client/types';\n\nexport default NotifAgent;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/client/EventEmitter.ts","../src/client/Channel.ts","../src/client/ConnectionManager.ts","../src/client/NotifAgent.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { EventCallback, GlobalEventCallback, EventMetadata } from './types';\n\nexport class EventEmitter {\n private listeners: Map<string, Set<EventCallback>> = new Map();\n private globalListeners: Set<GlobalEventCallback> = new Set();\n\n /**\n * Bind a callback to a specific event name.\n */\n public bind<T = any>(event: string, callback: EventCallback<T>): this {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(callback);\n return this;\n }\n\n /**\n * Unbind a callback from a specific event name, or all callbacks if callback is omitted.\n * If both event and callback are omitted, all listeners are removed.\n */\n public unbind<T = any>(event?: string, callback?: EventCallback<T>): this {\n if (!event) {\n this.listeners.clear();\n return this;\n }\n\n if (!callback) {\n this.listeners.delete(event);\n return this;\n }\n\n const set = this.listeners.get(event);\n if (set) {\n set.delete(callback);\n if (set.size === 0) {\n this.listeners.delete(event);\n }\n }\n\n return this;\n }\n\n /**\n * Bind a callback to ALL incoming events on this emitter.\n */\n public bind_global(callback: GlobalEventCallback): this {\n this.globalListeners.add(callback);\n return this;\n }\n\n /**\n * Unbind a global callback, or all global callbacks if callback is omitted.\n */\n public unbind_global(callback?: GlobalEventCallback): this {\n if (!callback) {\n this.globalListeners.clear();\n return this;\n }\n this.globalListeners.delete(callback);\n return this;\n }\n\n /**\n * Emit an event to registered listeners and global listeners.\n */\n public emit<T = any>(event: string, data: T, metadata?: EventMetadata): void {\n const set = this.listeners.get(event);\n if (set) {\n for (const cb of Array.from(set)) {\n try {\n cb(data, metadata);\n } catch (err) {\n console.error(`[notif-agent] Error in listener for event \"${event}\":`, err);\n }\n }\n }\n\n for (const globalCb of Array.from(this.globalListeners)) {\n try {\n globalCb(event, data, metadata);\n } catch (err) {\n console.error(`[notif-agent] Error in global listener for event \"${event}\":`, err);\n }\n }\n }\n\n /**\n * Clear all listeners.\n */\n public clear(): void {\n this.listeners.clear();\n this.globalListeners.clear();\n }\n}\n","import { EventEmitter } from './EventEmitter';\nimport { ChannelSubscriptionState, EventCallback, GlobalEventCallback, EventMetadata } from './types';\n\nexport class Channel {\n public readonly name: string;\n public state: ChannelSubscriptionState = 'subscribing';\n private emitter: EventEmitter = new EventEmitter();\n\n constructor(name: string) {\n this.name = name;\n }\n\n /**\n * Whether the channel is currently successfully subscribed.\n */\n public get subscribed(): boolean {\n return this.state === 'subscribed';\n }\n\n /**\n * Bind an event listener to this channel.\n *\n * Example:\n * ```ts\n * channel.bind('new-comment', (data) => {\n * console.log(data);\n * });\n * ```\n */\n public bind<T = any>(event: string, callback: EventCallback<T>): this {\n this.emitter.bind(event, callback);\n return this;\n }\n\n /**\n * Unbind an event listener from this channel.\n */\n public unbind<T = any>(event?: string, callback?: EventCallback<T>): this {\n this.emitter.unbind(event, callback);\n return this;\n }\n\n /**\n * Bind a global listener to all events received on this channel.\n *\n * Example:\n * ```ts\n * channel.bind_global((eventName, data) => {\n * console.log(`Event ${eventName}:`, data);\n * });\n * ```\n */\n public bind_global(callback: GlobalEventCallback): this {\n this.emitter.bind_global(callback);\n return this;\n }\n\n /**\n * Unbind a global listener from this channel.\n */\n public unbind_global(callback?: GlobalEventCallback): this {\n this.emitter.unbind_global(callback);\n return this;\n }\n\n /**\n * Internal method to dispatch an event onto this channel.\n */\n public handleEvent<T = any>(event: string, data: T, metadata?: EventMetadata): void {\n this.emitter.emit(event, data, {\n ...metadata,\n event,\n channel: this.name,\n });\n }\n\n /**\n * Internal method to update subscription status and fire Pusher-compatible subscription events.\n */\n public setSubscribed(data?: any): void {\n this.state = 'subscribed';\n // Pusher compatibility and standard notif-agent event\n this.handleEvent('subscription_succeeded', data ?? {});\n this.handleEvent('pusher:subscription_succeeded', data ?? {});\n }\n\n /**\n * Internal method to set subscription error.\n */\n public setSubscriptionError(error: any): void {\n this.state = 'error';\n this.handleEvent('subscription_error', error);\n this.handleEvent('pusher:subscription_error', error);\n }\n\n /**\n * Internal method called when channel is unsubscribed.\n */\n public setUnsubscribed(): void {\n this.state = 'unsubscribed';\n this.emitter.clear();\n }\n}\n","import { EventEmitter } from './EventEmitter';\nimport {\n ConnectionState,\n NotifAgentOptions,\n SSEMessagePayload,\n StateChangePayload,\n} from './types';\n\nexport class ConnectionManager {\n public state: ConnectionState = 'initialized';\n public clientId: string | null = null;\n\n /**\n * Pusher-compatible alias for clientId.\n */\n public get socket_id(): string | null {\n return this.clientId;\n }\n\n private emitter: EventEmitter = new EventEmitter();\n private options: Required<Omit<NotifAgentOptions, 'headers' | 'queryParams' | 'url' | 'authEndpoint' | 'auth'>> & {\n url: string;\n headers?: NotifAgentOptions['headers'];\n queryParams?: NotifAgentOptions['queryParams'];\n authEndpoint?: NotifAgentOptions['authEndpoint'];\n auth?: NotifAgentOptions['auth'];\n };\n\n private eventSource: EventSource | null = null;\n private abortController: AbortController | null = null;\n private reconnectAttempts = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private heartbeatTimer: ReturnType<typeof setTimeout> | null = null;\n private isManuallyClosed = false;\n\n constructor(url: string, options: NotifAgentOptions = {}) {\n this.options = {\n url,\n headers: options.headers,\n queryParams: options.queryParams,\n withCredentials: options.withCredentials ?? false,\n transport: options.transport ?? 'auto',\n reconnectBaseDelay: options.reconnectBaseDelay ?? 1000,\n reconnectMaxDelay: options.reconnectMaxDelay ?? 30000,\n maxReconnectAttempts: options.maxReconnectAttempts ?? Infinity,\n heartbeatTimeout: options.heartbeatTimeout ?? 45000,\n autoConnect: options.autoConnect ?? true,\n debug: options.debug ?? false,\n };\n\n if (this.options.autoConnect) {\n // Connect on next tick so callers have time to bind connection listeners\n setTimeout(() => {\n if (!this.isManuallyClosed && this.state === 'initialized') {\n this.connect();\n }\n }, 0);\n }\n }\n\n public bind<T = any>(event: string, callback: (data: T) => void): this {\n this.emitter.bind(event, callback);\n return this;\n }\n\n public unbind<T = any>(event?: string, callback?: (data: T) => void): this {\n this.emitter.unbind(event, callback);\n return this;\n }\n\n public connect(): void {\n this.isManuallyClosed = false;\n this.clearTimers();\n\n if (this.state === 'connected' || this.state === 'connecting') {\n return;\n }\n\n this.transition('connecting');\n this.establishConnection();\n }\n\n public disconnect(): void {\n this.isManuallyClosed = true;\n this.clientId = null;\n this.clearTimers();\n this.closeActiveTransport();\n this.transition('disconnected');\n }\n\n private transition(nextState: ConnectionState): void {\n if (this.state === nextState) return;\n\n const previous = this.state;\n this.state = nextState;\n\n this.log(`State transition: ${previous} -> ${nextState}`);\n\n const payload: StateChangePayload = { previous, current: nextState };\n this.emitter.emit('state_change', payload);\n this.emitter.emit(nextState, payload);\n }\n\n private async establishConnection(): Promise<void> {\n try {\n const headers = await this.resolveHeaders();\n const hasCustomHeaders = headers && Object.keys(headers).length > 0;\n const shouldUseFetch =\n this.options.transport === 'fetch' ||\n (this.options.transport === 'auto' && (hasCustomHeaders || typeof EventSource === 'undefined'));\n\n const fullUrl = this.buildUrl();\n\n if (shouldUseFetch) {\n this.log(`Connecting via Fetch SSE stream: ${fullUrl}`);\n this.connectViaFetch(fullUrl, headers);\n } else {\n this.log(`Connecting via native EventSource: ${fullUrl}`);\n this.connectViaEventSource(fullUrl);\n }\n } catch (err) {\n this.handleConnectionFailure(err);\n }\n }\n\n private connectViaEventSource(url: string): void {\n this.closeActiveTransport();\n\n try {\n const es = new EventSource(url, {\n withCredentials: this.options.withCredentials,\n });\n this.eventSource = es;\n\n es.onopen = () => {\n this.handleConnectionSuccess();\n };\n\n es.onmessage = (e: MessageEvent) => {\n this.resetHeartbeat();\n this.parseAndDispatchMessage('message', e.data, e.lastEventId);\n };\n\n es.onerror = (err) => {\n this.log('EventSource error occurred', err);\n if (es.readyState === EventSource.CLOSED) {\n this.handleConnectionFailure(err);\n } else {\n // EventSource is in CONNECTING state attempting internal reconnect\n this.transition('unavailable');\n }\n };\n } catch (err) {\n this.handleConnectionFailure(err);\n }\n }\n\n private async connectViaFetch(url: string, headers?: Record<string, string>): Promise<void> {\n this.closeActiveTransport();\n this.abortController = new AbortController();\n\n try {\n const requestHeaders: Record<string, string> = {\n Accept: 'text/event-stream',\n 'Cache-Control': 'no-cache',\n ...headers,\n };\n\n const response = await fetch(url, {\n method: 'GET',\n headers: requestHeaders,\n credentials: this.options.withCredentials ? 'include' : 'same-origin',\n signal: this.abortController.signal,\n });\n\n if (!response.ok) {\n throw new Error(`SSE connection failed with HTTP status ${response.status}: ${response.statusText}`);\n }\n\n if (!response.body) {\n throw new Error('Response body is null or stream reading is not supported');\n }\n\n this.handleConnectionSuccess();\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder('utf-8');\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n this.resetHeartbeat();\n buffer += decoder.decode(value, { stream: true });\n\n // Process SSE frames (blocks ending with double newline)\n const parts = buffer.split(/\\r\\n\\r\\n|\\n\\n/);\n buffer = parts.pop() ?? '';\n\n for (const part of parts) {\n if (part.trim().length > 0) {\n this.processSSEFrame(part);\n }\n }\n }\n\n // Stream closed normally from server\n if (!this.isManuallyClosed) {\n this.handleConnectionFailure(new Error('SSE stream ended by server'));\n }\n } catch (err: any) {\n if (err.name === 'AbortError' || this.isManuallyClosed) {\n // Expected cancellation\n return;\n }\n this.handleConnectionFailure(err);\n }\n }\n\n private processSSEFrame(frame: string): void {\n const lines = frame.split(/\\r\\n|\\r|\\n/);\n let event = 'message';\n let data = '';\n let id: string | undefined;\n\n for (const line of lines) {\n if (line.startsWith(':')) {\n // Comment / ping heartbeat\n this.resetHeartbeat();\n continue;\n }\n\n if (line.startsWith('event:')) {\n event = line.slice(6).trim();\n } else if (line.startsWith('data:')) {\n const value = line.slice(5).trim();\n data += (data ? '\\n' : '') + value;\n } else if (line.startsWith('id:')) {\n id = line.slice(3).trim();\n } else if (line.startsWith('retry:')) {\n const retryMs = parseInt(line.slice(6).trim(), 10);\n if (!isNaN(retryMs)) {\n this.options.reconnectBaseDelay = retryMs;\n }\n }\n }\n\n if (data || event !== 'message') {\n this.parseAndDispatchMessage(event, data, id);\n }\n }\n\n private parseAndDispatchMessage(sseEvent: string, rawData: string, id?: string): void {\n let parsedData: any = rawData;\n let channel: string | undefined;\n let eventName = sseEvent;\n\n if (rawData) {\n try {\n const json = JSON.parse(rawData);\n // Check if server packaged channel & event inside json payload\n if (typeof json === 'object' && json !== null) {\n if (json.channel && typeof json.channel === 'string') {\n channel = json.channel;\n }\n if (json.event && typeof json.event === 'string') {\n eventName = json.event;\n }\n if ('data' in json) {\n parsedData = json.data;\n } else {\n parsedData = json;\n }\n } else {\n parsedData = json;\n }\n } catch {\n parsedData = rawData;\n }\n }\n\n // Handle handshake event from NotifServer\n if (eventName === 'connected' && parsedData && typeof parsedData === 'object' && parsedData.clientId) {\n this.clientId = parsedData.clientId;\n this.emitter.emit('handshake', parsedData);\n }\n\n // Handle heartbeat pings\n if (eventName === 'ping' || eventName === 'heartbeat' || eventName === ':ping') {\n this.resetHeartbeat();\n return;\n }\n\n const payload: SSEMessagePayload = {\n channel,\n event: eventName,\n data: parsedData,\n id,\n timestamp: Date.now(),\n };\n\n this.emitter.emit('message', payload);\n }\n\n private handleConnectionSuccess(): void {\n this.reconnectAttempts = 0;\n this.transition('connected');\n this.resetHeartbeat();\n }\n\n private handleConnectionFailure(error: any): void {\n this.log('Connection failed or dropped', error);\n this.clientId = null; // the server forgets this id once the stream closes\n this.closeActiveTransport();\n this.clearHeartbeat();\n\n if (this.isManuallyClosed) {\n return;\n }\n\n this.emitter.emit('error', error);\n\n this.reconnectAttempts++;\n if (this.reconnectAttempts > this.options.maxReconnectAttempts) {\n this.log(`Max reconnect attempts (${this.options.maxReconnectAttempts}) exceeded. State -> failed`);\n this.transition('failed');\n return;\n }\n\n this.transition('unavailable');\n this.scheduleReconnect();\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n\n // Exponential backoff with jitter\n const delay = Math.min(\n this.options.reconnectBaseDelay * Math.pow(1.5, this.reconnectAttempts - 1),\n this.options.reconnectMaxDelay\n );\n const jitter = delay * 0.2 * (Math.random() - 0.5); // +/- 10%\n const totalDelay = Math.max(100, Math.round(delay + jitter));\n\n this.log(`Scheduling reconnect in ${totalDelay}ms (attempt #${this.reconnectAttempts})`);\n\n this.reconnectTimer = setTimeout(() => {\n if (!this.isManuallyClosed && this.state !== 'connected') {\n this.transition('connecting');\n this.establishConnection();\n }\n }, totalDelay);\n }\n\n private resetHeartbeat(): void {\n this.clearHeartbeat();\n\n if (this.options.heartbeatTimeout <= 0) return;\n\n this.heartbeatTimer = setTimeout(() => {\n this.log(`Heartbeat timeout (${this.options.heartbeatTimeout}ms) exceeded. Connection dropped.`);\n this.handleConnectionFailure(new Error('Heartbeat timeout'));\n }, this.options.heartbeatTimeout);\n }\n\n private clearHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearTimeout(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n private clearTimers(): void {\n this.clearHeartbeat();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n\n private closeActiveTransport(): void {\n if (this.eventSource) {\n try {\n this.eventSource.close();\n } catch {}\n this.eventSource = null;\n }\n\n if (this.abortController) {\n try {\n this.abortController.abort();\n } catch {}\n this.abortController = null;\n }\n }\n\n private buildUrl(): string {\n const url = new URL(this.options.url, typeof window !== 'undefined' ? window.location.href : 'http://localhost');\n if (this.options.queryParams) {\n for (const [key, value] of Object.entries(this.options.queryParams)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n return url.toString();\n }\n\n private async resolveHeaders(): Promise<Record<string, string> | undefined> {\n if (!this.options.headers) return undefined;\n if (typeof this.options.headers === 'function') {\n return await this.options.headers();\n }\n return this.options.headers;\n }\n\n private log(...args: any[]): void {\n if (this.options.debug) {\n console.log('[notif-agent:connection]', ...args);\n }\n }\n}\n","import { Channel } from './Channel';\nimport { ConnectionManager } from './ConnectionManager';\nimport { EventEmitter } from './EventEmitter';\nimport {\n EventCallback,\n GlobalEventCallback,\n NotifAgentOptions,\n SSEMessagePayload,\n} from './types';\n\nexport class NotifAgent {\n public readonly connection: ConnectionManager;\n private options: NotifAgentOptions;\n private channels: Map<string, Channel> = new Map();\n private globalEmitter: EventEmitter = new EventEmitter();\n\n /**\n * Unique client connection ID provided by NotifServer handshake.\n */\n public get clientId(): string | null {\n return this.connection.clientId;\n }\n\n /**\n * Pusher-compatible alias for clientId.\n */\n public get socket_id(): string | null {\n return this.connection.clientId;\n }\n\n constructor(urlOrOptions: string | NotifAgentOptions, maybeOptions?: NotifAgentOptions) {\n let options: NotifAgentOptions;\n\n if (typeof urlOrOptions === 'string') {\n options = { ...(maybeOptions ?? {}), url: urlOrOptions };\n } else {\n options = urlOrOptions;\n }\n\n if (!options.url) {\n throw new Error('[notif-agent] SSE URL must be specified');\n }\n\n this.options = options;\n this.connection = new ConnectionManager(options.url, options);\n\n // Listen to connection messages to route events\n this.connection.bind<SSEMessagePayload>('message', (payload) => {\n this.routeMessage(payload);\n });\n\n const triggerChannelSubscriptions = () => {\n for (const channel of this.channels.values()) {\n const isPrivate = channel.name.startsWith('private-') || channel.name.startsWith('presence-');\n if (isPrivate && this.options.authEndpoint) {\n this.authorizeChannel(channel);\n } else {\n channel.setSubscribed();\n }\n }\n };\n\n // Subscribe once per connection, after the server hands us a clientId (also on every reconnect).\n this.connection.bind('handshake', () => {\n triggerChannelSubscriptions();\n });\n }\n\n /**\n * Subscribe to a channel.\n *\n * Example:\n * ```ts\n * const channel = agent.subscribe('orders');\n * channel.bind('created', (order) => { ... });\n * ```\n */\n public subscribe(channelName: string): Channel {\n if (!channelName) {\n throw new Error('[notif-agent] Channel name cannot be empty');\n }\n\n let channel = this.channels.get(channelName);\n if (!channel) {\n channel = new Channel(channelName);\n this.channels.set(channelName, channel);\n\n // Handshake already done: subscribe now. Otherwise the handshake handler will.\n if (this.connection.state === 'connected' && this.connection.clientId) {\n setTimeout(() => {\n const isPrivate = channelName.startsWith('private-') || channelName.startsWith('presence-');\n if (isPrivate && this.options.authEndpoint) {\n this.authorizeChannel(channel!);\n } else {\n channel?.setSubscribed();\n }\n }, 0);\n }\n }\n\n return channel;\n }\n\n /**\n * Internal authorization helper for private/presence channels.\n */\n private async authorizeChannel(channel: Channel): Promise<void> {\n if (!this.options.authEndpoint) {\n channel.setSubscribed();\n return;\n }\n\n try {\n let customHeaders: Record<string, string> = {};\n if (typeof this.options.auth?.headers === 'function') {\n customHeaders = await this.options.auth.headers();\n } else if (this.options.auth?.headers) {\n customHeaders = this.options.auth.headers;\n }\n\n const body = {\n clientId: this.connection.clientId,\n socket_id: this.connection.clientId,\n channel: channel.name,\n ...(this.options.auth?.params ?? {}),\n };\n\n const response = await fetch(this.options.authEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...customHeaders,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`[notif-agent] Authorization failed (${response.status}): ${errorText}`);\n }\n\n const authData = await response.json().catch(() => ({}));\n channel.setSubscribed(authData);\n } catch (err) {\n channel.setSubscriptionError(err);\n }\n }\n\n /**\n * Unsubscribe from a channel.\n */\n public unsubscribe(channelName: string): void {\n const channel = this.channels.get(channelName);\n if (channel) {\n channel.setUnsubscribed();\n this.channels.delete(channelName);\n }\n }\n\n /**\n * Get an existing subscribed channel by name, if any.\n */\n public channel(channelName: string): Channel | undefined {\n return this.channels.get(channelName);\n }\n\n /**\n * Return all currently subscribed channels.\n */\n public allChannels(): Channel[] {\n return Array.from(this.channels.values());\n }\n\n /**\n * Bind to an event across all channels or global events.\n *\n * Example:\n * ```ts\n * agent.bind('system-alert', (data) => console.log(data));\n * ```\n */\n public bind<T = any>(event: string, callback: EventCallback<T>): this {\n this.globalEmitter.bind(event, callback);\n return this;\n }\n\n /**\n * Unbind an event listener.\n */\n public unbind<T = any>(event?: string, callback?: EventCallback<T>): this {\n this.globalEmitter.unbind(event, callback);\n return this;\n }\n\n /**\n * Bind to all events regardless of name.\n */\n public bind_global(callback: GlobalEventCallback): this {\n this.globalEmitter.bind_global(callback);\n return this;\n }\n\n /**\n * Unbind a global event listener.\n */\n public unbind_global(callback?: GlobalEventCallback): this {\n this.globalEmitter.unbind_global(callback);\n return this;\n }\n\n /**\n * Connect to the SSE endpoint.\n */\n public connect(): void {\n this.connection.connect();\n }\n\n /**\n * Disconnect from the SSE endpoint.\n */\n public disconnect(): void {\n this.connection.disconnect();\n }\n\n /**\n * Route incoming SSE message to global emitters and specific channels.\n */\n private routeMessage(payload: SSEMessagePayload): void {\n const metadata = {\n channel: payload.channel,\n event: payload.event,\n id: payload.id,\n timestamp: payload.timestamp,\n };\n\n // 1. Dispatch to global agent emitter\n this.globalEmitter.emit(payload.event, payload.data, metadata);\n\n // 2. Dispatch to specific channel if message contains a channel\n if (payload.channel) {\n const targetChannel = this.channels.get(payload.channel);\n if (targetChannel) {\n targetChannel.handleEvent(payload.event, payload.data, metadata);\n }\n } else {\n // If message has no channel specified, notify all active channels\n for (const ch of this.channels.values()) {\n ch.handleEvent(payload.event, payload.data, metadata);\n }\n }\n }\n}\n","import { NotifAgent } from './client/NotifAgent';\n\nexport { NotifAgent } from './client/NotifAgent';\nexport { Channel } from './client/Channel';\nexport { ConnectionManager } from './client/ConnectionManager';\nexport { EventEmitter } from './client/EventEmitter';\nexport * from './client/types';\n\nexport default NotifAgent;\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -416,6 +416,7 @@ var ConnectionManager = class {
|
|
|
416
416
|
}
|
|
417
417
|
handleConnectionFailure(error) {
|
|
418
418
|
this.log("Connection failed or dropped", error);
|
|
419
|
+
this.clientId = null;
|
|
419
420
|
this.closeActiveTransport();
|
|
420
421
|
this.clearHeartbeat();
|
|
421
422
|
if (this.isManuallyClosed) {
|
|
@@ -555,11 +556,6 @@ var NotifAgent = class {
|
|
|
555
556
|
this.connection.bind("handshake", () => {
|
|
556
557
|
triggerChannelSubscriptions();
|
|
557
558
|
});
|
|
558
|
-
this.connection.bind("connected", () => {
|
|
559
|
-
if (this.connection.clientId || !this.options.authEndpoint) {
|
|
560
|
-
triggerChannelSubscriptions();
|
|
561
|
-
}
|
|
562
|
-
});
|
|
563
559
|
}
|
|
564
560
|
/**
|
|
565
561
|
* Subscribe to a channel.
|
|
@@ -578,7 +574,7 @@ var NotifAgent = class {
|
|
|
578
574
|
if (!channel) {
|
|
579
575
|
channel = new Channel(channelName);
|
|
580
576
|
this.channels.set(channelName, channel);
|
|
581
|
-
if (this.connection.state === "connected") {
|
|
577
|
+
if (this.connection.state === "connected" && this.connection.clientId) {
|
|
582
578
|
setTimeout(() => {
|
|
583
579
|
const isPrivate = channelName.startsWith("private-") || channelName.startsWith("presence-");
|
|
584
580
|
if (isPrivate && this.options.authEndpoint) {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/EventEmitter.ts","../src/client/Channel.ts","../src/client/ConnectionManager.ts","../src/client/NotifAgent.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import { EventCallback, GlobalEventCallback, EventMetadata } from './types';\n\nexport class EventEmitter {\n private listeners: Map<string, Set<EventCallback>> = new Map();\n private globalListeners: Set<GlobalEventCallback> = new Set();\n\n /**\n * Bind a callback to a specific event name.\n */\n public bind<T = any>(event: string, callback: EventCallback<T>): this {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(callback);\n return this;\n }\n\n /**\n * Unbind a callback from a specific event name, or all callbacks if callback is omitted.\n * If both event and callback are omitted, all listeners are removed.\n */\n public unbind<T = any>(event?: string, callback?: EventCallback<T>): this {\n if (!event) {\n this.listeners.clear();\n return this;\n }\n\n if (!callback) {\n this.listeners.delete(event);\n return this;\n }\n\n const set = this.listeners.get(event);\n if (set) {\n set.delete(callback);\n if (set.size === 0) {\n this.listeners.delete(event);\n }\n }\n\n return this;\n }\n\n /**\n * Bind a callback to ALL incoming events on this emitter.\n */\n public bind_global(callback: GlobalEventCallback): this {\n this.globalListeners.add(callback);\n return this;\n }\n\n /**\n * Unbind a global callback, or all global callbacks if callback is omitted.\n */\n public unbind_global(callback?: GlobalEventCallback): this {\n if (!callback) {\n this.globalListeners.clear();\n return this;\n }\n this.globalListeners.delete(callback);\n return this;\n }\n\n /**\n * Emit an event to registered listeners and global listeners.\n */\n public emit<T = any>(event: string, data: T, metadata?: EventMetadata): void {\n const set = this.listeners.get(event);\n if (set) {\n for (const cb of Array.from(set)) {\n try {\n cb(data, metadata);\n } catch (err) {\n console.error(`[notif-agent] Error in listener for event \"${event}\":`, err);\n }\n }\n }\n\n for (const globalCb of Array.from(this.globalListeners)) {\n try {\n globalCb(event, data, metadata);\n } catch (err) {\n console.error(`[notif-agent] Error in global listener for event \"${event}\":`, err);\n }\n }\n }\n\n /**\n * Clear all listeners.\n */\n public clear(): void {\n this.listeners.clear();\n this.globalListeners.clear();\n }\n}\n","import { EventEmitter } from './EventEmitter';\nimport { ChannelSubscriptionState, EventCallback, GlobalEventCallback, EventMetadata } from './types';\n\nexport class Channel {\n public readonly name: string;\n public state: ChannelSubscriptionState = 'subscribing';\n private emitter: EventEmitter = new EventEmitter();\n\n constructor(name: string) {\n this.name = name;\n }\n\n /**\n * Whether the channel is currently successfully subscribed.\n */\n public get subscribed(): boolean {\n return this.state === 'subscribed';\n }\n\n /**\n * Bind an event listener to this channel.\n *\n * Example:\n * ```ts\n * channel.bind('new-comment', (data) => {\n * console.log(data);\n * });\n * ```\n */\n public bind<T = any>(event: string, callback: EventCallback<T>): this {\n this.emitter.bind(event, callback);\n return this;\n }\n\n /**\n * Unbind an event listener from this channel.\n */\n public unbind<T = any>(event?: string, callback?: EventCallback<T>): this {\n this.emitter.unbind(event, callback);\n return this;\n }\n\n /**\n * Bind a global listener to all events received on this channel.\n *\n * Example:\n * ```ts\n * channel.bind_global((eventName, data) => {\n * console.log(`Event ${eventName}:`, data);\n * });\n * ```\n */\n public bind_global(callback: GlobalEventCallback): this {\n this.emitter.bind_global(callback);\n return this;\n }\n\n /**\n * Unbind a global listener from this channel.\n */\n public unbind_global(callback?: GlobalEventCallback): this {\n this.emitter.unbind_global(callback);\n return this;\n }\n\n /**\n * Internal method to dispatch an event onto this channel.\n */\n public handleEvent<T = any>(event: string, data: T, metadata?: EventMetadata): void {\n this.emitter.emit(event, data, {\n ...metadata,\n event,\n channel: this.name,\n });\n }\n\n /**\n * Internal method to update subscription status and fire Pusher-compatible subscription events.\n */\n public setSubscribed(data?: any): void {\n this.state = 'subscribed';\n // Pusher compatibility and standard notif-agent event\n this.handleEvent('subscription_succeeded', data ?? {});\n this.handleEvent('pusher:subscription_succeeded', data ?? {});\n }\n\n /**\n * Internal method to set subscription error.\n */\n public setSubscriptionError(error: any): void {\n this.state = 'error';\n this.handleEvent('subscription_error', error);\n this.handleEvent('pusher:subscription_error', error);\n }\n\n /**\n * Internal method called when channel is unsubscribed.\n */\n public setUnsubscribed(): void {\n this.state = 'unsubscribed';\n this.emitter.clear();\n }\n}\n","import { EventEmitter } from './EventEmitter';\nimport {\n ConnectionState,\n NotifAgentOptions,\n SSEMessagePayload,\n StateChangePayload,\n} from './types';\n\nexport class ConnectionManager {\n public state: ConnectionState = 'initialized';\n public clientId: string | null = null;\n\n /**\n * Pusher-compatible alias for clientId.\n */\n public get socket_id(): string | null {\n return this.clientId;\n }\n\n private emitter: EventEmitter = new EventEmitter();\n private options: Required<Omit<NotifAgentOptions, 'headers' | 'queryParams' | 'url' | 'authEndpoint' | 'auth'>> & {\n url: string;\n headers?: NotifAgentOptions['headers'];\n queryParams?: NotifAgentOptions['queryParams'];\n authEndpoint?: NotifAgentOptions['authEndpoint'];\n auth?: NotifAgentOptions['auth'];\n };\n\n private eventSource: EventSource | null = null;\n private abortController: AbortController | null = null;\n private reconnectAttempts = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private heartbeatTimer: ReturnType<typeof setTimeout> | null = null;\n private isManuallyClosed = false;\n\n constructor(url: string, options: NotifAgentOptions = {}) {\n this.options = {\n url,\n headers: options.headers,\n queryParams: options.queryParams,\n withCredentials: options.withCredentials ?? false,\n transport: options.transport ?? 'auto',\n reconnectBaseDelay: options.reconnectBaseDelay ?? 1000,\n reconnectMaxDelay: options.reconnectMaxDelay ?? 30000,\n maxReconnectAttempts: options.maxReconnectAttempts ?? Infinity,\n heartbeatTimeout: options.heartbeatTimeout ?? 45000,\n autoConnect: options.autoConnect ?? true,\n debug: options.debug ?? false,\n };\n\n if (this.options.autoConnect) {\n // Connect on next tick so callers have time to bind connection listeners\n setTimeout(() => {\n if (!this.isManuallyClosed && this.state === 'initialized') {\n this.connect();\n }\n }, 0);\n }\n }\n\n public bind<T = any>(event: string, callback: (data: T) => void): this {\n this.emitter.bind(event, callback);\n return this;\n }\n\n public unbind<T = any>(event?: string, callback?: (data: T) => void): this {\n this.emitter.unbind(event, callback);\n return this;\n }\n\n public connect(): void {\n this.isManuallyClosed = false;\n this.clearTimers();\n\n if (this.state === 'connected' || this.state === 'connecting') {\n return;\n }\n\n this.transition('connecting');\n this.establishConnection();\n }\n\n public disconnect(): void {\n this.isManuallyClosed = true;\n this.clientId = null;\n this.clearTimers();\n this.closeActiveTransport();\n this.transition('disconnected');\n }\n\n private transition(nextState: ConnectionState): void {\n if (this.state === nextState) return;\n\n const previous = this.state;\n this.state = nextState;\n\n this.log(`State transition: ${previous} -> ${nextState}`);\n\n const payload: StateChangePayload = { previous, current: nextState };\n this.emitter.emit('state_change', payload);\n this.emitter.emit(nextState, payload);\n }\n\n private async establishConnection(): Promise<void> {\n try {\n const headers = await this.resolveHeaders();\n const hasCustomHeaders = headers && Object.keys(headers).length > 0;\n const shouldUseFetch =\n this.options.transport === 'fetch' ||\n (this.options.transport === 'auto' && (hasCustomHeaders || typeof EventSource === 'undefined'));\n\n const fullUrl = this.buildUrl();\n\n if (shouldUseFetch) {\n this.log(`Connecting via Fetch SSE stream: ${fullUrl}`);\n this.connectViaFetch(fullUrl, headers);\n } else {\n this.log(`Connecting via native EventSource: ${fullUrl}`);\n this.connectViaEventSource(fullUrl);\n }\n } catch (err) {\n this.handleConnectionFailure(err);\n }\n }\n\n private connectViaEventSource(url: string): void {\n this.closeActiveTransport();\n\n try {\n const es = new EventSource(url, {\n withCredentials: this.options.withCredentials,\n });\n this.eventSource = es;\n\n es.onopen = () => {\n this.handleConnectionSuccess();\n };\n\n es.onmessage = (e: MessageEvent) => {\n this.resetHeartbeat();\n this.parseAndDispatchMessage('message', e.data, e.lastEventId);\n };\n\n es.onerror = (err) => {\n this.log('EventSource error occurred', err);\n if (es.readyState === EventSource.CLOSED) {\n this.handleConnectionFailure(err);\n } else {\n // EventSource is in CONNECTING state attempting internal reconnect\n this.transition('unavailable');\n }\n };\n } catch (err) {\n this.handleConnectionFailure(err);\n }\n }\n\n private async connectViaFetch(url: string, headers?: Record<string, string>): Promise<void> {\n this.closeActiveTransport();\n this.abortController = new AbortController();\n\n try {\n const requestHeaders: Record<string, string> = {\n Accept: 'text/event-stream',\n 'Cache-Control': 'no-cache',\n ...headers,\n };\n\n const response = await fetch(url, {\n method: 'GET',\n headers: requestHeaders,\n credentials: this.options.withCredentials ? 'include' : 'same-origin',\n signal: this.abortController.signal,\n });\n\n if (!response.ok) {\n throw new Error(`SSE connection failed with HTTP status ${response.status}: ${response.statusText}`);\n }\n\n if (!response.body) {\n throw new Error('Response body is null or stream reading is not supported');\n }\n\n this.handleConnectionSuccess();\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder('utf-8');\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n this.resetHeartbeat();\n buffer += decoder.decode(value, { stream: true });\n\n // Process SSE frames (blocks ending with double newline)\n const parts = buffer.split(/\\r\\n\\r\\n|\\n\\n/);\n buffer = parts.pop() ?? '';\n\n for (const part of parts) {\n if (part.trim().length > 0) {\n this.processSSEFrame(part);\n }\n }\n }\n\n // Stream closed normally from server\n if (!this.isManuallyClosed) {\n this.handleConnectionFailure(new Error('SSE stream ended by server'));\n }\n } catch (err: any) {\n if (err.name === 'AbortError' || this.isManuallyClosed) {\n // Expected cancellation\n return;\n }\n this.handleConnectionFailure(err);\n }\n }\n\n private processSSEFrame(frame: string): void {\n const lines = frame.split(/\\r\\n|\\r|\\n/);\n let event = 'message';\n let data = '';\n let id: string | undefined;\n\n for (const line of lines) {\n if (line.startsWith(':')) {\n // Comment / ping heartbeat\n this.resetHeartbeat();\n continue;\n }\n\n if (line.startsWith('event:')) {\n event = line.slice(6).trim();\n } else if (line.startsWith('data:')) {\n const value = line.slice(5).trim();\n data += (data ? '\\n' : '') + value;\n } else if (line.startsWith('id:')) {\n id = line.slice(3).trim();\n } else if (line.startsWith('retry:')) {\n const retryMs = parseInt(line.slice(6).trim(), 10);\n if (!isNaN(retryMs)) {\n this.options.reconnectBaseDelay = retryMs;\n }\n }\n }\n\n if (data || event !== 'message') {\n this.parseAndDispatchMessage(event, data, id);\n }\n }\n\n private parseAndDispatchMessage(sseEvent: string, rawData: string, id?: string): void {\n let parsedData: any = rawData;\n let channel: string | undefined;\n let eventName = sseEvent;\n\n if (rawData) {\n try {\n const json = JSON.parse(rawData);\n // Check if server packaged channel & event inside json payload\n if (typeof json === 'object' && json !== null) {\n if (json.channel && typeof json.channel === 'string') {\n channel = json.channel;\n }\n if (json.event && typeof json.event === 'string') {\n eventName = json.event;\n }\n if ('data' in json) {\n parsedData = json.data;\n } else {\n parsedData = json;\n }\n } else {\n parsedData = json;\n }\n } catch {\n parsedData = rawData;\n }\n }\n\n // Handle handshake event from NotifServer\n if (eventName === 'connected' && parsedData && typeof parsedData === 'object' && parsedData.clientId) {\n this.clientId = parsedData.clientId;\n this.emitter.emit('handshake', parsedData);\n }\n\n // Handle heartbeat pings\n if (eventName === 'ping' || eventName === 'heartbeat' || eventName === ':ping') {\n this.resetHeartbeat();\n return;\n }\n\n const payload: SSEMessagePayload = {\n channel,\n event: eventName,\n data: parsedData,\n id,\n timestamp: Date.now(),\n };\n\n this.emitter.emit('message', payload);\n }\n\n private handleConnectionSuccess(): void {\n this.reconnectAttempts = 0;\n this.transition('connected');\n this.resetHeartbeat();\n }\n\n private handleConnectionFailure(error: any): void {\n this.log('Connection failed or dropped', error);\n this.closeActiveTransport();\n this.clearHeartbeat();\n\n if (this.isManuallyClosed) {\n return;\n }\n\n this.emitter.emit('error', error);\n\n this.reconnectAttempts++;\n if (this.reconnectAttempts > this.options.maxReconnectAttempts) {\n this.log(`Max reconnect attempts (${this.options.maxReconnectAttempts}) exceeded. State -> failed`);\n this.transition('failed');\n return;\n }\n\n this.transition('unavailable');\n this.scheduleReconnect();\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n\n // Exponential backoff with jitter\n const delay = Math.min(\n this.options.reconnectBaseDelay * Math.pow(1.5, this.reconnectAttempts - 1),\n this.options.reconnectMaxDelay\n );\n const jitter = delay * 0.2 * (Math.random() - 0.5); // +/- 10%\n const totalDelay = Math.max(100, Math.round(delay + jitter));\n\n this.log(`Scheduling reconnect in ${totalDelay}ms (attempt #${this.reconnectAttempts})`);\n\n this.reconnectTimer = setTimeout(() => {\n if (!this.isManuallyClosed && this.state !== 'connected') {\n this.transition('connecting');\n this.establishConnection();\n }\n }, totalDelay);\n }\n\n private resetHeartbeat(): void {\n this.clearHeartbeat();\n\n if (this.options.heartbeatTimeout <= 0) return;\n\n this.heartbeatTimer = setTimeout(() => {\n this.log(`Heartbeat timeout (${this.options.heartbeatTimeout}ms) exceeded. Connection dropped.`);\n this.handleConnectionFailure(new Error('Heartbeat timeout'));\n }, this.options.heartbeatTimeout);\n }\n\n private clearHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearTimeout(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n private clearTimers(): void {\n this.clearHeartbeat();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n\n private closeActiveTransport(): void {\n if (this.eventSource) {\n try {\n this.eventSource.close();\n } catch {}\n this.eventSource = null;\n }\n\n if (this.abortController) {\n try {\n this.abortController.abort();\n } catch {}\n this.abortController = null;\n }\n }\n\n private buildUrl(): string {\n const url = new URL(this.options.url, typeof window !== 'undefined' ? window.location.href : 'http://localhost');\n if (this.options.queryParams) {\n for (const [key, value] of Object.entries(this.options.queryParams)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n return url.toString();\n }\n\n private async resolveHeaders(): Promise<Record<string, string> | undefined> {\n if (!this.options.headers) return undefined;\n if (typeof this.options.headers === 'function') {\n return await this.options.headers();\n }\n return this.options.headers;\n }\n\n private log(...args: any[]): void {\n if (this.options.debug) {\n console.log('[notif-agent:connection]', ...args);\n }\n }\n}\n","import { Channel } from './Channel';\nimport { ConnectionManager } from './ConnectionManager';\nimport { EventEmitter } from './EventEmitter';\nimport {\n EventCallback,\n GlobalEventCallback,\n NotifAgentOptions,\n SSEMessagePayload,\n} from './types';\n\nexport class NotifAgent {\n public readonly connection: ConnectionManager;\n private options: NotifAgentOptions;\n private channels: Map<string, Channel> = new Map();\n private globalEmitter: EventEmitter = new EventEmitter();\n\n /**\n * Unique client connection ID provided by NotifServer handshake.\n */\n public get clientId(): string | null {\n return this.connection.clientId;\n }\n\n /**\n * Pusher-compatible alias for clientId.\n */\n public get socket_id(): string | null {\n return this.connection.clientId;\n }\n\n constructor(urlOrOptions: string | NotifAgentOptions, maybeOptions?: NotifAgentOptions) {\n let options: NotifAgentOptions;\n\n if (typeof urlOrOptions === 'string') {\n options = { ...(maybeOptions ?? {}), url: urlOrOptions };\n } else {\n options = urlOrOptions;\n }\n\n if (!options.url) {\n throw new Error('[notif-agent] SSE URL must be specified');\n }\n\n this.options = options;\n this.connection = new ConnectionManager(options.url, options);\n\n // Listen to connection messages to route events\n this.connection.bind<SSEMessagePayload>('message', (payload) => {\n this.routeMessage(payload);\n });\n\n const triggerChannelSubscriptions = () => {\n for (const channel of this.channels.values()) {\n const isPrivate = channel.name.startsWith('private-') || channel.name.startsWith('presence-');\n if (isPrivate && this.options.authEndpoint) {\n this.authorizeChannel(channel);\n } else {\n channel.setSubscribed();\n }\n }\n };\n\n // On handshake with server clientId, authorize channels\n this.connection.bind('handshake', () => {\n triggerChannelSubscriptions();\n });\n\n // On reconnect / connected\n this.connection.bind('connected', () => {\n if (this.connection.clientId || !this.options.authEndpoint) {\n triggerChannelSubscriptions();\n }\n });\n }\n\n /**\n * Subscribe to a channel.\n *\n * Example:\n * ```ts\n * const channel = agent.subscribe('orders');\n * channel.bind('created', (order) => { ... });\n * ```\n */\n public subscribe(channelName: string): Channel {\n if (!channelName) {\n throw new Error('[notif-agent] Channel name cannot be empty');\n }\n\n let channel = this.channels.get(channelName);\n if (!channel) {\n channel = new Channel(channelName);\n this.channels.set(channelName, channel);\n\n // If already connected, mark channel as subscribed or authorize if private\n if (this.connection.state === 'connected') {\n setTimeout(() => {\n const isPrivate = channelName.startsWith('private-') || channelName.startsWith('presence-');\n if (isPrivate && this.options.authEndpoint) {\n this.authorizeChannel(channel!);\n } else {\n channel?.setSubscribed();\n }\n }, 0);\n }\n }\n\n return channel;\n }\n\n /**\n * Internal authorization helper for private/presence channels.\n */\n private async authorizeChannel(channel: Channel): Promise<void> {\n if (!this.options.authEndpoint) {\n channel.setSubscribed();\n return;\n }\n\n try {\n let customHeaders: Record<string, string> = {};\n if (typeof this.options.auth?.headers === 'function') {\n customHeaders = await this.options.auth.headers();\n } else if (this.options.auth?.headers) {\n customHeaders = this.options.auth.headers;\n }\n\n const body = {\n clientId: this.connection.clientId,\n socket_id: this.connection.clientId,\n channel: channel.name,\n ...(this.options.auth?.params ?? {}),\n };\n\n const response = await fetch(this.options.authEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...customHeaders,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`[notif-agent] Authorization failed (${response.status}): ${errorText}`);\n }\n\n const authData = await response.json().catch(() => ({}));\n channel.setSubscribed(authData);\n } catch (err) {\n channel.setSubscriptionError(err);\n }\n }\n\n /**\n * Unsubscribe from a channel.\n */\n public unsubscribe(channelName: string): void {\n const channel = this.channels.get(channelName);\n if (channel) {\n channel.setUnsubscribed();\n this.channels.delete(channelName);\n }\n }\n\n /**\n * Get an existing subscribed channel by name, if any.\n */\n public channel(channelName: string): Channel | undefined {\n return this.channels.get(channelName);\n }\n\n /**\n * Return all currently subscribed channels.\n */\n public allChannels(): Channel[] {\n return Array.from(this.channels.values());\n }\n\n /**\n * Bind to an event across all channels or global events.\n *\n * Example:\n * ```ts\n * agent.bind('system-alert', (data) => console.log(data));\n * ```\n */\n public bind<T = any>(event: string, callback: EventCallback<T>): this {\n this.globalEmitter.bind(event, callback);\n return this;\n }\n\n /**\n * Unbind an event listener.\n */\n public unbind<T = any>(event?: string, callback?: EventCallback<T>): this {\n this.globalEmitter.unbind(event, callback);\n return this;\n }\n\n /**\n * Bind to all events regardless of name.\n */\n public bind_global(callback: GlobalEventCallback): this {\n this.globalEmitter.bind_global(callback);\n return this;\n }\n\n /**\n * Unbind a global event listener.\n */\n public unbind_global(callback?: GlobalEventCallback): this {\n this.globalEmitter.unbind_global(callback);\n return this;\n }\n\n /**\n * Connect to the SSE endpoint.\n */\n public connect(): void {\n this.connection.connect();\n }\n\n /**\n * Disconnect from the SSE endpoint.\n */\n public disconnect(): void {\n this.connection.disconnect();\n }\n\n /**\n * Route incoming SSE message to global emitters and specific channels.\n */\n private routeMessage(payload: SSEMessagePayload): void {\n const metadata = {\n channel: payload.channel,\n event: payload.event,\n id: payload.id,\n timestamp: payload.timestamp,\n };\n\n // 1. Dispatch to global agent emitter\n this.globalEmitter.emit(payload.event, payload.data, metadata);\n\n // 2. Dispatch to specific channel if message contains a channel\n if (payload.channel) {\n const targetChannel = this.channels.get(payload.channel);\n if (targetChannel) {\n targetChannel.handleEvent(payload.event, payload.data, metadata);\n }\n } else {\n // If message has no channel specified, notify all active channels\n for (const ch of this.channels.values()) {\n ch.handleEvent(payload.event, payload.data, metadata);\n }\n }\n }\n}\n","import { NotifAgent } from './client/NotifAgent';\n\nexport { NotifAgent } from './client/NotifAgent';\nexport { Channel } from './client/Channel';\nexport { ConnectionManager } from './client/ConnectionManager';\nexport { EventEmitter } from './client/EventEmitter';\nexport * from './client/types';\n\nexport default NotifAgent;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/client/EventEmitter.ts","../src/client/Channel.ts","../src/client/ConnectionManager.ts","../src/client/NotifAgent.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import { EventCallback, GlobalEventCallback, EventMetadata } from './types';\n\nexport class EventEmitter {\n private listeners: Map<string, Set<EventCallback>> = new Map();\n private globalListeners: Set<GlobalEventCallback> = new Set();\n\n /**\n * Bind a callback to a specific event name.\n */\n public bind<T = any>(event: string, callback: EventCallback<T>): this {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(callback);\n return this;\n }\n\n /**\n * Unbind a callback from a specific event name, or all callbacks if callback is omitted.\n * If both event and callback are omitted, all listeners are removed.\n */\n public unbind<T = any>(event?: string, callback?: EventCallback<T>): this {\n if (!event) {\n this.listeners.clear();\n return this;\n }\n\n if (!callback) {\n this.listeners.delete(event);\n return this;\n }\n\n const set = this.listeners.get(event);\n if (set) {\n set.delete(callback);\n if (set.size === 0) {\n this.listeners.delete(event);\n }\n }\n\n return this;\n }\n\n /**\n * Bind a callback to ALL incoming events on this emitter.\n */\n public bind_global(callback: GlobalEventCallback): this {\n this.globalListeners.add(callback);\n return this;\n }\n\n /**\n * Unbind a global callback, or all global callbacks if callback is omitted.\n */\n public unbind_global(callback?: GlobalEventCallback): this {\n if (!callback) {\n this.globalListeners.clear();\n return this;\n }\n this.globalListeners.delete(callback);\n return this;\n }\n\n /**\n * Emit an event to registered listeners and global listeners.\n */\n public emit<T = any>(event: string, data: T, metadata?: EventMetadata): void {\n const set = this.listeners.get(event);\n if (set) {\n for (const cb of Array.from(set)) {\n try {\n cb(data, metadata);\n } catch (err) {\n console.error(`[notif-agent] Error in listener for event \"${event}\":`, err);\n }\n }\n }\n\n for (const globalCb of Array.from(this.globalListeners)) {\n try {\n globalCb(event, data, metadata);\n } catch (err) {\n console.error(`[notif-agent] Error in global listener for event \"${event}\":`, err);\n }\n }\n }\n\n /**\n * Clear all listeners.\n */\n public clear(): void {\n this.listeners.clear();\n this.globalListeners.clear();\n }\n}\n","import { EventEmitter } from './EventEmitter';\nimport { ChannelSubscriptionState, EventCallback, GlobalEventCallback, EventMetadata } from './types';\n\nexport class Channel {\n public readonly name: string;\n public state: ChannelSubscriptionState = 'subscribing';\n private emitter: EventEmitter = new EventEmitter();\n\n constructor(name: string) {\n this.name = name;\n }\n\n /**\n * Whether the channel is currently successfully subscribed.\n */\n public get subscribed(): boolean {\n return this.state === 'subscribed';\n }\n\n /**\n * Bind an event listener to this channel.\n *\n * Example:\n * ```ts\n * channel.bind('new-comment', (data) => {\n * console.log(data);\n * });\n * ```\n */\n public bind<T = any>(event: string, callback: EventCallback<T>): this {\n this.emitter.bind(event, callback);\n return this;\n }\n\n /**\n * Unbind an event listener from this channel.\n */\n public unbind<T = any>(event?: string, callback?: EventCallback<T>): this {\n this.emitter.unbind(event, callback);\n return this;\n }\n\n /**\n * Bind a global listener to all events received on this channel.\n *\n * Example:\n * ```ts\n * channel.bind_global((eventName, data) => {\n * console.log(`Event ${eventName}:`, data);\n * });\n * ```\n */\n public bind_global(callback: GlobalEventCallback): this {\n this.emitter.bind_global(callback);\n return this;\n }\n\n /**\n * Unbind a global listener from this channel.\n */\n public unbind_global(callback?: GlobalEventCallback): this {\n this.emitter.unbind_global(callback);\n return this;\n }\n\n /**\n * Internal method to dispatch an event onto this channel.\n */\n public handleEvent<T = any>(event: string, data: T, metadata?: EventMetadata): void {\n this.emitter.emit(event, data, {\n ...metadata,\n event,\n channel: this.name,\n });\n }\n\n /**\n * Internal method to update subscription status and fire Pusher-compatible subscription events.\n */\n public setSubscribed(data?: any): void {\n this.state = 'subscribed';\n // Pusher compatibility and standard notif-agent event\n this.handleEvent('subscription_succeeded', data ?? {});\n this.handleEvent('pusher:subscription_succeeded', data ?? {});\n }\n\n /**\n * Internal method to set subscription error.\n */\n public setSubscriptionError(error: any): void {\n this.state = 'error';\n this.handleEvent('subscription_error', error);\n this.handleEvent('pusher:subscription_error', error);\n }\n\n /**\n * Internal method called when channel is unsubscribed.\n */\n public setUnsubscribed(): void {\n this.state = 'unsubscribed';\n this.emitter.clear();\n }\n}\n","import { EventEmitter } from './EventEmitter';\nimport {\n ConnectionState,\n NotifAgentOptions,\n SSEMessagePayload,\n StateChangePayload,\n} from './types';\n\nexport class ConnectionManager {\n public state: ConnectionState = 'initialized';\n public clientId: string | null = null;\n\n /**\n * Pusher-compatible alias for clientId.\n */\n public get socket_id(): string | null {\n return this.clientId;\n }\n\n private emitter: EventEmitter = new EventEmitter();\n private options: Required<Omit<NotifAgentOptions, 'headers' | 'queryParams' | 'url' | 'authEndpoint' | 'auth'>> & {\n url: string;\n headers?: NotifAgentOptions['headers'];\n queryParams?: NotifAgentOptions['queryParams'];\n authEndpoint?: NotifAgentOptions['authEndpoint'];\n auth?: NotifAgentOptions['auth'];\n };\n\n private eventSource: EventSource | null = null;\n private abortController: AbortController | null = null;\n private reconnectAttempts = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private heartbeatTimer: ReturnType<typeof setTimeout> | null = null;\n private isManuallyClosed = false;\n\n constructor(url: string, options: NotifAgentOptions = {}) {\n this.options = {\n url,\n headers: options.headers,\n queryParams: options.queryParams,\n withCredentials: options.withCredentials ?? false,\n transport: options.transport ?? 'auto',\n reconnectBaseDelay: options.reconnectBaseDelay ?? 1000,\n reconnectMaxDelay: options.reconnectMaxDelay ?? 30000,\n maxReconnectAttempts: options.maxReconnectAttempts ?? Infinity,\n heartbeatTimeout: options.heartbeatTimeout ?? 45000,\n autoConnect: options.autoConnect ?? true,\n debug: options.debug ?? false,\n };\n\n if (this.options.autoConnect) {\n // Connect on next tick so callers have time to bind connection listeners\n setTimeout(() => {\n if (!this.isManuallyClosed && this.state === 'initialized') {\n this.connect();\n }\n }, 0);\n }\n }\n\n public bind<T = any>(event: string, callback: (data: T) => void): this {\n this.emitter.bind(event, callback);\n return this;\n }\n\n public unbind<T = any>(event?: string, callback?: (data: T) => void): this {\n this.emitter.unbind(event, callback);\n return this;\n }\n\n public connect(): void {\n this.isManuallyClosed = false;\n this.clearTimers();\n\n if (this.state === 'connected' || this.state === 'connecting') {\n return;\n }\n\n this.transition('connecting');\n this.establishConnection();\n }\n\n public disconnect(): void {\n this.isManuallyClosed = true;\n this.clientId = null;\n this.clearTimers();\n this.closeActiveTransport();\n this.transition('disconnected');\n }\n\n private transition(nextState: ConnectionState): void {\n if (this.state === nextState) return;\n\n const previous = this.state;\n this.state = nextState;\n\n this.log(`State transition: ${previous} -> ${nextState}`);\n\n const payload: StateChangePayload = { previous, current: nextState };\n this.emitter.emit('state_change', payload);\n this.emitter.emit(nextState, payload);\n }\n\n private async establishConnection(): Promise<void> {\n try {\n const headers = await this.resolveHeaders();\n const hasCustomHeaders = headers && Object.keys(headers).length > 0;\n const shouldUseFetch =\n this.options.transport === 'fetch' ||\n (this.options.transport === 'auto' && (hasCustomHeaders || typeof EventSource === 'undefined'));\n\n const fullUrl = this.buildUrl();\n\n if (shouldUseFetch) {\n this.log(`Connecting via Fetch SSE stream: ${fullUrl}`);\n this.connectViaFetch(fullUrl, headers);\n } else {\n this.log(`Connecting via native EventSource: ${fullUrl}`);\n this.connectViaEventSource(fullUrl);\n }\n } catch (err) {\n this.handleConnectionFailure(err);\n }\n }\n\n private connectViaEventSource(url: string): void {\n this.closeActiveTransport();\n\n try {\n const es = new EventSource(url, {\n withCredentials: this.options.withCredentials,\n });\n this.eventSource = es;\n\n es.onopen = () => {\n this.handleConnectionSuccess();\n };\n\n es.onmessage = (e: MessageEvent) => {\n this.resetHeartbeat();\n this.parseAndDispatchMessage('message', e.data, e.lastEventId);\n };\n\n es.onerror = (err) => {\n this.log('EventSource error occurred', err);\n if (es.readyState === EventSource.CLOSED) {\n this.handleConnectionFailure(err);\n } else {\n // EventSource is in CONNECTING state attempting internal reconnect\n this.transition('unavailable');\n }\n };\n } catch (err) {\n this.handleConnectionFailure(err);\n }\n }\n\n private async connectViaFetch(url: string, headers?: Record<string, string>): Promise<void> {\n this.closeActiveTransport();\n this.abortController = new AbortController();\n\n try {\n const requestHeaders: Record<string, string> = {\n Accept: 'text/event-stream',\n 'Cache-Control': 'no-cache',\n ...headers,\n };\n\n const response = await fetch(url, {\n method: 'GET',\n headers: requestHeaders,\n credentials: this.options.withCredentials ? 'include' : 'same-origin',\n signal: this.abortController.signal,\n });\n\n if (!response.ok) {\n throw new Error(`SSE connection failed with HTTP status ${response.status}: ${response.statusText}`);\n }\n\n if (!response.body) {\n throw new Error('Response body is null or stream reading is not supported');\n }\n\n this.handleConnectionSuccess();\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder('utf-8');\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n this.resetHeartbeat();\n buffer += decoder.decode(value, { stream: true });\n\n // Process SSE frames (blocks ending with double newline)\n const parts = buffer.split(/\\r\\n\\r\\n|\\n\\n/);\n buffer = parts.pop() ?? '';\n\n for (const part of parts) {\n if (part.trim().length > 0) {\n this.processSSEFrame(part);\n }\n }\n }\n\n // Stream closed normally from server\n if (!this.isManuallyClosed) {\n this.handleConnectionFailure(new Error('SSE stream ended by server'));\n }\n } catch (err: any) {\n if (err.name === 'AbortError' || this.isManuallyClosed) {\n // Expected cancellation\n return;\n }\n this.handleConnectionFailure(err);\n }\n }\n\n private processSSEFrame(frame: string): void {\n const lines = frame.split(/\\r\\n|\\r|\\n/);\n let event = 'message';\n let data = '';\n let id: string | undefined;\n\n for (const line of lines) {\n if (line.startsWith(':')) {\n // Comment / ping heartbeat\n this.resetHeartbeat();\n continue;\n }\n\n if (line.startsWith('event:')) {\n event = line.slice(6).trim();\n } else if (line.startsWith('data:')) {\n const value = line.slice(5).trim();\n data += (data ? '\\n' : '') + value;\n } else if (line.startsWith('id:')) {\n id = line.slice(3).trim();\n } else if (line.startsWith('retry:')) {\n const retryMs = parseInt(line.slice(6).trim(), 10);\n if (!isNaN(retryMs)) {\n this.options.reconnectBaseDelay = retryMs;\n }\n }\n }\n\n if (data || event !== 'message') {\n this.parseAndDispatchMessage(event, data, id);\n }\n }\n\n private parseAndDispatchMessage(sseEvent: string, rawData: string, id?: string): void {\n let parsedData: any = rawData;\n let channel: string | undefined;\n let eventName = sseEvent;\n\n if (rawData) {\n try {\n const json = JSON.parse(rawData);\n // Check if server packaged channel & event inside json payload\n if (typeof json === 'object' && json !== null) {\n if (json.channel && typeof json.channel === 'string') {\n channel = json.channel;\n }\n if (json.event && typeof json.event === 'string') {\n eventName = json.event;\n }\n if ('data' in json) {\n parsedData = json.data;\n } else {\n parsedData = json;\n }\n } else {\n parsedData = json;\n }\n } catch {\n parsedData = rawData;\n }\n }\n\n // Handle handshake event from NotifServer\n if (eventName === 'connected' && parsedData && typeof parsedData === 'object' && parsedData.clientId) {\n this.clientId = parsedData.clientId;\n this.emitter.emit('handshake', parsedData);\n }\n\n // Handle heartbeat pings\n if (eventName === 'ping' || eventName === 'heartbeat' || eventName === ':ping') {\n this.resetHeartbeat();\n return;\n }\n\n const payload: SSEMessagePayload = {\n channel,\n event: eventName,\n data: parsedData,\n id,\n timestamp: Date.now(),\n };\n\n this.emitter.emit('message', payload);\n }\n\n private handleConnectionSuccess(): void {\n this.reconnectAttempts = 0;\n this.transition('connected');\n this.resetHeartbeat();\n }\n\n private handleConnectionFailure(error: any): void {\n this.log('Connection failed or dropped', error);\n this.clientId = null; // the server forgets this id once the stream closes\n this.closeActiveTransport();\n this.clearHeartbeat();\n\n if (this.isManuallyClosed) {\n return;\n }\n\n this.emitter.emit('error', error);\n\n this.reconnectAttempts++;\n if (this.reconnectAttempts > this.options.maxReconnectAttempts) {\n this.log(`Max reconnect attempts (${this.options.maxReconnectAttempts}) exceeded. State -> failed`);\n this.transition('failed');\n return;\n }\n\n this.transition('unavailable');\n this.scheduleReconnect();\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n\n // Exponential backoff with jitter\n const delay = Math.min(\n this.options.reconnectBaseDelay * Math.pow(1.5, this.reconnectAttempts - 1),\n this.options.reconnectMaxDelay\n );\n const jitter = delay * 0.2 * (Math.random() - 0.5); // +/- 10%\n const totalDelay = Math.max(100, Math.round(delay + jitter));\n\n this.log(`Scheduling reconnect in ${totalDelay}ms (attempt #${this.reconnectAttempts})`);\n\n this.reconnectTimer = setTimeout(() => {\n if (!this.isManuallyClosed && this.state !== 'connected') {\n this.transition('connecting');\n this.establishConnection();\n }\n }, totalDelay);\n }\n\n private resetHeartbeat(): void {\n this.clearHeartbeat();\n\n if (this.options.heartbeatTimeout <= 0) return;\n\n this.heartbeatTimer = setTimeout(() => {\n this.log(`Heartbeat timeout (${this.options.heartbeatTimeout}ms) exceeded. Connection dropped.`);\n this.handleConnectionFailure(new Error('Heartbeat timeout'));\n }, this.options.heartbeatTimeout);\n }\n\n private clearHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearTimeout(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n private clearTimers(): void {\n this.clearHeartbeat();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n\n private closeActiveTransport(): void {\n if (this.eventSource) {\n try {\n this.eventSource.close();\n } catch {}\n this.eventSource = null;\n }\n\n if (this.abortController) {\n try {\n this.abortController.abort();\n } catch {}\n this.abortController = null;\n }\n }\n\n private buildUrl(): string {\n const url = new URL(this.options.url, typeof window !== 'undefined' ? window.location.href : 'http://localhost');\n if (this.options.queryParams) {\n for (const [key, value] of Object.entries(this.options.queryParams)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n return url.toString();\n }\n\n private async resolveHeaders(): Promise<Record<string, string> | undefined> {\n if (!this.options.headers) return undefined;\n if (typeof this.options.headers === 'function') {\n return await this.options.headers();\n }\n return this.options.headers;\n }\n\n private log(...args: any[]): void {\n if (this.options.debug) {\n console.log('[notif-agent:connection]', ...args);\n }\n }\n}\n","import { Channel } from './Channel';\nimport { ConnectionManager } from './ConnectionManager';\nimport { EventEmitter } from './EventEmitter';\nimport {\n EventCallback,\n GlobalEventCallback,\n NotifAgentOptions,\n SSEMessagePayload,\n} from './types';\n\nexport class NotifAgent {\n public readonly connection: ConnectionManager;\n private options: NotifAgentOptions;\n private channels: Map<string, Channel> = new Map();\n private globalEmitter: EventEmitter = new EventEmitter();\n\n /**\n * Unique client connection ID provided by NotifServer handshake.\n */\n public get clientId(): string | null {\n return this.connection.clientId;\n }\n\n /**\n * Pusher-compatible alias for clientId.\n */\n public get socket_id(): string | null {\n return this.connection.clientId;\n }\n\n constructor(urlOrOptions: string | NotifAgentOptions, maybeOptions?: NotifAgentOptions) {\n let options: NotifAgentOptions;\n\n if (typeof urlOrOptions === 'string') {\n options = { ...(maybeOptions ?? {}), url: urlOrOptions };\n } else {\n options = urlOrOptions;\n }\n\n if (!options.url) {\n throw new Error('[notif-agent] SSE URL must be specified');\n }\n\n this.options = options;\n this.connection = new ConnectionManager(options.url, options);\n\n // Listen to connection messages to route events\n this.connection.bind<SSEMessagePayload>('message', (payload) => {\n this.routeMessage(payload);\n });\n\n const triggerChannelSubscriptions = () => {\n for (const channel of this.channels.values()) {\n const isPrivate = channel.name.startsWith('private-') || channel.name.startsWith('presence-');\n if (isPrivate && this.options.authEndpoint) {\n this.authorizeChannel(channel);\n } else {\n channel.setSubscribed();\n }\n }\n };\n\n // Subscribe once per connection, after the server hands us a clientId (also on every reconnect).\n this.connection.bind('handshake', () => {\n triggerChannelSubscriptions();\n });\n }\n\n /**\n * Subscribe to a channel.\n *\n * Example:\n * ```ts\n * const channel = agent.subscribe('orders');\n * channel.bind('created', (order) => { ... });\n * ```\n */\n public subscribe(channelName: string): Channel {\n if (!channelName) {\n throw new Error('[notif-agent] Channel name cannot be empty');\n }\n\n let channel = this.channels.get(channelName);\n if (!channel) {\n channel = new Channel(channelName);\n this.channels.set(channelName, channel);\n\n // Handshake already done: subscribe now. Otherwise the handshake handler will.\n if (this.connection.state === 'connected' && this.connection.clientId) {\n setTimeout(() => {\n const isPrivate = channelName.startsWith('private-') || channelName.startsWith('presence-');\n if (isPrivate && this.options.authEndpoint) {\n this.authorizeChannel(channel!);\n } else {\n channel?.setSubscribed();\n }\n }, 0);\n }\n }\n\n return channel;\n }\n\n /**\n * Internal authorization helper for private/presence channels.\n */\n private async authorizeChannel(channel: Channel): Promise<void> {\n if (!this.options.authEndpoint) {\n channel.setSubscribed();\n return;\n }\n\n try {\n let customHeaders: Record<string, string> = {};\n if (typeof this.options.auth?.headers === 'function') {\n customHeaders = await this.options.auth.headers();\n } else if (this.options.auth?.headers) {\n customHeaders = this.options.auth.headers;\n }\n\n const body = {\n clientId: this.connection.clientId,\n socket_id: this.connection.clientId,\n channel: channel.name,\n ...(this.options.auth?.params ?? {}),\n };\n\n const response = await fetch(this.options.authEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...customHeaders,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`[notif-agent] Authorization failed (${response.status}): ${errorText}`);\n }\n\n const authData = await response.json().catch(() => ({}));\n channel.setSubscribed(authData);\n } catch (err) {\n channel.setSubscriptionError(err);\n }\n }\n\n /**\n * Unsubscribe from a channel.\n */\n public unsubscribe(channelName: string): void {\n const channel = this.channels.get(channelName);\n if (channel) {\n channel.setUnsubscribed();\n this.channels.delete(channelName);\n }\n }\n\n /**\n * Get an existing subscribed channel by name, if any.\n */\n public channel(channelName: string): Channel | undefined {\n return this.channels.get(channelName);\n }\n\n /**\n * Return all currently subscribed channels.\n */\n public allChannels(): Channel[] {\n return Array.from(this.channels.values());\n }\n\n /**\n * Bind to an event across all channels or global events.\n *\n * Example:\n * ```ts\n * agent.bind('system-alert', (data) => console.log(data));\n * ```\n */\n public bind<T = any>(event: string, callback: EventCallback<T>): this {\n this.globalEmitter.bind(event, callback);\n return this;\n }\n\n /**\n * Unbind an event listener.\n */\n public unbind<T = any>(event?: string, callback?: EventCallback<T>): this {\n this.globalEmitter.unbind(event, callback);\n return this;\n }\n\n /**\n * Bind to all events regardless of name.\n */\n public bind_global(callback: GlobalEventCallback): this {\n this.globalEmitter.bind_global(callback);\n return this;\n }\n\n /**\n * Unbind a global event listener.\n */\n public unbind_global(callback?: GlobalEventCallback): this {\n this.globalEmitter.unbind_global(callback);\n return this;\n }\n\n /**\n * Connect to the SSE endpoint.\n */\n public connect(): void {\n this.connection.connect();\n }\n\n /**\n * Disconnect from the SSE endpoint.\n */\n public disconnect(): void {\n this.connection.disconnect();\n }\n\n /**\n * Route incoming SSE message to global emitters and specific channels.\n */\n private routeMessage(payload: SSEMessagePayload): void {\n const metadata = {\n channel: payload.channel,\n event: payload.event,\n id: payload.id,\n timestamp: payload.timestamp,\n };\n\n // 1. Dispatch to global agent emitter\n this.globalEmitter.emit(payload.event, payload.data, metadata);\n\n // 2. Dispatch to specific channel if message contains a channel\n if (payload.channel) {\n const targetChannel = this.channels.get(payload.channel);\n if (targetChannel) {\n targetChannel.handleEvent(payload.event, payload.data, metadata);\n }\n } else {\n // If message has no channel specified, notify all active channels\n for (const ch of this.channels.values()) {\n ch.handleEvent(payload.event, payload.data, metadata);\n }\n }\n }\n}\n","import { NotifAgent } from './client/NotifAgent';\n\nexport { NotifAgent } from './client/NotifAgent';\nexport { Channel } from './client/Channel';\nexport { ConnectionManager } from './client/ConnectionManager';\nexport { EventEmitter } from './client/EventEmitter';\nexport * from './client/types';\n\nexport default NotifAgent;\n"]}
|
package/dist/server.d.mts
CHANGED
|
@@ -119,6 +119,14 @@ declare class NotifServer {
|
|
|
119
119
|
*/
|
|
120
120
|
close(): void;
|
|
121
121
|
private removeClient;
|
|
122
|
+
/**
|
|
123
|
+
* App-given channels are final; the URL can only add public channels when the app gave none.
|
|
124
|
+
* `*` (all public channels) is the default when neither names any.
|
|
125
|
+
*/
|
|
126
|
+
private resolveChannels;
|
|
127
|
+
/** `*` never covers private channels; those need an explicit grant (options.channels or subscribeClient). */
|
|
128
|
+
private isSubscribed;
|
|
129
|
+
private formatMessage;
|
|
122
130
|
private startHeartbeat;
|
|
123
131
|
private log;
|
|
124
132
|
}
|
package/dist/server.d.ts
CHANGED
|
@@ -119,6 +119,14 @@ declare class NotifServer {
|
|
|
119
119
|
*/
|
|
120
120
|
close(): void;
|
|
121
121
|
private removeClient;
|
|
122
|
+
/**
|
|
123
|
+
* App-given channels are final; the URL can only add public channels when the app gave none.
|
|
124
|
+
* `*` (all public channels) is the default when neither names any.
|
|
125
|
+
*/
|
|
126
|
+
private resolveChannels;
|
|
127
|
+
/** `*` never covers private channels; those need an explicit grant (options.channels or subscribeClient). */
|
|
128
|
+
private isSubscribed;
|
|
129
|
+
private formatMessage;
|
|
122
130
|
private startHeartbeat;
|
|
123
131
|
private log;
|
|
124
132
|
}
|
package/dist/server.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// src/server/NotifServer.ts
|
|
4
|
+
var isPrivate = (ch) => ch.startsWith("private-") || ch.startsWith("presence-");
|
|
5
|
+
var MAX_BUFFERED_BYTES = 1024 * 1024;
|
|
4
6
|
var NotifServer = class {
|
|
5
7
|
clients = /* @__PURE__ */ new Map();
|
|
6
8
|
heartbeatInterval;
|
|
@@ -28,7 +30,7 @@ var NotifServer = class {
|
|
|
28
30
|
const channels = Array.isArray(channel) ? channel : [channel];
|
|
29
31
|
for (const ch of channels) {
|
|
30
32
|
for (const client of this.clients.values()) {
|
|
31
|
-
if (
|
|
33
|
+
if (this.isSubscribed(client, ch)) {
|
|
32
34
|
client.send(event, data, { channel: ch, id: options?.id, sseEvent: options?.sseEvent });
|
|
33
35
|
}
|
|
34
36
|
}
|
|
@@ -100,7 +102,7 @@ var NotifServer = class {
|
|
|
100
102
|
getSubscribersCount(channel) {
|
|
101
103
|
let count = 0;
|
|
102
104
|
for (const client of this.clients.values()) {
|
|
103
|
-
if (
|
|
105
|
+
if (this.isSubscribed(client, channel)) {
|
|
104
106
|
count++;
|
|
105
107
|
}
|
|
106
108
|
}
|
|
@@ -121,31 +123,24 @@ var NotifServer = class {
|
|
|
121
123
|
"Content-Type": "text/event-stream",
|
|
122
124
|
"Cache-Control": "no-cache, no-transform",
|
|
123
125
|
Connection: "keep-alive",
|
|
124
|
-
"X-Accel-Buffering": "no"
|
|
126
|
+
"X-Accel-Buffering": "no"
|
|
125
127
|
// Disable proxy buffering for Nginx
|
|
126
|
-
"Access-Control-Allow-Origin": "*"
|
|
127
128
|
});
|
|
128
129
|
if (typeof res.flushHeaders === "function") {
|
|
129
130
|
res.flushHeaders();
|
|
130
131
|
}
|
|
131
132
|
const clientId = options?.clientId ?? this.generateClientId();
|
|
132
|
-
const subscribedChannels =
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (queryChannels) {
|
|
138
|
-
for (const ch of queryChannels.split(",")) {
|
|
139
|
-
const trimmed = ch.trim();
|
|
140
|
-
if (trimmed) subscribedChannels.add(trimmed);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
} catch {
|
|
133
|
+
const subscribedChannels = this.resolveChannels(req.url, options?.channels);
|
|
134
|
+
const write = (chunk) => {
|
|
135
|
+
const ok = res.write(chunk);
|
|
136
|
+
if (typeof res.flush === "function") {
|
|
137
|
+
res.flush();
|
|
144
138
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
139
|
+
if (!ok && res.writableLength > MAX_BUFFERED_BYTES) {
|
|
140
|
+
this.log(`Client ${clientId} too slow, dropping`);
|
|
141
|
+
client.close();
|
|
142
|
+
}
|
|
143
|
+
};
|
|
149
144
|
const client = {
|
|
150
145
|
id: clientId,
|
|
151
146
|
userId: options?.userId,
|
|
@@ -153,35 +148,16 @@ var NotifServer = class {
|
|
|
153
148
|
meta: options?.meta ?? {},
|
|
154
149
|
send: (event, data, opt) => {
|
|
155
150
|
try {
|
|
156
|
-
|
|
157
|
-
if (opt?.id) message += `id: ${opt.id}
|
|
158
|
-
`;
|
|
159
|
-
message += `event: ${opt?.sseEvent ?? "message"}
|
|
160
|
-
`;
|
|
161
|
-
const payload = {
|
|
162
|
-
channel: opt?.channel,
|
|
163
|
-
event,
|
|
164
|
-
data
|
|
165
|
-
};
|
|
166
|
-
message += `data: ${JSON.stringify(payload)}
|
|
167
|
-
|
|
168
|
-
`;
|
|
169
|
-
res.write(message);
|
|
170
|
-
if (typeof res.flush === "function") {
|
|
171
|
-
res.flush();
|
|
172
|
-
}
|
|
151
|
+
write(this.formatMessage(event, data, opt));
|
|
173
152
|
} catch (err) {
|
|
174
153
|
this.log(`Error writing to client ${clientId}:`, err);
|
|
175
154
|
}
|
|
176
155
|
},
|
|
177
156
|
sendComment: (comment) => {
|
|
178
157
|
try {
|
|
179
|
-
|
|
158
|
+
write(`: ${comment}
|
|
180
159
|
|
|
181
160
|
`);
|
|
182
|
-
if (typeof res.flush === "function") {
|
|
183
|
-
res.flush();
|
|
184
|
-
}
|
|
185
161
|
} catch {
|
|
186
162
|
}
|
|
187
163
|
},
|
|
@@ -217,23 +193,7 @@ var NotifServer = class {
|
|
|
217
193
|
*/
|
|
218
194
|
createWebResponse(request, options) {
|
|
219
195
|
const clientId = options?.clientId ?? this.generateClientId();
|
|
220
|
-
const subscribedChannels =
|
|
221
|
-
if (request?.url) {
|
|
222
|
-
try {
|
|
223
|
-
const url = new URL(request.url);
|
|
224
|
-
const queryChannels = url.searchParams.get("channels");
|
|
225
|
-
if (queryChannels) {
|
|
226
|
-
for (const ch of queryChannels.split(",")) {
|
|
227
|
-
const trimmed = ch.trim();
|
|
228
|
-
if (trimmed) subscribedChannels.add(trimmed);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
} catch {
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
if (subscribedChannels.size === 0 && !options?.channels) {
|
|
235
|
-
subscribedChannels.add("*");
|
|
236
|
-
}
|
|
196
|
+
const subscribedChannels = this.resolveChannels(request?.url, options?.channels);
|
|
237
197
|
const encoder = new TextEncoder();
|
|
238
198
|
const stream = new ReadableStream({
|
|
239
199
|
start: (controller) => {
|
|
@@ -244,20 +204,7 @@ var NotifServer = class {
|
|
|
244
204
|
meta: options?.meta ?? {},
|
|
245
205
|
send: (event, data, opt) => {
|
|
246
206
|
try {
|
|
247
|
-
|
|
248
|
-
if (opt?.id) message += `id: ${opt.id}
|
|
249
|
-
`;
|
|
250
|
-
message += `event: ${opt?.sseEvent ?? "message"}
|
|
251
|
-
`;
|
|
252
|
-
const payload = {
|
|
253
|
-
channel: opt?.channel,
|
|
254
|
-
event,
|
|
255
|
-
data
|
|
256
|
-
};
|
|
257
|
-
message += `data: ${JSON.stringify(payload)}
|
|
258
|
-
|
|
259
|
-
`;
|
|
260
|
-
controller.enqueue(encoder.encode(message));
|
|
207
|
+
controller.enqueue(encoder.encode(this.formatMessage(event, data, opt)));
|
|
261
208
|
} catch (err) {
|
|
262
209
|
this.log(`Error enqueueing to client ${clientId}:`, err);
|
|
263
210
|
}
|
|
@@ -290,8 +237,7 @@ var NotifServer = class {
|
|
|
290
237
|
headers: {
|
|
291
238
|
"Content-Type": "text/event-stream",
|
|
292
239
|
"Cache-Control": "no-cache, no-transform",
|
|
293
|
-
Connection: "keep-alive"
|
|
294
|
-
"Access-Control-Allow-Origin": "*"
|
|
240
|
+
Connection: "keep-alive"
|
|
295
241
|
}
|
|
296
242
|
});
|
|
297
243
|
}
|
|
@@ -314,10 +260,45 @@ var NotifServer = class {
|
|
|
314
260
|
this.log(`Client disconnected: ${clientId}`);
|
|
315
261
|
}
|
|
316
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* App-given channels are final; the URL can only add public channels when the app gave none.
|
|
265
|
+
* `*` (all public channels) is the default when neither names any.
|
|
266
|
+
*/
|
|
267
|
+
resolveChannels(rawUrl, allowed) {
|
|
268
|
+
if (allowed) return new Set(allowed);
|
|
269
|
+
const channels = /* @__PURE__ */ new Set();
|
|
270
|
+
if (rawUrl) {
|
|
271
|
+
try {
|
|
272
|
+
const query = new URL(rawUrl, "http://localhost").searchParams.get("channels") ?? "";
|
|
273
|
+
for (const ch of query.split(",")) {
|
|
274
|
+
const trimmed = ch.trim();
|
|
275
|
+
if (trimmed && !isPrivate(trimmed)) channels.add(trimmed);
|
|
276
|
+
}
|
|
277
|
+
} catch {
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (channels.size === 0) channels.add("*");
|
|
281
|
+
return channels;
|
|
282
|
+
}
|
|
283
|
+
/** `*` never covers private channels; those need an explicit grant (options.channels or subscribeClient). */
|
|
284
|
+
isSubscribed(client, channel) {
|
|
285
|
+
return client.channels.has(channel) || client.channels.has("*") && !isPrivate(channel);
|
|
286
|
+
}
|
|
287
|
+
formatMessage(event, data, opt) {
|
|
288
|
+
let message = "";
|
|
289
|
+
if (opt?.id) message += `id: ${opt.id}
|
|
290
|
+
`;
|
|
291
|
+
message += `event: ${opt?.sseEvent ?? "message"}
|
|
292
|
+
`;
|
|
293
|
+
message += `data: ${JSON.stringify({ channel: opt?.channel, event, data })}
|
|
294
|
+
|
|
295
|
+
`;
|
|
296
|
+
return message;
|
|
297
|
+
}
|
|
317
298
|
startHeartbeat() {
|
|
318
299
|
this.heartbeatTimer = setInterval(() => {
|
|
319
300
|
for (const client of this.clients.values()) {
|
|
320
|
-
client.
|
|
301
|
+
client.send("ping", {});
|
|
321
302
|
}
|
|
322
303
|
}, this.heartbeatInterval);
|
|
323
304
|
}
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/NotifServer.ts"],"names":[],"mappings":"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","file":"server.js","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'http';\n\nexport interface NotifClient {\n id: string;\n userId?: string;\n channels: Set<string>;\n send: (event: string, data: any, options?: { channel?: string; id?: string; sseEvent?: string }) => void;\n sendComment: (comment: string) => void;\n close: () => void;\n meta: Record<string, any>;\n}\n\nexport interface NotifServerOptions {\n /**\n * Heartbeat interval in milliseconds to keep SSE connections open through proxies.\n * Defaults to 20000ms (20s). Set to 0 to disable.\n */\n heartbeatInterval?: number;\n\n /**\n * Optional custom client ID generator.\n */\n generateClientId?: () => string;\n\n /**\n * Debug logging.\n */\n debug?: boolean;\n}\n\nexport interface TriggerOptions {\n id?: string;\n sseEvent?: string;\n}\n\nexport class NotifServer {\n private clients: Map<string, NotifClient> = new Map();\n private heartbeatInterval: number;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private generateClientId: () => string;\n private debug: boolean;\n\n constructor(options: NotifServerOptions = {}) {\n this.heartbeatInterval = options.heartbeatInterval ?? 20000;\n this.debug = options.debug ?? false;\n this.generateClientId =\n options.generateClientId ?? (() => `client_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`);\n\n if (this.heartbeatInterval > 0) {\n this.startHeartbeat();\n }\n }\n\n /**\n * Broadcast an event to one or more channels.\n * Matches Pusher's `pusher.trigger(channel, event, data)` API.\n *\n * Example:\n * ```ts\n * server.trigger('orders', 'order-created', { id: 123, amount: 49.99 });\n * ```\n */\n public trigger(channel: string | string[], event: string, data: any, options?: TriggerOptions): void {\n const channels = Array.isArray(channel) ? channel : [channel];\n\n for (const ch of channels) {\n for (const client of this.clients.values()) {\n if (client.channels.has(ch) || client.channels.has('*')) {\n client.send(event, data, { channel: ch, id: options?.id, sseEvent: options?.sseEvent });\n }\n }\n }\n }\n\n /**\n * Alias for trigger().\n */\n public broadcast(channel: string | string[], event: string, data: any, options?: TriggerOptions): void {\n this.trigger(channel, event, data, options);\n }\n\n /**\n * Send an event directly to a specific client ID.\n */\n public sendToClient(clientId: string, event: string, data: any, options?: TriggerOptions & { channel?: string }): boolean {\n const client = this.clients.get(clientId);\n if (client) {\n client.send(event, data, { channel: options?.channel, id: options?.id, sseEvent: options?.sseEvent });\n return true;\n }\n return false;\n }\n\n /**\n * Send an event to all connected clients belonging to a specific user ID.\n */\n public sendToUser(userId: string, event: string, data: any, options?: TriggerOptions & { channel?: string }): number {\n let count = 0;\n for (const client of this.clients.values()) {\n if (client.userId === userId) {\n client.send(event, data, { channel: options?.channel, id: options?.id, sseEvent: options?.sseEvent });\n count++;\n }\n }\n return count;\n }\n\n /**\n * Subscribe a connected client to a channel.\n */\n public subscribeClient(clientId: string, channel: string): boolean {\n const client = this.clients.get(clientId);\n if (client) {\n client.channels.add(channel);\n this.log(`Client ${clientId} subscribed to \"${channel}\"`);\n return true;\n }\n return false;\n }\n\n /**\n * Unsubscribe a connected client from a channel.\n */\n public unsubscribeClient(clientId: string, channel: string): boolean {\n const client = this.clients.get(clientId);\n if (client) {\n const removed = client.channels.delete(channel);\n this.log(`Client ${clientId} unsubscribed from \"${channel}\"`);\n return removed;\n }\n return false;\n }\n\n /**\n * Get total connected clients count.\n */\n public getClientCount(): number {\n return this.clients.size;\n }\n\n /**\n * Get subscribers count for a specific channel.\n */\n public getSubscribersCount(channel: string): number {\n let count = 0;\n for (const client of this.clients.values()) {\n if (client.channels.has(channel) || client.channels.has('*')) {\n count++;\n }\n }\n return count;\n }\n\n /**\n * Handle incoming HTTP request in Node.js / Express / Fastify environment.\n *\n * Example:\n * ```ts\n * app.get('/sse', (req, res) => {\n * server.handleRequest(req, res);\n * });\n * ```\n */\n public handleRequest(\n req: IncomingMessage,\n res: ServerResponse,\n options?: {\n clientId?: string;\n userId?: string;\n channels?: string[];\n meta?: Record<string, any>;\n }\n ): NotifClient {\n // Set standard SSE HTTP headers\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache, no-transform',\n Connection: 'keep-alive',\n 'X-Accel-Buffering': 'no', // Disable proxy buffering for Nginx\n 'Access-Control-Allow-Origin': '*',\n });\n\n if (typeof (res as any).flushHeaders === 'function') {\n (res as any).flushHeaders();\n }\n\n const clientId = options?.clientId ?? this.generateClientId();\n\n // Parse initial channels from query parameters or options\n const subscribedChannels = new Set<string>(options?.channels ?? []);\n if (req.url) {\n try {\n const url = new URL(req.url, 'http://localhost');\n const queryChannels = url.searchParams.get('channels');\n if (queryChannels) {\n for (const ch of queryChannels.split(',')) {\n const trimmed = ch.trim();\n if (trimmed) subscribedChannels.add(trimmed);\n }\n }\n } catch {}\n }\n\n if (subscribedChannels.size === 0 && !options?.channels) {\n subscribedChannels.add('*');\n }\n\n const client: NotifClient = {\n id: clientId,\n userId: options?.userId,\n channels: subscribedChannels,\n meta: options?.meta ?? {},\n send: (event: string, data: any, opt?: { channel?: string; id?: string; sseEvent?: string }) => {\n try {\n let message = '';\n if (opt?.id) message += `id: ${opt.id}\\n`;\n message += `event: ${opt?.sseEvent ?? 'message'}\\n`;\n\n const payload = {\n channel: opt?.channel,\n event,\n data,\n };\n message += `data: ${JSON.stringify(payload)}\\n\\n`;\n\n res.write(message);\n if (typeof (res as any).flush === 'function') {\n (res as any).flush();\n }\n } catch (err) {\n this.log(`Error writing to client ${clientId}:`, err);\n }\n },\n sendComment: (comment: string) => {\n try {\n res.write(`: ${comment}\\n\\n`);\n if (typeof (res as any).flush === 'function') {\n (res as any).flush();\n }\n } catch {}\n },\n close: () => {\n try {\n res.end();\n } catch {}\n this.removeClient(clientId);\n },\n };\n\n this.clients.set(clientId, client);\n this.log(`Client connected: ${clientId}, channels: [${Array.from(subscribedChannels).join(', ')}]`);\n\n // Send connection established event\n client.send('connected', { clientId });\n\n // Handle connection close\n req.on('close', () => {\n this.removeClient(clientId);\n });\n\n res.on('close', () => {\n this.removeClient(clientId);\n });\n\n return client;\n }\n\n /**\n * Handle Web standard Request (Next.js App Router, Edge runtime, Hono, Cloudflare Workers).\n * Returns a standard `Response` object with a `ReadableStream`.\n *\n * Example:\n * ```ts\n * export function GET(request: Request) {\n * return server.createWebResponse(request);\n * }\n * ```\n */\n public createWebResponse(\n request?: Request,\n options?: {\n clientId?: string;\n userId?: string;\n channels?: string[];\n meta?: Record<string, any>;\n }\n ): Response {\n const clientId = options?.clientId ?? this.generateClientId();\n const subscribedChannels = new Set<string>(options?.channels ?? []);\n\n if (request?.url) {\n try {\n const url = new URL(request.url);\n const queryChannels = url.searchParams.get('channels');\n if (queryChannels) {\n for (const ch of queryChannels.split(',')) {\n const trimmed = ch.trim();\n if (trimmed) subscribedChannels.add(trimmed);\n }\n }\n } catch {}\n }\n\n if (subscribedChannels.size === 0 && !options?.channels) {\n subscribedChannels.add('*');\n }\n\n const encoder = new TextEncoder();\n let controllerRef: ReadableStreamDefaultController<Uint8Array> | null = null;\n\n const stream = new ReadableStream<Uint8Array>({\n start: (controller) => {\n controllerRef = controller;\n\n const client: NotifClient = {\n id: clientId,\n userId: options?.userId,\n channels: subscribedChannels,\n meta: options?.meta ?? {},\n send: (event: string, data: any, opt?: { channel?: string; id?: string; sseEvent?: string }) => {\n try {\n let message = '';\n if (opt?.id) message += `id: ${opt.id}\\n`;\n message += `event: ${opt?.sseEvent ?? 'message'}\\n`;\n\n const payload = {\n channel: opt?.channel,\n event,\n data,\n };\n message += `data: ${JSON.stringify(payload)}\\n\\n`;\n\n controller.enqueue(encoder.encode(message));\n } catch (err) {\n this.log(`Error enqueueing to client ${clientId}:`, err);\n }\n },\n sendComment: (comment: string) => {\n try {\n controller.enqueue(encoder.encode(`: ${comment}\\n\\n`));\n } catch {}\n },\n close: () => {\n try {\n controller.close();\n } catch {}\n this.removeClient(clientId);\n },\n };\n\n this.clients.set(clientId, client);\n this.log(`Web client connected: ${clientId}`);\n\n // Send connection handshake\n client.send('connected', { clientId });\n },\n cancel: () => {\n this.removeClient(clientId);\n },\n });\n\n return new Response(stream, {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache, no-transform',\n Connection: 'keep-alive',\n 'Access-Control-Allow-Origin': '*',\n },\n });\n }\n\n /**\n * Stop the server heartbeat and disconnect all clients.\n */\n public close(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n\n for (const client of this.clients.values()) {\n client.close();\n }\n this.clients.clear();\n }\n\n private removeClient(clientId: string): void {\n if (this.clients.has(clientId)) {\n this.clients.delete(clientId);\n this.log(`Client disconnected: ${clientId}`);\n }\n }\n\n private startHeartbeat(): void {\n this.heartbeatTimer = setInterval(() => {\n for (const client of this.clients.values()) {\n client.sendComment('ping');\n }\n }, this.heartbeatInterval);\n }\n\n private log(...args: any[]): void {\n if (this.debug) {\n console.log('[notif-agent:server]', ...args);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/server/NotifServer.ts"],"names":[],"mappings":"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","file":"server.js","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'http';\n\nexport interface NotifClient {\n id: string;\n userId?: string;\n channels: Set<string>;\n send: (event: string, data: any, options?: { channel?: string; id?: string; sseEvent?: string }) => void;\n sendComment: (comment: string) => void;\n close: () => void;\n meta: Record<string, any>;\n}\n\nexport interface NotifServerOptions {\n /**\n * Heartbeat interval in milliseconds to keep SSE connections open through proxies.\n * Defaults to 20000ms (20s). Set to 0 to disable.\n */\n heartbeatInterval?: number;\n\n /**\n * Optional custom client ID generator.\n */\n generateClientId?: () => string;\n\n /**\n * Debug logging.\n */\n debug?: boolean;\n}\n\nexport interface TriggerOptions {\n id?: string;\n sseEvent?: string;\n}\n\nconst isPrivate = (ch: string) => ch.startsWith('private-') || ch.startsWith('presence-');\n\n// A client whose unread buffer grows past this is dropped instead of buffering forever.\nconst MAX_BUFFERED_BYTES = 1024 * 1024;\n\nexport class NotifServer {\n private clients: Map<string, NotifClient> = new Map();\n private heartbeatInterval: number;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private generateClientId: () => string;\n private debug: boolean;\n\n constructor(options: NotifServerOptions = {}) {\n this.heartbeatInterval = options.heartbeatInterval ?? 20000;\n this.debug = options.debug ?? false;\n this.generateClientId =\n options.generateClientId ?? (() => `client_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`);\n\n if (this.heartbeatInterval > 0) {\n this.startHeartbeat();\n }\n }\n\n /**\n * Broadcast an event to one or more channels.\n * Matches Pusher's `pusher.trigger(channel, event, data)` API.\n *\n * Example:\n * ```ts\n * server.trigger('orders', 'order-created', { id: 123, amount: 49.99 });\n * ```\n */\n public trigger(channel: string | string[], event: string, data: any, options?: TriggerOptions): void {\n const channels = Array.isArray(channel) ? channel : [channel];\n\n for (const ch of channels) {\n for (const client of this.clients.values()) {\n if (this.isSubscribed(client, ch)) {\n client.send(event, data, { channel: ch, id: options?.id, sseEvent: options?.sseEvent });\n }\n }\n }\n }\n\n /**\n * Alias for trigger().\n */\n public broadcast(channel: string | string[], event: string, data: any, options?: TriggerOptions): void {\n this.trigger(channel, event, data, options);\n }\n\n /**\n * Send an event directly to a specific client ID.\n */\n public sendToClient(clientId: string, event: string, data: any, options?: TriggerOptions & { channel?: string }): boolean {\n const client = this.clients.get(clientId);\n if (client) {\n client.send(event, data, { channel: options?.channel, id: options?.id, sseEvent: options?.sseEvent });\n return true;\n }\n return false;\n }\n\n /**\n * Send an event to all connected clients belonging to a specific user ID.\n */\n public sendToUser(userId: string, event: string, data: any, options?: TriggerOptions & { channel?: string }): number {\n let count = 0;\n for (const client of this.clients.values()) {\n if (client.userId === userId) {\n client.send(event, data, { channel: options?.channel, id: options?.id, sseEvent: options?.sseEvent });\n count++;\n }\n }\n return count;\n }\n\n /**\n * Subscribe a connected client to a channel.\n */\n public subscribeClient(clientId: string, channel: string): boolean {\n const client = this.clients.get(clientId);\n if (client) {\n client.channels.add(channel);\n this.log(`Client ${clientId} subscribed to \"${channel}\"`);\n return true;\n }\n return false;\n }\n\n /**\n * Unsubscribe a connected client from a channel.\n */\n public unsubscribeClient(clientId: string, channel: string): boolean {\n const client = this.clients.get(clientId);\n if (client) {\n const removed = client.channels.delete(channel);\n this.log(`Client ${clientId} unsubscribed from \"${channel}\"`);\n return removed;\n }\n return false;\n }\n\n /**\n * Get total connected clients count.\n */\n public getClientCount(): number {\n return this.clients.size;\n }\n\n /**\n * Get subscribers count for a specific channel.\n */\n public getSubscribersCount(channel: string): number {\n let count = 0;\n for (const client of this.clients.values()) {\n if (this.isSubscribed(client, channel)) {\n count++;\n }\n }\n return count;\n }\n\n /**\n * Handle incoming HTTP request in Node.js / Express / Fastify environment.\n *\n * Example:\n * ```ts\n * app.get('/sse', (req, res) => {\n * server.handleRequest(req, res);\n * });\n * ```\n */\n public handleRequest(\n req: IncomingMessage,\n res: ServerResponse,\n options?: {\n clientId?: string;\n userId?: string;\n channels?: string[];\n meta?: Record<string, any>;\n }\n ): NotifClient {\n // Set standard SSE HTTP headers\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache, no-transform',\n Connection: 'keep-alive',\n 'X-Accel-Buffering': 'no', // Disable proxy buffering for Nginx\n });\n\n if (typeof (res as any).flushHeaders === 'function') {\n (res as any).flushHeaders();\n }\n\n const clientId = options?.clientId ?? this.generateClientId();\n const subscribedChannels = this.resolveChannels(req.url, options?.channels);\n\n const write = (chunk: string) => {\n const ok = res.write(chunk);\n if (typeof (res as any).flush === 'function') {\n (res as any).flush();\n }\n if (!ok && res.writableLength > MAX_BUFFERED_BYTES) {\n this.log(`Client ${clientId} too slow, dropping`);\n client.close();\n }\n };\n\n const client: NotifClient = {\n id: clientId,\n userId: options?.userId,\n channels: subscribedChannels,\n meta: options?.meta ?? {},\n send: (event, data, opt) => {\n try {\n write(this.formatMessage(event, data, opt));\n } catch (err) {\n this.log(`Error writing to client ${clientId}:`, err);\n }\n },\n sendComment: (comment: string) => {\n try {\n write(`: ${comment}\\n\\n`);\n } catch {}\n },\n close: () => {\n try {\n res.end();\n } catch {}\n this.removeClient(clientId);\n },\n };\n\n this.clients.set(clientId, client);\n this.log(`Client connected: ${clientId}, channels: [${Array.from(subscribedChannels).join(', ')}]`);\n\n // Send connection established event\n client.send('connected', { clientId });\n\n // Handle connection close\n req.on('close', () => {\n this.removeClient(clientId);\n });\n\n res.on('close', () => {\n this.removeClient(clientId);\n });\n\n return client;\n }\n\n /**\n * Handle Web standard Request (Next.js App Router, Edge runtime, Hono, Cloudflare Workers).\n * Returns a standard `Response` object with a `ReadableStream`.\n *\n * Example:\n * ```ts\n * export function GET(request: Request) {\n * return server.createWebResponse(request);\n * }\n * ```\n */\n public createWebResponse(\n request?: Request,\n options?: {\n clientId?: string;\n userId?: string;\n channels?: string[];\n meta?: Record<string, any>;\n }\n ): Response {\n const clientId = options?.clientId ?? this.generateClientId();\n const subscribedChannels = this.resolveChannels(request?.url, options?.channels);\n\n const encoder = new TextEncoder();\n let controllerRef: ReadableStreamDefaultController<Uint8Array> | null = null;\n\n const stream = new ReadableStream<Uint8Array>({\n start: (controller) => {\n controllerRef = controller;\n\n const client: NotifClient = {\n id: clientId,\n userId: options?.userId,\n channels: subscribedChannels,\n meta: options?.meta ?? {},\n send: (event, data, opt) => {\n try {\n controller.enqueue(encoder.encode(this.formatMessage(event, data, opt)));\n } catch (err) {\n this.log(`Error enqueueing to client ${clientId}:`, err);\n }\n },\n sendComment: (comment: string) => {\n try {\n controller.enqueue(encoder.encode(`: ${comment}\\n\\n`));\n } catch {}\n },\n close: () => {\n try {\n controller.close();\n } catch {}\n this.removeClient(clientId);\n },\n };\n\n this.clients.set(clientId, client);\n this.log(`Web client connected: ${clientId}`);\n\n // Send connection handshake\n client.send('connected', { clientId });\n },\n cancel: () => {\n this.removeClient(clientId);\n },\n });\n\n return new Response(stream, {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache, no-transform',\n Connection: 'keep-alive',\n },\n });\n }\n\n /**\n * Stop the server heartbeat and disconnect all clients.\n */\n public close(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n\n for (const client of this.clients.values()) {\n client.close();\n }\n this.clients.clear();\n }\n\n private removeClient(clientId: string): void {\n if (this.clients.has(clientId)) {\n this.clients.delete(clientId);\n this.log(`Client disconnected: ${clientId}`);\n }\n }\n\n /**\n * App-given channels are final; the URL can only add public channels when the app gave none.\n * `*` (all public channels) is the default when neither names any.\n */\n private resolveChannels(rawUrl: string | undefined, allowed?: string[]): Set<string> {\n if (allowed) return new Set(allowed);\n\n const channels = new Set<string>();\n if (rawUrl) {\n try {\n const query = new URL(rawUrl, 'http://localhost').searchParams.get('channels') ?? '';\n for (const ch of query.split(',')) {\n const trimmed = ch.trim();\n if (trimmed && !isPrivate(trimmed)) channels.add(trimmed);\n }\n } catch {}\n }\n\n if (channels.size === 0) channels.add('*');\n return channels;\n }\n\n /** `*` never covers private channels; those need an explicit grant (options.channels or subscribeClient). */\n private isSubscribed(client: NotifClient, channel: string): boolean {\n return client.channels.has(channel) || (client.channels.has('*') && !isPrivate(channel));\n }\n\n private formatMessage(event: string, data: any, opt?: { channel?: string; id?: string; sseEvent?: string }): string {\n let message = '';\n if (opt?.id) message += `id: ${opt.id}\\n`;\n message += `event: ${opt?.sseEvent ?? 'message'}\\n`;\n message += `data: ${JSON.stringify({ channel: opt?.channel, event, data })}\\n\\n`;\n return message;\n }\n\n private startHeartbeat(): void {\n // A real event, not an SSE comment: browser EventSource never surfaces comments,\n // so the client's heartbeat timeout would fire on every quiet connection.\n this.heartbeatTimer = setInterval(() => {\n for (const client of this.clients.values()) {\n client.send('ping', {});\n }\n }, this.heartbeatInterval);\n }\n\n private log(...args: any[]): void {\n if (this.debug) {\n console.log('[notif-agent:server]', ...args);\n }\n }\n}\n"]}
|
package/dist/server.mjs
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// src/server/NotifServer.ts
|
|
2
|
+
var isPrivate = (ch) => ch.startsWith("private-") || ch.startsWith("presence-");
|
|
3
|
+
var MAX_BUFFERED_BYTES = 1024 * 1024;
|
|
2
4
|
var NotifServer = class {
|
|
3
5
|
clients = /* @__PURE__ */ new Map();
|
|
4
6
|
heartbeatInterval;
|
|
@@ -26,7 +28,7 @@ var NotifServer = class {
|
|
|
26
28
|
const channels = Array.isArray(channel) ? channel : [channel];
|
|
27
29
|
for (const ch of channels) {
|
|
28
30
|
for (const client of this.clients.values()) {
|
|
29
|
-
if (
|
|
31
|
+
if (this.isSubscribed(client, ch)) {
|
|
30
32
|
client.send(event, data, { channel: ch, id: options?.id, sseEvent: options?.sseEvent });
|
|
31
33
|
}
|
|
32
34
|
}
|
|
@@ -98,7 +100,7 @@ var NotifServer = class {
|
|
|
98
100
|
getSubscribersCount(channel) {
|
|
99
101
|
let count = 0;
|
|
100
102
|
for (const client of this.clients.values()) {
|
|
101
|
-
if (
|
|
103
|
+
if (this.isSubscribed(client, channel)) {
|
|
102
104
|
count++;
|
|
103
105
|
}
|
|
104
106
|
}
|
|
@@ -119,31 +121,24 @@ var NotifServer = class {
|
|
|
119
121
|
"Content-Type": "text/event-stream",
|
|
120
122
|
"Cache-Control": "no-cache, no-transform",
|
|
121
123
|
Connection: "keep-alive",
|
|
122
|
-
"X-Accel-Buffering": "no"
|
|
124
|
+
"X-Accel-Buffering": "no"
|
|
123
125
|
// Disable proxy buffering for Nginx
|
|
124
|
-
"Access-Control-Allow-Origin": "*"
|
|
125
126
|
});
|
|
126
127
|
if (typeof res.flushHeaders === "function") {
|
|
127
128
|
res.flushHeaders();
|
|
128
129
|
}
|
|
129
130
|
const clientId = options?.clientId ?? this.generateClientId();
|
|
130
|
-
const subscribedChannels =
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (queryChannels) {
|
|
136
|
-
for (const ch of queryChannels.split(",")) {
|
|
137
|
-
const trimmed = ch.trim();
|
|
138
|
-
if (trimmed) subscribedChannels.add(trimmed);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
} catch {
|
|
131
|
+
const subscribedChannels = this.resolveChannels(req.url, options?.channels);
|
|
132
|
+
const write = (chunk) => {
|
|
133
|
+
const ok = res.write(chunk);
|
|
134
|
+
if (typeof res.flush === "function") {
|
|
135
|
+
res.flush();
|
|
142
136
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
137
|
+
if (!ok && res.writableLength > MAX_BUFFERED_BYTES) {
|
|
138
|
+
this.log(`Client ${clientId} too slow, dropping`);
|
|
139
|
+
client.close();
|
|
140
|
+
}
|
|
141
|
+
};
|
|
147
142
|
const client = {
|
|
148
143
|
id: clientId,
|
|
149
144
|
userId: options?.userId,
|
|
@@ -151,35 +146,16 @@ var NotifServer = class {
|
|
|
151
146
|
meta: options?.meta ?? {},
|
|
152
147
|
send: (event, data, opt) => {
|
|
153
148
|
try {
|
|
154
|
-
|
|
155
|
-
if (opt?.id) message += `id: ${opt.id}
|
|
156
|
-
`;
|
|
157
|
-
message += `event: ${opt?.sseEvent ?? "message"}
|
|
158
|
-
`;
|
|
159
|
-
const payload = {
|
|
160
|
-
channel: opt?.channel,
|
|
161
|
-
event,
|
|
162
|
-
data
|
|
163
|
-
};
|
|
164
|
-
message += `data: ${JSON.stringify(payload)}
|
|
165
|
-
|
|
166
|
-
`;
|
|
167
|
-
res.write(message);
|
|
168
|
-
if (typeof res.flush === "function") {
|
|
169
|
-
res.flush();
|
|
170
|
-
}
|
|
149
|
+
write(this.formatMessage(event, data, opt));
|
|
171
150
|
} catch (err) {
|
|
172
151
|
this.log(`Error writing to client ${clientId}:`, err);
|
|
173
152
|
}
|
|
174
153
|
},
|
|
175
154
|
sendComment: (comment) => {
|
|
176
155
|
try {
|
|
177
|
-
|
|
156
|
+
write(`: ${comment}
|
|
178
157
|
|
|
179
158
|
`);
|
|
180
|
-
if (typeof res.flush === "function") {
|
|
181
|
-
res.flush();
|
|
182
|
-
}
|
|
183
159
|
} catch {
|
|
184
160
|
}
|
|
185
161
|
},
|
|
@@ -215,23 +191,7 @@ var NotifServer = class {
|
|
|
215
191
|
*/
|
|
216
192
|
createWebResponse(request, options) {
|
|
217
193
|
const clientId = options?.clientId ?? this.generateClientId();
|
|
218
|
-
const subscribedChannels =
|
|
219
|
-
if (request?.url) {
|
|
220
|
-
try {
|
|
221
|
-
const url = new URL(request.url);
|
|
222
|
-
const queryChannels = url.searchParams.get("channels");
|
|
223
|
-
if (queryChannels) {
|
|
224
|
-
for (const ch of queryChannels.split(",")) {
|
|
225
|
-
const trimmed = ch.trim();
|
|
226
|
-
if (trimmed) subscribedChannels.add(trimmed);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
} catch {
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
if (subscribedChannels.size === 0 && !options?.channels) {
|
|
233
|
-
subscribedChannels.add("*");
|
|
234
|
-
}
|
|
194
|
+
const subscribedChannels = this.resolveChannels(request?.url, options?.channels);
|
|
235
195
|
const encoder = new TextEncoder();
|
|
236
196
|
const stream = new ReadableStream({
|
|
237
197
|
start: (controller) => {
|
|
@@ -242,20 +202,7 @@ var NotifServer = class {
|
|
|
242
202
|
meta: options?.meta ?? {},
|
|
243
203
|
send: (event, data, opt) => {
|
|
244
204
|
try {
|
|
245
|
-
|
|
246
|
-
if (opt?.id) message += `id: ${opt.id}
|
|
247
|
-
`;
|
|
248
|
-
message += `event: ${opt?.sseEvent ?? "message"}
|
|
249
|
-
`;
|
|
250
|
-
const payload = {
|
|
251
|
-
channel: opt?.channel,
|
|
252
|
-
event,
|
|
253
|
-
data
|
|
254
|
-
};
|
|
255
|
-
message += `data: ${JSON.stringify(payload)}
|
|
256
|
-
|
|
257
|
-
`;
|
|
258
|
-
controller.enqueue(encoder.encode(message));
|
|
205
|
+
controller.enqueue(encoder.encode(this.formatMessage(event, data, opt)));
|
|
259
206
|
} catch (err) {
|
|
260
207
|
this.log(`Error enqueueing to client ${clientId}:`, err);
|
|
261
208
|
}
|
|
@@ -288,8 +235,7 @@ var NotifServer = class {
|
|
|
288
235
|
headers: {
|
|
289
236
|
"Content-Type": "text/event-stream",
|
|
290
237
|
"Cache-Control": "no-cache, no-transform",
|
|
291
|
-
Connection: "keep-alive"
|
|
292
|
-
"Access-Control-Allow-Origin": "*"
|
|
238
|
+
Connection: "keep-alive"
|
|
293
239
|
}
|
|
294
240
|
});
|
|
295
241
|
}
|
|
@@ -312,10 +258,45 @@ var NotifServer = class {
|
|
|
312
258
|
this.log(`Client disconnected: ${clientId}`);
|
|
313
259
|
}
|
|
314
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* App-given channels are final; the URL can only add public channels when the app gave none.
|
|
263
|
+
* `*` (all public channels) is the default when neither names any.
|
|
264
|
+
*/
|
|
265
|
+
resolveChannels(rawUrl, allowed) {
|
|
266
|
+
if (allowed) return new Set(allowed);
|
|
267
|
+
const channels = /* @__PURE__ */ new Set();
|
|
268
|
+
if (rawUrl) {
|
|
269
|
+
try {
|
|
270
|
+
const query = new URL(rawUrl, "http://localhost").searchParams.get("channels") ?? "";
|
|
271
|
+
for (const ch of query.split(",")) {
|
|
272
|
+
const trimmed = ch.trim();
|
|
273
|
+
if (trimmed && !isPrivate(trimmed)) channels.add(trimmed);
|
|
274
|
+
}
|
|
275
|
+
} catch {
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (channels.size === 0) channels.add("*");
|
|
279
|
+
return channels;
|
|
280
|
+
}
|
|
281
|
+
/** `*` never covers private channels; those need an explicit grant (options.channels or subscribeClient). */
|
|
282
|
+
isSubscribed(client, channel) {
|
|
283
|
+
return client.channels.has(channel) || client.channels.has("*") && !isPrivate(channel);
|
|
284
|
+
}
|
|
285
|
+
formatMessage(event, data, opt) {
|
|
286
|
+
let message = "";
|
|
287
|
+
if (opt?.id) message += `id: ${opt.id}
|
|
288
|
+
`;
|
|
289
|
+
message += `event: ${opt?.sseEvent ?? "message"}
|
|
290
|
+
`;
|
|
291
|
+
message += `data: ${JSON.stringify({ channel: opt?.channel, event, data })}
|
|
292
|
+
|
|
293
|
+
`;
|
|
294
|
+
return message;
|
|
295
|
+
}
|
|
315
296
|
startHeartbeat() {
|
|
316
297
|
this.heartbeatTimer = setInterval(() => {
|
|
317
298
|
for (const client of this.clients.values()) {
|
|
318
|
-
client.
|
|
299
|
+
client.send("ping", {});
|
|
319
300
|
}
|
|
320
301
|
}, this.heartbeatInterval);
|
|
321
302
|
}
|
package/dist/server.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/NotifServer.ts"],"names":[],"mappings":"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","file":"server.mjs","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'http';\n\nexport interface NotifClient {\n id: string;\n userId?: string;\n channels: Set<string>;\n send: (event: string, data: any, options?: { channel?: string; id?: string; sseEvent?: string }) => void;\n sendComment: (comment: string) => void;\n close: () => void;\n meta: Record<string, any>;\n}\n\nexport interface NotifServerOptions {\n /**\n * Heartbeat interval in milliseconds to keep SSE connections open through proxies.\n * Defaults to 20000ms (20s). Set to 0 to disable.\n */\n heartbeatInterval?: number;\n\n /**\n * Optional custom client ID generator.\n */\n generateClientId?: () => string;\n\n /**\n * Debug logging.\n */\n debug?: boolean;\n}\n\nexport interface TriggerOptions {\n id?: string;\n sseEvent?: string;\n}\n\nexport class NotifServer {\n private clients: Map<string, NotifClient> = new Map();\n private heartbeatInterval: number;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private generateClientId: () => string;\n private debug: boolean;\n\n constructor(options: NotifServerOptions = {}) {\n this.heartbeatInterval = options.heartbeatInterval ?? 20000;\n this.debug = options.debug ?? false;\n this.generateClientId =\n options.generateClientId ?? (() => `client_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`);\n\n if (this.heartbeatInterval > 0) {\n this.startHeartbeat();\n }\n }\n\n /**\n * Broadcast an event to one or more channels.\n * Matches Pusher's `pusher.trigger(channel, event, data)` API.\n *\n * Example:\n * ```ts\n * server.trigger('orders', 'order-created', { id: 123, amount: 49.99 });\n * ```\n */\n public trigger(channel: string | string[], event: string, data: any, options?: TriggerOptions): void {\n const channels = Array.isArray(channel) ? channel : [channel];\n\n for (const ch of channels) {\n for (const client of this.clients.values()) {\n if (client.channels.has(ch) || client.channels.has('*')) {\n client.send(event, data, { channel: ch, id: options?.id, sseEvent: options?.sseEvent });\n }\n }\n }\n }\n\n /**\n * Alias for trigger().\n */\n public broadcast(channel: string | string[], event: string, data: any, options?: TriggerOptions): void {\n this.trigger(channel, event, data, options);\n }\n\n /**\n * Send an event directly to a specific client ID.\n */\n public sendToClient(clientId: string, event: string, data: any, options?: TriggerOptions & { channel?: string }): boolean {\n const client = this.clients.get(clientId);\n if (client) {\n client.send(event, data, { channel: options?.channel, id: options?.id, sseEvent: options?.sseEvent });\n return true;\n }\n return false;\n }\n\n /**\n * Send an event to all connected clients belonging to a specific user ID.\n */\n public sendToUser(userId: string, event: string, data: any, options?: TriggerOptions & { channel?: string }): number {\n let count = 0;\n for (const client of this.clients.values()) {\n if (client.userId === userId) {\n client.send(event, data, { channel: options?.channel, id: options?.id, sseEvent: options?.sseEvent });\n count++;\n }\n }\n return count;\n }\n\n /**\n * Subscribe a connected client to a channel.\n */\n public subscribeClient(clientId: string, channel: string): boolean {\n const client = this.clients.get(clientId);\n if (client) {\n client.channels.add(channel);\n this.log(`Client ${clientId} subscribed to \"${channel}\"`);\n return true;\n }\n return false;\n }\n\n /**\n * Unsubscribe a connected client from a channel.\n */\n public unsubscribeClient(clientId: string, channel: string): boolean {\n const client = this.clients.get(clientId);\n if (client) {\n const removed = client.channels.delete(channel);\n this.log(`Client ${clientId} unsubscribed from \"${channel}\"`);\n return removed;\n }\n return false;\n }\n\n /**\n * Get total connected clients count.\n */\n public getClientCount(): number {\n return this.clients.size;\n }\n\n /**\n * Get subscribers count for a specific channel.\n */\n public getSubscribersCount(channel: string): number {\n let count = 0;\n for (const client of this.clients.values()) {\n if (client.channels.has(channel) || client.channels.has('*')) {\n count++;\n }\n }\n return count;\n }\n\n /**\n * Handle incoming HTTP request in Node.js / Express / Fastify environment.\n *\n * Example:\n * ```ts\n * app.get('/sse', (req, res) => {\n * server.handleRequest(req, res);\n * });\n * ```\n */\n public handleRequest(\n req: IncomingMessage,\n res: ServerResponse,\n options?: {\n clientId?: string;\n userId?: string;\n channels?: string[];\n meta?: Record<string, any>;\n }\n ): NotifClient {\n // Set standard SSE HTTP headers\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache, no-transform',\n Connection: 'keep-alive',\n 'X-Accel-Buffering': 'no', // Disable proxy buffering for Nginx\n 'Access-Control-Allow-Origin': '*',\n });\n\n if (typeof (res as any).flushHeaders === 'function') {\n (res as any).flushHeaders();\n }\n\n const clientId = options?.clientId ?? this.generateClientId();\n\n // Parse initial channels from query parameters or options\n const subscribedChannels = new Set<string>(options?.channels ?? []);\n if (req.url) {\n try {\n const url = new URL(req.url, 'http://localhost');\n const queryChannels = url.searchParams.get('channels');\n if (queryChannels) {\n for (const ch of queryChannels.split(',')) {\n const trimmed = ch.trim();\n if (trimmed) subscribedChannels.add(trimmed);\n }\n }\n } catch {}\n }\n\n if (subscribedChannels.size === 0 && !options?.channels) {\n subscribedChannels.add('*');\n }\n\n const client: NotifClient = {\n id: clientId,\n userId: options?.userId,\n channels: subscribedChannels,\n meta: options?.meta ?? {},\n send: (event: string, data: any, opt?: { channel?: string; id?: string; sseEvent?: string }) => {\n try {\n let message = '';\n if (opt?.id) message += `id: ${opt.id}\\n`;\n message += `event: ${opt?.sseEvent ?? 'message'}\\n`;\n\n const payload = {\n channel: opt?.channel,\n event,\n data,\n };\n message += `data: ${JSON.stringify(payload)}\\n\\n`;\n\n res.write(message);\n if (typeof (res as any).flush === 'function') {\n (res as any).flush();\n }\n } catch (err) {\n this.log(`Error writing to client ${clientId}:`, err);\n }\n },\n sendComment: (comment: string) => {\n try {\n res.write(`: ${comment}\\n\\n`);\n if (typeof (res as any).flush === 'function') {\n (res as any).flush();\n }\n } catch {}\n },\n close: () => {\n try {\n res.end();\n } catch {}\n this.removeClient(clientId);\n },\n };\n\n this.clients.set(clientId, client);\n this.log(`Client connected: ${clientId}, channels: [${Array.from(subscribedChannels).join(', ')}]`);\n\n // Send connection established event\n client.send('connected', { clientId });\n\n // Handle connection close\n req.on('close', () => {\n this.removeClient(clientId);\n });\n\n res.on('close', () => {\n this.removeClient(clientId);\n });\n\n return client;\n }\n\n /**\n * Handle Web standard Request (Next.js App Router, Edge runtime, Hono, Cloudflare Workers).\n * Returns a standard `Response` object with a `ReadableStream`.\n *\n * Example:\n * ```ts\n * export function GET(request: Request) {\n * return server.createWebResponse(request);\n * }\n * ```\n */\n public createWebResponse(\n request?: Request,\n options?: {\n clientId?: string;\n userId?: string;\n channels?: string[];\n meta?: Record<string, any>;\n }\n ): Response {\n const clientId = options?.clientId ?? this.generateClientId();\n const subscribedChannels = new Set<string>(options?.channels ?? []);\n\n if (request?.url) {\n try {\n const url = new URL(request.url);\n const queryChannels = url.searchParams.get('channels');\n if (queryChannels) {\n for (const ch of queryChannels.split(',')) {\n const trimmed = ch.trim();\n if (trimmed) subscribedChannels.add(trimmed);\n }\n }\n } catch {}\n }\n\n if (subscribedChannels.size === 0 && !options?.channels) {\n subscribedChannels.add('*');\n }\n\n const encoder = new TextEncoder();\n let controllerRef: ReadableStreamDefaultController<Uint8Array> | null = null;\n\n const stream = new ReadableStream<Uint8Array>({\n start: (controller) => {\n controllerRef = controller;\n\n const client: NotifClient = {\n id: clientId,\n userId: options?.userId,\n channels: subscribedChannels,\n meta: options?.meta ?? {},\n send: (event: string, data: any, opt?: { channel?: string; id?: string; sseEvent?: string }) => {\n try {\n let message = '';\n if (opt?.id) message += `id: ${opt.id}\\n`;\n message += `event: ${opt?.sseEvent ?? 'message'}\\n`;\n\n const payload = {\n channel: opt?.channel,\n event,\n data,\n };\n message += `data: ${JSON.stringify(payload)}\\n\\n`;\n\n controller.enqueue(encoder.encode(message));\n } catch (err) {\n this.log(`Error enqueueing to client ${clientId}:`, err);\n }\n },\n sendComment: (comment: string) => {\n try {\n controller.enqueue(encoder.encode(`: ${comment}\\n\\n`));\n } catch {}\n },\n close: () => {\n try {\n controller.close();\n } catch {}\n this.removeClient(clientId);\n },\n };\n\n this.clients.set(clientId, client);\n this.log(`Web client connected: ${clientId}`);\n\n // Send connection handshake\n client.send('connected', { clientId });\n },\n cancel: () => {\n this.removeClient(clientId);\n },\n });\n\n return new Response(stream, {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache, no-transform',\n Connection: 'keep-alive',\n 'Access-Control-Allow-Origin': '*',\n },\n });\n }\n\n /**\n * Stop the server heartbeat and disconnect all clients.\n */\n public close(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n\n for (const client of this.clients.values()) {\n client.close();\n }\n this.clients.clear();\n }\n\n private removeClient(clientId: string): void {\n if (this.clients.has(clientId)) {\n this.clients.delete(clientId);\n this.log(`Client disconnected: ${clientId}`);\n }\n }\n\n private startHeartbeat(): void {\n this.heartbeatTimer = setInterval(() => {\n for (const client of this.clients.values()) {\n client.sendComment('ping');\n }\n }, this.heartbeatInterval);\n }\n\n private log(...args: any[]): void {\n if (this.debug) {\n console.log('[notif-agent:server]', ...args);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/server/NotifServer.ts"],"names":[],"mappings":";AAmCA,IAAM,SAAA,GAAY,CAAC,EAAA,KAAe,EAAA,CAAG,WAAW,UAAU,CAAA,IAAK,EAAA,CAAG,UAAA,CAAW,WAAW,CAAA;AAGxF,IAAM,qBAAqB,IAAA,GAAO,IAAA;AAE3B,IAAM,cAAN,MAAkB;AAAA,EACf,OAAA,uBAAwC,GAAA,EAAI;AAAA,EAC5C,iBAAA;AAAA,EACA,cAAA,GAAwD,IAAA;AAAA,EACxD,gBAAA;AAAA,EACA,KAAA;AAAA,EAER,WAAA,CAAY,OAAA,GAA8B,EAAC,EAAG;AAC5C,IAAA,IAAA,CAAK,iBAAA,GAAoB,QAAQ,iBAAA,IAAqB,GAAA;AACtD,IAAA,IAAA,CAAK,KAAA,GAAQ,QAAQ,KAAA,IAAS,KAAA;AAC9B,IAAA,IAAA,CAAK,mBACH,OAAA,CAAQ,gBAAA,KAAqB,MAAM,CAAA,OAAA,EAAU,IAAA,CAAK,KAAK,CAAA,CAAA,EAAI,IAAA,CAAK,MAAA,GAAS,QAAA,CAAS,EAAE,EAAE,SAAA,CAAU,CAAA,EAAG,CAAC,CAAC,CAAA,CAAA,CAAA;AAEvG,IAAA,IAAI,IAAA,CAAK,oBAAoB,CAAA,EAAG;AAC9B,MAAA,IAAA,CAAK,cAAA,EAAe;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWO,OAAA,CAAQ,OAAA,EAA4B,KAAA,EAAe,IAAA,EAAW,OAAA,EAAgC;AACnG,IAAA,MAAM,WAAW,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,GAAI,OAAA,GAAU,CAAC,OAAO,CAAA;AAE5D,IAAA,KAAA,MAAW,MAAM,QAAA,EAAU;AACzB,MAAA,KAAA,MAAW,MAAA,IAAU,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAO,EAAG;AAC1C,QAAA,IAAI,IAAA,CAAK,YAAA,CAAa,MAAA,EAAQ,EAAE,CAAA,EAAG;AACjC,UAAA,MAAA,CAAO,IAAA,CAAK,KAAA,EAAO,IAAA,EAAM,EAAE,OAAA,EAAS,EAAA,EAAI,EAAA,EAAI,OAAA,EAAS,EAAA,EAAI,QAAA,EAAU,OAAA,EAAS,QAAA,EAAU,CAAA;AAAA,QACxF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKO,SAAA,CAAU,OAAA,EAA4B,KAAA,EAAe,IAAA,EAAW,OAAA,EAAgC;AACrG,IAAA,IAAA,CAAK,OAAA,CAAQ,OAAA,EAAS,KAAA,EAAO,IAAA,EAAM,OAAO,CAAA;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKO,YAAA,CAAa,QAAA,EAAkB,KAAA,EAAe,IAAA,EAAW,OAAA,EAA0D;AACxH,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AACxC,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAA,CAAO,IAAA,CAAK,KAAA,EAAO,IAAA,EAAM,EAAE,OAAA,EAAS,OAAA,EAAS,OAAA,EAAS,EAAA,EAAI,OAAA,EAAS,EAAA,EAAI,QAAA,EAAU,OAAA,EAAS,UAAU,CAAA;AACpG,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKO,UAAA,CAAW,MAAA,EAAgB,KAAA,EAAe,IAAA,EAAW,OAAA,EAAyD;AACnH,IAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,IAAA,KAAA,MAAW,MAAA,IAAU,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAO,EAAG;AAC1C,MAAA,IAAI,MAAA,CAAO,WAAW,MAAA,EAAQ;AAC5B,QAAA,MAAA,CAAO,IAAA,CAAK,KAAA,EAAO,IAAA,EAAM,EAAE,OAAA,EAAS,OAAA,EAAS,OAAA,EAAS,EAAA,EAAI,OAAA,EAAS,EAAA,EAAI,QAAA,EAAU,OAAA,EAAS,UAAU,CAAA;AACpG,QAAA,KAAA,EAAA;AAAA,MACF;AAAA,IACF;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKO,eAAA,CAAgB,UAAkB,OAAA,EAA0B;AACjE,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AACxC,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAA,CAAO,QAAA,CAAS,IAAI,OAAO,CAAA;AAC3B,MAAA,IAAA,CAAK,GAAA,CAAI,CAAA,OAAA,EAAU,QAAQ,CAAA,gBAAA,EAAmB,OAAO,CAAA,CAAA,CAAG,CAAA;AACxD,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKO,iBAAA,CAAkB,UAAkB,OAAA,EAA0B;AACnE,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AACxC,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAM,OAAA,GAAU,MAAA,CAAO,QAAA,CAAS,MAAA,CAAO,OAAO,CAAA;AAC9C,MAAA,IAAA,CAAK,GAAA,CAAI,CAAA,OAAA,EAAU,QAAQ,CAAA,oBAAA,EAAuB,OAAO,CAAA,CAAA,CAAG,CAAA;AAC5D,MAAA,OAAO,OAAA;AAAA,IACT;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKO,cAAA,GAAyB;AAC9B,IAAA,OAAO,KAAK,OAAA,CAAQ,IAAA;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKO,oBAAoB,OAAA,EAAyB;AAClD,IAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,IAAA,KAAA,MAAW,MAAA,IAAU,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAO,EAAG;AAC1C,MAAA,IAAI,IAAA,CAAK,YAAA,CAAa,MAAA,EAAQ,OAAO,CAAA,EAAG;AACtC,QAAA,KAAA,EAAA;AAAA,MACF;AAAA,IACF;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYO,aAAA,CACL,GAAA,EACA,GAAA,EACA,OAAA,EAMa;AAEb,IAAA,GAAA,CAAI,UAAU,GAAA,EAAK;AAAA,MACjB,cAAA,EAAgB,mBAAA;AAAA,MAChB,eAAA,EAAiB,wBAAA;AAAA,MACjB,UAAA,EAAY,YAAA;AAAA,MACZ,mBAAA,EAAqB;AAAA;AAAA,KACtB,CAAA;AAED,IAAA,IAAI,OAAQ,GAAA,CAAY,YAAA,KAAiB,UAAA,EAAY;AACnD,MAAC,IAAY,YAAA,EAAa;AAAA,IAC5B;AAEA,IAAA,MAAM,QAAA,GAAW,OAAA,EAAS,QAAA,IAAY,IAAA,CAAK,gBAAA,EAAiB;AAC5D,IAAA,MAAM,qBAAqB,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,GAAA,EAAK,SAAS,QAAQ,CAAA;AAE1E,IAAA,MAAM,KAAA,GAAQ,CAAC,KAAA,KAAkB;AAC/B,MAAA,MAAM,EAAA,GAAK,GAAA,CAAI,KAAA,CAAM,KAAK,CAAA;AAC1B,MAAA,IAAI,OAAQ,GAAA,CAAY,KAAA,KAAU,UAAA,EAAY;AAC5C,QAAC,IAAY,KAAA,EAAM;AAAA,MACrB;AACA,MAAA,IAAI,CAAC,EAAA,IAAM,GAAA,CAAI,cAAA,GAAiB,kBAAA,EAAoB;AAClD,QAAA,IAAA,CAAK,GAAA,CAAI,CAAA,OAAA,EAAU,QAAQ,CAAA,mBAAA,CAAqB,CAAA;AAChD,QAAA,MAAA,CAAO,KAAA,EAAM;AAAA,MACf;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,MAAA,GAAsB;AAAA,MAC1B,EAAA,EAAI,QAAA;AAAA,MACJ,QAAQ,OAAA,EAAS,MAAA;AAAA,MACjB,QAAA,EAAU,kBAAA;AAAA,MACV,IAAA,EAAM,OAAA,EAAS,IAAA,IAAQ,EAAC;AAAA,MACxB,IAAA,EAAM,CAAC,KAAA,EAAO,IAAA,EAAM,GAAA,KAAQ;AAC1B,QAAA,IAAI;AACF,UAAA,KAAA,CAAM,IAAA,CAAK,aAAA,CAAc,KAAA,EAAO,IAAA,EAAM,GAAG,CAAC,CAAA;AAAA,QAC5C,SAAS,GAAA,EAAK;AACZ,UAAA,IAAA,CAAK,GAAA,CAAI,CAAA,wBAAA,EAA2B,QAAQ,CAAA,CAAA,CAAA,EAAK,GAAG,CAAA;AAAA,QACtD;AAAA,MACF,CAAA;AAAA,MACA,WAAA,EAAa,CAAC,OAAA,KAAoB;AAChC,QAAA,IAAI;AACF,UAAA,KAAA,CAAM,KAAK,OAAO;;AAAA,CAAM,CAAA;AAAA,QAC1B,CAAA,CAAA,MAAQ;AAAA,QAAC;AAAA,MACX,CAAA;AAAA,MACA,OAAO,MAAM;AACX,QAAA,IAAI;AACF,UAAA,GAAA,CAAI,GAAA,EAAI;AAAA,QACV,CAAA,CAAA,MAAQ;AAAA,QAAC;AACT,QAAA,IAAA,CAAK,aAAa,QAAQ,CAAA;AAAA,MAC5B;AAAA,KACF;AAEA,IAAA,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,QAAA,EAAU,MAAM,CAAA;AACjC,IAAA,IAAA,CAAK,GAAA,CAAI,CAAA,kBAAA,EAAqB,QAAQ,CAAA,aAAA,EAAgB,KAAA,CAAM,IAAA,CAAK,kBAAkB,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAG,CAAA;AAGlG,IAAA,MAAA,CAAO,IAAA,CAAK,WAAA,EAAa,EAAE,QAAA,EAAU,CAAA;AAGrC,IAAA,GAAA,CAAI,EAAA,CAAG,SAAS,MAAM;AACpB,MAAA,IAAA,CAAK,aAAa,QAAQ,CAAA;AAAA,IAC5B,CAAC,CAAA;AAED,IAAA,GAAA,CAAI,EAAA,CAAG,SAAS,MAAM;AACpB,MAAA,IAAA,CAAK,aAAa,QAAQ,CAAA;AAAA,IAC5B,CAAC,CAAA;AAED,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaO,iBAAA,CACL,SACA,OAAA,EAMU;AACV,IAAA,MAAM,QAAA,GAAW,OAAA,EAAS,QAAA,IAAY,IAAA,CAAK,gBAAA,EAAiB;AAC5D,IAAA,MAAM,qBAAqB,IAAA,CAAK,eAAA,CAAgB,OAAA,EAAS,GAAA,EAAK,SAAS,QAAQ,CAAA;AAE/E,IAAA,MAAM,OAAA,GAAU,IAAI,WAAA,EAAY;AAGhC,IAAA,MAAM,MAAA,GAAS,IAAI,cAAA,CAA2B;AAAA,MAC5C,KAAA,EAAO,CAAC,UAAA,KAAe;AAGrB,QAAA,MAAM,MAAA,GAAsB;AAAA,UAC1B,EAAA,EAAI,QAAA;AAAA,UACJ,QAAQ,OAAA,EAAS,MAAA;AAAA,UACjB,QAAA,EAAU,kBAAA;AAAA,UACV,IAAA,EAAM,OAAA,EAAS,IAAA,IAAQ,EAAC;AAAA,UACxB,IAAA,EAAM,CAAC,KAAA,EAAO,IAAA,EAAM,GAAA,KAAQ;AAC1B,YAAA,IAAI;AACF,cAAA,UAAA,CAAW,OAAA,CAAQ,QAAQ,MAAA,CAAO,IAAA,CAAK,cAAc,KAAA,EAAO,IAAA,EAAM,GAAG,CAAC,CAAC,CAAA;AAAA,YACzE,SAAS,GAAA,EAAK;AACZ,cAAA,IAAA,CAAK,GAAA,CAAI,CAAA,2BAAA,EAA8B,QAAQ,CAAA,CAAA,CAAA,EAAK,GAAG,CAAA;AAAA,YACzD;AAAA,UACF,CAAA;AAAA,UACA,WAAA,EAAa,CAAC,OAAA,KAAoB;AAChC,YAAA,IAAI;AACF,cAAA,UAAA,CAAW,OAAA,CAAQ,OAAA,CAAQ,MAAA,CAAO,CAAA,EAAA,EAAK,OAAO;;AAAA,CAAM,CAAC,CAAA;AAAA,YACvD,CAAA,CAAA,MAAQ;AAAA,YAAC;AAAA,UACX,CAAA;AAAA,UACA,OAAO,MAAM;AACX,YAAA,IAAI;AACF,cAAA,UAAA,CAAW,KAAA,EAAM;AAAA,YACnB,CAAA,CAAA,MAAQ;AAAA,YAAC;AACT,YAAA,IAAA,CAAK,aAAa,QAAQ,CAAA;AAAA,UAC5B;AAAA,SACF;AAEA,QAAA,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,QAAA,EAAU,MAAM,CAAA;AACjC,QAAA,IAAA,CAAK,GAAA,CAAI,CAAA,sBAAA,EAAyB,QAAQ,CAAA,CAAE,CAAA;AAG5C,QAAA,MAAA,CAAO,IAAA,CAAK,WAAA,EAAa,EAAE,QAAA,EAAU,CAAA;AAAA,MACvC,CAAA;AAAA,MACA,QAAQ,MAAM;AACZ,QAAA,IAAA,CAAK,aAAa,QAAQ,CAAA;AAAA,MAC5B;AAAA,KACD,CAAA;AAED,IAAA,OAAO,IAAI,SAAS,MAAA,EAAQ;AAAA,MAC1B,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,mBAAA;AAAA,QAChB,eAAA,EAAiB,wBAAA;AAAA,QACjB,UAAA,EAAY;AAAA;AACd,KACD,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKO,KAAA,GAAc;AACnB,IAAA,IAAI,KAAK,cAAA,EAAgB;AACvB,MAAA,aAAA,CAAc,KAAK,cAAc,CAAA;AACjC,MAAA,IAAA,CAAK,cAAA,GAAiB,IAAA;AAAA,IACxB;AAEA,IAAA,KAAA,MAAW,MAAA,IAAU,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAO,EAAG;AAC1C,MAAA,MAAA,CAAO,KAAA,EAAM;AAAA,IACf;AACA,IAAA,IAAA,CAAK,QAAQ,KAAA,EAAM;AAAA,EACrB;AAAA,EAEQ,aAAa,QAAA,EAAwB;AAC3C,IAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA,EAAG;AAC9B,MAAA,IAAA,CAAK,OAAA,CAAQ,OAAO,QAAQ,CAAA;AAC5B,MAAA,IAAA,CAAK,GAAA,CAAI,CAAA,qBAAA,EAAwB,QAAQ,CAAA,CAAE,CAAA;AAAA,IAC7C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAA,CAAgB,QAA4B,OAAA,EAAiC;AACnF,IAAA,IAAI,OAAA,EAAS,OAAO,IAAI,GAAA,CAAI,OAAO,CAAA;AAEnC,IAAA,MAAM,QAAA,uBAAe,GAAA,EAAY;AACjC,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,IAAI;AACF,QAAA,MAAM,KAAA,GAAQ,IAAI,GAAA,CAAI,MAAA,EAAQ,kBAAkB,CAAA,CAAE,YAAA,CAAa,GAAA,CAAI,UAAU,CAAA,IAAK,EAAA;AAClF,QAAA,KAAA,MAAW,EAAA,IAAM,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA,EAAG;AACjC,UAAA,MAAM,OAAA,GAAU,GAAG,IAAA,EAAK;AACxB,UAAA,IAAI,WAAW,CAAC,SAAA,CAAU,OAAO,CAAA,EAAG,QAAA,CAAS,IAAI,OAAO,CAAA;AAAA,QAC1D;AAAA,MACF,CAAA,CAAA,MAAQ;AAAA,MAAC;AAAA,IACX;AAEA,IAAA,IAAI,QAAA,CAAS,IAAA,KAAS,CAAA,EAAG,QAAA,CAAS,IAAI,GAAG,CAAA;AACzC,IAAA,OAAO,QAAA;AAAA,EACT;AAAA;AAAA,EAGQ,YAAA,CAAa,QAAqB,OAAA,EAA0B;AAClE,IAAA,OAAO,MAAA,CAAO,QAAA,CAAS,GAAA,CAAI,OAAO,CAAA,IAAM,MAAA,CAAO,QAAA,CAAS,GAAA,CAAI,GAAG,CAAA,IAAK,CAAC,SAAA,CAAU,OAAO,CAAA;AAAA,EACxF;AAAA,EAEQ,aAAA,CAAc,KAAA,EAAe,IAAA,EAAW,GAAA,EAAoE;AAClH,IAAA,IAAI,OAAA,GAAU,EAAA;AACd,IAAA,IAAI,GAAA,EAAK,EAAA,EAAI,OAAA,IAAW,CAAA,IAAA,EAAO,IAAI,EAAE;AAAA,CAAA;AACrC,IAAA,OAAA,IAAW,CAAA,OAAA,EAAU,GAAA,EAAK,QAAA,IAAY,SAAS;AAAA,CAAA;AAC/C,IAAA,OAAA,IAAW,CAAA,MAAA,EAAS,IAAA,CAAK,SAAA,CAAU,EAAE,OAAA,EAAS,KAAK,OAAA,EAAS,KAAA,EAAO,IAAA,EAAM,CAAC;;AAAA,CAAA;AAC1E,IAAA,OAAO,OAAA;AAAA,EACT;AAAA,EAEQ,cAAA,GAAuB;AAG7B,IAAA,IAAA,CAAK,cAAA,GAAiB,YAAY,MAAM;AACtC,MAAA,KAAA,MAAW,MAAA,IAAU,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAO,EAAG;AAC1C,QAAA,MAAA,CAAO,IAAA,CAAK,MAAA,EAAQ,EAAE,CAAA;AAAA,MACxB;AAAA,IACF,CAAA,EAAG,KAAK,iBAAiB,CAAA;AAAA,EAC3B;AAAA,EAEQ,OAAO,IAAA,EAAmB;AAChC,IAAA,IAAI,KAAK,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,GAAA,CAAI,sBAAA,EAAwB,GAAG,IAAI,CAAA;AAAA,IAC7C;AAAA,EACF;AACF","file":"server.mjs","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'http';\n\nexport interface NotifClient {\n id: string;\n userId?: string;\n channels: Set<string>;\n send: (event: string, data: any, options?: { channel?: string; id?: string; sseEvent?: string }) => void;\n sendComment: (comment: string) => void;\n close: () => void;\n meta: Record<string, any>;\n}\n\nexport interface NotifServerOptions {\n /**\n * Heartbeat interval in milliseconds to keep SSE connections open through proxies.\n * Defaults to 20000ms (20s). Set to 0 to disable.\n */\n heartbeatInterval?: number;\n\n /**\n * Optional custom client ID generator.\n */\n generateClientId?: () => string;\n\n /**\n * Debug logging.\n */\n debug?: boolean;\n}\n\nexport interface TriggerOptions {\n id?: string;\n sseEvent?: string;\n}\n\nconst isPrivate = (ch: string) => ch.startsWith('private-') || ch.startsWith('presence-');\n\n// A client whose unread buffer grows past this is dropped instead of buffering forever.\nconst MAX_BUFFERED_BYTES = 1024 * 1024;\n\nexport class NotifServer {\n private clients: Map<string, NotifClient> = new Map();\n private heartbeatInterval: number;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private generateClientId: () => string;\n private debug: boolean;\n\n constructor(options: NotifServerOptions = {}) {\n this.heartbeatInterval = options.heartbeatInterval ?? 20000;\n this.debug = options.debug ?? false;\n this.generateClientId =\n options.generateClientId ?? (() => `client_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`);\n\n if (this.heartbeatInterval > 0) {\n this.startHeartbeat();\n }\n }\n\n /**\n * Broadcast an event to one or more channels.\n * Matches Pusher's `pusher.trigger(channel, event, data)` API.\n *\n * Example:\n * ```ts\n * server.trigger('orders', 'order-created', { id: 123, amount: 49.99 });\n * ```\n */\n public trigger(channel: string | string[], event: string, data: any, options?: TriggerOptions): void {\n const channels = Array.isArray(channel) ? channel : [channel];\n\n for (const ch of channels) {\n for (const client of this.clients.values()) {\n if (this.isSubscribed(client, ch)) {\n client.send(event, data, { channel: ch, id: options?.id, sseEvent: options?.sseEvent });\n }\n }\n }\n }\n\n /**\n * Alias for trigger().\n */\n public broadcast(channel: string | string[], event: string, data: any, options?: TriggerOptions): void {\n this.trigger(channel, event, data, options);\n }\n\n /**\n * Send an event directly to a specific client ID.\n */\n public sendToClient(clientId: string, event: string, data: any, options?: TriggerOptions & { channel?: string }): boolean {\n const client = this.clients.get(clientId);\n if (client) {\n client.send(event, data, { channel: options?.channel, id: options?.id, sseEvent: options?.sseEvent });\n return true;\n }\n return false;\n }\n\n /**\n * Send an event to all connected clients belonging to a specific user ID.\n */\n public sendToUser(userId: string, event: string, data: any, options?: TriggerOptions & { channel?: string }): number {\n let count = 0;\n for (const client of this.clients.values()) {\n if (client.userId === userId) {\n client.send(event, data, { channel: options?.channel, id: options?.id, sseEvent: options?.sseEvent });\n count++;\n }\n }\n return count;\n }\n\n /**\n * Subscribe a connected client to a channel.\n */\n public subscribeClient(clientId: string, channel: string): boolean {\n const client = this.clients.get(clientId);\n if (client) {\n client.channels.add(channel);\n this.log(`Client ${clientId} subscribed to \"${channel}\"`);\n return true;\n }\n return false;\n }\n\n /**\n * Unsubscribe a connected client from a channel.\n */\n public unsubscribeClient(clientId: string, channel: string): boolean {\n const client = this.clients.get(clientId);\n if (client) {\n const removed = client.channels.delete(channel);\n this.log(`Client ${clientId} unsubscribed from \"${channel}\"`);\n return removed;\n }\n return false;\n }\n\n /**\n * Get total connected clients count.\n */\n public getClientCount(): number {\n return this.clients.size;\n }\n\n /**\n * Get subscribers count for a specific channel.\n */\n public getSubscribersCount(channel: string): number {\n let count = 0;\n for (const client of this.clients.values()) {\n if (this.isSubscribed(client, channel)) {\n count++;\n }\n }\n return count;\n }\n\n /**\n * Handle incoming HTTP request in Node.js / Express / Fastify environment.\n *\n * Example:\n * ```ts\n * app.get('/sse', (req, res) => {\n * server.handleRequest(req, res);\n * });\n * ```\n */\n public handleRequest(\n req: IncomingMessage,\n res: ServerResponse,\n options?: {\n clientId?: string;\n userId?: string;\n channels?: string[];\n meta?: Record<string, any>;\n }\n ): NotifClient {\n // Set standard SSE HTTP headers\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache, no-transform',\n Connection: 'keep-alive',\n 'X-Accel-Buffering': 'no', // Disable proxy buffering for Nginx\n });\n\n if (typeof (res as any).flushHeaders === 'function') {\n (res as any).flushHeaders();\n }\n\n const clientId = options?.clientId ?? this.generateClientId();\n const subscribedChannels = this.resolveChannels(req.url, options?.channels);\n\n const write = (chunk: string) => {\n const ok = res.write(chunk);\n if (typeof (res as any).flush === 'function') {\n (res as any).flush();\n }\n if (!ok && res.writableLength > MAX_BUFFERED_BYTES) {\n this.log(`Client ${clientId} too slow, dropping`);\n client.close();\n }\n };\n\n const client: NotifClient = {\n id: clientId,\n userId: options?.userId,\n channels: subscribedChannels,\n meta: options?.meta ?? {},\n send: (event, data, opt) => {\n try {\n write(this.formatMessage(event, data, opt));\n } catch (err) {\n this.log(`Error writing to client ${clientId}:`, err);\n }\n },\n sendComment: (comment: string) => {\n try {\n write(`: ${comment}\\n\\n`);\n } catch {}\n },\n close: () => {\n try {\n res.end();\n } catch {}\n this.removeClient(clientId);\n },\n };\n\n this.clients.set(clientId, client);\n this.log(`Client connected: ${clientId}, channels: [${Array.from(subscribedChannels).join(', ')}]`);\n\n // Send connection established event\n client.send('connected', { clientId });\n\n // Handle connection close\n req.on('close', () => {\n this.removeClient(clientId);\n });\n\n res.on('close', () => {\n this.removeClient(clientId);\n });\n\n return client;\n }\n\n /**\n * Handle Web standard Request (Next.js App Router, Edge runtime, Hono, Cloudflare Workers).\n * Returns a standard `Response` object with a `ReadableStream`.\n *\n * Example:\n * ```ts\n * export function GET(request: Request) {\n * return server.createWebResponse(request);\n * }\n * ```\n */\n public createWebResponse(\n request?: Request,\n options?: {\n clientId?: string;\n userId?: string;\n channels?: string[];\n meta?: Record<string, any>;\n }\n ): Response {\n const clientId = options?.clientId ?? this.generateClientId();\n const subscribedChannels = this.resolveChannels(request?.url, options?.channels);\n\n const encoder = new TextEncoder();\n let controllerRef: ReadableStreamDefaultController<Uint8Array> | null = null;\n\n const stream = new ReadableStream<Uint8Array>({\n start: (controller) => {\n controllerRef = controller;\n\n const client: NotifClient = {\n id: clientId,\n userId: options?.userId,\n channels: subscribedChannels,\n meta: options?.meta ?? {},\n send: (event, data, opt) => {\n try {\n controller.enqueue(encoder.encode(this.formatMessage(event, data, opt)));\n } catch (err) {\n this.log(`Error enqueueing to client ${clientId}:`, err);\n }\n },\n sendComment: (comment: string) => {\n try {\n controller.enqueue(encoder.encode(`: ${comment}\\n\\n`));\n } catch {}\n },\n close: () => {\n try {\n controller.close();\n } catch {}\n this.removeClient(clientId);\n },\n };\n\n this.clients.set(clientId, client);\n this.log(`Web client connected: ${clientId}`);\n\n // Send connection handshake\n client.send('connected', { clientId });\n },\n cancel: () => {\n this.removeClient(clientId);\n },\n });\n\n return new Response(stream, {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache, no-transform',\n Connection: 'keep-alive',\n },\n });\n }\n\n /**\n * Stop the server heartbeat and disconnect all clients.\n */\n public close(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n\n for (const client of this.clients.values()) {\n client.close();\n }\n this.clients.clear();\n }\n\n private removeClient(clientId: string): void {\n if (this.clients.has(clientId)) {\n this.clients.delete(clientId);\n this.log(`Client disconnected: ${clientId}`);\n }\n }\n\n /**\n * App-given channels are final; the URL can only add public channels when the app gave none.\n * `*` (all public channels) is the default when neither names any.\n */\n private resolveChannels(rawUrl: string | undefined, allowed?: string[]): Set<string> {\n if (allowed) return new Set(allowed);\n\n const channels = new Set<string>();\n if (rawUrl) {\n try {\n const query = new URL(rawUrl, 'http://localhost').searchParams.get('channels') ?? '';\n for (const ch of query.split(',')) {\n const trimmed = ch.trim();\n if (trimmed && !isPrivate(trimmed)) channels.add(trimmed);\n }\n } catch {}\n }\n\n if (channels.size === 0) channels.add('*');\n return channels;\n }\n\n /** `*` never covers private channels; those need an explicit grant (options.channels or subscribeClient). */\n private isSubscribed(client: NotifClient, channel: string): boolean {\n return client.channels.has(channel) || (client.channels.has('*') && !isPrivate(channel));\n }\n\n private formatMessage(event: string, data: any, opt?: { channel?: string; id?: string; sseEvent?: string }): string {\n let message = '';\n if (opt?.id) message += `id: ${opt.id}\\n`;\n message += `event: ${opt?.sseEvent ?? 'message'}\\n`;\n message += `data: ${JSON.stringify({ channel: opt?.channel, event, data })}\\n\\n`;\n return message;\n }\n\n private startHeartbeat(): void {\n // A real event, not an SSE comment: browser EventSource never surfaces comments,\n // so the client's heartbeat timeout would fire on every quiet connection.\n this.heartbeatTimer = setInterval(() => {\n for (const client of this.clients.values()) {\n client.send('ping', {});\n }\n }, this.heartbeatInterval);\n }\n\n private log(...args: any[]): void {\n if (this.debug) {\n console.log('[notif-agent:server]', ...args);\n }\n }\n}\n"]}
|
package/package.json
CHANGED