react-websocket 3.6.0 → 4.18.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.
Files changed (52) hide show
  1. package/README.md +34 -5
  2. package/dist/ag-ui.cjs +421 -0
  3. package/dist/ag-ui.cjs.map +1 -0
  4. package/dist/ag-ui.d.cts +493 -0
  5. package/dist/ag-ui.d.ts +171 -0
  6. package/dist/ag-ui.js +418 -0
  7. package/dist/ag-ui.js.map +1 -0
  8. package/dist/core.cjs +727 -162
  9. package/dist/core.cjs.map +1 -1
  10. package/dist/core.d.cts +501 -62
  11. package/dist/core.d.ts +501 -62
  12. package/dist/core.js +723 -163
  13. package/dist/core.js.map +1 -1
  14. package/dist/devtools.cjs +186 -0
  15. package/dist/devtools.cjs.map +1 -0
  16. package/dist/devtools.d.cts +32 -0
  17. package/dist/devtools.d.ts +32 -0
  18. package/dist/devtools.js +185 -0
  19. package/dist/devtools.js.map +1 -0
  20. package/dist/index.cjs +214 -19
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +705 -56
  23. package/dist/index.d.ts +421 -30
  24. package/dist/index.js +211 -21
  25. package/dist/index.js.map +1 -1
  26. package/dist/outbox.cjs +222 -0
  27. package/dist/outbox.cjs.map +1 -0
  28. package/dist/outbox.d.cts +127 -0
  29. package/dist/outbox.d.ts +127 -0
  30. package/dist/outbox.js +219 -0
  31. package/dist/outbox.js.map +1 -0
  32. package/dist/replay.cjs +324 -0
  33. package/dist/replay.cjs.map +1 -0
  34. package/dist/replay.d.cts +124 -0
  35. package/dist/replay.d.ts +124 -0
  36. package/dist/replay.js +322 -0
  37. package/dist/replay.js.map +1 -0
  38. package/dist/tabs.cjs +336 -0
  39. package/dist/tabs.cjs.map +1 -0
  40. package/dist/tabs.d.cts +81 -0
  41. package/dist/tabs.d.ts +81 -0
  42. package/dist/tabs.js +335 -0
  43. package/dist/tabs.js.map +1 -0
  44. package/dist/timeline.d.cts +1 -213
  45. package/dist/types-BEecFqIB.d.cts +268 -0
  46. package/dist/webtransport.cjs +243 -0
  47. package/dist/webtransport.cjs.map +1 -0
  48. package/dist/webtransport.d.cts +67 -0
  49. package/dist/webtransport.d.ts +67 -0
  50. package/dist/webtransport.js +242 -0
  51. package/dist/webtransport.js.map +1 -0
  52. package/package.json +139 -3
package/dist/index.d.cts CHANGED
@@ -1,4 +1,5 @@
1
1
 
2
+ import { RefObject } from "react";
2
3
  //#region src/types.d.ts
3
4
  /**
4
5
  * Where to connect: a URL, or a function that returns one (sync or async).
@@ -21,7 +22,8 @@ type UrlSource = string | (() => string | Promise<string>);
21
22
  * - `open`: connected. `send()` goes out immediately.
22
23
  * - `reconnecting`: the connection dropped (or an attempt failed) and a retry is scheduled or in progress.
23
24
  * - `closed`: stopped for good, by `close()` or after giving up on reconnecting.
24
- * It stays closed until `connect()` or `reconnect()` is called, or every hook unmounts.
25
+ * It stays closed until `connect()` or `reconnect()` is called, or every hook unmounts. If
26
+ * nothing held it when it stopped, the next hook to mount starts it again.
25
27
  */
26
28
  type Status = 'idle' | 'connecting' | 'open' | 'reconnecting' | 'closed';
27
29
  /** The client's state as seen by React. A new object is created on every change. */
@@ -30,7 +32,10 @@ interface Snapshot<In> {
30
32
  readonly status: Status;
31
33
  /** Most recent message (after `parse`/`json` and `schema`), kept across reconnects. */
32
34
  readonly lastMessage: In | undefined;
33
- /** Consecutive failed attempts since the last successful open. `0` while open. */
35
+ /**
36
+ * Consecutive failed attempts since the last stable connection. A connection that closes
37
+ * within `reconnect.minUptime` of opening counts as failed. `0` while open.
38
+ */
34
39
  readonly attempt: number;
35
40
  }
36
41
  /** Details of a closed connection, from the browser's `CloseEvent`. */
@@ -52,6 +57,14 @@ interface ReconnectOptions {
52
57
  * @default Infinity
53
58
  */
54
59
  maxAttempts?: number;
60
+ /**
61
+ * How long a connection must stay open, in ms, before the backoff resets. One that closes
62
+ * sooner counts as a failed attempt, so a server that accepts and then closes right away
63
+ * (e.g. rejecting the credentials sent on open) is retried with a growing delay, and
64
+ * `maxAttempts` still applies. `0` resets on every open.
65
+ * @default 5000
66
+ */
67
+ minUptime?: number;
55
68
  /**
56
69
  * Delay before the first retry, in ms.
57
70
  * @default 1000
@@ -69,21 +82,67 @@ interface ReconnectOptions {
69
82
  factor?: number;
70
83
  /**
71
84
  * Randomly shave up to this fraction (0–1) off each delay, so that many clients
72
- * dropped at once don't all reconnect at the same moment.
73
- * @default 0.5
85
+ * dropped at once don't all reconnect at the same moment. The default `1` picks each
86
+ * delay at random between 0 and the backoff ("full jitter").
87
+ * @default 1
74
88
  */
75
89
  jitter?: number;
76
90
  /**
77
91
  * Called on every unexpected close. Return `false` to stop reconnecting.
78
92
  *
93
+ * The default, `retryableClose`, retries everything except `1002` (protocol error), `1003`
94
+ * (unsupported data) and `1008` (policy violation). Your own function replaces it; call
95
+ * `retryableClose` from it to keep that rule, or return `true` to retry every close.
96
+ *
79
97
  * @example
80
98
  * ```ts
81
- * // Don't retry when the server rejects our credentials.
82
- * shouldReconnect: close => close.code !== 4001
99
+ * import { retryableClose } from 'react-websocket';
100
+ *
101
+ * // Also stop when our server rejects the credentials.
102
+ * shouldReconnect: close => close.code !== 4001 && retryableClose(close)
83
103
  * ```
84
- * @default () => true
104
+ * @default retryableClose
85
105
  */
86
106
  shouldReconnect?: (close: CloseInfo) => boolean;
107
+ /**
108
+ * How long the server asked the client to wait before trying again, in ms, read from the
109
+ * close. Return `undefined` when it didn't ask. The client waits that long plus the usual
110
+ * backoff, so clients told the same delay still spread out, and the `online` and
111
+ * `visibilitychange` events don't cut the wait short.
112
+ *
113
+ * The default, `retryAfter`, reads a `1012` (Service Restart) or `1013` (Try Again Later)
114
+ * close whose reason is a number of seconds, like an HTTP `Retry-After` header. Your own
115
+ * function replaces it.
116
+ *
117
+ * A `1013` close that names no delay still waits longer than other closes: its backoff starts
118
+ * at `maxDelay`.
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * import { retryAfter } from 'react-websocket';
123
+ *
124
+ * // Our server also closes with 4429 and the delay in ms as the reason.
125
+ * retryAfter: close => (close.code === 4429 ? Number(close.reason) : retryAfter(close))
126
+ * ```
127
+ * @default retryAfter
128
+ */
129
+ retryAfter?: (close: CloseInfo) => number | undefined;
130
+ }
131
+ /** Options for `client.migrate()`. */
132
+ interface MigrateOptions {
133
+ /**
134
+ * Where to connect instead: a URL, or a function called before the connection, like the
135
+ * client's own `url`. Later reconnects go there too, until the client is closed, gives up or
136
+ * is torn down.
137
+ * @default the client's current URL
138
+ */
139
+ url?: UrlSource;
140
+ /**
141
+ * Move at a random moment within this many ms, so that clients asked to move together don't
142
+ * all reconnect at once.
143
+ * @default 0
144
+ */
145
+ within?: number;
87
146
  }
88
147
  /** Application-level keep-alive. Useful behind proxies that drop idle connections. */
89
148
  interface HeartbeatOptions {
@@ -99,6 +158,10 @@ interface HeartbeatOptions {
99
158
  /**
100
159
  * If nothing at all arrives within this many ms after a ping, the connection is
101
160
  * treated as dead: it closes with code `4000` and reconnects.
161
+ *
162
+ * A ping also goes out right away when the browser comes back online or the tab becomes
163
+ * visible, so a connection that died during sleep is found within `timeout`, not after up
164
+ * to `interval` more.
102
165
  */
103
166
  timeout?: number;
104
167
  }
@@ -143,11 +206,19 @@ interface SendOptions {
143
206
  * ```
144
207
  */
145
208
  maxBuffered?: number;
209
+ /**
210
+ * Drop the message instead of sending it if it has been queued for longer than this many
211
+ * ms, for messages that go stale during a long outage, such as "typing" or a price quote.
212
+ * Overrides `queue.maxAge`. Checked when the socket opens and whenever another message is
213
+ * queued; `onDrop` is called then.
214
+ */
215
+ maxAge?: number;
146
216
  /**
147
217
  * Called if the message is dropped from the queue without being sent: replaced by a
148
- * newer message with the same `key`, or evicted by `queue.limit`. Not called when the
149
- * queue is cleared because the client closed or gave up, or when `send()` drops the
150
- * message right away (`volatile` while not open, or `maxBuffered`) and returns `false`.
218
+ * newer message with the same `key`, evicted by `queue.limit`, or older than `maxAge`. Not
219
+ * called when the queue is cleared because the client closed or gave up, or when `send()`
220
+ * drops the message right away (`volatile` while not open, or `maxBuffered`) and returns
221
+ * `false`.
151
222
  */
152
223
  onDrop?: () => void;
153
224
  }
@@ -156,9 +227,17 @@ interface QueueOptions {
156
227
  /**
157
228
  * Maximum number of messages held while not connected. When full, the oldest
158
229
  * message is dropped, skipping `priority` messages unless nothing else is queued.
159
- * @default Infinity
230
+ * `Infinity` keeps every message.
231
+ * @default 100
160
232
  */
161
233
  limit?: number;
234
+ /**
235
+ * Drop a queued message instead of sending it once it has waited longer than this many ms,
236
+ * calling its `onDrop`. A message's own `maxAge` overrides it. Checked when the socket opens
237
+ * and whenever another message is queued.
238
+ * @default Infinity
239
+ */
240
+ maxAge?: number;
162
241
  }
163
242
  /**
164
243
  * The minimal [Standard Schema v1](https://standardschema.dev) interface, implemented
@@ -232,8 +311,8 @@ interface WebSocketOptions<In = unknown, Out = unknown> {
232
311
  heartbeat?: HeartbeatOptions;
233
312
  /**
234
313
  * Buffer `send()` calls made while not connected and send them, in order, on open
235
- * (right after `open` listeners run).
236
- * `false` drops them instead. `{ limit }` caps the buffer, dropping the oldest.
314
+ * (right after `open` listeners run). It holds up to 100 messages, dropping the oldest;
315
+ * `{ limit }` changes that. `false` drops messages instead of queueing them.
237
316
  * The queue is cleared by `close()` or when the client gives up.
238
317
  * @default true
239
318
  */
@@ -357,7 +436,10 @@ interface WebSocketClient<In = unknown, Out = unknown> {
357
436
  /**
358
437
  * Close the connection and stop reconnecting. The status becomes `closed` and the
359
438
  * send queue is cleared. Mounted hooks stay mounted; call `connect()` or `reconnect()`
360
- * to start again.
439
+ * to start again. Closed while no hook holds it, the next hook to mount starts it again.
440
+ *
441
+ * Like `WebSocket.close()`, it throws for a code or reason the socket rejects (browsers take
442
+ * `1000` or `3000`–`4999`, and a reason up to 123 bytes), and then nothing has changed.
361
443
  * @param code - Close code. @default 1000
362
444
  */
363
445
  close(code?: number, reason?: string): void;
@@ -366,6 +448,28 @@ interface WebSocketClient<In = unknown, Out = unknown> {
366
448
  * backoff. Also restarts a `closed` client.
367
449
  */
368
450
  reconnect(): void;
451
+ /**
452
+ * Move to a new connection without a gap, for example when the server asks its clients to
453
+ * before a deploy. At a random moment within `options.within` ms, it opens a new connection
454
+ * (to `options.url`, if given) and, once that one is open, closes the current one with code
455
+ * `1000`. Until then the current connection keeps working, so the status stays `open` and
456
+ * `send()` doesn't queue.
457
+ *
458
+ * `open` listeners run for the new connection, as after any reconnect, so handshakes and
459
+ * topic subscriptions are sent again. Requests the old connection hadn't answered fail as on
460
+ * a lost connection. If the new connection fails before opening, the current one stays. If
461
+ * the client isn't open when the moment comes, only the URL changes, for the next attempt.
462
+ * A later call replaces one that hasn't moved yet.
463
+ *
464
+ * @example
465
+ * ```ts
466
+ * // The server sends { type: 'reconnect', within: 30000 } before it shuts down.
467
+ * live.on('message', message => {
468
+ * if (message.type === 'reconnect') live.migrate({ within: message.within, url: message.url });
469
+ * });
470
+ * ```
471
+ */
472
+ migrate(options?: MigrateOptions): void;
369
473
  /**
370
474
  * Hold the connection open until the returned function is called. This is what the
371
475
  * hooks use; call it yourself to integrate with non-React code.
@@ -375,6 +479,34 @@ interface WebSocketClient<In = unknown, Out = unknown> {
375
479
  }
376
480
  //#endregion
377
481
  //#region src/client.d.ts
482
+ /**
483
+ * The default `reconnect.shouldReconnect`: retry every close except `1002` (protocol error),
484
+ * `1003` (unsupported data) and `1008` (policy violation, often a rejected login), which
485
+ * retrying the same way can't fix. Call it from your own `shouldReconnect` to keep that rule.
486
+ *
487
+ * @example
488
+ * ```ts
489
+ * createWebSocket(url, {
490
+ * // Also stop on our server's "invalid token" code.
491
+ * reconnect: { shouldReconnect: close => close.code !== 4001 && retryableClose(close) }
492
+ * });
493
+ * ```
494
+ */
495
+ export declare function retryableClose(close: CloseInfo): boolean;
496
+ /**
497
+ * The default `reconnect.retryAfter`: for a `1012` (Service Restart) or `1013` (Try Again Later)
498
+ * close whose reason is a number of seconds, like an HTTP `Retry-After` header, that delay in ms.
499
+ * Call it from your own `retryAfter` to keep reading it.
500
+ *
501
+ * @example
502
+ * ```ts
503
+ * createWebSocket(url, {
504
+ * // Our server also closes with 4429 and the delay in ms as the reason.
505
+ * reconnect: { retryAfter: close => (close.code === 4429 ? Number(close.reason) : retryAfter(close)) }
506
+ * });
507
+ * ```
508
+ */
509
+ export declare function retryAfter(close: CloseInfo): number | undefined;
378
510
  /**
379
511
  * Create a WebSocket client, usually at module level, to share across components.
380
512
  *
@@ -396,6 +528,131 @@ interface WebSocketClient<In = unknown, Out = unknown> {
396
528
  */
397
529
  export declare function createWebSocket<In = unknown, Out = unknown>(url: UrlSource, options?: WebSocketOptions<In, Out>): WebSocketClient<In, Out>;
398
530
  //#endregion
531
+ //#region src/topics.d.ts
532
+ /** @internal Option key for a callback run when nothing holds a topic anymore. Used by feeds. */
533
+ declare const ON_RELEASE: unique symbol;
534
+ /** Options for {@link createWebSocketTopics}: the messages your server expects. */
535
+ interface WebSocketTopicsOptions<Out> {
536
+ /** The message that subscribes to `topic`. */
537
+ subscribe: (topic: string) => Out;
538
+ /** The message that unsubscribes from `topic`. Omit it if your server has none. */
539
+ unsubscribe?: (topic: string) => Out;
540
+ }
541
+ /** Reference-counted topic subscriptions on one client. Create with {@link createWebSocketTopics}. */
542
+ interface WebSocketTopics {
543
+ /** The client the subscription messages are sent on. */
544
+ readonly client: WebSocketClient<any, any>;
545
+ /**
546
+ * Hold a subscription to `topic`, and the client's connection, until the returned
547
+ * function is called. The release function is safe to call more than once.
548
+ */
549
+ acquire(topic: string): () => void;
550
+ /** The topics currently held, in the order they were first acquired. */
551
+ active(): string[];
552
+ /** Stop managing subscriptions. Only needed for managers created dynamically. */
553
+ dispose(): void;
554
+ }
555
+ /**
556
+ * Manage topic subscriptions that survive reconnects.
557
+ *
558
+ * - The first holder of a topic sends `subscribe(topic)`. Later holders share it.
559
+ * - A tick after the last holder releases it, `unsubscribe(topic)` is sent, so StrictMode
560
+ * and route transitions don't churn subscriptions.
561
+ * - After every reconnect, every held topic is subscribed again on the new socket, before
562
+ * messages queued while disconnected are sent.
563
+ *
564
+ * Subscriptions are only sent while the socket is open; nothing is queued for them.
565
+ *
566
+ * @example
567
+ * ```ts
568
+ * export const topics = createWebSocketTopics(live, {
569
+ * subscribe: topic => ({ type: 'subscribe', topic }),
570
+ * unsubscribe: topic => ({ type: 'unsubscribe', topic })
571
+ * });
572
+ *
573
+ * // In a component:
574
+ * useWebSocketTopic(topics, `prices:${symbol}`);
575
+ * ```
576
+ */
577
+ export declare function createWebSocketTopics<const Out>(client: WebSocketClient<any, Out>, options: WebSocketTopicsOptions<NoInfer<Out>> & {
578
+ [ON_RELEASE]?: (topic: string) => void;
579
+ }): WebSocketTopics;
580
+ //#endregion
581
+ //#region src/feeds.d.ts
582
+ /** Where a numbered message belongs: its topic, and its sequence number in that topic. */
583
+ interface FeedPosition {
584
+ readonly topic: string;
585
+ /** One more than the message before it on the same topic. */
586
+ readonly seq: number;
587
+ }
588
+ /** Options for {@link createWebSocketFeeds}: the messages your server expects and sends. */
589
+ interface WebSocketFeedsOptions<In, Out> {
590
+ /**
591
+ * The message that subscribes to `topic`. `after` is the sequence number of the last message
592
+ * received on it, so the server can send the ones after it, or `undefined` the first time.
593
+ * Sent on every new connection too.
594
+ */
595
+ subscribe: (topic: string, after: number | undefined) => Out;
596
+ /** The message that unsubscribes from `topic`. Omit it if your server has none. */
597
+ unsubscribe?: (topic: string) => Out;
598
+ /**
599
+ * The message that asks for what came after `after` when messages went missing on an open
600
+ * connection. Defaults to `subscribe(topic, after)`.
601
+ */
602
+ resume?: (topic: string, after: number) => Out;
603
+ /** Recognize a numbered message: its topic and sequence number. `undefined` for any other. */
604
+ sequence: (message: In) => FeedPosition | null | undefined;
605
+ /**
606
+ * Recognize a snapshot: a topic's whole state as of `seq`, which the server sends when it
607
+ * can't replay the messages after `after`. It's always delivered, and the numbering goes on
608
+ * from it.
609
+ */
610
+ snapshot?: (message: In) => FeedPosition | null | undefined;
611
+ /** Called when a message arrives after a gap, before the missing ones are asked for. */
612
+ onGap?: (topic: string, after: number, received: number) => void;
613
+ }
614
+ /**
615
+ * Topic subscriptions whose messages are numbered. A {@link WebSocketTopics}, so
616
+ * `useWebSocketTopic` takes it, and a message source for `createWebSocketState`.
617
+ * Create with {@link createWebSocketFeeds}.
618
+ */
619
+ interface WebSocketFeeds<In> extends WebSocketTopics {
620
+ /**
621
+ * Listen to messages in order: numbered ones once each and without gaps, others as they
622
+ * arrive. Returns an unsubscribe function.
623
+ */
624
+ on(type: 'message', listener: (message: In, event: MessageEvent) => void): () => void;
625
+ /** The sequence number of the last message delivered on `topic`, while it's held. */
626
+ position(topic: string): number | undefined;
627
+ }
628
+ /**
629
+ * Subscribe to topics whose messages carry a sequence number, and get each message once, in
630
+ * order, across reconnects:
631
+ *
632
+ * - On every new connection, each held topic is subscribed again with `after`, the last
633
+ * number received, so the server sends what was missed instead of everything.
634
+ * - A message numbered at or below the last one is a duplicate and is dropped.
635
+ * - A message that skips numbers is held back, and the topic asks for what's missing (`resume`)
636
+ * once, so nothing is delivered out of order.
637
+ * - A server that can't replay sends a `snapshot`, and the numbering goes on from it.
638
+ *
639
+ * Listen with `feeds.on('message', …)`, or pass `feeds` to `createWebSocketState` in place of
640
+ * the client. Hold topics with `useWebSocketTopic(feeds, topic)` or `feeds.acquire(topic)`.
641
+ *
642
+ * @example
643
+ * ```ts
644
+ * export const feeds = createWebSocketFeeds(live, {
645
+ * subscribe: (topic, after) => ({ type: 'subscribe', topic, after }),
646
+ * unsubscribe: topic => ({ type: 'unsubscribe', topic }),
647
+ * sequence: message => (message.type === 'event' ? message : undefined),
648
+ * snapshot: message => (message.type === 'snapshot' ? message : undefined)
649
+ * });
650
+ *
651
+ * export const chat = createWebSocketState(feeds, { initialState: [], reduce: addMessage });
652
+ * ```
653
+ */
654
+ export declare function createWebSocketFeeds<In, const Out>(client: WebSocketClient<In, Out>, options: WebSocketFeedsOptions<NoInfer<In>, NoInfer<Out>>): WebSocketFeeds<In>;
655
+ //#endregion
399
656
  //#region src/latency.d.ts
400
657
  /** Options for {@link createWebSocketLatency}: how pings and pongs look on the wire. */
401
658
  interface WebSocketLatencyOptions<In, Out> {
@@ -473,6 +730,91 @@ interface WebSocketLatency {
473
730
  */
474
731
  export declare function createWebSocketLatency<In, const Out>(client: WebSocketClient<In, Out>, options: WebSocketLatencyOptions<NoInfer<In>, NoInfer<Out>>): WebSocketLatency;
475
732
  //#endregion
733
+ //#region src/presence.d.ts
734
+ /** Another client's shared state, such as its cursor or what it's selected. */
735
+ interface PresencePeer<P> {
736
+ /** The peer's id, as the server reports it. */
737
+ readonly peer: string;
738
+ readonly state: P;
739
+ /** When its state last arrived, from `Date.now()`. */
740
+ readonly updatedAt: number;
741
+ }
742
+ /** Options for {@link createWebSocketPresence}: the messages your server relays. */
743
+ interface WebSocketPresenceOptions<P, In, Out> {
744
+ /** The message that shares this client's state with the others. Annotate `state`. */
745
+ send: (state: P) => Out;
746
+ /** The message that says this client left, sent by `leave()`. Omit it if the server has none. */
747
+ leave?: () => Out;
748
+ /**
749
+ * Recognize another peer's state: its id and state, or `state: null` when it left. `undefined`
750
+ * for any other message.
751
+ */
752
+ receive: (message: In) => {
753
+ readonly peer: string;
754
+ readonly state: P | null;
755
+ } | null | undefined;
756
+ /**
757
+ * Forget a peer that hasn't sent its state for this long, in ms, as if it had left. Covers
758
+ * peers whose connection died without the server noticing.
759
+ * @default 30000
760
+ */
761
+ timeout?: number;
762
+ /**
763
+ * Send this client's state again this often while it doesn't change, in ms, so the others
764
+ * don't forget it.
765
+ * @default timeout / 3
766
+ */
767
+ refresh?: number;
768
+ /**
769
+ * How many times per second this client's state may be sent. Changes in between are
770
+ * coalesced: the newest goes out at the end of the interval.
771
+ * @default 20
772
+ */
773
+ maxRate?: number;
774
+ }
775
+ /** Shared per-peer state that expires. Create with {@link createWebSocketPresence}. */
776
+ interface WebSocketPresence<P> {
777
+ /** The client the state is shared on. */
778
+ readonly client: WebSocketClient<any, any>;
779
+ /**
780
+ * Share this client's state, e.g. on every pointer move. It's sent at most `maxRate` times per
781
+ * second, the newest only, and again on every new connection and every `refresh`.
782
+ */
783
+ set(state: P): void;
784
+ /** Stop sharing, and send `leave`. `set()` shares again. */
785
+ leave(): void;
786
+ /** The other peers, in the order they first appeared. A new array on every change. */
787
+ getSnapshot(): readonly PresencePeer<P>[];
788
+ /** Get notified when the peers change. Compatible with `useSyncExternalStore`. */
789
+ subscribe(listener: () => void): () => void;
790
+ /** Stop sharing and listening. */
791
+ dispose(): void;
792
+ }
793
+ /**
794
+ * Share per-peer state that expires, for presence, live cursors and selections.
795
+ *
796
+ * - `set(state)` shares this client's state, throttled to `maxRate` sends per second with the
797
+ * newest winning, and sent again on every new connection and every `refresh`, so it's never
798
+ * queued stale while disconnected.
799
+ * - Other peers' states come from `receive`. A peer is forgotten when it leaves (`state: null`)
800
+ * or when nothing has arrived from it for `timeout`.
801
+ *
802
+ * The server relays each client's state to the others, tagged with a peer id, and says
803
+ * `state: null` when a client disconnects.
804
+ *
805
+ * @example
806
+ * ```ts
807
+ * export const cursors = createWebSocketPresence(room, {
808
+ * send: (cursor: { x: number; y: number }) => ({ type: 'cursor', cursor }),
809
+ * leave: () => ({ type: 'leave' }),
810
+ * receive: message => (message.type === 'cursor' ? { peer: message.peer, state: message.cursor } : undefined)
811
+ * });
812
+ *
813
+ * window.addEventListener('pointermove', event => cursors.set({ x: event.clientX, y: event.clientY }));
814
+ * ```
815
+ */
816
+ export declare function createWebSocketPresence<P, In, const Out>(client: WebSocketClient<In, Out>, options: WebSocketPresenceOptions<P, NoInfer<In>, NoInfer<Out>>): WebSocketPresence<P>;
817
+ //#endregion
476
818
  //#region src/requests.d.ts
477
819
  /** Options for {@link createWebSocketRequests}: how requests and replies look on the wire. */
478
820
  interface WebSocketRequestsOptions<Req, In, Out> {
@@ -715,6 +1057,138 @@ interface WebSocketResponder<P = unknown, R = unknown> {
715
1057
  */
716
1058
  export declare function createWebSocketResponder<Q extends RequestFields, R, In, const Out>(client: WebSocketClient<In, Out>, options: WebSocketResponderOptions<Q, R, NoInfer<In>, NoInfer<Out>>): WebSocketResponder<ParamsOf<Q>, R>;
717
1059
  //#endregion
1060
+ //#region src/runs.d.ts
1061
+ /**
1062
+ * What happens to a run when its connection drops: `keep` resumes it on the next connection,
1063
+ * for agents that keep working in the background; `cancel` aborts it and tells the server, for
1064
+ * a chat answer nobody may be waiting for.
1065
+ */
1066
+ type RunPolicy = 'keep' | 'cancel';
1067
+ /** Where a run is: streaming events, or ended. */
1068
+ type RunStatus = 'streaming' | 'done' | 'error' | 'aborted';
1069
+ /** A run's state, reduced from its events. A new object on every change. */
1070
+ interface AgentRun<T> {
1071
+ readonly runId: string;
1072
+ readonly status: RunStatus;
1073
+ /** Reduced from the run's events with `reduce`, starting from `initial`. */
1074
+ readonly value: T;
1075
+ /** What `error` returned for the event that ended the run, when `status` is `'error'`. */
1076
+ readonly error: unknown;
1077
+ }
1078
+ /** The subset of `Storage` that runs use, so `sessionStorage`, `localStorage` or your own fits. */
1079
+ type RunStorage = Pick<Storage, 'getItem' | 'setItem' | 'removeItem'>;
1080
+ /** Options for {@link createWebSocketRuns}: the messages your server expects and sends. */
1081
+ interface WebSocketRunsOptions<Req, T, In, Out> {
1082
+ /** Names the runs' entry in `storage`, `react-websocket-runs:<name>`. */
1083
+ name: string;
1084
+ /**
1085
+ * The message that starts a run, with its `runId`. Sent again on a new connection until the
1086
+ * run's first event arrives, so the server should start a run only once per `runId`.
1087
+ * Annotate `request`: that's what `runs.start()` accepts.
1088
+ */
1089
+ start: (request: Req, runId: string) => Out;
1090
+ /**
1091
+ * The message that asks for a run's events after `after`, its last event received, or from
1092
+ * the beginning when `after` is `undefined` (after a reload, or for `attach()`). Sent on every
1093
+ * new connection while the run is streaming.
1094
+ */
1095
+ resume: (runId: string, after: number | undefined) => Out;
1096
+ /** The message that stops a run, sent by `abort()` and for runs whose policy is `cancel`. */
1097
+ cancel?: (runId: string) => Out;
1098
+ /**
1099
+ * Recognize a run's event: its `runId`, and its `offset`, one more than the event before it.
1100
+ * `undefined` for any other message.
1101
+ */
1102
+ event: (message: In) => {
1103
+ readonly runId: string;
1104
+ readonly offset: number;
1105
+ } | null | undefined;
1106
+ /** Whether an event is the run's last. The run is `'done'` after reducing it. */
1107
+ done?: (message: In) => boolean;
1108
+ /** Recognize an event that ends the run with an error: return it, or `undefined`. */
1109
+ error?: (message: In) => unknown;
1110
+ /** A run's value before its first event. */
1111
+ initial: T;
1112
+ /** Fold an event into a run's value. Pure. */
1113
+ reduce: (value: T, message: In) => T;
1114
+ /** @default 'keep' */
1115
+ policy?: RunPolicy;
1116
+ /**
1117
+ * Where to remember streaming runs, so a reload resumes them.
1118
+ * @default sessionStorage, where it exists. `null` remembers nothing.
1119
+ */
1120
+ storage?: RunStorage | null;
1121
+ }
1122
+ /** Runs that stream events and survive reconnects and reloads. Create with {@link createWebSocketRuns}. */
1123
+ interface WebSocketRuns<Req, T> {
1124
+ /** The client the runs stream on. */
1125
+ readonly client: WebSocketClient<any, any>;
1126
+ /**
1127
+ * Start a run and return its `runId`. The start message is sent as soon as the socket is
1128
+ * open, and the run is remembered until it ends. `initial` overrides the `initial` option for
1129
+ * this run. A `runId` it already knows, streaming or ended, starts nothing: the server starts
1130
+ * a run only once per id. `delete()` it first to use the id again.
1131
+ */
1132
+ start(request: Req, options?: {
1133
+ runId?: string;
1134
+ policy?: RunPolicy;
1135
+ initial?: T;
1136
+ }): string;
1137
+ /**
1138
+ * Follow a run started elsewhere, such as in another tab or before a reload, from its first
1139
+ * event. Does nothing for a run it already knows.
1140
+ */
1141
+ attach(runId: string, options?: {
1142
+ policy?: RunPolicy;
1143
+ initial?: T;
1144
+ }): void;
1145
+ /** Stop a streaming run: send `cancel`, and make it `'aborted'`. */
1146
+ abort(runId: string): void;
1147
+ /** A run's state, or `undefined` for one it doesn't know. The same object until it changes. */
1148
+ get(runId: string): AgentRun<T> | undefined;
1149
+ /** Every run it knows, oldest first. A new array on every change. */
1150
+ list(): readonly AgentRun<T>[];
1151
+ /** Get notified when a run changes. Compatible with `useSyncExternalStore`. */
1152
+ subscribe(listener: () => void): () => void;
1153
+ /** Forget a run, aborting it first if it's streaming. */
1154
+ delete(runId: string): void;
1155
+ /** Stop following runs, and release the connection. Remembered runs stay remembered. */
1156
+ dispose(): void;
1157
+ }
1158
+ /**
1159
+ * Stream runs, such as an AI agent's answer, that survive reconnects and page reloads.
1160
+ *
1161
+ * - `start(request)` sends `start(request, runId)` and follows the run's events, folding them
1162
+ * into its value with `reduce`.
1163
+ * - Each event carries an `offset`. On a new connection, a streaming run sends
1164
+ * `resume(runId, after)` with the last offset received, so the server sends what was missed,
1165
+ * and duplicates are dropped.
1166
+ * - Streaming runs are remembered in `sessionStorage`. After a reload they're followed again from
1167
+ * their first event, rebuilding the value, so `list()` or `useAgentRun` can show them.
1168
+ * - A run whose policy is `cancel` is aborted when its connection drops, and `cancel` is sent
1169
+ * first thing on the next one.
1170
+ *
1171
+ * Built on `createWebSocketFeeds`, with each run a topic. While runs are streaming, it holds
1172
+ * the client's connection.
1173
+ *
1174
+ * @example
1175
+ * ```ts
1176
+ * export const runs = createWebSocketRuns(agent, {
1177
+ * name: 'chat',
1178
+ * start: (prompt: string, runId) => ({ type: 'run', runId, prompt }),
1179
+ * resume: (runId, after) => ({ type: 'resume', runId, after }),
1180
+ * cancel: runId => ({ type: 'cancel', runId }),
1181
+ * event: message => (message.type === 'token' || message.type === 'done' ? message : undefined),
1182
+ * done: message => message.type === 'done',
1183
+ * initial: '',
1184
+ * reduce: (text, message) => text + message.text
1185
+ * });
1186
+ *
1187
+ * const runId = runs.start('Summarize this thread');
1188
+ * ```
1189
+ */
1190
+ export declare function createWebSocketRuns<Req, T, In, const Out>(client: WebSocketClient<In, Out>, options: WebSocketRunsOptions<Req, T, NoInfer<In>, NoInfer<Out>>): WebSocketRuns<Req, T>;
1191
+ //#endregion
718
1192
  //#region src/sendrate.d.ts
719
1193
  /** Options for {@link createWebSocketSendRate}. */
720
1194
  interface WebSocketSendRateOptions {
@@ -822,6 +1296,15 @@ interface WebSocketStateOptions<S, In> {
822
1296
  *
823
1297
  * @typeParam S - The state type. Don't use a function type: `setState` treats functions as updaters.
824
1298
  */
1299
+ /**
1300
+ * Messages from somewhere other than the client itself, such as the in-order messages of
1301
+ * `createWebSocketFeeds`, for `createWebSocketState`.
1302
+ */
1303
+ interface MessageSource<In> {
1304
+ /** The client the messages come from. */
1305
+ readonly client: WebSocketClient<any, any>;
1306
+ on(type: 'message', listener: (message: In, event: MessageEvent) => void): () => void;
1307
+ }
825
1308
  interface WebSocketState<S> {
826
1309
  /** The client whose messages this store reduces. Hooks reading the store keep it connected. */
827
1310
  readonly client: WebSocketClient<any, any>;
@@ -843,6 +1326,9 @@ interface WebSocketState<S> {
843
1326
  * It starts listening immediately and keeps the state across reconnects; it doesn't open
844
1327
  * the connection by itself.
845
1328
  *
1329
+ * Pass feeds from `createWebSocketFeeds` in place of the client to reduce their messages
1330
+ * instead: numbered ones once each and in order.
1331
+ *
846
1332
  * @example
847
1333
  * ```ts
848
1334
  * const prices = createWebSocket<Tick>('wss://api.example.com/prices', { json: true });
@@ -856,53 +1342,142 @@ interface WebSocketState<S> {
856
1342
  * const acme = useWebSocketState(priceState, state => state.ACME);
857
1343
  * ```
858
1344
  */
859
- export declare function createWebSocketState<S, In>(client: WebSocketClient<In, any>, options: WebSocketStateOptions<S, NoInfer<In>>): WebSocketState<S>;
1345
+ export declare function createWebSocketState<S, In>(source: WebSocketClient<In, any> | MessageSource<In>, options: WebSocketStateOptions<S, NoInfer<In>>): WebSocketState<S>;
860
1346
  //#endregion
861
- //#region src/topics.d.ts
862
- /** Options for {@link createWebSocketTopics}: the messages your server expects. */
863
- interface WebSocketTopicsOptions<Out> {
864
- /** The message that subscribes to `topic`. */
865
- subscribe: (topic: string) => Out;
866
- /** The message that unsubscribes from `topic`. Omit it if your server has none. */
867
- unsubscribe?: (topic: string) => Out;
1347
+ //#region src/ag-ui.d.ts
1348
+ /** A tool call on an assistant message, as in AG-UI. */
1349
+ interface AgUiToolCall {
1350
+ readonly id: string;
1351
+ readonly type: 'function';
1352
+ readonly function: {
1353
+ readonly name: string;
1354
+ readonly arguments: string;
1355
+ };
868
1356
  }
869
- /** Reference-counted topic subscriptions on one client. Create with {@link createWebSocketTopics}. */
870
- interface WebSocketTopics {
871
- /** The client the subscription messages are sent on. */
1357
+ /** A message in an AG-UI thread. */
1358
+ interface AgUiMessage {
1359
+ readonly id: string;
1360
+ readonly role: 'developer' | 'system' | 'assistant' | 'user' | 'tool' | 'reasoning' | 'activity';
1361
+ readonly content?: unknown;
1362
+ readonly toolCalls?: readonly AgUiToolCall[];
1363
+ /** For a `tool` message, the call it answers. */
1364
+ readonly toolCallId?: string;
1365
+ /** For an `activity` message. */
1366
+ readonly activityType?: string;
1367
+ readonly [field: string]: unknown;
1368
+ }
1369
+ /** AG-UI's `RunAgentInput`: what a run starts from. */
1370
+ interface RunAgentInput {
1371
+ readonly threadId: string;
1372
+ readonly runId: string;
1373
+ readonly parentRunId?: string;
1374
+ readonly state?: unknown;
1375
+ readonly messages: readonly AgUiMessage[];
1376
+ readonly tools: readonly unknown[];
1377
+ readonly context: readonly unknown[];
1378
+ readonly forwardedProps: unknown;
1379
+ }
1380
+ /** A thread's messages and shared state, reduced from AG-UI events. */
1381
+ interface AgUiThread<S = unknown> {
1382
+ readonly messages: readonly AgUiMessage[];
1383
+ /** The shared state, from `STATE_SNAPSHOT` and `STATE_DELTA`. */
1384
+ readonly state: S;
1385
+ /**
1386
+ * `'running'` from `RUN_STARTED`, `'finished'` after `RUN_FINISHED`, `'error'` after
1387
+ * `RUN_ERROR`, `'aborted'` when the run was stopped from this side.
1388
+ */
1389
+ readonly status: 'idle' | 'running' | 'finished' | 'error' | 'aborted';
1390
+ /** The step in progress, between `STEP_STARTED` and `STEP_FINISHED`. */
1391
+ readonly step?: string;
1392
+ /** From `RUN_ERROR`. */
1393
+ readonly error?: {
1394
+ readonly message: string;
1395
+ readonly code?: string;
1396
+ };
1397
+ /** From `RUN_FINISHED`. */
1398
+ readonly result?: unknown;
1399
+ /**
1400
+ * A `STATE_DELTA` couldn't be applied. `state` is the last good one, and later deltas are
1401
+ * skipped until a `STATE_SNAPSHOT` arrives.
1402
+ */
1403
+ readonly stale: boolean;
1404
+ }
1405
+ /** An AG-UI agent over a WebSocket. Create with {@link createAgUiAgent}. */
1406
+ interface AgUiAgent<S> {
1407
+ /** The client the runs stream on. */
1408
+ readonly client: WebSocketClient<any, any>;
1409
+ /** The runs underneath, from `createWebSocketRuns`. */
1410
+ readonly runs: WebSocketRuns<RunAgentInput, AgUiThread<S>>;
1411
+ /**
1412
+ * Start a run with the thread so far plus `input.messages`, which show up in the thread right
1413
+ * away. A run that's still streaming is aborted first. Returns the run's id.
1414
+ */
1415
+ run(input?: {
1416
+ messages?: readonly AgUiMessage[];
1417
+ tools?: readonly unknown[];
1418
+ context?: readonly unknown[];
1419
+ forwardedProps?: unknown;
1420
+ }, options?: {
1421
+ policy?: RunPolicy;
1422
+ }): string;
1423
+ /** Stop the run that's streaming, if any. */
1424
+ abort(): void;
1425
+ /** The thread as of the latest run. The same object until it changes. */
1426
+ getSnapshot(): AgUiThread<S>;
1427
+ /** Get notified when the thread changes. Compatible with `useSyncExternalStore`. */
1428
+ subscribe(listener: () => void): () => void;
1429
+ /** Stop following runs, and release the connection. */
1430
+ dispose(): void;
1431
+ }
1432
+ //#endregion
1433
+ //#region src/outbox.d.ts
1434
+ /** What an outbox stores for each message. */
1435
+ interface OutboxRecord<M = unknown> {
1436
+ /** The message's idempotency key, sent with it every time. */
1437
+ readonly id: string;
1438
+ /** The message, as passed to `add()`. */
1439
+ readonly message: M;
1440
+ /** When it was added, from `Date.now()`. Entries are sent in this order. */
1441
+ readonly createdAt: number;
1442
+ }
1443
+ /** A message waiting in the outbox. */
1444
+ interface OutboxEntry<M = unknown> extends OutboxRecord<M> {
1445
+ /** Sent on the current connection, and waiting for the server's ack. */
1446
+ readonly sent: boolean;
1447
+ }
1448
+ /** A persistent outbox on one client. Create with {@link createWebSocketOutbox}. */
1449
+ interface WebSocketOutbox<M> {
1450
+ /** The client the entries are sent on. */
872
1451
  readonly client: WebSocketClient<any, any>;
873
1452
  /**
874
- * Hold a subscription to `topic`, and the client's connection, until the returned
875
- * function is called. The release function is safe to call more than once.
1453
+ * Resolves once the entries stored by an earlier page load are back in the outbox, and
1454
+ * rejects if they couldn't be loaded. Nothing is sent before.
876
1455
  */
877
- acquire(topic: string): () => void;
878
- /** The topics currently held, in the order they were first acquired. */
879
- active(): string[];
880
- /** Stop managing subscriptions. Only needed for managers created dynamically. */
1456
+ readonly ready: Promise<void>;
1457
+ /**
1458
+ * Add a message and send it as soon as the socket is open. Resolves with its id once it's
1459
+ * stored, and rejects if storing failed; the entry is still sent from memory then, but won't
1460
+ * survive a reload. Without `ack`, one sent right away isn't stored, and resolves at once.
1461
+ * @param id - The idempotency key, e.g. an order number. A new random one by default.
1462
+ */
1463
+ add(message: M, id?: string): Promise<string>;
1464
+ /**
1465
+ * Remove an entry without sending it again, e.g. when the user cancels it. Other tabs using
1466
+ * the same `name` drop it too.
1467
+ */
1468
+ remove(id: string): Promise<void>;
1469
+ /**
1470
+ * Remove every entry at once, including ones other tabs stored, e.g. on logout. Other tabs
1471
+ * using the same `name` drop theirs too. Resolves once they're deleted from storage.
1472
+ */
1473
+ clear(): Promise<void>;
1474
+ /** The waiting entries, oldest first. A new array on every change. */
1475
+ getSnapshot(): readonly OutboxEntry<M>[];
1476
+ /** Get notified when the entries change. Compatible with `useSyncExternalStore`. */
1477
+ subscribe(listener: () => void): () => void;
1478
+ /** Stop sending and listening, and release the connection. Stored entries stay stored. */
881
1479
  dispose(): void;
882
1480
  }
883
- /**
884
- * Manage topic subscriptions that survive reconnects.
885
- *
886
- * - The first holder of a topic sends `subscribe(topic)`. Later holders share it.
887
- * - A tick after the last holder releases it, `unsubscribe(topic)` is sent, so StrictMode
888
- * and route transitions don't churn subscriptions.
889
- * - After every reconnect, every held topic is subscribed again on the new socket, before
890
- * messages queued while disconnected are sent.
891
- *
892
- * Subscriptions are only sent while the socket is open; nothing is queued for them.
893
- *
894
- * @example
895
- * ```ts
896
- * export const topics = createWebSocketTopics(live, {
897
- * subscribe: topic => ({ type: 'subscribe', topic }),
898
- * unsubscribe: topic => ({ type: 'unsubscribe', topic })
899
- * });
900
- *
901
- * // In a component:
902
- * useWebSocketTopic(topics, `prices:${symbol}`);
903
- * ```
904
- */
905
- export declare function createWebSocketTopics<const Out>(client: WebSocketClient<any, Out>, options: WebSocketTopicsOptions<NoInfer<Out>>): WebSocketTopics;
906
1481
  //#endregion
907
1482
  //#region src/react.d.ts
908
1483
  /**
@@ -945,7 +1520,9 @@ interface UseWebSocketResult<In, Out> extends Snapshot<In> {
945
1520
  * Connect to a WebSocket and re-render with its status and latest message.
946
1521
  *
947
1522
  * - With a URL, every component using the same URL (and `protocols`) shares one
948
- * connection. Its options come from whichever component created it first.
1523
+ * connection. Its options come from the first of them to mount; in development, a
1524
+ * component passing different ones gets a console warning. A render React throws away
1525
+ * never decides them.
949
1526
  * - With a client from `createWebSocket()`, options are the client's; only handlers
950
1527
  * and `enabled` apply here.
951
1528
  * - With `null` or `undefined`, nothing connects and the status stays `idle`.
@@ -1024,6 +1601,78 @@ export declare function useWebSocketTopic(topics: WebSocketTopics | null | undef
1024
1601
  * ```
1025
1602
  */
1026
1603
  export declare function useWebSocketLatency(latency: WebSocketLatency): Latency;
1604
+ /**
1605
+ * The messages waiting in an outbox from `react-websocket/outbox`, oldest first, for a "3 orders
1606
+ * waiting to sync" banner. Re-renders when they change. `null` lists nothing. On the server the
1607
+ * list is empty.
1608
+ *
1609
+ * @example
1610
+ * ```tsx
1611
+ * const waiting = useWebSocketOutbox(orders);
1612
+ * if (!waiting.length) return null;
1613
+ * return <p role="status">{waiting.length} orders waiting to sync</p>;
1614
+ * ```
1615
+ */
1616
+ export declare function useWebSocketOutbox<M>(outbox: WebSocketOutbox<M> | null | undefined): readonly OutboxEntry<M>[];
1617
+ /**
1618
+ * Whether an element is on screen, from an `IntersectionObserver`, for dashboards that stream
1619
+ * full detail only for what's visible: pick a topic with it and pass it to `useWebSocketTopic`,
1620
+ * which switches subscriptions when it changes. `initial` until the first observation, on the
1621
+ * server, and where `IntersectionObserver` doesn't exist.
1622
+ *
1623
+ * @example
1624
+ * ```tsx
1625
+ * const ref = useRef<HTMLElement>(null);
1626
+ * useWebSocketTopic(feeds, useInView(ref) ? `run:${id}:tokens` : `run:${id}:status`);
1627
+ * return <article ref={ref}>…</article>;
1628
+ * ```
1629
+ */
1630
+ export declare function useInView(ref: RefObject<Element | null>, options?: {
1631
+ rootMargin?: string;
1632
+ threshold?: number;
1633
+ initial?: boolean;
1634
+ }): boolean;
1635
+ /**
1636
+ * The other peers' shared state from `createWebSocketPresence`, such as their cursors.
1637
+ * Re-renders when a peer's state arrives, it leaves, or it times out. Keeps the connection open
1638
+ * while mounted. On the server the list is empty.
1639
+ *
1640
+ * @example
1641
+ * ```tsx
1642
+ * const peers = useWebSocketPresence(cursors);
1643
+ * return peers.map(({ peer, state }) => <Cursor key={peer} x={state.x} y={state.y} />);
1644
+ * ```
1645
+ */
1646
+ export declare function useWebSocketPresence<P>(presence: WebSocketPresence<P> | null | undefined): readonly PresencePeer<P>[];
1647
+ /**
1648
+ * The thread of an AG-UI agent from `react-websocket/ag-ui`: its messages, shared state and
1649
+ * status, re-rendering on every event.
1650
+ *
1651
+ * @example
1652
+ * ```tsx
1653
+ * const thread = useAgUiAgent(agent);
1654
+ * return thread.messages.map(message => <Message key={message.id} message={message} />);
1655
+ * ```
1656
+ */
1657
+ export declare function useAgUiAgent<S>(agent: AgUiAgent<S>): AgUiThread<S>;
1658
+ /**
1659
+ * A run from `createWebSocketRuns`, such as an agent's answer: its `value` reduced from the
1660
+ * events so far, and its `status`. Re-renders on every event. A run it doesn't know, such as one
1661
+ * started in another tab, is attached and followed from its first event. `undefined` while the
1662
+ * run is unknown, for a `null` id, and on the server.
1663
+ *
1664
+ * @example
1665
+ * ```tsx
1666
+ * const run = useAgentRun(runs, runId);
1667
+ * return (
1668
+ * <>
1669
+ * <Markdown>{run?.value ?? ''}</Markdown>
1670
+ * {run?.status === 'streaming' && <button onClick={() => runs.abort(runId)}>Stop</button>}
1671
+ * </>
1672
+ * );
1673
+ * ```
1674
+ */
1675
+ export declare function useAgentRun<T>(runs: WebSocketRuns<any, T> | null | undefined, runId: string | null | undefined): AgentRun<T> | undefined;
1027
1676
  /**
1028
1677
  * Requests for `method` that a person answers, e.g. an agent asking to run a tool. While mounted,
1029
1678
  * it registers `method` on the responder without a handler, so new requests wait here instead of
@@ -1103,5 +1752,5 @@ export declare function useWebSocketStream<Req, In>(rpc: WebSocketRequests<Req,
1103
1752
  batch?: 'frame';
1104
1753
  }): UseWebSocketStreamResult<Req, readonly In[]>;
1105
1754
  //#endregion
1106
- export type { CloseInfo, EventMap, HeartbeatOptions, IncomingRequest, Latency, QueueOptions, ReconnectOptions, RequestHandler, RequestOptions, SendData, SendOptions, SendRate, Snapshot, StandardSchemaV1, Status, UrlSource, UseWebSocketOptions, UseWebSocketResult, UseWebSocketStreamOptions, UseWebSocketStreamResult, WebSocketClient, WebSocketHandlers, WebSocketLatency, WebSocketLatencyOptions, WebSocketOptions, WebSocketRequests, WebSocketRequestsOptions, WebSocketResponder, WebSocketResponderOptions, WebSocketSendRate, WebSocketSendRateOptions, WebSocketState, WebSocketStateOptions, WebSocketTopics, WebSocketTopicsOptions };
1755
+ export type { AgentRun, CloseInfo, EventMap, FeedPosition, HeartbeatOptions, IncomingRequest, Latency, MessageSource, MigrateOptions, PresencePeer, QueueOptions, ReconnectOptions, RequestHandler, RequestOptions, RunPolicy, RunStatus, RunStorage, SendData, SendOptions, SendRate, Snapshot, StandardSchemaV1, Status, UrlSource, UseWebSocketOptions, UseWebSocketResult, UseWebSocketStreamOptions, UseWebSocketStreamResult, WebSocketClient, WebSocketFeeds, WebSocketFeedsOptions, WebSocketHandlers, WebSocketLatency, WebSocketLatencyOptions, WebSocketOptions, WebSocketPresence, WebSocketPresenceOptions, WebSocketRequests, WebSocketRequestsOptions, WebSocketResponder, WebSocketResponderOptions, WebSocketRuns, WebSocketRunsOptions, WebSocketSendRate, WebSocketSendRateOptions, WebSocketState, WebSocketStateOptions, WebSocketTopics, WebSocketTopicsOptions };
1107
1756
  //# sourceMappingURL=index.d.cts.map