durablews 1.0.1 → 2.0.0-alpha.1
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 +63 -93
- package/dist/binding-bZNBe2Bz.d.cts +11 -0
- package/dist/binding-gyPQiK9i.d.ts +11 -0
- package/dist/chunk-GIDTCSPD.js +22 -0
- package/dist/chunk-GIDTCSPD.js.map +1 -0
- package/dist/chunk-MG4TK53H.js +590 -0
- package/dist/chunk-MG4TK53H.js.map +1 -0
- package/dist/compat.cjs +765 -0
- package/dist/compat.cjs.map +1 -0
- package/dist/compat.d.cts +72 -0
- package/dist/compat.d.ts +72 -0
- package/dist/compat.js +177 -0
- package/dist/compat.js.map +1 -0
- package/dist/index.cjs +612 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +81 -0
- package/dist/index.d.ts +81 -44
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +646 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +66 -0
- package/dist/react.d.ts +66 -0
- package/dist/react.js +42 -0
- package/dist/react.js.map +1 -0
- package/dist/types-BDvztGcG.d.cts +410 -0
- package/dist/types-BDvztGcG.d.ts +410 -0
- package/dist/vue.cjs +650 -0
- package/dist/vue.cjs.map +1 -0
- package/dist/vue.d.cts +72 -0
- package/dist/vue.d.ts +72 -0
- package/dist/vue.js +43 -0
- package/dist/vue.js.map +1 -0
- package/package.json +128 -69
- package/dist/durablews.es.js +0 -120
- package/dist/durablews.umd.js +0 -1
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Standard Schema v1 interface (https://standardschema.dev), vendored as
|
|
3
|
+
* types-only per the spec's guidance — implementing libraries (zod, valibot,
|
|
4
|
+
* arktype, …) conform to this shape, so DurableWS can accept any of them
|
|
5
|
+
* without depending on any of them. Keeps core zero-dependency.
|
|
6
|
+
*/
|
|
7
|
+
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
8
|
+
readonly "~standard": StandardSchemaV1.Props<Input, Output>;
|
|
9
|
+
}
|
|
10
|
+
declare namespace StandardSchemaV1 {
|
|
11
|
+
interface Props<Input = unknown, Output = Input> {
|
|
12
|
+
readonly version: 1;
|
|
13
|
+
readonly vendor: string;
|
|
14
|
+
readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
|
|
15
|
+
readonly types?: Types<Input, Output> | undefined;
|
|
16
|
+
}
|
|
17
|
+
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
18
|
+
interface SuccessResult<Output> {
|
|
19
|
+
readonly value: Output;
|
|
20
|
+
readonly issues?: undefined;
|
|
21
|
+
}
|
|
22
|
+
interface FailureResult {
|
|
23
|
+
readonly issues: ReadonlyArray<Issue>;
|
|
24
|
+
}
|
|
25
|
+
interface Issue {
|
|
26
|
+
readonly message: string;
|
|
27
|
+
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
28
|
+
}
|
|
29
|
+
interface PathSegment {
|
|
30
|
+
readonly key: PropertyKey;
|
|
31
|
+
}
|
|
32
|
+
interface Types<Input = unknown, Output = Input> {
|
|
33
|
+
readonly input: Input;
|
|
34
|
+
readonly output: Output;
|
|
35
|
+
}
|
|
36
|
+
type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema["~standard"]["types"]>["input"];
|
|
37
|
+
type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema["~standard"]["types"]>["output"];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Thrown (as an `error` event payload) when an inbound message fails the
|
|
41
|
+
* configured schema. The message is **not** emitted — handlers only ever see
|
|
42
|
+
* data that passed validation.
|
|
43
|
+
*/
|
|
44
|
+
declare class SchemaValidationError extends Error {
|
|
45
|
+
readonly issues: ReadonlyArray<StandardSchemaV1.Issue>;
|
|
46
|
+
constructor(issues: ReadonlyArray<StandardSchemaV1.Issue>);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Translates between application values and WebSocket wire frames.
|
|
51
|
+
*
|
|
52
|
+
* The codec is the single seam where serialization lives: `send()` runs values
|
|
53
|
+
* through `encode`, and incoming frames are run through `decode` before being
|
|
54
|
+
* emitted as `message`. The default is JSON (see `codec.ts`); supply your own
|
|
55
|
+
* for binary protocols, schema-based formats, etc.
|
|
56
|
+
*/
|
|
57
|
+
interface Codec {
|
|
58
|
+
/**
|
|
59
|
+
* Encode an outgoing value into a WebSocket-sendable frame.
|
|
60
|
+
*
|
|
61
|
+
* The return type deliberately mirrors `WebSocket.send`'s parameter
|
|
62
|
+
* (`BufferSource` is its exact alias), so the codec contract can never
|
|
63
|
+
* drift looser than what the socket accepts — e.g. TS 6's lib excludes
|
|
64
|
+
* `SharedArrayBuffer`-backed views from `send`, and this excludes them too.
|
|
65
|
+
*/
|
|
66
|
+
encode(data: unknown): string | BufferSource | Blob;
|
|
67
|
+
/** Decode an incoming frame (`string` for text, `ArrayBuffer`/`Blob` for binary). */
|
|
68
|
+
decode(data: unknown): unknown;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Tuning for automatic reconnection. All fields optional — the defaults give
|
|
72
|
+
* full-jitter exponential backoff with unlimited retries.
|
|
73
|
+
*/
|
|
74
|
+
interface ReconnectOptions {
|
|
75
|
+
/** First-retry delay ceiling in ms. Default `500`. */
|
|
76
|
+
readonly baseDelay?: number;
|
|
77
|
+
/** Exponential growth factor. Default `2`. */
|
|
78
|
+
readonly factor?: number;
|
|
79
|
+
/** Delay ceiling in ms. Default `30_000`. */
|
|
80
|
+
readonly maxDelay?: number;
|
|
81
|
+
/**
|
|
82
|
+
* Full jitter: each delay is drawn uniformly from `[0, computed]`, so a
|
|
83
|
+
* fleet of clients dropped at once doesn't retry in synchronized waves.
|
|
84
|
+
* Default `true`; set `false` for exact exponential delays.
|
|
85
|
+
*/
|
|
86
|
+
readonly jitter?: boolean;
|
|
87
|
+
/** Retries per disconnection before giving up. Default `Infinity`. */
|
|
88
|
+
readonly maxRetries?: number;
|
|
89
|
+
/**
|
|
90
|
+
* Decide per-close whether to reconnect (e.g. skip auth rejections by
|
|
91
|
+
* close code). Default: always reconnect. User-initiated `close()` never
|
|
92
|
+
* reconnects, regardless of this.
|
|
93
|
+
*/
|
|
94
|
+
readonly shouldReconnect?: (event: CloseEvent) => boolean;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Opt-in liveness checking. When configured, the client sends `message` every
|
|
98
|
+
* `interval` ms while open; if **no inbound frame of any kind** arrives within
|
|
99
|
+
* `timeout` ms of a ping, the link is declared dead and force-closed (code
|
|
100
|
+
* `4408`), which flows into the normal reconnect machinery.
|
|
101
|
+
*
|
|
102
|
+
* Requires a server that responds to the heartbeat message (or talks
|
|
103
|
+
* regularly for other reasons) — that app-level contract is why heartbeat is
|
|
104
|
+
* opt-in rather than on by default.
|
|
105
|
+
*/
|
|
106
|
+
interface HeartbeatOptions {
|
|
107
|
+
/** Milliseconds between pings. */
|
|
108
|
+
readonly interval: number;
|
|
109
|
+
/** The ping payload, run through the codec. Default `"ping"`. */
|
|
110
|
+
readonly message?: unknown;
|
|
111
|
+
/**
|
|
112
|
+
* Milliseconds after a ping to wait for inbound traffic before declaring
|
|
113
|
+
* the link dead. Default: `interval`.
|
|
114
|
+
*/
|
|
115
|
+
readonly timeout?: number;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Tuning for the outbound message queue.
|
|
119
|
+
*/
|
|
120
|
+
interface QueueOptions {
|
|
121
|
+
/**
|
|
122
|
+
* Maximum queued messages. When full, the **oldest** is dropped and a
|
|
123
|
+
* `drop` event fires — never silently unbounded, never silently lossy.
|
|
124
|
+
* Default `256`.
|
|
125
|
+
*/
|
|
126
|
+
readonly maxSize?: number;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Configuration options for the WebSocket client.
|
|
130
|
+
*/
|
|
131
|
+
interface WebSocketClientConfig {
|
|
132
|
+
/** The URL to connect to. */
|
|
133
|
+
readonly url: string | URL;
|
|
134
|
+
/** Optional subprotocol(s) passed to the underlying `WebSocket`. */
|
|
135
|
+
readonly protocols?: string | string[];
|
|
136
|
+
/**
|
|
137
|
+
* `binaryType` applied to the underlying socket on every (re)connect:
|
|
138
|
+
* `"arraybuffer"` delivers binary frames as `ArrayBuffer` instead of the
|
|
139
|
+
* browser default `Blob`.
|
|
140
|
+
*/
|
|
141
|
+
readonly binaryType?: BinaryType;
|
|
142
|
+
/** Wire-format codec. Defaults to JSON (`jsonCodec`). */
|
|
143
|
+
readonly codec?: Codec;
|
|
144
|
+
/**
|
|
145
|
+
* Automatic reconnection — **on by default** (durable by default). Pass
|
|
146
|
+
* `false` to disable, or options to tune the backoff.
|
|
147
|
+
*/
|
|
148
|
+
readonly reconnect?: false | ReconnectOptions;
|
|
149
|
+
/**
|
|
150
|
+
* Outbound queueing while disconnected — **on by default**. `send()`
|
|
151
|
+
* during `connecting`/`reconnecting` queues and flushes in order on open.
|
|
152
|
+
* Pass `false` to make `send()` throw whenever the socket isn't open.
|
|
153
|
+
*/
|
|
154
|
+
readonly queue?: false | QueueOptions;
|
|
155
|
+
/**
|
|
156
|
+
* Liveness checking — **opt-in** (off unless configured). See
|
|
157
|
+
* {@link HeartbeatOptions}.
|
|
158
|
+
*/
|
|
159
|
+
readonly heartbeat?: HeartbeatOptions;
|
|
160
|
+
/**
|
|
161
|
+
* A [Standard Schema](https://standardschema.dev) (zod, valibot, arktype,
|
|
162
|
+
* …) validating every **inbound** message after `codec.decode` and before
|
|
163
|
+
* middleware. Valid messages flow on with the schema's output value;
|
|
164
|
+
* invalid ones surface as an `error` event (`SchemaValidationError`) and
|
|
165
|
+
* are never emitted as `message`. When passed to `defineClient`, the
|
|
166
|
+
* message type is **inferred from the schema** — no generics needed.
|
|
167
|
+
*/
|
|
168
|
+
readonly schema?: StandardSchemaV1;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* The states a connection can occupy. This is the public, observable lifecycle.
|
|
172
|
+
*
|
|
173
|
+
* - `idle` — created but never connected.
|
|
174
|
+
* - `connecting` — a socket is open-in-progress, awaiting the first `open`.
|
|
175
|
+
* - `open` — connected and ready to send/receive.
|
|
176
|
+
* - `closing` — a close has been requested, awaiting the socket to finish.
|
|
177
|
+
* - `reconnecting` — the connection dropped; waiting out the backoff delay
|
|
178
|
+
* before the next attempt.
|
|
179
|
+
* - `closed` — the socket is closed; the client may `connect()` again.
|
|
180
|
+
*/
|
|
181
|
+
type ConnectionState = "idle" | "connecting" | "open" | "closing" | "reconnecting" | "closed";
|
|
182
|
+
/**
|
|
183
|
+
* A read-only snapshot of the client's observable state. Bounded by design —
|
|
184
|
+
* it holds lifecycle, never message history.
|
|
185
|
+
*/
|
|
186
|
+
interface ClientState {
|
|
187
|
+
/** The current connection state. */
|
|
188
|
+
readonly state: ConnectionState;
|
|
189
|
+
/**
|
|
190
|
+
* The most recent failure, if any: a transport error (`Event`) or a
|
|
191
|
+
* client-detected one like a heartbeat timeout (`Error`).
|
|
192
|
+
*/
|
|
193
|
+
readonly lastError: Event | Error | null;
|
|
194
|
+
/**
|
|
195
|
+
* Retries used in the current disconnection episode. `0` while healthy;
|
|
196
|
+
* resets on a successful open or a user `close()`.
|
|
197
|
+
*/
|
|
198
|
+
readonly retryAttempt: number;
|
|
199
|
+
/** Messages currently waiting in the outbound queue. */
|
|
200
|
+
readonly queueLength: number;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Payload emitted on every `drop` event — a queued outbound message that will
|
|
204
|
+
* never be sent.
|
|
205
|
+
*/
|
|
206
|
+
interface DropEvent<TOut = unknown> {
|
|
207
|
+
/** The original (un-encoded) value passed to `send()`. */
|
|
208
|
+
readonly data: TOut;
|
|
209
|
+
/**
|
|
210
|
+
* Why it was dropped: `overflow` — the queue was full and this was the
|
|
211
|
+
* oldest entry; `close` — the connection ended (user `close()` or terminal
|
|
212
|
+
* failure) with messages still queued.
|
|
213
|
+
*/
|
|
214
|
+
readonly reason: "overflow" | "close";
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Payload emitted on every `reconnecting` event (one per scheduled retry).
|
|
218
|
+
*/
|
|
219
|
+
interface ReconnectingEvent {
|
|
220
|
+
/** 1-based retry number within this disconnection episode. */
|
|
221
|
+
readonly attempt: number;
|
|
222
|
+
/** The backoff delay (ms) before this attempt fires. */
|
|
223
|
+
readonly delay: number;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* The context handed to each message middleware.
|
|
227
|
+
*/
|
|
228
|
+
interface MessageContext<TIn = unknown> {
|
|
229
|
+
/**
|
|
230
|
+
* The decoded (and, if a schema is configured, validated) inbound message.
|
|
231
|
+
* Middleware may reassign this to transform what later middleware — and
|
|
232
|
+
* the `message` event — receive.
|
|
233
|
+
*/
|
|
234
|
+
data: TIn;
|
|
235
|
+
/** The client, e.g. for sending a reply from within the pipeline. */
|
|
236
|
+
readonly client: WebSocketClient<TIn>;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Message middleware, run in registration order for each inbound message.
|
|
240
|
+
*
|
|
241
|
+
* Call `next()` to pass control to the next middleware; the message is emitted
|
|
242
|
+
* as a `message` event only if the whole chain calls through. Return without
|
|
243
|
+
* calling `next()` to short-circuit (e.g. an auto-reply that shouldn't bubble).
|
|
244
|
+
* May be async.
|
|
245
|
+
*/
|
|
246
|
+
type Middleware<TIn = unknown> = (ctx: MessageContext<TIn>, next: () => void | Promise<void>) => void | Promise<void>;
|
|
247
|
+
/**
|
|
248
|
+
* The context handed to each outbound middleware.
|
|
249
|
+
*/
|
|
250
|
+
interface OutboundContext<TOut = unknown> {
|
|
251
|
+
/**
|
|
252
|
+
* The outbound message, exactly as passed to `send()`. Middleware may
|
|
253
|
+
* reassign this to transform what later middleware — and ultimately
|
|
254
|
+
* `codec.encode` — receive.
|
|
255
|
+
*/
|
|
256
|
+
data: TOut;
|
|
257
|
+
/** The client, e.g. to read `getState()` from within the pipeline. */
|
|
258
|
+
readonly client: WebSocketClient<unknown, TOut>;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Outbound middleware, run in registration order for each outgoing message at
|
|
262
|
+
* **transmission time** — after dequeue, before `codec.encode` — so a message
|
|
263
|
+
* queued across a reconnect sees middleware (e.g. a token refresh) that is
|
|
264
|
+
* fresh when it actually goes out.
|
|
265
|
+
*
|
|
266
|
+
* May be async: the outbound path is serialized, so messages reach the socket
|
|
267
|
+
* in `send()` order even while an earlier message's middleware awaits (a
|
|
268
|
+
* delaying middleware therefore delays everything behind it — head-of-line,
|
|
269
|
+
* by design). Return without calling `next()` to deliberately not send the
|
|
270
|
+
* message (no `drop` event — `drop` means durability loss, not policy).
|
|
271
|
+
* A throw/rejection surfaces as an `error` event and skips only that message.
|
|
272
|
+
*
|
|
273
|
+
* Heartbeat pings bypass outbound middleware entirely.
|
|
274
|
+
*/
|
|
275
|
+
type OutboundMiddleware<TOut = unknown> = (ctx: OutboundContext<TOut>, next: () => void | Promise<void>) => void | Promise<void>;
|
|
276
|
+
/**
|
|
277
|
+
* The object form accepted by `use()`: register middleware per direction, so
|
|
278
|
+
* one logical middleware (auth, logging, metrics) has a single registration
|
|
279
|
+
* site. Either side may be omitted.
|
|
280
|
+
*/
|
|
281
|
+
interface DirectionalMiddleware<TIn = unknown, TOut = unknown> {
|
|
282
|
+
readonly inbound?: Middleware<TIn>;
|
|
283
|
+
readonly outbound?: OutboundMiddleware<TOut>;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Payload emitted on every `statechange`.
|
|
287
|
+
*/
|
|
288
|
+
interface StateChange {
|
|
289
|
+
/** The state being left. */
|
|
290
|
+
readonly previous: ConnectionState;
|
|
291
|
+
/** The state being entered. */
|
|
292
|
+
readonly current: ConnectionState;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* The events a client emits, mapped to their payload types. Used to give
|
|
296
|
+
* `on()` precise, per-event payload typing.
|
|
297
|
+
*/
|
|
298
|
+
interface ClientEventMap<TIn = unknown, TOut = unknown> {
|
|
299
|
+
/** The socket opened. */
|
|
300
|
+
open: undefined;
|
|
301
|
+
/** A message was received, decoded, and (if configured) validated. */
|
|
302
|
+
message: TIn;
|
|
303
|
+
/** The socket closed (clean or otherwise). */
|
|
304
|
+
close: CloseEvent;
|
|
305
|
+
/**
|
|
306
|
+
* Something failed: a transport error (an `Event` from the socket) or a
|
|
307
|
+
* middleware that threw/rejected (an `Error`).
|
|
308
|
+
*/
|
|
309
|
+
error: Event | Error;
|
|
310
|
+
/** The connection state changed. */
|
|
311
|
+
statechange: StateChange;
|
|
312
|
+
/** A reconnect attempt was scheduled (fires once per retry). */
|
|
313
|
+
reconnecting: ReconnectingEvent;
|
|
314
|
+
/** A queued outbound message was dropped and will never be sent. */
|
|
315
|
+
drop: DropEvent<TOut>;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* A resilient, zero-dependency WebSocket client.
|
|
319
|
+
*
|
|
320
|
+
* @typeParam TIn - The type of inbound messages (what `on("message")`
|
|
321
|
+
* handlers receive). Inferred from `config.schema` when one is given.
|
|
322
|
+
* @typeParam TOut - The type accepted by `send()`.
|
|
323
|
+
*/
|
|
324
|
+
interface WebSocketClient<TIn = unknown, TOut = unknown> {
|
|
325
|
+
/** The current connection state. */
|
|
326
|
+
readonly state: ConnectionState;
|
|
327
|
+
/**
|
|
328
|
+
* Opens the connection.
|
|
329
|
+
*
|
|
330
|
+
* Resolves the first time the socket opens — including when that open is
|
|
331
|
+
* a successful *retry* (the promise survives failed attempts while
|
|
332
|
+
* reconnection is active). Calling it while already `open` resolves
|
|
333
|
+
* immediately; calling it while `connecting` returns the same in-flight
|
|
334
|
+
* promise (idempotent); calling it while `reconnecting` skips the backoff
|
|
335
|
+
* wait and attempts immediately.
|
|
336
|
+
*
|
|
337
|
+
* Rejects only on **terminal** failure: retries exhausted
|
|
338
|
+
* (`reconnect.maxRetries`), a `shouldReconnect` veto, `close()` before the
|
|
339
|
+
* first open, or — with `reconnect: false` — any close before opening.
|
|
340
|
+
*
|
|
341
|
+
* **Under the default `maxRetries: Infinity`, this promise never rejects**:
|
|
342
|
+
* against a down host it stays pending while the client keeps retrying.
|
|
343
|
+
* That is the durable-by-default contract, by design. If you need a
|
|
344
|
+
* deadline, set a finite `maxRetries` or race it:
|
|
345
|
+
* `Promise.race([client.connect(), timeout(10_000)])`.
|
|
346
|
+
*
|
|
347
|
+
* Failures *after* the first open surface via the `error` / `close` /
|
|
348
|
+
* `reconnecting` events, not this promise. For fire-and-forget use, attach
|
|
349
|
+
* a `.catch` or listen for `error` to avoid an unhandled rejection.
|
|
350
|
+
*/
|
|
351
|
+
connect(): Promise<void>;
|
|
352
|
+
/**
|
|
353
|
+
* Sends data over the connection. Non-string data is encoded (JSON by
|
|
354
|
+
* default).
|
|
355
|
+
*
|
|
356
|
+
* While `connecting` or `reconnecting`, the message is **queued** (bounded,
|
|
357
|
+
* drop-oldest — see `queue` config) and flushed in order when the socket
|
|
358
|
+
* opens; queued messages that will never send surface as `drop` events.
|
|
359
|
+
* Throws when the client is `idle`, `closing`, or `closed` — states where
|
|
360
|
+
* no open is coming — or whenever the socket isn't open if `queue: false`.
|
|
361
|
+
*/
|
|
362
|
+
send(data: TOut): void;
|
|
363
|
+
/**
|
|
364
|
+
* Closes the connection.
|
|
365
|
+
* @param code - Optional close code (see `error.ts`).
|
|
366
|
+
* @param reason - Optional human-readable close reason.
|
|
367
|
+
*/
|
|
368
|
+
close(code?: number, reason?: string): void;
|
|
369
|
+
/**
|
|
370
|
+
* Subscribes to a client event.
|
|
371
|
+
* @returns an unsubscribe function.
|
|
372
|
+
*/
|
|
373
|
+
on<K extends keyof ClientEventMap<TIn, TOut>>(event: K, handler: (payload: ClientEventMap<TIn, TOut>[K]) => void): () => void;
|
|
374
|
+
/**
|
|
375
|
+
* Registers message middleware.
|
|
376
|
+
*
|
|
377
|
+
* A bare function registers **inbound** middleware (run in order for each
|
|
378
|
+
* inbound message — unchanged). The object form registers per direction:
|
|
379
|
+
* `use({ outbound })`, `use({ inbound, outbound })`. See
|
|
380
|
+
* {@link OutboundMiddleware} for the outbound contract (transmission-time
|
|
381
|
+
* execution, ordered async, silent short-circuit, per-message errors).
|
|
382
|
+
*
|
|
383
|
+
* @returns the client, for chaining.
|
|
384
|
+
*/
|
|
385
|
+
use(middleware: Middleware<TIn> | DirectionalMiddleware<TIn, TOut>): WebSocketClient<TIn, TOut>;
|
|
386
|
+
/**
|
|
387
|
+
* Returns a read-only snapshot of the client's observable state.
|
|
388
|
+
*
|
|
389
|
+
* The snapshot is **referentially stable**: repeated calls return the same
|
|
390
|
+
* frozen object until something actually changes. Together with
|
|
391
|
+
* {@link subscribe} this is exactly the `subscribe`/`getSnapshot` pair
|
|
392
|
+
* React's `useSyncExternalStore` requires, and it drives Vue/Svelte
|
|
393
|
+
* reactivity equally well.
|
|
394
|
+
*/
|
|
395
|
+
getState(): ClientState;
|
|
396
|
+
/**
|
|
397
|
+
* Subscribes to **any** change of the observable snapshot — connection
|
|
398
|
+
* state, `lastError`, `retryAttempt`, or `queueLength`. Unlike
|
|
399
|
+
* `on("statechange")` (which fires only on FSM transitions), this also
|
|
400
|
+
* fires when, e.g., the queue grows on a `send()` while disconnected.
|
|
401
|
+
*
|
|
402
|
+
* The listener receives no arguments; read `getState()` for the new
|
|
403
|
+
* snapshot.
|
|
404
|
+
*
|
|
405
|
+
* @returns an unsubscribe function.
|
|
406
|
+
*/
|
|
407
|
+
subscribe(listener: () => void): () => void;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export { type Codec as C, type DirectionalMiddleware as D, type HeartbeatOptions as H, type Middleware as M, type OutboundContext as O, type QueueOptions as Q, type ReconnectOptions as R, StandardSchemaV1 as S, type WebSocketClient as W, type WebSocketClientConfig as a, type ClientEventMap as b, type ClientState as c, type ConnectionState as d, type DropEvent as e, type MessageContext as f, type OutboundMiddleware as g, type ReconnectingEvent as h, SchemaValidationError as i, type StateChange as j };
|