@vielzeug/pulse 2.1.0 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_connection.cjs.map +1 -1
- package/dist/_connection.d.ts.map +1 -1
- package/dist/_connection.js.map +1 -1
- package/dist/_utils.cjs.map +1 -1
- package/dist/_utils.js.map +1 -1
- package/dist/_wait.cjs.map +1 -1
- package/dist/_wait.js.map +1 -1
- package/dist/channel.cjs.map +1 -1
- package/dist/channel.js.map +1 -1
- package/dist/heartbeat.cjs.map +1 -1
- package/dist/heartbeat.d.ts.map +1 -1
- package/dist/heartbeat.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/presence.cjs.map +1 -1
- package/dist/presence.d.ts +1 -1
- package/dist/presence.d.ts.map +1 -1
- package/dist/presence.js.map +1 -1
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.js.map +1 -1
- package/dist/pulse.cjs.map +1 -1
- package/dist/pulse.d.ts.map +1 -1
- package/dist/pulse.iife.js.map +1 -1
- package/dist/pulse.js.map +1 -1
- package/package.json +15 -15
package/dist/_connection.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_connection.cjs","names":[],"sources":["../src/_connection.ts"],"sourcesContent":["import type { PulseStatus, ReconnectOptions } from './types';\n\nimport { defaultReconnectDelay, sleep } from './_utils';\nimport { PulseConnectionError, PulseDisposedError } from './errors';\n\ntype ConnectionCallbacks = {\n onClose(): void;\n onError(error: PulseConnectionError): void;\n onMessage(event: MessageEvent): void;\n onOpen(): void;\n onStatus(status: PulseStatus): void;\n};\n\nexport type ConnectionController = {\n connect(): Promise<void>;\n disconnect(code?: number, reason?: string): void;\n dispose(): void;\n forceReconnect(code: number, reason: string): void;\n readonly open: boolean;\n send(frame: string): void;\n};\n\ntype Opening = {\n promise: Promise<void>;\n reject(error: PulseConnectionError): void;\n resolve(): void;\n socket: WebSocket;\n};\n\nconst DEFAULT_MAX_ATTEMPTS = 5;\n\n/** Owns the one active socket and its retry loop. @internal */\nexport function createConnection(\n url: string,\n protocols: string | string[] | undefined,\n reconnect: boolean | ReconnectOptions | undefined,\n callbacks: ConnectionCallbacks,\n): ConnectionController {\n const options: ReconnectOptions | undefined = reconnect === true ? {} : reconnect || undefined;\n const maxAttempts = options ? (options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS) : 0;\n const configuredDelay = options?.delay;\n const delay: (attempt: number) => number =\n typeof configuredDelay === 'function'\n ? configuredDelay\n : typeof configuredDelay === 'number'\n ? () => configuredDelay\n : defaultReconnectDelay;\n\n let disposed = false;\n let desired = false;\n let retrying = false;\n let retryCtrl: AbortController | undefined;\n let socket: WebSocket | undefined;\n let opening: Opening | undefined;\n const waiters = new Set<{ reject(error: Error): void; resolve(): void }>();\n\n function setStatus(status: PulseStatus): void {\n callbacks.onStatus(status);\n }\n\n function rejectWaiters(error: Error): void {\n for (const waiter of waiters) waiter.reject(error);\n waiters.clear();\n }\n\n function resolveWaiters(): void {\n for (const waiter of waiters) waiter.resolve();\n waiters.clear();\n }\n\n function rejectOpening(socketToReject: WebSocket, error: PulseConnectionError): void {\n if (opening?.socket !== socketToReject) return;\n\n opening.reject(error);\n opening = undefined;\n }\n\n function openSocket(): Promise<void> {\n if (socket?.readyState === WebSocket.OPEN) return Promise.resolve();\n\n if (opening) return opening.promise;\n\n const nextSocket = new WebSocket(url, protocols);\n\n socket = nextSocket;\n\n let resolveOpening: () => void;\n let rejectOpeningPromise: (error: PulseConnectionError) => void;\n const promise = new Promise<void>((resolve, reject) => {\n resolveOpening = resolve;\n rejectOpeningPromise = reject;\n });\n\n opening = { promise, reject: rejectOpeningPromise!, resolve: resolveOpening!, socket: nextSocket };\n\n nextSocket.onopen = (): void => {\n if (socket !== nextSocket || !desired) {\n nextSocket.close(1000, 'stale connection');\n\n return;\n }\n\n if (opening?.socket === nextSocket) {\n opening.resolve();\n opening = undefined;\n }\n\n setStatus('open');\n callbacks.onOpen();\n resolveWaiters();\n };\n\n nextSocket.onmessage = (event: MessageEvent): void => {\n if (socket === nextSocket) callbacks.onMessage(event);\n };\n\n nextSocket.onerror = (): void => {\n if (socket !== nextSocket) return;\n\n const error = new PulseConnectionError('WebSocket error', url);\n\n callbacks.onError(error);\n rejectOpening(nextSocket, error);\n rejectWaiters(error);\n };\n\n nextSocket.onclose = (): void => {\n if (socket !== nextSocket) return;\n\n socket = undefined;\n callbacks.onClose();\n\n const error = new PulseConnectionError('Connection closed', url);\n\n rejectOpening(nextSocket, error);\n\n if (!desired || disposed) {\n setStatus('closed');\n\n return;\n }\n\n if (!retrying) void reconnectLoop();\n };\n\n return promise;\n }\n\n async function reconnectLoop(): Promise<void> {\n if (retrying || disposed || !desired) return;\n\n retrying = true;\n\n const controller = new AbortController();\n\n retryCtrl = controller;\n setStatus('reconnecting');\n\n let lastError: PulseConnectionError | undefined;\n\n for (let attempt = 0; attempt < maxAttempts && desired && !disposed; attempt++) {\n await sleep(delay(attempt), controller.signal);\n\n if (controller.signal.aborted || !desired || disposed) break;\n\n try {\n await openSocket();\n retrying = false;\n\n return;\n } catch (error) {\n lastError = error instanceof PulseConnectionError ? error : new PulseConnectionError('Reconnect failed', url);\n }\n }\n\n if (!controller.signal.aborted && desired && !disposed) {\n desired = false;\n setStatus('closed');\n callbacks.onError(lastError ?? new PulseConnectionError('Reconnect budget exhausted', url));\n rejectWaiters(lastError ?? new PulseConnectionError('Reconnect budget exhausted', url));\n }\n\n if (retryCtrl === controller) retryCtrl = undefined;\n\n retrying = false;\n }\n\n function cancelRetry(): void {\n retryCtrl?.abort();\n retryCtrl = undefined;\n retrying = false;\n }\n\n return {\n connect(): Promise<void> {\n if (disposed) return Promise.reject(new PulseDisposedError());\n\n desired = true;\n\n if (socket?.readyState === WebSocket.OPEN) return Promise.resolve();\n\n const connected = new Promise<void>((resolve, reject) => {\n waiters.add({ reject, resolve });\n });\n\n if (!opening && !retrying) {\n setStatus('connecting');\n void openSocket().catch(() => {});\n }\n\n return connected;\n },\n\n disconnect(code = 1000, reason = ''): void {\n desired = false;\n cancelRetry();\n rejectWaiters(new PulseConnectionError('Connection closed', url));\n setStatus('closed');\n socket?.close(code, reason);\n },\n\n dispose(): void {\n if (disposed) return;\n\n disposed = true;\n desired = false;\n cancelRetry();\n rejectWaiters(new PulseDisposedError());\n socket?.close(1000, 'disposed');\n socket = undefined;\n opening = undefined;\n setStatus('closed');\n },\n\n forceReconnect(code: number, reason: string): void {\n if (desired && socket?.readyState === WebSocket.OPEN) socket.close(code, reason);\n },\n\n get open() {\n return socket?.readyState === WebSocket.OPEN;\n },\n\n send(frame: string): void {\n if (socket?.readyState !== WebSocket.OPEN) {\n throw new PulseConnectionError('Connection is not open', url);\n }\n\n socket.send(frame);\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"_connection.cjs","names":[],"sources":["../src/_connection.ts"],"sourcesContent":["import { defaultReconnectDelay, sleep } from './_utils';\nimport { PulseConnectionError, PulseDisposedError } from './errors';\nimport type { PulseStatus, ReconnectOptions } from './types';\n\ntype ConnectionCallbacks = {\n onClose(): void;\n onError(error: PulseConnectionError): void;\n onMessage(event: MessageEvent): void;\n onOpen(): void;\n onStatus(status: PulseStatus): void;\n};\n\nexport type ConnectionController = {\n connect(): Promise<void>;\n disconnect(code?: number, reason?: string): void;\n dispose(): void;\n forceReconnect(code: number, reason: string): void;\n readonly open: boolean;\n send(frame: string): void;\n};\n\ntype Opening = {\n promise: Promise<void>;\n reject(error: PulseConnectionError): void;\n resolve(): void;\n socket: WebSocket;\n};\n\nconst DEFAULT_MAX_ATTEMPTS = 5;\n\n/** Owns the one active socket and its retry loop. @internal */\nexport function createConnection(\n url: string,\n protocols: string | string[] | undefined,\n reconnect: boolean | ReconnectOptions | undefined,\n callbacks: ConnectionCallbacks,\n): ConnectionController {\n const options: ReconnectOptions | undefined = reconnect === true ? {} : reconnect || undefined;\n const maxAttempts = options ? (options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS) : 0;\n const configuredDelay = options?.delay;\n const delay: (attempt: number) => number =\n typeof configuredDelay === 'function'\n ? configuredDelay\n : typeof configuredDelay === 'number'\n ? () => configuredDelay\n : defaultReconnectDelay;\n\n let disposed = false;\n let desired = false;\n let retrying = false;\n let retryCtrl: AbortController | undefined;\n let socket: WebSocket | undefined;\n let opening: Opening | undefined;\n const waiters = new Set<{ reject(error: Error): void; resolve(): void }>();\n\n function setStatus(status: PulseStatus): void {\n callbacks.onStatus(status);\n }\n\n function rejectWaiters(error: Error): void {\n for (const waiter of waiters) waiter.reject(error);\n waiters.clear();\n }\n\n function resolveWaiters(): void {\n for (const waiter of waiters) waiter.resolve();\n waiters.clear();\n }\n\n function rejectOpening(socketToReject: WebSocket, error: PulseConnectionError): void {\n if (opening?.socket !== socketToReject) return;\n\n opening.reject(error);\n opening = undefined;\n }\n\n function openSocket(): Promise<void> {\n if (socket?.readyState === WebSocket.OPEN) return Promise.resolve();\n\n if (opening) return opening.promise;\n\n const nextSocket = new WebSocket(url, protocols);\n\n socket = nextSocket;\n\n let resolveOpening: () => void;\n let rejectOpeningPromise: (error: PulseConnectionError) => void;\n const promise = new Promise<void>((resolve, reject) => {\n resolveOpening = resolve;\n rejectOpeningPromise = reject;\n });\n\n opening = { promise, reject: rejectOpeningPromise!, resolve: resolveOpening!, socket: nextSocket };\n\n nextSocket.onopen = (): void => {\n if (socket !== nextSocket || !desired) {\n nextSocket.close(1000, 'stale connection');\n\n return;\n }\n\n if (opening?.socket === nextSocket) {\n opening.resolve();\n opening = undefined;\n }\n\n setStatus('open');\n callbacks.onOpen();\n resolveWaiters();\n };\n\n nextSocket.onmessage = (event: MessageEvent): void => {\n if (socket === nextSocket) callbacks.onMessage(event);\n };\n\n nextSocket.onerror = (): void => {\n if (socket !== nextSocket) return;\n\n const error = new PulseConnectionError('WebSocket error', url);\n\n callbacks.onError(error);\n rejectOpening(nextSocket, error);\n rejectWaiters(error);\n };\n\n nextSocket.onclose = (): void => {\n if (socket !== nextSocket) return;\n\n socket = undefined;\n callbacks.onClose();\n\n const error = new PulseConnectionError('Connection closed', url);\n\n rejectOpening(nextSocket, error);\n\n if (!desired || disposed) {\n setStatus('closed');\n\n return;\n }\n\n if (!retrying) void reconnectLoop();\n };\n\n return promise;\n }\n\n async function reconnectLoop(): Promise<void> {\n if (retrying || disposed || !desired) return;\n\n retrying = true;\n\n const controller = new AbortController();\n\n retryCtrl = controller;\n setStatus('reconnecting');\n\n let lastError: PulseConnectionError | undefined;\n\n for (let attempt = 0; attempt < maxAttempts && desired && !disposed; attempt++) {\n await sleep(delay(attempt), controller.signal);\n\n if (controller.signal.aborted || !desired || disposed) break;\n\n try {\n await openSocket();\n retrying = false;\n\n return;\n } catch (error) {\n lastError = error instanceof PulseConnectionError ? error : new PulseConnectionError('Reconnect failed', url);\n }\n }\n\n if (!controller.signal.aborted && desired && !disposed) {\n desired = false;\n setStatus('closed');\n callbacks.onError(lastError ?? new PulseConnectionError('Reconnect budget exhausted', url));\n rejectWaiters(lastError ?? new PulseConnectionError('Reconnect budget exhausted', url));\n }\n\n if (retryCtrl === controller) retryCtrl = undefined;\n\n retrying = false;\n }\n\n function cancelRetry(): void {\n retryCtrl?.abort();\n retryCtrl = undefined;\n retrying = false;\n }\n\n return {\n connect(): Promise<void> {\n if (disposed) return Promise.reject(new PulseDisposedError());\n\n desired = true;\n\n if (socket?.readyState === WebSocket.OPEN) return Promise.resolve();\n\n const connected = new Promise<void>((resolve, reject) => {\n waiters.add({ reject, resolve });\n });\n\n if (!opening && !retrying) {\n setStatus('connecting');\n void openSocket().catch(() => {});\n }\n\n return connected;\n },\n\n disconnect(code = 1000, reason = ''): void {\n desired = false;\n cancelRetry();\n rejectWaiters(new PulseConnectionError('Connection closed', url));\n setStatus('closed');\n socket?.close(code, reason);\n },\n\n dispose(): void {\n if (disposed) return;\n\n disposed = true;\n desired = false;\n cancelRetry();\n rejectWaiters(new PulseDisposedError());\n socket?.close(1000, 'disposed');\n socket = undefined;\n opening = undefined;\n setStatus('closed');\n },\n\n forceReconnect(code: number, reason: string): void {\n if (desired && socket?.readyState === WebSocket.OPEN) socket.close(code, reason);\n },\n\n get open() {\n return socket?.readyState === WebSocket.OPEN;\n },\n\n send(frame: string): void {\n if (socket?.readyState !== WebSocket.OPEN) {\n throw new PulseConnectionError('Connection is not open', url);\n }\n\n socket.send(frame);\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_connection.d.ts","sourceRoot":"","sources":["../src/_connection.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"_connection.d.ts","sourceRoot":"","sources":["../src/_connection.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjD,OAAO,IAAI,IAAI,CAAC;IAChB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACnD,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC"}
|
package/dist/_connection.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_connection.js","names":[],"sources":["../src/_connection.ts"],"sourcesContent":["import type { PulseStatus, ReconnectOptions } from './types';\n\nimport { defaultReconnectDelay, sleep } from './_utils';\nimport { PulseConnectionError, PulseDisposedError } from './errors';\n\ntype ConnectionCallbacks = {\n onClose(): void;\n onError(error: PulseConnectionError): void;\n onMessage(event: MessageEvent): void;\n onOpen(): void;\n onStatus(status: PulseStatus): void;\n};\n\nexport type ConnectionController = {\n connect(): Promise<void>;\n disconnect(code?: number, reason?: string): void;\n dispose(): void;\n forceReconnect(code: number, reason: string): void;\n readonly open: boolean;\n send(frame: string): void;\n};\n\ntype Opening = {\n promise: Promise<void>;\n reject(error: PulseConnectionError): void;\n resolve(): void;\n socket: WebSocket;\n};\n\nconst DEFAULT_MAX_ATTEMPTS = 5;\n\n/** Owns the one active socket and its retry loop. @internal */\nexport function createConnection(\n url: string,\n protocols: string | string[] | undefined,\n reconnect: boolean | ReconnectOptions | undefined,\n callbacks: ConnectionCallbacks,\n): ConnectionController {\n const options: ReconnectOptions | undefined = reconnect === true ? {} : reconnect || undefined;\n const maxAttempts = options ? (options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS) : 0;\n const configuredDelay = options?.delay;\n const delay: (attempt: number) => number =\n typeof configuredDelay === 'function'\n ? configuredDelay\n : typeof configuredDelay === 'number'\n ? () => configuredDelay\n : defaultReconnectDelay;\n\n let disposed = false;\n let desired = false;\n let retrying = false;\n let retryCtrl: AbortController | undefined;\n let socket: WebSocket | undefined;\n let opening: Opening | undefined;\n const waiters = new Set<{ reject(error: Error): void; resolve(): void }>();\n\n function setStatus(status: PulseStatus): void {\n callbacks.onStatus(status);\n }\n\n function rejectWaiters(error: Error): void {\n for (const waiter of waiters) waiter.reject(error);\n waiters.clear();\n }\n\n function resolveWaiters(): void {\n for (const waiter of waiters) waiter.resolve();\n waiters.clear();\n }\n\n function rejectOpening(socketToReject: WebSocket, error: PulseConnectionError): void {\n if (opening?.socket !== socketToReject) return;\n\n opening.reject(error);\n opening = undefined;\n }\n\n function openSocket(): Promise<void> {\n if (socket?.readyState === WebSocket.OPEN) return Promise.resolve();\n\n if (opening) return opening.promise;\n\n const nextSocket = new WebSocket(url, protocols);\n\n socket = nextSocket;\n\n let resolveOpening: () => void;\n let rejectOpeningPromise: (error: PulseConnectionError) => void;\n const promise = new Promise<void>((resolve, reject) => {\n resolveOpening = resolve;\n rejectOpeningPromise = reject;\n });\n\n opening = { promise, reject: rejectOpeningPromise!, resolve: resolveOpening!, socket: nextSocket };\n\n nextSocket.onopen = (): void => {\n if (socket !== nextSocket || !desired) {\n nextSocket.close(1000, 'stale connection');\n\n return;\n }\n\n if (opening?.socket === nextSocket) {\n opening.resolve();\n opening = undefined;\n }\n\n setStatus('open');\n callbacks.onOpen();\n resolveWaiters();\n };\n\n nextSocket.onmessage = (event: MessageEvent): void => {\n if (socket === nextSocket) callbacks.onMessage(event);\n };\n\n nextSocket.onerror = (): void => {\n if (socket !== nextSocket) return;\n\n const error = new PulseConnectionError('WebSocket error', url);\n\n callbacks.onError(error);\n rejectOpening(nextSocket, error);\n rejectWaiters(error);\n };\n\n nextSocket.onclose = (): void => {\n if (socket !== nextSocket) return;\n\n socket = undefined;\n callbacks.onClose();\n\n const error = new PulseConnectionError('Connection closed', url);\n\n rejectOpening(nextSocket, error);\n\n if (!desired || disposed) {\n setStatus('closed');\n\n return;\n }\n\n if (!retrying) void reconnectLoop();\n };\n\n return promise;\n }\n\n async function reconnectLoop(): Promise<void> {\n if (retrying || disposed || !desired) return;\n\n retrying = true;\n\n const controller = new AbortController();\n\n retryCtrl = controller;\n setStatus('reconnecting');\n\n let lastError: PulseConnectionError | undefined;\n\n for (let attempt = 0; attempt < maxAttempts && desired && !disposed; attempt++) {\n await sleep(delay(attempt), controller.signal);\n\n if (controller.signal.aborted || !desired || disposed) break;\n\n try {\n await openSocket();\n retrying = false;\n\n return;\n } catch (error) {\n lastError = error instanceof PulseConnectionError ? error : new PulseConnectionError('Reconnect failed', url);\n }\n }\n\n if (!controller.signal.aborted && desired && !disposed) {\n desired = false;\n setStatus('closed');\n callbacks.onError(lastError ?? new PulseConnectionError('Reconnect budget exhausted', url));\n rejectWaiters(lastError ?? new PulseConnectionError('Reconnect budget exhausted', url));\n }\n\n if (retryCtrl === controller) retryCtrl = undefined;\n\n retrying = false;\n }\n\n function cancelRetry(): void {\n retryCtrl?.abort();\n retryCtrl = undefined;\n retrying = false;\n }\n\n return {\n connect(): Promise<void> {\n if (disposed) return Promise.reject(new PulseDisposedError());\n\n desired = true;\n\n if (socket?.readyState === WebSocket.OPEN) return Promise.resolve();\n\n const connected = new Promise<void>((resolve, reject) => {\n waiters.add({ reject, resolve });\n });\n\n if (!opening && !retrying) {\n setStatus('connecting');\n void openSocket().catch(() => {});\n }\n\n return connected;\n },\n\n disconnect(code = 1000, reason = ''): void {\n desired = false;\n cancelRetry();\n rejectWaiters(new PulseConnectionError('Connection closed', url));\n setStatus('closed');\n socket?.close(code, reason);\n },\n\n dispose(): void {\n if (disposed) return;\n\n disposed = true;\n desired = false;\n cancelRetry();\n rejectWaiters(new PulseDisposedError());\n socket?.close(1000, 'disposed');\n socket = undefined;\n opening = undefined;\n setStatus('closed');\n },\n\n forceReconnect(code: number, reason: string): void {\n if (desired && socket?.readyState === WebSocket.OPEN) socket.close(code, reason);\n },\n\n get open() {\n return socket?.readyState === WebSocket.OPEN;\n },\n\n send(frame: string): void {\n if (socket?.readyState !== WebSocket.OPEN) {\n throw new PulseConnectionError('Connection is not open', url);\n }\n\n socket.send(frame);\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"_connection.js","names":[],"sources":["../src/_connection.ts"],"sourcesContent":["import { defaultReconnectDelay, sleep } from './_utils';\nimport { PulseConnectionError, PulseDisposedError } from './errors';\nimport type { PulseStatus, ReconnectOptions } from './types';\n\ntype ConnectionCallbacks = {\n onClose(): void;\n onError(error: PulseConnectionError): void;\n onMessage(event: MessageEvent): void;\n onOpen(): void;\n onStatus(status: PulseStatus): void;\n};\n\nexport type ConnectionController = {\n connect(): Promise<void>;\n disconnect(code?: number, reason?: string): void;\n dispose(): void;\n forceReconnect(code: number, reason: string): void;\n readonly open: boolean;\n send(frame: string): void;\n};\n\ntype Opening = {\n promise: Promise<void>;\n reject(error: PulseConnectionError): void;\n resolve(): void;\n socket: WebSocket;\n};\n\nconst DEFAULT_MAX_ATTEMPTS = 5;\n\n/** Owns the one active socket and its retry loop. @internal */\nexport function createConnection(\n url: string,\n protocols: string | string[] | undefined,\n reconnect: boolean | ReconnectOptions | undefined,\n callbacks: ConnectionCallbacks,\n): ConnectionController {\n const options: ReconnectOptions | undefined = reconnect === true ? {} : reconnect || undefined;\n const maxAttempts = options ? (options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS) : 0;\n const configuredDelay = options?.delay;\n const delay: (attempt: number) => number =\n typeof configuredDelay === 'function'\n ? configuredDelay\n : typeof configuredDelay === 'number'\n ? () => configuredDelay\n : defaultReconnectDelay;\n\n let disposed = false;\n let desired = false;\n let retrying = false;\n let retryCtrl: AbortController | undefined;\n let socket: WebSocket | undefined;\n let opening: Opening | undefined;\n const waiters = new Set<{ reject(error: Error): void; resolve(): void }>();\n\n function setStatus(status: PulseStatus): void {\n callbacks.onStatus(status);\n }\n\n function rejectWaiters(error: Error): void {\n for (const waiter of waiters) waiter.reject(error);\n waiters.clear();\n }\n\n function resolveWaiters(): void {\n for (const waiter of waiters) waiter.resolve();\n waiters.clear();\n }\n\n function rejectOpening(socketToReject: WebSocket, error: PulseConnectionError): void {\n if (opening?.socket !== socketToReject) return;\n\n opening.reject(error);\n opening = undefined;\n }\n\n function openSocket(): Promise<void> {\n if (socket?.readyState === WebSocket.OPEN) return Promise.resolve();\n\n if (opening) return opening.promise;\n\n const nextSocket = new WebSocket(url, protocols);\n\n socket = nextSocket;\n\n let resolveOpening: () => void;\n let rejectOpeningPromise: (error: PulseConnectionError) => void;\n const promise = new Promise<void>((resolve, reject) => {\n resolveOpening = resolve;\n rejectOpeningPromise = reject;\n });\n\n opening = { promise, reject: rejectOpeningPromise!, resolve: resolveOpening!, socket: nextSocket };\n\n nextSocket.onopen = (): void => {\n if (socket !== nextSocket || !desired) {\n nextSocket.close(1000, 'stale connection');\n\n return;\n }\n\n if (opening?.socket === nextSocket) {\n opening.resolve();\n opening = undefined;\n }\n\n setStatus('open');\n callbacks.onOpen();\n resolveWaiters();\n };\n\n nextSocket.onmessage = (event: MessageEvent): void => {\n if (socket === nextSocket) callbacks.onMessage(event);\n };\n\n nextSocket.onerror = (): void => {\n if (socket !== nextSocket) return;\n\n const error = new PulseConnectionError('WebSocket error', url);\n\n callbacks.onError(error);\n rejectOpening(nextSocket, error);\n rejectWaiters(error);\n };\n\n nextSocket.onclose = (): void => {\n if (socket !== nextSocket) return;\n\n socket = undefined;\n callbacks.onClose();\n\n const error = new PulseConnectionError('Connection closed', url);\n\n rejectOpening(nextSocket, error);\n\n if (!desired || disposed) {\n setStatus('closed');\n\n return;\n }\n\n if (!retrying) void reconnectLoop();\n };\n\n return promise;\n }\n\n async function reconnectLoop(): Promise<void> {\n if (retrying || disposed || !desired) return;\n\n retrying = true;\n\n const controller = new AbortController();\n\n retryCtrl = controller;\n setStatus('reconnecting');\n\n let lastError: PulseConnectionError | undefined;\n\n for (let attempt = 0; attempt < maxAttempts && desired && !disposed; attempt++) {\n await sleep(delay(attempt), controller.signal);\n\n if (controller.signal.aborted || !desired || disposed) break;\n\n try {\n await openSocket();\n retrying = false;\n\n return;\n } catch (error) {\n lastError = error instanceof PulseConnectionError ? error : new PulseConnectionError('Reconnect failed', url);\n }\n }\n\n if (!controller.signal.aborted && desired && !disposed) {\n desired = false;\n setStatus('closed');\n callbacks.onError(lastError ?? new PulseConnectionError('Reconnect budget exhausted', url));\n rejectWaiters(lastError ?? new PulseConnectionError('Reconnect budget exhausted', url));\n }\n\n if (retryCtrl === controller) retryCtrl = undefined;\n\n retrying = false;\n }\n\n function cancelRetry(): void {\n retryCtrl?.abort();\n retryCtrl = undefined;\n retrying = false;\n }\n\n return {\n connect(): Promise<void> {\n if (disposed) return Promise.reject(new PulseDisposedError());\n\n desired = true;\n\n if (socket?.readyState === WebSocket.OPEN) return Promise.resolve();\n\n const connected = new Promise<void>((resolve, reject) => {\n waiters.add({ reject, resolve });\n });\n\n if (!opening && !retrying) {\n setStatus('connecting');\n void openSocket().catch(() => {});\n }\n\n return connected;\n },\n\n disconnect(code = 1000, reason = ''): void {\n desired = false;\n cancelRetry();\n rejectWaiters(new PulseConnectionError('Connection closed', url));\n setStatus('closed');\n socket?.close(code, reason);\n },\n\n dispose(): void {\n if (disposed) return;\n\n disposed = true;\n desired = false;\n cancelRetry();\n rejectWaiters(new PulseDisposedError());\n socket?.close(1000, 'disposed');\n socket = undefined;\n opening = undefined;\n setStatus('closed');\n },\n\n forceReconnect(code: number, reason: string): void {\n if (desired && socket?.readyState === WebSocket.OPEN) socket.close(code, reason);\n },\n\n get open() {\n return socket?.readyState === WebSocket.OPEN;\n },\n\n send(frame: string): void {\n if (socket?.readyState !== WebSocket.OPEN) {\n throw new PulseConnectionError('Connection is not open', url);\n }\n\n socket.send(frame);\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/_utils.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_utils.cjs","names":[],"sources":["../src/_utils.ts"],"sourcesContent":["/**\n * Returns a signal that aborts as soon as any of the provided signals abort.\n * With a single argument, returns it directly (no allocation).\n * Cleanup listeners are registered to prevent leaks.\n *\n * @internal\n */\nexport function combineSignals(first: AbortSignal, ...rest: AbortSignal[]): AbortSignal {\n if (rest.length === 0) return first;\n\n return rest.reduce(mergeTwo, first);\n}\n\nfunction mergeTwo(a: AbortSignal, b: AbortSignal): AbortSignal {\n if (a.aborted) return a;\n\n if (b.aborted) return b;\n\n const ctrl = new AbortController();\n const onA = (): void => ctrl.abort(a.reason);\n const onB = (): void => ctrl.abort(b.reason);\n\n a.addEventListener('abort', onA, { once: true });\n b.addEventListener('abort', onB, { once: true });\n ctrl.signal.addEventListener(\n 'abort',\n () => {\n a.removeEventListener('abort', onA);\n b.removeEventListener('abort', onB);\n },\n { once: true },\n );\n\n return ctrl.signal;\n}\n\n/**\n * Create a child `AbortController` that aborts as soon as `parent` does.\n * Handles the case where `parent` is already aborted at call time — a plain\n * `addEventListener('abort', ...)` would miss that, since the event already fired.\n *\n * @internal\n */\nexport function deriveAbortController(parent: AbortSignal): AbortController {\n const ctrl = new AbortController();\n\n if (parent.aborted) {\n ctrl.abort(parent.reason);\n } else {\n parent.addEventListener('abort', () => ctrl.abort(parent.reason), { once: true });\n }\n\n return ctrl;\n}\n\n/**\n * Sleep for `ms` milliseconds, aborting early when the signal fires.\n * Resolves (does not reject) on abort — callers check `signal.aborted`.\n *\n * @internal\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n if (signal?.aborted) {\n resolve();\n\n return;\n }\n\n const id = setTimeout(resolve, ms);\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(id);\n resolve();\n },\n { once: true },\n );\n });\n}\n\n/**\n * Full-jitter exponential backoff in ms, capped at `maxMs`.\n * `attempt` is zero-based.\n *\n * @internal\n */\nexport function defaultReconnectDelay(attempt: number, maxMs = 30_000): number {\n const base = Math.min(1000 *
|
|
1
|
+
{"version":3,"file":"_utils.cjs","names":[],"sources":["../src/_utils.ts"],"sourcesContent":["/**\n * Returns a signal that aborts as soon as any of the provided signals abort.\n * With a single argument, returns it directly (no allocation).\n * Cleanup listeners are registered to prevent leaks.\n *\n * @internal\n */\nexport function combineSignals(first: AbortSignal, ...rest: AbortSignal[]): AbortSignal {\n if (rest.length === 0) return first;\n\n return rest.reduce(mergeTwo, first);\n}\n\nfunction mergeTwo(a: AbortSignal, b: AbortSignal): AbortSignal {\n if (a.aborted) return a;\n\n if (b.aborted) return b;\n\n const ctrl = new AbortController();\n const onA = (): void => ctrl.abort(a.reason);\n const onB = (): void => ctrl.abort(b.reason);\n\n a.addEventListener('abort', onA, { once: true });\n b.addEventListener('abort', onB, { once: true });\n ctrl.signal.addEventListener(\n 'abort',\n () => {\n a.removeEventListener('abort', onA);\n b.removeEventListener('abort', onB);\n },\n { once: true },\n );\n\n return ctrl.signal;\n}\n\n/**\n * Create a child `AbortController` that aborts as soon as `parent` does.\n * Handles the case where `parent` is already aborted at call time — a plain\n * `addEventListener('abort', ...)` would miss that, since the event already fired.\n *\n * @internal\n */\nexport function deriveAbortController(parent: AbortSignal): AbortController {\n const ctrl = new AbortController();\n\n if (parent.aborted) {\n ctrl.abort(parent.reason);\n } else {\n parent.addEventListener('abort', () => ctrl.abort(parent.reason), { once: true });\n }\n\n return ctrl;\n}\n\n/**\n * Sleep for `ms` milliseconds, aborting early when the signal fires.\n * Resolves (does not reject) on abort — callers check `signal.aborted`.\n *\n * @internal\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n if (signal?.aborted) {\n resolve();\n\n return;\n }\n\n const id = setTimeout(resolve, ms);\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(id);\n resolve();\n },\n { once: true },\n );\n });\n}\n\n/**\n * Full-jitter exponential backoff in ms, capped at `maxMs`.\n * `attempt` is zero-based.\n *\n * @internal\n */\nexport function defaultReconnectDelay(attempt: number, maxMs = 30_000): number {\n const base = Math.min(1000 * 2 ** attempt, maxMs);\n\n return Math.random() * base;\n}\n"],"mappings":"AAOA,SAAgB,EAAe,EAAoB,GAAG,EAAkC,CAGtF,OAFI,EAAK,SAAW,EAAU,EAEvB,EAAK,OAAO,EAAU,CAAK,CACpC,CAEA,SAAS,EAAS,EAAgB,EAA6B,CAC7D,GAAI,EAAE,QAAS,OAAO,EAEtB,GAAI,EAAE,QAAS,OAAO,EAEtB,IAAM,EAAO,IAAI,gBACX,MAAkB,EAAK,MAAM,EAAE,MAAM,EACrC,MAAkB,EAAK,MAAM,EAAE,MAAM,EAa3C,OAXA,EAAE,iBAAiB,QAAS,EAAK,CAAE,KAAM,EAAK,CAAC,EAC/C,EAAE,iBAAiB,QAAS,EAAK,CAAE,KAAM,EAAK,CAAC,EAC/C,EAAK,OAAO,iBACV,YACM,CACJ,EAAE,oBAAoB,QAAS,CAAG,EAClC,EAAE,oBAAoB,QAAS,CAAG,CACpC,EACA,CAAE,KAAM,EAAK,CACf,EAEO,EAAK,MACd,CASA,SAAgB,EAAsB,EAAsC,CAC1E,IAAM,EAAO,IAAI,gBAQjB,OANI,EAAO,QACT,EAAK,MAAM,EAAO,MAAM,EAExB,EAAO,iBAAiB,YAAe,EAAK,MAAM,EAAO,MAAM,EAAG,CAAE,KAAM,EAAK,CAAC,EAG3E,CACT,CAQA,SAAgB,EAAM,EAAY,EAAqC,CACrE,OAAO,IAAI,QAAS,GAAY,CAC9B,GAAI,GAAQ,QAAS,CACnB,EAAQ,EAER,MACF,CAEA,IAAM,EAAK,WAAW,EAAS,CAAE,EAEjC,GAAQ,iBACN,YACM,CACJ,aAAa,CAAE,EACf,EAAQ,CACV,EACA,CAAE,KAAM,EAAK,CACf,CACF,CAAC,CACH,CAQA,SAAgB,EAAsB,EAAiB,EAAQ,IAAgB,CAC7E,IAAM,EAAO,KAAK,IAAI,IAAO,GAAK,EAAS,CAAK,EAEhD,OAAO,KAAK,OAAO,EAAI,CACzB"}
|
package/dist/_utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_utils.js","names":[],"sources":["../src/_utils.ts"],"sourcesContent":["/**\n * Returns a signal that aborts as soon as any of the provided signals abort.\n * With a single argument, returns it directly (no allocation).\n * Cleanup listeners are registered to prevent leaks.\n *\n * @internal\n */\nexport function combineSignals(first: AbortSignal, ...rest: AbortSignal[]): AbortSignal {\n if (rest.length === 0) return first;\n\n return rest.reduce(mergeTwo, first);\n}\n\nfunction mergeTwo(a: AbortSignal, b: AbortSignal): AbortSignal {\n if (a.aborted) return a;\n\n if (b.aborted) return b;\n\n const ctrl = new AbortController();\n const onA = (): void => ctrl.abort(a.reason);\n const onB = (): void => ctrl.abort(b.reason);\n\n a.addEventListener('abort', onA, { once: true });\n b.addEventListener('abort', onB, { once: true });\n ctrl.signal.addEventListener(\n 'abort',\n () => {\n a.removeEventListener('abort', onA);\n b.removeEventListener('abort', onB);\n },\n { once: true },\n );\n\n return ctrl.signal;\n}\n\n/**\n * Create a child `AbortController` that aborts as soon as `parent` does.\n * Handles the case where `parent` is already aborted at call time — a plain\n * `addEventListener('abort', ...)` would miss that, since the event already fired.\n *\n * @internal\n */\nexport function deriveAbortController(parent: AbortSignal): AbortController {\n const ctrl = new AbortController();\n\n if (parent.aborted) {\n ctrl.abort(parent.reason);\n } else {\n parent.addEventListener('abort', () => ctrl.abort(parent.reason), { once: true });\n }\n\n return ctrl;\n}\n\n/**\n * Sleep for `ms` milliseconds, aborting early when the signal fires.\n * Resolves (does not reject) on abort — callers check `signal.aborted`.\n *\n * @internal\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n if (signal?.aborted) {\n resolve();\n\n return;\n }\n\n const id = setTimeout(resolve, ms);\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(id);\n resolve();\n },\n { once: true },\n );\n });\n}\n\n/**\n * Full-jitter exponential backoff in ms, capped at `maxMs`.\n * `attempt` is zero-based.\n *\n * @internal\n */\nexport function defaultReconnectDelay(attempt: number, maxMs = 30_000): number {\n const base = Math.min(1000 *
|
|
1
|
+
{"version":3,"file":"_utils.js","names":[],"sources":["../src/_utils.ts"],"sourcesContent":["/**\n * Returns a signal that aborts as soon as any of the provided signals abort.\n * With a single argument, returns it directly (no allocation).\n * Cleanup listeners are registered to prevent leaks.\n *\n * @internal\n */\nexport function combineSignals(first: AbortSignal, ...rest: AbortSignal[]): AbortSignal {\n if (rest.length === 0) return first;\n\n return rest.reduce(mergeTwo, first);\n}\n\nfunction mergeTwo(a: AbortSignal, b: AbortSignal): AbortSignal {\n if (a.aborted) return a;\n\n if (b.aborted) return b;\n\n const ctrl = new AbortController();\n const onA = (): void => ctrl.abort(a.reason);\n const onB = (): void => ctrl.abort(b.reason);\n\n a.addEventListener('abort', onA, { once: true });\n b.addEventListener('abort', onB, { once: true });\n ctrl.signal.addEventListener(\n 'abort',\n () => {\n a.removeEventListener('abort', onA);\n b.removeEventListener('abort', onB);\n },\n { once: true },\n );\n\n return ctrl.signal;\n}\n\n/**\n * Create a child `AbortController` that aborts as soon as `parent` does.\n * Handles the case where `parent` is already aborted at call time — a plain\n * `addEventListener('abort', ...)` would miss that, since the event already fired.\n *\n * @internal\n */\nexport function deriveAbortController(parent: AbortSignal): AbortController {\n const ctrl = new AbortController();\n\n if (parent.aborted) {\n ctrl.abort(parent.reason);\n } else {\n parent.addEventListener('abort', () => ctrl.abort(parent.reason), { once: true });\n }\n\n return ctrl;\n}\n\n/**\n * Sleep for `ms` milliseconds, aborting early when the signal fires.\n * Resolves (does not reject) on abort — callers check `signal.aborted`.\n *\n * @internal\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n if (signal?.aborted) {\n resolve();\n\n return;\n }\n\n const id = setTimeout(resolve, ms);\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(id);\n resolve();\n },\n { once: true },\n );\n });\n}\n\n/**\n * Full-jitter exponential backoff in ms, capped at `maxMs`.\n * `attempt` is zero-based.\n *\n * @internal\n */\nexport function defaultReconnectDelay(attempt: number, maxMs = 30_000): number {\n const base = Math.min(1000 * 2 ** attempt, maxMs);\n\n return Math.random() * base;\n}\n"],"mappings":";AAOA,SAAgB,EAAe,GAAoB,GAAG,GAAkC;CAGtF,OAFI,EAAK,WAAW,IAAU,IAEvB,EAAK,OAAO,GAAU,CAAK;AACpC;AAEA,SAAS,EAAS,GAAgB,GAA6B;CAC7D,IAAI,EAAE,SAAS,OAAO;CAEtB,IAAI,EAAE,SAAS,OAAO;CAEtB,IAAM,IAAO,IAAI,gBAAgB,GAC3B,UAAkB,EAAK,MAAM,EAAE,MAAM,GACrC,UAAkB,EAAK,MAAM,EAAE,MAAM;CAa3C,OAXA,EAAE,iBAAiB,SAAS,GAAK,EAAE,MAAM,GAAK,CAAC,GAC/C,EAAE,iBAAiB,SAAS,GAAK,EAAE,MAAM,GAAK,CAAC,GAC/C,EAAK,OAAO,iBACV,eACM;EAEJ,AADA,EAAE,oBAAoB,SAAS,CAAG,GAClC,EAAE,oBAAoB,SAAS,CAAG;CACpC,GACA,EAAE,MAAM,GAAK,CACf,GAEO,EAAK;AACd;AASA,SAAgB,EAAsB,GAAsC;CAC1E,IAAM,IAAO,IAAI,gBAAgB;CAQjC,OANI,EAAO,UACT,EAAK,MAAM,EAAO,MAAM,IAExB,EAAO,iBAAiB,eAAe,EAAK,MAAM,EAAO,MAAM,GAAG,EAAE,MAAM,GAAK,CAAC,GAG3E;AACT;AAQA,SAAgB,EAAM,GAAY,GAAqC;CACrE,OAAO,IAAI,SAAS,MAAY;EAC9B,IAAI,GAAQ,SAAS;GACnB,EAAQ;GAER;EACF;EAEA,IAAM,IAAK,WAAW,GAAS,CAAE;EAEjC,GAAQ,iBACN,eACM;GAEJ,AADA,aAAa,CAAE,GACf,EAAQ;EACV,GACA,EAAE,MAAM,GAAK,CACf;CACF,CAAC;AACH;AAQA,SAAgB,EAAsB,GAAiB,IAAQ,KAAgB;CAC7E,IAAM,IAAO,KAAK,IAAI,MAAO,KAAK,GAAS,CAAK;CAEhD,OAAO,KAAK,OAAO,IAAI;AACzB"}
|
package/dist/_wait.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_wait.cjs","names":[],"sources":["../src/_wait.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"_wait.cjs","names":[],"sources":["../src/_wait.ts"],"sourcesContent":["import { combineSignals } from './_utils';\nimport { PulseAbortError, PulseTimeoutError } from './errors';\nimport type { Unsubscribe } from './types';\n\n/**\n * Shared implementation for `pulse.wait()` and `channel.wait()`.\n * Resolves on the next event dispatched via `subscribe`, or rejects when\n * the combined signal aborts or the optional timeout elapses.\n *\n * @internal\n */\nexport function createWaitPromise<T>(\n event: string,\n baseSignal: AbortSignal,\n opts: { signal?: AbortSignal; timeout?: number } | undefined,\n subscribe: (event: string, handler: (payload: unknown) => void) => Unsubscribe,\n): Promise<T> {\n return new Promise((resolve, reject) => {\n const signals: AbortSignal[] = [baseSignal];\n\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n if (opts?.signal) signals.push(opts.signal);\n\n if (opts?.timeout !== undefined) {\n const timeoutCtrl = new AbortController();\n\n timeoutId = setTimeout(() => {\n timeoutCtrl.abort(new PulseTimeoutError(event));\n }, opts.timeout);\n signals.push(timeoutCtrl.signal);\n }\n\n const combined = signals.length === 1 ? signals[0]! : combineSignals(signals[0]!, ...signals.slice(1));\n\n if (combined.aborted) {\n clearTimeout(timeoutId);\n reject(combined.reason instanceof PulseTimeoutError ? combined.reason : new PulseAbortError());\n\n return;\n }\n\n let unsub: Unsubscribe = () => {};\n\n const onAbort = (): void => {\n clearTimeout(timeoutId);\n unsub();\n reject(combined.reason instanceof PulseTimeoutError ? combined.reason : new PulseAbortError());\n };\n\n combined.addEventListener('abort', onAbort, { once: true });\n\n unsub = subscribe(event, (payload) => {\n clearTimeout(timeoutId);\n combined.removeEventListener('abort', onAbort);\n resolve(payload as T);\n });\n });\n}\n"],"mappings":"0DAWA,SAAgB,EACd,EACA,EACA,EACA,EACY,CACZ,OAAO,IAAI,SAAS,EAAS,IAAW,CACtC,IAAM,EAAyB,CAAC,CAAU,EAEtC,EAIJ,GAFI,GAAM,QAAQ,EAAQ,KAAK,EAAK,MAAM,EAEtC,GAAM,UAAY,IAAA,GAAW,CAC/B,IAAM,EAAc,IAAI,gBAExB,EAAY,eAAiB,CAC3B,EAAY,MAAM,IAAI,EAAA,kBAAkB,CAAK,CAAC,CAChD,EAAG,EAAK,OAAO,EACf,EAAQ,KAAK,EAAY,MAAM,CACjC,CAEA,IAAM,EAAW,EAAQ,SAAW,EAAI,EAAQ,GAAM,EAAA,eAAe,EAAQ,GAAK,GAAG,EAAQ,MAAM,CAAC,CAAC,EAErG,GAAI,EAAS,QAAS,CACpB,aAAa,CAAS,EACtB,EAAO,EAAS,kBAAkB,EAAA,kBAAoB,EAAS,OAAS,IAAI,EAAA,eAAiB,EAE7F,MACF,CAEA,IAAI,MAA2B,CAAC,EAE1B,MAAsB,CAC1B,aAAa,CAAS,EACtB,EAAM,EACN,EAAO,EAAS,kBAAkB,EAAA,kBAAoB,EAAS,OAAS,IAAI,EAAA,eAAiB,CAC/F,EAEA,EAAS,iBAAiB,QAAS,EAAS,CAAE,KAAM,EAAK,CAAC,EAE1D,EAAQ,EAAU,EAAQ,GAAY,CACpC,aAAa,CAAS,EACtB,EAAS,oBAAoB,QAAS,CAAO,EAC7C,EAAQ,CAAY,CACtB,CAAC,CACH,CAAC,CACH"}
|
package/dist/_wait.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_wait.js","names":[],"sources":["../src/_wait.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"_wait.js","names":[],"sources":["../src/_wait.ts"],"sourcesContent":["import { combineSignals } from './_utils';\nimport { PulseAbortError, PulseTimeoutError } from './errors';\nimport type { Unsubscribe } from './types';\n\n/**\n * Shared implementation for `pulse.wait()` and `channel.wait()`.\n * Resolves on the next event dispatched via `subscribe`, or rejects when\n * the combined signal aborts or the optional timeout elapses.\n *\n * @internal\n */\nexport function createWaitPromise<T>(\n event: string,\n baseSignal: AbortSignal,\n opts: { signal?: AbortSignal; timeout?: number } | undefined,\n subscribe: (event: string, handler: (payload: unknown) => void) => Unsubscribe,\n): Promise<T> {\n return new Promise((resolve, reject) => {\n const signals: AbortSignal[] = [baseSignal];\n\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n if (opts?.signal) signals.push(opts.signal);\n\n if (opts?.timeout !== undefined) {\n const timeoutCtrl = new AbortController();\n\n timeoutId = setTimeout(() => {\n timeoutCtrl.abort(new PulseTimeoutError(event));\n }, opts.timeout);\n signals.push(timeoutCtrl.signal);\n }\n\n const combined = signals.length === 1 ? signals[0]! : combineSignals(signals[0]!, ...signals.slice(1));\n\n if (combined.aborted) {\n clearTimeout(timeoutId);\n reject(combined.reason instanceof PulseTimeoutError ? combined.reason : new PulseAbortError());\n\n return;\n }\n\n let unsub: Unsubscribe = () => {};\n\n const onAbort = (): void => {\n clearTimeout(timeoutId);\n unsub();\n reject(combined.reason instanceof PulseTimeoutError ? combined.reason : new PulseAbortError());\n };\n\n combined.addEventListener('abort', onAbort, { once: true });\n\n unsub = subscribe(event, (payload) => {\n clearTimeout(timeoutId);\n combined.removeEventListener('abort', onAbort);\n resolve(payload as T);\n });\n });\n}\n"],"mappings":";;;AAWA,SAAgB,EACd,GACA,GACA,GACA,GACY;CACZ,OAAO,IAAI,SAAS,GAAS,MAAW;EACtC,IAAM,IAAyB,CAAC,CAAU,GAEtC;EAIJ,IAFI,GAAM,UAAQ,EAAQ,KAAK,EAAK,MAAM,GAEtC,GAAM,YAAY,KAAA,GAAW;GAC/B,IAAM,IAAc,IAAI,gBAAgB;GAKxC,AAHA,IAAY,iBAAiB;IAC3B,EAAY,MAAM,IAAI,EAAkB,CAAK,CAAC;GAChD,GAAG,EAAK,OAAO,GACf,EAAQ,KAAK,EAAY,MAAM;EACjC;EAEA,IAAM,IAAW,EAAQ,WAAW,IAAI,EAAQ,KAAM,EAAe,EAAQ,IAAK,GAAG,EAAQ,MAAM,CAAC,CAAC;EAErG,IAAI,EAAS,SAAS;GAEpB,AADA,aAAa,CAAS,GACtB,EAAO,EAAS,kBAAkB,IAAoB,EAAS,SAAS,IAAI,EAAgB,CAAC;GAE7F;EACF;EAEA,IAAI,UAA2B,CAAC,GAE1B,UAAsB;GAG1B,AAFA,aAAa,CAAS,GACtB,EAAM,GACN,EAAO,EAAS,kBAAkB,IAAoB,EAAS,SAAS,IAAI,EAAgB,CAAC;EAC/F;EAIA,AAFA,EAAS,iBAAiB,SAAS,GAAS,EAAE,MAAM,GAAK,CAAC,GAE1D,IAAQ,EAAU,IAAQ,MAAY;GAGpC,AAFA,aAAa,CAAS,GACtB,EAAS,oBAAoB,SAAS,CAAO,GAC7C,EAAQ,CAAY;EACtB,CAAC;CACH,CAAC;AACH"}
|
package/dist/channel.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel.cjs","names":[],"sources":["../src/channel.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"channel.cjs","names":[],"sources":["../src/channel.ts"],"sourcesContent":["import { deriveAbortController } from './_utils';\nimport { createWaitPromise } from './_wait';\nimport { PulseDisposedError } from './errors';\nimport type { EventKey, MessageMap, PulseChannel, Unsubscribe } from './types';\n\ntype SendFn = (channel: string, event: string, payload: unknown) => void;\ntype SubscribeFn = (channel: string, event: string, handler: (payload: unknown) => void) => () => void;\n\n/**\n * Create a typed channel object that scopes messaging to a named namespace.\n * @internal\n */\nexport function createChannel<TServer extends MessageMap, TClient extends MessageMap>(\n name: string,\n send: SendFn,\n subscribe: SubscribeFn,\n disposalSignal: AbortSignal,\n onDispose?: () => void,\n): PulseChannel<TServer, TClient> {\n const ctrl = deriveAbortController(disposalSignal);\n const tracked = new Set<() => void>();\n\n let disposed = ctrl.signal.aborted;\n\n ctrl.signal.addEventListener(\n 'abort',\n () => {\n disposed = true;\n },\n { once: true },\n );\n\n const channel: PulseChannel<TServer, TClient> = {\n get disposalSignal() {\n return ctrl.signal;\n },\n\n dispose() {\n if (disposed) return;\n\n disposed = true;\n ctrl.abort();\n\n for (const unsub of tracked) unsub();\n\n tracked.clear();\n onDispose?.();\n },\n\n get disposed() {\n return disposed;\n },\n\n get name() {\n return name;\n },\n\n on<K extends EventKey<TServer>>(event: K, handler: (payload: TServer[K]) => void): Unsubscribe {\n if (disposed) {\n throw new PulseDisposedError(`Channel \"${name}\"`);\n }\n\n const unsub = subscribe(name, event, handler as (payload: unknown) => void);\n\n tracked.add(unsub);\n\n return () => {\n unsub();\n tracked.delete(unsub);\n };\n },\n\n once<K extends EventKey<TServer>>(event: K, handler: (payload: TServer[K]) => void): Unsubscribe {\n if (disposed) {\n throw new PulseDisposedError(`Channel \"${name}\"`);\n }\n\n let unsub: Unsubscribe = () => {};\n\n const wrapped = (payload: unknown): void => {\n tracked.delete(unsub);\n unsub();\n (handler as (payload: unknown) => void)(payload);\n };\n\n unsub = subscribe(name, event, wrapped);\n tracked.add(unsub);\n\n return () => {\n tracked.delete(unsub);\n unsub();\n };\n },\n\n send<K extends EventKey<TClient>>(event: K, payload: TClient[K]): void {\n if (disposed) {\n throw new PulseDisposedError(`Channel \"${name}\"`);\n }\n\n send(name, event, payload);\n },\n\n [Symbol.dispose]() {\n this.dispose();\n },\n\n wait<K extends EventKey<TServer>>(\n event: K,\n opts?: { signal?: AbortSignal; timeout?: number },\n ): Promise<TServer[K]> {\n return createWaitPromise<TServer[K]>(event as string, ctrl.signal, opts, (ev, handler) =>\n subscribe(name, ev, handler),\n );\n },\n };\n\n return channel;\n}\n"],"mappings":"mFAYA,SAAgB,EACd,EACA,EACA,EACA,EACA,EACgC,CAChC,IAAM,EAAO,EAAA,sBAAsB,CAAc,EAC3C,EAAU,IAAI,IAEhB,EAAW,EAAK,OAAO,QA8F3B,OA5FA,EAAK,OAAO,iBACV,YACM,CACJ,EAAW,EACb,EACA,CAAE,KAAM,EAAK,CACf,EAsFO,CAnFL,IAAI,gBAAiB,CACnB,OAAO,EAAK,MACd,EAEA,SAAU,CACJ,MAGJ,CADA,EAAW,GACX,EAAK,MAAM,EAEX,IAAK,IAAM,KAAS,EAAS,EAAM,EAEnC,EAAQ,MAAM,EACd,IAAY,CALD,CAMb,EAEA,IAAI,UAAW,CACb,OAAO,CACT,EAEA,IAAI,MAAO,CACT,OAAO,CACT,EAEA,GAAgC,EAAU,EAAqD,CAC7F,GAAI,EACF,MAAM,IAAI,EAAA,mBAAmB,YAAY,EAAK,EAAE,EAGlD,IAAM,EAAQ,EAAU,EAAM,EAAO,CAAqC,EAI1E,OAFA,EAAQ,IAAI,CAAK,MAEJ,CACX,EAAM,EACN,EAAQ,OAAO,CAAK,CACtB,CACF,EAEA,KAAkC,EAAU,EAAqD,CAC/F,GAAI,EACF,MAAM,IAAI,EAAA,mBAAmB,YAAY,EAAK,EAAE,EAGlD,IAAI,MAA2B,CAAC,EAWhC,MAHA,GAAQ,EAAU,EAAM,EANP,GAA2B,CAC1C,EAAQ,OAAO,CAAK,EACpB,EAAM,EACN,EAAwC,CAAO,CACjD,CAEsC,EACtC,EAAQ,IAAI,CAAK,MAEJ,CACX,EAAQ,OAAO,CAAK,EACpB,EAAM,CACR,CACF,EAEA,KAAkC,EAAU,EAA2B,CACrE,GAAI,EACF,MAAM,IAAI,EAAA,mBAAmB,YAAY,EAAK,EAAE,EAGlD,EAAK,EAAM,EAAO,CAAO,CAC3B,EAEA,CAAC,OAAO,UAAW,CACjB,KAAK,QAAQ,CACf,EAEA,KACE,EACA,EACqB,CACrB,OAAO,EAAA,kBAA8B,EAAiB,EAAK,OAAQ,GAAO,EAAI,IAC5E,EAAU,EAAM,EAAI,CAAO,CAC7B,CACF,CAGK,CACT"}
|
package/dist/channel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel.js","names":[],"sources":["../src/channel.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"channel.js","names":[],"sources":["../src/channel.ts"],"sourcesContent":["import { deriveAbortController } from './_utils';\nimport { createWaitPromise } from './_wait';\nimport { PulseDisposedError } from './errors';\nimport type { EventKey, MessageMap, PulseChannel, Unsubscribe } from './types';\n\ntype SendFn = (channel: string, event: string, payload: unknown) => void;\ntype SubscribeFn = (channel: string, event: string, handler: (payload: unknown) => void) => () => void;\n\n/**\n * Create a typed channel object that scopes messaging to a named namespace.\n * @internal\n */\nexport function createChannel<TServer extends MessageMap, TClient extends MessageMap>(\n name: string,\n send: SendFn,\n subscribe: SubscribeFn,\n disposalSignal: AbortSignal,\n onDispose?: () => void,\n): PulseChannel<TServer, TClient> {\n const ctrl = deriveAbortController(disposalSignal);\n const tracked = new Set<() => void>();\n\n let disposed = ctrl.signal.aborted;\n\n ctrl.signal.addEventListener(\n 'abort',\n () => {\n disposed = true;\n },\n { once: true },\n );\n\n const channel: PulseChannel<TServer, TClient> = {\n get disposalSignal() {\n return ctrl.signal;\n },\n\n dispose() {\n if (disposed) return;\n\n disposed = true;\n ctrl.abort();\n\n for (const unsub of tracked) unsub();\n\n tracked.clear();\n onDispose?.();\n },\n\n get disposed() {\n return disposed;\n },\n\n get name() {\n return name;\n },\n\n on<K extends EventKey<TServer>>(event: K, handler: (payload: TServer[K]) => void): Unsubscribe {\n if (disposed) {\n throw new PulseDisposedError(`Channel \"${name}\"`);\n }\n\n const unsub = subscribe(name, event, handler as (payload: unknown) => void);\n\n tracked.add(unsub);\n\n return () => {\n unsub();\n tracked.delete(unsub);\n };\n },\n\n once<K extends EventKey<TServer>>(event: K, handler: (payload: TServer[K]) => void): Unsubscribe {\n if (disposed) {\n throw new PulseDisposedError(`Channel \"${name}\"`);\n }\n\n let unsub: Unsubscribe = () => {};\n\n const wrapped = (payload: unknown): void => {\n tracked.delete(unsub);\n unsub();\n (handler as (payload: unknown) => void)(payload);\n };\n\n unsub = subscribe(name, event, wrapped);\n tracked.add(unsub);\n\n return () => {\n tracked.delete(unsub);\n unsub();\n };\n },\n\n send<K extends EventKey<TClient>>(event: K, payload: TClient[K]): void {\n if (disposed) {\n throw new PulseDisposedError(`Channel \"${name}\"`);\n }\n\n send(name, event, payload);\n },\n\n [Symbol.dispose]() {\n this.dispose();\n },\n\n wait<K extends EventKey<TServer>>(\n event: K,\n opts?: { signal?: AbortSignal; timeout?: number },\n ): Promise<TServer[K]> {\n return createWaitPromise<TServer[K]>(event as string, ctrl.signal, opts, (ev, handler) =>\n subscribe(name, ev, handler),\n );\n },\n };\n\n return channel;\n}\n"],"mappings":";;;;AAYA,SAAgB,EACd,GACA,GACA,GACA,GACA,GACgC;CAChC,IAAM,IAAO,EAAsB,CAAc,GAC3C,oBAAU,IAAI,IAAgB,GAEhC,IAAW,EAAK,OAAO;CA8F3B,OA5FA,EAAK,OAAO,iBACV,eACM;EACJ,IAAW;CACb,GACA,EAAE,MAAM,GAAK,CACf,GAsFO;EAnFL,IAAI,iBAAiB;GACnB,OAAO,EAAK;EACd;EAEA,UAAU;GACJ,QAGJ;IADA,IAAW,IACX,EAAK,MAAM;IAEX,KAAK,IAAM,KAAS,GAAS,EAAM;IAGnC,AADA,EAAQ,MAAM,GACd,IAAY;GALD;EAMb;EAEA,IAAI,WAAW;GACb,OAAO;EACT;EAEA,IAAI,OAAO;GACT,OAAO;EACT;EAEA,GAAgC,GAAU,GAAqD;GAC7F,IAAI,GACF,MAAM,IAAI,EAAmB,YAAY,EAAK,EAAE;GAGlD,IAAM,IAAQ,EAAU,GAAM,GAAO,CAAqC;GAI1E,OAFA,EAAQ,IAAI,CAAK,SAEJ;IAEX,AADA,EAAM,GACN,EAAQ,OAAO,CAAK;GACtB;EACF;EAEA,KAAkC,GAAU,GAAqD;GAC/F,IAAI,GACF,MAAM,IAAI,EAAmB,YAAY,EAAK,EAAE;GAGlD,IAAI,UAA2B,CAAC;GAWhC,OAHA,IAAQ,EAAU,GAAM,IANP,MAA2B;IAG1C,AAFA,EAAQ,OAAO,CAAK,GACpB,EAAM,GACN,EAAwC,CAAO;GACjD,CAEsC,GACtC,EAAQ,IAAI,CAAK,SAEJ;IAEX,AADA,EAAQ,OAAO,CAAK,GACpB,EAAM;GACR;EACF;EAEA,KAAkC,GAAU,GAA2B;GACrE,IAAI,GACF,MAAM,IAAI,EAAmB,YAAY,EAAK,EAAE;GAGlD,EAAK,GAAM,GAAO,CAAO;EAC3B;EAEA,CAAC,OAAO,WAAW;GACjB,KAAK,QAAQ;EACf;EAEA,KACE,GACA,GACqB;GACrB,OAAO,EAA8B,GAAiB,EAAK,QAAQ,IAAO,GAAI,MAC5E,EAAU,GAAM,GAAI,CAAO,CAC7B;EACF;CAGK;AACT"}
|
package/dist/heartbeat.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heartbeat.cjs","names":[],"sources":["../src/heartbeat.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"heartbeat.cjs","names":[],"sources":["../src/heartbeat.ts"],"sourcesContent":["import { encode } from './protocol';\nimport type { HeartbeatOptions } from './types';\n\nconst DEFAULT_INTERVAL = 30_000;\nconst DEFAULT_TIMEOUT = 5_000;\n\nexport type HeartbeatHandle = {\n /** Called when a `pong` frame is received. Resets the timeout timer. */\n onPong(): void;\n /** Start the heartbeat loop. */\n start(): void;\n /** Stop the heartbeat loop and cancel any pending timers. */\n stop(): void;\n};\n\n/**\n * Create a heartbeat manager that sends periodic pings and expects pong replies.\n * Calls `onDead` when a pong is not received within the timeout window.\n * @internal\n */\nexport function createHeartbeat(\n opts: boolean | HeartbeatOptions | undefined,\n send: (frame: string) => void,\n onDead: () => void,\n): HeartbeatHandle {\n if (!opts) {\n return { onPong() {}, start() {}, stop() {} };\n }\n\n const options: HeartbeatOptions = opts === true ? {} : opts;\n const interval = options.interval ?? DEFAULT_INTERVAL;\n const timeout = options.timeout ?? DEFAULT_TIMEOUT;\n\n let pingTimer: ReturnType<typeof setTimeout> | undefined;\n let pongTimer: ReturnType<typeof setTimeout> | undefined;\n let running = false;\n\n function schedulePing(): void {\n pingTimer = setTimeout(() => {\n const ts = Date.now();\n\n send(encode({ ts, type: 'ping' }));\n\n pongTimer = setTimeout(() => {\n onDead();\n }, timeout);\n }, interval);\n }\n\n return {\n onPong() {\n clearTimeout(pongTimer);\n pongTimer = undefined;\n\n if (running) schedulePing();\n },\n\n start() {\n running = true;\n clearTimeout(pingTimer);\n clearTimeout(pongTimer);\n pongTimer = undefined;\n schedulePing();\n },\n\n stop() {\n running = false;\n clearTimeout(pingTimer);\n clearTimeout(pongTimer);\n pingTimer = undefined;\n pongTimer = undefined;\n },\n };\n}\n"],"mappings":"kCAGA,IAAM,EAAmB,IACnB,EAAkB,IAgBxB,SAAgB,EACd,EACA,EACA,EACiB,CACjB,GAAI,CAAC,EACH,MAAO,CAAE,QAAS,CAAC,EAAG,OAAQ,CAAC,EAAG,MAAO,CAAC,CAAE,EAG9C,IAAM,EAA4B,IAAS,GAAO,CAAC,EAAI,EACjD,EAAW,EAAQ,UAAY,EAC/B,EAAU,EAAQ,SAAW,EAE/B,EACA,EACA,EAAU,GAEd,SAAS,GAAqB,CAC5B,EAAY,eAAiB,CAG3B,EAAK,EAAA,OAAO,CAAE,GAFH,KAAK,IAEF,EAAI,KAAM,MAAO,CAAC,CAAC,EAEjC,EAAY,eAAiB,CAC3B,EAAO,CACT,EAAG,CAAO,CACZ,EAAG,CAAQ,CACb,CAEA,MAAO,CACL,QAAS,CACP,aAAa,CAAS,EACtB,EAAY,IAAA,GAER,GAAS,EAAa,CAC5B,EAEA,OAAQ,CACN,EAAU,GACV,aAAa,CAAS,EACtB,aAAa,CAAS,EACtB,EAAY,IAAA,GACZ,EAAa,CACf,EAEA,MAAO,CACL,EAAU,GACV,aAAa,CAAS,EACtB,aAAa,CAAS,EACtB,EAAY,IAAA,GACZ,EAAY,IAAA,EACd,CACF,CACF"}
|
package/dist/heartbeat.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"","sources":["../src/heartbeat.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"","sources":["../src/heartbeat.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,eAAe,GAAG;IAC5B,wEAAwE;IACxE,MAAM,IAAI,IAAI,CAAC;IACf,gCAAgC;IAChC,KAAK,IAAI,IAAI,CAAC;IACd,6DAA6D;IAC7D,IAAI,IAAI,IAAI,CAAC;CACd,CAAC"}
|
package/dist/heartbeat.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heartbeat.js","names":[],"sources":["../src/heartbeat.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"heartbeat.js","names":[],"sources":["../src/heartbeat.ts"],"sourcesContent":["import { encode } from './protocol';\nimport type { HeartbeatOptions } from './types';\n\nconst DEFAULT_INTERVAL = 30_000;\nconst DEFAULT_TIMEOUT = 5_000;\n\nexport type HeartbeatHandle = {\n /** Called when a `pong` frame is received. Resets the timeout timer. */\n onPong(): void;\n /** Start the heartbeat loop. */\n start(): void;\n /** Stop the heartbeat loop and cancel any pending timers. */\n stop(): void;\n};\n\n/**\n * Create a heartbeat manager that sends periodic pings and expects pong replies.\n * Calls `onDead` when a pong is not received within the timeout window.\n * @internal\n */\nexport function createHeartbeat(\n opts: boolean | HeartbeatOptions | undefined,\n send: (frame: string) => void,\n onDead: () => void,\n): HeartbeatHandle {\n if (!opts) {\n return { onPong() {}, start() {}, stop() {} };\n }\n\n const options: HeartbeatOptions = opts === true ? {} : opts;\n const interval = options.interval ?? DEFAULT_INTERVAL;\n const timeout = options.timeout ?? DEFAULT_TIMEOUT;\n\n let pingTimer: ReturnType<typeof setTimeout> | undefined;\n let pongTimer: ReturnType<typeof setTimeout> | undefined;\n let running = false;\n\n function schedulePing(): void {\n pingTimer = setTimeout(() => {\n const ts = Date.now();\n\n send(encode({ ts, type: 'ping' }));\n\n pongTimer = setTimeout(() => {\n onDead();\n }, timeout);\n }, interval);\n }\n\n return {\n onPong() {\n clearTimeout(pongTimer);\n pongTimer = undefined;\n\n if (running) schedulePing();\n },\n\n start() {\n running = true;\n clearTimeout(pingTimer);\n clearTimeout(pongTimer);\n pongTimer = undefined;\n schedulePing();\n },\n\n stop() {\n running = false;\n clearTimeout(pingTimer);\n clearTimeout(pongTimer);\n pingTimer = undefined;\n pongTimer = undefined;\n },\n };\n}\n"],"mappings":";;AAGA,IAAM,IAAmB,KACnB,IAAkB;AAgBxB,SAAgB,EACd,GACA,GACA,GACiB;CACjB,IAAI,CAAC,GACH,OAAO;EAAE,SAAS,CAAC;EAAG,QAAQ,CAAC;EAAG,OAAO,CAAC;CAAE;CAG9C,IAAM,IAA4B,MAAS,KAAO,CAAC,IAAI,GACjD,IAAW,EAAQ,YAAY,GAC/B,IAAU,EAAQ,WAAW,GAE/B,GACA,GACA,IAAU;CAEd,SAAS,IAAqB;EAC5B,IAAY,iBAAiB;GAK3B,AAFA,EAAK,EAAO;IAAE,IAFH,KAAK,IAEF;IAAI,MAAM;GAAO,CAAC,CAAC,GAEjC,IAAY,iBAAiB;IAC3B,EAAO;GACT,GAAG,CAAO;EACZ,GAAG,CAAQ;CACb;CAEA,OAAO;EACL,SAAS;GAIP,AAHA,aAAa,CAAS,GACtB,IAAY,KAAA,GAER,KAAS,EAAa;EAC5B;EAEA,QAAQ;GAKN,AAJA,IAAU,IACV,aAAa,CAAS,GACtB,aAAa,CAAS,GACtB,IAAY,KAAA,GACZ,EAAa;EACf;EAEA,OAAO;GAKL,AAJA,IAAU,IACV,aAAa,CAAS,GACtB,aAAa,CAAS,GACtB,IAAY,KAAA,GACZ,IAAY,KAAA;EACd;CACF;AACF"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { ChannelDefinition, ChannelDefinitions, EventKey, HeartbeatOptions, MessageMap, OutgoingMessage, OutgoingTransform, PresenceChannel, Pulse, PulseChannel, PulseOptions, PulseStatus, PresenceDefinitions, ReconnectOptions, Unsubscribe, } from './types';
|
|
2
1
|
export { PulseAbortError, PulseConnectionError, PulseDisposedError, PulseError, PulseProtocolError, PulseTimeoutError, } from './errors';
|
|
3
2
|
export { createPulse } from './pulse';
|
|
3
|
+
export type { ChannelDefinition, ChannelDefinitions, EventKey, HeartbeatOptions, MessageMap, OutgoingMessage, OutgoingTransform, PresenceChannel, PresenceDefinitions, Pulse, PulseChannel, PulseOptions, PulseStatus, ReconnectOptions, Unsubscribe, } from './types';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,KAAK,EACL,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,UAAU,EACV,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,KAAK,EACL,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,WAAW,GACZ,MAAM,SAAS,CAAC"}
|
package/dist/presence.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presence.cjs","names":[],"sources":["../src/presence.ts"],"sourcesContent":["import { type Signal, signal } from '@vielzeug/ripple';\
|
|
1
|
+
{"version":3,"file":"presence.cjs","names":[],"sources":["../src/presence.ts"],"sourcesContent":["import { type Signal, signal } from '@vielzeug/ripple';\nimport { deriveAbortController } from './_utils';\nimport { PulseDisposedError } from './errors';\nimport type { InPresenceJoinFrame, InPresenceLeaveFrame, InPresenceStateFrame } from './protocol';\nimport type { PresenceChannel, Unsubscribe } from './types';\n\ntype UpdateFn<T> = (room: string, state: T) => void;\n\nexport type PresenceEvents = {\n onJoin(handler: (frame: InPresenceJoinFrame) => void): Unsubscribe;\n onLeave(handler: (frame: InPresenceLeaveFrame) => void): Unsubscribe;\n onState(handler: (frame: InPresenceStateFrame) => void): Unsubscribe;\n};\n\n/**\n * Create a presence channel that reactively tracks room member states.\n * @internal\n */\nexport function createPresence<T>(\n room: string,\n update: UpdateFn<T>,\n events: PresenceEvents,\n disposalSignal: AbortSignal,\n registerReset?: (reset: () => void) => void,\n onDispose?: () => void,\n): PresenceChannel<T> {\n const ctrl = deriveAbortController(disposalSignal);\n\n let disposed = ctrl.signal.aborted;\n\n ctrl.signal.addEventListener(\n 'abort',\n () => {\n disposed = true;\n },\n { once: true },\n );\n\n const members: Signal<Map<string, T>> = signal(new Map<string, T>());\n\n registerReset?.(() => {\n members.value = new Map<string, T>();\n });\n\n const joinHandlers = new Set<(memberId: string, state: T) => void>();\n const leaveHandlers = new Set<(memberId: string) => void>();\n\n const unsubs: Array<() => void> = [\n events.onState((frame) => {\n if (frame.room !== room) return;\n\n const next = new Map<string, T>();\n\n for (const [id, state] of Object.entries(frame.members)) {\n next.set(id, state as T);\n }\n\n members.value = next;\n }),\n events.onJoin((frame) => {\n if (frame.room !== room) return;\n\n const next = new Map(members.value);\n\n next.set(frame.id, frame.state as T);\n members.value = next;\n\n for (const handler of joinHandlers) {\n handler(frame.id, frame.state as T);\n }\n }),\n events.onLeave((frame) => {\n if (frame.room !== room) return;\n\n const next = new Map(members.value);\n\n next.delete(frame.id);\n members.value = next;\n\n for (const handler of leaveHandlers) {\n handler(frame.id);\n }\n }),\n ];\n\n const presence: PresenceChannel<T> = {\n get disposalSignal() {\n return ctrl.signal;\n },\n\n dispose() {\n if (disposed) return;\n\n disposed = true;\n ctrl.abort();\n\n for (const unsub of unsubs) unsub();\n\n unsubs.length = 0;\n joinHandlers.clear();\n leaveHandlers.clear();\n onDispose?.();\n },\n\n get disposed() {\n return disposed;\n },\n\n onJoin(handler: (memberId: string, state: T) => void): Unsubscribe {\n if (disposed) {\n throw new PulseDisposedError(`Presence \"${room}\"`);\n }\n\n joinHandlers.add(handler);\n\n return () => joinHandlers.delete(handler);\n },\n\n onLeave(handler: (memberId: string) => void): Unsubscribe {\n if (disposed) {\n throw new PulseDisposedError(`Presence \"${room}\"`);\n }\n\n leaveHandlers.add(handler);\n\n return () => leaveHandlers.delete(handler);\n },\n\n get room() {\n return room;\n },\n\n get state() {\n return members;\n },\n\n [Symbol.dispose]() {\n this.dispose();\n },\n\n update(state: T): void {\n if (disposed) throw new PulseDisposedError(`Presence \"${room}\"`);\n\n update(room, state);\n },\n };\n\n return presence;\n}\n"],"mappings":"4FAkBA,SAAgB,EACd,EACA,EACA,EACA,EACA,EACA,EACoB,CACpB,IAAM,EAAO,EAAA,sBAAsB,CAAc,EAE7C,EAAW,EAAK,OAAO,QAE3B,EAAK,OAAO,iBACV,YACM,CACJ,EAAW,EACb,EACA,CAAE,KAAM,EAAK,CACf,EAEA,IAAM,GAAA,EAAkC,EAAA,OAAA,CAAO,IAAI,GAAgB,EAEnE,QAAsB,CACpB,EAAQ,MAAQ,IAAI,GACtB,CAAC,EAED,IAAM,EAAe,IAAI,IACnB,EAAgB,IAAI,IAEpB,EAA4B,CAChC,EAAO,QAAS,GAAU,CACxB,GAAI,EAAM,OAAS,EAAM,OAEzB,IAAM,EAAO,IAAI,IAEjB,IAAK,GAAM,CAAC,EAAI,KAAU,OAAO,QAAQ,EAAM,OAAO,EACpD,EAAK,IAAI,EAAI,CAAU,EAGzB,EAAQ,MAAQ,CAClB,CAAC,EACD,EAAO,OAAQ,GAAU,CACvB,GAAI,EAAM,OAAS,EAAM,OAEzB,IAAM,EAAO,IAAI,IAAI,EAAQ,KAAK,EAElC,EAAK,IAAI,EAAM,GAAI,EAAM,KAAU,EACnC,EAAQ,MAAQ,EAEhB,IAAK,IAAM,KAAW,EACpB,EAAQ,EAAM,GAAI,EAAM,KAAU,CAEtC,CAAC,EACD,EAAO,QAAS,GAAU,CACxB,GAAI,EAAM,OAAS,EAAM,OAEzB,IAAM,EAAO,IAAI,IAAI,EAAQ,KAAK,EAElC,EAAK,OAAO,EAAM,EAAE,EACpB,EAAQ,MAAQ,EAEhB,IAAK,IAAM,KAAW,EACpB,EAAQ,EAAM,EAAE,CAEpB,CAAC,CACH,EAgEA,MAAO,CA7DL,IAAI,gBAAiB,CACnB,OAAO,EAAK,MACd,EAEA,SAAU,CACJ,MAGJ,CADA,EAAW,GACX,EAAK,MAAM,EAEX,IAAK,IAAM,KAAS,EAAQ,EAAM,EAElC,EAAO,OAAS,EAChB,EAAa,MAAM,EACnB,EAAc,MAAM,EACpB,IAAY,CAPD,CAQb,EAEA,IAAI,UAAW,CACb,OAAO,CACT,EAEA,OAAO,EAA4D,CACjE,GAAI,EACF,MAAM,IAAI,EAAA,mBAAmB,aAAa,EAAK,EAAE,EAKnD,OAFA,EAAa,IAAI,CAAO,MAEX,EAAa,OAAO,CAAO,CAC1C,EAEA,QAAQ,EAAkD,CACxD,GAAI,EACF,MAAM,IAAI,EAAA,mBAAmB,aAAa,EAAK,EAAE,EAKnD,OAFA,EAAc,IAAI,CAAO,MAEZ,EAAc,OAAO,CAAO,CAC3C,EAEA,IAAI,MAAO,CACT,OAAO,CACT,EAEA,IAAI,OAAQ,CACV,OAAO,CACT,EAEA,CAAC,OAAO,UAAW,CACjB,KAAK,QAAQ,CACf,EAEA,OAAO,EAAgB,CACrB,GAAI,EAAU,MAAM,IAAI,EAAA,mBAAmB,aAAa,EAAK,EAAE,EAE/D,EAAO,EAAM,CAAK,CACpB,CAGK,CACT"}
|
package/dist/presence.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { InPresenceJoinFrame, InPresenceLeaveFrame, InPresenceStateFrame } from './protocol';
|
|
1
2
|
import type { Unsubscribe } from './types';
|
|
2
|
-
import { type InPresenceJoinFrame, type InPresenceLeaveFrame, type InPresenceStateFrame } from './protocol';
|
|
3
3
|
export type PresenceEvents = {
|
|
4
4
|
onJoin(handler: (frame: InPresenceJoinFrame) => void): Unsubscribe;
|
|
5
5
|
onLeave(handler: (frame: InPresenceLeaveFrame) => void): Unsubscribe;
|
package/dist/presence.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../src/presence.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../src/presence.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClG,OAAO,KAAK,EAAmB,WAAW,EAAE,MAAM,SAAS,CAAC;AAI5D,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,GAAG,WAAW,CAAC;IACnE,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAAG,WAAW,CAAC;IACrE,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAAG,WAAW,CAAC;CACtE,CAAC"}
|
package/dist/presence.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presence.js","names":[],"sources":["../src/presence.ts"],"sourcesContent":["import { type Signal, signal } from '@vielzeug/ripple';\
|
|
1
|
+
{"version":3,"file":"presence.js","names":[],"sources":["../src/presence.ts"],"sourcesContent":["import { type Signal, signal } from '@vielzeug/ripple';\nimport { deriveAbortController } from './_utils';\nimport { PulseDisposedError } from './errors';\nimport type { InPresenceJoinFrame, InPresenceLeaveFrame, InPresenceStateFrame } from './protocol';\nimport type { PresenceChannel, Unsubscribe } from './types';\n\ntype UpdateFn<T> = (room: string, state: T) => void;\n\nexport type PresenceEvents = {\n onJoin(handler: (frame: InPresenceJoinFrame) => void): Unsubscribe;\n onLeave(handler: (frame: InPresenceLeaveFrame) => void): Unsubscribe;\n onState(handler: (frame: InPresenceStateFrame) => void): Unsubscribe;\n};\n\n/**\n * Create a presence channel that reactively tracks room member states.\n * @internal\n */\nexport function createPresence<T>(\n room: string,\n update: UpdateFn<T>,\n events: PresenceEvents,\n disposalSignal: AbortSignal,\n registerReset?: (reset: () => void) => void,\n onDispose?: () => void,\n): PresenceChannel<T> {\n const ctrl = deriveAbortController(disposalSignal);\n\n let disposed = ctrl.signal.aborted;\n\n ctrl.signal.addEventListener(\n 'abort',\n () => {\n disposed = true;\n },\n { once: true },\n );\n\n const members: Signal<Map<string, T>> = signal(new Map<string, T>());\n\n registerReset?.(() => {\n members.value = new Map<string, T>();\n });\n\n const joinHandlers = new Set<(memberId: string, state: T) => void>();\n const leaveHandlers = new Set<(memberId: string) => void>();\n\n const unsubs: Array<() => void> = [\n events.onState((frame) => {\n if (frame.room !== room) return;\n\n const next = new Map<string, T>();\n\n for (const [id, state] of Object.entries(frame.members)) {\n next.set(id, state as T);\n }\n\n members.value = next;\n }),\n events.onJoin((frame) => {\n if (frame.room !== room) return;\n\n const next = new Map(members.value);\n\n next.set(frame.id, frame.state as T);\n members.value = next;\n\n for (const handler of joinHandlers) {\n handler(frame.id, frame.state as T);\n }\n }),\n events.onLeave((frame) => {\n if (frame.room !== room) return;\n\n const next = new Map(members.value);\n\n next.delete(frame.id);\n members.value = next;\n\n for (const handler of leaveHandlers) {\n handler(frame.id);\n }\n }),\n ];\n\n const presence: PresenceChannel<T> = {\n get disposalSignal() {\n return ctrl.signal;\n },\n\n dispose() {\n if (disposed) return;\n\n disposed = true;\n ctrl.abort();\n\n for (const unsub of unsubs) unsub();\n\n unsubs.length = 0;\n joinHandlers.clear();\n leaveHandlers.clear();\n onDispose?.();\n },\n\n get disposed() {\n return disposed;\n },\n\n onJoin(handler: (memberId: string, state: T) => void): Unsubscribe {\n if (disposed) {\n throw new PulseDisposedError(`Presence \"${room}\"`);\n }\n\n joinHandlers.add(handler);\n\n return () => joinHandlers.delete(handler);\n },\n\n onLeave(handler: (memberId: string) => void): Unsubscribe {\n if (disposed) {\n throw new PulseDisposedError(`Presence \"${room}\"`);\n }\n\n leaveHandlers.add(handler);\n\n return () => leaveHandlers.delete(handler);\n },\n\n get room() {\n return room;\n },\n\n get state() {\n return members;\n },\n\n [Symbol.dispose]() {\n this.dispose();\n },\n\n update(state: T): void {\n if (disposed) throw new PulseDisposedError(`Presence \"${room}\"`);\n\n update(room, state);\n },\n };\n\n return presence;\n}\n"],"mappings":";;;;AAkBA,SAAgB,EACd,GACA,GACA,GACA,GACA,GACA,GACoB;CACpB,IAAM,IAAO,EAAsB,CAAc,GAE7C,IAAW,EAAK,OAAO;CAE3B,EAAK,OAAO,iBACV,eACM;EACJ,IAAW;CACb,GACA,EAAE,MAAM,GAAK,CACf;CAEA,IAAM,IAAkC,kBAAO,IAAI,IAAe,CAAC;CAEnE,UAAsB;EACpB,EAAQ,wBAAQ,IAAI,IAAe;CACrC,CAAC;CAED,IAAM,oBAAe,IAAI,IAA0C,GAC7D,oBAAgB,IAAI,IAAgC,GAEpD,IAA4B;EAChC,EAAO,SAAS,MAAU;GACxB,IAAI,EAAM,SAAS,GAAM;GAEzB,IAAM,oBAAO,IAAI,IAAe;GAEhC,KAAK,IAAM,CAAC,GAAI,MAAU,OAAO,QAAQ,EAAM,OAAO,GACpD,EAAK,IAAI,GAAI,CAAU;GAGzB,EAAQ,QAAQ;EAClB,CAAC;EACD,EAAO,QAAQ,MAAU;GACvB,IAAI,EAAM,SAAS,GAAM;GAEzB,IAAM,IAAO,IAAI,IAAI,EAAQ,KAAK;GAGlC,AADA,EAAK,IAAI,EAAM,IAAI,EAAM,KAAU,GACnC,EAAQ,QAAQ;GAEhB,KAAK,IAAM,KAAW,GACpB,EAAQ,EAAM,IAAI,EAAM,KAAU;EAEtC,CAAC;EACD,EAAO,SAAS,MAAU;GACxB,IAAI,EAAM,SAAS,GAAM;GAEzB,IAAM,IAAO,IAAI,IAAI,EAAQ,KAAK;GAGlC,AADA,EAAK,OAAO,EAAM,EAAE,GACpB,EAAQ,QAAQ;GAEhB,KAAK,IAAM,KAAW,GACpB,EAAQ,EAAM,EAAE;EAEpB,CAAC;CACH;CAgEA,OAAO;EA7DL,IAAI,iBAAiB;GACnB,OAAO,EAAK;EACd;EAEA,UAAU;GACJ,QAGJ;IADA,IAAW,IACX,EAAK,MAAM;IAEX,KAAK,IAAM,KAAS,GAAQ,EAAM;IAKlC,AAHA,EAAO,SAAS,GAChB,EAAa,MAAM,GACnB,EAAc,MAAM,GACpB,IAAY;GAPD;EAQb;EAEA,IAAI,WAAW;GACb,OAAO;EACT;EAEA,OAAO,GAA4D;GACjE,IAAI,GACF,MAAM,IAAI,EAAmB,aAAa,EAAK,EAAE;GAKnD,OAFA,EAAa,IAAI,CAAO,SAEX,EAAa,OAAO,CAAO;EAC1C;EAEA,QAAQ,GAAkD;GACxD,IAAI,GACF,MAAM,IAAI,EAAmB,aAAa,EAAK,EAAE;GAKnD,OAFA,EAAc,IAAI,CAAO,SAEZ,EAAc,OAAO,CAAO;EAC3C;EAEA,IAAI,OAAO;GACT,OAAO;EACT;EAEA,IAAI,QAAQ;GACV,OAAO;EACT;EAEA,CAAC,OAAO,WAAW;GACjB,KAAK,QAAQ;EACf;EAEA,OAAO,GAAgB;GACrB,IAAI,GAAU,MAAM,IAAI,EAAmB,aAAa,EAAK,EAAE;GAE/D,EAAO,GAAM,CAAK;EACpB;CAGK;AACT"}
|
package/dist/protocol.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.cjs","names":[],"sources":["../src/protocol.ts"],"sourcesContent":["import { PulseProtocolError } from './errors';\n\n// ─── Outgoing frames (client → server) ────────────────────────────────────────\n\nexport type OutMessageFrame = { channel?: string; event: string; payload: unknown; type: 'message' };\nexport type OutSubscribeFrame = { channel: string; type: 'subscribe' };\nexport type OutUnsubscribeFrame = { channel: string; type: 'unsubscribe' };\nexport type OutJoinFrame = { room: string; type: 'join' };\nexport type OutLeaveFrame = { room: string; type: 'leave' };\nexport type OutPresenceFrame = { room: string; state: unknown; type: 'presence' };\nexport type OutPingFrame = { ts: number; type: 'ping' };\n\nexport type OutFrame =\n | OutJoinFrame\n | OutLeaveFrame\n | OutMessageFrame\n | OutPingFrame\n | OutPresenceFrame\n | OutSubscribeFrame\n | OutUnsubscribeFrame;\n\n// ─── Incoming frames (server → client) ────────────────────────────────────────\n\nexport type InMessageFrame = { channel?: string; event: string; payload: unknown; type: 'message' };\nexport type InSubscribedFrame = { channel: string; type: 'subscribed' };\nexport type InUnsubscribedFrame = { channel: string; type: 'unsubscribed' };\nexport type InJoinedFrame = { room: string; type: 'joined' };\nexport type InLeftFrame = { room: string; type: 'left' };\nexport type InPresenceStateFrame = { members: Record<string, unknown>; room: string; type: 'presence_state' };\nexport type InPresenceJoinFrame = { id: string; room: string; state: unknown; type: 'presence_join' };\nexport type InPresenceLeaveFrame = { id: string; room: string; type: 'presence_leave' };\nexport type InPongFrame = { ts: number; type: 'pong' };\nexport type InErrorFrame = { code: string; message: string; type: 'error' };\n\nexport type InFrame =\n | InErrorFrame\n | InJoinedFrame\n | InLeftFrame\n | InMessageFrame\n | InPongFrame\n | InPresenceJoinFrame\n | InPresenceLeaveFrame\n | InPresenceStateFrame\n | InSubscribedFrame\n | InUnsubscribedFrame;\n\ntype ParsedFrame = { type: string } & Record<string, unknown>;\nexport type DecodedInFrame = { frame: InFrame; kind: 'known' } | { kind: 'unknown'; type: string };\n\n// ─── Codec ────────────────────────────────────────────────────────────────────\n\n/**\n * Encode an outgoing frame to a JSON string.\n * @internal\n */\nexport function encode(frame: OutFrame): string {\n return JSON.stringify(frame);\n}\n\n/**\n * Parse a raw MessageEvent data string and ensure it has a string `type` field.\n * Throws `PulseProtocolError` if the data is not valid JSON or missing the `type` field.\n * @internal\n */\nexport function decode(raw: unknown): ParsedFrame {\n if (typeof raw !== 'string') {\n throw new PulseProtocolError('Expected string message data', raw);\n }\n\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(raw);\n } catch (
|
|
1
|
+
{"version":3,"file":"protocol.cjs","names":[],"sources":["../src/protocol.ts"],"sourcesContent":["import { PulseProtocolError } from './errors';\n\n// ─── Outgoing frames (client → server) ────────────────────────────────────────\n\nexport type OutMessageFrame = { channel?: string; event: string; payload: unknown; type: 'message' };\nexport type OutSubscribeFrame = { channel: string; type: 'subscribe' };\nexport type OutUnsubscribeFrame = { channel: string; type: 'unsubscribe' };\nexport type OutJoinFrame = { room: string; type: 'join' };\nexport type OutLeaveFrame = { room: string; type: 'leave' };\nexport type OutPresenceFrame = { room: string; state: unknown; type: 'presence' };\nexport type OutPingFrame = { ts: number; type: 'ping' };\n\nexport type OutFrame =\n | OutJoinFrame\n | OutLeaveFrame\n | OutMessageFrame\n | OutPingFrame\n | OutPresenceFrame\n | OutSubscribeFrame\n | OutUnsubscribeFrame;\n\n// ─── Incoming frames (server → client) ────────────────────────────────────────\n\nexport type InMessageFrame = { channel?: string; event: string; payload: unknown; type: 'message' };\nexport type InSubscribedFrame = { channel: string; type: 'subscribed' };\nexport type InUnsubscribedFrame = { channel: string; type: 'unsubscribed' };\nexport type InJoinedFrame = { room: string; type: 'joined' };\nexport type InLeftFrame = { room: string; type: 'left' };\nexport type InPresenceStateFrame = { members: Record<string, unknown>; room: string; type: 'presence_state' };\nexport type InPresenceJoinFrame = { id: string; room: string; state: unknown; type: 'presence_join' };\nexport type InPresenceLeaveFrame = { id: string; room: string; type: 'presence_leave' };\nexport type InPongFrame = { ts: number; type: 'pong' };\nexport type InErrorFrame = { code: string; message: string; type: 'error' };\n\nexport type InFrame =\n | InErrorFrame\n | InJoinedFrame\n | InLeftFrame\n | InMessageFrame\n | InPongFrame\n | InPresenceJoinFrame\n | InPresenceLeaveFrame\n | InPresenceStateFrame\n | InSubscribedFrame\n | InUnsubscribedFrame;\n\ntype ParsedFrame = { type: string } & Record<string, unknown>;\nexport type DecodedInFrame = { frame: InFrame; kind: 'known' } | { kind: 'unknown'; type: string };\n\n// ─── Codec ────────────────────────────────────────────────────────────────────\n\n/**\n * Encode an outgoing frame to a JSON string.\n * @internal\n */\nexport function encode(frame: OutFrame): string {\n return JSON.stringify(frame);\n}\n\n/**\n * Parse a raw MessageEvent data string and ensure it has a string `type` field.\n * Throws `PulseProtocolError` if the data is not valid JSON or missing the `type` field.\n * @internal\n */\nexport function decode(raw: unknown): ParsedFrame {\n if (typeof raw !== 'string') {\n throw new PulseProtocolError('Expected string message data', raw);\n }\n\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(raw);\n } catch (_cause) {\n throw new PulseProtocolError('JSON parse error', raw);\n }\n\n if (\n parsed === null ||\n typeof parsed !== 'object' ||\n !('type' in parsed) ||\n typeof (parsed as { type: unknown }).type !== 'string'\n ) {\n throw new PulseProtocolError('Missing or invalid \"type\" field', parsed);\n }\n\n return parsed as ParsedFrame;\n}\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction getStringProp(frame: unknown, key: string): string | null {\n if (!isObjectRecord(frame)) return null;\n\n const value = frame[key];\n\n return typeof value === 'string' ? value : null;\n}\n\nexport function isErrorFrame(frame: unknown): frame is InErrorFrame {\n return getStringProp(frame, 'code') !== null && getStringProp(frame, 'message') !== null;\n}\n\nexport function isJoinedFrame(frame: unknown): frame is InJoinedFrame {\n return getStringProp(frame, 'room') !== null;\n}\n\nexport function isLeftFrame(frame: unknown): frame is InLeftFrame {\n return getStringProp(frame, 'room') !== null;\n}\n\nexport function isMessageFrame(frame: unknown): frame is InMessageFrame {\n if (!isObjectRecord(frame) || getStringProp(frame, 'event') === null || !('payload' in frame)) return false;\n\n return frame.channel === undefined || typeof frame.channel === 'string';\n}\n\nexport function isPongFrame(frame: unknown): frame is InPongFrame {\n return isObjectRecord(frame) && typeof frame.ts === 'number';\n}\n\nexport function isPresenceJoinFrame(frame: unknown): frame is InPresenceJoinFrame {\n return (\n isObjectRecord(frame) &&\n getStringProp(frame, 'id') !== null &&\n getStringProp(frame, 'room') !== null &&\n 'state' in frame\n );\n}\n\nexport function isPresenceLeaveFrame(frame: unknown): frame is InPresenceLeaveFrame {\n return getStringProp(frame, 'id') !== null && getStringProp(frame, 'room') !== null;\n}\n\nexport function isPresenceStateFrame(frame: unknown): frame is InPresenceStateFrame {\n return isObjectRecord(frame) && getStringProp(frame, 'room') !== null && isObjectRecord(frame.members);\n}\n\nfunction isSubscribedFrame(frame: unknown): frame is InSubscribedFrame {\n return getStringProp(frame, 'channel') !== null;\n}\n\nfunction isUnsubscribedFrame(frame: unknown): frame is InUnsubscribedFrame {\n return getStringProp(frame, 'channel') !== null;\n}\n\n/**\n * Parse and validate known incoming frame shapes.\n * Unknown frame `type` values are passed through so callers can warn/drop them.\n * @internal\n */\nexport function decodeValidated(raw: unknown): DecodedInFrame {\n const frame = decode(raw) as ParsedFrame;\n\n switch (frame.type) {\n case 'error':\n if (isErrorFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'joined':\n if (isJoinedFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'left':\n if (isLeftFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'message':\n if (isMessageFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'pong':\n if (isPongFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'presence_join':\n if (isPresenceJoinFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'presence_leave':\n if (isPresenceLeaveFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'presence_state':\n if (isPresenceStateFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'subscribed':\n if (isSubscribedFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'unsubscribed':\n if (isUnsubscribedFrame(frame)) return { frame, kind: 'known' };\n\n break;\n default:\n return { kind: 'unknown', type: frame.type };\n }\n\n throw new PulseProtocolError(`Malformed \"${frame.type}\" frame`, frame);\n}\n"],"mappings":"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"}
|
package/dist/protocol.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","names":[],"sources":["../src/protocol.ts"],"sourcesContent":["import { PulseProtocolError } from './errors';\n\n// ─── Outgoing frames (client → server) ────────────────────────────────────────\n\nexport type OutMessageFrame = { channel?: string; event: string; payload: unknown; type: 'message' };\nexport type OutSubscribeFrame = { channel: string; type: 'subscribe' };\nexport type OutUnsubscribeFrame = { channel: string; type: 'unsubscribe' };\nexport type OutJoinFrame = { room: string; type: 'join' };\nexport type OutLeaveFrame = { room: string; type: 'leave' };\nexport type OutPresenceFrame = { room: string; state: unknown; type: 'presence' };\nexport type OutPingFrame = { ts: number; type: 'ping' };\n\nexport type OutFrame =\n | OutJoinFrame\n | OutLeaveFrame\n | OutMessageFrame\n | OutPingFrame\n | OutPresenceFrame\n | OutSubscribeFrame\n | OutUnsubscribeFrame;\n\n// ─── Incoming frames (server → client) ────────────────────────────────────────\n\nexport type InMessageFrame = { channel?: string; event: string; payload: unknown; type: 'message' };\nexport type InSubscribedFrame = { channel: string; type: 'subscribed' };\nexport type InUnsubscribedFrame = { channel: string; type: 'unsubscribed' };\nexport type InJoinedFrame = { room: string; type: 'joined' };\nexport type InLeftFrame = { room: string; type: 'left' };\nexport type InPresenceStateFrame = { members: Record<string, unknown>; room: string; type: 'presence_state' };\nexport type InPresenceJoinFrame = { id: string; room: string; state: unknown; type: 'presence_join' };\nexport type InPresenceLeaveFrame = { id: string; room: string; type: 'presence_leave' };\nexport type InPongFrame = { ts: number; type: 'pong' };\nexport type InErrorFrame = { code: string; message: string; type: 'error' };\n\nexport type InFrame =\n | InErrorFrame\n | InJoinedFrame\n | InLeftFrame\n | InMessageFrame\n | InPongFrame\n | InPresenceJoinFrame\n | InPresenceLeaveFrame\n | InPresenceStateFrame\n | InSubscribedFrame\n | InUnsubscribedFrame;\n\ntype ParsedFrame = { type: string } & Record<string, unknown>;\nexport type DecodedInFrame = { frame: InFrame; kind: 'known' } | { kind: 'unknown'; type: string };\n\n// ─── Codec ────────────────────────────────────────────────────────────────────\n\n/**\n * Encode an outgoing frame to a JSON string.\n * @internal\n */\nexport function encode(frame: OutFrame): string {\n return JSON.stringify(frame);\n}\n\n/**\n * Parse a raw MessageEvent data string and ensure it has a string `type` field.\n * Throws `PulseProtocolError` if the data is not valid JSON or missing the `type` field.\n * @internal\n */\nexport function decode(raw: unknown): ParsedFrame {\n if (typeof raw !== 'string') {\n throw new PulseProtocolError('Expected string message data', raw);\n }\n\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(raw);\n } catch (
|
|
1
|
+
{"version":3,"file":"protocol.js","names":[],"sources":["../src/protocol.ts"],"sourcesContent":["import { PulseProtocolError } from './errors';\n\n// ─── Outgoing frames (client → server) ────────────────────────────────────────\n\nexport type OutMessageFrame = { channel?: string; event: string; payload: unknown; type: 'message' };\nexport type OutSubscribeFrame = { channel: string; type: 'subscribe' };\nexport type OutUnsubscribeFrame = { channel: string; type: 'unsubscribe' };\nexport type OutJoinFrame = { room: string; type: 'join' };\nexport type OutLeaveFrame = { room: string; type: 'leave' };\nexport type OutPresenceFrame = { room: string; state: unknown; type: 'presence' };\nexport type OutPingFrame = { ts: number; type: 'ping' };\n\nexport type OutFrame =\n | OutJoinFrame\n | OutLeaveFrame\n | OutMessageFrame\n | OutPingFrame\n | OutPresenceFrame\n | OutSubscribeFrame\n | OutUnsubscribeFrame;\n\n// ─── Incoming frames (server → client) ────────────────────────────────────────\n\nexport type InMessageFrame = { channel?: string; event: string; payload: unknown; type: 'message' };\nexport type InSubscribedFrame = { channel: string; type: 'subscribed' };\nexport type InUnsubscribedFrame = { channel: string; type: 'unsubscribed' };\nexport type InJoinedFrame = { room: string; type: 'joined' };\nexport type InLeftFrame = { room: string; type: 'left' };\nexport type InPresenceStateFrame = { members: Record<string, unknown>; room: string; type: 'presence_state' };\nexport type InPresenceJoinFrame = { id: string; room: string; state: unknown; type: 'presence_join' };\nexport type InPresenceLeaveFrame = { id: string; room: string; type: 'presence_leave' };\nexport type InPongFrame = { ts: number; type: 'pong' };\nexport type InErrorFrame = { code: string; message: string; type: 'error' };\n\nexport type InFrame =\n | InErrorFrame\n | InJoinedFrame\n | InLeftFrame\n | InMessageFrame\n | InPongFrame\n | InPresenceJoinFrame\n | InPresenceLeaveFrame\n | InPresenceStateFrame\n | InSubscribedFrame\n | InUnsubscribedFrame;\n\ntype ParsedFrame = { type: string } & Record<string, unknown>;\nexport type DecodedInFrame = { frame: InFrame; kind: 'known' } | { kind: 'unknown'; type: string };\n\n// ─── Codec ────────────────────────────────────────────────────────────────────\n\n/**\n * Encode an outgoing frame to a JSON string.\n * @internal\n */\nexport function encode(frame: OutFrame): string {\n return JSON.stringify(frame);\n}\n\n/**\n * Parse a raw MessageEvent data string and ensure it has a string `type` field.\n * Throws `PulseProtocolError` if the data is not valid JSON or missing the `type` field.\n * @internal\n */\nexport function decode(raw: unknown): ParsedFrame {\n if (typeof raw !== 'string') {\n throw new PulseProtocolError('Expected string message data', raw);\n }\n\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(raw);\n } catch (_cause) {\n throw new PulseProtocolError('JSON parse error', raw);\n }\n\n if (\n parsed === null ||\n typeof parsed !== 'object' ||\n !('type' in parsed) ||\n typeof (parsed as { type: unknown }).type !== 'string'\n ) {\n throw new PulseProtocolError('Missing or invalid \"type\" field', parsed);\n }\n\n return parsed as ParsedFrame;\n}\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction getStringProp(frame: unknown, key: string): string | null {\n if (!isObjectRecord(frame)) return null;\n\n const value = frame[key];\n\n return typeof value === 'string' ? value : null;\n}\n\nexport function isErrorFrame(frame: unknown): frame is InErrorFrame {\n return getStringProp(frame, 'code') !== null && getStringProp(frame, 'message') !== null;\n}\n\nexport function isJoinedFrame(frame: unknown): frame is InJoinedFrame {\n return getStringProp(frame, 'room') !== null;\n}\n\nexport function isLeftFrame(frame: unknown): frame is InLeftFrame {\n return getStringProp(frame, 'room') !== null;\n}\n\nexport function isMessageFrame(frame: unknown): frame is InMessageFrame {\n if (!isObjectRecord(frame) || getStringProp(frame, 'event') === null || !('payload' in frame)) return false;\n\n return frame.channel === undefined || typeof frame.channel === 'string';\n}\n\nexport function isPongFrame(frame: unknown): frame is InPongFrame {\n return isObjectRecord(frame) && typeof frame.ts === 'number';\n}\n\nexport function isPresenceJoinFrame(frame: unknown): frame is InPresenceJoinFrame {\n return (\n isObjectRecord(frame) &&\n getStringProp(frame, 'id') !== null &&\n getStringProp(frame, 'room') !== null &&\n 'state' in frame\n );\n}\n\nexport function isPresenceLeaveFrame(frame: unknown): frame is InPresenceLeaveFrame {\n return getStringProp(frame, 'id') !== null && getStringProp(frame, 'room') !== null;\n}\n\nexport function isPresenceStateFrame(frame: unknown): frame is InPresenceStateFrame {\n return isObjectRecord(frame) && getStringProp(frame, 'room') !== null && isObjectRecord(frame.members);\n}\n\nfunction isSubscribedFrame(frame: unknown): frame is InSubscribedFrame {\n return getStringProp(frame, 'channel') !== null;\n}\n\nfunction isUnsubscribedFrame(frame: unknown): frame is InUnsubscribedFrame {\n return getStringProp(frame, 'channel') !== null;\n}\n\n/**\n * Parse and validate known incoming frame shapes.\n * Unknown frame `type` values are passed through so callers can warn/drop them.\n * @internal\n */\nexport function decodeValidated(raw: unknown): DecodedInFrame {\n const frame = decode(raw) as ParsedFrame;\n\n switch (frame.type) {\n case 'error':\n if (isErrorFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'joined':\n if (isJoinedFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'left':\n if (isLeftFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'message':\n if (isMessageFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'pong':\n if (isPongFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'presence_join':\n if (isPresenceJoinFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'presence_leave':\n if (isPresenceLeaveFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'presence_state':\n if (isPresenceStateFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'subscribed':\n if (isSubscribedFrame(frame)) return { frame, kind: 'known' };\n\n break;\n case 'unsubscribed':\n if (isUnsubscribedFrame(frame)) return { frame, kind: 'known' };\n\n break;\n default:\n return { kind: 'unknown', type: frame.type };\n }\n\n throw new PulseProtocolError(`Malformed \"${frame.type}\" frame`, frame);\n}\n"],"mappings":"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"}
|