@orpc/client 2.0.0-beta.3 → 2.0.0-beta.31
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/README.md +71 -101
- package/dist/adapters/fetch/index.d.mts +10 -5
- package/dist/adapters/fetch/index.d.ts +10 -5
- package/dist/adapters/fetch/index.mjs +31 -6
- package/dist/adapters/message-port/index.d.mts +11 -6
- package/dist/adapters/message-port/index.d.ts +11 -6
- package/dist/adapters/message-port/index.mjs +20 -15
- package/dist/adapters/standard/index.d.mts +6 -7
- package/dist/adapters/standard/index.d.ts +6 -7
- package/dist/adapters/standard/index.mjs +3 -3
- package/dist/adapters/websocket/index.d.mts +19 -14
- package/dist/adapters/websocket/index.d.ts +19 -14
- package/dist/adapters/websocket/index.mjs +11 -11
- package/dist/index.d.mts +49 -48
- package/dist/index.d.ts +49 -48
- package/dist/index.mjs +32 -49
- package/dist/plugins/index.d.mts +124 -12
- package/dist/plugins/index.d.ts +124 -12
- package/dist/plugins/index.mjs +290 -23
- package/dist/shared/{client.Cby_-GGh.d.mts → client.B0-4UDVl.d.mts} +1 -1
- package/dist/shared/{client.CPF3hX6O.d.ts → client.BhTyskpV.d.ts} +1 -1
- package/dist/shared/{client.DMXKFDyV.mjs → client.BnATe4Ob.mjs} +176 -58
- package/dist/shared/{client.8ug8I-zu.d.mts → client.CFVTHyN6.d.mts} +54 -6
- package/dist/shared/{client.8ug8I-zu.d.ts → client.CFVTHyN6.d.ts} +54 -6
- package/dist/shared/{client.Dnfj8jnT.mjs → client.DcoDDrD4.mjs} +17 -8
- package/dist/shared/{client.BdItY5DT.d.mts → client.Qwo2aQOm.d.mts} +18 -0
- package/dist/shared/{client.BdItY5DT.d.ts → client.Qwo2aQOm.d.ts} +18 -0
- package/dist/shared/{client.DXhchJ84.mjs → client.vEM0O_Eg.mjs} +8 -9
- package/package.json +19 -6
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { isPlainObject, wrapAsyncIterator, isTypescriptObject, isAsyncIteratorObject, stringifyJSON } from '@orpc/shared';
|
|
1
|
+
import { isPlainObject, wrapAsyncIterator, isTypescriptObject, NullProtoObj, isAsyncIteratorObject, stringifyJSON } from '@orpc/shared';
|
|
2
2
|
import { getEventMeta, withEventMeta, ErrorEvent } from '@standardserver/core';
|
|
3
|
-
import { O as ORPCError } from './client.
|
|
3
|
+
import { O as ORPCError, M as MalformedResponseError, C as COMMON_ERROR_STATUS_MAP } from './client.DcoDDrD4.mjs';
|
|
4
4
|
|
|
5
5
|
function isInferableError(error) {
|
|
6
6
|
return error instanceof ORPCError && error.inferable;
|
|
@@ -27,20 +27,42 @@ function createORPCErrorFromJson(json, options = {}) {
|
|
|
27
27
|
error.inferable = json.inferable;
|
|
28
28
|
return error;
|
|
29
29
|
}
|
|
30
|
+
function createORPCErrorFromMalformedResponse(options) {
|
|
31
|
+
const error = new ORPCError("MALFORMED_ORPC_RESPONSE", {
|
|
32
|
+
message: options.message ?? inferMalformedResponseMessage(options.response),
|
|
33
|
+
data: options.response
|
|
34
|
+
});
|
|
35
|
+
error.cause = new MalformedResponseError({ ...options, message: error.message });
|
|
36
|
+
return error;
|
|
37
|
+
}
|
|
38
|
+
const INFERRED_MESSAGE_MIN_LENGTH = 1;
|
|
39
|
+
const INFERRED_MESSAGE_MAX_LENGTH = 256;
|
|
40
|
+
function isInferableMessage(text) {
|
|
41
|
+
return text.length >= INFERRED_MESSAGE_MIN_LENGTH && text.length <= INFERRED_MESSAGE_MAX_LENGTH;
|
|
42
|
+
}
|
|
43
|
+
function inferMalformedResponseMessage(response) {
|
|
44
|
+
if (typeof response.body === "string" && isInferableMessage(response.body)) {
|
|
45
|
+
return response.body;
|
|
46
|
+
}
|
|
47
|
+
if (isPlainObject(response.body) && typeof response.body.message === "string" && isInferableMessage(response.body.message)) {
|
|
48
|
+
return response.body.message;
|
|
49
|
+
}
|
|
50
|
+
const commonCode = Object.entries(COMMON_ERROR_STATUS_MAP).find(([, status]) => status === response.status)?.[0];
|
|
51
|
+
return commonCode?.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
|
|
52
|
+
}
|
|
30
53
|
function cloneORPCError(error) {
|
|
31
54
|
const cloned = new ORPCError(error.code, {
|
|
32
|
-
...error,
|
|
33
55
|
message: error.message,
|
|
34
56
|
data: error.data,
|
|
35
57
|
cause: error.cause
|
|
36
58
|
});
|
|
59
|
+
Object.setPrototypeOf(cloned, Object.getPrototypeOf(error));
|
|
60
|
+
Object.defineProperties(cloned, Object.getOwnPropertyDescriptors(error));
|
|
37
61
|
cloned.stack = error.stack;
|
|
38
|
-
cloned.defined = error.defined;
|
|
39
|
-
cloned.inferable = error.inferable;
|
|
40
62
|
return cloned;
|
|
41
63
|
}
|
|
42
64
|
|
|
43
|
-
function
|
|
65
|
+
function wrapAsyncIteratorPreservingEventMeta(iterator, { mapResult, mapError, ...rest }) {
|
|
44
66
|
return wrapAsyncIterator(iterator, {
|
|
45
67
|
...rest,
|
|
46
68
|
mapResult: mapResult && (async (result) => {
|
|
@@ -66,7 +88,7 @@ function wrapEventIteratorPreservingMeta(iterator, { mapResult, mapError, ...res
|
|
|
66
88
|
});
|
|
67
89
|
}
|
|
68
90
|
|
|
69
|
-
const REGEX_STRING_PATTERN = /^\/(
|
|
91
|
+
const REGEX_STRING_PATTERN = /^\/([\s\S]*)\/([a-z]*)$/;
|
|
70
92
|
const DEFAULT_RPC_JSON_SERIALIZER_HANDLERS = {
|
|
71
93
|
undefined: {
|
|
72
94
|
condition(data) {
|
|
@@ -169,49 +191,140 @@ const DEFAULT_RPC_JSON_SERIALIZER_HANDLERS = {
|
|
|
169
191
|
};
|
|
170
192
|
class RPCJsonSerializer {
|
|
171
193
|
handlers;
|
|
194
|
+
inlineBuiltInHandlers;
|
|
195
|
+
handlerEntries;
|
|
172
196
|
omitUndefinedProperties;
|
|
173
197
|
constructor(options = {}) {
|
|
174
|
-
this.handlers = {
|
|
175
|
-
...DEFAULT_RPC_JSON_SERIALIZER_HANDLERS,
|
|
176
|
-
...options.handlers
|
|
177
|
-
};
|
|
178
198
|
this.omitUndefinedProperties = options.omitUndefinedProperties !== false;
|
|
199
|
+
this.handlers = Object.assign(new NullProtoObj(), DEFAULT_RPC_JSON_SERIALIZER_HANDLERS);
|
|
200
|
+
const customHandlers = options.handlers;
|
|
201
|
+
if (customHandlers === void 0) {
|
|
202
|
+
this.inlineBuiltInHandlers = true;
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
let inlineBuiltInHandlers = true;
|
|
206
|
+
let handlerEntries = [];
|
|
207
|
+
for (const key in customHandlers) {
|
|
208
|
+
const handler = customHandlers[key];
|
|
209
|
+
this.handlers[key] = handler;
|
|
210
|
+
if (inlineBuiltInHandlers && key in DEFAULT_RPC_JSON_SERIALIZER_HANDLERS) {
|
|
211
|
+
inlineBuiltInHandlers = false;
|
|
212
|
+
}
|
|
213
|
+
if (inlineBuiltInHandlers && handler !== void 0) {
|
|
214
|
+
handlerEntries.push([key, handler]);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (!inlineBuiltInHandlers) {
|
|
218
|
+
handlerEntries = [];
|
|
219
|
+
for (const key in this.handlers) {
|
|
220
|
+
const handler = this.handlers[key];
|
|
221
|
+
if (handler !== void 0) {
|
|
222
|
+
handlerEntries.push([key, handler]);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
this.inlineBuiltInHandlers = inlineBuiltInHandlers;
|
|
227
|
+
this.handlerEntries = handlerEntries;
|
|
179
228
|
}
|
|
180
229
|
serialize(data) {
|
|
181
|
-
|
|
182
|
-
const
|
|
230
|
+
let meta = [];
|
|
231
|
+
const maps = [];
|
|
232
|
+
const blobs = [];
|
|
233
|
+
const json = this.serializeValue(data, [], meta, maps, blobs);
|
|
234
|
+
meta = meta.length === 0 ? void 0 : meta;
|
|
183
235
|
if (maps.length === 0) {
|
|
184
236
|
return { json, meta };
|
|
185
237
|
}
|
|
186
238
|
return { json, meta, maps, blobs };
|
|
187
239
|
}
|
|
240
|
+
/**
|
|
241
|
+
* `segments` is a shared mutable stack (push/pop while walking),
|
|
242
|
+
* so it must be copied before being stored in `meta` or `maps`.
|
|
243
|
+
*/
|
|
188
244
|
serializeValue(data, segments, meta, maps, blobs) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
245
|
+
if (this.inlineBuiltInHandlers) {
|
|
246
|
+
switch (typeof data) {
|
|
247
|
+
case "string":
|
|
248
|
+
case "boolean":
|
|
249
|
+
return data;
|
|
250
|
+
case "number":
|
|
251
|
+
if (Number.isNaN(data)) {
|
|
252
|
+
meta.push(["nan", ...segments]);
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
return data;
|
|
256
|
+
case "undefined":
|
|
257
|
+
meta.push(["undefined", ...segments]);
|
|
258
|
+
return null;
|
|
259
|
+
case "bigint":
|
|
260
|
+
meta.push(["bigint", ...segments]);
|
|
261
|
+
return data.toString();
|
|
262
|
+
case "object": {
|
|
263
|
+
if (data === null) {
|
|
264
|
+
return data;
|
|
265
|
+
}
|
|
266
|
+
if (data instanceof Date) {
|
|
267
|
+
meta.push(["date", ...segments]);
|
|
268
|
+
return Number.isNaN(data.getTime()) ? null : data.toISOString();
|
|
269
|
+
}
|
|
270
|
+
if (data instanceof URL) {
|
|
271
|
+
meta.push(["url", ...segments]);
|
|
272
|
+
return data.toString();
|
|
273
|
+
}
|
|
274
|
+
if (data instanceof RegExp) {
|
|
275
|
+
meta.push(["regexp", ...segments]);
|
|
276
|
+
return data.toString();
|
|
277
|
+
}
|
|
278
|
+
if (data instanceof Set) {
|
|
279
|
+
const result = this.serializeValue(Array.from(data), segments, meta, maps, blobs);
|
|
280
|
+
meta.push(["set", ...segments]);
|
|
281
|
+
return result;
|
|
282
|
+
}
|
|
283
|
+
if (data instanceof Map) {
|
|
284
|
+
const result = this.serializeValue(Array.from(data.entries()), segments, meta, maps, blobs);
|
|
285
|
+
meta.push(["map", ...segments]);
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
const handlerEntries = this.handlerEntries;
|
|
292
|
+
if (handlerEntries) {
|
|
293
|
+
for (let i = 0; i < handlerEntries.length; i++) {
|
|
294
|
+
const entry = handlerEntries[i];
|
|
295
|
+
const handler = entry[1];
|
|
296
|
+
if (handler.condition(data)) {
|
|
297
|
+
const serialized = handler.serialize(data);
|
|
298
|
+
if (handler.isTerminal) {
|
|
299
|
+
meta.push([entry[0], ...segments]);
|
|
300
|
+
if (serialized instanceof Blob) {
|
|
301
|
+
maps.push(segments.slice());
|
|
302
|
+
blobs.push(serialized);
|
|
303
|
+
}
|
|
304
|
+
return serialized;
|
|
305
|
+
}
|
|
306
|
+
const result = this.serializeValue(serialized, segments, meta, maps, blobs);
|
|
307
|
+
meta.push([entry[0], ...segments]);
|
|
308
|
+
return result;
|
|
196
309
|
}
|
|
197
|
-
const result = this.serializeValue(serialized, segments, meta, maps, blobs);
|
|
198
|
-
meta.push([key, ...segments]);
|
|
199
|
-
return result;
|
|
200
310
|
}
|
|
201
311
|
}
|
|
202
312
|
if (data instanceof Blob) {
|
|
203
|
-
maps.push(segments);
|
|
313
|
+
maps.push(segments.slice());
|
|
204
314
|
blobs.push(data);
|
|
205
|
-
return
|
|
315
|
+
return data;
|
|
206
316
|
}
|
|
207
317
|
if (Array.isArray(data)) {
|
|
208
|
-
const json =
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
318
|
+
const json = [];
|
|
319
|
+
for (let i = 0; i < data.length; i++) {
|
|
320
|
+
segments.push(i);
|
|
321
|
+
json.push(this.serializeValue(data[i], segments, meta, maps, blobs));
|
|
322
|
+
segments.pop();
|
|
323
|
+
}
|
|
324
|
+
return json;
|
|
212
325
|
}
|
|
213
326
|
if (isPlainObject(data)) {
|
|
214
|
-
const json =
|
|
327
|
+
const json = new NullProtoObj();
|
|
215
328
|
for (const k in data) {
|
|
216
329
|
const v = data[k];
|
|
217
330
|
if (k === "toJSON" && typeof v === "function") {
|
|
@@ -220,41 +333,46 @@ class RPCJsonSerializer {
|
|
|
220
333
|
if (v === void 0 && this.omitUndefinedProperties) {
|
|
221
334
|
continue;
|
|
222
335
|
}
|
|
223
|
-
|
|
336
|
+
segments.push(k);
|
|
337
|
+
json[k] = this.serializeValue(v, segments, meta, maps, blobs);
|
|
338
|
+
segments.pop();
|
|
224
339
|
}
|
|
225
|
-
return
|
|
340
|
+
return json;
|
|
226
341
|
}
|
|
227
|
-
return
|
|
342
|
+
return data;
|
|
228
343
|
}
|
|
229
344
|
deserialize(serialized) {
|
|
230
345
|
const ref = { data: serialized.json };
|
|
231
346
|
if (serialized.blobs?.length) {
|
|
232
|
-
serialized.maps.
|
|
347
|
+
for (let i = 0; i < serialized.maps.length; i++) {
|
|
348
|
+
const segments = serialized.maps[i];
|
|
233
349
|
let currentRef = ref;
|
|
234
350
|
let preSegment = "data";
|
|
235
|
-
segments.
|
|
351
|
+
for (let j = 0; j < segments.length; j++) {
|
|
236
352
|
currentRef = currentRef[preSegment];
|
|
237
|
-
preSegment =
|
|
353
|
+
preSegment = segments[j];
|
|
238
354
|
if (!Object.hasOwn(currentRef, preSegment)) {
|
|
239
355
|
throw new Error(`Security error: Invalid serialized data. Segment "${preSegment}" does not exist.`);
|
|
240
356
|
}
|
|
241
|
-
}
|
|
357
|
+
}
|
|
242
358
|
currentRef[preSegment] = serialized.blobs[i];
|
|
243
|
-
}
|
|
359
|
+
}
|
|
244
360
|
}
|
|
245
|
-
serialized.meta
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
361
|
+
if (serialized.meta) {
|
|
362
|
+
for (const item of serialized.meta) {
|
|
363
|
+
const type = item[0];
|
|
364
|
+
let currentRef = ref;
|
|
365
|
+
let preSegment = "data";
|
|
366
|
+
for (let i = 1; i < item.length; i++) {
|
|
367
|
+
currentRef = currentRef[preSegment];
|
|
368
|
+
preSegment = item[i];
|
|
369
|
+
if (!Object.hasOwn(currentRef, preSegment)) {
|
|
370
|
+
throw new Error(`Security error: Invalid serialized data. Segment "${preSegment}" does not exist.`);
|
|
371
|
+
}
|
|
254
372
|
}
|
|
373
|
+
currentRef[preSegment] = this.handlers[type].deserialize(currentRef[preSegment]);
|
|
255
374
|
}
|
|
256
|
-
|
|
257
|
-
});
|
|
375
|
+
}
|
|
258
376
|
return ref.data;
|
|
259
377
|
}
|
|
260
378
|
}
|
|
@@ -271,23 +389,23 @@ class RPCSerializer {
|
|
|
271
389
|
return data;
|
|
272
390
|
}
|
|
273
391
|
if (isAsyncIteratorObject(data)) {
|
|
274
|
-
return
|
|
392
|
+
return wrapAsyncIteratorPreservingEventMeta(data, {
|
|
275
393
|
mapResult: (result) => {
|
|
276
394
|
if (result.value === void 0) {
|
|
277
395
|
return result;
|
|
278
396
|
}
|
|
279
|
-
return { done: result.done, value: this.serializeValue(result.value,
|
|
397
|
+
return { done: result.done, value: this.serializeValue(result.value, false) };
|
|
280
398
|
},
|
|
281
399
|
mapError: (e) => new ErrorEvent(
|
|
282
|
-
this.serializeValue(toORPCError(e).toJSON(),
|
|
400
|
+
this.serializeValue(toORPCError(e).toJSON(), false),
|
|
283
401
|
{ cause: e }
|
|
284
402
|
)
|
|
285
403
|
});
|
|
286
404
|
}
|
|
287
|
-
return this.serializeValue(data, options);
|
|
288
|
-
}
|
|
289
|
-
serializeValue(data, options) {
|
|
290
405
|
const useFormDataForBlobs = options.useFormDataForBlobFields ?? this.defaultSerializeOptions?.useFormDataForBlobFields ?? true;
|
|
406
|
+
return this.serializeValue(data, useFormDataForBlobs);
|
|
407
|
+
}
|
|
408
|
+
serializeValue(data, useFormDataForBlobs) {
|
|
291
409
|
const { json, meta, maps, blobs } = this.jsonSerializer.serialize(data);
|
|
292
410
|
if (!useFormDataForBlobs || !blobs?.length) {
|
|
293
411
|
return { json, meta };
|
|
@@ -304,7 +422,7 @@ class RPCSerializer {
|
|
|
304
422
|
return data;
|
|
305
423
|
}
|
|
306
424
|
if (isAsyncIteratorObject(data)) {
|
|
307
|
-
return
|
|
425
|
+
return wrapAsyncIteratorPreservingEventMeta(data, {
|
|
308
426
|
mapResult: (result) => {
|
|
309
427
|
if (result.value === void 0) {
|
|
310
428
|
return result;
|
|
@@ -331,7 +449,7 @@ class RPCSerializer {
|
|
|
331
449
|
}
|
|
332
450
|
const serialized = JSON.parse(data.get("data"));
|
|
333
451
|
const blobs = [];
|
|
334
|
-
for (const [key, value] of data
|
|
452
|
+
for (const [key, value] of data) {
|
|
335
453
|
if (value instanceof Blob) {
|
|
336
454
|
blobs[Number(key)] = value;
|
|
337
455
|
}
|
|
@@ -340,4 +458,4 @@ class RPCSerializer {
|
|
|
340
458
|
}
|
|
341
459
|
}
|
|
342
460
|
|
|
343
|
-
export { RPCSerializer as R,
|
|
461
|
+
export { RPCSerializer as R, createORPCErrorFromJson as a, isInferableError as b, createORPCErrorFromMalformedResponse as c, RPCJsonSerializer as d, cloneORPCError as e, isORPCErrorJson as i, toORPCError as t, wrapAsyncIteratorPreservingEventMeta as w };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PromiseWithError, Registry, MaybeOptionalOptions } from '@orpc/shared';
|
|
2
|
+
import { StandardResponse } from '@standardserver/core';
|
|
2
3
|
|
|
3
4
|
interface ClientContext {
|
|
4
5
|
[key: PropertyKey]: any;
|
|
@@ -21,6 +22,11 @@ type NestedClient<TClientContext extends ClientContext> = Client<TClientContext,
|
|
|
21
22
|
[k: string]: NestedClient<TClientContext>;
|
|
22
23
|
};
|
|
23
24
|
type AnyNestedClient = NestedClient<any>;
|
|
25
|
+
/**
|
|
26
|
+
* Infers the **client context type** required by a client.
|
|
27
|
+
*
|
|
28
|
+
* @see {@link https://orpc.dev/docs/client/client-side#infer-client-context | Client-Side Clients - Infer Client Context}
|
|
29
|
+
*/
|
|
24
30
|
type InferClientContext<T extends AnyNestedClient> = T extends NestedClient<infer U> ? U : never;
|
|
25
31
|
interface ClientLink<TClientContext extends ClientContext> {
|
|
26
32
|
call: (path: string[], input: unknown, options: ClientOptions<TClientContext>) => Promise<unknown>;
|
|
@@ -29,6 +35,8 @@ interface ClientLink<TClientContext extends ClientContext> {
|
|
|
29
35
|
* Recursively infers the **input types** from a client.
|
|
30
36
|
*
|
|
31
37
|
* Produces a nested map where each endpoint's input type is preserved.
|
|
38
|
+
*
|
|
39
|
+
* @see {@link https://orpc.dev/docs/client/client-side#infer-client-inputs | Client-Side Clients - Infer Client Inputs}
|
|
32
40
|
*/
|
|
33
41
|
type InferClientInputs<T extends AnyNestedClient> = T extends Client<any, infer U, any, any> ? U : {
|
|
34
42
|
[K in keyof T]: T[K] extends AnyNestedClient ? InferClientInputs<T[K]> : never;
|
|
@@ -38,6 +46,8 @@ type InferClientInputs<T extends AnyNestedClient> = T extends Client<any, infer
|
|
|
38
46
|
*
|
|
39
47
|
* If an endpoint's input includes `{ body: ... }`, only the `body` portion is extracted.
|
|
40
48
|
* Produces a nested map of body input types.
|
|
49
|
+
*
|
|
50
|
+
* @see {@link https://orpc.dev/docs/client/client-side#infer-client-body-inputs | Client-Side Clients - Infer Client Body Inputs}
|
|
41
51
|
*/
|
|
42
52
|
type InferClientBodyInputs<T extends AnyNestedClient> = T extends Client<any, infer U, any, any> ? U extends {
|
|
43
53
|
body: infer UBody;
|
|
@@ -48,6 +58,8 @@ type InferClientBodyInputs<T extends AnyNestedClient> = T extends Client<any, in
|
|
|
48
58
|
* Recursively infers the **output types** from a client.
|
|
49
59
|
*
|
|
50
60
|
* Produces a nested map where each endpoint's output type is preserved.
|
|
61
|
+
*
|
|
62
|
+
* @see {@link https://orpc.dev/docs/client/client-side#infer-client-outputs | Client-Side Clients - Infer Client Outputs}
|
|
51
63
|
*/
|
|
52
64
|
type InferClientOutputs<T extends AnyNestedClient> = T extends Client<any, any, infer U, any> ? U : {
|
|
53
65
|
[K in keyof T]: T[K] extends AnyNestedClient ? InferClientOutputs<T[K]> : never;
|
|
@@ -57,6 +69,8 @@ type InferClientOutputs<T extends AnyNestedClient> = T extends Client<any, any,
|
|
|
57
69
|
*
|
|
58
70
|
* If an endpoint's output includes `{ body: ... }`, only the `body` portion is extracted.
|
|
59
71
|
* Produces a nested map of body output types.
|
|
72
|
+
*
|
|
73
|
+
* @see {@link https://orpc.dev/docs/client/client-side#infer-client-body-outputs | Client-Side Clients - Infer Client Body Outputs}
|
|
60
74
|
*/
|
|
61
75
|
type InferClientBodyOutputs<T extends AnyNestedClient> = T extends Client<any, any, infer U, any> ? U extends {
|
|
62
76
|
body: infer UBody;
|
|
@@ -64,22 +78,33 @@ type InferClientBodyOutputs<T extends AnyNestedClient> = T extends Client<any, a
|
|
|
64
78
|
[K in keyof T]: T[K] extends AnyNestedClient ? InferClientBodyOutputs<T[K]> : never;
|
|
65
79
|
};
|
|
66
80
|
/**
|
|
67
|
-
* Recursively infers the **error types** from a client when you use [type-safe errors](https://orpc.dev/docs/error-handling#
|
|
81
|
+
* Recursively infers the **error types** from a client when you use [type-safe errors](https://orpc.dev/docs/error-handling#typesafe-errors).
|
|
68
82
|
*
|
|
69
83
|
* Produces a nested map where each endpoint's error type is preserved.
|
|
84
|
+
*
|
|
85
|
+
* @see {@link https://orpc.dev/docs/client/client-side#infer-client-errors | Client-Side Clients - Infer Client Errors}
|
|
70
86
|
*/
|
|
71
87
|
type InferClientErrors<T extends AnyNestedClient> = T extends Client<any, any, any, infer U> ? U : {
|
|
72
88
|
[K in keyof T]: T[K] extends AnyNestedClient ? InferClientErrors<T[K]> : never;
|
|
73
89
|
};
|
|
74
90
|
/**
|
|
75
|
-
* Recursively infers a **union of all error types** from a client when you use [type-safe errors](https://orpc.dev/docs/error-handling#
|
|
91
|
+
* Recursively infers a **union of all error types** from a client when you use [type-safe errors](https://orpc.dev/docs/error-handling#typesafe-errors).
|
|
76
92
|
*
|
|
77
93
|
* Useful when you want to handle all possible errors from any endpoint at once.
|
|
94
|
+
*
|
|
95
|
+
* @see {@link https://orpc.dev/docs/client/client-side#infer-client-error | Client-Side Clients - Infer Client Error}
|
|
78
96
|
*/
|
|
79
97
|
type InferClientError<T extends AnyNestedClient> = T extends Client<any, any, any, infer U> ? U : {
|
|
80
98
|
[K in keyof T]: T[K] extends AnyNestedClient ? InferClientError<T[K]> : never;
|
|
81
99
|
}[keyof T];
|
|
82
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Default mapping between common oRPC error codes and HTTP status codes.
|
|
103
|
+
* Handlers use it to determine response status codes; spread it to build a custom `errorStatusMap`.
|
|
104
|
+
*
|
|
105
|
+
* @see {@link https://orpc.dev/docs/rpc/handler#custom-error-response | RPC Handler - Custom Error Response}
|
|
106
|
+
* @see {@link https://orpc.dev/docs/openapi/handler#custom-error-response | OpenAPI Handler - Custom Error Response}
|
|
107
|
+
*/
|
|
83
108
|
declare const COMMON_ERROR_STATUS_MAP: {
|
|
84
109
|
BAD_REQUEST: number;
|
|
85
110
|
UNAUTHORIZED: number;
|
|
@@ -114,10 +139,16 @@ type ORPCErrorOptions<TData> = ErrorOptions & {
|
|
|
114
139
|
} : {
|
|
115
140
|
data: TData;
|
|
116
141
|
});
|
|
142
|
+
/**
|
|
143
|
+
* Typed error carrying a `code`, a `message`, and optional `data`.
|
|
144
|
+
* Throw it from handlers or middleware to produce typed error responses on the client.
|
|
145
|
+
*
|
|
146
|
+
* @see {@link https://orpc.dev/docs/error-handling#orpcerror-class | Error Handling - ORPCError Class}
|
|
147
|
+
*/
|
|
117
148
|
declare class ORPCError<TCode extends ORPCErrorCode, TData> extends Error {
|
|
118
149
|
/**
|
|
119
|
-
* @
|
|
120
|
-
* The `__branch` property is used for type branding, helping TypeScript distinguish
|
|
150
|
+
* @remarks
|
|
151
|
+
* **Note**: The `__branch` property is used for type branding, helping TypeScript distinguish
|
|
121
152
|
* an `ORPCError` instance from plain objects with a similar structure.
|
|
122
153
|
*/
|
|
123
154
|
readonly name: "ORPCError" & {
|
|
@@ -162,6 +193,23 @@ interface ORPCErrorJSON<TCode extends string, TData> extends Pick<ORPCError<TCod
|
|
|
162
193
|
}
|
|
163
194
|
type AnyORPCError = ORPCError<any, any>;
|
|
164
195
|
type AnyORPCErrorJSON = ORPCErrorJSON<any, any>;
|
|
196
|
+
interface MalformedResponseErrorOptions extends ErrorOptions {
|
|
197
|
+
message?: string;
|
|
198
|
+
response: StandardResponse;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Error indicating a response does not follow the expected oRPC format, carrying
|
|
202
|
+
* the resolved response. Found as the `cause` of a `MALFORMED_ORPC_RESPONSE`
|
|
203
|
+
* `ORPCError`.
|
|
204
|
+
*
|
|
205
|
+
* @see {@link https://orpc.dev/docs/rpc/link#malformed-responses | RPC Link - Malformed Responses}
|
|
206
|
+
* @see {@link https://orpc.dev/docs/openapi/link#malformed-responses | OpenAPI Link - Malformed Responses}
|
|
207
|
+
*/
|
|
208
|
+
declare class MalformedResponseError extends Error {
|
|
209
|
+
readonly name = "MalformedResponseError";
|
|
210
|
+
response: StandardResponse;
|
|
211
|
+
constructor(options: MalformedResponseErrorOptions);
|
|
212
|
+
}
|
|
165
213
|
|
|
166
|
-
export { ORPCError as
|
|
167
|
-
export type { AnyORPCError as A, ClientContext as C, FriendlyClientOptions as F, InferClientContext as I, NestedClient as N, ORPCErrorCode as O, ClientOptions as a, ClientLink as b,
|
|
214
|
+
export { ORPCError as h, COMMON_ERROR_STATUS_MAP as j, MalformedResponseError as p };
|
|
215
|
+
export type { AnyORPCError as A, ClientContext as C, FriendlyClientOptions as F, InferClientContext as I, MalformedResponseErrorOptions as M, NestedClient as N, ORPCErrorCode as O, ClientOptions as a, ClientLink as b, AnyNestedClient as c, InferClientError as d, Client as e, ClientRest as f, ORPCErrorJSON as g, AnyORPCErrorJSON as i, InferClientBodyInputs as k, InferClientBodyOutputs as l, InferClientErrors as m, InferClientInputs as n, InferClientOutputs as o, ORPCErrorOptions as q };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PromiseWithError, Registry, MaybeOptionalOptions } from '@orpc/shared';
|
|
2
|
+
import { StandardResponse } from '@standardserver/core';
|
|
2
3
|
|
|
3
4
|
interface ClientContext {
|
|
4
5
|
[key: PropertyKey]: any;
|
|
@@ -21,6 +22,11 @@ type NestedClient<TClientContext extends ClientContext> = Client<TClientContext,
|
|
|
21
22
|
[k: string]: NestedClient<TClientContext>;
|
|
22
23
|
};
|
|
23
24
|
type AnyNestedClient = NestedClient<any>;
|
|
25
|
+
/**
|
|
26
|
+
* Infers the **client context type** required by a client.
|
|
27
|
+
*
|
|
28
|
+
* @see {@link https://orpc.dev/docs/client/client-side#infer-client-context | Client-Side Clients - Infer Client Context}
|
|
29
|
+
*/
|
|
24
30
|
type InferClientContext<T extends AnyNestedClient> = T extends NestedClient<infer U> ? U : never;
|
|
25
31
|
interface ClientLink<TClientContext extends ClientContext> {
|
|
26
32
|
call: (path: string[], input: unknown, options: ClientOptions<TClientContext>) => Promise<unknown>;
|
|
@@ -29,6 +35,8 @@ interface ClientLink<TClientContext extends ClientContext> {
|
|
|
29
35
|
* Recursively infers the **input types** from a client.
|
|
30
36
|
*
|
|
31
37
|
* Produces a nested map where each endpoint's input type is preserved.
|
|
38
|
+
*
|
|
39
|
+
* @see {@link https://orpc.dev/docs/client/client-side#infer-client-inputs | Client-Side Clients - Infer Client Inputs}
|
|
32
40
|
*/
|
|
33
41
|
type InferClientInputs<T extends AnyNestedClient> = T extends Client<any, infer U, any, any> ? U : {
|
|
34
42
|
[K in keyof T]: T[K] extends AnyNestedClient ? InferClientInputs<T[K]> : never;
|
|
@@ -38,6 +46,8 @@ type InferClientInputs<T extends AnyNestedClient> = T extends Client<any, infer
|
|
|
38
46
|
*
|
|
39
47
|
* If an endpoint's input includes `{ body: ... }`, only the `body` portion is extracted.
|
|
40
48
|
* Produces a nested map of body input types.
|
|
49
|
+
*
|
|
50
|
+
* @see {@link https://orpc.dev/docs/client/client-side#infer-client-body-inputs | Client-Side Clients - Infer Client Body Inputs}
|
|
41
51
|
*/
|
|
42
52
|
type InferClientBodyInputs<T extends AnyNestedClient> = T extends Client<any, infer U, any, any> ? U extends {
|
|
43
53
|
body: infer UBody;
|
|
@@ -48,6 +58,8 @@ type InferClientBodyInputs<T extends AnyNestedClient> = T extends Client<any, in
|
|
|
48
58
|
* Recursively infers the **output types** from a client.
|
|
49
59
|
*
|
|
50
60
|
* Produces a nested map where each endpoint's output type is preserved.
|
|
61
|
+
*
|
|
62
|
+
* @see {@link https://orpc.dev/docs/client/client-side#infer-client-outputs | Client-Side Clients - Infer Client Outputs}
|
|
51
63
|
*/
|
|
52
64
|
type InferClientOutputs<T extends AnyNestedClient> = T extends Client<any, any, infer U, any> ? U : {
|
|
53
65
|
[K in keyof T]: T[K] extends AnyNestedClient ? InferClientOutputs<T[K]> : never;
|
|
@@ -57,6 +69,8 @@ type InferClientOutputs<T extends AnyNestedClient> = T extends Client<any, any,
|
|
|
57
69
|
*
|
|
58
70
|
* If an endpoint's output includes `{ body: ... }`, only the `body` portion is extracted.
|
|
59
71
|
* Produces a nested map of body output types.
|
|
72
|
+
*
|
|
73
|
+
* @see {@link https://orpc.dev/docs/client/client-side#infer-client-body-outputs | Client-Side Clients - Infer Client Body Outputs}
|
|
60
74
|
*/
|
|
61
75
|
type InferClientBodyOutputs<T extends AnyNestedClient> = T extends Client<any, any, infer U, any> ? U extends {
|
|
62
76
|
body: infer UBody;
|
|
@@ -64,22 +78,33 @@ type InferClientBodyOutputs<T extends AnyNestedClient> = T extends Client<any, a
|
|
|
64
78
|
[K in keyof T]: T[K] extends AnyNestedClient ? InferClientBodyOutputs<T[K]> : never;
|
|
65
79
|
};
|
|
66
80
|
/**
|
|
67
|
-
* Recursively infers the **error types** from a client when you use [type-safe errors](https://orpc.dev/docs/error-handling#
|
|
81
|
+
* Recursively infers the **error types** from a client when you use [type-safe errors](https://orpc.dev/docs/error-handling#typesafe-errors).
|
|
68
82
|
*
|
|
69
83
|
* Produces a nested map where each endpoint's error type is preserved.
|
|
84
|
+
*
|
|
85
|
+
* @see {@link https://orpc.dev/docs/client/client-side#infer-client-errors | Client-Side Clients - Infer Client Errors}
|
|
70
86
|
*/
|
|
71
87
|
type InferClientErrors<T extends AnyNestedClient> = T extends Client<any, any, any, infer U> ? U : {
|
|
72
88
|
[K in keyof T]: T[K] extends AnyNestedClient ? InferClientErrors<T[K]> : never;
|
|
73
89
|
};
|
|
74
90
|
/**
|
|
75
|
-
* Recursively infers a **union of all error types** from a client when you use [type-safe errors](https://orpc.dev/docs/error-handling#
|
|
91
|
+
* Recursively infers a **union of all error types** from a client when you use [type-safe errors](https://orpc.dev/docs/error-handling#typesafe-errors).
|
|
76
92
|
*
|
|
77
93
|
* Useful when you want to handle all possible errors from any endpoint at once.
|
|
94
|
+
*
|
|
95
|
+
* @see {@link https://orpc.dev/docs/client/client-side#infer-client-error | Client-Side Clients - Infer Client Error}
|
|
78
96
|
*/
|
|
79
97
|
type InferClientError<T extends AnyNestedClient> = T extends Client<any, any, any, infer U> ? U : {
|
|
80
98
|
[K in keyof T]: T[K] extends AnyNestedClient ? InferClientError<T[K]> : never;
|
|
81
99
|
}[keyof T];
|
|
82
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Default mapping between common oRPC error codes and HTTP status codes.
|
|
103
|
+
* Handlers use it to determine response status codes; spread it to build a custom `errorStatusMap`.
|
|
104
|
+
*
|
|
105
|
+
* @see {@link https://orpc.dev/docs/rpc/handler#custom-error-response | RPC Handler - Custom Error Response}
|
|
106
|
+
* @see {@link https://orpc.dev/docs/openapi/handler#custom-error-response | OpenAPI Handler - Custom Error Response}
|
|
107
|
+
*/
|
|
83
108
|
declare const COMMON_ERROR_STATUS_MAP: {
|
|
84
109
|
BAD_REQUEST: number;
|
|
85
110
|
UNAUTHORIZED: number;
|
|
@@ -114,10 +139,16 @@ type ORPCErrorOptions<TData> = ErrorOptions & {
|
|
|
114
139
|
} : {
|
|
115
140
|
data: TData;
|
|
116
141
|
});
|
|
142
|
+
/**
|
|
143
|
+
* Typed error carrying a `code`, a `message`, and optional `data`.
|
|
144
|
+
* Throw it from handlers or middleware to produce typed error responses on the client.
|
|
145
|
+
*
|
|
146
|
+
* @see {@link https://orpc.dev/docs/error-handling#orpcerror-class | Error Handling - ORPCError Class}
|
|
147
|
+
*/
|
|
117
148
|
declare class ORPCError<TCode extends ORPCErrorCode, TData> extends Error {
|
|
118
149
|
/**
|
|
119
|
-
* @
|
|
120
|
-
* The `__branch` property is used for type branding, helping TypeScript distinguish
|
|
150
|
+
* @remarks
|
|
151
|
+
* **Note**: The `__branch` property is used for type branding, helping TypeScript distinguish
|
|
121
152
|
* an `ORPCError` instance from plain objects with a similar structure.
|
|
122
153
|
*/
|
|
123
154
|
readonly name: "ORPCError" & {
|
|
@@ -162,6 +193,23 @@ interface ORPCErrorJSON<TCode extends string, TData> extends Pick<ORPCError<TCod
|
|
|
162
193
|
}
|
|
163
194
|
type AnyORPCError = ORPCError<any, any>;
|
|
164
195
|
type AnyORPCErrorJSON = ORPCErrorJSON<any, any>;
|
|
196
|
+
interface MalformedResponseErrorOptions extends ErrorOptions {
|
|
197
|
+
message?: string;
|
|
198
|
+
response: StandardResponse;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Error indicating a response does not follow the expected oRPC format, carrying
|
|
202
|
+
* the resolved response. Found as the `cause` of a `MALFORMED_ORPC_RESPONSE`
|
|
203
|
+
* `ORPCError`.
|
|
204
|
+
*
|
|
205
|
+
* @see {@link https://orpc.dev/docs/rpc/link#malformed-responses | RPC Link - Malformed Responses}
|
|
206
|
+
* @see {@link https://orpc.dev/docs/openapi/link#malformed-responses | OpenAPI Link - Malformed Responses}
|
|
207
|
+
*/
|
|
208
|
+
declare class MalformedResponseError extends Error {
|
|
209
|
+
readonly name = "MalformedResponseError";
|
|
210
|
+
response: StandardResponse;
|
|
211
|
+
constructor(options: MalformedResponseErrorOptions);
|
|
212
|
+
}
|
|
165
213
|
|
|
166
|
-
export { ORPCError as
|
|
167
|
-
export type { AnyORPCError as A, ClientContext as C, FriendlyClientOptions as F, InferClientContext as I, NestedClient as N, ORPCErrorCode as O, ClientOptions as a, ClientLink as b,
|
|
214
|
+
export { ORPCError as h, COMMON_ERROR_STATUS_MAP as j, MalformedResponseError as p };
|
|
215
|
+
export type { AnyORPCError as A, ClientContext as C, FriendlyClientOptions as F, InferClientContext as I, MalformedResponseErrorOptions as M, NestedClient as N, ORPCErrorCode as O, ClientOptions as a, ClientLink as b, AnyNestedClient as c, InferClientError as d, Client as e, ClientRest as f, ORPCErrorJSON as g, AnyORPCErrorJSON as i, InferClientBodyInputs as k, InferClientBodyOutputs as l, InferClientErrors as m, InferClientInputs as n, InferClientOutputs as o, ORPCErrorOptions as q };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolveMaybeOptionalOptions,
|
|
1
|
+
import { resolveMaybeOptionalOptions, getConstructors } from '@orpc/shared';
|
|
2
2
|
|
|
3
3
|
const COMMON_ERROR_STATUS_MAP = {
|
|
4
4
|
BAD_REQUEST: 400,
|
|
@@ -33,8 +33,8 @@ class ORPCError extends Error {
|
|
|
33
33
|
ORPCErrorConstructors.add(ORPCError);
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
|
-
* @
|
|
37
|
-
* The `__branch` property is used for type branding, helping TypeScript distinguish
|
|
36
|
+
* @remarks
|
|
37
|
+
* **Note**: The `__branch` property is used for type branding, helping TypeScript distinguish
|
|
38
38
|
* an `ORPCError` instance from plain objects with a similar structure.
|
|
39
39
|
*/
|
|
40
40
|
name = "ORPCError";
|
|
@@ -81,12 +81,21 @@ class ORPCError extends Error {
|
|
|
81
81
|
if (!ORPCErrorConstructors.has(this)) {
|
|
82
82
|
return super[Symbol.hasInstance](instance);
|
|
83
83
|
}
|
|
84
|
-
const constructor
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
for (const constructor of getConstructors(instance)) {
|
|
85
|
+
if (ORPCErrorConstructors.has(constructor)) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
87
88
|
}
|
|
88
|
-
return
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
class MalformedResponseError extends Error {
|
|
93
|
+
name = "MalformedResponseError";
|
|
94
|
+
response;
|
|
95
|
+
constructor(options) {
|
|
96
|
+
super(options.message, options);
|
|
97
|
+
this.response = options.response;
|
|
89
98
|
}
|
|
90
99
|
}
|
|
91
100
|
|
|
92
|
-
export { COMMON_ERROR_STATUS_MAP as C, ORPCError as O };
|
|
101
|
+
export { COMMON_ERROR_STATUS_MAP as C, MalformedResponseError as M, ORPCError as O };
|