@irpclib/irpc 1.0.0-beta.20 → 1.0.0-beta.21
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/call.d.ts +19 -12
- package/dist/call.js +58 -16
- package/dist/enum.d.ts +1 -0
- package/dist/enum.js +1 -0
- package/dist/error.d.ts +5 -0
- package/dist/error.js +7 -2
- package/dist/index.d.ts +6 -3
- package/dist/index.js +6 -3
- package/dist/module.d.ts +5 -4
- package/dist/module.js +26 -18
- package/dist/reader.d.ts +24 -0
- package/dist/reader.js +37 -0
- package/dist/resolver.d.ts +2 -12
- package/dist/resolver.js +20 -2
- package/dist/state.d.ts +68 -5
- package/dist/state.js +99 -14
- package/dist/stream.d.ts +57 -0
- package/dist/stream.js +204 -0
- package/dist/transport.d.ts +5 -4
- package/dist/transport.js +28 -18
- package/dist/types.d.ts +47 -21
- package/package.json +2 -2
- package/readme.md +99 -30
package/dist/state.js
CHANGED
|
@@ -2,40 +2,125 @@ import { IRPC_STATUS } from "./enum.js";
|
|
|
2
2
|
import { anchor, mutable, subscribe } from "@anchorlib/core";
|
|
3
3
|
|
|
4
4
|
//#region src/state.ts
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* A reactive state wrapper that implements the standard Promise interface.
|
|
7
|
+
*
|
|
8
|
+
* RemoteState acts as a dual-layer abstraction:
|
|
9
|
+
* 1. For asynchronous execution, it operates as a `Promise<T>` that resolves upon completion or rejects upon failure.
|
|
10
|
+
* 2. For reactive environments, it exposes an `.subscribe()` method to react to intermediate data mutations.
|
|
11
|
+
*
|
|
12
|
+
* @template T - The type of data held by the state.
|
|
13
|
+
*/
|
|
14
|
+
var RemoteState = class extends Promise {
|
|
15
|
+
state;
|
|
16
|
+
accept;
|
|
17
|
+
reject;
|
|
18
|
+
/**
|
|
19
|
+
* The current data payload of the state.
|
|
20
|
+
*/
|
|
7
21
|
get data() {
|
|
8
|
-
return this
|
|
22
|
+
return this.state.data;
|
|
9
23
|
}
|
|
10
24
|
set data(data) {
|
|
11
|
-
this
|
|
25
|
+
this.state.data = data;
|
|
12
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* The current error encountered by the state, if any.
|
|
29
|
+
*/
|
|
13
30
|
get error() {
|
|
14
|
-
return this
|
|
31
|
+
return this.state.error;
|
|
15
32
|
}
|
|
16
33
|
set error(error) {
|
|
17
|
-
this
|
|
34
|
+
this.state.error = error;
|
|
18
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* The execution status of the state (PENDING, SUCCESS, ERROR).
|
|
38
|
+
* Transitioning to a terminal status (SUCCESS or ERROR) will automatically resolve or reject the underlying Promise.
|
|
39
|
+
*/
|
|
19
40
|
get status() {
|
|
20
|
-
return this
|
|
41
|
+
return this.state.status;
|
|
21
42
|
}
|
|
22
43
|
set status(status) {
|
|
23
|
-
this
|
|
44
|
+
this.state.status = status;
|
|
45
|
+
if (this.status === IRPC_STATUS.ERROR) {
|
|
46
|
+
this.reject(new Error(this.error.message));
|
|
47
|
+
this.destroy();
|
|
48
|
+
} else if (this.status === IRPC_STATUS.SUCCESS) {
|
|
49
|
+
this.accept(this.data);
|
|
50
|
+
this.destroy();
|
|
51
|
+
}
|
|
24
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Initializes a new RemoteState with an optional initial payload.
|
|
55
|
+
*
|
|
56
|
+
* @param init - An optional starting value for the data payload.
|
|
57
|
+
*/
|
|
25
58
|
constructor(init) {
|
|
26
|
-
|
|
27
|
-
|
|
59
|
+
let acceptFn;
|
|
60
|
+
let rejectFn;
|
|
61
|
+
super((resolve, reject) => {
|
|
62
|
+
acceptFn = resolve;
|
|
63
|
+
rejectFn = reject;
|
|
64
|
+
});
|
|
65
|
+
this.accept = acceptFn;
|
|
66
|
+
this.reject = rejectFn;
|
|
67
|
+
this.state = mutable({
|
|
68
|
+
data: init,
|
|
28
69
|
error: void 0,
|
|
29
|
-
status: IRPC_STATUS.
|
|
70
|
+
status: IRPC_STATUS.PENDING
|
|
30
71
|
});
|
|
31
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Subscribes to changes emitted by the internal state.
|
|
75
|
+
*
|
|
76
|
+
* @param handler - A callback function invoked whenever the state mutates.
|
|
77
|
+
* @returns An unsubscribe function to terminate the listener.
|
|
78
|
+
*/
|
|
32
79
|
subscribe(handler) {
|
|
33
|
-
return subscribe(this
|
|
80
|
+
return subscribe(this.state, handler);
|
|
34
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Destroys the reactive state bindings.
|
|
84
|
+
*/
|
|
35
85
|
destroy() {
|
|
36
|
-
anchor.destroy(this
|
|
86
|
+
anchor.destroy(this.state);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Ensures that chained Promise operations return standard Promises
|
|
90
|
+
* rather than instantiating new RemoteState subclasses.
|
|
91
|
+
*/
|
|
92
|
+
static get [Symbol.species]() {
|
|
93
|
+
return Promise;
|
|
37
94
|
}
|
|
38
95
|
};
|
|
96
|
+
/**
|
|
97
|
+
* A utility factory to structurally instantiate an active `RemoteState` pipeline natively
|
|
98
|
+
* decoupled from standard Promise chains. This elegantly captures constructor functions
|
|
99
|
+
* pushing events into the state before terminating mechanically via secure internal hooks.
|
|
100
|
+
*
|
|
101
|
+
* @template T - The type of the streamed payload data.
|
|
102
|
+
* @param construct - The isolated stream constructor callback that natively operates the pipeline.
|
|
103
|
+
* @param init - An optional initial value to prime the state payload inherently.
|
|
104
|
+
* @returns A fully active RemoteState inherently bound to the callbacks executing natively.
|
|
105
|
+
*/
|
|
106
|
+
function stream(construct, init) {
|
|
107
|
+
const state = new RemoteState(init);
|
|
108
|
+
const accept = ((...values) => {
|
|
109
|
+
if (values.length > 0) state.data = values[0];
|
|
110
|
+
state.status = IRPC_STATUS.SUCCESS;
|
|
111
|
+
});
|
|
112
|
+
const reject = (error) => {
|
|
113
|
+
state.error = error;
|
|
114
|
+
state.status = IRPC_STATUS.ERROR;
|
|
115
|
+
};
|
|
116
|
+
try {
|
|
117
|
+
const result = construct(state.data, accept, reject);
|
|
118
|
+
if (result instanceof Promise) result.catch(reject);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
reject(error);
|
|
121
|
+
}
|
|
122
|
+
return state;
|
|
123
|
+
}
|
|
39
124
|
|
|
40
125
|
//#endregion
|
|
41
|
-
export { RemoteState };
|
|
126
|
+
export { RemoteState, stream };
|
package/dist/stream.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { IRPCData, IRPCError, IRPCPacketStream, IRPCResponse, IRPCStatus } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/stream.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A server-side producer that normalizes and serializes RPC outputs into standard transport packets.
|
|
7
|
+
*
|
|
8
|
+
* Supports both standard asynchronous responses and reactive streams. When handling a continuous stream,
|
|
9
|
+
* it intercepts state mutations and emits sequential network packets (`ANSWER`, `EVENT`, `CLOSE`).
|
|
10
|
+
*
|
|
11
|
+
* @template T - The type of data yielded by the stream.
|
|
12
|
+
*/
|
|
13
|
+
declare class IRPCStream<T extends IRPCData> {
|
|
14
|
+
private id;
|
|
15
|
+
private name;
|
|
16
|
+
private initializer;
|
|
17
|
+
private pipeHandlers;
|
|
18
|
+
private closeHandlers;
|
|
19
|
+
private errorHandlers;
|
|
20
|
+
value?: T;
|
|
21
|
+
error?: IRPCError;
|
|
22
|
+
status: IRPCStatus;
|
|
23
|
+
/**
|
|
24
|
+
* Initializes a stream wrapping an asynchronous RPC execution.
|
|
25
|
+
*
|
|
26
|
+
* @param id - The unique identifier of the RPC request.
|
|
27
|
+
* @param name - The name of the specification processing the execution.
|
|
28
|
+
* @param initializer - An execution callback that yields an IRPCResponse.
|
|
29
|
+
*/
|
|
30
|
+
constructor(id: string, name: string, initializer: () => Promise<IRPCResponse>);
|
|
31
|
+
/**
|
|
32
|
+
* Evaluates the underlying initializer and propagates standard transport packets
|
|
33
|
+
* to all bound pipe handlers based on the output lifecycle.
|
|
34
|
+
*/
|
|
35
|
+
private start;
|
|
36
|
+
/**
|
|
37
|
+
* Binds a handler to receive the outbound stream packets.
|
|
38
|
+
* If invoked after the stream has fulfilled or rejected natively, it automatically plays back the conclusive packet.
|
|
39
|
+
*
|
|
40
|
+
* @param handler - A callback function to receive packets.
|
|
41
|
+
*/
|
|
42
|
+
pipe(handler: (event: IRPCPacketStream<T>) => void): void;
|
|
43
|
+
/**
|
|
44
|
+
* Binds a handler to trap any internal runtime failures independently.
|
|
45
|
+
*
|
|
46
|
+
* @param handler - A callback function to receive stream errors.
|
|
47
|
+
*/
|
|
48
|
+
catch(handler: (error: IRPCError) => void): void;
|
|
49
|
+
/**
|
|
50
|
+
* Binds a handler triggered upon terminal completion of the stream process (success or error).
|
|
51
|
+
*
|
|
52
|
+
* @param handler - A callback function invoked at stream completion.
|
|
53
|
+
*/
|
|
54
|
+
close(handler: () => void): void;
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
export { IRPCStream };
|
package/dist/stream.js
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { IRPC_PACKET_TYPE, IRPC_STATUS } from "./enum.js";
|
|
2
|
+
import { ERROR_CODE } from "./error.js";
|
|
3
|
+
import { RemoteState } from "./state.js";
|
|
4
|
+
|
|
5
|
+
//#region src/stream.ts
|
|
6
|
+
/**
|
|
7
|
+
* A server-side producer that normalizes and serializes RPC outputs into standard transport packets.
|
|
8
|
+
*
|
|
9
|
+
* Supports both standard asynchronous responses and reactive streams. When handling a continuous stream,
|
|
10
|
+
* it intercepts state mutations and emits sequential network packets (`ANSWER`, `EVENT`, `CLOSE`).
|
|
11
|
+
*
|
|
12
|
+
* @template T - The type of data yielded by the stream.
|
|
13
|
+
*/
|
|
14
|
+
var IRPCStream = class {
|
|
15
|
+
pipeHandlers = /* @__PURE__ */ new Set();
|
|
16
|
+
closeHandlers = /* @__PURE__ */ new Set();
|
|
17
|
+
errorHandlers = /* @__PURE__ */ new Set();
|
|
18
|
+
value;
|
|
19
|
+
error;
|
|
20
|
+
status = IRPC_STATUS.IDLE;
|
|
21
|
+
/**
|
|
22
|
+
* Initializes a stream wrapping an asynchronous RPC execution.
|
|
23
|
+
*
|
|
24
|
+
* @param id - The unique identifier of the RPC request.
|
|
25
|
+
* @param name - The name of the specification processing the execution.
|
|
26
|
+
* @param initializer - An execution callback that yields an IRPCResponse.
|
|
27
|
+
*/
|
|
28
|
+
constructor(id, name, initializer) {
|
|
29
|
+
this.id = id;
|
|
30
|
+
this.name = name;
|
|
31
|
+
this.initializer = initializer;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Evaluates the underlying initializer and propagates standard transport packets
|
|
35
|
+
* to all bound pipe handlers based on the output lifecycle.
|
|
36
|
+
*/
|
|
37
|
+
async start() {
|
|
38
|
+
if (this.status !== IRPC_STATUS.IDLE) return;
|
|
39
|
+
this.status = IRPC_STATUS.PENDING;
|
|
40
|
+
const { id, name } = this;
|
|
41
|
+
try {
|
|
42
|
+
const { result } = await this.initializer();
|
|
43
|
+
if (result instanceof RemoteState) {
|
|
44
|
+
this.value = result.data;
|
|
45
|
+
if (result.status === IRPC_STATUS.SUCCESS || result.status === IRPC_STATUS.ERROR) {
|
|
46
|
+
if (result.status === IRPC_STATUS.ERROR) {
|
|
47
|
+
this.error = {
|
|
48
|
+
code: ERROR_CODE.STREAM_ERROR,
|
|
49
|
+
message: result.error.message
|
|
50
|
+
};
|
|
51
|
+
this.status = IRPC_STATUS.ERROR;
|
|
52
|
+
} else this.status = IRPC_STATUS.SUCCESS;
|
|
53
|
+
const packet = {
|
|
54
|
+
id,
|
|
55
|
+
name,
|
|
56
|
+
type: IRPC_PACKET_TYPE.ANSWER,
|
|
57
|
+
data: this.value,
|
|
58
|
+
error: this.error,
|
|
59
|
+
status: this.status,
|
|
60
|
+
createdAt: Date.now()
|
|
61
|
+
};
|
|
62
|
+
this.pipeHandlers.forEach((handler) => handler(packet));
|
|
63
|
+
this.errorHandlers.forEach((handler) => handler(this.error));
|
|
64
|
+
this.closeHandlers.forEach((handler) => handler());
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
this.pipeHandlers.forEach((handler) => {
|
|
68
|
+
handler({
|
|
69
|
+
id,
|
|
70
|
+
name,
|
|
71
|
+
type: IRPC_PACKET_TYPE.ANSWER,
|
|
72
|
+
data: result.data,
|
|
73
|
+
status: result.status,
|
|
74
|
+
createdAt: Date.now()
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
const unsubscribe = result.subscribe((state, { type, keys, value }) => {
|
|
78
|
+
if (type === "init") return;
|
|
79
|
+
const [rootKey] = keys;
|
|
80
|
+
if (rootKey === "data") this.pipeHandlers.forEach((handler) => {
|
|
81
|
+
handler({
|
|
82
|
+
id,
|
|
83
|
+
name,
|
|
84
|
+
type: IRPC_PACKET_TYPE.EVENT,
|
|
85
|
+
status: state.status,
|
|
86
|
+
data: {
|
|
87
|
+
type,
|
|
88
|
+
keys,
|
|
89
|
+
value
|
|
90
|
+
},
|
|
91
|
+
createdAt: Date.now()
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
else if (rootKey === "status") {
|
|
95
|
+
if (state.status !== IRPC_STATUS.SUCCESS && state.status !== IRPC_STATUS.ERROR) return;
|
|
96
|
+
this.status = state.status;
|
|
97
|
+
if (state.status === IRPC_STATUS.ERROR) {
|
|
98
|
+
this.error = {
|
|
99
|
+
code: ERROR_CODE.STREAM_ERROR,
|
|
100
|
+
message: state.error.message
|
|
101
|
+
};
|
|
102
|
+
this.errorHandlers.forEach((handler) => handler(this.error));
|
|
103
|
+
}
|
|
104
|
+
this.pipeHandlers.forEach((handler) => {
|
|
105
|
+
handler({
|
|
106
|
+
id,
|
|
107
|
+
name,
|
|
108
|
+
type: IRPC_PACKET_TYPE.CLOSE,
|
|
109
|
+
error: this.error,
|
|
110
|
+
status: this.status,
|
|
111
|
+
createdAt: Date.now()
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
this.closeHandlers.forEach((handler) => handler());
|
|
115
|
+
unsubscribe();
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
} else {
|
|
119
|
+
this.value = result;
|
|
120
|
+
this.status = IRPC_STATUS.SUCCESS;
|
|
121
|
+
const packet = {
|
|
122
|
+
id,
|
|
123
|
+
name,
|
|
124
|
+
type: IRPC_PACKET_TYPE.ANSWER,
|
|
125
|
+
status: IRPC_STATUS.SUCCESS,
|
|
126
|
+
data: this.value,
|
|
127
|
+
createdAt: Date.now()
|
|
128
|
+
};
|
|
129
|
+
this.pipeHandlers.forEach((handler) => handler(packet));
|
|
130
|
+
this.closeHandlers.forEach((handler) => handler());
|
|
131
|
+
}
|
|
132
|
+
} catch (error) {
|
|
133
|
+
this.error = {
|
|
134
|
+
code: ERROR_CODE.STREAM_ERROR,
|
|
135
|
+
message: error.message
|
|
136
|
+
};
|
|
137
|
+
this.status = IRPC_STATUS.ERROR;
|
|
138
|
+
this.pipeHandlers.forEach((handler) => {
|
|
139
|
+
handler({
|
|
140
|
+
id,
|
|
141
|
+
name,
|
|
142
|
+
type: IRPC_PACKET_TYPE.ANSWER,
|
|
143
|
+
status: IRPC_STATUS.ERROR,
|
|
144
|
+
error,
|
|
145
|
+
createdAt: Date.now()
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
this.errorHandlers.forEach((handler) => handler(this.error));
|
|
149
|
+
this.closeHandlers.forEach((handler) => handler());
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Binds a handler to receive the outbound stream packets.
|
|
155
|
+
* If invoked after the stream has fulfilled or rejected natively, it automatically plays back the conclusive packet.
|
|
156
|
+
*
|
|
157
|
+
* @param handler - A callback function to receive packets.
|
|
158
|
+
*/
|
|
159
|
+
pipe(handler) {
|
|
160
|
+
if (this.status === IRPC_STATUS.SUCCESS || this.status === IRPC_STATUS.ERROR) {
|
|
161
|
+
handler({
|
|
162
|
+
id: this.id,
|
|
163
|
+
name: this.name,
|
|
164
|
+
type: IRPC_PACKET_TYPE.ANSWER,
|
|
165
|
+
data: this.value,
|
|
166
|
+
error: this.error,
|
|
167
|
+
status: this.status,
|
|
168
|
+
createdAt: Date.now()
|
|
169
|
+
});
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
this.pipeHandlers.add(handler);
|
|
173
|
+
this.start().catch(() => {});
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Binds a handler to trap any internal runtime failures independently.
|
|
177
|
+
*
|
|
178
|
+
* @param handler - A callback function to receive stream errors.
|
|
179
|
+
*/
|
|
180
|
+
catch(handler) {
|
|
181
|
+
if (this.status === IRPC_STATUS.ERROR) {
|
|
182
|
+
handler(this.error);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
this.errorHandlers.add(handler);
|
|
186
|
+
this.start().catch(() => {});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Binds a handler triggered upon terminal completion of the stream process (success or error).
|
|
190
|
+
*
|
|
191
|
+
* @param handler - A callback function invoked at stream completion.
|
|
192
|
+
*/
|
|
193
|
+
close(handler) {
|
|
194
|
+
if (this.status === IRPC_STATUS.SUCCESS || this.status === IRPC_STATUS.ERROR) {
|
|
195
|
+
handler();
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
this.closeHandlers.add(handler);
|
|
199
|
+
this.start().catch(() => {});
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
//#endregion
|
|
204
|
+
export { IRPCStream };
|
package/dist/transport.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { IRPCData, IRPCInputs, IRPCOutput, IRPCSpec, TransportConfig } from "./types.js";
|
|
1
|
+
import { IRPCCallConfig, IRPCData, IRPCInputs, IRPCOutput, IRPCSpec, TransportConfig } from "./types.js";
|
|
2
|
+
import { IRPCReader } from "./reader.js";
|
|
2
3
|
import { IRPCCall } from "./call.js";
|
|
3
4
|
|
|
4
5
|
//#region src/transport.d.ts
|
|
@@ -22,16 +23,16 @@ declare class IRPCTransport {
|
|
|
22
23
|
* Initiates an RPC call with the given specification and arguments.
|
|
23
24
|
* @param spec - The RPC specification defining the method to call.
|
|
24
25
|
* @param args - An array of arguments to pass to the RPC method.
|
|
25
|
-
* @param
|
|
26
|
+
* @param config - Optional call configuration, including timeout, retry settings, and more.
|
|
26
27
|
* @returns A promise that resolves with the RPC response data or rejects with an error.
|
|
27
28
|
*/
|
|
28
|
-
call(spec: IRPCSpec<IRPCInputs, IRPCOutput>, args: IRPCData[],
|
|
29
|
+
call(spec: IRPCSpec<IRPCInputs, IRPCOutput>, args: IRPCData[], config?: IRPCCallConfig): IRPCReader<IRPCData>;
|
|
29
30
|
/**
|
|
30
31
|
* Schedules an RPC call for execution, implementing debouncing logic.
|
|
31
32
|
* Queued calls will be dispatched after the configured debounce delay.
|
|
32
33
|
* @param call - The RPC call to schedule.
|
|
33
34
|
*/
|
|
34
|
-
|
|
35
|
+
schedule(call: IRPCCall): void;
|
|
35
36
|
/**
|
|
36
37
|
* Dispatches a batch of RPC calls. This base implementation rejects all calls
|
|
37
38
|
* with a "not implemented" error. Subclasses should override this method to
|
package/dist/transport.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IRPC_PACKET_TYPE, IRPC_STATUS } from "./enum.js";
|
|
2
2
|
import { ERROR_CODE, ERROR_MESSAGE } from "./error.js";
|
|
3
|
+
import { IRPCCall } from "./call.js";
|
|
3
4
|
|
|
4
5
|
//#region src/transport.ts
|
|
5
6
|
/**
|
|
@@ -22,27 +23,26 @@ var IRPCTransport = class {
|
|
|
22
23
|
* Initiates an RPC call with the given specification and arguments.
|
|
23
24
|
* @param spec - The RPC specification defining the method to call.
|
|
24
25
|
* @param args - An array of arguments to pass to the RPC method.
|
|
25
|
-
* @param
|
|
26
|
+
* @param config - Optional call configuration, including timeout, retry settings, and more.
|
|
26
27
|
* @returns A promise that resolves with the RPC response data or rejects with an error.
|
|
27
28
|
*/
|
|
28
|
-
call(spec, args,
|
|
29
|
+
call(spec, args, config) {
|
|
29
30
|
const payload = {
|
|
30
31
|
name: spec.name,
|
|
31
32
|
args
|
|
32
33
|
};
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
clearTimeout(timer);
|
|
43
|
-
}, timeout);
|
|
44
|
-
this.schedule(call);
|
|
34
|
+
const { timeout, maxRetries, retryMode, retryDelay } = {
|
|
35
|
+
...this.config,
|
|
36
|
+
...config
|
|
37
|
+
};
|
|
38
|
+
const call = new IRPCCall(this, payload, {
|
|
39
|
+
timeout,
|
|
40
|
+
maxRetries,
|
|
41
|
+
retryMode,
|
|
42
|
+
retryDelay
|
|
45
43
|
});
|
|
44
|
+
this.schedule(call);
|
|
45
|
+
return call.reader;
|
|
46
46
|
}
|
|
47
47
|
/**
|
|
48
48
|
* Schedules an RPC call for execution, implementing debouncing logic.
|
|
@@ -52,12 +52,12 @@ var IRPCTransport = class {
|
|
|
52
52
|
schedule(call) {
|
|
53
53
|
const { debounce } = this.config ?? {};
|
|
54
54
|
if (debounce === false) {
|
|
55
|
-
this.dispatch([call]).finally(() => {});
|
|
55
|
+
this.dispatch([call]).finally(() => {}).catch(() => {});
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
58
|
const timeout = typeof debounce === "number" && !Number.isNaN(debounce) ? debounce : 0;
|
|
59
59
|
const dispatch = () => {
|
|
60
|
-
this.dispatch(Array.from(this.queue)).finally(() => {});
|
|
60
|
+
this.dispatch(Array.from(this.queue)).finally(() => {}).catch(() => {});
|
|
61
61
|
this.queue.clear();
|
|
62
62
|
};
|
|
63
63
|
if (!this.queue.size) if (timeout === 0) queueMicrotask(dispatch);
|
|
@@ -73,7 +73,17 @@ var IRPCTransport = class {
|
|
|
73
73
|
*/
|
|
74
74
|
async dispatch(calls) {
|
|
75
75
|
calls.forEach((call) => {
|
|
76
|
-
call.
|
|
76
|
+
call.enqueue({
|
|
77
|
+
id: call.id,
|
|
78
|
+
name: call.payload.name,
|
|
79
|
+
type: IRPC_PACKET_TYPE.CLOSE,
|
|
80
|
+
status: IRPC_STATUS.ERROR,
|
|
81
|
+
error: {
|
|
82
|
+
code: ERROR_CODE.TRANSPORT_NOT_IMPLEMENTED,
|
|
83
|
+
message: ERROR_MESSAGE[ERROR_CODE.TRANSPORT_NOT_IMPLEMENTED]
|
|
84
|
+
},
|
|
85
|
+
createdAt: Date.now()
|
|
86
|
+
});
|
|
77
87
|
});
|
|
78
88
|
}
|
|
79
89
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { IRPC_DATA_TYPE, IRPC_EVENT_TYPE, IRPC_PACKET_TYPE, IRPC_STATUS } from "./enum.js";
|
|
2
2
|
import { ErrorCode } from "./error.js";
|
|
3
3
|
import { IRPCTransport } from "./transport.js";
|
|
4
|
+
import { RemoteState } from "./state.js";
|
|
5
|
+
import { StateChange } from "@anchorlib/core";
|
|
4
6
|
import { ZodArray, ZodBoolean, ZodNull, ZodNumber, ZodObject, ZodSafeParseResult, ZodString, ZodUndefined } from "zod/v4";
|
|
5
7
|
|
|
6
8
|
//#region src/types.d.ts
|
|
@@ -19,28 +21,32 @@ type IRPCStatus = (typeof IRPC_STATUS)[keyof typeof IRPC_STATUS];
|
|
|
19
21
|
type IRPCDataType = (typeof IRPC_DATA_TYPE)[keyof typeof IRPC_DATA_TYPE];
|
|
20
22
|
type IRPCPacketType = (typeof IRPC_PACKET_TYPE)[keyof typeof IRPC_PACKET_TYPE];
|
|
21
23
|
type IRPCEventType = (typeof IRPC_EVENT_TYPE)[keyof typeof IRPC_EVENT_TYPE];
|
|
22
|
-
type
|
|
24
|
+
type IRPCPacketBase = {
|
|
23
25
|
id: string;
|
|
24
26
|
name: string;
|
|
25
27
|
type: IRPCPacketType;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
status: IRPCStatus;
|
|
29
|
+
createdAt?: number;
|
|
30
|
+
arrivedAt?: number;
|
|
28
31
|
};
|
|
29
32
|
type IRPCPacketData = {
|
|
30
33
|
type: IRPCDataType;
|
|
31
34
|
value: IRPCData;
|
|
32
35
|
};
|
|
33
|
-
type IRPCPacketCall =
|
|
36
|
+
type IRPCPacketCall = IRPCPacketBase & {
|
|
34
37
|
args: IRPCData[];
|
|
35
38
|
};
|
|
36
|
-
type IRPCPacketAnswer =
|
|
37
|
-
data?:
|
|
39
|
+
type IRPCPacketAnswer<T extends IRPCData> = IRPCPacketBase & {
|
|
40
|
+
data?: T;
|
|
38
41
|
error?: IRPCError;
|
|
39
42
|
};
|
|
40
|
-
type IRPCPacketEvent =
|
|
41
|
-
data:
|
|
42
|
-
|
|
43
|
+
type IRPCPacketEvent = IRPCPacketBase & {
|
|
44
|
+
data: StateChange;
|
|
45
|
+
};
|
|
46
|
+
type IRPCPacketClose = IRPCPacketBase & {
|
|
47
|
+
error?: IRPCError;
|
|
43
48
|
};
|
|
49
|
+
type IRPCPacketStream<T extends IRPCData> = IRPCPacketAnswer<T> | IRPCPacketEvent | IRPCPacketClose;
|
|
44
50
|
interface IRPCReadable<T> {
|
|
45
51
|
data: T;
|
|
46
52
|
error: Error | undefined;
|
|
@@ -102,8 +108,7 @@ type IRPCPackageInfo = {
|
|
|
102
108
|
/** Optional description of the namespace */
|
|
103
109
|
description?: string;
|
|
104
110
|
};
|
|
105
|
-
type IRPCPackageConfig = IRPCPackageInfo & {
|
|
106
|
-
timeout?: number;
|
|
111
|
+
type IRPCPackageConfig = IRPCPackageInfo & IRPCCallConfig & {
|
|
107
112
|
transport?: IRPCTransport;
|
|
108
113
|
};
|
|
109
114
|
/**
|
|
@@ -145,8 +150,6 @@ type IRPCInit<I extends IRPCInputs, O extends IRPCOutput> = {
|
|
|
145
150
|
schema?: IRPCSchema<I, O>;
|
|
146
151
|
/** Optional maximum age of a call in milliseconds */
|
|
147
152
|
maxAge?: number;
|
|
148
|
-
/** Optional timeout for RPC calls */
|
|
149
|
-
timeout?: number;
|
|
150
153
|
/**
|
|
151
154
|
* Whether to coalesce multiple calls to the same RPC function within a short time period.
|
|
152
155
|
* If true, multiple calls with the same parameters will be combined into a single call,
|
|
@@ -154,7 +157,18 @@ type IRPCInit<I extends IRPCInputs, O extends IRPCOutput> = {
|
|
|
154
157
|
* This can help reduce the number of actual function executions.
|
|
155
158
|
*/
|
|
156
159
|
coalesce?: boolean;
|
|
157
|
-
};
|
|
160
|
+
} & IRPCCallConfig;
|
|
161
|
+
/**
|
|
162
|
+
* Type definition for an RPC declaration.
|
|
163
|
+
* Represents an RPC function with its name, description, and configuration.
|
|
164
|
+
*
|
|
165
|
+
* @template F - The function signature of the RPC
|
|
166
|
+
* @template I - Tuple of input validation schemas
|
|
167
|
+
* @template O - Output validation schema
|
|
168
|
+
*/
|
|
169
|
+
type IRPCDeclareInit<F, I extends IRPCInputs, O extends IRPCOutput> = F extends ((...args: any[]) => RemoteState<infer R>) ? IRPCInit<I, IRPCOutput> & {
|
|
170
|
+
init: () => R;
|
|
171
|
+
} : IRPCInit<I, O>;
|
|
158
172
|
/**
|
|
159
173
|
* Complete specification for an RPC function including its implementation.
|
|
160
174
|
* Extends IRPCInit with the actual handler function.
|
|
@@ -165,6 +179,7 @@ type IRPCInit<I extends IRPCInputs, O extends IRPCOutput> = {
|
|
|
165
179
|
type IRPCSpec<I extends IRPCInputs, O extends IRPCOutput> = IRPCInit<I, O> & {
|
|
166
180
|
/** The actual handler function that implements the RPC */
|
|
167
181
|
handler: IRPCHandler;
|
|
182
|
+
init?: () => unknown;
|
|
168
183
|
};
|
|
169
184
|
/**
|
|
170
185
|
* Represents an incoming RPC request.
|
|
@@ -194,11 +209,6 @@ type IRPCResponse = {
|
|
|
194
209
|
/** Result of the RPC call if successful */
|
|
195
210
|
result?: unknown;
|
|
196
211
|
};
|
|
197
|
-
type IRPCCache = {
|
|
198
|
-
data: IRPCData;
|
|
199
|
-
expiresAt: number;
|
|
200
|
-
timestamp: number;
|
|
201
|
-
};
|
|
202
212
|
/**
|
|
203
213
|
* Context storage mechanism for RPC operations.
|
|
204
214
|
*/
|
|
@@ -216,9 +226,25 @@ type IRPCContextProvider = {
|
|
|
216
226
|
/** Gets the current context store */
|
|
217
227
|
getStore<K, V>(): IRPCContext<K, V>;
|
|
218
228
|
};
|
|
219
|
-
|
|
229
|
+
/**
|
|
230
|
+
* Configuration options for an RPC call.
|
|
231
|
+
*/
|
|
232
|
+
type IRPCCallConfig = {
|
|
233
|
+
/** Timeout for the RPC call in milliseconds */
|
|
220
234
|
timeout?: number;
|
|
235
|
+
/** Maximum number of retries for the call */
|
|
236
|
+
maxRetries?: number;
|
|
237
|
+
/** Retry strategy mode - either linear or exponential backoff */
|
|
238
|
+
retryMode?: 'linear' | 'exponential';
|
|
239
|
+
/** Base delay between retries in milliseconds */
|
|
240
|
+
retryDelay?: number;
|
|
241
|
+
};
|
|
242
|
+
/**
|
|
243
|
+
* Configuration for transport layer, extending call configuration with debounce settings.
|
|
244
|
+
*/
|
|
245
|
+
type TransportConfig = IRPCCallConfig & {
|
|
246
|
+
/** Debounce setting for transport - can be a boolean to enable/disable or a number for specific delay */
|
|
221
247
|
debounce?: number | boolean;
|
|
222
248
|
};
|
|
223
249
|
//#endregion
|
|
224
|
-
export { IRPCArraySchema,
|
|
250
|
+
export { IRPCArraySchema, IRPCCallConfig, IRPCContext, IRPCContextProvider, IRPCData, IRPCDataSchema, IRPCDataType, IRPCDeclareInit, IRPCError, IRPCEventType, IRPCHandler, IRPCInit, IRPCInputs, IRPCObject, IRPCObjectSchema, IRPCOutput, IRPCPackageConfig, IRPCPackageInfo, IRPCPacketAnswer, IRPCPacketBase, IRPCPacketCall, IRPCPacketClose, IRPCPacketData, IRPCPacketEvent, IRPCPacketStream, IRPCPacketType, IRPCParseResult, IRPCPayload, IRPCPrimitive, IRPCPrimitiveSchema, IRPCReadable, IRPCRequest, IRPCResponse, IRPCSchema, IRPCSpec, IRPCSpecStore, IRPCStatus, IRPCStubStore, TransportConfig };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@irpclib/irpc",
|
|
4
|
-
"version": "1.0.0-beta.
|
|
4
|
+
"version": "1.0.0-beta.21",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"module": "./dist/index.js",
|
|
7
7
|
"exports": {
|
|
@@ -46,6 +46,6 @@
|
|
|
46
46
|
},
|
|
47
47
|
"license": "MIT",
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@anchorlib/core": "1.0.0-beta.
|
|
49
|
+
"@anchorlib/core": "1.0.0-beta.20"
|
|
50
50
|
}
|
|
51
51
|
}
|