@orpc/client 0.0.0-next.d16a1b6 → 0.0.0-next.d3b4900

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.
package/dist/index.mjs CHANGED
@@ -1,17 +1,41 @@
1
- import { i as isDefinedError } from './shared/client.DcaJQZfy.mjs';
2
- export { C as COMMON_ORPC_ERROR_DEFS, O as ORPCError, c as createAutoRetryEventIterator, a as fallbackORPCErrorMessage, f as fallbackORPCErrorStatus, m as mapEventIterator, o as onEventIteratorStatusChange, r as registerEventIteratorState, t as toORPCError, u as updateEventIteratorStatus } from './shared/client.DcaJQZfy.mjs';
1
+ import { i as isDefinedError } from './shared/client.BacCdg3F.mjs';
2
+ export { C as COMMON_ORPC_ERROR_DEFS, O as ORPCError, a as fallbackORPCErrorMessage, f as fallbackORPCErrorStatus, m as mapEventIterator, t as toORPCError } from './shared/client.BacCdg3F.mjs';
3
+ export { onError, onFinish, onStart, onSuccess } from '@orpc/shared';
3
4
  export { ErrorEvent } from '@orpc/standard-server';
4
- import '@orpc/shared';
5
+
6
+ async function safe(promise) {
7
+ try {
8
+ const output = await promise;
9
+ return Object.assign(
10
+ [null, output, false],
11
+ { error: null, data: output, isDefined: false }
12
+ );
13
+ } catch (e) {
14
+ const error = e;
15
+ if (isDefinedError(error)) {
16
+ return Object.assign(
17
+ [error, void 0, true],
18
+ { error, data: void 0, isDefined: true }
19
+ );
20
+ }
21
+ return Object.assign(
22
+ [error, void 0, false],
23
+ { error, data: void 0, isDefined: false }
24
+ );
25
+ }
26
+ }
27
+ function resolveFriendlyClientOptions(options) {
28
+ return {
29
+ ...options,
30
+ context: options?.context ?? {}
31
+ // Context only optional if all fields are optional
32
+ };
33
+ }
5
34
 
6
35
  function createORPCClient(link, options) {
7
36
  const path = options?.path ?? [];
8
- const procedureClient = async (...[input, options2]) => {
9
- const optionsOut = {
10
- ...options2,
11
- context: options2?.context ?? {}
12
- // options.context can be undefined when all field is optional
13
- };
14
- return await link.call(path, input, optionsOut);
37
+ const procedureClient = async (...[input, options2 = {}]) => {
38
+ return await link.call(path, input, resolveFriendlyClientOptions(options2));
15
39
  };
16
40
  const recursive = new Proxy(procedureClient, {
17
41
  get(target, key) {
@@ -38,26 +62,4 @@ class DynamicLink {
38
62
  }
39
63
  }
40
64
 
41
- async function safe(promise) {
42
- try {
43
- const output = await promise;
44
- return Object.assign(
45
- [null, output, false],
46
- { error: null, data: output, isDefined: false }
47
- );
48
- } catch (e) {
49
- const error = e;
50
- if (isDefinedError(error)) {
51
- return Object.assign(
52
- [error, void 0, true],
53
- { error, data: void 0, isDefined: true }
54
- );
55
- }
56
- return Object.assign(
57
- [error, void 0, false],
58
- { error, data: void 0, isDefined: false }
59
- );
60
- }
61
- }
62
-
63
- export { DynamicLink, createORPCClient, isDefinedError, safe };
65
+ export { DynamicLink, createORPCClient, isDefinedError, resolveFriendlyClientOptions, safe };
@@ -0,0 +1,61 @@
1
+ import { Value } from '@orpc/shared';
2
+ import { S as StandardLinkPlugin, a as StandardLinkOptions } from '../shared/client.CKw2tbcl.mjs';
3
+ import { C as ClientOptions } from '../shared/client.RZs5Myak.mjs';
4
+ import '@orpc/standard-server';
5
+
6
+ interface ClientRetryPluginAttemptOptions {
7
+ lastEventRetry: number | undefined;
8
+ lastEventId: string | undefined;
9
+ attemptIndex: number;
10
+ error: unknown;
11
+ }
12
+ interface ClientRetryPluginContext {
13
+ /**
14
+ * Maximum retry attempts before throwing
15
+ * Use `Number.POSITIVE_INFINITY` for infinite retries (e.g., when handling Server-Sent Events).
16
+ *
17
+ * @default 0
18
+ */
19
+ retry?: number;
20
+ /**
21
+ * Delay (in ms) before retrying.
22
+ *
23
+ * @default (o) => o.lastEventRetry ?? 2000
24
+ */
25
+ retryDelay?: Value<number, [
26
+ attemptOptions: ClientRetryPluginAttemptOptions,
27
+ clientOptions: ClientOptions<ClientRetryPluginContext>,
28
+ path: readonly string[],
29
+ input: unknown
30
+ ]>;
31
+ /**
32
+ * Determine should retry or not.
33
+ *
34
+ * @default true
35
+ */
36
+ shouldRetry?: Value<boolean, [
37
+ attemptOptions: ClientRetryPluginAttemptOptions,
38
+ clientOptions: ClientOptions<ClientRetryPluginContext>,
39
+ path: readonly string[],
40
+ input: unknown
41
+ ]>;
42
+ /**
43
+ * The hook called when retrying, and return the unsubscribe function.
44
+ */
45
+ onRetry?: (options: ClientRetryPluginAttemptOptions, clientOptions: ClientOptions<ClientRetryPluginContext>, path: readonly string[], input: unknown) => void | (() => void);
46
+ }
47
+ declare class ClientRetryPluginInvalidEventIteratorRetryResponse extends Error {
48
+ }
49
+ interface ClientRetryPluginOptions {
50
+ default?: ClientRetryPluginContext;
51
+ }
52
+ declare class ClientRetryPlugin<T extends ClientRetryPluginContext> implements StandardLinkPlugin<T> {
53
+ private readonly defaultRetry;
54
+ private readonly defaultRetryDelay;
55
+ private readonly defaultShouldRetry;
56
+ private readonly defaultOnRetry;
57
+ constructor(options?: ClientRetryPluginOptions);
58
+ init(options: StandardLinkOptions<T>): void;
59
+ }
60
+
61
+ export { ClientRetryPlugin, type ClientRetryPluginAttemptOptions, type ClientRetryPluginContext, ClientRetryPluginInvalidEventIteratorRetryResponse, type ClientRetryPluginOptions };
@@ -0,0 +1,61 @@
1
+ import { Value } from '@orpc/shared';
2
+ import { S as StandardLinkPlugin, a as StandardLinkOptions } from '../shared/client.Bt40CWA-.js';
3
+ import { C as ClientOptions } from '../shared/client.RZs5Myak.js';
4
+ import '@orpc/standard-server';
5
+
6
+ interface ClientRetryPluginAttemptOptions {
7
+ lastEventRetry: number | undefined;
8
+ lastEventId: string | undefined;
9
+ attemptIndex: number;
10
+ error: unknown;
11
+ }
12
+ interface ClientRetryPluginContext {
13
+ /**
14
+ * Maximum retry attempts before throwing
15
+ * Use `Number.POSITIVE_INFINITY` for infinite retries (e.g., when handling Server-Sent Events).
16
+ *
17
+ * @default 0
18
+ */
19
+ retry?: number;
20
+ /**
21
+ * Delay (in ms) before retrying.
22
+ *
23
+ * @default (o) => o.lastEventRetry ?? 2000
24
+ */
25
+ retryDelay?: Value<number, [
26
+ attemptOptions: ClientRetryPluginAttemptOptions,
27
+ clientOptions: ClientOptions<ClientRetryPluginContext>,
28
+ path: readonly string[],
29
+ input: unknown
30
+ ]>;
31
+ /**
32
+ * Determine should retry or not.
33
+ *
34
+ * @default true
35
+ */
36
+ shouldRetry?: Value<boolean, [
37
+ attemptOptions: ClientRetryPluginAttemptOptions,
38
+ clientOptions: ClientOptions<ClientRetryPluginContext>,
39
+ path: readonly string[],
40
+ input: unknown
41
+ ]>;
42
+ /**
43
+ * The hook called when retrying, and return the unsubscribe function.
44
+ */
45
+ onRetry?: (options: ClientRetryPluginAttemptOptions, clientOptions: ClientOptions<ClientRetryPluginContext>, path: readonly string[], input: unknown) => void | (() => void);
46
+ }
47
+ declare class ClientRetryPluginInvalidEventIteratorRetryResponse extends Error {
48
+ }
49
+ interface ClientRetryPluginOptions {
50
+ default?: ClientRetryPluginContext;
51
+ }
52
+ declare class ClientRetryPlugin<T extends ClientRetryPluginContext> implements StandardLinkPlugin<T> {
53
+ private readonly defaultRetry;
54
+ private readonly defaultRetryDelay;
55
+ private readonly defaultShouldRetry;
56
+ private readonly defaultOnRetry;
57
+ constructor(options?: ClientRetryPluginOptions);
58
+ init(options: StandardLinkOptions<T>): void;
59
+ }
60
+
61
+ export { ClientRetryPlugin, type ClientRetryPluginAttemptOptions, type ClientRetryPluginContext, ClientRetryPluginInvalidEventIteratorRetryResponse, type ClientRetryPluginOptions };
@@ -0,0 +1,126 @@
1
+ import { isAsyncIteratorObject, value } from '@orpc/shared';
2
+ import { getEventMeta } from '@orpc/standard-server';
3
+
4
+ class ClientRetryPluginInvalidEventIteratorRetryResponse extends Error {
5
+ }
6
+ class ClientRetryPlugin {
7
+ defaultRetry;
8
+ defaultRetryDelay;
9
+ defaultShouldRetry;
10
+ defaultOnRetry;
11
+ constructor(options = {}) {
12
+ this.defaultRetry = options.default?.retry ?? 0;
13
+ this.defaultRetryDelay = options.default?.retryDelay ?? ((o) => o.lastEventRetry ?? 2e3);
14
+ this.defaultShouldRetry = options.default?.shouldRetry ?? true;
15
+ this.defaultOnRetry = options.default?.onRetry;
16
+ }
17
+ init(options) {
18
+ options.interceptors ??= [];
19
+ options.interceptors.push(async (interceptorOptions) => {
20
+ const maxAttempts = interceptorOptions.options.context.retry ?? this.defaultRetry;
21
+ const retryDelay = interceptorOptions.options.context.retryDelay ?? this.defaultRetryDelay;
22
+ const shouldRetry = interceptorOptions.options.context.shouldRetry ?? this.defaultShouldRetry;
23
+ const onRetry = interceptorOptions.options.context.onRetry ?? this.defaultOnRetry;
24
+ if (maxAttempts <= 0) {
25
+ return interceptorOptions.next();
26
+ }
27
+ let lastEventId = interceptorOptions.options.lastEventId;
28
+ let lastEventRetry;
29
+ let unsubscribe;
30
+ let attemptIndex = 0;
31
+ const next = async (initial) => {
32
+ let current = initial;
33
+ while (true) {
34
+ const newClientOptions = { ...interceptorOptions.options, lastEventId };
35
+ if (current) {
36
+ if (attemptIndex >= maxAttempts) {
37
+ throw current.error;
38
+ }
39
+ const attemptOptions = {
40
+ attemptIndex,
41
+ error: current.error,
42
+ lastEventId,
43
+ lastEventRetry
44
+ };
45
+ const shouldRetryBool = await value(
46
+ shouldRetry,
47
+ attemptOptions,
48
+ newClientOptions,
49
+ interceptorOptions.path,
50
+ interceptorOptions.input
51
+ );
52
+ if (!shouldRetryBool) {
53
+ throw current.error;
54
+ }
55
+ unsubscribe = onRetry?.(
56
+ attemptOptions,
57
+ newClientOptions,
58
+ interceptorOptions.path,
59
+ interceptorOptions.input
60
+ );
61
+ const retryDelayMs = await value(
62
+ retryDelay,
63
+ attemptOptions,
64
+ newClientOptions,
65
+ interceptorOptions.path,
66
+ interceptorOptions.input
67
+ );
68
+ await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
69
+ attemptIndex++;
70
+ }
71
+ try {
72
+ const output2 = await interceptorOptions.next({
73
+ ...interceptorOptions,
74
+ options: newClientOptions
75
+ });
76
+ return output2;
77
+ } catch (error) {
78
+ if (newClientOptions.signal?.aborted === true) {
79
+ throw error;
80
+ }
81
+ current = { error };
82
+ } finally {
83
+ unsubscribe?.();
84
+ unsubscribe = void 0;
85
+ }
86
+ }
87
+ };
88
+ const output = await next();
89
+ if (!isAsyncIteratorObject(output)) {
90
+ return output;
91
+ }
92
+ return async function* () {
93
+ let current = output;
94
+ try {
95
+ while (true) {
96
+ try {
97
+ const item = await current.next();
98
+ const meta = getEventMeta(item.value);
99
+ lastEventId = meta?.id ?? lastEventId;
100
+ lastEventRetry = meta?.retry ?? lastEventRetry;
101
+ if (item.done) {
102
+ return item.value;
103
+ }
104
+ yield item.value;
105
+ } catch (error) {
106
+ const meta = getEventMeta(error);
107
+ lastEventId = meta?.id ?? lastEventId;
108
+ lastEventRetry = meta?.retry ?? lastEventRetry;
109
+ const maybeEventIterator = await next({ error });
110
+ if (!isAsyncIteratorObject(maybeEventIterator)) {
111
+ throw new ClientRetryPluginInvalidEventIteratorRetryResponse(
112
+ "RetryPlugin: Expected an Event Iterator, got a non-Event Iterator"
113
+ );
114
+ }
115
+ current = maybeEventIterator;
116
+ }
117
+ }
118
+ } finally {
119
+ await current.return?.();
120
+ }
121
+ }();
122
+ });
123
+ }
124
+ }
125
+
126
+ export { ClientRetryPlugin, ClientRetryPluginInvalidEventIteratorRetryResponse };
@@ -1,4 +1,4 @@
1
- import { isObject, isTypescriptObject, retry } from '@orpc/shared';
1
+ import { isObject, isTypescriptObject } from '@orpc/shared';
2
2
  import { getEventMeta, withEventMeta } from '@orpc/standard-server';
3
3
 
4
4
  const COMMON_ORPC_ERROR_DEFS = {
@@ -137,33 +137,6 @@ function toORPCError(error) {
137
137
  });
138
138
  }
139
139
 
140
- const iteratorStates = /* @__PURE__ */ new WeakMap();
141
- function registerEventIteratorState(iterator, state) {
142
- iteratorStates.set(iterator, state);
143
- }
144
- function updateEventIteratorStatus(state, status) {
145
- if (state.status !== status) {
146
- state.status = status;
147
- state.listeners.forEach((cb) => cb(status));
148
- }
149
- }
150
- function onEventIteratorStatusChange(iterator, callback, notifyImmediately = true) {
151
- const state = iteratorStates.get(iterator);
152
- if (!state) {
153
- throw new Error("Iterator is not registered.");
154
- }
155
- if (notifyImmediately) {
156
- callback(state.status);
157
- }
158
- state.listeners.push(callback);
159
- return () => {
160
- const index = state.listeners.indexOf(callback);
161
- if (index !== -1) {
162
- state.listeners.splice(index, 1);
163
- }
164
- };
165
- }
166
-
167
140
  function mapEventIterator(iterator, maps) {
168
141
  return async function* () {
169
142
  try {
@@ -195,71 +168,5 @@ function mapEventIterator(iterator, maps) {
195
168
  }
196
169
  }();
197
170
  }
198
- const MAX_ALLOWED_RETRY_TIMES = 99;
199
- function createAutoRetryEventIterator(initial, reconnect, initialLastEventId) {
200
- const state = {
201
- status: "connected",
202
- listeners: []
203
- };
204
- const iterator = async function* () {
205
- let current = initial;
206
- let lastEventId = initialLastEventId;
207
- let lastRetry;
208
- let retryTimes = 0;
209
- try {
210
- while (true) {
211
- try {
212
- updateEventIteratorStatus(state, "connected");
213
- const { done, value } = await current.next();
214
- const meta = getEventMeta(value);
215
- lastEventId = meta?.id ?? lastEventId;
216
- lastRetry = meta?.retry ?? lastRetry;
217
- retryTimes = 0;
218
- if (done) {
219
- return value;
220
- }
221
- yield value;
222
- } catch (e) {
223
- updateEventIteratorStatus(state, "reconnecting");
224
- const meta = getEventMeta(e);
225
- lastEventId = meta?.id ?? lastEventId;
226
- lastRetry = meta?.retry ?? lastRetry;
227
- let currentError = e;
228
- current = await retry({ times: MAX_ALLOWED_RETRY_TIMES }, async (exit) => {
229
- retryTimes += 1;
230
- if (retryTimes > MAX_ALLOWED_RETRY_TIMES) {
231
- throw exit(new Error(
232
- `Exceeded maximum retry attempts (${MAX_ALLOWED_RETRY_TIMES}) for event iterator. Possible infinite retry loop detected. Please review the retry logic.`,
233
- { cause: currentError }
234
- ));
235
- }
236
- const reconnected = await (async () => {
237
- try {
238
- return await reconnect({
239
- lastRetry,
240
- lastEventId,
241
- retryTimes,
242
- error: currentError
243
- });
244
- } catch (e2) {
245
- currentError = e2;
246
- throw e2;
247
- }
248
- })();
249
- if (!reconnected) {
250
- throw exit(currentError);
251
- }
252
- return reconnected;
253
- });
254
- }
255
- }
256
- } finally {
257
- updateEventIteratorStatus(state, "closed");
258
- await current.return?.();
259
- }
260
- }();
261
- registerEventIteratorState(iterator, state);
262
- return iterator;
263
- }
264
171
 
265
- export { COMMON_ORPC_ERROR_DEFS as C, ORPCError as O, fallbackORPCErrorMessage as a, createAutoRetryEventIterator as c, fallbackORPCErrorStatus as f, isDefinedError as i, mapEventIterator as m, onEventIteratorStatusChange as o, registerEventIteratorState as r, toORPCError as t, updateEventIteratorStatus as u };
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 };
@@ -0,0 +1,39 @@
1
+ import { Interceptor } from '@orpc/shared';
2
+ import { StandardRequest, StandardLazyResponse } from '@orpc/standard-server';
3
+ import { a as ClientContext, C as ClientOptions, b as ClientLink } from './client.RZs5Myak.js';
4
+
5
+ interface StandardLinkCodec<T extends ClientContext> {
6
+ encode(path: readonly string[], input: unknown, options: ClientOptions<T>): Promise<StandardRequest>;
7
+ decode(response: StandardLazyResponse, options: ClientOptions<T>, path: readonly string[], input: unknown): Promise<unknown>;
8
+ }
9
+ interface StandardLinkClient<T extends ClientContext> {
10
+ call(request: StandardRequest, options: ClientOptions<T>, path: readonly string[], input: unknown): Promise<StandardLazyResponse>;
11
+ }
12
+
13
+ declare class InvalidEventIteratorRetryResponse extends Error {
14
+ }
15
+ interface StandardLinkPlugin<T extends ClientContext> {
16
+ init?(options: StandardLinkOptions<T>): void;
17
+ }
18
+ interface StandardLinkOptions<T extends ClientContext> {
19
+ interceptors?: Interceptor<{
20
+ path: readonly string[];
21
+ input: unknown;
22
+ options: ClientOptions<T>;
23
+ }, unknown, unknown>[];
24
+ clientInterceptors?: Interceptor<{
25
+ request: StandardRequest;
26
+ }, StandardLazyResponse, unknown>[];
27
+ plugins?: StandardLinkPlugin<T>[];
28
+ }
29
+ declare class StandardLink<T extends ClientContext> implements ClientLink<T> {
30
+ #private;
31
+ readonly codec: StandardLinkCodec<T>;
32
+ readonly sender: StandardLinkClient<T>;
33
+ private readonly interceptors;
34
+ private readonly clientInterceptors;
35
+ constructor(codec: StandardLinkCodec<T>, sender: StandardLinkClient<T>, options?: StandardLinkOptions<T>);
36
+ call(path: readonly string[], input: unknown, options: ClientOptions<T>): Promise<unknown>;
37
+ }
38
+
39
+ export { InvalidEventIteratorRetryResponse as I, type StandardLinkPlugin as S, type StandardLinkOptions as a, type StandardLinkClient as b, type StandardLinkCodec as c, StandardLink as d };