@orpc/client 0.0.0-next.a8e421c → 0.0.0-next.a910d34

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 (33) hide show
  1. package/README.md +26 -22
  2. package/dist/adapters/fetch/index.d.mts +16 -13
  3. package/dist/adapters/fetch/index.d.ts +16 -13
  4. package/dist/adapters/fetch/index.mjs +5 -13
  5. package/dist/adapters/message-port/index.d.mts +59 -0
  6. package/dist/adapters/message-port/index.d.ts +59 -0
  7. package/dist/adapters/message-port/index.mjs +71 -0
  8. package/dist/adapters/standard/index.d.mts +8 -103
  9. package/dist/adapters/standard/index.d.ts +8 -103
  10. package/dist/adapters/standard/index.mjs +2 -3
  11. package/dist/adapters/websocket/index.d.mts +29 -0
  12. package/dist/adapters/websocket/index.d.ts +29 -0
  13. package/dist/adapters/websocket/index.mjs +44 -0
  14. package/dist/index.d.mts +62 -27
  15. package/dist/index.d.ts +62 -27
  16. package/dist/index.mjs +54 -35
  17. package/dist/plugins/index.d.mts +165 -25
  18. package/dist/plugins/index.d.ts +165 -25
  19. package/dist/plugins/index.mjs +313 -51
  20. package/dist/shared/client.BOYsZIRq.d.mts +29 -0
  21. package/dist/shared/client.BOYsZIRq.d.ts +29 -0
  22. package/dist/shared/{client.BacCdg3F.mjs → client.BngOL3Ai.mjs} +50 -49
  23. package/dist/shared/{client.Be-O_tdu.mjs → client.BvXDSBF5.mjs} +52 -28
  24. package/dist/shared/client.C4VxIexA.d.mts +46 -0
  25. package/dist/shared/client.CXXEPIbK.d.ts +46 -0
  26. package/dist/shared/client.WCinBImJ.d.ts +91 -0
  27. package/dist/shared/client.aTp4sII-.d.mts +91 -0
  28. package/package.json +16 -5
  29. package/dist/shared/client.CupM8eRP.d.mts +0 -30
  30. package/dist/shared/client.CupM8eRP.d.ts +0 -30
  31. package/dist/shared/client.CvnV7_uV.mjs +0 -12
  32. package/dist/shared/client.DrOAzyMB.d.mts +0 -45
  33. package/dist/shared/client.aGal-uGY.d.ts +0 -45
@@ -1,6 +1,249 @@
1
- export { C as CompositeClientPlugin } from '../shared/client.CvnV7_uV.mjs';
2
- import { isAsyncIteratorObject, value } from '@orpc/shared';
3
- import { getEventMeta } from '@orpc/standard-server';
1
+ import { isAsyncIteratorObject, defer, value, splitInHalf, toArray, stringifyJSON } from '@orpc/shared';
2
+ import { toBatchRequest, parseBatchResponse, toBatchAbortSignal } from '@orpc/standard-server/batch';
3
+ import { replicateStandardLazyResponse, getEventMeta } from '@orpc/standard-server';
4
+
5
+ class BatchLinkPlugin {
6
+ groups;
7
+ maxSize;
8
+ batchUrl;
9
+ maxUrlLength;
10
+ batchHeaders;
11
+ mapRequestItem;
12
+ exclude;
13
+ mode;
14
+ pending;
15
+ order = 5e6;
16
+ constructor(options) {
17
+ this.groups = options.groups;
18
+ this.pending = /* @__PURE__ */ new Map();
19
+ this.maxSize = options.maxSize ?? 10;
20
+ this.maxUrlLength = options.maxUrlLength ?? 2083;
21
+ this.mode = options.mode ?? "streaming";
22
+ this.batchUrl = options.url ?? (([options2]) => `${options2.request.url.origin}${options2.request.url.pathname}/__batch__`);
23
+ this.batchHeaders = options.headers ?? (([options2, ...rest]) => {
24
+ const headers = {};
25
+ for (const [key, value2] of Object.entries(options2.request.headers)) {
26
+ if (rest.every((item) => item.request.headers[key] === value2)) {
27
+ headers[key] = value2;
28
+ }
29
+ }
30
+ return headers;
31
+ });
32
+ this.mapRequestItem = options.mapRequestItem ?? (({ request, batchHeaders }) => {
33
+ const headers = {};
34
+ for (const [key, value2] of Object.entries(request.headers)) {
35
+ if (batchHeaders[key] !== value2) {
36
+ headers[key] = value2;
37
+ }
38
+ }
39
+ return {
40
+ method: request.method,
41
+ url: request.url,
42
+ headers,
43
+ body: request.body,
44
+ signal: request.signal
45
+ };
46
+ });
47
+ this.exclude = options.exclude ?? (() => false);
48
+ }
49
+ init(options) {
50
+ options.clientInterceptors ??= [];
51
+ options.clientInterceptors.push((options2) => {
52
+ if (options2.request.headers["x-orpc-batch"] !== "1") {
53
+ return options2.next();
54
+ }
55
+ return options2.next({
56
+ ...options2,
57
+ request: {
58
+ ...options2.request,
59
+ headers: {
60
+ ...options2.request.headers,
61
+ "x-orpc-batch": void 0
62
+ }
63
+ }
64
+ });
65
+ });
66
+ options.clientInterceptors.push((options2) => {
67
+ if (this.exclude(options2) || options2.request.body instanceof Blob || options2.request.body instanceof FormData || isAsyncIteratorObject(options2.request.body)) {
68
+ return options2.next();
69
+ }
70
+ const group = this.groups.find((group2) => group2.condition(options2));
71
+ if (!group) {
72
+ return options2.next();
73
+ }
74
+ return new Promise((resolve, reject) => {
75
+ this.#enqueueRequest(group, options2, resolve, reject);
76
+ defer(() => this.#processPendingBatches());
77
+ });
78
+ });
79
+ }
80
+ #enqueueRequest(group, options, resolve, reject) {
81
+ const items = this.pending.get(group);
82
+ if (items) {
83
+ items.push([options, resolve, reject]);
84
+ } else {
85
+ this.pending.set(group, [[options, resolve, reject]]);
86
+ }
87
+ }
88
+ async #processPendingBatches() {
89
+ const pending = this.pending;
90
+ this.pending = /* @__PURE__ */ new Map();
91
+ for (const [group, items] of pending) {
92
+ const getItems = items.filter(([options]) => options.request.method === "GET");
93
+ const restItems = items.filter(([options]) => options.request.method !== "GET");
94
+ this.#executeBatch("GET", group, getItems);
95
+ this.#executeBatch("POST", group, restItems);
96
+ }
97
+ }
98
+ async #executeBatch(method, group, groupItems) {
99
+ if (!groupItems.length) {
100
+ return;
101
+ }
102
+ const batchItems = groupItems;
103
+ if (batchItems.length === 1) {
104
+ batchItems[0][0].next().then(batchItems[0][1]).catch(batchItems[0][2]);
105
+ return;
106
+ }
107
+ try {
108
+ const options = batchItems.map(([options2]) => options2);
109
+ const maxSize = await value(this.maxSize, options);
110
+ if (batchItems.length > maxSize) {
111
+ const [first, second] = splitInHalf(batchItems);
112
+ this.#executeBatch(method, group, first);
113
+ this.#executeBatch(method, group, second);
114
+ return;
115
+ }
116
+ const batchUrl = new URL(await value(this.batchUrl, options));
117
+ const batchHeaders = await value(this.batchHeaders, options);
118
+ const mappedItems = batchItems.map(([options2]) => this.mapRequestItem({ ...options2, batchUrl, batchHeaders }));
119
+ const batchRequest = toBatchRequest({
120
+ method,
121
+ url: batchUrl,
122
+ headers: batchHeaders,
123
+ requests: mappedItems
124
+ });
125
+ const maxUrlLength = await value(this.maxUrlLength, options);
126
+ if (batchRequest.url.toString().length > maxUrlLength) {
127
+ const [first, second] = splitInHalf(batchItems);
128
+ this.#executeBatch(method, group, first);
129
+ this.#executeBatch(method, group, second);
130
+ return;
131
+ }
132
+ const mode = value(this.mode, options);
133
+ const lazyResponse = await options[0].next({
134
+ request: { ...batchRequest, headers: { ...batchRequest.headers, "x-orpc-batch": mode } },
135
+ signal: batchRequest.signal,
136
+ context: group.context,
137
+ input: group.input,
138
+ path: toArray(group.path)
139
+ });
140
+ const parsed = parseBatchResponse({ ...lazyResponse, body: await lazyResponse.body() });
141
+ for await (const item of parsed) {
142
+ batchItems[item.index]?.[1]({ ...item, body: () => Promise.resolve(item.body) });
143
+ }
144
+ throw new Error("Something went wrong make batch response not contains enough responses. This can be a bug please report it.");
145
+ } catch (error) {
146
+ for (const [, , reject] of batchItems) {
147
+ reject(error);
148
+ }
149
+ }
150
+ }
151
+ }
152
+
153
+ class DedupeRequestsPlugin {
154
+ #groups;
155
+ #filter;
156
+ order = 4e6;
157
+ // make sure execute before batch plugin
158
+ #queue = /* @__PURE__ */ new Map();
159
+ constructor(options) {
160
+ this.#groups = options.groups;
161
+ this.#filter = options.filter ?? (({ request }) => request.method === "GET");
162
+ }
163
+ init(options) {
164
+ options.clientInterceptors ??= [];
165
+ options.clientInterceptors.push((options2) => {
166
+ if (options2.request.body instanceof Blob || options2.request.body instanceof FormData || options2.request.body instanceof URLSearchParams || isAsyncIteratorObject(options2.request.body) || !this.#filter(options2)) {
167
+ return options2.next();
168
+ }
169
+ const group = this.#groups.find((group2) => group2.condition(options2));
170
+ if (!group) {
171
+ return options2.next();
172
+ }
173
+ return new Promise((resolve, reject) => {
174
+ this.#enqueue(group, options2, resolve, reject);
175
+ defer(() => this.#dequeue());
176
+ });
177
+ });
178
+ }
179
+ #enqueue(group, options, resolve, reject) {
180
+ let queue = this.#queue.get(group);
181
+ if (!queue) {
182
+ this.#queue.set(group, queue = []);
183
+ }
184
+ const matched = queue.find((item) => {
185
+ const requestString1 = stringifyJSON({
186
+ body: item.options.request.body,
187
+ headers: item.options.request.headers,
188
+ method: item.options.request.method,
189
+ url: item.options.request.url
190
+ });
191
+ const requestString2 = stringifyJSON({
192
+ body: options.request.body,
193
+ headers: options.request.headers,
194
+ method: options.request.method,
195
+ url: options.request.url
196
+ });
197
+ return requestString1 === requestString2;
198
+ });
199
+ if (matched) {
200
+ matched.signals.push(options.request.signal);
201
+ matched.resolves.push(resolve);
202
+ matched.rejects.push(reject);
203
+ } else {
204
+ queue.push({
205
+ options,
206
+ signals: [options.request.signal],
207
+ resolves: [resolve],
208
+ rejects: [reject]
209
+ });
210
+ }
211
+ }
212
+ async #dequeue() {
213
+ const promises = [];
214
+ for (const [group, items] of this.#queue) {
215
+ for (const { options, signals, resolves, rejects } of items) {
216
+ promises.push(
217
+ this.#execute(group, options, signals, resolves, rejects)
218
+ );
219
+ }
220
+ }
221
+ this.#queue.clear();
222
+ await Promise.all(promises);
223
+ }
224
+ async #execute(group, options, signals, resolves, rejects) {
225
+ try {
226
+ const dedupedRequest = {
227
+ ...options.request,
228
+ signal: toBatchAbortSignal(signals)
229
+ };
230
+ const response = await options.next({
231
+ ...options,
232
+ request: dedupedRequest,
233
+ signal: dedupedRequest.signal,
234
+ context: group.context
235
+ });
236
+ const replicatedResponses = replicateStandardLazyResponse(response, resolves.length);
237
+ for (const resolve of resolves) {
238
+ resolve(replicatedResponses.shift());
239
+ }
240
+ } catch (error) {
241
+ for (const reject of rejects) {
242
+ reject(error);
243
+ }
244
+ }
245
+ }
246
+ }
4
247
 
5
248
  class ClientRetryPluginInvalidEventIteratorRetryResponse extends Error {
6
249
  }
@@ -11,78 +254,64 @@ class ClientRetryPlugin {
11
254
  defaultOnRetry;
12
255
  constructor(options = {}) {
13
256
  this.defaultRetry = options.default?.retry ?? 0;
14
- this.defaultRetryDelay = options.default?.retryDelay ?? ((o) => o.eventIteratorLastRetry ?? 2e3);
257
+ this.defaultRetryDelay = options.default?.retryDelay ?? ((o) => o.lastEventRetry ?? 2e3);
15
258
  this.defaultShouldRetry = options.default?.shouldRetry ?? true;
16
259
  this.defaultOnRetry = options.default?.onRetry;
17
260
  }
18
261
  init(options) {
19
262
  options.interceptors ??= [];
20
263
  options.interceptors.push(async (interceptorOptions) => {
21
- const maxAttempts = interceptorOptions.options.context.retry ?? this.defaultRetry;
22
- const retryDelay = interceptorOptions.options.context.retryDelay ?? this.defaultRetryDelay;
23
- const shouldRetry = interceptorOptions.options.context.shouldRetry ?? this.defaultShouldRetry;
24
- const onRetry = interceptorOptions.options.context.onRetry ?? this.defaultOnRetry;
264
+ const maxAttempts = await value(
265
+ interceptorOptions.context.retry ?? this.defaultRetry,
266
+ interceptorOptions
267
+ );
268
+ const retryDelay = interceptorOptions.context.retryDelay ?? this.defaultRetryDelay;
269
+ const shouldRetry = interceptorOptions.context.shouldRetry ?? this.defaultShouldRetry;
270
+ const onRetry = interceptorOptions.context.onRetry ?? this.defaultOnRetry;
25
271
  if (maxAttempts <= 0) {
26
272
  return interceptorOptions.next();
27
273
  }
28
- let eventIteratorLastEventId = interceptorOptions.options.lastEventId;
29
- let eventIteratorLastRetry;
30
- let unsubscribe;
274
+ let lastEventId = interceptorOptions.lastEventId;
275
+ let lastEventRetry;
276
+ let callback;
31
277
  let attemptIndex = 0;
32
- const next = async (initial) => {
33
- let current = initial;
278
+ const next = async (initialError) => {
279
+ let currentError = initialError;
34
280
  while (true) {
35
- if (current) {
281
+ const updatedInterceptorOptions = { ...interceptorOptions, lastEventId };
282
+ if (currentError) {
36
283
  if (attemptIndex >= maxAttempts) {
37
- throw current.error;
284
+ throw currentError.error;
38
285
  }
39
286
  const attemptOptions = {
287
+ ...updatedInterceptorOptions,
40
288
  attemptIndex,
41
- error: current.error,
42
- eventIteratorLastEventId,
43
- eventIteratorLastRetry
289
+ error: currentError.error,
290
+ lastEventRetry
44
291
  };
45
292
  const shouldRetryBool = await value(
46
293
  shouldRetry,
47
- attemptOptions,
48
- interceptorOptions.options,
49
- interceptorOptions.path,
50
- interceptorOptions.input
294
+ attemptOptions
51
295
  );
52
296
  if (!shouldRetryBool) {
53
- throw current.error;
297
+ throw currentError.error;
54
298
  }
55
- unsubscribe = onRetry?.(
56
- attemptOptions,
57
- interceptorOptions.options,
58
- interceptorOptions.path,
59
- interceptorOptions.input
60
- );
61
- const retryDelayMs = await value(
62
- retryDelay,
63
- attemptOptions,
64
- interceptorOptions.options,
65
- interceptorOptions.path,
66
- interceptorOptions.input
67
- );
299
+ callback = onRetry?.(attemptOptions);
300
+ const retryDelayMs = await value(retryDelay, attemptOptions);
68
301
  await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
69
302
  attemptIndex++;
70
303
  }
71
304
  try {
72
- const newClientOptions = { ...interceptorOptions.options, lastEventId: eventIteratorLastEventId };
73
- const output2 = await interceptorOptions.next({
74
- ...interceptorOptions,
75
- options: newClientOptions
76
- });
77
- return output2;
305
+ currentError = void 0;
306
+ return await interceptorOptions.next(updatedInterceptorOptions);
78
307
  } catch (error) {
79
- if (interceptorOptions.options.signal?.aborted === true) {
308
+ currentError = { error };
309
+ if (updatedInterceptorOptions.signal?.aborted === true) {
80
310
  throw error;
81
311
  }
82
- current = { error };
83
312
  } finally {
84
- unsubscribe?.();
85
- unsubscribe = void 0;
313
+ callback?.(!currentError);
314
+ callback = void 0;
86
315
  }
87
316
  }
88
317
  };
@@ -97,16 +326,16 @@ class ClientRetryPlugin {
97
326
  try {
98
327
  const item = await current.next();
99
328
  const meta = getEventMeta(item.value);
100
- eventIteratorLastEventId = meta?.id ?? eventIteratorLastEventId;
101
- eventIteratorLastRetry = meta?.retry ?? eventIteratorLastRetry;
329
+ lastEventId = meta?.id ?? lastEventId;
330
+ lastEventRetry = meta?.retry ?? lastEventRetry;
102
331
  if (item.done) {
103
332
  return item.value;
104
333
  }
105
334
  yield item.value;
106
335
  } catch (error) {
107
336
  const meta = getEventMeta(error);
108
- eventIteratorLastEventId = meta?.id ?? eventIteratorLastEventId;
109
- eventIteratorLastRetry = meta?.retry ?? eventIteratorLastRetry;
337
+ lastEventId = meta?.id ?? lastEventId;
338
+ lastEventRetry = meta?.retry ?? lastEventRetry;
110
339
  const maybeEventIterator = await next({ error });
111
340
  if (!isAsyncIteratorObject(maybeEventIterator)) {
112
341
  throw new ClientRetryPluginInvalidEventIteratorRetryResponse(
@@ -124,4 +353,37 @@ class ClientRetryPlugin {
124
353
  }
125
354
  }
126
355
 
127
- export { ClientRetryPlugin, ClientRetryPluginInvalidEventIteratorRetryResponse };
356
+ class SimpleCsrfProtectionLinkPlugin {
357
+ headerName;
358
+ headerValue;
359
+ exclude;
360
+ constructor(options = {}) {
361
+ this.headerName = options.headerName ?? "x-csrf-token";
362
+ this.headerValue = options.headerValue ?? "orpc";
363
+ this.exclude = options.exclude ?? false;
364
+ }
365
+ order = 8e6;
366
+ init(options) {
367
+ options.clientInterceptors ??= [];
368
+ options.clientInterceptors.push(async (options2) => {
369
+ const excluded = await value(this.exclude, options2);
370
+ if (excluded) {
371
+ return options2.next();
372
+ }
373
+ const headerName = await value(this.headerName, options2);
374
+ const headerValue = await value(this.headerValue, options2);
375
+ return options2.next({
376
+ ...options2,
377
+ request: {
378
+ ...options2.request,
379
+ headers: {
380
+ ...options2.request.headers,
381
+ [headerName]: headerValue
382
+ }
383
+ }
384
+ });
385
+ });
386
+ }
387
+ }
388
+
389
+ export { BatchLinkPlugin, ClientRetryPlugin, ClientRetryPluginInvalidEventIteratorRetryResponse, DedupeRequestsPlugin, SimpleCsrfProtectionLinkPlugin };
@@ -0,0 +1,29 @@
1
+ import { PromiseWithError } from '@orpc/shared';
2
+
3
+ type HTTPPath = `/${string}`;
4
+ type HTTPMethod = 'HEAD' | 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
5
+ type ClientContext = Record<PropertyKey, any>;
6
+ interface ClientOptions<T extends ClientContext> {
7
+ signal?: AbortSignal;
8
+ lastEventId?: string | undefined;
9
+ context: T;
10
+ }
11
+ type FriendlyClientOptions<T extends ClientContext> = Omit<ClientOptions<T>, 'context'> & (Record<never, never> extends T ? {
12
+ context?: T;
13
+ } : {
14
+ context: T;
15
+ });
16
+ type ClientRest<TClientContext extends ClientContext, TInput> = Record<never, never> extends TClientContext ? undefined extends TInput ? [input?: TInput, options?: FriendlyClientOptions<TClientContext>] : [input: TInput, options?: FriendlyClientOptions<TClientContext>] : [input: TInput, options: FriendlyClientOptions<TClientContext>];
17
+ type ClientPromiseResult<TOutput, TError> = PromiseWithError<TOutput, TError>;
18
+ interface Client<TClientContext extends ClientContext, TInput, TOutput, TError> {
19
+ (...rest: ClientRest<TClientContext, TInput>): ClientPromiseResult<TOutput, TError>;
20
+ }
21
+ type NestedClient<TClientContext extends ClientContext> = Client<TClientContext, any, any, any> | {
22
+ [k: string]: NestedClient<TClientContext>;
23
+ };
24
+ type InferClientContext<T extends NestedClient<any>> = T extends NestedClient<infer U> ? U : never;
25
+ interface ClientLink<TClientContext extends ClientContext> {
26
+ call: (path: readonly string[], input: unknown, options: ClientOptions<TClientContext>) => Promise<unknown>;
27
+ }
28
+
29
+ export type { ClientLink as C, FriendlyClientOptions as F, HTTPPath as H, InferClientContext as I, NestedClient as N, ClientPromiseResult as a, ClientContext as b, ClientOptions as c, Client as d, ClientRest as e, HTTPMethod as f };
@@ -0,0 +1,29 @@
1
+ import { PromiseWithError } from '@orpc/shared';
2
+
3
+ type HTTPPath = `/${string}`;
4
+ type HTTPMethod = 'HEAD' | 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
5
+ type ClientContext = Record<PropertyKey, any>;
6
+ interface ClientOptions<T extends ClientContext> {
7
+ signal?: AbortSignal;
8
+ lastEventId?: string | undefined;
9
+ context: T;
10
+ }
11
+ type FriendlyClientOptions<T extends ClientContext> = Omit<ClientOptions<T>, 'context'> & (Record<never, never> extends T ? {
12
+ context?: T;
13
+ } : {
14
+ context: T;
15
+ });
16
+ type ClientRest<TClientContext extends ClientContext, TInput> = Record<never, never> extends TClientContext ? undefined extends TInput ? [input?: TInput, options?: FriendlyClientOptions<TClientContext>] : [input: TInput, options?: FriendlyClientOptions<TClientContext>] : [input: TInput, options: FriendlyClientOptions<TClientContext>];
17
+ type ClientPromiseResult<TOutput, TError> = PromiseWithError<TOutput, TError>;
18
+ interface Client<TClientContext extends ClientContext, TInput, TOutput, TError> {
19
+ (...rest: ClientRest<TClientContext, TInput>): ClientPromiseResult<TOutput, TError>;
20
+ }
21
+ type NestedClient<TClientContext extends ClientContext> = Client<TClientContext, any, any, any> | {
22
+ [k: string]: NestedClient<TClientContext>;
23
+ };
24
+ type InferClientContext<T extends NestedClient<any>> = T extends NestedClient<infer U> ? U : never;
25
+ interface ClientLink<TClientContext extends ClientContext> {
26
+ call: (path: readonly string[], input: unknown, options: ClientOptions<TClientContext>) => Promise<unknown>;
27
+ }
28
+
29
+ export type { ClientLink as C, FriendlyClientOptions as F, HTTPPath as H, InferClientContext as I, NestedClient as N, ClientPromiseResult as a, ClientContext as b, ClientOptions as c, Client as d, ClientRest as e, HTTPMethod as f };
@@ -1,4 +1,4 @@
1
- import { isObject, isTypescriptObject } from '@orpc/shared';
1
+ import { resolveMaybeOptionalOptions, isObject, AsyncIteratorClass, isTypescriptObject } from '@orpc/shared';
2
2
  import { getEventMeta, withEventMeta } from '@orpc/standard-server';
3
3
 
4
4
  const COMMON_ORPC_ERROR_DEFS = {
@@ -90,16 +90,17 @@ class ORPCError extends Error {
90
90
  code;
91
91
  status;
92
92
  data;
93
- constructor(code, ...[options]) {
94
- if (options?.status && (options.status < 400 || options.status >= 600)) {
95
- throw new Error("[ORPCError] The error status code must be in the 400-599 range.");
93
+ constructor(code, ...rest) {
94
+ const options = resolveMaybeOptionalOptions(rest);
95
+ if (options.status !== void 0 && !isORPCErrorStatus(options.status)) {
96
+ throw new Error("[ORPCError] Invalid error status code.");
96
97
  }
97
- const message = fallbackORPCErrorMessage(code, options?.message);
98
+ const message = fallbackORPCErrorMessage(code, options.message);
98
99
  super(message, options);
99
100
  this.code = code;
100
- this.status = fallbackORPCErrorStatus(code, options?.status);
101
- this.defined = options?.defined ?? false;
102
- this.data = options?.data;
101
+ this.status = fallbackORPCErrorStatus(code, options.status);
102
+ this.defined = options.defined ?? false;
103
+ this.data = options.data;
103
104
  }
104
105
  toJSON() {
105
106
  return {
@@ -110,22 +111,6 @@ class ORPCError extends Error {
110
111
  data: this.data
111
112
  };
112
113
  }
113
- static fromJSON(json, options) {
114
- return new ORPCError(json.code, {
115
- ...options,
116
- ...json
117
- });
118
- }
119
- static isValidJSON(json) {
120
- if (!isObject(json)) {
121
- return false;
122
- }
123
- const validKeys = ["defined", "code", "status", "message", "data"];
124
- if (Object.keys(json).some((k) => !validKeys.includes(k))) {
125
- return false;
126
- }
127
- return "defined" in json && typeof json.defined === "boolean" && "code" in json && typeof json.code === "string" && "status" in json && typeof json.status === "number" && "message" in json && typeof json.message === "string";
128
- }
129
114
  }
130
115
  function isDefinedError(error) {
131
116
  return error instanceof ORPCError && error.defined;
@@ -136,37 +121,53 @@ function toORPCError(error) {
136
121
  cause: error
137
122
  });
138
123
  }
124
+ function isORPCErrorStatus(status) {
125
+ return status < 200 || status >= 400;
126
+ }
127
+ function isORPCErrorJson(json) {
128
+ if (!isObject(json)) {
129
+ return false;
130
+ }
131
+ const validKeys = ["defined", "code", "status", "message", "data"];
132
+ if (Object.keys(json).some((k) => !validKeys.includes(k))) {
133
+ return false;
134
+ }
135
+ return "defined" in json && typeof json.defined === "boolean" && "code" in json && typeof json.code === "string" && "status" in json && typeof json.status === "number" && isORPCErrorStatus(json.status) && "message" in json && typeof json.message === "string";
136
+ }
137
+ function createORPCErrorFromJson(json, options = {}) {
138
+ return new ORPCError(json.code, {
139
+ ...options,
140
+ ...json
141
+ });
142
+ }
139
143
 
140
144
  function mapEventIterator(iterator, maps) {
141
- return async function* () {
142
- try {
143
- while (true) {
144
- const { done, value } = await iterator.next();
145
- let mappedValue = await maps.value(value, done);
146
- if (mappedValue !== value) {
147
- const meta = getEventMeta(value);
148
- if (meta && isTypescriptObject(mappedValue)) {
149
- mappedValue = withEventMeta(mappedValue, meta);
145
+ return new AsyncIteratorClass(async () => {
146
+ const { done, value } = await (async () => {
147
+ try {
148
+ return await iterator.next();
149
+ } catch (error) {
150
+ let mappedError = await maps.error(error);
151
+ if (mappedError !== error) {
152
+ const meta = getEventMeta(error);
153
+ if (meta && isTypescriptObject(mappedError)) {
154
+ mappedError = withEventMeta(mappedError, meta);
150
155
  }
151
156
  }
152
- if (done) {
153
- return mappedValue;
154
- }
155
- yield mappedValue;
157
+ throw mappedError;
156
158
  }
157
- } catch (error) {
158
- let mappedError = await maps.error(error);
159
- if (mappedError !== error) {
160
- const meta = getEventMeta(error);
161
- if (meta && isTypescriptObject(mappedError)) {
162
- mappedError = withEventMeta(mappedError, meta);
163
- }
159
+ })();
160
+ let mappedValue = await maps.value(value, done);
161
+ if (mappedValue !== value) {
162
+ const meta = getEventMeta(value);
163
+ if (meta && isTypescriptObject(mappedValue)) {
164
+ mappedValue = withEventMeta(mappedValue, meta);
164
165
  }
165
- throw mappedError;
166
- } finally {
167
- await iterator.return?.();
168
166
  }
169
- }();
167
+ return { done, value: mappedValue };
168
+ }, async () => {
169
+ await iterator.return?.();
170
+ });
170
171
  }
171
172
 
172
- export { COMMON_ORPC_ERROR_DEFS as C, ORPCError as O, fallbackORPCErrorMessage as a, fallbackORPCErrorStatus as f, isDefinedError as i, mapEventIterator as m, toORPCError as t };
173
+ export { COMMON_ORPC_ERROR_DEFS as C, ORPCError as O, fallbackORPCErrorMessage as a, isORPCErrorStatus as b, isORPCErrorJson as c, createORPCErrorFromJson as d, fallbackORPCErrorStatus as f, isDefinedError as i, mapEventIterator as m, toORPCError as t };