@orpc/client 1.14.6 → 2.0.0-beta.10
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 +78 -107
- package/dist/adapters/fetch/index.d.mts +54 -35
- package/dist/adapters/fetch/index.d.ts +54 -35
- package/dist/adapters/fetch/index.mjs +49 -27
- package/dist/adapters/message-port/index.d.mts +25 -30
- package/dist/adapters/message-port/index.d.ts +25 -30
- package/dist/adapters/message-port/index.mjs +33 -29
- package/dist/adapters/standard/index.d.mts +59 -9
- package/dist/adapters/standard/index.d.ts +59 -9
- package/dist/adapters/standard/index.mjs +5 -5
- package/dist/adapters/websocket/index.d.mts +113 -21
- package/dist/adapters/websocket/index.d.ts +113 -21
- package/dist/adapters/websocket/index.mjs +95 -37
- package/dist/index.d.mts +84 -159
- package/dist/index.d.ts +84 -159
- package/dist/index.mjs +76 -34
- package/dist/plugins/index.d.mts +125 -132
- package/dist/plugins/index.d.ts +125 -132
- package/dist/plugins/index.mjs +373 -284
- package/dist/shared/client.8ug8I-zu.d.mts +167 -0
- package/dist/shared/client.8ug8I-zu.d.ts +167 -0
- package/dist/shared/client.BN52ep3E.mjs +174 -0
- package/dist/shared/client.BdItY5DT.d.mts +111 -0
- package/dist/shared/client.BdItY5DT.d.ts +111 -0
- package/dist/shared/client.CPF3hX6O.d.ts +96 -0
- package/dist/shared/client.Cby_-GGh.d.mts +96 -0
- package/dist/shared/client.D3TIIok6.mjs +343 -0
- package/dist/shared/client.Dnfj8jnT.mjs +92 -0
- package/package.json +7 -7
- package/dist/shared/client.2jUAqzYU.d.ts +0 -45
- package/dist/shared/client.B3pNRBih.d.ts +0 -91
- package/dist/shared/client.BFAVy68H.d.mts +0 -91
- package/dist/shared/client.BLtwTQUg.mjs +0 -40
- package/dist/shared/client.CpCa3si8.d.mts +0 -45
- package/dist/shared/client.D9eWXdBV.mjs +0 -174
- package/dist/shared/client.DLhbktiD.mjs +0 -404
- package/dist/shared/client.i2uoJbEp.d.mts +0 -83
- package/dist/shared/client.i2uoJbEp.d.ts +0 -83
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { StandardBody } from '@standardserver/core';
|
|
2
|
+
import { Segment } from '@orpc/shared';
|
|
3
|
+
|
|
4
|
+
type RPCJsonSerializationMeta = [type: string, ...path: Segment[]];
|
|
5
|
+
type RPCJsonSerialization = {
|
|
6
|
+
json: unknown;
|
|
7
|
+
meta?: RPCJsonSerializationMeta[] | undefined;
|
|
8
|
+
maps?: undefined;
|
|
9
|
+
blobs?: undefined;
|
|
10
|
+
} | {
|
|
11
|
+
json: unknown;
|
|
12
|
+
meta?: RPCJsonSerializationMeta[] | undefined;
|
|
13
|
+
maps: Segment[][];
|
|
14
|
+
blobs: Blob[];
|
|
15
|
+
};
|
|
16
|
+
interface RPCJsonSerializerHandler {
|
|
17
|
+
condition(value: unknown): boolean;
|
|
18
|
+
serialize(value: any): unknown;
|
|
19
|
+
deserialize(serialized: any): unknown;
|
|
20
|
+
/**
|
|
21
|
+
* If false, the result of this serializer will not be further processed by other serializers,
|
|
22
|
+
* even if it matches their conditions and treat it as final serialized value.
|
|
23
|
+
* This can be useful for serializers that return primitive values, which should not be further processed.
|
|
24
|
+
* to improve performance and avoid potential issues with other serializers.
|
|
25
|
+
*
|
|
26
|
+
* @default false
|
|
27
|
+
*/
|
|
28
|
+
isTerminal?: boolean;
|
|
29
|
+
}
|
|
30
|
+
interface RPCJsonSerializerOptions {
|
|
31
|
+
/**
|
|
32
|
+
* Extend or override the built-in type handlers used during serialization and deserialization.
|
|
33
|
+
*
|
|
34
|
+
* Each key is a unique type identifier (e.g. `"date"`, `"bigint"`) and maps to a handler
|
|
35
|
+
* that defines how to detect, serialize, and deserialize values of that type.
|
|
36
|
+
*
|
|
37
|
+
* **Extending:** Add new keys to support custom types:
|
|
38
|
+
* ```ts
|
|
39
|
+
* handlers: {
|
|
40
|
+
* buffer: {
|
|
41
|
+
* condition: (v) => v instanceof Buffer,
|
|
42
|
+
* serialize: (v: Buffer) => v.toString('base64'),
|
|
43
|
+
* deserialize: (s: string) => Buffer.from(s, 'base64'),
|
|
44
|
+
* isTerminal: true,
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* **Overriding:** Use an existing key to replace a built-in handler:
|
|
50
|
+
* ```ts
|
|
51
|
+
* handlers: {
|
|
52
|
+
* date: {
|
|
53
|
+
* condition: (v) => v instanceof Date,
|
|
54
|
+
* serialize: (v: Date) => v.getTime(),
|
|
55
|
+
* deserialize: (n: number) => new Date(n),
|
|
56
|
+
* isTerminal: true,
|
|
57
|
+
* }
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* **Disabling:** Set a key to `undefined` to remove a built-in handler:
|
|
62
|
+
* ```ts
|
|
63
|
+
* handlers: { regexp: undefined }
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* Built-in type keys: `undefined`, `bigint`, `date`, `nan`, `url`, `regexp`, `set`, `map`.
|
|
67
|
+
*/
|
|
68
|
+
handlers?: Record<string, undefined | RPCJsonSerializerHandler> | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* If true, properties with undefined values will be omitted during serialization.
|
|
71
|
+
*
|
|
72
|
+
* @default true
|
|
73
|
+
*/
|
|
74
|
+
omitUndefinedProperties?: boolean | undefined;
|
|
75
|
+
}
|
|
76
|
+
declare class RPCJsonSerializer {
|
|
77
|
+
private readonly handlers;
|
|
78
|
+
private readonly omitUndefinedProperties;
|
|
79
|
+
constructor(options?: RPCJsonSerializerOptions);
|
|
80
|
+
serialize(data: unknown): RPCJsonSerialization;
|
|
81
|
+
private serializeValue;
|
|
82
|
+
deserialize(serialized: RPCJsonSerialization): unknown;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
interface RPCSerializerSerializeOptions {
|
|
86
|
+
/**
|
|
87
|
+
* Use FormData for serialization when nested blobs are present.
|
|
88
|
+
* Does not apply to root-level Blob values.
|
|
89
|
+
*
|
|
90
|
+
* @default true
|
|
91
|
+
*/
|
|
92
|
+
useFormDataForBlobFields?: boolean;
|
|
93
|
+
}
|
|
94
|
+
interface RPCSerializerOptions extends RPCJsonSerializerOptions {
|
|
95
|
+
/**
|
|
96
|
+
* Default options for serialize method
|
|
97
|
+
*/
|
|
98
|
+
serialize?: RPCSerializerSerializeOptions | undefined;
|
|
99
|
+
}
|
|
100
|
+
declare class RPCSerializer {
|
|
101
|
+
private readonly jsonSerializer;
|
|
102
|
+
private readonly defaultSerializeOptions;
|
|
103
|
+
constructor(options?: RPCSerializerOptions);
|
|
104
|
+
serialize(data: unknown, options?: RPCSerializerSerializeOptions): StandardBody;
|
|
105
|
+
private serializeValue;
|
|
106
|
+
deserialize(data: StandardBody): unknown;
|
|
107
|
+
private deserializeValue;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export { RPCJsonSerializer as b, RPCSerializer as e };
|
|
111
|
+
export type { RPCJsonSerialization as R, RPCJsonSerializationMeta as a, RPCJsonSerializerHandler as c, RPCJsonSerializerOptions as d, RPCSerializerOptions as f, RPCSerializerSerializeOptions as g };
|
|
@@ -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.js';
|
|
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,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) {
|
|
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 };
|