@orpc/client 2.0.0-beta.4 → 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 (30) hide show
  1. package/README.md +97 -94
  2. package/dist/adapters/fetch/index.d.mts +16 -33
  3. package/dist/adapters/fetch/index.d.ts +16 -33
  4. package/dist/adapters/fetch/index.mjs +33 -30
  5. package/dist/adapters/message-port/index.d.mts +13 -8
  6. package/dist/adapters/message-port/index.d.ts +13 -8
  7. package/dist/adapters/message-port/index.mjs +27 -17
  8. package/dist/adapters/standard/index.d.mts +9 -10
  9. package/dist/adapters/standard/index.d.ts +9 -10
  10. package/dist/adapters/standard/index.mjs +5 -5
  11. package/dist/adapters/websocket/index.d.mts +33 -18
  12. package/dist/adapters/websocket/index.d.ts +33 -18
  13. package/dist/adapters/websocket/index.mjs +45 -24
  14. package/dist/index.d.mts +62 -61
  15. package/dist/index.d.ts +62 -61
  16. package/dist/index.mjs +47 -54
  17. package/dist/plugins/index.d.mts +174 -13
  18. package/dist/plugins/index.d.ts +174 -13
  19. package/dist/plugins/index.mjs +580 -198
  20. package/dist/shared/{client.BdItY5DT.d.mts → client.BPa_Mmuh.d.mts} +25 -4
  21. package/dist/shared/{client.BdItY5DT.d.ts → client.BPa_Mmuh.d.ts} +25 -4
  22. package/dist/shared/{client.Cby_-GGh.d.mts → client.BjbdW5Rj.d.mts} +2 -2
  23. package/dist/shared/{client.DXhchJ84.mjs → client.Bstqyaro.mjs} +25 -30
  24. package/dist/shared/{client.Dnfj8jnT.mjs → client.DD2eNne_.mjs} +20 -15
  25. package/dist/shared/{client.CPF3hX6O.d.ts → client.DiHfJmHK.d.ts} +2 -2
  26. package/dist/shared/client.DpkGsZt-.mjs +486 -0
  27. package/dist/shared/{client.8ug8I-zu.d.mts → client.Dw9_40WO.d.mts} +57 -16
  28. package/dist/shared/{client.8ug8I-zu.d.ts → client.Dw9_40WO.d.ts} +57 -16
  29. package/package.json +22 -8
  30. package/dist/shared/client.DMXKFDyV.mjs +0 -343
@@ -1,18 +1,19 @@
1
- import { runWithSignal, AbortError, sleep, promiseWithResolvers, toStringOrBytes } from '@orpc/shared';
2
- import { ClientPeer, encodePeerMessage, decodePeerMessage, isServerPeerSendMessage } from '@standardserver/peer';
3
- import { S as StandardLink, R as RPCLinkCodec } from '../../shared/client.DXhchJ84.mjs';
4
- import '@standardserver/core';
5
- import '@standardserver/fetch';
6
- import '../../shared/client.Dnfj8jnT.mjs';
7
- import '../../shared/client.DMXKFDyV.mjs';
1
+ import { runWithSignal, AbortError, sleep, promiseWithResolvers, sequential, loadBytes, toStringOrBytes } from '@orpc/shared';
2
+ import { ClientPeer, encodePeerMessage, decodePeerMessage, isServerPeerSendMessage } from '@standard-server/peer';
3
+ import { S as StandardLink, R as RPCLinkCodec } from '../../shared/client.Bstqyaro.mjs';
4
+ import '@standard-server/core';
5
+ import '@standard-server/fetch';
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;
11
- class WebsocketLinkTransport {
11
+ class WebSocketLinkTransport {
12
12
  connect;
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
  });
@@ -71,29 +79,42 @@ class WebsocketLinkTransport {
71
79
  connectingResolvers?.resolve();
72
80
  });
73
81
  }
74
- websocket.addEventListener("message", async (event) => {
75
- const message = await toStringOrBytes(event.data);
82
+ websocket.addEventListener("message", sequential(async (event) => {
83
+ const message = event.data instanceof Blob ? await loadBytes(event.data) : toStringOrBytes(event.data);
76
84
  const result = decodePeerMessage(message, this.decodePeerMessageOptions);
77
85
  if (result.matched && isServerPeerSendMessage(result.message)) {
78
- await peer.message(result.message);
86
+ peer.message(result.message);
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
  }
@@ -102,9 +123,9 @@ class WebsocketLinkTransport {
102
123
  class RPCLink extends StandardLink {
103
124
  constructor(options) {
104
125
  const codec = new RPCLinkCodec(options);
105
- const transport = new WebsocketLinkTransport(options);
126
+ const transport = new WebSocketLinkTransport(options);
106
127
  super(codec, transport, options);
107
128
  }
108
129
  }
109
130
 
110
- export { RPCLink, WebsocketLinkTransport };
131
+ export { RPCLink, WebSocketLinkTransport };
package/dist/index.d.mts CHANGED
@@ -1,15 +1,12 @@
1
- import { O as ORPCErrorCode, c as ORPCError, d as ORPCErrorJSON, A as AnyORPCError, C as ClientContext, a as ClientOptions, e as AnyNestedClient, I as InferClientContext, f as InferClientError, g as Client, b as ClientLink, h as ClientRest, F as FriendlyClientOptions } from './shared/client.8ug8I-zu.mjs';
2
- 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, N as NestedClient, p as ORPCErrorOptions } from './shared/client.8ug8I-zu.mjs';
3
- import { Interceptor, PromiseWithError, ThrowableError, Promisable, WrapAsyncIteratorOptions, AsyncIteratorClass } from '@orpc/shared';
4
- export { AsyncCleanupFn, AsyncIteratorClass, AsyncIteratorClassNextFn, MaybeOptionalOptions, PromiseWithError, Registry, ThrowableError, asyncIteratorToStream as eventIteratorToStream, asyncIteratorToUnproxiedDataStream as eventIteratorToUnproxiedDataStream, onError, onFinish, onStart, onSuccess, streamToAsyncIteratorClass as streamToEventIterator } from '@orpc/shared';
5
- 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.BdItY5DT.mjs';
6
- export { ErrorEvent, EventMeta, getEventMeta, unwrapEvent, withEventMeta } from '@standardserver/core';
1
+ import { WrapAsyncIteratorOptions, AsyncIteratorClass, Interceptor, PromiseWithError, ThrowableError, Promisable } from '@orpc/shared';
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.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
+ import { StandardResponse } from '@standard-server/core';
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.BPa_Mmuh.mjs';
7
8
 
8
- declare function isInferableError<T>(error: T): error is Extract<T, AnyORPCError>;
9
- declare function toORPCError<T>(error: T): Extract<T, AnyORPCError> | ORPCError<'INTERNAL_SERVER_ERROR', undefined>;
10
- declare function isORPCErrorJson(json: unknown): json is ORPCErrorJSON<ORPCErrorCode, unknown>;
11
- declare function createORPCErrorFromJson<TCode extends ORPCErrorCode, TData>(json: ORPCErrorJSON<TCode, TData>, options?: ErrorOptions): ORPCError<TCode, TData>;
12
- declare function cloneORPCError<T extends ORPCErrorCode, TData>(error: ORPCError<T, TData>): ORPCError<T, TData>;
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>;
13
10
 
14
11
  interface ORPCClientInterceptorOptions<TClientContext extends ClientContext, TInput> extends ClientOptions<TClientContext> {
15
12
  path: string[];
@@ -41,68 +38,49 @@ interface ORPCClientOptions<T extends AnyNestedClient> {
41
38
  */
42
39
  scoped?: ORPCClientScoped<T>;
43
40
  }
41
+ /**
42
+ * Creates a fully typed oRPC client from a link.
43
+ * The returned client mirrors the shape of your router or contract,
44
+ * so calling a procedure is as simple as calling a function.
45
+ *
46
+ * @see {@link https://orpc.dev/docs/client/client-side | Client-Side Clients}
47
+ */
44
48
  declare function createORPCClient<T extends AnyNestedClient>(link: ClientLink<InferClientContext<T>>, { path, ...options }?: NoInfer<ORPCClientOptions<T>>): T;
45
49
 
46
50
  declare function resolveFriendlyClientOptions<T extends ClientContext>(options: FriendlyClientOptions<T>): ClientOptions<T>;
47
51
  declare function resolveClientRest<TClientContext extends ClientContext, TInput>(rest: ClientRest<TClientContext, TInput>): [input: TInput, options: ClientOptions<TClientContext>];
48
- type SafeResult<TOutput, TError> = [error: null, data: TOutput, inferableError: null, isSuccess: true] & {
52
+ type SafeResult<TOutput, TError> = [error: null, data: TOutput, definedError: null, isSuccess: true] & {
49
53
  error: null;
50
54
  data: TOutput;
51
- inferableError: null;
55
+ definedError: null;
52
56
  isSuccess: true;
53
- } | [error: Exclude<TError, AnyORPCError>, data: undefined, inferableError: null, isSuccess: false] & {
57
+ } | [error: Exclude<TError, AnyORPCError>, data: undefined, definedError: null, isSuccess: false] & {
54
58
  error: Exclude<TError, AnyORPCError>;
55
59
  data: undefined;
56
- inferableError: null;
60
+ definedError: null;
57
61
  isSuccess: false;
58
- } | [error: Extract<TError, AnyORPCError>, data: undefined, inferableError: Extract<TError, AnyORPCError>, isSuccess: false] & {
62
+ } | [error: Extract<TError, AnyORPCError>, data: undefined, definedError: Extract<TError, AnyORPCError>, isSuccess: false] & {
59
63
  error: Extract<TError, AnyORPCError>;
60
64
  data: undefined;
61
- inferableError: Extract<TError, AnyORPCError>;
65
+ definedError: Extract<TError, AnyORPCError>;
62
66
  isSuccess: false;
63
67
  };
64
68
  /**
65
- * Works like try/catch, but help you infer the error type if it is inferable ORPCError.
69
+ * Works like try/catch, but help you infer the error type if it is a defined ORPCError.
66
70
  *
67
71
  * @example
68
72
  * ```ts
69
- * const [error, data, inferableError, isSuccess] = await safe(client(...))
70
- * // or const { error, data, inferableError, isSuccess } = await safe(client(...))
73
+ * const [error, data, definedError, isSuccess] = await safe(client(...))
74
+ * // or const { error, data, definedError, isSuccess } = await safe(client(...))
71
75
  *
72
- * if (inferableError) {
73
- * console.log(inferableError) // or error, both are well typed
76
+ * if (definedError) {
77
+ * console.log(definedError) // or error, both are well typed
74
78
  * }
75
- */
76
- declare function safe<TOutput, TError = ThrowableError>(promise: PromiseWithError<TOutput, TError>): Promise<SafeResult<TOutput, TError>>;
77
- interface ConsumeEventIteratorOptions<T, TReturn, TError> {
78
- /**
79
- * Called on each event
80
- */
81
- onEvent: (event: T) => void;
82
- /**
83
- * Called once error happens
84
- */
85
- onError?: (error: TError) => void;
86
- /**
87
- * Called once event iterator is done
88
- *
89
- * @info If iterator is canceled, `undefined` can be passed on success
90
- */
91
- onSuccess?: (value: TReturn | undefined) => void;
92
- /**
93
- * Called once after onError or onSuccess
94
- *
95
- * @info If iterator is canceled, `undefined` can be passed on success
96
- */
97
- onFinish?: (state: [error: TError, data: undefined, isSuccess: false] | [error: null, data: TReturn | undefined, isSuccess: true]) => void;
98
- }
99
- /**
100
- * Consumes an event iterator with lifecycle callbacks
79
+ * ```
101
80
  *
102
- * @warning If no `onError` or `onFinish` is provided, error will be thrown into unhandled rejection channel.
103
- * @return unsubscribe callback
81
+ * @see {@link https://orpc.dev/docs/client/error-handling#using-safe-and-isdefinederror | Client Error Handling - Using safe and isDefinedError}
104
82
  */
105
- declare function consumeEventIterator<T, TReturn, TError = ThrowableError>(iterator: AsyncIterator<T, TReturn> | PromiseWithError<AsyncIterator<T, TReturn>, TError>, options: ConsumeEventIteratorOptions<T, TReturn, TError>): () => Promise<void>;
83
+ declare function safe<TOutput, TError = ThrowableError>(promise: PromiseWithError<TOutput, TError>): Promise<SafeResult<TOutput, TError>>;
106
84
 
107
85
  type SafeClient<T extends AnyNestedClient> = T extends Client<infer UContext, infer UInput, infer UOutput, infer UError> ? (...rest: ClientRest<UContext, UInput>) => Promise<SafeResult<UOutput, UError>> : {
108
86
  [K in keyof T]: T[K] extends AnyNestedClient ? SafeClient<T[K]> : never;
@@ -113,11 +91,11 @@ type SafeClient<T extends AnyNestedClient> = T extends Client<infer UContext, in
113
91
  * @example
114
92
  * ```ts
115
93
  * const safeClient = createSafeClient(client)
116
- * const { error, data, inferrableError, isSuccess } = await safeClient.doSomething({ id: '123' })
117
- * // or const [error, data, inferrableError, isSuccess] = await safeClient.doSomething({ id: '123' })
94
+ * const { error, data, definedError, isSuccess } = await safeClient.doSomething({ id: '123' })
95
+ * // or const [error, data, definedError, isSuccess] = await safeClient.doSomething({ id: '123' })
118
96
  * ```
119
97
  *
120
- * @see {@link https://orpc.dev/docs/client/error-handling#using-createsafeclient Safe Client Docs}
98
+ * @see {@link https://orpc.dev/docs/client/error-handling#safe-client | Client Error Handling - Safe Client}
121
99
  */
122
100
  declare function createSafeClient<T extends AnyNestedClient>(client: T): SafeClient<T>;
123
101
 
@@ -136,7 +114,7 @@ declare const RECURSIVE_CLIENT_UNWRAP_KEYS: Set<string>;
136
114
  * DynamicLink provides a way to dynamically resolve and delegate calls to other ClientLinks
137
115
  * based on the request path, input, and context.
138
116
  *
139
- * @see {@link https://orpc.dev/docs/client/dynamic-link Dynamic Link Docs}
117
+ * @see {@link https://orpc.dev/docs/client/dynamic-link | DynamicLink}
140
118
  */
141
119
  declare class DynamicLink<TClientContext extends ClientContext> implements ClientLink<TClientContext> {
142
120
  private readonly linkResolver;
@@ -144,12 +122,35 @@ declare class DynamicLink<TClientContext extends ClientContext> implements Clien
144
122
  call(path: string[], input: unknown, options: ClientOptions<TClientContext>): Promise<unknown>;
145
123
  }
146
124
 
147
- declare function wrapEventIteratorPreservingMeta<TYield, TReturn, TMappedYield = TYield, TMappedReturn = TReturn>(iterator: AsyncIterator<TYield, TReturn>, { mapResult, mapError, ...rest }: WrapAsyncIteratorOptions<TYield, TReturn, TMappedYield, TMappedReturn>): AsyncIteratorClass<TMappedYield, TMappedReturn>;
148
-
149
125
  /**
150
- * @deprecated Use `isInferableError` instead.
126
+ * Checks if an error is an `ORPCError` that matches a definition in the procedure's `.errors` map,
127
+ * narrowing it so `code` and `data` are fully typed.
128
+ *
129
+ * @see {@link https://orpc.dev/docs/client/error-handling#using-safe-and-isdefinederror | Client Error Handling - Using safe and isDefinedError}
130
+ */
131
+ declare function isDefinedError<T>(error: T): error is Extract<T, AnyORPCError>;
132
+ declare function toORPCError<T>(error: T): Extract<T, AnyORPCError> | ORPCError<'INTERNAL_SERVER_ERROR', undefined>;
133
+ declare function isORPCErrorJson(json: unknown): json is ORPCErrorJSON<ORPCErrorCode, unknown>;
134
+ declare function createORPCErrorFromJson<TCode extends ORPCErrorCode, TData>(json: ORPCErrorJSON<TCode, TData>, options?: ErrorOptions): ORPCError<TCode, TData>;
135
+ /**
136
+ * Creates the `MALFORMED_ORPC_RESPONSE` `ORPCError` used when a response
137
+ * does not follow the expected oRPC format. Unless overridden via `options.message`,
138
+ * the message is inferred from the response body or status. The `cause` is a
139
+ * `MalformedResponseError` carrying the resolved response.
140
+ *
141
+ * @see {@link https://orpc.dev/docs/rpc/link#malformed-responses | RPC Link - Malformed Responses}
142
+ * @see {@link https://orpc.dev/docs/openapi/link#malformed-responses | OpenAPI Link - Malformed Responses}
143
+ */
144
+ declare function createORPCErrorFromMalformedResponse(options: MalformedResponseErrorOptions): ORPCError<'MALFORMED_ORPC_RESPONSE', StandardResponse>;
145
+ /**
146
+ * Clones an `ORPCError` while preserving its prototype chain, so instances of
147
+ * `ORPCError` subclasses remain `instanceof` their class.
148
+ *
149
+ * Limitation: subclass constructors are not re-run, so private fields
150
+ * (`#field`) are not carried over and subclass members that read them
151
+ * will throw on the clone.
151
152
  */
152
- declare const isDefinedError: typeof isInferableError;
153
+ declare function cloneORPCError<T extends AnyORPCError>(error: T): T;
153
154
 
154
- export { AnyNestedClient, AnyORPCError, Client, ClientContext, ClientLink, ClientOptions, ClientRest, DynamicLink, FriendlyClientOptions, InferClientContext, InferClientError, ORPCError, ORPCErrorCode, ORPCErrorJSON, RECURSIVE_CLIENT_UNWRAP_KEYS, cloneORPCError, consumeEventIterator, createORPCClient, createORPCErrorFromJson, createSafeClient, isDefinedError, isInferableError, isORPCErrorJson, resolveClientRest, resolveFriendlyClientOptions, safe, toORPCError, wrapEventIteratorPreservingMeta };
155
- export type { ConsumeEventIteratorOptions, ORPCClientInterceptor, ORPCClientInterceptorOptions, ORPCClientOptions, ORPCClientScoped, ORPCClientScopedOptions, SafeClient, SafeResult };
155
+ export { AnyNestedClient, AnyORPCError, Client, ClientContext, ClientLink, ClientOptions, ClientRest, DynamicLink, FriendlyClientOptions, InferClientContext, InferClientError, InferClientError as InferClientErrorUnion, MalformedResponseErrorOptions, ORPCError, ORPCErrorCode, ORPCErrorJSON, RECURSIVE_CLIENT_UNWRAP_KEYS, cloneORPCError, createORPCClient, createORPCErrorFromJson, createORPCErrorFromMalformedResponse, createSafeClient, isDefinedError, isORPCErrorJson, resolveClientRest, resolveFriendlyClientOptions, safe, toORPCError, wrapAsyncIteratorPreservingEventMeta };
156
+ export type { ORPCClientInterceptor, ORPCClientInterceptorOptions, ORPCClientOptions, ORPCClientScoped, ORPCClientScopedOptions, SafeClient, SafeResult };
package/dist/index.d.ts CHANGED
@@ -1,15 +1,12 @@
1
- import { O as ORPCErrorCode, c as ORPCError, d as ORPCErrorJSON, A as AnyORPCError, C as ClientContext, a as ClientOptions, e as AnyNestedClient, I as InferClientContext, f as InferClientError, g as Client, b as ClientLink, h as ClientRest, F as FriendlyClientOptions } from './shared/client.8ug8I-zu.js';
2
- 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, N as NestedClient, p as ORPCErrorOptions } from './shared/client.8ug8I-zu.js';
3
- import { Interceptor, PromiseWithError, ThrowableError, Promisable, WrapAsyncIteratorOptions, AsyncIteratorClass } from '@orpc/shared';
4
- export { AsyncCleanupFn, AsyncIteratorClass, AsyncIteratorClassNextFn, MaybeOptionalOptions, PromiseWithError, Registry, ThrowableError, asyncIteratorToStream as eventIteratorToStream, asyncIteratorToUnproxiedDataStream as eventIteratorToUnproxiedDataStream, onError, onFinish, onStart, onSuccess, streamToAsyncIteratorClass as streamToEventIterator } from '@orpc/shared';
5
- 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.BdItY5DT.js';
6
- export { ErrorEvent, EventMeta, getEventMeta, unwrapEvent, withEventMeta } from '@standardserver/core';
1
+ import { WrapAsyncIteratorOptions, AsyncIteratorClass, Interceptor, PromiseWithError, ThrowableError, Promisable } from '@orpc/shared';
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.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
+ import { StandardResponse } from '@standard-server/core';
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.BPa_Mmuh.js';
7
8
 
8
- declare function isInferableError<T>(error: T): error is Extract<T, AnyORPCError>;
9
- declare function toORPCError<T>(error: T): Extract<T, AnyORPCError> | ORPCError<'INTERNAL_SERVER_ERROR', undefined>;
10
- declare function isORPCErrorJson(json: unknown): json is ORPCErrorJSON<ORPCErrorCode, unknown>;
11
- declare function createORPCErrorFromJson<TCode extends ORPCErrorCode, TData>(json: ORPCErrorJSON<TCode, TData>, options?: ErrorOptions): ORPCError<TCode, TData>;
12
- declare function cloneORPCError<T extends ORPCErrorCode, TData>(error: ORPCError<T, TData>): ORPCError<T, TData>;
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>;
13
10
 
14
11
  interface ORPCClientInterceptorOptions<TClientContext extends ClientContext, TInput> extends ClientOptions<TClientContext> {
15
12
  path: string[];
@@ -41,68 +38,49 @@ interface ORPCClientOptions<T extends AnyNestedClient> {
41
38
  */
42
39
  scoped?: ORPCClientScoped<T>;
43
40
  }
41
+ /**
42
+ * Creates a fully typed oRPC client from a link.
43
+ * The returned client mirrors the shape of your router or contract,
44
+ * so calling a procedure is as simple as calling a function.
45
+ *
46
+ * @see {@link https://orpc.dev/docs/client/client-side | Client-Side Clients}
47
+ */
44
48
  declare function createORPCClient<T extends AnyNestedClient>(link: ClientLink<InferClientContext<T>>, { path, ...options }?: NoInfer<ORPCClientOptions<T>>): T;
45
49
 
46
50
  declare function resolveFriendlyClientOptions<T extends ClientContext>(options: FriendlyClientOptions<T>): ClientOptions<T>;
47
51
  declare function resolveClientRest<TClientContext extends ClientContext, TInput>(rest: ClientRest<TClientContext, TInput>): [input: TInput, options: ClientOptions<TClientContext>];
48
- type SafeResult<TOutput, TError> = [error: null, data: TOutput, inferableError: null, isSuccess: true] & {
52
+ type SafeResult<TOutput, TError> = [error: null, data: TOutput, definedError: null, isSuccess: true] & {
49
53
  error: null;
50
54
  data: TOutput;
51
- inferableError: null;
55
+ definedError: null;
52
56
  isSuccess: true;
53
- } | [error: Exclude<TError, AnyORPCError>, data: undefined, inferableError: null, isSuccess: false] & {
57
+ } | [error: Exclude<TError, AnyORPCError>, data: undefined, definedError: null, isSuccess: false] & {
54
58
  error: Exclude<TError, AnyORPCError>;
55
59
  data: undefined;
56
- inferableError: null;
60
+ definedError: null;
57
61
  isSuccess: false;
58
- } | [error: Extract<TError, AnyORPCError>, data: undefined, inferableError: Extract<TError, AnyORPCError>, isSuccess: false] & {
62
+ } | [error: Extract<TError, AnyORPCError>, data: undefined, definedError: Extract<TError, AnyORPCError>, isSuccess: false] & {
59
63
  error: Extract<TError, AnyORPCError>;
60
64
  data: undefined;
61
- inferableError: Extract<TError, AnyORPCError>;
65
+ definedError: Extract<TError, AnyORPCError>;
62
66
  isSuccess: false;
63
67
  };
64
68
  /**
65
- * Works like try/catch, but help you infer the error type if it is inferable ORPCError.
69
+ * Works like try/catch, but help you infer the error type if it is a defined ORPCError.
66
70
  *
67
71
  * @example
68
72
  * ```ts
69
- * const [error, data, inferableError, isSuccess] = await safe(client(...))
70
- * // or const { error, data, inferableError, isSuccess } = await safe(client(...))
73
+ * const [error, data, definedError, isSuccess] = await safe(client(...))
74
+ * // or const { error, data, definedError, isSuccess } = await safe(client(...))
71
75
  *
72
- * if (inferableError) {
73
- * console.log(inferableError) // or error, both are well typed
76
+ * if (definedError) {
77
+ * console.log(definedError) // or error, both are well typed
74
78
  * }
75
- */
76
- declare function safe<TOutput, TError = ThrowableError>(promise: PromiseWithError<TOutput, TError>): Promise<SafeResult<TOutput, TError>>;
77
- interface ConsumeEventIteratorOptions<T, TReturn, TError> {
78
- /**
79
- * Called on each event
80
- */
81
- onEvent: (event: T) => void;
82
- /**
83
- * Called once error happens
84
- */
85
- onError?: (error: TError) => void;
86
- /**
87
- * Called once event iterator is done
88
- *
89
- * @info If iterator is canceled, `undefined` can be passed on success
90
- */
91
- onSuccess?: (value: TReturn | undefined) => void;
92
- /**
93
- * Called once after onError or onSuccess
94
- *
95
- * @info If iterator is canceled, `undefined` can be passed on success
96
- */
97
- onFinish?: (state: [error: TError, data: undefined, isSuccess: false] | [error: null, data: TReturn | undefined, isSuccess: true]) => void;
98
- }
99
- /**
100
- * Consumes an event iterator with lifecycle callbacks
79
+ * ```
101
80
  *
102
- * @warning If no `onError` or `onFinish` is provided, error will be thrown into unhandled rejection channel.
103
- * @return unsubscribe callback
81
+ * @see {@link https://orpc.dev/docs/client/error-handling#using-safe-and-isdefinederror | Client Error Handling - Using safe and isDefinedError}
104
82
  */
105
- declare function consumeEventIterator<T, TReturn, TError = ThrowableError>(iterator: AsyncIterator<T, TReturn> | PromiseWithError<AsyncIterator<T, TReturn>, TError>, options: ConsumeEventIteratorOptions<T, TReturn, TError>): () => Promise<void>;
83
+ declare function safe<TOutput, TError = ThrowableError>(promise: PromiseWithError<TOutput, TError>): Promise<SafeResult<TOutput, TError>>;
106
84
 
107
85
  type SafeClient<T extends AnyNestedClient> = T extends Client<infer UContext, infer UInput, infer UOutput, infer UError> ? (...rest: ClientRest<UContext, UInput>) => Promise<SafeResult<UOutput, UError>> : {
108
86
  [K in keyof T]: T[K] extends AnyNestedClient ? SafeClient<T[K]> : never;
@@ -113,11 +91,11 @@ type SafeClient<T extends AnyNestedClient> = T extends Client<infer UContext, in
113
91
  * @example
114
92
  * ```ts
115
93
  * const safeClient = createSafeClient(client)
116
- * const { error, data, inferrableError, isSuccess } = await safeClient.doSomething({ id: '123' })
117
- * // or const [error, data, inferrableError, isSuccess] = await safeClient.doSomething({ id: '123' })
94
+ * const { error, data, definedError, isSuccess } = await safeClient.doSomething({ id: '123' })
95
+ * // or const [error, data, definedError, isSuccess] = await safeClient.doSomething({ id: '123' })
118
96
  * ```
119
97
  *
120
- * @see {@link https://orpc.dev/docs/client/error-handling#using-createsafeclient Safe Client Docs}
98
+ * @see {@link https://orpc.dev/docs/client/error-handling#safe-client | Client Error Handling - Safe Client}
121
99
  */
122
100
  declare function createSafeClient<T extends AnyNestedClient>(client: T): SafeClient<T>;
123
101
 
@@ -136,7 +114,7 @@ declare const RECURSIVE_CLIENT_UNWRAP_KEYS: Set<string>;
136
114
  * DynamicLink provides a way to dynamically resolve and delegate calls to other ClientLinks
137
115
  * based on the request path, input, and context.
138
116
  *
139
- * @see {@link https://orpc.dev/docs/client/dynamic-link Dynamic Link Docs}
117
+ * @see {@link https://orpc.dev/docs/client/dynamic-link | DynamicLink}
140
118
  */
141
119
  declare class DynamicLink<TClientContext extends ClientContext> implements ClientLink<TClientContext> {
142
120
  private readonly linkResolver;
@@ -144,12 +122,35 @@ declare class DynamicLink<TClientContext extends ClientContext> implements Clien
144
122
  call(path: string[], input: unknown, options: ClientOptions<TClientContext>): Promise<unknown>;
145
123
  }
146
124
 
147
- declare function wrapEventIteratorPreservingMeta<TYield, TReturn, TMappedYield = TYield, TMappedReturn = TReturn>(iterator: AsyncIterator<TYield, TReturn>, { mapResult, mapError, ...rest }: WrapAsyncIteratorOptions<TYield, TReturn, TMappedYield, TMappedReturn>): AsyncIteratorClass<TMappedYield, TMappedReturn>;
148
-
149
125
  /**
150
- * @deprecated Use `isInferableError` instead.
126
+ * Checks if an error is an `ORPCError` that matches a definition in the procedure's `.errors` map,
127
+ * narrowing it so `code` and `data` are fully typed.
128
+ *
129
+ * @see {@link https://orpc.dev/docs/client/error-handling#using-safe-and-isdefinederror | Client Error Handling - Using safe and isDefinedError}
130
+ */
131
+ declare function isDefinedError<T>(error: T): error is Extract<T, AnyORPCError>;
132
+ declare function toORPCError<T>(error: T): Extract<T, AnyORPCError> | ORPCError<'INTERNAL_SERVER_ERROR', undefined>;
133
+ declare function isORPCErrorJson(json: unknown): json is ORPCErrorJSON<ORPCErrorCode, unknown>;
134
+ declare function createORPCErrorFromJson<TCode extends ORPCErrorCode, TData>(json: ORPCErrorJSON<TCode, TData>, options?: ErrorOptions): ORPCError<TCode, TData>;
135
+ /**
136
+ * Creates the `MALFORMED_ORPC_RESPONSE` `ORPCError` used when a response
137
+ * does not follow the expected oRPC format. Unless overridden via `options.message`,
138
+ * the message is inferred from the response body or status. The `cause` is a
139
+ * `MalformedResponseError` carrying the resolved response.
140
+ *
141
+ * @see {@link https://orpc.dev/docs/rpc/link#malformed-responses | RPC Link - Malformed Responses}
142
+ * @see {@link https://orpc.dev/docs/openapi/link#malformed-responses | OpenAPI Link - Malformed Responses}
143
+ */
144
+ declare function createORPCErrorFromMalformedResponse(options: MalformedResponseErrorOptions): ORPCError<'MALFORMED_ORPC_RESPONSE', StandardResponse>;
145
+ /**
146
+ * Clones an `ORPCError` while preserving its prototype chain, so instances of
147
+ * `ORPCError` subclasses remain `instanceof` their class.
148
+ *
149
+ * Limitation: subclass constructors are not re-run, so private fields
150
+ * (`#field`) are not carried over and subclass members that read them
151
+ * will throw on the clone.
151
152
  */
152
- declare const isDefinedError: typeof isInferableError;
153
+ declare function cloneORPCError<T extends AnyORPCError>(error: T): T;
153
154
 
154
- export { AnyNestedClient, AnyORPCError, Client, ClientContext, ClientLink, ClientOptions, ClientRest, DynamicLink, FriendlyClientOptions, InferClientContext, InferClientError, ORPCError, ORPCErrorCode, ORPCErrorJSON, RECURSIVE_CLIENT_UNWRAP_KEYS, cloneORPCError, consumeEventIterator, createORPCClient, createORPCErrorFromJson, createSafeClient, isDefinedError, isInferableError, isORPCErrorJson, resolveClientRest, resolveFriendlyClientOptions, safe, toORPCError, wrapEventIteratorPreservingMeta };
155
- export type { ConsumeEventIteratorOptions, ORPCClientInterceptor, ORPCClientInterceptorOptions, ORPCClientOptions, ORPCClientScoped, ORPCClientScopedOptions, SafeClient, SafeResult };
155
+ export { AnyNestedClient, AnyORPCError, Client, ClientContext, ClientLink, ClientOptions, ClientRest, DynamicLink, FriendlyClientOptions, InferClientContext, InferClientError, InferClientError as InferClientErrorUnion, MalformedResponseErrorOptions, ORPCError, ORPCErrorCode, ORPCErrorJSON, RECURSIVE_CLIENT_UNWRAP_KEYS, cloneORPCError, createORPCClient, createORPCErrorFromJson, createORPCErrorFromMalformedResponse, createSafeClient, isDefinedError, isORPCErrorJson, resolveClientRest, resolveFriendlyClientOptions, safe, toORPCError, wrapAsyncIteratorPreservingEventMeta };
156
+ export type { ORPCClientInterceptor, ORPCClientInterceptorOptions, ORPCClientOptions, ORPCClientScoped, ORPCClientScopedOptions, SafeClient, SafeResult };