@orpc/client 1.14.6 → 2.0.0-beta.1

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 (38) hide show
  1. package/README.md +74 -106
  2. package/dist/adapters/fetch/index.d.mts +55 -36
  3. package/dist/adapters/fetch/index.d.ts +55 -36
  4. package/dist/adapters/fetch/index.mjs +50 -28
  5. package/dist/adapters/message-port/index.d.mts +25 -30
  6. package/dist/adapters/message-port/index.d.ts +25 -30
  7. package/dist/adapters/message-port/index.mjs +33 -29
  8. package/dist/adapters/standard/index.d.mts +58 -9
  9. package/dist/adapters/standard/index.d.ts +58 -9
  10. package/dist/adapters/standard/index.mjs +5 -5
  11. package/dist/adapters/websocket/index.d.mts +113 -21
  12. package/dist/adapters/websocket/index.d.ts +113 -21
  13. package/dist/adapters/websocket/index.mjs +95 -37
  14. package/dist/index.d.mts +84 -159
  15. package/dist/index.d.ts +84 -159
  16. package/dist/index.mjs +76 -34
  17. package/dist/plugins/index.d.mts +125 -132
  18. package/dist/plugins/index.d.ts +125 -132
  19. package/dist/plugins/index.mjs +373 -284
  20. package/dist/shared/client.8ug8I-zu.d.mts +167 -0
  21. package/dist/shared/client.8ug8I-zu.d.ts +167 -0
  22. package/dist/shared/client.BdItY5DT.d.mts +111 -0
  23. package/dist/shared/client.BdItY5DT.d.ts +111 -0
  24. package/dist/shared/client.CPF3hX6O.d.ts +96 -0
  25. package/dist/shared/client.Cby_-GGh.d.mts +96 -0
  26. package/dist/shared/client.DMXKFDyV.mjs +343 -0
  27. package/dist/shared/client.DXhchJ84.mjs +174 -0
  28. package/dist/shared/client.Dnfj8jnT.mjs +92 -0
  29. package/package.json +7 -7
  30. package/dist/shared/client.2jUAqzYU.d.ts +0 -45
  31. package/dist/shared/client.B3pNRBih.d.ts +0 -91
  32. package/dist/shared/client.BFAVy68H.d.mts +0 -91
  33. package/dist/shared/client.BLtwTQUg.mjs +0 -40
  34. package/dist/shared/client.CpCa3si8.d.mts +0 -45
  35. package/dist/shared/client.D9eWXdBV.mjs +0 -174
  36. package/dist/shared/client.DLhbktiD.mjs +0 -404
  37. package/dist/shared/client.i2uoJbEp.d.mts +0 -83
  38. package/dist/shared/client.i2uoJbEp.d.ts +0 -83
@@ -0,0 +1,96 @@
1
+ import { Promisable, OrderablePlugin, Interceptor } from '@orpc/shared';
2
+ import { StandardRequest, StandardLazyResponse } from '@standardserver/core';
3
+ import { C as ClientContext, a as ClientOptions, A as AnyORPCError, b as ClientLink } from './client.8ug8I-zu.mjs';
4
+
5
+ type StandardLinkCodecDecodedResponse = {
6
+ kind: 'output';
7
+ output: unknown;
8
+ } | {
9
+ kind: 'error';
10
+ error: AnyORPCError;
11
+ };
12
+ interface StandardLinkCodec<T extends ClientContext> {
13
+ encodeInput(input: unknown, path: string[], options: ClientOptions<T>): Promisable<StandardRequest>;
14
+ decodeResponse(response: StandardLazyResponse, path: string[], options: ClientOptions<T>): Promisable<StandardLinkCodecDecodedResponse>;
15
+ }
16
+
17
+ interface StandardLinkPlugin<T extends ClientContext> extends OrderablePlugin {
18
+ /**
19
+ * Initializes the plugin and returns new link options.
20
+ * Called once per plugin instance during composition.
21
+ *
22
+ * This method allows plugins to wrap, extend, or transform link options
23
+ * such as interceptors, or configuration.
24
+ *
25
+ * @param options - The current link options from previous plugins or base configuration
26
+ * @returns Transformed link options with plugin's modifications applied
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * init(options) {
31
+ * return {
32
+ * ...options,
33
+ * interceptors: [...(options.interceptors || []), myInterceptor]
34
+ * }
35
+ * }
36
+ * ```
37
+ */
38
+ init?(options: StandardLinkOptions<T>): StandardLinkOptions<T>;
39
+ }
40
+ declare class CompositeStandardLinkPlugin<T extends ClientContext> implements StandardLinkPlugin<T> {
41
+ name: string;
42
+ protected readonly plugins: StandardLinkPlugin<T>[];
43
+ constructor(plugins?: StandardLinkPlugin<T>[]);
44
+ init(options: StandardLinkOptions<T>): StandardLinkOptions<T>;
45
+ }
46
+
47
+ /**
48
+ * Handles the transport layer for sending requests and receiving responses.
49
+ *
50
+ * Implementations are responsible for the actual network communication,
51
+ * such as HTTP fetch, WebSocket, or other transport mechanisms.
52
+ */
53
+ interface StandardLinkTransport<T extends ClientContext> {
54
+ /**
55
+ * @throws Transport-level errors (network failures, timeouts, etc.)
56
+ */
57
+ send(request: StandardRequest, path: string[], options: ClientOptions<T>): Promise<StandardLazyResponse>;
58
+ }
59
+
60
+ interface StandardLinkInterceptorOptions<T extends ClientContext> extends ClientOptions<T> {
61
+ path: string[];
62
+ input: unknown;
63
+ }
64
+ type StandardLinkInterceptor<T extends ClientContext> = Interceptor<StandardLinkInterceptorOptions<T>, Promise<unknown>>;
65
+ interface StandardLinkTransportInterceptorOptions<T extends ClientContext> extends ClientOptions<T> {
66
+ path: string[];
67
+ request: StandardRequest;
68
+ }
69
+ type StandardLinkTransportInterceptor<T extends ClientContext> = Interceptor<StandardLinkTransportInterceptorOptions<T>, Promise<StandardLazyResponse>>;
70
+ interface StandardLinkOptions<T extends ClientContext> {
71
+ /**
72
+ * Interceptors that execute around the entire call, including transport and codec.
73
+ * Useful for error handling, logging, metrics, ...
74
+ */
75
+ interceptors?: StandardLinkInterceptor<T>[];
76
+ /**
77
+ * Interceptors that execute around the transport layer, after encoding and before decoding.
78
+ * Useful for modifying the request or response, adding transport-level logging, ...
79
+ */
80
+ transportInterceptors?: StandardLinkTransportInterceptor<T>[];
81
+ plugins?: StandardLinkPlugin<T>[];
82
+ }
83
+ declare class StandardLink<T extends ClientContext> implements ClientLink<T> {
84
+ private readonly codec;
85
+ private readonly transport;
86
+ private readonly interceptors;
87
+ private readonly transportInterceptors;
88
+ constructor(codec: StandardLinkCodec<T>, transport: StandardLinkTransport<T>, options?: StandardLinkOptions<T>);
89
+ /**
90
+ * @throws ORPCError, transport-level errors (network failures, timeouts, etc.)
91
+ */
92
+ call(path: string[], input: unknown, options: ClientOptions<T>): Promise<unknown>;
93
+ }
94
+
95
+ export { CompositeStandardLinkPlugin as C, StandardLink as a };
96
+ export type { StandardLinkTransport as S, StandardLinkOptions as b, StandardLinkPlugin as c, StandardLinkTransportInterceptorOptions as d, StandardLinkInterceptorOptions as e, StandardLinkCodec as f, StandardLinkCodecDecodedResponse as g, StandardLinkInterceptor as h, StandardLinkTransportInterceptor as i };
@@ -0,0 +1,343 @@
1
+ import { isPlainObject, wrapAsyncIterator, isTypescriptObject, isAsyncIteratorObject, stringifyJSON } from '@orpc/shared';
2
+ import { getEventMeta, withEventMeta, ErrorEvent } from '@standardserver/core';
3
+ import { O as ORPCError } from './client.Dnfj8jnT.mjs';
4
+
5
+ function isInferableError(error) {
6
+ return error instanceof ORPCError && error.inferable;
7
+ }
8
+ function toORPCError(error) {
9
+ return error instanceof ORPCError ? error : new ORPCError("INTERNAL_SERVER_ERROR", { cause: error });
10
+ }
11
+ function isORPCErrorJson(json) {
12
+ if (!isPlainObject(json)) {
13
+ return false;
14
+ }
15
+ const validKeys = ["defined", "inferable", "code", "message", "data"];
16
+ if (Object.keys(json).some((k) => !validKeys.includes(k))) {
17
+ return false;
18
+ }
19
+ return "defined" in json && typeof json.defined === "boolean" && "inferable" in json && typeof json.inferable === "boolean" && "code" in json && typeof json.code === "string" && "message" in json && typeof json.message === "string";
20
+ }
21
+ function createORPCErrorFromJson(json, options = {}) {
22
+ const error = new ORPCError(json.code, {
23
+ ...json,
24
+ ...options
25
+ });
26
+ error.defined = json.defined;
27
+ error.inferable = json.inferable;
28
+ return error;
29
+ }
30
+ function cloneORPCError(error) {
31
+ const cloned = new ORPCError(error.code, {
32
+ ...error,
33
+ message: error.message,
34
+ data: error.data,
35
+ cause: error.cause
36
+ });
37
+ cloned.stack = error.stack;
38
+ cloned.defined = error.defined;
39
+ cloned.inferable = error.inferable;
40
+ return cloned;
41
+ }
42
+
43
+ function wrapEventIteratorPreservingMeta(iterator, { mapResult, mapError, ...rest }) {
44
+ return wrapAsyncIterator(iterator, {
45
+ ...rest,
46
+ mapResult: mapResult && (async (result) => {
47
+ const mapped = await mapResult(result);
48
+ if (mapped.value !== result.value) {
49
+ const meta = getEventMeta(result.value);
50
+ if (meta && isTypescriptObject(mapped.value)) {
51
+ return { done: mapped.done, value: withEventMeta(mapped.value, meta) };
52
+ }
53
+ }
54
+ return mapped;
55
+ }),
56
+ mapError: mapError && (async (error) => {
57
+ const mapped = await mapError(error);
58
+ if (mapped !== error) {
59
+ const meta = getEventMeta(error);
60
+ if (meta && isTypescriptObject(mapped)) {
61
+ return withEventMeta(mapped, meta);
62
+ }
63
+ }
64
+ return mapped;
65
+ })
66
+ });
67
+ }
68
+
69
+ const REGEX_STRING_PATTERN = /^\/(.*)\/([a-z]*)$/;
70
+ const DEFAULT_RPC_JSON_SERIALIZER_HANDLERS = {
71
+ undefined: {
72
+ condition(data) {
73
+ return data === void 0;
74
+ },
75
+ serialize() {
76
+ return null;
77
+ },
78
+ deserialize() {
79
+ return void 0;
80
+ },
81
+ isTerminal: true
82
+ },
83
+ bigint: {
84
+ condition(data) {
85
+ return typeof data === "bigint";
86
+ },
87
+ serialize(data) {
88
+ return data.toString();
89
+ },
90
+ deserialize(serialized) {
91
+ return BigInt(serialized);
92
+ },
93
+ isTerminal: true
94
+ },
95
+ date: {
96
+ condition(data) {
97
+ return data instanceof Date;
98
+ },
99
+ serialize(data) {
100
+ if (Number.isNaN(data.getTime())) {
101
+ return null;
102
+ }
103
+ return data.toISOString();
104
+ },
105
+ deserialize(serialized) {
106
+ return new Date(serialized ?? "Invalid Date");
107
+ },
108
+ isTerminal: true
109
+ },
110
+ nan: {
111
+ condition(data) {
112
+ return typeof data === "number" && Number.isNaN(data);
113
+ },
114
+ serialize() {
115
+ return null;
116
+ },
117
+ deserialize() {
118
+ return Number.NaN;
119
+ },
120
+ isTerminal: true
121
+ },
122
+ url: {
123
+ condition(data) {
124
+ return data instanceof URL;
125
+ },
126
+ serialize(data) {
127
+ return data.toString();
128
+ },
129
+ deserialize(serialized) {
130
+ return new URL(serialized);
131
+ },
132
+ isTerminal: true
133
+ },
134
+ regexp: {
135
+ condition(data) {
136
+ return data instanceof RegExp;
137
+ },
138
+ serialize(data) {
139
+ return data.toString();
140
+ },
141
+ deserialize(serialized) {
142
+ const [, pattern, flags] = serialized.match(REGEX_STRING_PATTERN);
143
+ return new RegExp(pattern, flags);
144
+ },
145
+ isTerminal: true
146
+ },
147
+ set: {
148
+ condition(data) {
149
+ return data instanceof Set;
150
+ },
151
+ serialize(data) {
152
+ return Array.from(data);
153
+ },
154
+ deserialize(serialized) {
155
+ return new Set(serialized);
156
+ }
157
+ },
158
+ map: {
159
+ condition(data) {
160
+ return data instanceof Map;
161
+ },
162
+ serialize(data) {
163
+ return Array.from(data.entries());
164
+ },
165
+ deserialize(serialized) {
166
+ return new Map(serialized);
167
+ }
168
+ }
169
+ };
170
+ class RPCJsonSerializer {
171
+ handlers;
172
+ omitUndefinedProperties;
173
+ constructor(options = {}) {
174
+ this.handlers = {
175
+ ...DEFAULT_RPC_JSON_SERIALIZER_HANDLERS,
176
+ ...options.handlers
177
+ };
178
+ this.omitUndefinedProperties = options.omitUndefinedProperties !== false;
179
+ }
180
+ serialize(data) {
181
+ const [json, meta_, maps, blobs] = this.serializeValue(data, [], [], [], []);
182
+ const meta = meta_.length === 0 ? void 0 : meta_;
183
+ if (maps.length === 0) {
184
+ return { json, meta };
185
+ }
186
+ return { json, meta, maps, blobs };
187
+ }
188
+ serializeValue(data, segments, meta, maps, blobs) {
189
+ for (const key in this.handlers) {
190
+ const handler = this.handlers[key];
191
+ if (handler && handler.condition(data)) {
192
+ const serialized = handler.serialize(data);
193
+ if (handler.isTerminal) {
194
+ meta.push([key, ...segments]);
195
+ return [serialized, meta, maps, blobs];
196
+ }
197
+ const result = this.serializeValue(serialized, segments, meta, maps, blobs);
198
+ meta.push([key, ...segments]);
199
+ return result;
200
+ }
201
+ }
202
+ if (data instanceof Blob) {
203
+ maps.push(segments);
204
+ blobs.push(data);
205
+ return [data, meta, maps, blobs];
206
+ }
207
+ if (Array.isArray(data)) {
208
+ const json = data.map((v, i) => {
209
+ return this.serializeValue(v, [...segments, i], meta, maps, blobs)[0];
210
+ });
211
+ return [json, meta, maps, blobs];
212
+ }
213
+ if (isPlainObject(data)) {
214
+ const json = {};
215
+ for (const k in data) {
216
+ const v = data[k];
217
+ if (k === "toJSON" && typeof v === "function") {
218
+ continue;
219
+ }
220
+ if (v === void 0 && this.omitUndefinedProperties) {
221
+ continue;
222
+ }
223
+ json[k] = this.serializeValue(v, [...segments, k], meta, maps, blobs)[0];
224
+ }
225
+ return [json, meta, maps, blobs];
226
+ }
227
+ return [data, meta, maps, blobs];
228
+ }
229
+ deserialize(serialized) {
230
+ const ref = { data: serialized.json };
231
+ if (serialized.blobs?.length) {
232
+ serialized.maps.forEach((segments, i) => {
233
+ let currentRef = ref;
234
+ let preSegment = "data";
235
+ segments.forEach((segment) => {
236
+ currentRef = currentRef[preSegment];
237
+ preSegment = segment;
238
+ if (!Object.hasOwn(currentRef, preSegment)) {
239
+ throw new Error(`Security error: Invalid serialized data. Segment "${preSegment}" does not exist.`);
240
+ }
241
+ });
242
+ currentRef[preSegment] = serialized.blobs[i];
243
+ });
244
+ }
245
+ serialized.meta?.forEach((item) => {
246
+ const type = item[0];
247
+ let currentRef = ref;
248
+ let preSegment = "data";
249
+ for (let i = 1; i < item.length; i++) {
250
+ currentRef = currentRef[preSegment];
251
+ preSegment = item[i];
252
+ if (!Object.hasOwn(currentRef, preSegment)) {
253
+ throw new Error(`Security error: Invalid serialized data. Segment "${preSegment}" does not exist.`);
254
+ }
255
+ }
256
+ currentRef[preSegment] = this.handlers[type].deserialize(currentRef[preSegment]);
257
+ });
258
+ return ref.data;
259
+ }
260
+ }
261
+
262
+ class RPCSerializer {
263
+ jsonSerializer;
264
+ defaultSerializeOptions;
265
+ constructor(options = {}) {
266
+ this.jsonSerializer = new RPCJsonSerializer(options);
267
+ this.defaultSerializeOptions = options.serialize;
268
+ }
269
+ serialize(data, options = {}) {
270
+ if (data === void 0 || data instanceof ReadableStream || data instanceof Blob) {
271
+ return data;
272
+ }
273
+ if (isAsyncIteratorObject(data)) {
274
+ return wrapEventIteratorPreservingMeta(data, {
275
+ mapResult: (result) => {
276
+ if (result.value === void 0) {
277
+ return result;
278
+ }
279
+ return { done: result.done, value: this.serializeValue(result.value, options) };
280
+ },
281
+ mapError: (e) => new ErrorEvent(
282
+ this.serializeValue(toORPCError(e).toJSON(), { ...options, useFormDataForBlobFields: false }),
283
+ { cause: e }
284
+ )
285
+ });
286
+ }
287
+ return this.serializeValue(data, options);
288
+ }
289
+ serializeValue(data, options) {
290
+ const useFormDataForBlobs = options.useFormDataForBlobFields ?? this.defaultSerializeOptions?.useFormDataForBlobFields ?? true;
291
+ const { json, meta, maps, blobs } = this.jsonSerializer.serialize(data);
292
+ if (!useFormDataForBlobs || !blobs?.length) {
293
+ return { json, meta };
294
+ }
295
+ const form = new FormData();
296
+ form.set("data", stringifyJSON({ json, meta, maps }));
297
+ blobs.forEach((blob, i) => {
298
+ form.set(i.toString(), blob);
299
+ });
300
+ return form;
301
+ }
302
+ deserialize(data) {
303
+ if (data === void 0 || data instanceof ReadableStream || data instanceof Blob) {
304
+ return data;
305
+ }
306
+ if (isAsyncIteratorObject(data)) {
307
+ return wrapEventIteratorPreservingMeta(data, {
308
+ mapResult: (result) => {
309
+ if (result.value === void 0) {
310
+ return result;
311
+ }
312
+ return { done: result.done, value: this.deserializeValue(result.value) };
313
+ },
314
+ mapError: (e) => {
315
+ if (!(e instanceof ErrorEvent)) {
316
+ return e;
317
+ }
318
+ const deserialized = this.deserializeValue(e.data);
319
+ if (isORPCErrorJson(deserialized)) {
320
+ return createORPCErrorFromJson(deserialized, { cause: e });
321
+ }
322
+ return new ErrorEvent(deserialized, { cause: e });
323
+ }
324
+ });
325
+ }
326
+ return this.deserializeValue(data);
327
+ }
328
+ deserializeValue(data) {
329
+ if (!(data instanceof FormData)) {
330
+ return this.jsonSerializer.deserialize(data);
331
+ }
332
+ const serialized = JSON.parse(data.get("data"));
333
+ const blobs = [];
334
+ for (const [key, value] of data.entries()) {
335
+ if (value instanceof Blob) {
336
+ blobs[Number(key)] = value;
337
+ }
338
+ }
339
+ return this.jsonSerializer.deserialize({ ...serialized, blobs });
340
+ }
341
+ }
342
+
343
+ export { RPCSerializer as R, isInferableError as a, RPCJsonSerializer as b, createORPCErrorFromJson as c, cloneORPCError as d, isORPCErrorJson as i, toORPCError as t, wrapEventIteratorPreservingMeta as w };
@@ -0,0 +1,174 @@
1
+ import { sortPlugins, runWithSpan, ORPC_NAME, isAsyncIteratorObject, override, traceAsyncIterator, intercept, getOpenTelemetryConfig, value, pathToHttpPath, stringifyJSON } from '@orpc/shared';
2
+ import { mergeStandardHeaders, parseStandardUrl } from '@standardserver/core';
3
+ import { toStandardHeaders } from '@standardserver/fetch';
4
+ import { O as ORPCError } from './client.Dnfj8jnT.mjs';
5
+ import { R as RPCSerializer, i as isORPCErrorJson, c as createORPCErrorFromJson } from './client.DMXKFDyV.mjs';
6
+
7
+ class CompositeStandardLinkPlugin {
8
+ name = "~composite";
9
+ plugins;
10
+ constructor(plugins = []) {
11
+ this.plugins = sortPlugins(plugins);
12
+ }
13
+ init(options) {
14
+ for (const plugin of this.plugins) {
15
+ if (plugin.init) {
16
+ options = plugin.init(options);
17
+ }
18
+ }
19
+ return options;
20
+ }
21
+ }
22
+
23
+ class StandardLink {
24
+ constructor(codec, transport, options = {}) {
25
+ this.codec = codec;
26
+ this.transport = transport;
27
+ options = new CompositeStandardLinkPlugin(options.plugins).init(options);
28
+ this.interceptors = options.interceptors;
29
+ this.transportInterceptors = options.transportInterceptors;
30
+ }
31
+ interceptors;
32
+ transportInterceptors;
33
+ /**
34
+ * @throws ORPCError, transport-level errors (network failures, timeouts, etc.)
35
+ */
36
+ call(path, input, options) {
37
+ return runWithSpan(`${ORPC_NAME}.${path.join("/")}`, (span) => {
38
+ span?.setAttribute("rpc.system", ORPC_NAME);
39
+ span?.setAttribute("rpc.method", path.join("."));
40
+ if (isAsyncIteratorObject(input)) {
41
+ input = override(input, traceAsyncIterator("consume_event_iterator_input", input));
42
+ }
43
+ return intercept(this.interceptors, { ...options, path, input }, async ({ path: path2, input: input2, ...options2 }) => {
44
+ const otel = getOpenTelemetryConfig();
45
+ let activeContext;
46
+ const activeSpan = otel?.trace.getActiveSpan() ?? span;
47
+ if (activeSpan && otel) {
48
+ activeContext = otel.trace.setSpan(otel.context.active(), activeSpan);
49
+ }
50
+ let request = await runWithSpan(
51
+ { name: "encode_input", context: activeContext },
52
+ () => this.codec.encodeInput(input2, path2, options2)
53
+ );
54
+ if (activeContext && otel?.propagation) {
55
+ const headers = { ...request.headers };
56
+ otel.propagation.inject(activeContext, headers);
57
+ request = { ...request, headers };
58
+ }
59
+ const response = await intercept(
60
+ this.transportInterceptors,
61
+ { ...options2, path: path2, request },
62
+ ({ path: path3, request: request2, ...options3 }) => {
63
+ let activeTransportContext;
64
+ const activeTransportSpan = otel?.trace.getActiveSpan() ?? activeSpan;
65
+ if (activeTransportSpan && otel) {
66
+ activeTransportContext = otel.trace.setSpan(otel.context.active(), activeTransportSpan);
67
+ }
68
+ return runWithSpan(
69
+ { name: "send_request", context: activeTransportContext },
70
+ () => this.transport.send(request2, path3, options3)
71
+ );
72
+ }
73
+ );
74
+ const decodedResult = await runWithSpan(
75
+ { name: "decode_response", context: activeContext },
76
+ () => this.codec.decodeResponse(response, path2, options2)
77
+ );
78
+ if (decodedResult.kind === "error") {
79
+ throw decodedResult.error;
80
+ }
81
+ const output = decodedResult.output;
82
+ if (isAsyncIteratorObject(output)) {
83
+ return override(output, traceAsyncIterator("consume_event_iterator_output", output));
84
+ }
85
+ return output;
86
+ });
87
+ });
88
+ }
89
+ }
90
+
91
+ const END_SLASH_REGEX = /\/$/;
92
+ class RPCLinkCodec {
93
+ baseUrl;
94
+ maxUrlLength;
95
+ fallbackMethod;
96
+ expectedMethod;
97
+ headers;
98
+ serializer;
99
+ constructor(options) {
100
+ this.baseUrl = options.url ?? "/";
101
+ this.maxUrlLength = options.maxUrlLength ?? 2083;
102
+ this.fallbackMethod = options.fallbackMethod ?? "POST";
103
+ this.expectedMethod = options.method ?? this.fallbackMethod;
104
+ this.headers = options.headers ?? {};
105
+ this.serializer = options.serializer ?? new RPCSerializer();
106
+ }
107
+ async encodeInput(input, path, options) {
108
+ let headers = toResolvedStandardHeaders(await value(this.headers, options, path, input));
109
+ if (options.lastEventId !== void 0) {
110
+ headers = mergeStandardHeaders(headers, { "last-event-id": options.lastEventId });
111
+ }
112
+ const expectedMethod = await value(this.expectedMethod, options, path, input);
113
+ const baseUrl = await value(this.baseUrl, options, path, input);
114
+ const [pathname, search, hash] = parseStandardUrl(baseUrl);
115
+ const newPathname = `${pathname.replace(END_SLASH_REGEX, "")}${pathToHttpPath(path)}`;
116
+ const serialized = this.serializer.serialize(input);
117
+ if (expectedMethod === "GET" && !(serialized instanceof Blob) && !(serialized instanceof ReadableStream) && !(serialized instanceof FormData) && !isAsyncIteratorObject(serialized)) {
118
+ const maxUrlLength = await value(this.maxUrlLength, options, path, input);
119
+ const mergedSearch = new URLSearchParams(search);
120
+ mergedSearch.append("data", stringifyJSON(serialized) ?? "");
121
+ const url2 = `${newPathname}?${mergedSearch}${hash ?? ""}`;
122
+ if (url2.length <= maxUrlLength) {
123
+ return {
124
+ body: void 0,
125
+ method: expectedMethod,
126
+ headers,
127
+ url: url2,
128
+ signal: options.signal
129
+ };
130
+ }
131
+ }
132
+ const url = `${newPathname}${search ?? ""}${hash ?? ""}`;
133
+ return {
134
+ url,
135
+ method: expectedMethod === "GET" ? this.fallbackMethod : expectedMethod,
136
+ headers,
137
+ body: serialized,
138
+ signal: options.signal
139
+ };
140
+ }
141
+ async decodeResponse(response) {
142
+ const isOk = response.status >= 200 && response.status < 400;
143
+ const body = await response.resolveBody();
144
+ const deserialized = await (async () => {
145
+ try {
146
+ return this.serializer.deserialize(body);
147
+ } catch (cause) {
148
+ throw new Error("Invalid RPC response format.", {
149
+ cause
150
+ });
151
+ }
152
+ })();
153
+ if (!isOk) {
154
+ if (isORPCErrorJson(deserialized)) {
155
+ return { kind: "error", error: createORPCErrorFromJson(deserialized) };
156
+ }
157
+ return {
158
+ kind: "error",
159
+ error: new ORPCError("MALFORMED_ORPC_ERROR_RESPONSE", {
160
+ data: { headers: response.headers, status: response.status, body: deserialized }
161
+ })
162
+ };
163
+ }
164
+ return { kind: "output", output: deserialized };
165
+ }
166
+ }
167
+ function toResolvedStandardHeaders(headers) {
168
+ if (typeof headers.forEach === "function") {
169
+ return toStandardHeaders(headers);
170
+ }
171
+ return headers;
172
+ }
173
+
174
+ export { CompositeStandardLinkPlugin as C, RPCLinkCodec as R, StandardLink as S };
@@ -0,0 +1,92 @@
1
+ import { resolveMaybeOptionalOptions, getConstructor } from '@orpc/shared';
2
+
3
+ const COMMON_ERROR_STATUS_MAP = {
4
+ BAD_REQUEST: 400,
5
+ UNAUTHORIZED: 401,
6
+ PAYMENT_REQUIRED: 402,
7
+ FORBIDDEN: 403,
8
+ NOT_FOUND: 404,
9
+ METHOD_NOT_SUPPORTED: 405,
10
+ NOT_ACCEPTABLE: 406,
11
+ TIMEOUT: 408,
12
+ CONFLICT: 409,
13
+ GONE: 410,
14
+ PRECONDITION_FAILED: 412,
15
+ PAYLOAD_TOO_LARGE: 413,
16
+ UNSUPPORTED_MEDIA_TYPE: 415,
17
+ UNPROCESSABLE_CONTENT: 422,
18
+ PRECONDITION_REQUIRED: 428,
19
+ TOO_MANY_REQUESTS: 429,
20
+ CLIENT_CLOSED_REQUEST: 499,
21
+ INTERNAL_SERVER_ERROR: 500,
22
+ NOT_IMPLEMENTED: 501,
23
+ BAD_GATEWAY: 502,
24
+ SERVICE_UNAVAILABLE: 503,
25
+ GATEWAY_TIMEOUT: 504
26
+ };
27
+ let ORPCErrorConstructors;
28
+ class ORPCError extends Error {
29
+ static {
30
+ const ORPC_ERROR_CONSTRUCTORS_SYMBOL = Symbol.for("ORPC_ERROR_CONSTRUCTORS");
31
+ void (globalThis[ORPC_ERROR_CONSTRUCTORS_SYMBOL] ??= /* @__PURE__ */ new WeakSet());
32
+ ORPCErrorConstructors = globalThis[ORPC_ERROR_CONSTRUCTORS_SYMBOL];
33
+ ORPCErrorConstructors.add(ORPCError);
34
+ }
35
+ /**
36
+ * @info
37
+ * The `__branch` property is used for type branding, helping TypeScript distinguish
38
+ * an `ORPCError` instance from plain objects with a similar structure.
39
+ */
40
+ name = "ORPCError";
41
+ /**
42
+ * Indicates whether the error matches a definition in the procedure's `.errors` map.
43
+ */
44
+ defined = false;
45
+ /**
46
+ * Indicates whether the error's type is inferable at the TypeScript level.
47
+ * This is typically true when the error is explicitly defined or returned within a handler.
48
+ */
49
+ inferable = false;
50
+ code;
51
+ data;
52
+ constructor(code, ...rest) {
53
+ const options = resolveMaybeOptionalOptions(rest);
54
+ const message = options.message ?? code.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
55
+ super(message, options);
56
+ this.code = code;
57
+ this.data = options.data;
58
+ }
59
+ toJSON() {
60
+ return {
61
+ defined: this.defined,
62
+ inferable: this.inferable,
63
+ code: this.code,
64
+ message: this.message,
65
+ data: this.data
66
+ };
67
+ }
68
+ /**
69
+ * Workaround for Next.js where different contexts use separate
70
+ * dependency graphs, causing multiple ORPCError constructors existing and breaking
71
+ * `instanceof` checks across contexts.
72
+ *
73
+ * This is particularly problematic with "Optimized SSR", where orpc-client
74
+ * executes in one context but is invoked from another. When an error is thrown
75
+ * in the execution context, `instanceof ORPCError` checks fail in the
76
+ * invocation context due to separate class constructors.
77
+ *
78
+ * @todo Remove this and related code if Next.js resolves the multiple dependency graph issue.
79
+ */
80
+ static [Symbol.hasInstance](instance) {
81
+ if (!ORPCErrorConstructors.has(this)) {
82
+ return super[Symbol.hasInstance](instance);
83
+ }
84
+ const constructor = getConstructor(instance);
85
+ if (constructor && ORPCErrorConstructors.has(constructor)) {
86
+ return true;
87
+ }
88
+ return super[Symbol.hasInstance](instance);
89
+ }
90
+ }
91
+
92
+ export { COMMON_ERROR_STATUS_MAP as C, ORPCError as O };