@kyneta/websocket-transport 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -132,7 +132,9 @@ const exchange = new Exchange({
132
132
 
133
133
  ## Connection Lifecycle
134
134
 
135
- The client adapter manages connection state through a validated state machine with async-observable transitions:
135
+ The connection lifecycle is a `Program<WsClientMsg, WebsocketClientState, WsClientEffect>` from `@kyneta/machine` — a pure Mealy machine with data effects. The transport class (`WebsocketClientTransport`) is a thin imperative shell that interprets data effects as I/O (FC/IS design). Every state × event combination is covered by pure data tests — no sockets, no timing, never flaky.
136
+
137
+ The WebSocket client has a **5-state lifecycle** with an extra `ready` state compared to SSE and Unix Socket transports. The server sends a text `"ready"` signal after the TCP connection opens, and only then does the client create a channel and begin the establishment handshake.
136
138
 
137
139
  ```/dev/null/state-machine.txt#L1-8
138
140
  disconnected → connecting → connected → ready
@@ -152,6 +154,19 @@ disconnected → connecting → connected → ready
152
154
  | `ready` | Server sent `"ready"` text frame — protocol messages can flow. |
153
155
  | `reconnecting` | Connection lost, scheduling next attempt. Tracks `attempt` and `nextAttemptMs`. |
154
156
 
157
+ ### Program Architecture
158
+
159
+ The program (`createWsClientProgram`) encodes all transitions and side effects as inspectable data:
160
+
161
+ - **Messages** (`WsClientMsg`): `start`, `socket-opened`, `server-ready`, `socket-closed`, `socket-error`, `reconnect-timer-fired`, `stop`
162
+ - **Effects** (`WsClientEffect`): `create-websocket`, `close-websocket`, `add-channel-and-establish`, `remove-channel`, `start-reconnect-timer`, `cancel-reconnect-timer`, `start-keepalive`, `stop-keepalive`
163
+
164
+ The imperative shell interprets each effect as real I/O — creating `WebSocket` instances, scheduling timers, sending keepalive pings. Keepalive is modeled as `start-keepalive` / `stop-keepalive` effects rather than internal timer logic.
165
+
166
+ ### Race Condition Handling
167
+
168
+ The server may send `"ready"` before the client's `open` event fires (server-ready while still `connecting`). The program handles this by transitioning directly from `connecting` → `ready`, skipping the `connected` state entirely.
169
+
155
170
  ### Connection Handshake
156
171
 
157
172
  1. Client opens Websocket, transitions to `connecting`
@@ -162,6 +177,8 @@ disconnected → connecting → connected → ready
162
177
 
163
178
  ### Observing State
164
179
 
180
+ The public observation API is powered by `createObservableProgram` from `@kyneta/machine`:
181
+
165
182
  ```/dev/null/observe-state.ts#L1-18
166
183
  import { createWebsocketClient } from "@kyneta/websocket-network-adapter/client"
167
184
 
package/dist/bun.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ServerWebSocket } from 'bun';
2
- import { S as Socket } from './types-DG_89zA4.js';
3
- export { D as DisconnectReason, a as SocketReadyState } from './types-DG_89zA4.js';
4
- import '@kyneta/exchange';
2
+ import { S as Socket } from './types-DdNb8cAz.js';
3
+ export { D as DisconnectReason, a as SocketReadyState } from './types-DdNb8cAz.js';
4
+ import '@kyneta/transport';
5
5
 
6
6
  /**
7
7
  * Data structure stored in `ws.data` for handler callbacks.
@@ -2,7 +2,9 @@
2
2
  function wrapStandardWebsocket(ws) {
3
3
  return {
4
4
  send(data) {
5
- ws.send(data);
5
+ ws.send(
6
+ typeof data === "string" ? data : data
7
+ );
6
8
  },
7
9
  close(code, reason) {
8
10
  ws.close(code, reason);
@@ -106,4 +108,4 @@ export {
106
108
  wrapStandardWebsocket,
107
109
  wrapNodeWebsocket
108
110
  };
109
- //# sourceMappingURL=chunk-5FHT54WT.js.map
111
+ //# sourceMappingURL=chunk-PSG3LLT5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["// types — framework-agnostic Websocket abstractions for @kyneta/websocket-network-adapter.\n//\n// The `Socket` interface decouples the adapter from any specific Websocket\n// library (browser WebSocket, Node `ws`, Bun ServerWebSocket). Platform-\n// specific wrappers (`wrapStandardWebsocket`, `wrapNodeWebsocket`,\n// `wrapBunWebsocket`) adapt concrete implementations to this interface.\n//\n// Ported from @loro-extended/adapter-websocket's WsSocket with kyneta\n// naming conventions applied.\n\nimport type {\n TransitionListener as GenericTransitionListener,\n PeerId,\n StateTransition,\n} from \"@kyneta/transport\"\n\n// ---------------------------------------------------------------------------\n// Socket ready states\n// ---------------------------------------------------------------------------\n\n/**\n * Websocket ready states — mirrors the standard WebSocket readyState\n * values as human-readable strings.\n */\nexport type SocketReadyState = \"connecting\" | \"open\" | \"closing\" | \"closed\"\n\n// ---------------------------------------------------------------------------\n// Socket interface\n// ---------------------------------------------------------------------------\n\n/**\n * Framework-agnostic Websocket interface.\n *\n * This allows the adapter to work with any Websocket library:\n * - Browser `WebSocket` via `wrapStandardWebsocket()`\n * - Node.js `ws` library via `wrapNodeWebsocket()`\n * - Bun `ServerWebSocket` via `wrapBunWebsocket()`\n *\n * The interface is intentionally minimal — only the operations the\n * adapter needs are exposed.\n */\nexport interface Socket {\n /** Send binary or text data through the Websocket. */\n send(data: Uint8Array | string): void\n\n /** Close the Websocket connection. */\n close(code?: number, reason?: string): void\n\n /** Register a handler for incoming messages (binary or text). */\n onMessage(handler: (data: Uint8Array | string) => void): void\n\n /** Register a handler for connection close. */\n onClose(handler: (code: number, reason: string) => void): void\n\n /** Register a handler for errors. */\n onError(handler: (error: Error) => void): void\n\n /** The current ready state of the Websocket. */\n readonly readyState: SocketReadyState\n}\n\n// ---------------------------------------------------------------------------\n// Connection types — used by server adapter\n// ---------------------------------------------------------------------------\n\n/**\n * Options for handling a new Websocket connection on the server.\n */\nexport interface WebsocketConnectionOptions {\n /** The Websocket instance, wrapped in the Socket interface. */\n socket: Socket\n\n /** Optional peer ID extracted from the upgrade request. */\n peerId?: PeerId\n\n /** Optional authentication token from the upgrade request. */\n authToken?: string\n}\n\n/**\n * Handle for an active Websocket connection.\n */\nexport interface WebsocketConnectionHandle {\n /** The peer ID for this connection. */\n readonly peerId: PeerId\n\n /** The channel ID for this connection. */\n readonly channelId: number\n\n /** Close the connection. */\n close(code?: number, reason?: string): void\n}\n\n/**\n * Result of handling a Websocket connection on the server.\n */\nexport interface WebsocketConnectionResult {\n /** The connection handle for managing this peer. */\n connection: WebsocketConnectionHandle\n\n /** Call this to start processing messages. */\n start(): void\n}\n\n// ---------------------------------------------------------------------------\n// Disconnect reason\n// ---------------------------------------------------------------------------\n\n/**\n * Discriminated union describing why a Websocket connection was lost.\n */\nexport type DisconnectReason =\n | { type: \"intentional\" }\n | { type: \"error\"; error: Error }\n | { type: \"closed\"; code: number; reason: string }\n | { type: \"max-retries-exceeded\"; attempts: number }\n | { type: \"not-started\" }\n\n// ---------------------------------------------------------------------------\n// Connection state (for client adapter observability)\n// ---------------------------------------------------------------------------\n\n/**\n * All possible states of the Websocket client.\n *\n * State machine transitions:\n * ```\n * disconnected → connecting → connected → ready\n * ↓ ↓ ↓\n * reconnecting ← ─ ┴ ─ ─ ─ ─ ┘\n * ↓\n * connecting (retry)\n * ↓\n * disconnected (max retries)\n * ```\n */\nexport type WebsocketClientState =\n | { status: \"disconnected\"; reason?: DisconnectReason }\n | { status: \"connecting\"; attempt: number }\n | { status: \"connected\" }\n | { status: \"ready\" }\n | { status: \"reconnecting\"; attempt: number; nextAttemptMs: number }\n\n/**\n * A state transition event for websocket client states.\n * Specialized from the generic `StateTransition<S>`.\n */\nexport type WebsocketClientStateTransition =\n StateTransition<WebsocketClientState>\n\n/**\n * Listener for websocket client state transitions.\n * Specialized from the generic `TransitionListener<S>`.\n */\nexport type TransitionListener = GenericTransitionListener<WebsocketClientState>\n\n// ---------------------------------------------------------------------------\n// Socket wrapper — standard WebSocket API (browser + Node ws)\n// ---------------------------------------------------------------------------\n\n/**\n * Wrap a standard `WebSocket` (browser or Node.js `ws` via `ws` package\n * in `WebSocket`-compatible mode) into the `Socket` interface.\n *\n * Handles `ArrayBuffer`, `Blob`, and string messages.\n */\nexport function wrapStandardWebsocket(ws: WebSocket): Socket {\n return {\n send(data: Uint8Array | string): void {\n ws.send(\n typeof data === \"string\" ? data : (data as Uint8Array<ArrayBuffer>),\n )\n },\n\n close(code?: number, reason?: string): void {\n ws.close(code, reason)\n },\n\n onMessage(handler: (data: Uint8Array | string) => void): void {\n ws.addEventListener(\"message\", event => {\n if (event.data instanceof ArrayBuffer) {\n handler(new Uint8Array(event.data))\n } else if (typeof Blob !== \"undefined\" && event.data instanceof Blob) {\n // Handle Blob data (browser)\n event.data.arrayBuffer().then(buffer => {\n handler(new Uint8Array(buffer))\n })\n } else {\n handler(event.data as string)\n }\n })\n },\n\n onClose(handler: (code: number, reason: string) => void): void {\n ws.addEventListener(\"close\", event => {\n handler(event.code, event.reason)\n })\n },\n\n onError(handler: (error: Error) => void): void {\n ws.addEventListener(\"error\", _event => {\n handler(new Error(\"WebSocket error\"))\n })\n },\n\n get readyState(): SocketReadyState {\n switch (ws.readyState) {\n case WebSocket.CONNECTING:\n return \"connecting\"\n case WebSocket.OPEN:\n return \"open\"\n case WebSocket.CLOSING:\n return \"closing\"\n case WebSocket.CLOSED:\n return \"closed\"\n default:\n return \"closed\"\n }\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Socket wrapper — Node.js `ws` library (raw API, not WebSocket-compat)\n// ---------------------------------------------------------------------------\n\n/**\n * The minimal interface we need from the Node.js `ws` library's `WebSocket`.\n *\n * Using a structural type rather than importing `ws` — consumers provide\n * the actual `ws` instance, we just need these methods.\n */\nexport interface NodeWebsocketLike {\n send(data: Uint8Array | string): void\n close(code?: number, reason?: string): void\n on(\n event: \"message\",\n handler: (data: Buffer | ArrayBuffer | string, isBinary: boolean) => void,\n ): void\n on(event: \"close\", handler: (code: number, reason: Buffer) => void): void\n on(event: \"error\", handler: (error: Error) => void): void\n readyState: number\n}\n\n/**\n * Wrap a Node.js `ws` library WebSocket into the `Socket` interface.\n *\n * Handles `Buffer` → `Uint8Array` conversion for binary messages.\n */\nexport function wrapNodeWebsocket(ws: NodeWebsocketLike): Socket {\n const CONNECTING = 0\n const OPEN = 1\n const CLOSING = 2\n\n return {\n send(data: Uint8Array | string): void {\n ws.send(data)\n },\n\n close(code?: number, reason?: string): void {\n ws.close(code, reason)\n },\n\n onMessage(handler: (data: Uint8Array | string) => void): void {\n ws.on(\n \"message\",\n (data: Buffer | ArrayBuffer | string, isBinary: boolean) => {\n if (isBinary) {\n if (data instanceof ArrayBuffer) {\n handler(new Uint8Array(data))\n } else if (typeof Buffer !== \"undefined\" && Buffer.isBuffer(data)) {\n handler(new Uint8Array(data))\n } else {\n handler(new Uint8Array(data as unknown as ArrayBuffer))\n }\n } else {\n if (typeof Buffer !== \"undefined\" && Buffer.isBuffer(data)) {\n handler(data.toString(\"utf-8\"))\n } else {\n handler(data as string)\n }\n }\n },\n )\n },\n\n onClose(handler: (code: number, reason: string) => void): void {\n ws.on(\"close\", (code: number, reason: Buffer) => {\n handler(code, reason.toString())\n })\n },\n\n onError(handler: (error: Error) => void): void {\n ws.on(\"error\", handler)\n },\n\n get readyState(): SocketReadyState {\n switch (ws.readyState) {\n case CONNECTING:\n return \"connecting\"\n case OPEN:\n return \"open\"\n case CLOSING:\n return \"closing\"\n default:\n return \"closed\"\n }\n },\n }\n}\n"],"mappings":";AAsKO,SAAS,sBAAsB,IAAuB;AAC3D,SAAO;AAAA,IACL,KAAK,MAAiC;AACpC,SAAG;AAAA,QACD,OAAO,SAAS,WAAW,OAAQ;AAAA,MACrC;AAAA,IACF;AAAA,IAEA,MAAM,MAAe,QAAuB;AAC1C,SAAG,MAAM,MAAM,MAAM;AAAA,IACvB;AAAA,IAEA,UAAU,SAAoD;AAC5D,SAAG,iBAAiB,WAAW,WAAS;AACtC,YAAI,MAAM,gBAAgB,aAAa;AACrC,kBAAQ,IAAI,WAAW,MAAM,IAAI,CAAC;AAAA,QACpC,WAAW,OAAO,SAAS,eAAe,MAAM,gBAAgB,MAAM;AAEpE,gBAAM,KAAK,YAAY,EAAE,KAAK,YAAU;AACtC,oBAAQ,IAAI,WAAW,MAAM,CAAC;AAAA,UAChC,CAAC;AAAA,QACH,OAAO;AACL,kBAAQ,MAAM,IAAc;AAAA,QAC9B;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,QAAQ,SAAuD;AAC7D,SAAG,iBAAiB,SAAS,WAAS;AACpC,gBAAQ,MAAM,MAAM,MAAM,MAAM;AAAA,MAClC,CAAC;AAAA,IACH;AAAA,IAEA,QAAQ,SAAuC;AAC7C,SAAG,iBAAiB,SAAS,YAAU;AACrC,gBAAQ,IAAI,MAAM,iBAAiB,CAAC;AAAA,MACtC,CAAC;AAAA,IACH;AAAA,IAEA,IAAI,aAA+B;AACjC,cAAQ,GAAG,YAAY;AAAA,QACrB,KAAK,UAAU;AACb,iBAAO;AAAA,QACT,KAAK,UAAU;AACb,iBAAO;AAAA,QACT,KAAK,UAAU;AACb,iBAAO;AAAA,QACT,KAAK,UAAU;AACb,iBAAO;AAAA,QACT;AACE,iBAAO;AAAA,MACX;AAAA,IACF;AAAA,EACF;AACF;AA6BO,SAAS,kBAAkB,IAA+B;AAC/D,QAAM,aAAa;AACnB,QAAM,OAAO;AACb,QAAM,UAAU;AAEhB,SAAO;AAAA,IACL,KAAK,MAAiC;AACpC,SAAG,KAAK,IAAI;AAAA,IACd;AAAA,IAEA,MAAM,MAAe,QAAuB;AAC1C,SAAG,MAAM,MAAM,MAAM;AAAA,IACvB;AAAA,IAEA,UAAU,SAAoD;AAC5D,SAAG;AAAA,QACD;AAAA,QACA,CAAC,MAAqC,aAAsB;AAC1D,cAAI,UAAU;AACZ,gBAAI,gBAAgB,aAAa;AAC/B,sBAAQ,IAAI,WAAW,IAAI,CAAC;AAAA,YAC9B,WAAW,OAAO,WAAW,eAAe,OAAO,SAAS,IAAI,GAAG;AACjE,sBAAQ,IAAI,WAAW,IAAI,CAAC;AAAA,YAC9B,OAAO;AACL,sBAAQ,IAAI,WAAW,IAA8B,CAAC;AAAA,YACxD;AAAA,UACF,OAAO;AACL,gBAAI,OAAO,WAAW,eAAe,OAAO,SAAS,IAAI,GAAG;AAC1D,sBAAQ,KAAK,SAAS,OAAO,CAAC;AAAA,YAChC,OAAO;AACL,sBAAQ,IAAc;AAAA,YACxB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,QAAQ,SAAuD;AAC7D,SAAG,GAAG,SAAS,CAAC,MAAc,WAAmB;AAC/C,gBAAQ,MAAM,OAAO,SAAS,CAAC;AAAA,MACjC,CAAC;AAAA,IACH;AAAA,IAEA,QAAQ,SAAuC;AAC7C,SAAG,GAAG,SAAS,OAAO;AAAA,IACxB;AAAA,IAEA,IAAI,aAA+B;AACjC,cAAQ,GAAG,YAAY;AAAA,QACrB,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AACH,iBAAO;AAAA,QACT;AACE,iBAAO;AAAA,MACX;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
package/dist/client.d.ts CHANGED
@@ -1,6 +1,58 @@
1
- import { PeerId, Transport, GeneratedChannel, TransportFactory, ClientStateMachine } from '@kyneta/exchange';
2
- import { W as WebsocketClientStateTransition, D as DisconnectReason, b as WebsocketClientState, T as TransitionListener } from './types-DG_89zA4.js';
3
- export { S as Socket, a as SocketReadyState, w as wrapStandardWebsocket } from './types-DG_89zA4.js';
1
+ import { Program, TransitionListener } from '@kyneta/machine';
2
+ import { ReconnectOptions, PeerId, Transport, GeneratedChannel, TransportFactory } from '@kyneta/transport';
3
+ import { W as WebsocketClientState, b as WebsocketClientStateTransition, D as DisconnectReason } from './types-DdNb8cAz.js';
4
+ export { S as Socket, a as SocketReadyState, T as TransitionListener, w as wrapStandardWebsocket } from './types-DdNb8cAz.js';
5
+
6
+ type WsClientMsg = {
7
+ type: "start";
8
+ } | {
9
+ type: "socket-opened";
10
+ } | {
11
+ type: "server-ready";
12
+ } | {
13
+ type: "socket-closed";
14
+ code: number;
15
+ reason: string;
16
+ } | {
17
+ type: "socket-error";
18
+ error: Error;
19
+ } | {
20
+ type: "reconnect-timer-fired";
21
+ } | {
22
+ type: "stop";
23
+ };
24
+ type WsClientEffect = {
25
+ type: "create-websocket";
26
+ attempt: number;
27
+ } | {
28
+ type: "close-websocket";
29
+ } | {
30
+ type: "add-channel-and-establish";
31
+ } | {
32
+ type: "remove-channel";
33
+ } | {
34
+ type: "start-reconnect-timer";
35
+ delayMs: number;
36
+ } | {
37
+ type: "cancel-reconnect-timer";
38
+ } | {
39
+ type: "start-keepalive";
40
+ } | {
41
+ type: "stop-keepalive";
42
+ };
43
+ interface WsClientProgramOptions {
44
+ reconnect?: Partial<ReconnectOptions>;
45
+ /** Inject jitter source for deterministic testing. Default: () => Math.random() * 1000 */
46
+ jitterFn?: () => number;
47
+ }
48
+ /**
49
+ * Create the websocket client connection lifecycle program — a pure Mealy machine.
50
+ *
51
+ * The returned `Program<WsClientMsg, WebsocketClientState, WsClientEffect>`
52
+ * encodes every state transition and effect as inspectable data. The imperative
53
+ * shell interprets `WsClientEffect` as actual I/O.
54
+ */
55
+ declare function createWsClientProgram(options?: WsClientProgramOptions): Program<WsClientMsg, WebsocketClientState, WsClientEffect>;
4
56
 
5
57
  /**
6
58
  * Default fragment threshold in bytes.
@@ -8,7 +60,7 @@ export { S as Socket, a as SocketReadyState, w as wrapStandardWebsocket } from '
8
60
  */
9
61
  declare const DEFAULT_FRAGMENT_THRESHOLD: number;
10
62
  /**
11
- * Options for the Websocket client adapter (browser connections).
63
+ * Options for the Websocket client transport (browser connections).
12
64
  */
13
65
  interface WebsocketClientOptions {
14
66
  /** Websocket URL to connect to. Can be a string or a function of peerId. */
@@ -17,7 +69,7 @@ interface WebsocketClientOptions {
17
69
  WebSocket?: typeof globalThis.WebSocket;
18
70
  /** Reconnection options. */
19
71
  reconnect?: {
20
- enabled: boolean;
72
+ enabled?: boolean;
21
73
  maxAttempts?: number;
22
74
  baseDelay?: number;
23
75
  maxDelay?: number;
@@ -63,11 +115,15 @@ interface ServiceWebsocketClientOptions extends WebsocketClientOptions {
63
115
  headers?: Record<string, string>;
64
116
  }
65
117
  /**
66
- * Websocket client network adapter for @kyneta/exchange.
118
+ * Websocket client network transport for @kyneta/exchange.
67
119
  *
68
120
  * Connects to a Websocket server, sends and receives ChannelMsg via
69
121
  * the kyneta wire format (CBOR codec + framing + fragmentation).
70
122
  *
123
+ * Internally, the connection lifecycle is a `Program<Msg, Model, Fx>` —
124
+ * a pure Mealy machine whose transitions are deterministically testable.
125
+ * This class is the imperative shell that interprets data effects as I/O.
126
+ *
71
127
  * Prefer the factory functions for construction:
72
128
  * - `createWebsocketClient()` — browser-to-server
73
129
  * - `createServiceWebsocketClient()` — service-to-service (with headers)
@@ -76,14 +132,13 @@ declare class WebsocketClientTransport extends Transport<void> {
76
132
  #private;
77
133
  constructor(options: ServiceWebsocketClientOptions);
78
134
  /**
79
- * Get the current state of the connection.
135
+ * Get the current connection state.
80
136
  */
81
137
  getState(): WebsocketClientState;
82
138
  /**
83
139
  * Subscribe to state transitions.
84
- * @returns Unsubscribe function
85
140
  */
86
- subscribeToTransitions(listener: TransitionListener): () => void;
141
+ subscribeToTransitions(listener: TransitionListener<WebsocketClientState>): () => void;
87
142
  /**
88
143
  * Wait for a specific state.
89
144
  */
@@ -97,7 +152,7 @@ declare class WebsocketClientTransport extends Transport<void> {
97
152
  timeoutMs?: number;
98
153
  }): Promise<WebsocketClientState>;
99
154
  /**
100
- * Check if the client is ready (server ready signal received).
155
+ * Whether the client is ready (server ready signal received).
101
156
  */
102
157
  get isReady(): boolean;
103
158
  protected generate(): GeneratedChannel;
@@ -105,14 +160,15 @@ declare class WebsocketClientTransport extends Transport<void> {
105
160
  onStop(): Promise<void>;
106
161
  }
107
162
  /**
108
- * Create a Websocket client adapter factory for browser-to-server connections.
163
+ * Create a Websocket client transport factory for browser-to-server
164
+ * connections.
109
165
  *
110
- * Returns an `TransportFactory` — a closure that creates a fresh adapter
166
+ * Returns an `TransportFactory` — a closure that creates a fresh transport
111
167
  * instance when called. Pass directly to `Exchange({ transports: [...] })`.
112
168
  *
113
169
  * @example
114
170
  * ```typescript
115
- * import { createWebsocketClient } from "@kyneta/websocket-network-adapter/client"
171
+ * import { createWebsocketClient } from "@kyneta/websocket-transport/client"
116
172
  *
117
173
  * const exchange = new Exchange({
118
174
  * transports: [createWebsocketClient({
@@ -124,7 +180,7 @@ declare class WebsocketClientTransport extends Transport<void> {
124
180
  */
125
181
  declare function createWebsocketClient(options: WebsocketClientOptions): TransportFactory;
126
182
  /**
127
- * Create a Websocket client adapter for service-to-service connections.
183
+ * Create a Websocket client transport for service-to-service connections.
128
184
  *
129
185
  * This factory is for backend environments (Bun, Node.js) where you need
130
186
  * to pass authentication headers during the Websocket upgrade.
@@ -135,7 +191,7 @@ declare function createWebsocketClient(options: WebsocketClientOptions): Transpo
135
191
  *
136
192
  * @example
137
193
  * ```typescript
138
- * import { createServiceWebsocketClient } from "@kyneta/websocket-network-adapter/client"
194
+ * import { createServiceWebsocketClient } from "@kyneta/websocket-transport/client"
139
195
  *
140
196
  * const exchange = new Exchange({
141
197
  * transports: [createServiceWebsocketClient({
@@ -148,38 +204,4 @@ declare function createWebsocketClient(options: WebsocketClientOptions): Transpo
148
204
  */
149
205
  declare function createServiceWebsocketClient(options: ServiceWebsocketClientOptions): TransportFactory;
150
206
 
151
- /**
152
- * Observable state machine for Websocket client connection lifecycle.
153
- *
154
- * Extends the generic `ClientStateMachine<WebsocketClientState>` with
155
- * websocket-specific convenience helpers.
156
- *
157
- * Usage:
158
- * ```typescript
159
- * const sm = new WebsocketClientStateMachine()
160
- *
161
- * sm.subscribeToTransitions(({ from, to }) => {
162
- * console.log(`${from.status} → ${to.status}`)
163
- * })
164
- *
165
- * sm.transition({ status: "connecting", attempt: 1 })
166
- * sm.transition({ status: "connected" })
167
- * sm.transition({ status: "ready" })
168
- *
169
- * // Transitions are delivered asynchronously via microtask
170
- * // Listener will see: disconnected → connecting, connecting → connected, connected → ready
171
- * ```
172
- */
173
- declare class WebsocketClientStateMachine extends ClientStateMachine<WebsocketClientState> {
174
- constructor();
175
- /**
176
- * Check if the client is in a "connected" state (either connected or ready).
177
- */
178
- isConnectedOrReady(): boolean;
179
- /**
180
- * Check if the client is ready (server ready signal received).
181
- */
182
- isReady(): boolean;
183
- }
184
-
185
- export { DEFAULT_FRAGMENT_THRESHOLD, DisconnectReason, type ServiceWebsocketClientOptions, TransitionListener, type WebsocketClientLifecycleEvents, type WebsocketClientOptions, WebsocketClientState, WebsocketClientStateMachine, WebsocketClientStateTransition, WebsocketClientTransport, createServiceWebsocketClient, createWebsocketClient };
207
+ export { DEFAULT_FRAGMENT_THRESHOLD, DisconnectReason, type ServiceWebsocketClientOptions, type WebsocketClientLifecycleEvents, type WebsocketClientOptions, WebsocketClientState, WebsocketClientStateTransition, WebsocketClientTransport, type WsClientEffect, type WsClientMsg, type WsClientProgramOptions, createServiceWebsocketClient, createWebsocketClient, createWsClientProgram };