@orpc/client 2.0.0-beta.40 → 2.0.0-beta.41

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 (29) hide show
  1. package/README.md +5 -5
  2. package/dist/adapters/fetch/index.d.mts +1 -1
  3. package/dist/adapters/fetch/index.d.ts +1 -1
  4. package/dist/adapters/fetch/index.mjs +5 -4
  5. package/dist/adapters/message-port/index.d.mts +1 -1
  6. package/dist/adapters/message-port/index.d.ts +1 -1
  7. package/dist/adapters/message-port/index.mjs +10 -5
  8. package/dist/adapters/standard/index.d.mts +2 -2
  9. package/dist/adapters/standard/index.d.ts +2 -2
  10. package/dist/adapters/standard/index.mjs +3 -3
  11. package/dist/adapters/websocket/index.d.mts +13 -3
  12. package/dist/adapters/websocket/index.d.ts +13 -3
  13. package/dist/adapters/websocket/index.mjs +34 -13
  14. package/dist/index.d.mts +3 -3
  15. package/dist/index.d.ts +3 -3
  16. package/dist/index.mjs +3 -3
  17. package/dist/plugins/index.d.mts +40 -0
  18. package/dist/plugins/index.d.ts +40 -0
  19. package/dist/plugins/index.mjs +301 -190
  20. package/dist/shared/{client.n8K9dFhY.d.mts → client.BPa_Mmuh.d.mts} +1 -1
  21. package/dist/shared/{client.n8K9dFhY.d.ts → client.BPa_Mmuh.d.ts} +1 -1
  22. package/dist/shared/{client.BWkR2vPU.d.mts → client.BjbdW5Rj.d.mts} +1 -1
  23. package/dist/shared/{client.VXsLhJtT.mjs → client.Bstqyaro.mjs} +1 -1
  24. package/dist/shared/{client.Dtv1JPkU.mjs → client.DD2eNne_.mjs} +1 -0
  25. package/dist/shared/{client.BnpRXnLi.d.ts → client.DiHfJmHK.d.ts} +1 -1
  26. package/dist/shared/{client.BYHnU_Z3.mjs → client.DpkGsZt-.mjs} +19 -2
  27. package/dist/shared/{client.BoXZCzuS.d.ts → client.Dw9_40WO.d.mts} +1 -0
  28. package/dist/shared/{client.BoXZCzuS.d.mts → client.Dw9_40WO.d.ts} +1 -0
  29. package/package.json +7 -5
package/README.md CHANGED
@@ -85,7 +85,7 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
85
85
 
86
86
  <table>
87
87
  <tr>
88
- <td width="2000"><a href="https://screenshotone.com/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener" title="The screenshot API for developers"><img src="https://avatars.githubusercontent.com/u/97035603?v=4" width="64" align="left" hspace="12" alt="ScreenshotOne.com"/><b>ScreenshotOne.com</b></a><br /><sub>The screenshot API for developers</sub></td>
88
+ <td width="2000"><a href="https://screenshotone.com/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="The screenshot API for developers"><img src="https://avatars.githubusercontent.com/u/97035603?v=4" width="64" align="left" hspace="12" alt="ScreenshotOne.com"/><b>ScreenshotOne.com</b></a><br /><sub>The screenshot API for developers</sub></td>
89
89
  </tr>
90
90
  <tr>
91
91
  <td width="2000"><a href="https://yuzu.health/careers?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="We&#39;re hiring NYC based engineers"><img src="https://avatars.githubusercontent.com/u/102488956?v=4" width="64" align="left" hspace="12" alt="Yuzu"/><b>Yuzu</b></a><br /><sub>We&#39;re hiring NYC based engineers</sub></td>
@@ -127,19 +127,18 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
127
127
  <td align="center"><a href="https://soymilk.party/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="あわわわとーにゅ"><img src="https://avatars.githubusercontent.com/u/17376330?u=de3353804be889f009f7e0a1582daf04d0ab292d&amp;v=4" width="139" alt="あわわわとーにゅ"/><br />あわわわとーにゅ</a></td>
128
128
  <td align="center"><a href="https://github.com/nicognaW?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="nk"><img src="https://avatars.githubusercontent.com/u/66731869?u=4699bda3a9092d3ec34fbd959450767bcc8b8b6d&amp;v=4" width="139" alt="nk"/><br />nk</a></td>
129
129
  <td align="center"><a href="https://supastarter.dev/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="supastarter"><img src="https://avatars.githubusercontent.com/u/110960143?v=4" width="139" alt="supastarter"/><br />supastarter</a></td>
130
- <td align="center"><a href="https://github.com/divmgl?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Dexter Miguel"><img src="https://avatars.githubusercontent.com/u/5452298?u=645993204be8696c085ecf0d228c3062efe2ed65&amp;v=4" width="139" alt="Dexter Miguel"/><br />Dexter Miguel</a></td>
131
130
  <td align="center"><a href="https://github.com/herrfugbaum?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="herrfugbaum"><img src="https://avatars.githubusercontent.com/u/12859776?u=644dc1666d0220bc0468eb0de3c56b919f635b16&amp;v=4" width="139" alt="herrfugbaum"/><br />herrfugbaum</a></td>
131
+ <td align="center"><a href="https://laststance.io/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Ryota Murakami"><img src="https://avatars.githubusercontent.com/u/5501268?u=599389e03340734325726ca3f8f423c021d47d7f&amp;v=4" width="139" alt="Ryota Murakami"/><br />Ryota Murakami</a></td>
132
132
  </tr>
133
133
  <tr>
134
- <td align="center"><a href="https://laststance.io/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Ryota Murakami"><img src="https://avatars.githubusercontent.com/u/5501268?u=599389e03340734325726ca3f8f423c021d47d7f&amp;v=4" width="139" alt="Ryota Murakami"/><br />Ryota Murakami</a></td>
135
134
  <td align="center"><a href="https://cra.mr/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="David Cramer"><img src="https://avatars.githubusercontent.com/u/23610?v=4" width="139" alt="David Cramer"/><br />David Cramer</a></td>
136
135
  <td align="center"><a href="https://valerii15298.github.io/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Valerii Petryniak"><img src="https://avatars.githubusercontent.com/u/44531564?u=88ac74d9bacd20401518441907acad21063cd397&amp;v=4" width="139" alt="Valerii Petryniak"/><br />Valerii Petryniak</a></td>
137
136
  <td align="center"><a href="https://letstri.dev/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Valerii Strilets"><img src="https://avatars.githubusercontent.com/u/13253748?u=c7b10399ccc8f8081e24db94ec32cd9858e86ac3&amp;v=4" width="139" alt="Valerii Strilets"/><br />Valerii Strilets</a></td>
138
137
  <td align="center"><a href="https://blacklight.sh/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Kyle Mistele"><img src="https://avatars.githubusercontent.com/u/18430555?u=3afebeb81de666e35aaac3ed46f14159d7603ffb&amp;v=4" width="139" alt="Kyle Mistele"/><br />Kyle Mistele</a></td>
139
138
  <td align="center"><a href="https://github.com/christ12938?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="christ12938"><img src="https://avatars.githubusercontent.com/u/25758598?v=4" width="139" alt="christ12938"/><br />christ12938</a></td>
139
+ <td align="center"><a href="https://github.com/Ryanjso?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Ryan Soderberg"><img src="https://avatars.githubusercontent.com/u/39172778?u=5ed913c31d57e7221b75784abcad48c7ebddde27&amp;v=4" width="139" alt="Ryan Soderberg"/><br />Ryan Soderberg</a></td>
140
140
  </tr>
141
141
  <tr>
142
- <td align="center"><a href="https://github.com/Ryanjso?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Ryan Soderberg"><img src="https://avatars.githubusercontent.com/u/39172778?u=5ed913c31d57e7221b75784abcad48c7ebddde27&amp;v=4" width="139" alt="Ryan Soderberg"/><br />Ryan Soderberg</a></td>
143
142
  <td align="center"><a href="https://github.com/itigoore01?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="shota"><img src="https://avatars.githubusercontent.com/u/11831107?u=c976a6dc7e055eb026304c46c99100ed22b0c8e0&amp;v=4" width="139" alt="shota"/><br />shota</a></td>
144
143
  <td align="center"><a href="https://github.com/ellis-driscoll?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Ellis Driscoll"><img src="https://avatars.githubusercontent.com/u/70685966?u=c5f95bc33b5991d9744abe00052542e4a2ed3cb9&amp;v=4" width="139" alt="Ellis Driscoll"/><br />Ellis Driscoll</a></td>
145
144
  <td align="center"><a href="https://github.com/hoangbn?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Hoang Nguyen"><img src="https://avatars.githubusercontent.com/u/38968280?u=c90084c6de65c56facabab7ba13a72a49ddbc3e4&amp;v=4" width="139" alt="Hoang Nguyen"/><br />Hoang Nguyen</a></td>
@@ -173,12 +172,13 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
173
172
  <td align="center"><a href="https://kellychan.im/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Kelly Peilin Chan"><img src="https://avatars.githubusercontent.com/u/520852?u=6b0f7105f694e7b5cacf410a3f04c7044b469dc8&amp;v=4" width="119" alt="Kelly Peilin Chan"/><br />Kelly Peilin Chan</a></td>
174
173
  <td align="center"><a href="https://guyariely.com/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Guy Ariely"><img src="https://avatars.githubusercontent.com/u/42813496?u=edb6b7f563bf28e160a290832e7da57c0506f8ca&amp;v=4" width="119" alt="Guy Ariely"/><br />Guy Ariely</a></td>
175
174
  <td align="center"><a href="https://paulsenon.com/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="PaulSenon"><img src="https://avatars.githubusercontent.com/u/19531087?u=6385741eb91d200b8c513ec6045482e301767ca6&amp;v=4" width="119" alt="PaulSenon"/><br />PaulSenon</a></td>
175
+ <td align="center"><a href="https://nakasyou.how/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Shotaro Nakamura"><img src="https://avatars.githubusercontent.com/u/79000684?u=f644df3f29f0e8677a90967115774564f1d9d6ab&amp;v=4" width="119" alt="Shotaro Nakamura"/><br />Shotaro Nakamura</a></td>
176
176
  <td align="center"><a href="https://piscis.dev/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Alex"><img src="https://avatars.githubusercontent.com/u/326163?u=b245f368bd940cf51d08c0b6bf55f8257f359437&amp;v=4" width="119" alt="Alex"/><br />Alex</a></td>
177
177
  <td align="center"><a href="https://opensource.gubanov.eu/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Andrey Gubanov"><img src="https://avatars.githubusercontent.com/u/1082083?u=c5f2daf7ebece498e85c83367bb37b4e10e2649d&amp;v=4" width="119" alt="Andrey Gubanov"/><br />Andrey Gubanov</a></td>
178
178
  </tr>
179
179
  </table>
180
180
 
181
- With thanks to [36 past sponsors](https://htmlpreview.github.io/?https://github.com/middleapi/static/blob/main/sponsors.svg) who helped get oRPC here.
181
+ With thanks to [38 past sponsors](https://orpc.dev/sponsors#past-sponsors) who helped get oRPC here.
182
182
 
183
183
  ## References
184
184
 
@@ -4,7 +4,7 @@ import { StandardRequest, StandardLazyResponse } from '@standard-server/core';
4
4
  import { ToFetchBodyOptions } from '@standard-server/fetch';
5
5
  import { StandardLinkTransport, StandardLink, StandardLinkOptions } from '../standard/index.mjs';
6
6
  import { RPCLinkCodecOptions } from '../standard/index.mjs';
7
- import '../../shared/client.n8K9dFhY.mjs';
7
+ import '../../shared/client.BPa_Mmuh.mjs';
8
8
 
9
9
  interface FetchLinkTransportOptions<T extends ClientContext> {
10
10
  /**
@@ -4,7 +4,7 @@ import { StandardRequest, StandardLazyResponse } from '@standard-server/core';
4
4
  import { ToFetchBodyOptions } from '@standard-server/fetch';
5
5
  import { StandardLinkTransport, StandardLink, StandardLinkOptions } from '../standard/index.js';
6
6
  import { RPCLinkCodecOptions } from '../standard/index.js';
7
- import '../../shared/client.n8K9dFhY.js';
7
+ import '../../shared/client.BPa_Mmuh.js';
8
8
 
9
9
  interface FetchLinkTransportOptions<T extends ClientContext> {
10
10
  /**
@@ -1,9 +1,9 @@
1
1
  import { value, once } from '@orpc/shared';
2
2
  import { toFetchBody, toFetchHeaders, toStandardLazyResponse } from '@standard-server/fetch';
3
- import { S as StandardLink, R as RPCLinkCodec } from '../../shared/client.VXsLhJtT.mjs';
3
+ import { S as StandardLink, R as RPCLinkCodec } from '../../shared/client.Bstqyaro.mjs';
4
4
  import '@standard-server/core';
5
- import '../../shared/client.BYHnU_Z3.mjs';
6
- import '../../shared/client.Dtv1JPkU.mjs';
5
+ import '../../shared/client.DpkGsZt-.mjs';
6
+ import '../../shared/client.DD2eNne_.mjs';
7
7
 
8
8
  const GET_SUPPORTED_DUPLEX_MODE = once(() => {
9
9
  try {
@@ -53,7 +53,8 @@ class FetchLinkTransport {
53
53
  init.duplex = duplex;
54
54
  }
55
55
  }
56
- const response = await this.fetch(url, init, options, path);
56
+ const fetch = this.fetch;
57
+ const response = await fetch(url, init, options, path);
57
58
  const standardResponse = toStandardLazyResponse(response);
58
59
  return standardResponse;
59
60
  }
@@ -4,7 +4,7 @@ import { StandardRequest, StandardLazyResponse } from '@standard-server/core';
4
4
  import { ClientPeer, EncodePeerMessageOptions, DecodePeerMessageOptions } from '@standard-server/peer';
5
5
  import { StandardLinkTransport, StandardLink, StandardLinkOptions } from '../standard/index.mjs';
6
6
  import { RPCLinkCodecOptions } from '../standard/index.mjs';
7
- import '../../shared/client.n8K9dFhY.mjs';
7
+ import '../../shared/client.BPa_Mmuh.mjs';
8
8
 
9
9
  /**
10
10
  * The message port used by electron in main process
@@ -4,7 +4,7 @@ import { StandardRequest, StandardLazyResponse } from '@standard-server/core';
4
4
  import { ClientPeer, EncodePeerMessageOptions, DecodePeerMessageOptions } from '@standard-server/peer';
5
5
  import { StandardLinkTransport, StandardLink, StandardLinkOptions } from '../standard/index.js';
6
6
  import { RPCLinkCodecOptions } from '../standard/index.js';
7
- import '../../shared/client.n8K9dFhY.js';
7
+ import '../../shared/client.BPa_Mmuh.js';
8
8
 
9
9
  /**
10
10
  * The message port used by electron in main process
@@ -1,10 +1,10 @@
1
- import { value } from '@orpc/shared';
1
+ import { value, AbortError } from '@orpc/shared';
2
2
  import { ClientPeer, encodePeerMessage, decodePeerMessage, isServerPeerSendMessage, isPeerMessage } from '@standard-server/peer';
3
- import { S as StandardLink, R as RPCLinkCodec } from '../../shared/client.VXsLhJtT.mjs';
3
+ import { S as StandardLink, R as RPCLinkCodec } from '../../shared/client.Bstqyaro.mjs';
4
4
  import '@standard-server/core';
5
5
  import '@standard-server/fetch';
6
- import '../../shared/client.BYHnU_Z3.mjs';
7
- import '../../shared/client.Dtv1JPkU.mjs';
6
+ import '../../shared/client.DpkGsZt-.mjs';
7
+ import '../../shared/client.DD2eNne_.mjs';
8
8
 
9
9
  function postMessagePortMessage(port, data, transfer) {
10
10
  if (transfer) {
@@ -51,7 +51,11 @@ function onMessagePortClose(port, callback) {
51
51
  class MessagePortLinkTransport {
52
52
  peer;
53
53
  constructor({ port, experimental_transfer, encodePeerMessage: encodePeerMessageOptions, decodePeerMessage: decodePeerMessageOptions }) {
54
+ let closeReason;
54
55
  this.peer = new ClientPeer(async (message) => {
56
+ if (closeReason) {
57
+ throw closeReason;
58
+ }
55
59
  const transfer = await value(experimental_transfer, message, port);
56
60
  if (transfer) {
57
61
  postMessagePortMessage(port, message, transfer);
@@ -76,7 +80,8 @@ class MessagePortLinkTransport {
76
80
  return { matched: true };
77
81
  });
78
82
  onMessagePortClose(port, async () => {
79
- await this.peer.close();
83
+ closeReason = new AbortError("MessagePort closed");
84
+ await this.peer.close(closeReason);
80
85
  });
81
86
  }
82
87
  async send(standardRequest, _path, _options) {
@@ -1,5 +1,5 @@
1
- import { f as StandardLinkCodec, g as StandardLinkCodecDecodedResponse } from '../../shared/client.BWkR2vPU.mjs';
2
- export { C as CompositeStandardLinkPlugin, a as StandardLink, h as StandardLinkInterceptor, e as StandardLinkInterceptorOptions, b as StandardLinkOptions, c as StandardLinkPlugin, S as StandardLinkTransport, i as StandardLinkTransportInterceptor, d as StandardLinkTransportInterceptorOptions } from '../../shared/client.BWkR2vPU.mjs';
1
+ import { f as StandardLinkCodec, g as StandardLinkCodecDecodedResponse } from '../../shared/client.BjbdW5Rj.mjs';
2
+ export { C as CompositeStandardLinkPlugin, a as StandardLink, h as StandardLinkInterceptor, e as StandardLinkInterceptorOptions, b as StandardLinkOptions, c as StandardLinkPlugin, S as StandardLinkTransport, i as StandardLinkTransportInterceptor, d as StandardLinkTransportInterceptorOptions } from '../../shared/client.BjbdW5Rj.mjs';
3
3
  import { Value, Promisable, Public } from '@orpc/shared';
4
4
  import { StandardUrl, StandardHeaders, StandardRequest, StandardLazyResponse } from '@standard-server/core';
5
5
  import { ClientContext, ClientOptions } from '../../index.mjs';
@@ -1,5 +1,5 @@
1
- import { f as StandardLinkCodec, g as StandardLinkCodecDecodedResponse } from '../../shared/client.BnpRXnLi.js';
2
- export { C as CompositeStandardLinkPlugin, a as StandardLink, h as StandardLinkInterceptor, e as StandardLinkInterceptorOptions, b as StandardLinkOptions, c as StandardLinkPlugin, S as StandardLinkTransport, i as StandardLinkTransportInterceptor, d as StandardLinkTransportInterceptorOptions } from '../../shared/client.BnpRXnLi.js';
1
+ import { f as StandardLinkCodec, g as StandardLinkCodecDecodedResponse } from '../../shared/client.DiHfJmHK.js';
2
+ export { C as CompositeStandardLinkPlugin, a as StandardLink, h as StandardLinkInterceptor, e as StandardLinkInterceptorOptions, b as StandardLinkOptions, c as StandardLinkPlugin, S as StandardLinkTransport, i as StandardLinkTransportInterceptor, d as StandardLinkTransportInterceptorOptions } from '../../shared/client.DiHfJmHK.js';
3
3
  import { Value, Promisable, Public } from '@orpc/shared';
4
4
  import { StandardUrl, StandardHeaders, StandardRequest, StandardLazyResponse } from '@standard-server/core';
5
5
  import { ClientContext, ClientOptions } from '../../index.js';
@@ -1,6 +1,6 @@
1
- export { C as CompositeStandardLinkPlugin, R as RPCLinkCodec, S as StandardLink } from '../../shared/client.VXsLhJtT.mjs';
1
+ export { C as CompositeStandardLinkPlugin, R as RPCLinkCodec, S as StandardLink } from '../../shared/client.Bstqyaro.mjs';
2
2
  import '@orpc/shared';
3
3
  import '@standard-server/core';
4
4
  import '@standard-server/fetch';
5
- import '../../shared/client.BYHnU_Z3.mjs';
6
- import '../../shared/client.Dtv1JPkU.mjs';
5
+ import '../../shared/client.DpkGsZt-.mjs';
6
+ import '../../shared/client.DD2eNne_.mjs';
@@ -4,7 +4,7 @@ import { StandardRequest, StandardLazyResponse } from '@standard-server/core';
4
4
  import { EncodePeerMessageOptions, DecodePeerMessageOptions } from '@standard-server/peer';
5
5
  import { StandardLinkTransport, StandardLink, StandardLinkOptions } from '../standard/index.mjs';
6
6
  import { RPCLinkCodecOptions } from '../standard/index.mjs';
7
- import '../../shared/client.n8K9dFhY.mjs';
7
+ import '../../shared/client.BPa_Mmuh.mjs';
8
8
 
9
9
  type WebSocketLike = Pick<WebSocket, 'addEventListener' | 'removeEventListener' | 'send' | 'readyState'>;
10
10
  interface WebSocketLinkTransportAttemptInfo {
@@ -17,7 +17,7 @@ interface WebSocketLinkTransportAttemptInfo {
17
17
  /**
18
18
  * Attempt number within the current (re)connect cycle.
19
19
  * Starts at 1, increments on each consecutive failure, and resets to 1
20
- * once a connection succeeds. Use this for backoff calculations.
20
+ * once a connection succeeds or the cycle gives up. Use this for backoff calculations.
21
21
  */
22
22
  attempt: number;
23
23
  }
@@ -36,12 +36,21 @@ interface WebSocketLinkTransportReconnectOptions {
36
36
  delay?: undefined | ((info: WebSocketLinkTransportAttemptInfo) => number);
37
37
  /**
38
38
  * Maximum number of consecutive failed attempts before giving up.
39
- * When exceeded, `getConnectedPeer` throws instead of retrying.
39
+ * When reached, calls waiting for the connection fail, and the next
40
+ * call starts a new reconnect cycle.
40
41
  * Should greater than 1
41
42
  *
42
43
  * @default Infinity
43
44
  */
44
45
  maxAttempt?: undefined | number;
46
+ /**
47
+ * Maximum number of connection attempts over the transport's lifetime,
48
+ * successful ones included (see `totalAttempt`).
49
+ * When reached, calls that need a new connection fail instead of connecting.
50
+ *
51
+ * @default Infinity
52
+ */
53
+ maxTotalAttempt?: undefined | number;
45
54
  /**
46
55
  * Whether to proactively reconnect right after the socket closes,
47
56
  * rather than waiting for the next call to trigger reconnection.
@@ -99,6 +108,7 @@ declare class WebSocketLinkTransport<T extends ClientContext> implements Standar
99
108
  private readonly reconnectEnabled;
100
109
  private readonly reconnectDelay;
101
110
  private readonly reconnectMaxAttempt;
111
+ private readonly reconnectMaxTotalAttempt;
102
112
  private readonly reconnectOnCloseEnabled;
103
113
  private readonly reconnectOnCloseDelay;
104
114
  private readonly encodePeerMessageOptions;
@@ -4,7 +4,7 @@ import { StandardRequest, StandardLazyResponse } from '@standard-server/core';
4
4
  import { EncodePeerMessageOptions, DecodePeerMessageOptions } from '@standard-server/peer';
5
5
  import { StandardLinkTransport, StandardLink, StandardLinkOptions } from '../standard/index.js';
6
6
  import { RPCLinkCodecOptions } from '../standard/index.js';
7
- import '../../shared/client.n8K9dFhY.js';
7
+ import '../../shared/client.BPa_Mmuh.js';
8
8
 
9
9
  type WebSocketLike = Pick<WebSocket, 'addEventListener' | 'removeEventListener' | 'send' | 'readyState'>;
10
10
  interface WebSocketLinkTransportAttemptInfo {
@@ -17,7 +17,7 @@ interface WebSocketLinkTransportAttemptInfo {
17
17
  /**
18
18
  * Attempt number within the current (re)connect cycle.
19
19
  * Starts at 1, increments on each consecutive failure, and resets to 1
20
- * once a connection succeeds. Use this for backoff calculations.
20
+ * once a connection succeeds or the cycle gives up. Use this for backoff calculations.
21
21
  */
22
22
  attempt: number;
23
23
  }
@@ -36,12 +36,21 @@ interface WebSocketLinkTransportReconnectOptions {
36
36
  delay?: undefined | ((info: WebSocketLinkTransportAttemptInfo) => number);
37
37
  /**
38
38
  * Maximum number of consecutive failed attempts before giving up.
39
- * When exceeded, `getConnectedPeer` throws instead of retrying.
39
+ * When reached, calls waiting for the connection fail, and the next
40
+ * call starts a new reconnect cycle.
40
41
  * Should greater than 1
41
42
  *
42
43
  * @default Infinity
43
44
  */
44
45
  maxAttempt?: undefined | number;
46
+ /**
47
+ * Maximum number of connection attempts over the transport's lifetime,
48
+ * successful ones included (see `totalAttempt`).
49
+ * When reached, calls that need a new connection fail instead of connecting.
50
+ *
51
+ * @default Infinity
52
+ */
53
+ maxTotalAttempt?: undefined | number;
45
54
  /**
46
55
  * Whether to proactively reconnect right after the socket closes,
47
56
  * rather than waiting for the next call to trigger reconnection.
@@ -99,6 +108,7 @@ declare class WebSocketLinkTransport<T extends ClientContext> implements Standar
99
108
  private readonly reconnectEnabled;
100
109
  private readonly reconnectDelay;
101
110
  private readonly reconnectMaxAttempt;
111
+ private readonly reconnectMaxTotalAttempt;
102
112
  private readonly reconnectOnCloseEnabled;
103
113
  private readonly reconnectOnCloseDelay;
104
114
  private readonly encodePeerMessageOptions;
@@ -1,10 +1,10 @@
1
1
  import { runWithSignal, AbortError, sleep, promiseWithResolvers, sequential, loadBytes, toStringOrBytes } from '@orpc/shared';
2
2
  import { ClientPeer, encodePeerMessage, decodePeerMessage, isServerPeerSendMessage } from '@standard-server/peer';
3
- import { S as StandardLink, R as RPCLinkCodec } from '../../shared/client.VXsLhJtT.mjs';
3
+ import { S as StandardLink, R as RPCLinkCodec } from '../../shared/client.Bstqyaro.mjs';
4
4
  import '@standard-server/core';
5
5
  import '@standard-server/fetch';
6
- import '../../shared/client.BYHnU_Z3.mjs';
7
- import '../../shared/client.Dtv1JPkU.mjs';
6
+ import '../../shared/client.DpkGsZt-.mjs';
7
+ import '../../shared/client.DD2eNne_.mjs';
8
8
 
9
9
  const WEBSOCKET_CONNECTING = 0;
10
10
  const WEBSOCKET_OPEN = 1;
@@ -13,6 +13,7 @@ class WebSocketLinkTransport {
13
13
  reconnectEnabled;
14
14
  reconnectDelay;
15
15
  reconnectMaxAttempt;
16
+ reconnectMaxTotalAttempt;
16
17
  reconnectOnCloseEnabled;
17
18
  reconnectOnCloseDelay;
18
19
  encodePeerMessageOptions;
@@ -22,6 +23,7 @@ class WebSocketLinkTransport {
22
23
  this.reconnectEnabled = options.reconnect?.enabled ?? false;
23
24
  this.reconnectDelay = options.reconnect?.delay ?? ((info) => info.attempt === 1 ? 0 : 2e3);
24
25
  this.reconnectMaxAttempt = options.reconnect?.maxAttempt ?? Infinity;
26
+ this.reconnectMaxTotalAttempt = options.reconnect?.maxTotalAttempt ?? Infinity;
25
27
  this.reconnectOnCloseEnabled = this.reconnectEnabled && (options.reconnect?.onClose?.enabled ?? false);
26
28
  this.reconnectOnCloseDelay = options.reconnect?.onClose?.delay ?? 0;
27
29
  this.encodePeerMessageOptions = options.encodePeerMessage;
@@ -45,14 +47,13 @@ class WebSocketLinkTransport {
45
47
  const current = this.current;
46
48
  const resolved = await current;
47
49
  if (resolved && (!this.reconnectEnabled || resolved.websocket.readyState === WEBSOCKET_OPEN)) {
48
- this.attempt = 0;
49
50
  return resolved.peer;
50
51
  }
51
52
  if (current !== this.current) {
52
53
  return this.getConnectedPeer();
53
54
  }
54
- if (this.attempt >= this.reconnectMaxAttempt) {
55
- throw new AbortError(`WebSocket reconnect failed after ${this.attempt} attempt(s)`);
55
+ if (this.totalAttempt >= this.reconnectMaxTotalAttempt) {
56
+ throw new AbortError(`WebSocket reconnect stopped after ${this.totalAttempt} total attempt(s)`);
56
57
  }
57
58
  this.current = (async () => {
58
59
  this.totalAttempt += 1;
@@ -60,7 +61,14 @@ class WebSocketLinkTransport {
60
61
  const info = { totalAttempt: this.totalAttempt, attempt: this.attempt };
61
62
  await sleep(this.reconnectDelay(info));
62
63
  const websocket = await this.connect(info);
64
+ if (websocket.readyState !== WEBSOCKET_CONNECTING && websocket.readyState !== WEBSOCKET_OPEN) {
65
+ throw new AbortError("WebSocket is already closing or closed");
66
+ }
67
+ let closeReason;
63
68
  const peer = new ClientPeer(async (message) => {
69
+ if (closeReason) {
70
+ throw closeReason;
71
+ }
64
72
  const encoded = await encodePeerMessage(message, this.encodePeerMessageOptions);
65
73
  return websocket.send(encoded);
66
74
  });
@@ -79,21 +87,34 @@ class WebSocketLinkTransport {
79
87
  }
80
88
  }));
81
89
  websocket.addEventListener("close", async (event) => {
90
+ closeReason = new AbortError(`WebSocket closed (code ${event.code}: ${event.reason})`);
82
91
  connectingResolvers?.resolve();
83
- if (this.reconnectOnCloseEnabled) {
84
- sleep(this.reconnectOnCloseDelay).then(() => this.getConnectedPeer()).catch(() => {
85
- });
86
- }
87
- const reason = new AbortError(`WebSocket closed (code ${event.code}: ${event.reason})`);
88
- await peer.close(reason);
92
+ await peer.close(closeReason);
93
+ });
94
+ websocket.addEventListener("error", () => {
89
95
  });
90
96
  await connectingResolvers?.promise;
91
- connectingResolvers = void 0;
97
+ if (closeReason) {
98
+ throw closeReason;
99
+ }
100
+ if (this.reconnectOnCloseEnabled) {
101
+ websocket.addEventListener("close", () => {
102
+ sleep(this.reconnectOnCloseDelay).then(() => this.getConnectedPeer()).catch(() => {
103
+ });
104
+ });
105
+ }
106
+ this.attempt = 0;
92
107
  return { websocket, peer };
93
108
  })().catch((error) => {
94
109
  if (!this.reconnectEnabled) {
95
110
  throw error;
96
111
  }
112
+ if (this.attempt >= this.reconnectMaxAttempt) {
113
+ const attempt = this.attempt;
114
+ this.attempt = 0;
115
+ this.current = void 0;
116
+ throw new AbortError(`WebSocket reconnect failed after ${attempt} attempt(s)`, { cause: error });
117
+ }
97
118
  });
98
119
  return this.getConnectedPeer();
99
120
  }
package/dist/index.d.mts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { WrapAsyncIteratorOptions, AsyncIteratorClass, Interceptor, PromiseWithError, ThrowableError, Promisable } from '@orpc/shared';
2
2
  export { AsyncCleanupFn, AsyncIteratorClass, AsyncIteratorClassNextFn, PromiseWithError as ClientPromiseResult, MaybeOptionalOptions, PromiseWithError, Registry, ThrowableError, asyncIteratorToStream, asyncIteratorToUnproxiedDataStream, consumeAsyncIterator, consumeAsyncIterator as consumeEventIterator, asyncIteratorToStream as eventIteratorToStream, asyncIteratorToUnproxiedDataStream as eventIteratorToUnproxiedDataStream, onAsyncIteratorObjectError, onError, onFinish, onReadableStreamError, onStart, onSuccess, streamToAsyncIteratorObject, streamToAsyncIteratorObject as streamToEventIterator } from '@orpc/shared';
3
- import { C as ClientContext, a as ClientOptions, c as AnyNestedClient, I as InferClientContext, d as InferClientError, e as Client, b as ClientLink, A as AnyORPCError, f as ClientRest, F as FriendlyClientOptions, O as ORPCErrorCode, g as ORPCErrorJSON, h as ORPCError, M as MalformedResponseErrorOptions } from './shared/client.BoXZCzuS.mjs';
4
- export { i as AnyORPCErrorJSON, j as COMMON_ERROR_STATUS_MAP, k as InferClientBodyInputs, l as InferClientBodyOutputs, m as InferClientErrors, n as InferClientInputs, o as InferClientOutputs, p as MalformedResponseError, N as NestedClient, q as ORPCErrorOptions } from './shared/client.BoXZCzuS.mjs';
3
+ import { C as ClientContext, a as ClientOptions, c as AnyNestedClient, I as InferClientContext, d as InferClientError, e as Client, b as ClientLink, A as AnyORPCError, f as ClientRest, F as FriendlyClientOptions, O as ORPCErrorCode, g as ORPCErrorJSON, h as ORPCError, M as MalformedResponseErrorOptions } from './shared/client.Dw9_40WO.mjs';
4
+ export { i as AnyORPCErrorJSON, j as COMMON_ERROR_STATUS_MAP, k as InferClientBodyInputs, l as InferClientBodyOutputs, m as InferClientErrors, n as InferClientInputs, o as InferClientOutputs, p as MalformedResponseError, N as NestedClient, q as ORPCErrorOptions } from './shared/client.Dw9_40WO.mjs';
5
5
  import { StandardResponse } from '@standard-server/core';
6
6
  export { ErrorEvent, EventMeta, StandardBody, StandardBodyHint, StandardHeaders, StandardLazyRequest, StandardLazyResponse, StandardMethod, StandardRequest, StandardResponse, StandardUrl, getEventMeta, unwrapEvent, withEventMeta } from '@standard-server/core';
7
- export { R as RPCJsonSerialization, a as RPCJsonSerializationMeta, b as RPCJsonSerializer, c as RPCJsonSerializerHandler, d as RPCJsonSerializerOptions, e as RPCSerializer, f as RPCSerializerOptions, g as RPCSerializerSerializeOptions } from './shared/client.n8K9dFhY.mjs';
7
+ export { R as RPCJsonSerialization, a as RPCJsonSerializationMeta, b as RPCJsonSerializer, c as RPCJsonSerializerHandler, d as RPCJsonSerializerOptions, e as RPCSerializer, f as RPCSerializerOptions, g as RPCSerializerSerializeOptions } from './shared/client.BPa_Mmuh.mjs';
8
8
 
9
9
  declare function wrapAsyncIteratorPreservingEventMeta<TYield, TReturn, TMappedYield = TYield, TMappedReturn = TReturn>(iterator: AsyncIterator<TYield, TReturn>, { mapResult, mapError, ...rest }: WrapAsyncIteratorOptions<TYield, TReturn, TMappedYield, TMappedReturn>): AsyncIteratorClass<TMappedYield, TMappedReturn>;
10
10
 
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { WrapAsyncIteratorOptions, AsyncIteratorClass, Interceptor, PromiseWithError, ThrowableError, Promisable } from '@orpc/shared';
2
2
  export { AsyncCleanupFn, AsyncIteratorClass, AsyncIteratorClassNextFn, PromiseWithError as ClientPromiseResult, MaybeOptionalOptions, PromiseWithError, Registry, ThrowableError, asyncIteratorToStream, asyncIteratorToUnproxiedDataStream, consumeAsyncIterator, consumeAsyncIterator as consumeEventIterator, asyncIteratorToStream as eventIteratorToStream, asyncIteratorToUnproxiedDataStream as eventIteratorToUnproxiedDataStream, onAsyncIteratorObjectError, onError, onFinish, onReadableStreamError, onStart, onSuccess, streamToAsyncIteratorObject, streamToAsyncIteratorObject as streamToEventIterator } from '@orpc/shared';
3
- import { C as ClientContext, a as ClientOptions, c as AnyNestedClient, I as InferClientContext, d as InferClientError, e as Client, b as ClientLink, A as AnyORPCError, f as ClientRest, F as FriendlyClientOptions, O as ORPCErrorCode, g as ORPCErrorJSON, h as ORPCError, M as MalformedResponseErrorOptions } from './shared/client.BoXZCzuS.js';
4
- export { i as AnyORPCErrorJSON, j as COMMON_ERROR_STATUS_MAP, k as InferClientBodyInputs, l as InferClientBodyOutputs, m as InferClientErrors, n as InferClientInputs, o as InferClientOutputs, p as MalformedResponseError, N as NestedClient, q as ORPCErrorOptions } from './shared/client.BoXZCzuS.js';
3
+ import { C as ClientContext, a as ClientOptions, c as AnyNestedClient, I as InferClientContext, d as InferClientError, e as Client, b as ClientLink, A as AnyORPCError, f as ClientRest, F as FriendlyClientOptions, O as ORPCErrorCode, g as ORPCErrorJSON, h as ORPCError, M as MalformedResponseErrorOptions } from './shared/client.Dw9_40WO.js';
4
+ export { i as AnyORPCErrorJSON, j as COMMON_ERROR_STATUS_MAP, k as InferClientBodyInputs, l as InferClientBodyOutputs, m as InferClientErrors, n as InferClientInputs, o as InferClientOutputs, p as MalformedResponseError, N as NestedClient, q as ORPCErrorOptions } from './shared/client.Dw9_40WO.js';
5
5
  import { StandardResponse } from '@standard-server/core';
6
6
  export { ErrorEvent, EventMeta, StandardBody, StandardBodyHint, StandardHeaders, StandardLazyRequest, StandardLazyResponse, StandardMethod, StandardRequest, StandardResponse, StandardUrl, getEventMeta, unwrapEvent, withEventMeta } from '@standard-server/core';
7
- export { R as RPCJsonSerialization, a as RPCJsonSerializationMeta, b as RPCJsonSerializer, c as RPCJsonSerializerHandler, d as RPCJsonSerializerOptions, e as RPCSerializer, f as RPCSerializerOptions, g as RPCSerializerSerializeOptions } from './shared/client.n8K9dFhY.js';
7
+ export { R as RPCJsonSerialization, a as RPCJsonSerializationMeta, b as RPCJsonSerializer, c as RPCJsonSerializerHandler, d as RPCJsonSerializerOptions, e as RPCSerializer, f as RPCSerializerOptions, g as RPCSerializerSerializeOptions } from './shared/client.BPa_Mmuh.js';
8
8
 
9
9
  declare function wrapAsyncIteratorPreservingEventMeta<TYield, TReturn, TMappedYield = TYield, TMappedReturn = TReturn>(iterator: AsyncIterator<TYield, TReturn>, { mapResult, mapError, ...rest }: WrapAsyncIteratorOptions<TYield, TReturn, TMappedYield, TMappedReturn>): AsyncIteratorClass<TMappedYield, TMappedReturn>;
10
10
 
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import { b as isDefinedError } from './shared/client.BYHnU_Z3.mjs';
2
- export { d as RPCJsonSerializer, R as RPCSerializer, e as cloneORPCError, a as createORPCErrorFromJson, c as createORPCErrorFromMalformedResponse, i as isORPCErrorJson, t as toORPCError, w as wrapAsyncIteratorPreservingEventMeta } from './shared/client.BYHnU_Z3.mjs';
1
+ import { b as isDefinedError } from './shared/client.DpkGsZt-.mjs';
2
+ export { d as RPCJsonSerializer, R as RPCSerializer, e as cloneORPCError, a as createORPCErrorFromJson, c as createORPCErrorFromMalformedResponse, i as isORPCErrorJson, t as toORPCError, w as wrapAsyncIteratorPreservingEventMeta } from './shared/client.DpkGsZt-.mjs';
3
3
  import { toArray, intercept, isTypescriptObject } from '@orpc/shared';
4
4
  export { AsyncIteratorClass, asyncIteratorToStream, asyncIteratorToUnproxiedDataStream, consumeAsyncIterator, consumeAsyncIterator as consumeEventIterator, asyncIteratorToStream as eventIteratorToStream, asyncIteratorToUnproxiedDataStream as eventIteratorToUnproxiedDataStream, onAsyncIteratorObjectError, onError, onFinish, onReadableStreamError, onStart, onSuccess, streamToAsyncIteratorObject, streamToAsyncIteratorObject as streamToEventIterator } from '@orpc/shared';
5
- export { C as COMMON_ERROR_STATUS_MAP, M as MalformedResponseError, O as ORPCError } from './shared/client.Dtv1JPkU.mjs';
5
+ export { C as COMMON_ERROR_STATUS_MAP, M as MalformedResponseError, O as ORPCError } from './shared/client.DD2eNne_.mjs';
6
6
  export { ErrorEvent, getEventMeta, unwrapEvent, withEventMeta } from '@standard-server/core';
7
7
 
8
8
  const RECURSIVE_CLIENT_UNWRAP_KEYS = /* @__PURE__ */ new Set([
@@ -31,12 +31,27 @@ interface BatchLinkPluginOptions<T extends ClientContext> {
31
31
  * @default () => true
32
32
  */
33
33
  filter?: Value<boolean, [options: StandardLinkTransportInterceptorOptions<T>]>;
34
+ /**
35
+ * Only requests with the same scope are batched together.
36
+ * On the server, return a value unique to the incoming request so different users never share a batch.
37
+ *
38
+ * @default () => undefined
39
+ */
40
+ scope?: (options: StandardLinkTransportInterceptorOptions<T>) => unknown;
34
41
  /**
35
42
  * The maximum number of requests in the batch.
36
43
  *
37
44
  * @default 10
38
45
  */
39
46
  maxSize?: Value<Promisable<number>, [subOptionsList: [StandardLinkTransportInterceptorOptions<T>, ...StandardLinkTransportInterceptorOptions<T>[]]]>;
47
+ /**
48
+ * How long (in ms) to wait for more requests before sending the batch,
49
+ * counted from the first queued request.
50
+ * With `0`, only requests made in the same event loop tick are batched.
51
+ *
52
+ * @default 0
53
+ */
54
+ wait?: number;
40
55
  /**
41
56
  * The batch response mode.
42
57
  *
@@ -90,7 +105,9 @@ declare class BatchLinkPlugin<T extends ClientContext> implements StandardLinkPl
90
105
  name: string;
91
106
  private readonly groups;
92
107
  private readonly filter;
108
+ private readonly scope;
93
109
  private readonly maxSize;
110
+ private readonly wait;
94
111
  private readonly mode;
95
112
  private readonly batchUrl;
96
113
  private readonly maxUrlLength;
@@ -101,6 +118,12 @@ declare class BatchLinkPlugin<T extends ClientContext> implements StandardLinkPl
101
118
  constructor(options: NoInfer<BatchLinkPluginOptions<T>>);
102
119
  init(options: StandardLinkOptions<T>): StandardLinkOptions<T>;
103
120
  private processPendingBatches;
121
+ /**
122
+ * Runs the batch in the async context of its first request instead of the timer's,
123
+ * so the transport and batch options see that caller's request state.
124
+ * `executeBatch` always runs in the context of its first request.
125
+ */
126
+ private executeBatchInOwnContext;
104
127
  private executeBatch;
105
128
  }
106
129
 
@@ -129,6 +152,21 @@ interface DedupeLinkPluginOptions<T extends ClientContext> {
129
152
  * @default ({ request }) => request.method === 'GET' || request.method === 'QUERY'
130
153
  */
131
154
  filter?: Value<boolean, [options: StandardLinkTransportInterceptorOptions<T>]>;
155
+ /**
156
+ * Only requests with the same scope are deduplicated together.
157
+ * On the server, return a value unique to the incoming request so different users never share a response.
158
+ *
159
+ * @default () => undefined
160
+ */
161
+ scope?: (options: StandardLinkTransportInterceptorOptions<T>) => unknown;
162
+ /**
163
+ * How long (in ms) to wait for more identical requests before sending,
164
+ * counted from the first queued request.
165
+ * With `0`, only requests made in the same event loop tick are deduplicated.
166
+ *
167
+ * @default 0
168
+ */
169
+ wait?: number;
132
170
  }
133
171
  /**
134
172
  * Prevents redundant requests by deduplicating similar in-flight requests,
@@ -141,6 +179,8 @@ declare class DedupeLinkPlugin<T extends ClientContext> implements StandardLinkP
141
179
  before: string[];
142
180
  private readonly groups;
143
181
  private readonly filter;
182
+ private readonly scope;
183
+ private readonly wait;
144
184
  private readonly queue;
145
185
  constructor(options: NoInfer<DedupeLinkPluginOptions<T>>);
146
186
  init(options: StandardLinkOptions<T>): StandardLinkOptions<T>;
@@ -31,12 +31,27 @@ interface BatchLinkPluginOptions<T extends ClientContext> {
31
31
  * @default () => true
32
32
  */
33
33
  filter?: Value<boolean, [options: StandardLinkTransportInterceptorOptions<T>]>;
34
+ /**
35
+ * Only requests with the same scope are batched together.
36
+ * On the server, return a value unique to the incoming request so different users never share a batch.
37
+ *
38
+ * @default () => undefined
39
+ */
40
+ scope?: (options: StandardLinkTransportInterceptorOptions<T>) => unknown;
34
41
  /**
35
42
  * The maximum number of requests in the batch.
36
43
  *
37
44
  * @default 10
38
45
  */
39
46
  maxSize?: Value<Promisable<number>, [subOptionsList: [StandardLinkTransportInterceptorOptions<T>, ...StandardLinkTransportInterceptorOptions<T>[]]]>;
47
+ /**
48
+ * How long (in ms) to wait for more requests before sending the batch,
49
+ * counted from the first queued request.
50
+ * With `0`, only requests made in the same event loop tick are batched.
51
+ *
52
+ * @default 0
53
+ */
54
+ wait?: number;
40
55
  /**
41
56
  * The batch response mode.
42
57
  *
@@ -90,7 +105,9 @@ declare class BatchLinkPlugin<T extends ClientContext> implements StandardLinkPl
90
105
  name: string;
91
106
  private readonly groups;
92
107
  private readonly filter;
108
+ private readonly scope;
93
109
  private readonly maxSize;
110
+ private readonly wait;
94
111
  private readonly mode;
95
112
  private readonly batchUrl;
96
113
  private readonly maxUrlLength;
@@ -101,6 +118,12 @@ declare class BatchLinkPlugin<T extends ClientContext> implements StandardLinkPl
101
118
  constructor(options: NoInfer<BatchLinkPluginOptions<T>>);
102
119
  init(options: StandardLinkOptions<T>): StandardLinkOptions<T>;
103
120
  private processPendingBatches;
121
+ /**
122
+ * Runs the batch in the async context of its first request instead of the timer's,
123
+ * so the transport and batch options see that caller's request state.
124
+ * `executeBatch` always runs in the context of its first request.
125
+ */
126
+ private executeBatchInOwnContext;
104
127
  private executeBatch;
105
128
  }
106
129
 
@@ -129,6 +152,21 @@ interface DedupeLinkPluginOptions<T extends ClientContext> {
129
152
  * @default ({ request }) => request.method === 'GET' || request.method === 'QUERY'
130
153
  */
131
154
  filter?: Value<boolean, [options: StandardLinkTransportInterceptorOptions<T>]>;
155
+ /**
156
+ * Only requests with the same scope are deduplicated together.
157
+ * On the server, return a value unique to the incoming request so different users never share a response.
158
+ *
159
+ * @default () => undefined
160
+ */
161
+ scope?: (options: StandardLinkTransportInterceptorOptions<T>) => unknown;
162
+ /**
163
+ * How long (in ms) to wait for more identical requests before sending,
164
+ * counted from the first queued request.
165
+ * With `0`, only requests made in the same event loop tick are deduplicated.
166
+ *
167
+ * @default 0
168
+ */
169
+ wait?: number;
132
170
  }
133
171
  /**
134
172
  * Prevents redundant requests by deduplicating similar in-flight requests,
@@ -141,6 +179,8 @@ declare class DedupeLinkPlugin<T extends ClientContext> implements StandardLinkP
141
179
  before: string[];
142
180
  private readonly groups;
143
181
  private readonly filter;
182
+ private readonly scope;
183
+ private readonly wait;
144
184
  private readonly queue;
145
185
  constructor(options: NoInfer<DedupeLinkPluginOptions<T>>);
146
186
  init(options: StandardLinkOptions<T>): StandardLinkOptions<T>;