@orpc/client 2.0.0-beta.43 → 2.0.0-beta.45

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 +56 -57
  2. package/dist/adapters/fetch/index.d.mts +3 -3
  3. package/dist/adapters/fetch/index.d.ts +3 -3
  4. package/dist/adapters/fetch/index.mjs +9 -3
  5. package/dist/adapters/message-port/index.d.mts +2 -2
  6. package/dist/adapters/message-port/index.d.ts +2 -2
  7. package/dist/adapters/message-port/index.mjs +3 -3
  8. package/dist/adapters/standard/index.d.mts +8 -8
  9. package/dist/adapters/standard/index.d.ts +8 -8
  10. package/dist/adapters/standard/index.mjs +3 -3
  11. package/dist/adapters/websocket/index.d.mts +9 -9
  12. package/dist/adapters/websocket/index.d.ts +9 -9
  13. package/dist/adapters/websocket/index.mjs +3 -3
  14. package/dist/index.d.mts +9 -20
  15. package/dist/index.d.ts +9 -20
  16. package/dist/index.mjs +3 -3
  17. package/dist/plugins/index.d.mts +51 -37
  18. package/dist/plugins/index.d.ts +51 -37
  19. package/dist/plugins/index.mjs +20 -10
  20. package/dist/shared/{client.Dw9_40WO.d.mts → client.BoHJeq15.d.mts} +36 -11
  21. package/dist/shared/{client.Dw9_40WO.d.ts → client.BoHJeq15.d.ts} +36 -11
  22. package/dist/shared/{client.Bstqyaro.mjs → client.Bpyj1NM2.mjs} +11 -8
  23. package/dist/shared/{client.DiHfJmHK.d.ts → client.CkwtFnrc.d.mts} +5 -5
  24. package/dist/shared/{client.BjbdW5Rj.d.mts → client.DBDKICdk.d.ts} +5 -5
  25. package/dist/shared/{client.BPa_Mmuh.d.mts → client.DqIWeNhQ.d.mts} +7 -8
  26. package/dist/shared/{client.BPa_Mmuh.d.ts → client.DqIWeNhQ.d.ts} +7 -8
  27. package/dist/shared/{client.DD2eNne_.mjs → client.LF04eOvL.mjs} +24 -6
  28. package/dist/shared/{client.DpkGsZt-.mjs → client._wG5INmC.mjs} +69 -50
  29. package/package.json +8 -8
@@ -3,7 +3,19 @@ import { StandardUrl, StandardHeaders, StandardRequest, StandardLazyResponse } f
3
3
  import { ClientContext } from '../index.js';
4
4
  import { StandardLinkPlugin, StandardLinkTransportInterceptorOptions, StandardLinkOptions, StandardLinkInterceptorOptions } from '../adapters/standard/index.js';
5
5
 
6
- type BatchLinkPluginMode = 'streaming' | 'buffered';
6
+ /**
7
+ * Header that marks a request as a batch, set by the Batch Link Plugin and detected by the Batch Handler Plugin.
8
+ * Nothing between the client and server, such as a CORS policy or proxy, should block or strip it.
9
+ *
10
+ * @see {@link https://orpc.dev/docs/plugins/batch#setup | Batch Plugin - Setup}
11
+ */
12
+ declare const BATCH_HEADER = "orpc-batch";
13
+ /**
14
+ * Default `maxSize` of both the Batch Link Plugin and the Batch Handler Plugin.
15
+ *
16
+ * @see {@link https://orpc.dev/docs/plugins/batch#max-size | Batch Plugin - Max Size}
17
+ */
18
+ declare const DEFAULT_BATCH_MAX_SIZE = 10;
7
19
  interface BatchLinkPluginGroup<T extends ClientContext> {
8
20
  /**
9
21
  * Determines whether a request should be included in this batch group.
@@ -21,7 +33,7 @@ interface BatchLinkPluginGroup<T extends ClientContext> {
21
33
  *
22
34
  * @default []
23
35
  */
24
- path?: Value<string[], [items: [StandardLinkTransportInterceptorOptions<T>, ...StandardLinkTransportInterceptorOptions<T>[]]]>;
36
+ path?: Value<string[], [items: [StandardLinkTransportInterceptorOptions<T>, ...StandardLinkTransportInterceptorOptions<T>[]]]> | undefined;
25
37
  }
26
38
  interface BatchLinkPluginOptions<T extends ClientContext> {
27
39
  groups: [BatchLinkPluginGroup<T>, ...BatchLinkPluginGroup<T>[]];
@@ -30,20 +42,22 @@ interface BatchLinkPluginOptions<T extends ClientContext> {
30
42
  *
31
43
  * @default () => true
32
44
  */
33
- filter?: Value<boolean, [options: StandardLinkTransportInterceptorOptions<T>]>;
45
+ filter?: Value<boolean, [options: StandardLinkTransportInterceptorOptions<T>]> | undefined;
34
46
  /**
35
47
  * Only requests with the same scope are batched together.
36
48
  * On the server, return a value unique to the incoming request so different users never share a batch.
37
49
  *
38
50
  * @default () => undefined
39
51
  */
40
- scope?: (options: StandardLinkTransportInterceptorOptions<T>) => unknown;
52
+ scope?: ((options: StandardLinkTransportInterceptorOptions<T>) => unknown) | undefined;
41
53
  /**
42
- * The maximum number of requests in the batch.
54
+ * The maximum number of requests in the batch. Larger batches are split.
55
+ * Keep it at or below the server Batch Handler Plugin's `maxSize`, which rejects larger batches with a `413`.
43
56
  *
44
- * @default 10
57
+ * @default DEFAULT_BATCH_MAX_SIZE (10)
58
+ * @see {@link https://orpc.dev/docs/plugins/batch#max-size | Batch Plugin - Max Size}
45
59
  */
46
- maxSize?: Value<Promisable<number>, [subOptionsList: [StandardLinkTransportInterceptorOptions<T>, ...StandardLinkTransportInterceptorOptions<T>[]]]>;
60
+ maxSize?: Value<Promisable<number>, [subOptionsList: [StandardLinkTransportInterceptorOptions<T>, ...StandardLinkTransportInterceptorOptions<T>[]]]> | undefined;
47
61
  /**
48
62
  * How long (in ms) to wait for more requests before sending the batch,
49
63
  * counted from the first queued request.
@@ -51,19 +65,13 @@ interface BatchLinkPluginOptions<T extends ClientContext> {
51
65
  *
52
66
  * @default 0
53
67
  */
54
- wait?: number;
55
- /**
56
- * The batch response mode.
57
- *
58
- * @default 'streaming'
59
- */
60
- mode?: Value<BatchLinkPluginMode, [subOptionsList: [StandardLinkTransportInterceptorOptions<T>, ...StandardLinkTransportInterceptorOptions<T>[]]]>;
68
+ wait?: number | undefined;
61
69
  /**
62
70
  * URL for the batch request.
63
71
  *
64
72
  * @default URL of the first subrequest in the batch + '/__batch__'
65
73
  */
66
- url?: Value<Promisable<StandardUrl>, [subOptionsList: [StandardLinkTransportInterceptorOptions<T>, ...StandardLinkTransportInterceptorOptions<T>[]]]>;
74
+ url?: Value<Promisable<StandardUrl>, [subOptionsList: [StandardLinkTransportInterceptorOptions<T>, ...StandardLinkTransportInterceptorOptions<T>[]]]> | undefined;
67
75
  /**
68
76
  * The maximum length of the URL that runtime supports,
69
77
  * if exceeded, the batch will be split into smaller batches and sent sequentially.
@@ -72,25 +80,25 @@ interface BatchLinkPluginOptions<T extends ClientContext> {
72
80
  *
73
81
  * @default 2083
74
82
  */
75
- maxUrlLength?: Value<Promisable<number>, [subOptionsList: [StandardLinkTransportInterceptorOptions<T>, ...StandardLinkTransportInterceptorOptions<T>[]]]>;
83
+ maxUrlLength?: Value<Promisable<number>, [subOptionsList: [StandardLinkTransportInterceptorOptions<T>, ...StandardLinkTransportInterceptorOptions<T>[]]]> | undefined;
76
84
  /**
77
85
  * Headers used for the batch request.
78
86
  *
79
87
  * @default Common headers among all subrequests in the batch.
80
88
  */
81
- headers?: Value<Promisable<StandardHeaders>, [subOptionsList: [StandardLinkTransportInterceptorOptions<T>, ...StandardLinkTransportInterceptorOptions<T>[]]]>;
89
+ headers?: Value<Promisable<StandardHeaders>, [subOptionsList: [StandardLinkTransportInterceptorOptions<T>, ...StandardLinkTransportInterceptorOptions<T>[]]]> | undefined;
82
90
  /**
83
91
  * Map each subrequest in the batch before it is sent.
84
92
  *
85
93
  * @default Removes headers that are duplicated with the batch headers
86
94
  */
87
- mapSubrequest?: (subOptions: StandardLinkTransportInterceptorOptions<T>, partialBatchRequest: Pick<StandardRequest, 'url' | 'headers'>) => StandardRequest;
95
+ mapSubrequest?: ((subOptions: StandardLinkTransportInterceptorOptions<T>, partialBatchRequest: Pick<StandardRequest, 'url' | 'headers'>) => StandardRequest) | undefined;
88
96
  /**
89
97
  * Maps each subresponse before returning the final response.
90
98
  *
91
99
  * @default Low-priority merges headers from the batch response into each subresponse.
92
100
  */
93
- mapSubresponse?: (subResponse: StandardLazyResponse, batchResponse: StandardLazyResponse, subOptions: StandardLinkTransportInterceptorOptions<T>) => StandardLazyResponse;
101
+ mapSubresponse?: ((subResponse: StandardLazyResponse, batchResponse: StandardLazyResponse, subOptions: StandardLinkTransportInterceptorOptions<T>) => StandardLazyResponse) | undefined;
94
102
  }
95
103
  /**
96
104
  * Combines multiple client requests into a single batch request
@@ -108,7 +116,6 @@ declare class BatchLinkPlugin<T extends ClientContext> implements StandardLinkPl
108
116
  private readonly scope;
109
117
  private readonly maxSize;
110
118
  private readonly wait;
111
- private readonly mode;
112
119
  private readonly batchUrl;
113
120
  private readonly maxUrlLength;
114
121
  private readonly batchHeaders;
@@ -151,14 +158,14 @@ interface DedupeLinkPluginOptions<T extends ClientContext> {
151
158
  *
152
159
  * @default ({ request }) => request.method === 'GET' || request.method === 'QUERY'
153
160
  */
154
- filter?: Value<boolean, [options: StandardLinkTransportInterceptorOptions<T>]>;
161
+ filter?: Value<boolean, [options: StandardLinkTransportInterceptorOptions<T>]> | undefined;
155
162
  /**
156
163
  * Only requests with the same scope are deduplicated together.
157
164
  * On the server, return a value unique to the incoming request so different users never share a response.
158
165
  *
159
166
  * @default () => undefined
160
167
  */
161
- scope?: (options: StandardLinkTransportInterceptorOptions<T>) => unknown;
168
+ scope?: ((options: StandardLinkTransportInterceptorOptions<T>) => unknown) | undefined;
162
169
  /**
163
170
  * How long (in ms) to wait for more identical requests before sending,
164
171
  * counted from the first queued request.
@@ -166,7 +173,7 @@ interface DedupeLinkPluginOptions<T extends ClientContext> {
166
173
  *
167
174
  * @default 0
168
175
  */
169
- wait?: number;
176
+ wait?: number | undefined;
170
177
  }
171
178
  /**
172
179
  * Prevents redundant requests by deduplicating similar in-flight requests,
@@ -195,7 +202,7 @@ interface RequestCompressionLinkPluginOptions<T extends ClientContext> {
195
202
  *
196
203
  * @default 'gzip'
197
204
  */
198
- encoding?: 'gzip' | 'deflate' | 'deflate-raw';
205
+ encoding?: 'gzip' | 'deflate' | 'deflate-raw' | undefined;
199
206
  /**
200
207
  * The minimum request size in bytes required to trigger compression.
201
208
  * Requests smaller than this threshold will not be compressed to avoid overhead.
@@ -203,7 +210,7 @@ interface RequestCompressionLinkPluginOptions<T extends ClientContext> {
203
210
  *
204
211
  * @default 1024 (1KB)
205
212
  */
206
- threshold?: number;
213
+ threshold?: number | undefined;
207
214
  /**
208
215
  * Determines whether a request with the given Content-Type should be compressed.
209
216
  * Only consulted for binary transfers (streams, files, and file form-data parts).
@@ -211,7 +218,7 @@ interface RequestCompressionLinkPluginOptions<T extends ClientContext> {
211
218
  *
212
219
  * @default isCompressibleContentType (covers common text-based formats)
213
220
  */
214
- isCompressibleContentType?: (contentType: string | null | undefined, options: StandardLinkTransportInterceptorOptions<T>) => boolean;
221
+ isCompressibleContentType?: ((contentType: string | null | undefined, options: StandardLinkTransportInterceptorOptions<T>) => boolean) | undefined;
215
222
  }
216
223
  /**
217
224
  * Compresses request bodies before sending them to the server,
@@ -239,7 +246,7 @@ interface ResponseCompressionLinkPluginOptions<_T extends ClientContext> {
239
246
  *
240
247
  * @default ['gzip', 'deflate']
241
248
  */
242
- encodings?: readonly ('gzip' | 'deflate' | 'deflate-raw')[];
249
+ encodings?: readonly ('gzip' | 'deflate' | 'deflate-raw')[] | undefined;
243
250
  }
244
251
  /**
245
252
  * Advertises Accept-Encoding on requests and decompresses response bodies
@@ -286,7 +293,7 @@ interface RetryLinkPluginContext {
286
293
  *
287
294
  * @default 0
288
295
  */
289
- retry?: Value<Promisable<number>, [Omit<StandardLinkInterceptorOptions<RetryLinkPluginContext>, 'next'>]>;
296
+ retry?: Value<Promisable<number>, [Omit<StandardLinkInterceptorOptions<RetryLinkPluginContext>, 'next'>]> | undefined;
290
297
  /**
291
298
  * Delay (in ms) before retrying.
292
299
  *
@@ -295,17 +302,17 @@ interface RetryLinkPluginContext {
295
302
  *
296
303
  * @default (o) => o.lastEventRetry ?? 2000
297
304
  */
298
- retryDelay?: Value<Promisable<number>, [RetryLinkPluginAttemptOptions<RetryLinkPluginContext>]>;
305
+ retryDelay?: Value<Promisable<number>, [RetryLinkPluginAttemptOptions<RetryLinkPluginContext>]> | undefined;
299
306
  /**
300
307
  * Determine whether to retry.
301
308
  *
302
- * @default true
309
+ * @default (o) => isRetryableError(o.error)
303
310
  */
304
- shouldRetry?: Value<Promisable<boolean>, [RetryLinkPluginAttemptOptions<RetryLinkPluginContext>]>;
311
+ shouldRetry?: Value<Promisable<boolean>, [RetryLinkPluginAttemptOptions<RetryLinkPluginContext>]> | undefined;
305
312
  /**
306
313
  * Hook called before each retry. Can return a cleanup callback.
307
314
  */
308
- onRetry?: (options: RetryLinkPluginAttemptOptions<RetryLinkPluginContext>) => void | ((isSuccess: boolean) => void);
315
+ onRetry?: ((options: RetryLinkPluginAttemptOptions<RetryLinkPluginContext>) => void | ((isSuccess: boolean) => void)) | undefined;
309
316
  }
310
317
  interface RetryLinkPluginOptions<_T extends RetryLinkPluginContext> {
311
318
  /**
@@ -313,6 +320,13 @@ interface RetryLinkPluginOptions<_T extends RetryLinkPluginContext> {
313
320
  */
314
321
  default?: RetryLinkPluginContext | undefined;
315
322
  }
323
+ /**
324
+ * Default `shouldRetry` check of `RetryLinkPlugin`. Returns `false` only for errors
325
+ * from a 4xx response other than `408` and `429`.
326
+ *
327
+ * @see {@link https://orpc.dev/docs/plugins/retry#client-error-responses | Retry Plugin - Client Error Responses}
328
+ */
329
+ declare function isRetryableError(error: unknown): boolean;
316
330
  /**
317
331
  * Automatically retries failed requests based on customizable retry strategies,
318
332
  * improving the resilience of your application.
@@ -341,7 +355,7 @@ interface RetryAfterLinkPluginOptions<T extends ClientContext> {
341
355
  condition?: Value<boolean, [
342
356
  response: StandardLazyResponse,
343
357
  options: StandardLinkTransportInterceptorOptions<T>
344
- ]>;
358
+ ]> | undefined;
345
359
  /**
346
360
  * Maximum attempts before giving up retries.
347
361
  *
@@ -350,7 +364,7 @@ interface RetryAfterLinkPluginOptions<T extends ClientContext> {
350
364
  maxAttempts?: Value<number, [
351
365
  response: StandardLazyResponse,
352
366
  options: StandardLinkTransportInterceptorOptions<T>
353
- ]>;
367
+ ]> | undefined;
354
368
  /**
355
369
  * Maximum timeout in milliseconds to wait before giving up retries.
356
370
  *
@@ -359,7 +373,7 @@ interface RetryAfterLinkPluginOptions<T extends ClientContext> {
359
373
  timeout?: Value<number, [
360
374
  response: StandardLazyResponse,
361
375
  options: StandardLinkTransportInterceptorOptions<T>
362
- ]>;
376
+ ]> | undefined;
363
377
  }
364
378
  /**
365
379
  * The Retry After Link Plugin automatically retries requests based on server `retry-after` header.
@@ -402,5 +416,5 @@ declare class TimeoutLinkPlugin<T extends ClientContext> implements StandardLink
402
416
  init(options: StandardLinkOptions<T>): StandardLinkOptions<T>;
403
417
  }
404
418
 
405
- export { BatchLinkPlugin, RetryLinkPlugin as ClientRetryPlugin, DedupeLinkPlugin, DedupeLinkPlugin as DedupeRequestsPlugin, RequestCompressionLinkPlugin, ResponseCompressionLinkPlugin, RetryAfterLinkPlugin, RetryAfterLinkPlugin as RetryAfterPlugin, RetryLinkPlugin, TimeoutLinkPlugin };
406
- export type { BatchLinkPluginGroup, BatchLinkPluginMode, BatchLinkPluginOptions, RetryLinkPluginContext as ClientRetryPluginContext, DedupeLinkPluginGroup, DedupeLinkPluginOptions, RequestCompressionLinkPluginOptions, ResponseCompressionLinkPluginOptions, RetryAfterLinkPluginOptions, RetryLinkPluginAttemptOptions, RetryLinkPluginContext, RetryLinkPluginOptions, TimeoutLinkPluginOptions };
419
+ export { BATCH_HEADER, BatchLinkPlugin, RetryLinkPlugin as ClientRetryPlugin, DEFAULT_BATCH_MAX_SIZE, DedupeLinkPlugin, DedupeLinkPlugin as DedupeRequestsPlugin, RequestCompressionLinkPlugin, ResponseCompressionLinkPlugin, RetryAfterLinkPlugin, RetryAfterLinkPlugin as RetryAfterPlugin, RetryLinkPlugin, TimeoutLinkPlugin, isRetryableError };
420
+ export type { BatchLinkPluginGroup, BatchLinkPluginOptions, RetryLinkPluginContext as ClientRetryPluginContext, DedupeLinkPluginGroup, DedupeLinkPluginOptions, RequestCompressionLinkPluginOptions, ResponseCompressionLinkPluginOptions, RetryAfterLinkPluginOptions, RetryLinkPluginAttemptOptions, RetryLinkPluginContext, RetryLinkPluginOptions, TimeoutLinkPluginOptions };
@@ -2,8 +2,10 @@ import { toArray, value, splitInHalf, promiseWithResolvers, safeEncodeURICompone
2
2
  import { parseStandardUrl, flattenStandardHeader, generateContentDisposition, getEventMeta } from '@standard-server/core';
3
3
  import { ClientPeer, isServerPeerSendMessage, decodePeerMessage } from '@standard-server/peer';
4
4
  import { toFetchHeaders, toStandardBody } from '@standard-server/fetch';
5
- import { C as COMMON_ERROR_STATUS_MAP } from '../shared/client.DD2eNne_.mjs';
5
+ import { O as ORPCError, R as ResponseError, C as COMMON_ERROR_STATUS_MAP } from '../shared/client.LF04eOvL.mjs';
6
6
 
7
+ const BATCH_HEADER = "orpc-batch";
8
+ const DEFAULT_BATCH_MAX_SIZE = 10;
7
9
  class BatchLinkPlugin {
8
10
  name = "~batch";
9
11
  groups;
@@ -11,7 +13,6 @@ class BatchLinkPlugin {
11
13
  scope;
12
14
  maxSize;
13
15
  wait;
14
- mode;
15
16
  batchUrl;
16
17
  maxUrlLength;
17
18
  batchHeaders;
@@ -22,9 +23,8 @@ class BatchLinkPlugin {
22
23
  this.groups = options.groups;
23
24
  this.filter = options.filter ?? (() => true);
24
25
  this.scope = options.scope ?? (() => void 0);
25
- this.maxSize = options.maxSize ?? 10;
26
+ this.maxSize = options.maxSize ?? DEFAULT_BATCH_MAX_SIZE;
26
27
  this.wait = options.wait ?? 0;
27
- this.mode = options.mode ?? "streaming";
28
28
  this.batchUrl = options.url ?? ((options2) => {
29
29
  const [pathname] = parseStandardUrl(options2[0].request.url);
30
30
  return `${pathname}/__batch__`;
@@ -141,7 +141,6 @@ class BatchLinkPlugin {
141
141
  }
142
142
  const url = await value(this.batchUrl, subOptionsList);
143
143
  const headers = await value(this.batchHeaders, subOptionsList);
144
- const mode = value(this.mode, subOptionsList);
145
144
  let suppressErrorFromCurrentBatch = false;
146
145
  const controller = new AbortController();
147
146
  const pendingMessages = [];
@@ -185,7 +184,7 @@ class BatchLinkPlugin {
185
184
  const request = {
186
185
  url,
187
186
  method,
188
- headers: { ...headers, "orpc-batch": mode },
187
+ headers: { ...headers, [BATCH_HEADER]: "1" },
189
188
  signal: controller.signal
190
189
  };
191
190
  if (method === "GET") {
@@ -745,6 +744,14 @@ function parseContentEncodings(header) {
745
744
  return header.split(",").map((part) => part.trim().toLowerCase());
746
745
  }
747
746
 
747
+ function isRetryableError(error) {
748
+ const responseError = error instanceof ORPCError ? error.cause : error;
749
+ if (!(responseError instanceof ResponseError)) {
750
+ return true;
751
+ }
752
+ const { status } = responseError.response;
753
+ return status < 400 || status >= 500 || status === COMMON_ERROR_STATUS_MAP.TIMEOUT || status === COMMON_ERROR_STATUS_MAP.TOO_MANY_REQUESTS;
754
+ }
748
755
  class RetryLinkPlugin {
749
756
  defaultRetry;
750
757
  defaultRetryDelay;
@@ -754,7 +761,7 @@ class RetryLinkPlugin {
754
761
  constructor(options = {}) {
755
762
  this.defaultRetry = options.default?.retry ?? 0;
756
763
  this.defaultRetryDelay = options.default?.retryDelay ?? ((o) => o.lastEventRetry ?? 2e3);
757
- this.defaultShouldRetry = options.default?.shouldRetry ?? true;
764
+ this.defaultShouldRetry = options.default?.shouldRetry ?? ((o) => isRetryableError(o.error));
758
765
  this.defaultOnRetry = options.default?.onRetry;
759
766
  }
760
767
  init(options) {
@@ -774,13 +781,14 @@ class RetryLinkPlugin {
774
781
  let lastEventRetry;
775
782
  let callback;
776
783
  let attempt = 1;
784
+ let isIteratorAborted = false;
777
785
  const callNext = async (initialError) => {
778
786
  let currentError = initialError;
779
787
  while (true) {
780
788
  const updatedCallOptions = { ...callOptions, lastEventId };
781
789
  let retryDelayMs = 0;
782
790
  if (currentError) {
783
- if (attempt > maxAttempts) {
791
+ if (isIteratorAborted || attempt > maxAttempts) {
784
792
  throw currentError.error;
785
793
  }
786
794
  const attemptOptions = {
@@ -802,6 +810,9 @@ class RetryLinkPlugin {
802
810
  try {
803
811
  if (currentError) {
804
812
  await sleep(retryDelayMs, { signal: updatedCallOptions.signal });
813
+ if (isIteratorAborted) {
814
+ throw currentError.error;
815
+ }
805
816
  attempt++;
806
817
  }
807
818
  currentError = void 0;
@@ -822,7 +833,6 @@ class RetryLinkPlugin {
822
833
  return output;
823
834
  }
824
835
  let current = output;
825
- let isIteratorAborted = false;
826
836
  return override(() => current, new AsyncIteratorClass(
827
837
  async () => {
828
838
  while (true) {
@@ -958,4 +968,4 @@ class TimeoutLinkPlugin {
958
968
  }
959
969
  }
960
970
 
961
- export { BatchLinkPlugin, RetryLinkPlugin as ClientRetryPlugin, DedupeLinkPlugin, DedupeLinkPlugin as DedupeRequestsPlugin, RequestCompressionLinkPlugin, ResponseCompressionLinkPlugin, RetryAfterLinkPlugin, RetryAfterLinkPlugin as RetryAfterPlugin, RetryLinkPlugin, TimeoutLinkPlugin };
971
+ export { BATCH_HEADER, BatchLinkPlugin, RetryLinkPlugin as ClientRetryPlugin, DEFAULT_BATCH_MAX_SIZE, DedupeLinkPlugin, DedupeLinkPlugin as DedupeRequestsPlugin, RequestCompressionLinkPlugin, ResponseCompressionLinkPlugin, RetryAfterLinkPlugin, RetryAfterLinkPlugin as RetryAfterPlugin, RetryLinkPlugin, TimeoutLinkPlugin, isRetryableError };
@@ -10,7 +10,7 @@ interface ClientOptions<T extends ClientContext> {
10
10
  context: T;
11
11
  }
12
12
  type FriendlyClientOptions<T extends ClientContext> = Omit<ClientOptions<T>, 'context'> & (object extends T ? {
13
- context?: T;
13
+ context?: T | undefined;
14
14
  } : {
15
15
  context: T;
16
16
  });
@@ -134,7 +134,7 @@ type ORPCErrorCode = Registry extends {
134
134
  ORPCErrorCode: infer T extends string;
135
135
  } ? T : (keyof typeof COMMON_ERROR_STATUS_MAP) | (string & {});
136
136
  type ORPCErrorOptions<TData> = ErrorOptions & {
137
- message?: string;
137
+ message?: string | undefined;
138
138
  } & (undefined extends TData ? {
139
139
  data?: TData;
140
140
  } : {
@@ -186,23 +186,48 @@ interface ORPCErrorJSON<TCode extends string, TData> extends Pick<ORPCError<TCod
186
186
  }
187
187
  type AnyORPCError = ORPCError<any, any>;
188
188
  type AnyORPCErrorJSON = ORPCErrorJSON<any, any>;
189
- interface MalformedResponseErrorOptions extends ErrorOptions {
190
- message?: string;
189
+ interface ResponseErrorOptions extends ErrorOptions {
190
+ /**
191
+ * @default inferred from the response status
192
+ */
193
+ message?: string | undefined;
194
+ response: StandardResponse;
195
+ }
196
+ /**
197
+ * Error carrying the resolved response a link received. Links set it as the `cause`
198
+ * of an `ORPCError` decoded from an error response, so details that are not part
199
+ * of the error itself, such as its status or headers, stay available.
200
+ *
201
+ * @see {@link https://orpc.dev/docs/rpc/link#error-responses | RPC Link - Error Responses}
202
+ * @see {@link https://orpc.dev/docs/openapi/link#error-responses | OpenAPI Link - Error Responses}
203
+ */
204
+ declare class ResponseError extends Error {
205
+ readonly name: string;
191
206
  response: StandardResponse;
207
+ constructor(options: ResponseErrorOptions);
208
+ }
209
+ interface MalformedResponseErrorOptions extends ResponseErrorOptions {
210
+ /**
211
+ * @default inferred from the response body or status
212
+ */
213
+ message?: string | undefined;
192
214
  }
193
215
  /**
194
- * Error indicating a response does not follow the expected oRPC format, carrying
195
- * the resolved response. Found as the `cause` of a `MALFORMED_ORPC_RESPONSE`
196
- * `ORPCError`.
216
+ * Error thrown by links when a response does not follow the expected oRPC format,
217
+ * for example when a proxy or gateway answers instead of your handler. Extends
218
+ * `ResponseError`, so it carries the resolved response. Unless overridden via
219
+ * `options.message`, the message is inferred from the response body or status.
220
+ *
221
+ * Unlike `ORPCError`, it reaches a handler's callers as a generic `INTERNAL_SERVER_ERROR`
222
+ * when thrown from the handler, so an upstream's response is not sent to them.
197
223
  *
198
224
  * @see {@link https://orpc.dev/docs/rpc/link#malformed-responses | RPC Link - Malformed Responses}
199
225
  * @see {@link https://orpc.dev/docs/openapi/link#malformed-responses | OpenAPI Link - Malformed Responses}
200
226
  */
201
- declare class MalformedResponseError extends Error {
227
+ declare class MalformedResponseError extends ResponseError {
202
228
  readonly name = "MalformedResponseError";
203
- response: StandardResponse;
204
229
  constructor(options: MalformedResponseErrorOptions);
205
230
  }
206
231
 
207
- export { ORPCError as h, COMMON_ERROR_STATUS_MAP as j, MalformedResponseError as p };
208
- export type { AnyORPCError as A, ClientContext as C, FriendlyClientOptions as F, InferClientContext as I, MalformedResponseErrorOptions as M, NestedClient as N, ORPCErrorCode as O, ClientOptions as a, ClientLink as b, AnyNestedClient as c, InferClientError as d, Client as e, ClientRest as f, ORPCErrorJSON as g, AnyORPCErrorJSON as i, InferClientBodyInputs as k, InferClientBodyOutputs as l, InferClientErrors as m, InferClientInputs as n, InferClientOutputs as o, ORPCErrorOptions as q };
232
+ export { MalformedResponseError as M, ResponseError as R, ORPCError as h, COMMON_ERROR_STATUS_MAP as j };
233
+ export type { AnyORPCError as A, ClientContext as C, FriendlyClientOptions as F, InferClientContext as I, NestedClient as N, ORPCErrorCode as O, ClientOptions as a, ClientLink as b, AnyNestedClient as c, InferClientError as d, Client as e, ClientRest as f, ORPCErrorJSON as g, AnyORPCErrorJSON as i, InferClientBodyInputs as k, InferClientBodyOutputs as l, InferClientErrors as m, InferClientInputs as n, InferClientOutputs as o, MalformedResponseErrorOptions as p, ORPCErrorOptions as q, ResponseErrorOptions as r };
@@ -10,7 +10,7 @@ interface ClientOptions<T extends ClientContext> {
10
10
  context: T;
11
11
  }
12
12
  type FriendlyClientOptions<T extends ClientContext> = Omit<ClientOptions<T>, 'context'> & (object extends T ? {
13
- context?: T;
13
+ context?: T | undefined;
14
14
  } : {
15
15
  context: T;
16
16
  });
@@ -134,7 +134,7 @@ type ORPCErrorCode = Registry extends {
134
134
  ORPCErrorCode: infer T extends string;
135
135
  } ? T : (keyof typeof COMMON_ERROR_STATUS_MAP) | (string & {});
136
136
  type ORPCErrorOptions<TData> = ErrorOptions & {
137
- message?: string;
137
+ message?: string | undefined;
138
138
  } & (undefined extends TData ? {
139
139
  data?: TData;
140
140
  } : {
@@ -186,23 +186,48 @@ interface ORPCErrorJSON<TCode extends string, TData> extends Pick<ORPCError<TCod
186
186
  }
187
187
  type AnyORPCError = ORPCError<any, any>;
188
188
  type AnyORPCErrorJSON = ORPCErrorJSON<any, any>;
189
- interface MalformedResponseErrorOptions extends ErrorOptions {
190
- message?: string;
189
+ interface ResponseErrorOptions extends ErrorOptions {
190
+ /**
191
+ * @default inferred from the response status
192
+ */
193
+ message?: string | undefined;
194
+ response: StandardResponse;
195
+ }
196
+ /**
197
+ * Error carrying the resolved response a link received. Links set it as the `cause`
198
+ * of an `ORPCError` decoded from an error response, so details that are not part
199
+ * of the error itself, such as its status or headers, stay available.
200
+ *
201
+ * @see {@link https://orpc.dev/docs/rpc/link#error-responses | RPC Link - Error Responses}
202
+ * @see {@link https://orpc.dev/docs/openapi/link#error-responses | OpenAPI Link - Error Responses}
203
+ */
204
+ declare class ResponseError extends Error {
205
+ readonly name: string;
191
206
  response: StandardResponse;
207
+ constructor(options: ResponseErrorOptions);
208
+ }
209
+ interface MalformedResponseErrorOptions extends ResponseErrorOptions {
210
+ /**
211
+ * @default inferred from the response body or status
212
+ */
213
+ message?: string | undefined;
192
214
  }
193
215
  /**
194
- * Error indicating a response does not follow the expected oRPC format, carrying
195
- * the resolved response. Found as the `cause` of a `MALFORMED_ORPC_RESPONSE`
196
- * `ORPCError`.
216
+ * Error thrown by links when a response does not follow the expected oRPC format,
217
+ * for example when a proxy or gateway answers instead of your handler. Extends
218
+ * `ResponseError`, so it carries the resolved response. Unless overridden via
219
+ * `options.message`, the message is inferred from the response body or status.
220
+ *
221
+ * Unlike `ORPCError`, it reaches a handler's callers as a generic `INTERNAL_SERVER_ERROR`
222
+ * when thrown from the handler, so an upstream's response is not sent to them.
197
223
  *
198
224
  * @see {@link https://orpc.dev/docs/rpc/link#malformed-responses | RPC Link - Malformed Responses}
199
225
  * @see {@link https://orpc.dev/docs/openapi/link#malformed-responses | OpenAPI Link - Malformed Responses}
200
226
  */
201
- declare class MalformedResponseError extends Error {
227
+ declare class MalformedResponseError extends ResponseError {
202
228
  readonly name = "MalformedResponseError";
203
- response: StandardResponse;
204
229
  constructor(options: MalformedResponseErrorOptions);
205
230
  }
206
231
 
207
- export { ORPCError as h, COMMON_ERROR_STATUS_MAP as j, MalformedResponseError as p };
208
- export type { AnyORPCError as A, ClientContext as C, FriendlyClientOptions as F, InferClientContext as I, MalformedResponseErrorOptions as M, NestedClient as N, ORPCErrorCode as O, ClientOptions as a, ClientLink as b, AnyNestedClient as c, InferClientError as d, Client as e, ClientRest as f, ORPCErrorJSON as g, AnyORPCErrorJSON as i, InferClientBodyInputs as k, InferClientBodyOutputs as l, InferClientErrors as m, InferClientInputs as n, InferClientOutputs as o, ORPCErrorOptions as q };
232
+ export { MalformedResponseError as M, ResponseError as R, ORPCError as h, COMMON_ERROR_STATUS_MAP as j };
233
+ export type { AnyORPCError as A, ClientContext as C, FriendlyClientOptions as F, InferClientContext as I, NestedClient as N, ORPCErrorCode as O, ClientOptions as a, ClientLink as b, AnyNestedClient as c, InferClientError as d, Client as e, ClientRest as f, ORPCErrorJSON as g, AnyORPCErrorJSON as i, InferClientBodyInputs as k, InferClientBodyOutputs as l, InferClientErrors as m, InferClientInputs as n, InferClientOutputs as o, MalformedResponseErrorOptions as p, ORPCErrorOptions as q, ResponseErrorOptions as r };
@@ -1,7 +1,8 @@
1
1
  import { sortPlugins, runWithSpan, ORPC_NAME, getTracer, isAsyncIteratorObject, override, traceAsyncIterator, traceReadableStream, intercept, value, pathToHttpPath, stringifyJSON } from '@orpc/shared';
2
2
  import { mergeStandardHeaders, parseStandardUrl } from '@standard-server/core';
3
3
  import { toStandardHeaders } from '@standard-server/fetch';
4
- import { R as RPCSerializer, c as createORPCErrorFromMalformedResponse, i as isORPCErrorJson, a as createORPCErrorFromJson } from './client.DpkGsZt-.mjs';
4
+ import { M as MalformedResponseError, R as ResponseError } from './client.LF04eOvL.mjs';
5
+ import { R as RPCSerializer, i as isORPCErrorJson, c as createORPCErrorFromJson } from './client._wG5INmC.mjs';
5
6
 
6
7
  class CompositeStandardLinkPlugin {
7
8
  name = "~composite";
@@ -30,7 +31,7 @@ class StandardLink {
30
31
  interceptors;
31
32
  transportInterceptors;
32
33
  /**
33
- * @throws ORPCError, transport-level errors (network failures, timeouts, etc.)
34
+ * @throws ORPCError, MalformedResponseError, transport-level errors (network failures, timeouts, etc.)
34
35
  */
35
36
  call(path, input, options) {
36
37
  return runWithSpan(`${ORPC_NAME}.${path.join("/")}`, (span) => {
@@ -140,7 +141,7 @@ class RPCLinkCodec {
140
141
  try {
141
142
  return this.serializer.deserialize(body);
142
143
  } catch (cause) {
143
- throw createORPCErrorFromMalformedResponse({
144
+ throw new MalformedResponseError({
144
145
  message: "Invalid RPC response format.",
145
146
  response: { status: response.status, headers: response.headers, body },
146
147
  cause
@@ -149,12 +150,14 @@ class RPCLinkCodec {
149
150
  })();
150
151
  if (!isOk) {
151
152
  if (isORPCErrorJson(deserialized)) {
152
- return { kind: "error", error: createORPCErrorFromJson(deserialized) };
153
+ return {
154
+ kind: "error",
155
+ error: createORPCErrorFromJson(deserialized, {
156
+ cause: new ResponseError({ response: { status: response.status, headers: response.headers, body } })
157
+ })
158
+ };
153
159
  }
154
- return {
155
- kind: "error",
156
- error: createORPCErrorFromMalformedResponse({ response: { headers: response.headers, status: response.status, body } })
157
- };
160
+ throw new MalformedResponseError({ response: { headers: response.headers, status: response.status, body } });
158
161
  }
159
162
  return { kind: "output", output: deserialized };
160
163
  }
@@ -1,6 +1,6 @@
1
1
  import { Promisable, OrderablePlugin, Interceptor } from '@orpc/shared';
2
2
  import { StandardRequest, StandardLazyResponse } from '@standard-server/core';
3
- import { C as ClientContext, a as ClientOptions, A as AnyORPCError, b as ClientLink } from './client.Dw9_40WO.js';
3
+ import { C as ClientContext, a as ClientOptions, A as AnyORPCError, b as ClientLink } from './client.BoHJeq15.mjs';
4
4
 
5
5
  type StandardLinkCodecDecodedResponse = {
6
6
  kind: 'output';
@@ -72,13 +72,13 @@ interface StandardLinkOptions<T extends ClientContext> {
72
72
  * Interceptors that execute around the entire call, including transport and codec.
73
73
  * Useful for error handling, logging, metrics, ...
74
74
  */
75
- interceptors?: StandardLinkInterceptor<T>[];
75
+ interceptors?: StandardLinkInterceptor<T>[] | undefined;
76
76
  /**
77
77
  * Interceptors that execute around the transport layer, after encoding and before decoding.
78
78
  * Useful for modifying the request or response, adding transport-level logging, ...
79
79
  */
80
- transportInterceptors?: StandardLinkTransportInterceptor<T>[];
81
- plugins?: StandardLinkPlugin<T>[];
80
+ transportInterceptors?: StandardLinkTransportInterceptor<T>[] | undefined;
81
+ plugins?: StandardLinkPlugin<T>[] | undefined;
82
82
  }
83
83
  declare class StandardLink<T extends ClientContext> implements ClientLink<T> {
84
84
  private readonly codec;
@@ -87,7 +87,7 @@ declare class StandardLink<T extends ClientContext> implements ClientLink<T> {
87
87
  private readonly transportInterceptors;
88
88
  constructor(codec: StandardLinkCodec<T>, transport: StandardLinkTransport<T>, options?: StandardLinkOptions<T>);
89
89
  /**
90
- * @throws ORPCError, transport-level errors (network failures, timeouts, etc.)
90
+ * @throws ORPCError, MalformedResponseError, transport-level errors (network failures, timeouts, etc.)
91
91
  */
92
92
  call(path: string[], input: unknown, options: ClientOptions<T>): Promise<unknown>;
93
93
  }
@@ -1,6 +1,6 @@
1
1
  import { Promisable, OrderablePlugin, Interceptor } from '@orpc/shared';
2
2
  import { StandardRequest, StandardLazyResponse } from '@standard-server/core';
3
- import { C as ClientContext, a as ClientOptions, A as AnyORPCError, b as ClientLink } from './client.Dw9_40WO.mjs';
3
+ import { C as ClientContext, a as ClientOptions, A as AnyORPCError, b as ClientLink } from './client.BoHJeq15.js';
4
4
 
5
5
  type StandardLinkCodecDecodedResponse = {
6
6
  kind: 'output';
@@ -72,13 +72,13 @@ interface StandardLinkOptions<T extends ClientContext> {
72
72
  * Interceptors that execute around the entire call, including transport and codec.
73
73
  * Useful for error handling, logging, metrics, ...
74
74
  */
75
- interceptors?: StandardLinkInterceptor<T>[];
75
+ interceptors?: StandardLinkInterceptor<T>[] | undefined;
76
76
  /**
77
77
  * Interceptors that execute around the transport layer, after encoding and before decoding.
78
78
  * Useful for modifying the request or response, adding transport-level logging, ...
79
79
  */
80
- transportInterceptors?: StandardLinkTransportInterceptor<T>[];
81
- plugins?: StandardLinkPlugin<T>[];
80
+ transportInterceptors?: StandardLinkTransportInterceptor<T>[] | undefined;
81
+ plugins?: StandardLinkPlugin<T>[] | undefined;
82
82
  }
83
83
  declare class StandardLink<T extends ClientContext> implements ClientLink<T> {
84
84
  private readonly codec;
@@ -87,7 +87,7 @@ declare class StandardLink<T extends ClientContext> implements ClientLink<T> {
87
87
  private readonly transportInterceptors;
88
88
  constructor(codec: StandardLinkCodec<T>, transport: StandardLinkTransport<T>, options?: StandardLinkOptions<T>);
89
89
  /**
90
- * @throws ORPCError, transport-level errors (network failures, timeouts, etc.)
90
+ * @throws ORPCError, MalformedResponseError, transport-level errors (network failures, timeouts, etc.)
91
91
  */
92
92
  call(path: string[], input: unknown, options: ClientOptions<T>): Promise<unknown>;
93
93
  }