@irpclib/irpc 0.0.1 → 1.0.0-beta.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cache.d.ts +20 -0
- package/dist/cache.js +55 -0
- package/dist/call.d.ts +2 -1
- package/dist/call.js +4 -3
- package/dist/error.d.ts +50 -0
- package/dist/error.js +50 -0
- package/dist/index.d.ts +7 -5
- package/dist/index.js +6 -5
- package/dist/module.d.ts +97 -11
- package/dist/module.js +145 -125
- package/dist/resolver.d.ts +61 -0
- package/dist/resolver.js +143 -0
- package/dist/transport.d.ts +45 -0
- package/dist/transport.js +74 -0
- package/dist/types.d.ts +45 -71
- package/dist/types.js +1 -8
- package/dist/uuid.d.ts +21 -0
- package/dist/uuid.js +45 -0
- package/package.json +11 -15
- package/readme.md +139 -111
- package/dist/batch.d.ts +0 -18
- package/dist/batch.js +0 -23
- package/dist/utils.d.ts +0 -17
- package/dist/utils.js +0 -26
package/dist/module.js
CHANGED
|
@@ -1,156 +1,176 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { IRPCCacher } from "./cache.js";
|
|
2
|
+
import { ERROR_CODE, ERROR_MESSAGE } from "./error.js";
|
|
3
|
+
import { IRPCTransport } from "./transport.js";
|
|
3
4
|
|
|
4
5
|
//#region src/module.ts
|
|
5
6
|
const DEFAULT_TIMEOUT = 2e4;
|
|
7
|
+
const NAME_CONSTRAINT = /^[a-zA-Z0-9_]+$/;
|
|
8
|
+
const VERSION_CONSTRAINT = /^[0-9]+\.[0-9]+\.[0-9]+$/;
|
|
6
9
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* a registry for mapping functions to their specifications, and various methods
|
|
11
|
-
* for managing and executing remote procedure calls.
|
|
12
|
-
*
|
|
13
|
-
* @param config - Optional partial configuration for the IRPC module, excluding 'submit' and 'transport'
|
|
14
|
-
* @returns An IRPC factory function with attached utility methods
|
|
10
|
+
* IRPCPackage represents a package containing multiple IRPC (Isomorphic-RPC) specifications
|
|
11
|
+
* and their corresponding stubs. It manages the configuration, transport, and execution
|
|
12
|
+
* of remote procedure calls.
|
|
15
13
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
var IRPCPackage = class {
|
|
15
|
+
/**
|
|
16
|
+
* A map storing all IRPC specifications by their names
|
|
17
|
+
*/
|
|
18
|
+
specs = /* @__PURE__ */ new Map();
|
|
19
|
+
/**
|
|
20
|
+
* A weak map linking stub functions to their corresponding specifications
|
|
21
|
+
*/
|
|
22
|
+
stubs = /* @__PURE__ */ new WeakMap();
|
|
23
|
+
/**
|
|
24
|
+
* A map storing caches for each IRPC Entry
|
|
25
|
+
*/
|
|
26
|
+
cache = /* @__PURE__ */ new WeakMap();
|
|
27
|
+
/**
|
|
28
|
+
* Configuration object for the IRPC package
|
|
29
|
+
*/
|
|
30
|
+
config = {
|
|
31
|
+
name: "global",
|
|
21
32
|
version: "1.0.0",
|
|
22
|
-
timeout: DEFAULT_TIMEOUT
|
|
23
|
-
...config
|
|
33
|
+
timeout: DEFAULT_TIMEOUT
|
|
24
34
|
};
|
|
25
35
|
/**
|
|
26
|
-
*
|
|
27
|
-
* Each handler can either execute a local function or make a remote call.
|
|
36
|
+
* Gets the href URL for this package in the format "name/version"
|
|
28
37
|
*/
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const fn = ((...args) => {
|
|
33
|
-
if (typeof host.handler === "function") return host.handler(...args);
|
|
34
|
-
else return remoteCall(module, host, ...args);
|
|
35
|
-
});
|
|
36
|
-
registry.set(fn, host);
|
|
37
|
-
return fn;
|
|
38
|
-
});
|
|
38
|
+
get href() {
|
|
39
|
+
return [this.config.name, this.config.version].join("/");
|
|
40
|
+
}
|
|
39
41
|
/**
|
|
40
|
-
*
|
|
42
|
+
* Gets the package information (name, version, and optional description)
|
|
41
43
|
*/
|
|
42
|
-
|
|
43
|
-
name
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
get info() {
|
|
45
|
+
const { name, version, description } = this.config;
|
|
46
|
+
return {
|
|
47
|
+
name,
|
|
48
|
+
version,
|
|
49
|
+
description
|
|
50
|
+
};
|
|
51
|
+
}
|
|
46
52
|
/**
|
|
47
|
-
*
|
|
48
|
-
* @param irpc - The IRPC function to construct
|
|
49
|
-
* @param handler - The actual implementation of the IRPC function
|
|
53
|
+
* Gets the transport mechanism used for remote calls
|
|
50
54
|
*/
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (!host) throw new Error("IRPC can not be found.");
|
|
55
|
-
host.handler = handler;
|
|
56
|
-
});
|
|
55
|
+
get transport() {
|
|
56
|
+
return this.config.transport;
|
|
57
|
+
}
|
|
57
58
|
/**
|
|
58
|
-
*
|
|
59
|
-
* @param
|
|
59
|
+
* Creates a new IRPCPackage instance
|
|
60
|
+
* @param config - Optional partial configuration for the package
|
|
61
|
+
* @throws Error if the package name or version doesn't match the required format
|
|
60
62
|
*/
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
});
|
|
63
|
+
constructor(config) {
|
|
64
|
+
this.configure(config ?? {});
|
|
65
|
+
}
|
|
65
66
|
/**
|
|
66
|
-
*
|
|
67
|
-
* @param
|
|
68
|
-
* @returns
|
|
67
|
+
* Declares a new IRPC specification and creates a corresponding stub function
|
|
68
|
+
* @param init - The initialization object containing the IRPC specification
|
|
69
|
+
* @returns A stub function that can be used to call the IRPC
|
|
70
|
+
* @throws Error if an IRPC with the same name already exists
|
|
69
71
|
*/
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
declare(init) {
|
|
73
|
+
if (this.specs.has(init.name)) throw new Error(`IRPC ${init.name} already exists.`);
|
|
74
|
+
const spec = { ...init };
|
|
75
|
+
const caches = new IRPCCacher();
|
|
76
|
+
const timeout = spec.timeout ?? this.config.timeout;
|
|
77
|
+
const stub = (async (...args) => {
|
|
78
|
+
if (typeof spec.handler === "function") return spec.handler(...args);
|
|
79
|
+
if (!this.transport) throw new Error(ERROR_MESSAGE[ERROR_CODE.TRANSPORT_MISSING]);
|
|
80
|
+
if (spec.maxAge) {
|
|
81
|
+
const key = JSON.stringify(args);
|
|
82
|
+
const cache = caches.get(key);
|
|
83
|
+
if (cache) return cache.value;
|
|
84
|
+
const data = await this.transport.call(spec, args, timeout);
|
|
85
|
+
caches.set(key, data, spec.maxAge);
|
|
86
|
+
return data;
|
|
87
|
+
}
|
|
88
|
+
return await this.transport.call(spec, args, timeout);
|
|
89
|
+
});
|
|
90
|
+
this.specs.set(init.name, spec);
|
|
91
|
+
this.stubs.set(stub, spec);
|
|
92
|
+
this.cache.set(stub, caches);
|
|
93
|
+
return stub;
|
|
94
|
+
}
|
|
73
95
|
/**
|
|
74
|
-
*
|
|
75
|
-
* @param
|
|
96
|
+
* Resolves and executes an IRPC call based on a request object
|
|
97
|
+
* @param req - The request containing the IRPC name and arguments
|
|
98
|
+
* @returns The result of the IRPC execution
|
|
99
|
+
* @throws Error if the IRPC doesn't exist or doesn't have an implementation
|
|
76
100
|
*/
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
101
|
+
async resolve(req) {
|
|
102
|
+
const spec = this.specs.get(req.name);
|
|
103
|
+
if (!spec) return Promise.reject(/* @__PURE__ */ new Error(`IRPC ${req.name} does not exist.`));
|
|
104
|
+
if (typeof spec.handler !== "function") return Promise.reject(/* @__PURE__ */ new Error(`IRPC ${req.name} does not have an implementation.`));
|
|
105
|
+
return await spec.handler(...req.args);
|
|
106
|
+
}
|
|
80
107
|
/**
|
|
81
|
-
*
|
|
82
|
-
* @param
|
|
108
|
+
* Associates a handler function with a stub function
|
|
109
|
+
* @param stub - The stub function created by declare()
|
|
110
|
+
* @param handler - The actual implementation function
|
|
111
|
+
* @returns This IRPCPackage instance for chaining
|
|
112
|
+
* @throws Error if the stub or handler is invalid, or if no IRPC exists for the stub
|
|
113
|
+
*/
|
|
114
|
+
construct(stub, handler) {
|
|
115
|
+
if (typeof stub !== "function") throw new Error(ERROR_MESSAGE[ERROR_CODE.STUB_INVALID]);
|
|
116
|
+
if (typeof handler !== "function") throw new Error(ERROR_MESSAGE[ERROR_CODE.INVALID_HANDLER]);
|
|
117
|
+
const spec = this.stubs.get(stub);
|
|
118
|
+
if (!spec?.name) throw new Error(ERROR_MESSAGE[ERROR_CODE.NOT_FOUND]);
|
|
119
|
+
spec.handler = handler;
|
|
120
|
+
return this;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Sets the transport mechanism for this package
|
|
124
|
+
* @param transport - The transport instance to use for remote calls
|
|
125
|
+
* @returns This IRPCPackage instance for chaining
|
|
126
|
+
* @throws Error if the transport is not a valid Transport instance
|
|
127
|
+
*/
|
|
128
|
+
use(transport) {
|
|
129
|
+
if (!(transport instanceof IRPCTransport)) throw new Error(ERROR_MESSAGE[ERROR_CODE.TRANSPORT_INVALID]);
|
|
130
|
+
this.config.transport = transport;
|
|
131
|
+
return this;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Retrieves an IRPC specification by name or request object
|
|
135
|
+
* @param query - Either a string name or an IRPCRequest object
|
|
83
136
|
* @returns The IRPC specification or undefined if not found
|
|
84
137
|
*/
|
|
85
|
-
|
|
86
|
-
return
|
|
87
|
-
|
|
138
|
+
get(query) {
|
|
139
|
+
if (typeof query === "string") return this.specs.get(query);
|
|
140
|
+
return this.specs.get(query.name);
|
|
141
|
+
}
|
|
88
142
|
/**
|
|
89
|
-
*
|
|
90
|
-
* @param
|
|
91
|
-
* @returns
|
|
143
|
+
* Updates the package configuration
|
|
144
|
+
* @param config - Partial configuration object with properties to update
|
|
145
|
+
* @returns This IRPCPackage instance for chaining
|
|
146
|
+
* @throws Error if the provided name or version is invalid
|
|
92
147
|
*/
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (!
|
|
96
|
-
|
|
97
|
-
return
|
|
98
|
-
}
|
|
148
|
+
configure(config) {
|
|
149
|
+
if (config.name && !NAME_CONSTRAINT.test(config.name)) throw new Error(`Invalid IRPC name: ${config.name}`);
|
|
150
|
+
if (config.version && !VERSION_CONSTRAINT.test(config.version)) throw new Error(`Invalid IRPC version: ${config.version}`);
|
|
151
|
+
Object.assign(this.config, config);
|
|
152
|
+
return this;
|
|
153
|
+
}
|
|
99
154
|
/**
|
|
100
|
-
*
|
|
101
|
-
* @param
|
|
155
|
+
* Invalidates the cache for a specific stub and arguments combination
|
|
156
|
+
* @param stub - The IRPC stub function whose cache needs to be invalidated
|
|
157
|
+
* @param args - The arguments array used as cache key
|
|
102
158
|
*/
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
});
|
|
111
|
-
} catch (error) {
|
|
112
|
-
calls.forEach((call) => {
|
|
113
|
-
call.reject(error);
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
return factory;
|
|
118
|
-
}
|
|
159
|
+
invalidate(stub, ...args) {
|
|
160
|
+
const caches = this.cache.get(stub);
|
|
161
|
+
if (!caches) return;
|
|
162
|
+
if (args.length) caches.delete(JSON.stringify(args));
|
|
163
|
+
else caches.clear();
|
|
164
|
+
}
|
|
165
|
+
};
|
|
119
166
|
/**
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* It handles timeouts and promise resolution/rejection based on the response.
|
|
124
|
-
*
|
|
125
|
-
* @param module - The IRPC module containing transport and configuration
|
|
126
|
-
* @param spec - The IRPC specification defining the remote procedure
|
|
127
|
-
* @param args - Arguments to pass to the remote procedure
|
|
128
|
-
* @returns A promise that resolves with the remote call result or rejects with an error
|
|
129
|
-
* @throws Error if no transport is configured or if the call times out
|
|
167
|
+
* Creates a new IRPCPackage instance with the given configuration
|
|
168
|
+
* @param config - Optional partial configuration for the package
|
|
169
|
+
* @returns A new IRPCPackage instance
|
|
130
170
|
*/
|
|
131
|
-
function
|
|
132
|
-
|
|
133
|
-
name: spec.name,
|
|
134
|
-
args
|
|
135
|
-
};
|
|
136
|
-
return new Promise((resolve, reject) => {
|
|
137
|
-
if (!module.transport) {
|
|
138
|
-
reject(/* @__PURE__ */ new Error("IRPC transport can not be found."));
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
const timeout = module.timeout ? setTimeout(() => {
|
|
142
|
-
call.reject(/* @__PURE__ */ new Error("IRPC timeout."));
|
|
143
|
-
}, module.timeout) : void 0;
|
|
144
|
-
const call = new IRPCCall(payload, (value) => {
|
|
145
|
-
resolve(value);
|
|
146
|
-
clearTimeout(timeout);
|
|
147
|
-
}, (reason) => {
|
|
148
|
-
reject(reason);
|
|
149
|
-
clearTimeout(timeout);
|
|
150
|
-
});
|
|
151
|
-
batch(call, module.submit);
|
|
152
|
-
});
|
|
171
|
+
function createPackage(config) {
|
|
172
|
+
return new IRPCPackage(config);
|
|
153
173
|
}
|
|
154
174
|
|
|
155
175
|
//#endregion
|
|
156
|
-
export {
|
|
176
|
+
export { IRPCPackage, createPackage };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { IRPCDataSchema, IRPCError, IRPCInputs, IRPCOutput, IRPCRequest, IRPCResponse, IRPCSpec } from "./types.js";
|
|
2
|
+
import { IRPCPackage } from "./module.js";
|
|
3
|
+
|
|
4
|
+
//#region src/resolver.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Resolver class for handling IRPC requests
|
|
8
|
+
*
|
|
9
|
+
* This class is responsible for resolving IRPC requests by validating inputs,
|
|
10
|
+
* executing the requested method, and formatting the response.
|
|
11
|
+
*/
|
|
12
|
+
declare class IRPCResolver {
|
|
13
|
+
req: IRPCRequest;
|
|
14
|
+
module: IRPCPackage;
|
|
15
|
+
/**
|
|
16
|
+
* Getter for the specification of the RPC method
|
|
17
|
+
*
|
|
18
|
+
* Retrieves the specification of the RPC method from the module based on the request
|
|
19
|
+
*/
|
|
20
|
+
get spec(): IRPCSpec<IRPCInputs, IRPCDataSchema> | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Creates a new IRPCResolver instance
|
|
23
|
+
*
|
|
24
|
+
* @param req - The IRPC request object containing id, name and arguments
|
|
25
|
+
* @param module - The IRPC package module that contains the method to be executed
|
|
26
|
+
*/
|
|
27
|
+
constructor(req: IRPCRequest, module: IRPCPackage);
|
|
28
|
+
/**
|
|
29
|
+
* Resolves an IRPC request
|
|
30
|
+
*
|
|
31
|
+
* This method validates the request, parses inputs according to the schema,
|
|
32
|
+
* and forwards the request to the appropriate handler.
|
|
33
|
+
*
|
|
34
|
+
* @returns A promise that resolves to an IRPC response with either the result or an error
|
|
35
|
+
*/
|
|
36
|
+
resolve(): Promise<IRPCResponse>;
|
|
37
|
+
/**
|
|
38
|
+
* Forwards a validated request to the module's resolver
|
|
39
|
+
*
|
|
40
|
+
* @param req - The validated IRPC request object
|
|
41
|
+
* @param schema - Optional output schema for result validation
|
|
42
|
+
* @returns A promise that resolves to an IRPC response with the result or an error
|
|
43
|
+
*/
|
|
44
|
+
forward({
|
|
45
|
+
id,
|
|
46
|
+
name,
|
|
47
|
+
args
|
|
48
|
+
}: IRPCRequest, schema?: IRPCOutput): Promise<{
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
result: string | number | boolean | IRPCDataSchema | Record<string, unknown> | (string | number | boolean | Record<string, unknown> | null | undefined)[] | null | undefined;
|
|
52
|
+
error?: undefined;
|
|
53
|
+
} | {
|
|
54
|
+
id: string;
|
|
55
|
+
name: string;
|
|
56
|
+
error: IRPCError;
|
|
57
|
+
result?: undefined;
|
|
58
|
+
}>;
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { IRPCResolver };
|
package/dist/resolver.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { ERROR_CODE } from "./error.js";
|
|
2
|
+
|
|
3
|
+
//#region src/resolver.ts
|
|
4
|
+
/**
|
|
5
|
+
* Resolver class for handling IRPC requests
|
|
6
|
+
*
|
|
7
|
+
* This class is responsible for resolving IRPC requests by validating inputs,
|
|
8
|
+
* executing the requested method, and formatting the response.
|
|
9
|
+
*/
|
|
10
|
+
var IRPCResolver = class {
|
|
11
|
+
/**
|
|
12
|
+
* Getter for the specification of the RPC method
|
|
13
|
+
*
|
|
14
|
+
* Retrieves the specification of the RPC method from the module based on the request
|
|
15
|
+
*/
|
|
16
|
+
get spec() {
|
|
17
|
+
return this.module.get(this.req);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Creates a new IRPCResolver instance
|
|
21
|
+
*
|
|
22
|
+
* @param req - The IRPC request object containing id, name and arguments
|
|
23
|
+
* @param module - The IRPC package module that contains the method to be executed
|
|
24
|
+
*/
|
|
25
|
+
constructor(req, module) {
|
|
26
|
+
this.req = req;
|
|
27
|
+
this.module = module;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Resolves an IRPC request
|
|
31
|
+
*
|
|
32
|
+
* This method validates the request, parses inputs according to the schema,
|
|
33
|
+
* and forwards the request to the appropriate handler.
|
|
34
|
+
*
|
|
35
|
+
* @returns A promise that resolves to an IRPC response with either the result or an error
|
|
36
|
+
*/
|
|
37
|
+
async resolve() {
|
|
38
|
+
const { id, name, args } = this.req;
|
|
39
|
+
if (!this.spec) return {
|
|
40
|
+
id,
|
|
41
|
+
name,
|
|
42
|
+
error: {
|
|
43
|
+
code: ERROR_CODE.NOT_FOUND,
|
|
44
|
+
message: `IRPC "${name}" does not exist.`
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const { schema } = this.spec;
|
|
48
|
+
const inputs = parseInput(args, schema?.input);
|
|
49
|
+
if (!inputs.success) return {
|
|
50
|
+
id,
|
|
51
|
+
name,
|
|
52
|
+
error: {
|
|
53
|
+
code: ERROR_CODE.INVALID_INPUT,
|
|
54
|
+
message: inputs.error
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
return this.forward({
|
|
58
|
+
id,
|
|
59
|
+
name,
|
|
60
|
+
args: inputs.data
|
|
61
|
+
}, schema?.output);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Forwards a validated request to the module's resolver
|
|
65
|
+
*
|
|
66
|
+
* @param req - The validated IRPC request object
|
|
67
|
+
* @param schema - Optional output schema for result validation
|
|
68
|
+
* @returns A promise that resolves to an IRPC response with the result or an error
|
|
69
|
+
*/
|
|
70
|
+
async forward({ id, name, args }, schema) {
|
|
71
|
+
try {
|
|
72
|
+
const output = parseOutput(await this.module.resolve({
|
|
73
|
+
id,
|
|
74
|
+
name,
|
|
75
|
+
args
|
|
76
|
+
}), schema);
|
|
77
|
+
if (output.success) return {
|
|
78
|
+
id,
|
|
79
|
+
name,
|
|
80
|
+
result: output.data
|
|
81
|
+
};
|
|
82
|
+
else return {
|
|
83
|
+
id,
|
|
84
|
+
name,
|
|
85
|
+
error: {
|
|
86
|
+
code: ERROR_CODE.INVALID_OUTPUT,
|
|
87
|
+
message: output.error?.message
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return {
|
|
92
|
+
id,
|
|
93
|
+
name,
|
|
94
|
+
error: {
|
|
95
|
+
code: ERROR_CODE.UNKNOWN,
|
|
96
|
+
message: error.message
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Parses and validates input arguments against their schemas
|
|
104
|
+
*
|
|
105
|
+
* @param args - Array of input arguments
|
|
106
|
+
* @param schema - Optional schema for validating the arguments
|
|
107
|
+
* @returns Parsed result with success status and any error messages
|
|
108
|
+
*/
|
|
109
|
+
function parseInput(args, schema) {
|
|
110
|
+
if (schema && args.length !== schema.length) return {
|
|
111
|
+
data: args,
|
|
112
|
+
success: false,
|
|
113
|
+
error: "Invalid arguments"
|
|
114
|
+
};
|
|
115
|
+
const parsed = args.map((arg, i) => {
|
|
116
|
+
const input = schema?.[i];
|
|
117
|
+
return input ? input.safeParse(arg) : {
|
|
118
|
+
success: true,
|
|
119
|
+
data: arg
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
data: parsed.map((arg) => arg.data),
|
|
124
|
+
error: parsed.filter((arg) => !arg.success).map((arg) => arg.error?.message).join("\n"),
|
|
125
|
+
success: parsed.every((arg) => arg.success)
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Parses and validates output result against its schema
|
|
130
|
+
*
|
|
131
|
+
* @param result - The result to validate
|
|
132
|
+
* @param schema - Optional schema for validating the result
|
|
133
|
+
* @returns Parsed result with success status and any error messages
|
|
134
|
+
*/
|
|
135
|
+
function parseOutput(result, schema) {
|
|
136
|
+
return schema ? schema.safeParse(result) : {
|
|
137
|
+
success: true,
|
|
138
|
+
data: result
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
//#endregion
|
|
143
|
+
export { IRPCResolver };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { IRPCData, IRPCInputs, IRPCOutput, IRPCSpec, TransportConfig } from "./types.js";
|
|
2
|
+
import { IRPCCall } from "./call.js";
|
|
3
|
+
|
|
4
|
+
//#region src/transport.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* IRPCTransport is responsible for managing and dispatching RPC calls.
|
|
8
|
+
* It handles queuing, debouncing, and timeout management for RPC requests.
|
|
9
|
+
*/
|
|
10
|
+
declare class IRPCTransport {
|
|
11
|
+
config?: TransportConfig | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* A set of pending RPC calls that are queued for execution.
|
|
14
|
+
*/
|
|
15
|
+
queue: Set<IRPCCall>;
|
|
16
|
+
/**
|
|
17
|
+
* Creates a new IRPCTransport instance.
|
|
18
|
+
* @param config - Optional transport configuration including timeout and debounce settings.
|
|
19
|
+
*/
|
|
20
|
+
constructor(config?: TransportConfig | undefined);
|
|
21
|
+
/**
|
|
22
|
+
* Initiates an RPC call with the given specification and arguments.
|
|
23
|
+
* @param spec - The RPC specification defining the method to call.
|
|
24
|
+
* @param args - An array of arguments to pass to the RPC method.
|
|
25
|
+
* @param timeout - Optional timeout value for the RPC call.
|
|
26
|
+
* @returns A promise that resolves with the RPC response data or rejects with an error.
|
|
27
|
+
*/
|
|
28
|
+
call(spec: IRPCSpec<IRPCInputs, IRPCOutput>, args: IRPCData[], timeout?: number | undefined): Promise<IRPCData>;
|
|
29
|
+
/**
|
|
30
|
+
* Schedules an RPC call for execution, implementing debouncing logic.
|
|
31
|
+
* Queued calls will be dispatched after the configured debounce delay.
|
|
32
|
+
* @param call - The RPC call to schedule.
|
|
33
|
+
*/
|
|
34
|
+
protected schedule(call: IRPCCall): void;
|
|
35
|
+
/**
|
|
36
|
+
* Dispatches a batch of RPC calls. This base implementation rejects all calls
|
|
37
|
+
* with a "not implemented" error. Subclasses should override this method to
|
|
38
|
+
* provide actual transport mechanism.
|
|
39
|
+
* @param calls - An array of RPC calls to dispatch.
|
|
40
|
+
* @returns A promise that resolves when all calls have been processed.
|
|
41
|
+
*/
|
|
42
|
+
protected dispatch(calls: IRPCCall[]): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { IRPCTransport };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { IRPCCall } from "./call.js";
|
|
2
|
+
import { ERROR_CODE, ERROR_MESSAGE } from "./error.js";
|
|
3
|
+
|
|
4
|
+
//#region src/transport.ts
|
|
5
|
+
/**
|
|
6
|
+
* IRPCTransport is responsible for managing and dispatching RPC calls.
|
|
7
|
+
* It handles queuing, debouncing, and timeout management for RPC requests.
|
|
8
|
+
*/
|
|
9
|
+
var IRPCTransport = class {
|
|
10
|
+
/**
|
|
11
|
+
* A set of pending RPC calls that are queued for execution.
|
|
12
|
+
*/
|
|
13
|
+
queue = /* @__PURE__ */ new Set();
|
|
14
|
+
/**
|
|
15
|
+
* Creates a new IRPCTransport instance.
|
|
16
|
+
* @param config - Optional transport configuration including timeout and debounce settings.
|
|
17
|
+
*/
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.config = config;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Initiates an RPC call with the given specification and arguments.
|
|
23
|
+
* @param spec - The RPC specification defining the method to call.
|
|
24
|
+
* @param args - An array of arguments to pass to the RPC method.
|
|
25
|
+
* @param timeout - Optional timeout value for the RPC call.
|
|
26
|
+
* @returns A promise that resolves with the RPC response data or rejects with an error.
|
|
27
|
+
*/
|
|
28
|
+
call(spec, args, timeout = this.config?.timeout) {
|
|
29
|
+
const payload = {
|
|
30
|
+
name: spec.name,
|
|
31
|
+
args
|
|
32
|
+
};
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
const timer = timeout ? setTimeout(() => {
|
|
35
|
+
call.reject(new Error(ERROR_MESSAGE[ERROR_CODE.TIMEOUT]));
|
|
36
|
+
}, timeout) : void 0;
|
|
37
|
+
const call = new IRPCCall(payload, (value) => {
|
|
38
|
+
resolve(value);
|
|
39
|
+
clearTimeout(timer);
|
|
40
|
+
}, (reason) => {
|
|
41
|
+
reject(reason);
|
|
42
|
+
clearTimeout(timer);
|
|
43
|
+
}, timeout);
|
|
44
|
+
this.schedule(call);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Schedules an RPC call for execution, implementing debouncing logic.
|
|
49
|
+
* Queued calls will be dispatched after the configured debounce delay.
|
|
50
|
+
* @param call - The RPC call to schedule.
|
|
51
|
+
*/
|
|
52
|
+
schedule(call) {
|
|
53
|
+
if (!this.queue.size) setTimeout(() => {
|
|
54
|
+
this.dispatch(Array.from(this.queue));
|
|
55
|
+
this.queue.clear();
|
|
56
|
+
}, this.config?.debounce ?? 0);
|
|
57
|
+
this.queue.add(call);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Dispatches a batch of RPC calls. This base implementation rejects all calls
|
|
61
|
+
* with a "not implemented" error. Subclasses should override this method to
|
|
62
|
+
* provide actual transport mechanism.
|
|
63
|
+
* @param calls - An array of RPC calls to dispatch.
|
|
64
|
+
* @returns A promise that resolves when all calls have been processed.
|
|
65
|
+
*/
|
|
66
|
+
async dispatch(calls) {
|
|
67
|
+
calls.forEach((call) => {
|
|
68
|
+
call.reject(new Error(ERROR_MESSAGE[ERROR_CODE.TRANSPORT_NOT_IMPLEMENTED]));
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
//#endregion
|
|
74
|
+
export { IRPCTransport };
|