@x-oasis/async-call-rpc 0.1.38
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 +48 -0
- package/dist/async-call-rpc.cjs.development.js +1275 -0
- package/dist/async-call-rpc.cjs.development.js.map +1 -0
- package/dist/async-call-rpc.cjs.production.min.js +2 -0
- package/dist/async-call-rpc.cjs.production.min.js.map +1 -0
- package/dist/async-call-rpc.esm.js +1559 -0
- package/dist/async-call-rpc.esm.js.map +1 -0
- package/dist/buffer/BufferFactory.d.ts +12 -0
- package/dist/buffer/DataBuffer.d.ts +2 -0
- package/dist/buffer/MessagePackBuffer.d.ts +10 -0
- package/dist/buffer/ReadBaseBuffer.d.ts +5 -0
- package/dist/buffer/ReadBuffer.d.ts +14 -0
- package/dist/buffer/SerializationFormat.d.ts +16 -0
- package/dist/buffer/WriteBaseBuffer.d.ts +5 -0
- package/dist/buffer/WriteBuffer.d.ts +5 -0
- package/dist/buffer/examples.d.ts +10 -0
- package/dist/buffer/index.d.ts +8 -0
- package/dist/common.d.ts +4 -0
- package/dist/endpoint/ProxyRPCClient.d.ts +12 -0
- package/dist/endpoint/RPCClientHost.d.ts +12 -0
- package/dist/endpoint/RPCService.d.ts +20 -0
- package/dist/endpoint/RPCServiceHost.d.ts +10 -0
- package/dist/error.d.ts +21 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +8 -0
- package/dist/middlewares/buffer.d.ts +18 -0
- package/dist/middlewares/handleDisconnectedRequest.d.ts +7 -0
- package/dist/middlewares/handlePortRequest.d.ts +3 -0
- package/dist/middlewares/handleRequest.d.ts +3 -0
- package/dist/middlewares/handleRequestUtils.d.ts +10 -0
- package/dist/middlewares/handleResponse.d.ts +3 -0
- package/dist/middlewares/index.d.ts +7 -0
- package/dist/middlewares/logger.d.ts +4 -0
- package/dist/middlewares/normalize.d.ts +14 -0
- package/dist/middlewares/prepareRequestData.d.ts +28 -0
- package/dist/middlewares/sendRequest.d.ts +6 -0
- package/dist/middlewares/updateSeqInfo.d.ts +6 -0
- package/dist/middlewares/utils.d.ts +3 -0
- package/dist/protocol/AbstractChannelProtocol.d.ts +55 -0
- package/dist/protocol/MessageChannel.d.ts +18 -0
- package/dist/protocol/WebSocketChannel.d.ts +23 -0
- package/dist/protocol/WorkerChannel.d.ts +11 -0
- package/dist/types/buffer.d.ts +4 -0
- package/dist/types/channel.d.ts +27 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/middleware.d.ts +44 -0
- package/dist/types/proxyChannel.d.ts +3 -0
- package/dist/types/proxyService.d.ts +11 -0
- package/dist/types/rpc.d.ts +25 -0
- package/dist/types/rpcProtocol.d.ts +22 -0
- package/dist/utils/constants.d.ts +5 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/jsonrpc.d.ts +36 -0
- package/package.json +36 -0
- package/src/buffer/ARCHITECTURE.md +298 -0
- package/src/buffer/BufferFactory.ts +124 -0
- package/src/buffer/CHANGELOG.md +207 -0
- package/src/buffer/DataBuffer.ts +1 -0
- package/src/buffer/MessagePackBuffer.ts +79 -0
- package/src/buffer/OPTIMIZATION.md +258 -0
- package/src/buffer/README.md +147 -0
- package/src/buffer/ReadBaseBuffer.ts +20 -0
- package/src/buffer/ReadBuffer.ts +58 -0
- package/src/buffer/SerializationFormat.ts +81 -0
- package/src/buffer/WriteBaseBuffer.ts +20 -0
- package/src/buffer/WriteBuffer.ts +15 -0
- package/src/buffer/examples.ts +242 -0
- package/src/buffer/index.ts +15 -0
- package/src/common.ts +20 -0
- package/src/endpoint/ProxyRPCClient.ts +64 -0
- package/src/endpoint/RPCClientHost.ts +45 -0
- package/src/endpoint/RPCService.ts +54 -0
- package/src/endpoint/RPCServiceHost.ts +18 -0
- package/src/error.ts +98 -0
- package/src/index.ts +16 -0
- package/src/middlewares/buffer.ts +33 -0
- package/src/middlewares/handleDisconnectedRequest.ts +30 -0
- package/src/middlewares/handlePortRequest.ts +141 -0
- package/src/middlewares/handleRequest.ts +128 -0
- package/src/middlewares/handleRequestUtils.ts +43 -0
- package/src/middlewares/handleResponse.ts +36 -0
- package/src/middlewares/index.ts +11 -0
- package/src/middlewares/logger.ts +22 -0
- package/src/middlewares/normalize.ts +167 -0
- package/src/middlewares/prepareRequestData.ts +137 -0
- package/src/middlewares/sendRequest.ts +15 -0
- package/src/middlewares/updateSeqInfo.ts +34 -0
- package/src/middlewares/utils.ts +67 -0
- package/src/protocol/AbstractChannelProtocol.ts +343 -0
- package/src/protocol/MessageChannel.ts +80 -0
- package/src/protocol/WebSocketChannel.ts +179 -0
- package/src/protocol/WorkerChannel.ts +36 -0
- package/src/types/buffer.ts +5 -0
- package/src/types/channel.ts +50 -0
- package/src/types/index.ts +9 -0
- package/src/types/messageChannel.ts +133 -0
- package/src/types/middleware.ts +54 -0
- package/src/types/proxyChannel.ts +3 -0
- package/src/types/proxyService.ts +18 -0
- package/src/types/rpc.ts +61 -0
- package/src/types/rpcProtocol.ts +24 -0
- package/src/utils/constants.ts +17 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/jsonrpc.ts +242 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { IpcRenderer, UtilityProcess, WebContents } from 'electron';
|
|
2
|
+
import { AbstractChannelProtocolProps as BaseAbstractChannelProtocolProps } from './channel';
|
|
3
|
+
|
|
4
|
+
export interface ChannelPort {
|
|
5
|
+
on(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
|
|
6
|
+
removeListener(
|
|
7
|
+
event: 'message',
|
|
8
|
+
listener: (messageEvent: MessageEvent) => void
|
|
9
|
+
): this;
|
|
10
|
+
postMessage(message: any, transfer?: MainPort[]): void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type UtilityMessageChannelPortStoreProps = {
|
|
14
|
+
name: string;
|
|
15
|
+
port: ParentPort;
|
|
16
|
+
masterProcessName: string;
|
|
17
|
+
clientMiddlewares?: ClientMiddleware[];
|
|
18
|
+
senderMiddlewares?: SenderMiddleware[];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type OnMessageEntry = {
|
|
22
|
+
data: any;
|
|
23
|
+
ports: any;
|
|
24
|
+
};
|
|
25
|
+
export type SenderEntry = any;
|
|
26
|
+
|
|
27
|
+
export type ClientMiddleware = (
|
|
28
|
+
channel?: MessageChannelProtocol
|
|
29
|
+
) => (v: OnMessageEntry) => OnMessageEntry;
|
|
30
|
+
|
|
31
|
+
export type SenderMiddleware = (
|
|
32
|
+
channel?: MessageChannelProtocol
|
|
33
|
+
) => (data: SenderEntry) => SenderEntry;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Extended AbstractChannelProtocolProps for message channel protocols
|
|
37
|
+
* Includes additional middleware configuration options
|
|
38
|
+
*/
|
|
39
|
+
export type AbstractChannelProtocolProps = BaseAbstractChannelProtocolProps & {
|
|
40
|
+
clientMiddlewares?: ClientMiddleware[];
|
|
41
|
+
senderMiddlewares?: SenderMiddleware[];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type DeferredMessageChannelProtocolProps =
|
|
45
|
+
AbstractChannelProtocolProps & {
|
|
46
|
+
port?: MainPort;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type MessageChannelProtocolProps = AbstractChannelProtocolProps & {
|
|
50
|
+
port?: MainPort;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type ProcessChannelProtocolProps = {
|
|
54
|
+
process: UtilityProcess;
|
|
55
|
+
} & AbstractChannelProtocolProps;
|
|
56
|
+
|
|
57
|
+
export type IPCMainGlobalChannelProtocolProps = AbstractChannelProtocolProps & {
|
|
58
|
+
channelName: string;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export type IPCMainChannelProtocolProps = {
|
|
62
|
+
channelName: string;
|
|
63
|
+
webContents: WebContents;
|
|
64
|
+
} & AbstractChannelProtocolProps;
|
|
65
|
+
|
|
66
|
+
export type IPCRendererChannelProtocolProps = {
|
|
67
|
+
channelName: string;
|
|
68
|
+
ipcRenderer: IpcRenderer;
|
|
69
|
+
projectName: string;
|
|
70
|
+
} & AbstractChannelProtocolProps;
|
|
71
|
+
|
|
72
|
+
export interface ParentPort extends NodeJS.EventEmitter {
|
|
73
|
+
on(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
|
|
74
|
+
once(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
|
|
75
|
+
addListener(
|
|
76
|
+
event: 'message',
|
|
77
|
+
listener: (messageEvent: MessageEvent) => void
|
|
78
|
+
): this;
|
|
79
|
+
removeListener(
|
|
80
|
+
event: 'message',
|
|
81
|
+
listener: (messageEvent: MessageEvent) => void
|
|
82
|
+
): this;
|
|
83
|
+
postMessage(message: any): void;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export type UtilityNodeJSProcess = NodeJS.Process;
|
|
87
|
+
|
|
88
|
+
export interface MainPort extends NodeJS.EventEmitter {
|
|
89
|
+
// Docs: https://electronjs.org/docs/api/message-port-main
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Emitted when the remote end of a MessagePortMain object becomes disconnected.
|
|
93
|
+
*/
|
|
94
|
+
/**
|
|
95
|
+
* Emitted when a MessagePortMain object receives a message.
|
|
96
|
+
*/
|
|
97
|
+
on(event: 'close', listener: Function): this;
|
|
98
|
+
on(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
|
|
99
|
+
off(event: 'close', listener: Function): this;
|
|
100
|
+
off(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
|
|
101
|
+
once(event: 'close', listener: Function): this;
|
|
102
|
+
once(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
|
|
103
|
+
addListener(event: 'close', listener: Function): this;
|
|
104
|
+
addListener(
|
|
105
|
+
event: 'message',
|
|
106
|
+
listener: (messageEvent: MessageEvent) => void
|
|
107
|
+
): this;
|
|
108
|
+
removeListener(event: 'close', listener: Function): this;
|
|
109
|
+
removeListener(
|
|
110
|
+
event: 'message',
|
|
111
|
+
listener: (messageEvent: MessageEvent) => void
|
|
112
|
+
): this;
|
|
113
|
+
/**
|
|
114
|
+
* Disconnects the port, so it is no longer active.
|
|
115
|
+
*/
|
|
116
|
+
close(): void;
|
|
117
|
+
/**
|
|
118
|
+
* Sends a message from the port, and optionally, transfers ownership of objects to
|
|
119
|
+
* other browsing contexts.
|
|
120
|
+
*/
|
|
121
|
+
postMessage(message: any, transfer?: MainPort[]): void;
|
|
122
|
+
/**
|
|
123
|
+
* Starts the sending of messages queued on the port. Messages will be queued until
|
|
124
|
+
* this method is called.
|
|
125
|
+
*/
|
|
126
|
+
start(): void;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function isUtilityProcess(
|
|
130
|
+
process: NodeJS.Process
|
|
131
|
+
): process is UtilityNodeJSProcess {
|
|
132
|
+
return !!(process as UtilityNodeJSProcess).parentPort;
|
|
133
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Deferred } from '@x-oasis/deferred';
|
|
2
|
+
|
|
3
|
+
import { HostRequestEntry, RequestEntry } from './rpc';
|
|
4
|
+
|
|
5
|
+
export type MiddlewareFunction = {
|
|
6
|
+
(...args: any[]): any;
|
|
7
|
+
displayName?: string;
|
|
8
|
+
lifecycle?: SendMiddlewareLifecycle;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type MessageOutput = {
|
|
12
|
+
event: any;
|
|
13
|
+
ports: any;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type NormalizedRawMessageOutput = MessageOutput & {
|
|
17
|
+
data: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type DeserializedMessageOutput = MessageOutput & {
|
|
21
|
+
data: HostRequestEntry | RequestEntry;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type SenderMiddlewareOutput = {
|
|
25
|
+
data: any;
|
|
26
|
+
transfer: any;
|
|
27
|
+
seqId: number;
|
|
28
|
+
returnValue: Deferred;
|
|
29
|
+
isOptionsRequest: boolean;
|
|
30
|
+
middlewareContext: MiddlewareContext;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type PendingSendEntry = SenderMiddlewareOutput & {
|
|
34
|
+
// fnName: string;
|
|
35
|
+
methodName: string;
|
|
36
|
+
lifecycle: SendMiddlewareLifecycle;
|
|
37
|
+
middlewareContext: MiddlewareContext;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type MiddlewareContext = {
|
|
41
|
+
isResumed?: boolean;
|
|
42
|
+
startLifecycle: SendMiddlewareLifecycle;
|
|
43
|
+
minLifecycle: SendMiddlewareLifecycle;
|
|
44
|
+
reserved: PendingSendEntry;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export enum SendMiddlewareLifecycle {
|
|
48
|
+
Initial = 0,
|
|
49
|
+
Prepare = 10,
|
|
50
|
+
Transform = 20,
|
|
51
|
+
DataOperation = 30,
|
|
52
|
+
Send = 40,
|
|
53
|
+
Aborted = 100,
|
|
54
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import AbstractChannelProtocol from '../protocol/AbstractChannelProtocol';
|
|
2
|
+
|
|
3
|
+
// export type IService = {
|
|
4
|
+
// [key: string]: Function
|
|
5
|
+
// }
|
|
6
|
+
export type IService = any;
|
|
7
|
+
|
|
8
|
+
export type ServiceHandlerPath = string;
|
|
9
|
+
export type ProxyRPCClientChannel =
|
|
10
|
+
| AbstractChannelProtocol
|
|
11
|
+
| { (): AbstractChannelProtocol };
|
|
12
|
+
|
|
13
|
+
export type ProxyRPCClientProps = {
|
|
14
|
+
requestPath: string;
|
|
15
|
+
channel: ProxyRPCClientChannel;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type ServiceHandlers = Record<string, (...args: any[]) => any>;
|
package/src/types/rpc.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export enum RequestType {
|
|
2
|
+
/**
|
|
3
|
+
* for normal request, wait for return value
|
|
4
|
+
*/
|
|
5
|
+
PromiseRequest = 'pr',
|
|
6
|
+
PromiseAbort = 'pa',
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* send a command
|
|
10
|
+
*/
|
|
11
|
+
SignalRequest = 'sr',
|
|
12
|
+
SignalAbort = 'sa',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type RequestRawSequenceId = number;
|
|
16
|
+
|
|
17
|
+
export type RequestSequenceId = string;
|
|
18
|
+
export type RequestServicePath = string;
|
|
19
|
+
export type RequestFnName = string;
|
|
20
|
+
|
|
21
|
+
export type RequestEntryHeader = [
|
|
22
|
+
RequestType,
|
|
23
|
+
RequestSequenceId,
|
|
24
|
+
RequestServicePath,
|
|
25
|
+
RequestFnName
|
|
26
|
+
];
|
|
27
|
+
export type RequestEntryBody = any;
|
|
28
|
+
export type RequestEntry = [RequestEntryHeader, RequestEntryBody];
|
|
29
|
+
|
|
30
|
+
export enum ResponseType {
|
|
31
|
+
ReturnSuccess = 'rs',
|
|
32
|
+
ReturnFail = 'rf',
|
|
33
|
+
|
|
34
|
+
PortSuccess = 'ps',
|
|
35
|
+
PortFail = 'pf',
|
|
36
|
+
}
|
|
37
|
+
export type ResponseEntryHeader = [ResponseType, RequestSequenceId];
|
|
38
|
+
export type ResponseEntryBody = any;
|
|
39
|
+
|
|
40
|
+
export type HostName = string;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 0 RequestType: PromiseRequest, PromiseAbort, SignalRequest, SignalAbort
|
|
44
|
+
* 1 RequestSequenceId: string
|
|
45
|
+
*/
|
|
46
|
+
export type HostRequestEntryHeader = [
|
|
47
|
+
RequestType,
|
|
48
|
+
RequestSequenceId,
|
|
49
|
+
RequestServicePath,
|
|
50
|
+
RequestFnName,
|
|
51
|
+
HostName
|
|
52
|
+
];
|
|
53
|
+
export type HostRequestEntryBody = any;
|
|
54
|
+
export type HostRequestEntry = [HostRequestEntryHeader, HostRequestEntryBody];
|
|
55
|
+
|
|
56
|
+
// export type SendingProps = {
|
|
57
|
+
// requestPath?: string;
|
|
58
|
+
// fnName?: string;
|
|
59
|
+
// args?: any;
|
|
60
|
+
// isOptionsRequest?: boolean;
|
|
61
|
+
// };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type IRPCProtocolServer = {
|
|
2
|
+
source: any;
|
|
3
|
+
encoder: null;
|
|
4
|
+
decoder: null;
|
|
5
|
+
onRequest: () => {};
|
|
6
|
+
handleRequest: () => {};
|
|
7
|
+
sendReply: () => {};
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type IRPCProtocolClient = {
|
|
11
|
+
source: any;
|
|
12
|
+
encode: () => {};
|
|
13
|
+
decode: () => {};
|
|
14
|
+
sendRequest: () => {};
|
|
15
|
+
onReply: () => {};
|
|
16
|
+
handleReply: () => {};
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type IRPCProtocol = {
|
|
20
|
+
encode: Function;
|
|
21
|
+
decode: Function;
|
|
22
|
+
onMessage: Function;
|
|
23
|
+
send: Function;
|
|
24
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants used for JSONRPC implementation
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export const ERROR = 'Error';
|
|
6
|
+
|
|
7
|
+
export const isArray = Array.isArray;
|
|
8
|
+
|
|
9
|
+
export const isObject = (val: unknown): val is object => {
|
|
10
|
+
return val !== null && typeof val === 'object' && !isArray(val);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const isFunction = (val: unknown): val is Function => {
|
|
14
|
+
return typeof val === 'function';
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const UNDEFINED = void 0;
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { ID, ErrorResponse } from '../error';
|
|
2
|
+
import { ERROR, isArray, isFunction, isObject, UNDEFINED } from './constants';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* JSONRPC version constant
|
|
6
|
+
*/
|
|
7
|
+
export const jsonrpc = '2.0' as const;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* JSONRPC Request interface
|
|
11
|
+
*/
|
|
12
|
+
export interface Request {
|
|
13
|
+
readonly jsonrpc: typeof jsonrpc;
|
|
14
|
+
readonly id?: ID;
|
|
15
|
+
readonly method: string;
|
|
16
|
+
readonly params: readonly unknown[] | object;
|
|
17
|
+
readonly remoteStack?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* JSONRPC Success Response interface
|
|
22
|
+
*/
|
|
23
|
+
export interface SuccessResponse {
|
|
24
|
+
readonly jsonrpc: typeof jsonrpc;
|
|
25
|
+
readonly id?: ID;
|
|
26
|
+
readonly result: unknown;
|
|
27
|
+
readonly undef?: boolean; // Non-standard extension for undefined values
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* JSONRPC Response type (success or error)
|
|
32
|
+
*/
|
|
33
|
+
export type Response = SuccessResponse | ErrorResponse<unknown>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Error map function type for custom error mapping
|
|
37
|
+
*/
|
|
38
|
+
export type ErrorMapFunction<T = unknown> = (
|
|
39
|
+
error: unknown,
|
|
40
|
+
request: Request
|
|
41
|
+
) => {
|
|
42
|
+
code: number;
|
|
43
|
+
message: string;
|
|
44
|
+
data?: T;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* AsyncCall error detail structure
|
|
49
|
+
*/
|
|
50
|
+
export interface AsyncCallErrorDetail {
|
|
51
|
+
readonly stack?: string;
|
|
52
|
+
readonly type?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Create a JSONRPC request object
|
|
57
|
+
*/
|
|
58
|
+
export const makeRequest = (
|
|
59
|
+
id: ID,
|
|
60
|
+
method: string,
|
|
61
|
+
params: readonly unknown[] | object,
|
|
62
|
+
remoteStack?: string
|
|
63
|
+
): Request => {
|
|
64
|
+
const x: Request = { jsonrpc, id, method, params, remoteStack };
|
|
65
|
+
deleteUndefined(x, 'id');
|
|
66
|
+
deleteFalsy(x, 'remoteStack');
|
|
67
|
+
return x;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Create a JSONRPC success response object
|
|
72
|
+
*/
|
|
73
|
+
export const makeSuccessResponse = (
|
|
74
|
+
id: ID,
|
|
75
|
+
result: unknown
|
|
76
|
+
): SuccessResponse => {
|
|
77
|
+
const x: SuccessResponse = { jsonrpc, id, result };
|
|
78
|
+
deleteUndefined(x, 'id');
|
|
79
|
+
return x;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Create a JSONRPC error response object
|
|
84
|
+
* Pre-defined errors from JSONRPC 2.0 specification section 5.1
|
|
85
|
+
*/
|
|
86
|
+
export const makeErrorResponse = <T>(
|
|
87
|
+
id: ID,
|
|
88
|
+
code: number,
|
|
89
|
+
message: string,
|
|
90
|
+
data?: T
|
|
91
|
+
): ErrorResponse<T> => {
|
|
92
|
+
if (id === UNDEFINED) id = null;
|
|
93
|
+
code = Math.floor(code);
|
|
94
|
+
if (Number.isNaN(code)) code = -1;
|
|
95
|
+
const x: ErrorResponse<T> = {
|
|
96
|
+
jsonrpc,
|
|
97
|
+
id,
|
|
98
|
+
error: { code, message, data },
|
|
99
|
+
};
|
|
100
|
+
deleteUndefined(x.error, 'data');
|
|
101
|
+
return x;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Parse error response (-32700)
|
|
106
|
+
* Pre-defined error in JSONRPC 2.0 specification section 5.1
|
|
107
|
+
*/
|
|
108
|
+
export const ErrorResponseParseError = <T>(
|
|
109
|
+
e: unknown,
|
|
110
|
+
mapper: ErrorMapFunction<T>
|
|
111
|
+
): ErrorResponse<T> => {
|
|
112
|
+
const obj = ErrorResponseMapped({} as any, e, mapper);
|
|
113
|
+
const o = obj.error as Mutable<ErrorResponse['error']>;
|
|
114
|
+
o.code = -32700;
|
|
115
|
+
o.message = 'Parse error';
|
|
116
|
+
return obj;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Invalid Request error response (-32600)
|
|
121
|
+
* Pre-defined error in JSONRPC 2.0 specification section 5.1
|
|
122
|
+
*/
|
|
123
|
+
export const ErrorResponseInvalidRequest = (id: ID): ErrorResponse => {
|
|
124
|
+
return makeErrorResponse(id, -32600, 'Invalid Request');
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Method not found error response (-32601)
|
|
129
|
+
* Pre-defined error in JSONRPC 2.0 specification section 5.1
|
|
130
|
+
*/
|
|
131
|
+
export const ErrorResponseMethodNotFound = (id: ID): ErrorResponse => {
|
|
132
|
+
return makeErrorResponse(id, -32601, 'Method not found');
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Invalid params error response (-32602)
|
|
137
|
+
* Pre-defined error in JSONRPC 2.0 specification section 5.1
|
|
138
|
+
*/
|
|
139
|
+
export const ErrorResponseInvalidParams = (id: ID): ErrorResponse => {
|
|
140
|
+
return makeErrorResponse(id, -32602, 'Invalid params');
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Internal error response (-32603)
|
|
145
|
+
* Pre-defined error in JSONRPC 2.0 specification section 5.1
|
|
146
|
+
*/
|
|
147
|
+
export const ErrorResponseInternalError = (id: ID): ErrorResponse => {
|
|
148
|
+
return makeErrorResponse(id, -32603, 'Internal error');
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Map an error to a JSONRPC error response using a custom mapper
|
|
153
|
+
*/
|
|
154
|
+
export const ErrorResponseMapped = <T>(
|
|
155
|
+
request: Request,
|
|
156
|
+
e: unknown,
|
|
157
|
+
mapper: ErrorMapFunction<T>
|
|
158
|
+
): ErrorResponse<T> => {
|
|
159
|
+
const { id } = request;
|
|
160
|
+
const { code, message, data } = mapper(e, request);
|
|
161
|
+
return makeErrorResponse(id, code, message, data);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Default error mapper that extracts error information
|
|
166
|
+
*/
|
|
167
|
+
export const defaultErrorMapper =
|
|
168
|
+
(stack = '', code = -1): ErrorMapFunction<AsyncCallErrorDetail> =>
|
|
169
|
+
(e) => {
|
|
170
|
+
let message = toString('', () => (e as any).message);
|
|
171
|
+
let type = toString(
|
|
172
|
+
ERROR,
|
|
173
|
+
(ctor = (e as any).constructor) => isFunction(ctor) && ctor.name
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// Check for DOMException
|
|
177
|
+
const E = globalThis.DOMException;
|
|
178
|
+
if (E && e instanceof E) {
|
|
179
|
+
type = `DOMException:${e.name}`;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const eType = typeof e;
|
|
183
|
+
if (
|
|
184
|
+
eType === 'string' ||
|
|
185
|
+
eType === 'number' ||
|
|
186
|
+
eType === 'boolean' ||
|
|
187
|
+
eType === 'bigint'
|
|
188
|
+
) {
|
|
189
|
+
type = ERROR;
|
|
190
|
+
message = String(e);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const data: AsyncCallErrorDetail = stack ? { stack, type } : { type };
|
|
194
|
+
return { code, message, data };
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Check if an object is a valid JSONRPC request or response
|
|
199
|
+
*/
|
|
200
|
+
export const isJSONRPCObject = (data: any): data is Response | Request => {
|
|
201
|
+
if (!isObject(data)) return false;
|
|
202
|
+
if (!('jsonrpc' in data)) return false;
|
|
203
|
+
const obj = data as { jsonrpc?: string; params?: unknown };
|
|
204
|
+
if (obj.jsonrpc !== jsonrpc) return false;
|
|
205
|
+
if ('params' in obj) {
|
|
206
|
+
const params = obj.params;
|
|
207
|
+
if (!isArray(params) && !isObject(params)) return false;
|
|
208
|
+
}
|
|
209
|
+
return true;
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Helper function to safely convert value to string
|
|
214
|
+
*/
|
|
215
|
+
const toString = (_default: string, val: () => any): string => {
|
|
216
|
+
try {
|
|
217
|
+
const v = val();
|
|
218
|
+
if (v === UNDEFINED) return _default;
|
|
219
|
+
return String(v);
|
|
220
|
+
} catch {
|
|
221
|
+
return _default;
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Delete undefined property from object
|
|
227
|
+
*/
|
|
228
|
+
const deleteUndefined = <O>(x: O, key: keyof O): void => {
|
|
229
|
+
if (x[key] === UNDEFINED) delete x[key];
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Delete falsy property from object
|
|
234
|
+
*/
|
|
235
|
+
const deleteFalsy = <T>(x: T, key: keyof T): void => {
|
|
236
|
+
if (!x[key]) delete x[key];
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Make a type mutable
|
|
241
|
+
*/
|
|
242
|
+
type Mutable<T> = { -readonly [key in keyof T]: T[key] };
|