@irpclib/irpc 1.0.0-beta.22 → 1.0.0-beta.23
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 +7 -4
- package/dist/call.js +25 -7
- package/dist/context.d.ts +6 -16
- package/dist/context.js +11 -22
- package/dist/enum.d.ts +19 -12
- package/dist/enum.js +20 -13
- package/dist/error.d.ts +2 -0
- package/dist/error.js +2 -0
- package/dist/file.d.ts +37 -0
- package/dist/file.js +86 -0
- package/dist/index.d.ts +11 -6
- package/dist/index.js +11 -6
- package/dist/module.d.ts +41 -9
- package/dist/module.js +142 -12
- package/dist/packet.d.ts +32 -0
- package/dist/packet.js +100 -0
- package/dist/reader.d.ts +16 -3
- package/dist/reader.js +22 -4
- package/dist/resolver.js +5 -0
- package/dist/router.d.ts +42 -0
- package/dist/router.js +59 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +15 -0
- package/dist/state.d.ts +13 -17
- package/dist/state.js +77 -23
- package/dist/store.d.ts +44 -0
- package/dist/store.js +76 -0
- package/dist/stream.d.ts +13 -2
- package/dist/stream.js +78 -15
- package/dist/transport.d.ts +8 -1
- package/dist/transport.js +28 -5
- package/dist/types.d.ts +91 -16
- package/package.json +9 -7
- package/readme.md +8 -3
- package/dist/uuid.d.ts +0 -21
- package/dist/uuid.js +0 -45
package/dist/module.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { IRPCCacher } from "./cache.js";
|
|
2
|
+
import { IRPC_STATUS } from "./enum.js";
|
|
2
3
|
import { ERROR_CODE, ERROR_MESSAGE } from "./error.js";
|
|
3
4
|
import { RemoteState } from "./state.js";
|
|
5
|
+
import { IRPCReader } from "./reader.js";
|
|
4
6
|
import { IRPCTransport } from "./transport.js";
|
|
7
|
+
import { IRPC_STORE } from "./store.js";
|
|
8
|
+
import { anchor, createObserver, isBrowser, microtask, onCleanup, replay, uuid } from "@anchorlib/core";
|
|
5
9
|
|
|
6
10
|
//#region src/module.ts
|
|
7
11
|
const DEFAULT_TIMEOUT = 2e4;
|
|
@@ -17,6 +21,7 @@ var IRPCPackage = class {
|
|
|
17
21
|
* A map storing all IRPC specifications by their names
|
|
18
22
|
*/
|
|
19
23
|
specs = /* @__PURE__ */ new Map();
|
|
24
|
+
hooks = /* @__PURE__ */ new Map();
|
|
20
25
|
/**
|
|
21
26
|
* A weak map linking stub functions to their corresponding specifications
|
|
22
27
|
*/
|
|
@@ -63,6 +68,7 @@ var IRPCPackage = class {
|
|
|
63
68
|
*/
|
|
64
69
|
constructor(config) {
|
|
65
70
|
this.configure(config ?? {});
|
|
71
|
+
IRPC_STORE.register(this);
|
|
66
72
|
}
|
|
67
73
|
/**
|
|
68
74
|
* Declares a new IRPC specification and creates a corresponding stub function
|
|
@@ -71,17 +77,67 @@ var IRPCPackage = class {
|
|
|
71
77
|
* @throws Error if an IRPC with the same name already exists
|
|
72
78
|
*/
|
|
73
79
|
declare(options) {
|
|
74
|
-
|
|
75
|
-
|
|
80
|
+
const $options = options;
|
|
81
|
+
if (this.specs.has($options.name)) throw new Error(`IRPC ${$options.name} already exists.`);
|
|
82
|
+
const spec = {
|
|
83
|
+
init: () => void 0,
|
|
84
|
+
...$options
|
|
85
|
+
};
|
|
76
86
|
const calls = /* @__PURE__ */ new Map();
|
|
77
87
|
const caches = new IRPCCacher();
|
|
78
88
|
const stub = ((...args) => {
|
|
89
|
+
return execute(args, new IRPCReader(uuid(), spec.init()));
|
|
90
|
+
});
|
|
91
|
+
/** Browser only stub for single immediate execution **/
|
|
92
|
+
stub.once = (...args) => {
|
|
93
|
+
return prepare(() => args);
|
|
94
|
+
};
|
|
95
|
+
stub.with = (getArgs, debounce) => {
|
|
96
|
+
return prepare(typeof getArgs === "function" ? getArgs : () => getArgs, false, debounce);
|
|
97
|
+
};
|
|
98
|
+
stub.when = (getArgs, debounce) => {
|
|
99
|
+
return prepare(typeof getArgs === "function" ? getArgs : () => getArgs, true, debounce);
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* A preparation utility to generate and schedule call on the browser environment.
|
|
103
|
+
*
|
|
104
|
+
* @param getArgs - A function that returns the arguments for the call.
|
|
105
|
+
* @param deferred - A flag indicating whether the call should be deferred.
|
|
106
|
+
* @param debounce - The debounce time in milliseconds.
|
|
107
|
+
* @returns {IRPCReader<IRPCData>} - The reader for the call.
|
|
108
|
+
*/
|
|
109
|
+
function prepare(getArgs, deferred, debounce = 0) {
|
|
110
|
+
const reader = new IRPCReader(uuid(), spec.init(), deferred ? IRPC_STATUS.IDLE : IRPC_STATUS.PENDING);
|
|
111
|
+
if (isBrowser()) {
|
|
112
|
+
const observer = createObserver(() => {
|
|
113
|
+
observer.reset();
|
|
114
|
+
dispatch();
|
|
115
|
+
});
|
|
116
|
+
const [schedule, cancel] = microtask(debounce);
|
|
117
|
+
const dispatch = (coalesce = true) => {
|
|
118
|
+
const args = observer.run(getArgs);
|
|
119
|
+
if (!coalesce) return execute(args, reader);
|
|
120
|
+
schedule(() => {
|
|
121
|
+
execute(args, reader);
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
if (deferred) observer.run(getArgs);
|
|
125
|
+
else dispatch(false);
|
|
126
|
+
onCleanup(() => {
|
|
127
|
+
cancel();
|
|
128
|
+
observer.destroy();
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return reader;
|
|
132
|
+
}
|
|
133
|
+
const execute = (args, reader) => {
|
|
79
134
|
if (!this.transport && typeof spec.handler !== "function") return Promise.reject(new Error(ERROR_MESSAGE[ERROR_CODE.TRANSPORT_MISSING]));
|
|
135
|
+
reader.status = IRPC_STATUS.PENDING;
|
|
80
136
|
const callKey = JSON.stringify(args);
|
|
81
137
|
const cached = caches.get(callKey);
|
|
82
138
|
if (cached) return cached.value;
|
|
83
139
|
if (spec.coalesce !== false && calls.has(callKey)) return calls.get(callKey);
|
|
84
|
-
const { timeout, maxRetries, retryDelay, retryMode } = {
|
|
140
|
+
const { timeout, maxRetries, retryDelay, retryMode, init } = {
|
|
85
141
|
...this.config,
|
|
86
142
|
...spec
|
|
87
143
|
};
|
|
@@ -89,19 +145,25 @@ var IRPCPackage = class {
|
|
|
89
145
|
timeout,
|
|
90
146
|
maxRetries,
|
|
91
147
|
retryDelay,
|
|
92
|
-
retryMode
|
|
148
|
+
retryMode,
|
|
149
|
+
init
|
|
93
150
|
};
|
|
94
|
-
const
|
|
151
|
+
const hooks = this.hooks.get(spec);
|
|
152
|
+
if (hooks) hooks.forEach((hook) => hook({
|
|
153
|
+
name: spec.name,
|
|
154
|
+
args
|
|
155
|
+
}));
|
|
156
|
+
const call = typeof spec.handler === "function" ? intercept(spec, args, reader) : this.transport.call(spec, args, config, reader);
|
|
95
157
|
calls.set(callKey, call);
|
|
96
158
|
if (spec.maxAge) caches.set(callKey, call, spec.maxAge);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
this.specs.set(options.name, spec);
|
|
159
|
+
onCleanup(() => call.close());
|
|
160
|
+
call.finally(() => calls.delete(callKey)).catch((err) => IRPC_STORE.error(err, [{ name: spec.name }]));
|
|
161
|
+
return reader;
|
|
162
|
+
};
|
|
163
|
+
this.specs.set($options.name, spec);
|
|
103
164
|
this.stubs.set(stub, spec);
|
|
104
165
|
this.cache.set(stub, caches);
|
|
166
|
+
this.hooks.set(spec, /* @__PURE__ */ new Set());
|
|
105
167
|
return stub;
|
|
106
168
|
}
|
|
107
169
|
/**
|
|
@@ -132,6 +194,35 @@ var IRPCPackage = class {
|
|
|
132
194
|
return this;
|
|
133
195
|
}
|
|
134
196
|
/**
|
|
197
|
+
* Registers a hook function for a specific stub function
|
|
198
|
+
* @param stub - The stub function created by declare()
|
|
199
|
+
* @param handler - The hook function to register
|
|
200
|
+
* @returns This IRPCPackage instance for chaining
|
|
201
|
+
* @throws Error if the stub is invalid or if no IRPC exists for the stub
|
|
202
|
+
*/
|
|
203
|
+
hook(stub, handler) {
|
|
204
|
+
if (!this.stubs.has(stub)) {
|
|
205
|
+
const error = new Error(ERROR_MESSAGE[ERROR_CODE.NOT_FOUND]);
|
|
206
|
+
IRPC_STORE.error(error);
|
|
207
|
+
return this;
|
|
208
|
+
}
|
|
209
|
+
const spec = this.stubs.get(stub);
|
|
210
|
+
this.hooks.get(spec).add(handler);
|
|
211
|
+
return this;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Resolves and executes all registered hooks for a given request
|
|
215
|
+
* @param req - The request containing the IRPC name and arguments
|
|
216
|
+
* @returns A promise that resolves when all hooks have been executed
|
|
217
|
+
* @throws Error if no IRPC exists for the request or if the hooks are not registered
|
|
218
|
+
*/
|
|
219
|
+
async resolveHooks(req) {
|
|
220
|
+
const spec = this.specs.get(req.name);
|
|
221
|
+
if (!spec || !this.hooks.has(spec)) throw new Error(ERROR_MESSAGE[ERROR_CODE.NOT_FOUND]);
|
|
222
|
+
const hooks = this.hooks.get(spec);
|
|
223
|
+
for (const hook of hooks) await hook(req);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
135
226
|
* Sets the transport mechanism for this package
|
|
136
227
|
* @param transport - The transport instance to use for remote calls
|
|
137
228
|
* @returns This IRPCPackage instance for chaining
|
|
@@ -183,6 +274,45 @@ var IRPCPackage = class {
|
|
|
183
274
|
function createPackage(config) {
|
|
184
275
|
return new IRPCPackage(config);
|
|
185
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* Intercepts local function call to get an instant response without remote execution.
|
|
279
|
+
*
|
|
280
|
+
* @param reader - The reader object to intercept.
|
|
281
|
+
* @param spec - The IRPC specification for the function call.
|
|
282
|
+
* @param args - The arguments to be passed to the function.
|
|
283
|
+
* @returns {IRPCReader<IRPCData>} - The IRPCReader object for consumer.
|
|
284
|
+
*/
|
|
285
|
+
function intercept(spec, args, reader) {
|
|
286
|
+
try {
|
|
287
|
+
const result = spec.handler(...args);
|
|
288
|
+
if (!(result instanceof Promise)) {
|
|
289
|
+
reader.accept(result);
|
|
290
|
+
return reader;
|
|
291
|
+
}
|
|
292
|
+
if (!(result instanceof RemoteState)) {
|
|
293
|
+
result.then((value) => {
|
|
294
|
+
reader.accept(value);
|
|
295
|
+
}).catch((err) => {
|
|
296
|
+
reader.reject(err);
|
|
297
|
+
});
|
|
298
|
+
return reader;
|
|
299
|
+
}
|
|
300
|
+
anchor.assign(reader.state, result.state);
|
|
301
|
+
const unsubscribe = result.subscribe((_, event) => {
|
|
302
|
+
if (event.type === "init") return;
|
|
303
|
+
const [rootKey] = event.keys;
|
|
304
|
+
if (rootKey === "status") {
|
|
305
|
+
reader.status = event.value;
|
|
306
|
+
if (reader.status === IRPC_STATUS.SUCCESS) unsubscribe();
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
replay(reader.state, event);
|
|
310
|
+
});
|
|
311
|
+
} catch (error) {
|
|
312
|
+
reader.reject(error);
|
|
313
|
+
}
|
|
314
|
+
return reader;
|
|
315
|
+
}
|
|
186
316
|
|
|
187
317
|
//#endregion
|
|
188
|
-
export { IRPCPackage, createPackage };
|
|
318
|
+
export { IRPCPackage, createPackage, intercept };
|
package/dist/packet.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { IRPCFileMeta, IRPCFileStream } from "./file.js";
|
|
2
|
+
import { IRPCData } from "./types.js";
|
|
3
|
+
|
|
4
|
+
//#region src/packet.d.ts
|
|
5
|
+
declare const IRPC_FILE_IDENTIFIER: "IRPC_PACKET_FILE";
|
|
6
|
+
type IRPCFilePointer = {
|
|
7
|
+
id: string;
|
|
8
|
+
type: typeof IRPC_FILE_IDENTIFIER;
|
|
9
|
+
meta: IRPCFileMeta;
|
|
10
|
+
};
|
|
11
|
+
type IRPCFileQueue = {
|
|
12
|
+
file: IRPCFilePointer;
|
|
13
|
+
data: Blob;
|
|
14
|
+
};
|
|
15
|
+
type IRPCPacketJson = {
|
|
16
|
+
data: IRPCData;
|
|
17
|
+
files: IRPCFilePointer[];
|
|
18
|
+
};
|
|
19
|
+
type IRPCPacketQueues = {
|
|
20
|
+
json: IRPCPacketJson;
|
|
21
|
+
queues: IRPCFileQueue[];
|
|
22
|
+
};
|
|
23
|
+
type PacketStream = {
|
|
24
|
+
data: IRPCData;
|
|
25
|
+
files: Map<string, IRPCFileStream>;
|
|
26
|
+
resolved: number;
|
|
27
|
+
};
|
|
28
|
+
declare function isFilePointer(data: IRPCData): boolean;
|
|
29
|
+
declare function encode(data: IRPCData): IRPCPacketQueues;
|
|
30
|
+
declare function decode(packet: IRPCPacketJson): PacketStream;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { IRPCFilePointer, IRPCFileQueue, IRPCPacketJson, IRPCPacketQueues, IRPC_FILE_IDENTIFIER, PacketStream, decode, encode, isFilePointer };
|
package/dist/packet.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { IRPCFile, IRPCFileStream } from "./file.js";
|
|
2
|
+
import { isArray, isObject, uuid } from "@anchorlib/core";
|
|
3
|
+
|
|
4
|
+
//#region src/packet.ts
|
|
5
|
+
const IRPC_FILE_IDENTIFIER = "IRPC_PACKET_FILE";
|
|
6
|
+
function isFilePointer(data) {
|
|
7
|
+
return isObject(data) && data.type === IRPC_FILE_IDENTIFIER;
|
|
8
|
+
}
|
|
9
|
+
function encode(data) {
|
|
10
|
+
const json = {
|
|
11
|
+
data,
|
|
12
|
+
files: []
|
|
13
|
+
};
|
|
14
|
+
const packet = {
|
|
15
|
+
json,
|
|
16
|
+
queues: []
|
|
17
|
+
};
|
|
18
|
+
if (data instanceof IRPCFile) {
|
|
19
|
+
const { pointer, queue } = createPointer(data);
|
|
20
|
+
json.data = pointer;
|
|
21
|
+
json.files.push(pointer);
|
|
22
|
+
packet.queues.push(queue);
|
|
23
|
+
} else if (isObject(data) || isArray(data)) encodePointers(data, json.files, packet.queues);
|
|
24
|
+
return packet;
|
|
25
|
+
}
|
|
26
|
+
function decode(packet) {
|
|
27
|
+
const files = packet.files.map((file) => {
|
|
28
|
+
return [file.id, new IRPCFileStream(file.meta)];
|
|
29
|
+
});
|
|
30
|
+
const stream = {
|
|
31
|
+
data: packet.data,
|
|
32
|
+
files: new Map(files),
|
|
33
|
+
resolved: 0
|
|
34
|
+
};
|
|
35
|
+
if (isFilePointer(packet.data)) {
|
|
36
|
+
const { id } = packet.data;
|
|
37
|
+
stream.data = stream.files.get(id);
|
|
38
|
+
} else if (isObject(packet.data) || isArray(packet.data)) decodePointers(packet.data, stream.files);
|
|
39
|
+
return stream;
|
|
40
|
+
}
|
|
41
|
+
function createPointer(file) {
|
|
42
|
+
const pointer = {
|
|
43
|
+
id: uuid(),
|
|
44
|
+
meta: file.meta,
|
|
45
|
+
type: IRPC_FILE_IDENTIFIER
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
pointer,
|
|
49
|
+
queue: {
|
|
50
|
+
file: pointer,
|
|
51
|
+
data: file.data
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Replace all IRPCFile inside an object with IRPCPacketFile.
|
|
57
|
+
* @param {Record<string, unknown> | unknown[]} data - The object to encode.
|
|
58
|
+
* @param {IRPCFilePointer[]} pointers - The array of IRPCPacketFile to replace.
|
|
59
|
+
* @param {IRPCFileQueue[]} queues - The array of IRPCPacketFileQueue to replace.
|
|
60
|
+
*/
|
|
61
|
+
function encodePointers(data, pointers, queues) {
|
|
62
|
+
if (isArray(data)) data.forEach((item, i) => {
|
|
63
|
+
if (item instanceof IRPCFile) {
|
|
64
|
+
const { pointer, queue } = createPointer(item);
|
|
65
|
+
data[i] = pointer;
|
|
66
|
+
pointers.push(pointer);
|
|
67
|
+
queues.push(queue);
|
|
68
|
+
} else if (isObject(item) || isArray(item)) encodePointers(item, pointers, queues);
|
|
69
|
+
});
|
|
70
|
+
else if (isObject(data)) Object.entries(data).forEach(([key, value]) => {
|
|
71
|
+
if (value instanceof IRPCFile) {
|
|
72
|
+
const { pointer, queue } = createPointer(value);
|
|
73
|
+
data[key] = pointer;
|
|
74
|
+
pointers.push(pointer);
|
|
75
|
+
queues.push(queue);
|
|
76
|
+
} else if (isObject(value) || isArray(value)) encodePointers(value, pointers, queues);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Replace all IRPCPacketFile inside an object with IRPCFileStream.
|
|
81
|
+
* @param data - The object to decode.
|
|
82
|
+
* @param files - The map of IRPCFileStream to replace.
|
|
83
|
+
*/
|
|
84
|
+
function decodePointers(data, files) {
|
|
85
|
+
if (isArray(data)) data.forEach((item, i) => {
|
|
86
|
+
if (isFilePointer(item)) {
|
|
87
|
+
const { id } = item;
|
|
88
|
+
data[i] = files.get(id);
|
|
89
|
+
} else if (isObject(item) || isArray(item)) decodePointers(item, files);
|
|
90
|
+
});
|
|
91
|
+
else if (isObject(data)) Object.entries(data).forEach(([key, value]) => {
|
|
92
|
+
if (isFilePointer(value)) {
|
|
93
|
+
const { id } = value;
|
|
94
|
+
data[key] = files.get(id);
|
|
95
|
+
} else if (isObject(value) || isArray(value)) decodePointers(value, files);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
//#endregion
|
|
100
|
+
export { IRPC_FILE_IDENTIFIER, decode, encode, isFilePointer };
|
package/dist/reader.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IRPCData, IRPCPacketStream } from "./types.js";
|
|
1
|
+
import { IRPCData, IRPCPacketStream, IRPCStatus } from "./types.js";
|
|
2
2
|
import { RemoteState } from "./state.js";
|
|
3
3
|
|
|
4
4
|
//#region src/reader.d.ts
|
|
@@ -10,8 +10,15 @@ import { RemoteState } from "./state.js";
|
|
|
10
10
|
*/
|
|
11
11
|
declare class IRPCReader<T extends IRPCData> extends RemoteState<T> {
|
|
12
12
|
id: string;
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
onClose?: () => void;
|
|
14
|
+
/**
|
|
15
|
+
* Initializes a new RemoteState with an optional initial payload.
|
|
16
|
+
*
|
|
17
|
+
* @param id - The unique identifier for this state instance.
|
|
18
|
+
* @param init - An optional starting value for the data payload.
|
|
19
|
+
* @param status - The initial status of the state (PENDING, SUCCESS, ERROR).
|
|
20
|
+
*/
|
|
21
|
+
constructor(id: string, init?: T, status?: IRPCStatus);
|
|
15
22
|
/**
|
|
16
23
|
* Pushes incoming network packets into this reader, evaluating payload data
|
|
17
24
|
* and subsequently updating the core state values locally.
|
|
@@ -19,6 +26,12 @@ declare class IRPCReader<T extends IRPCData> extends RemoteState<T> {
|
|
|
19
26
|
* @param packet - The incoming unified Stream Packet structure (`ANSWER`, `EVENT`, or `CLOSE`).
|
|
20
27
|
*/
|
|
21
28
|
push(packet: IRPCPacketStream<T>): void;
|
|
29
|
+
close(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Ensures that chained Promise operations return standard Promises
|
|
32
|
+
* rather than instantiating new RemoteState subclasses.
|
|
33
|
+
*/
|
|
34
|
+
static get [Symbol.species](): PromiseConstructor;
|
|
22
35
|
}
|
|
23
36
|
//#endregion
|
|
24
37
|
export { IRPCReader };
|
package/dist/reader.js
CHANGED
|
@@ -9,9 +9,16 @@ import { replay } from "@anchorlib/core";
|
|
|
9
9
|
* @template T - The type of data yielded by the stream.
|
|
10
10
|
*/
|
|
11
11
|
var IRPCReader = class extends RemoteState {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
onClose;
|
|
13
|
+
/**
|
|
14
|
+
* Initializes a new RemoteState with an optional initial payload.
|
|
15
|
+
*
|
|
16
|
+
* @param id - The unique identifier for this state instance.
|
|
17
|
+
* @param init - An optional starting value for the data payload.
|
|
18
|
+
* @param status - The initial status of the state (PENDING, SUCCESS, ERROR).
|
|
19
|
+
*/
|
|
20
|
+
constructor(id, init, status = IRPC_STATUS.PENDING) {
|
|
21
|
+
super(init, status);
|
|
15
22
|
this.id = id;
|
|
16
23
|
}
|
|
17
24
|
/**
|
|
@@ -22,7 +29,6 @@ var IRPCReader = class extends RemoteState {
|
|
|
22
29
|
*/
|
|
23
30
|
push(packet) {
|
|
24
31
|
packet.arrivedAt = Date.now();
|
|
25
|
-
this.packets.add(packet);
|
|
26
32
|
if (packet.type === IRPC_PACKET_TYPE.ANSWER) if (packet.status === IRPC_STATUS.ERROR) this.error = new Error(packet.error.message);
|
|
27
33
|
else this.data = packet.data;
|
|
28
34
|
else if (packet.type === IRPC_PACKET_TYPE.EVENT) replay(this.state, packet.data);
|
|
@@ -31,6 +37,18 @@ var IRPCReader = class extends RemoteState {
|
|
|
31
37
|
}
|
|
32
38
|
this.status = packet.status;
|
|
33
39
|
}
|
|
40
|
+
close() {
|
|
41
|
+
this.status = IRPC_STATUS.SUCCESS;
|
|
42
|
+
super.close();
|
|
43
|
+
this.onClose?.();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Ensures that chained Promise operations return standard Promises
|
|
47
|
+
* rather than instantiating new RemoteState subclasses.
|
|
48
|
+
*/
|
|
49
|
+
static get [Symbol.species]() {
|
|
50
|
+
return Promise;
|
|
51
|
+
}
|
|
34
52
|
};
|
|
35
53
|
|
|
36
54
|
//#endregion
|
package/dist/resolver.js
CHANGED
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { IRPCTransport } from "./transport.js";
|
|
2
|
+
import { IRPCRequest } from "./types.js";
|
|
3
|
+
import { IRPCPackage } from "./module.js";
|
|
4
|
+
|
|
5
|
+
//#region src/router.d.ts
|
|
6
|
+
type IRPCHook = () => void | Promise<void>;
|
|
7
|
+
declare class IRPCRouter {
|
|
8
|
+
module: IRPCPackage;
|
|
9
|
+
transport: IRPCTransport;
|
|
10
|
+
/** Array of middleware functions to be executed */
|
|
11
|
+
hooks: IRPCHook[];
|
|
12
|
+
/**
|
|
13
|
+
* Creates a new Router instance
|
|
14
|
+
* @param {IRPCPackage} module - The IRPC package module to resolve requests against
|
|
15
|
+
* @param {IRPCTransport} transport - The transport mechanism to use for resolving requests
|
|
16
|
+
*/
|
|
17
|
+
constructor(module: IRPCPackage, transport: IRPCTransport);
|
|
18
|
+
/**
|
|
19
|
+
* Adds a hook function to the router
|
|
20
|
+
* @param hook - The hook function to add
|
|
21
|
+
* @returns The current Router instance for chaining
|
|
22
|
+
*/
|
|
23
|
+
use(hook: IRPCHook): this;
|
|
24
|
+
/**
|
|
25
|
+
* Resolves hook functions for a given request
|
|
26
|
+
* @param req - The IRPC request to process hook for
|
|
27
|
+
* @returns An error response if hook fails, undefined otherwise
|
|
28
|
+
*/
|
|
29
|
+
protected resolveHooks(req: IRPCRequest): Promise<{
|
|
30
|
+
id: string;
|
|
31
|
+
name: string;
|
|
32
|
+
type: "close";
|
|
33
|
+
status: "error";
|
|
34
|
+
error: {
|
|
35
|
+
code: string;
|
|
36
|
+
message: string;
|
|
37
|
+
};
|
|
38
|
+
createdAt: number;
|
|
39
|
+
} | undefined>;
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { IRPCHook, IRPCRouter };
|
package/dist/router.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { IRPC_PACKET_TYPE, IRPC_STATUS } from "./enum.js";
|
|
2
|
+
import { ERROR_CODE, ERROR_MESSAGE } from "./error.js";
|
|
3
|
+
import { IRPC_STORE } from "./store.js";
|
|
4
|
+
|
|
5
|
+
//#region src/router.ts
|
|
6
|
+
var IRPCRouter = class {
|
|
7
|
+
/** Array of middleware functions to be executed */
|
|
8
|
+
hooks = [];
|
|
9
|
+
/**
|
|
10
|
+
* Creates a new Router instance
|
|
11
|
+
* @param {IRPCPackage} module - The IRPC package module to resolve requests against
|
|
12
|
+
* @param {IRPCTransport} transport - The transport mechanism to use for resolving requests
|
|
13
|
+
*/
|
|
14
|
+
constructor(module, transport) {
|
|
15
|
+
this.module = module;
|
|
16
|
+
this.transport = transport;
|
|
17
|
+
IRPC_STORE.route(this);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Adds a hook function to the router
|
|
21
|
+
* @param hook - The hook function to add
|
|
22
|
+
* @returns The current Router instance for chaining
|
|
23
|
+
*/
|
|
24
|
+
use(hook) {
|
|
25
|
+
if (typeof hook !== "function") {
|
|
26
|
+
const error = new Error(ERROR_MESSAGE[ERROR_CODE.INVALID_HOOK]);
|
|
27
|
+
IRPC_STORE.error(error);
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
this.hooks.push(hook);
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolves hook functions for a given request
|
|
35
|
+
* @param req - The IRPC request to process hook for
|
|
36
|
+
* @returns An error response if hook fails, undefined otherwise
|
|
37
|
+
*/
|
|
38
|
+
async resolveHooks(req) {
|
|
39
|
+
for (const hook of this.hooks) try {
|
|
40
|
+
await hook();
|
|
41
|
+
} catch (error) {
|
|
42
|
+
IRPC_STORE.error(error, [req.id, req.name]);
|
|
43
|
+
return {
|
|
44
|
+
id: req.id,
|
|
45
|
+
name: req.name,
|
|
46
|
+
type: IRPC_PACKET_TYPE.CLOSE,
|
|
47
|
+
status: IRPC_STATUS.ERROR,
|
|
48
|
+
error: {
|
|
49
|
+
code: ERROR_CODE.UNKNOWN,
|
|
50
|
+
message: ERROR_MESSAGE[ERROR_CODE.UNKNOWN]
|
|
51
|
+
},
|
|
52
|
+
createdAt: Date.now()
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
//#endregion
|
|
59
|
+
export { IRPCRouter };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { setAsyncScope, setReactive } from "@anchorlib/core";
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
+
|
|
4
|
+
//#region src/server/index.ts
|
|
5
|
+
var AnchorASL = class extends AsyncLocalStorage {
|
|
6
|
+
store = /* @__PURE__ */ new Map();
|
|
7
|
+
getStore() {
|
|
8
|
+
return super.getStore() ?? this.store;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
setAsyncScope(new AnchorASL());
|
|
12
|
+
setReactive(false);
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { };
|
package/dist/state.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IRPCReadable, IRPCStatus } from "./types.js";
|
|
1
|
+
import { IRPCReadable, IRPCStatus, StreamConstructor } from "./types.js";
|
|
2
2
|
import * as _anchorlib_core0 from "@anchorlib/core";
|
|
3
3
|
import { StateSubscriber } from "@anchorlib/core";
|
|
4
4
|
|
|
@@ -14,9 +14,8 @@ import { StateSubscriber } from "@anchorlib/core";
|
|
|
14
14
|
* @template T - The type of data held by the state.
|
|
15
15
|
*/
|
|
16
16
|
declare class RemoteState<T> extends Promise<T> {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
protected readonly reject: (error: Error) => void;
|
|
17
|
+
#private;
|
|
18
|
+
get state(): IRPCReadable<T>;
|
|
20
19
|
/**
|
|
21
20
|
* The current data payload of the state.
|
|
22
21
|
*/
|
|
@@ -37,8 +36,12 @@ declare class RemoteState<T> extends Promise<T> {
|
|
|
37
36
|
* Initializes a new RemoteState with an optional initial payload.
|
|
38
37
|
*
|
|
39
38
|
* @param init - An optional starting value for the data payload.
|
|
39
|
+
* @param status - The initial status of the state (PENDING, SUCCESS, ERROR).
|
|
40
40
|
*/
|
|
41
|
-
constructor(init?: T);
|
|
41
|
+
constructor(init?: T, status?: IRPCStatus);
|
|
42
|
+
accept(value?: T): void;
|
|
43
|
+
reject(error?: Error): void;
|
|
44
|
+
abort(): void;
|
|
42
45
|
/**
|
|
43
46
|
* Subscribes to changes emitted by the internal state.
|
|
44
47
|
*
|
|
@@ -46,6 +49,10 @@ declare class RemoteState<T> extends Promise<T> {
|
|
|
46
49
|
* @returns An unsubscribe function to terminate the listener.
|
|
47
50
|
*/
|
|
48
51
|
subscribe(handler: StateSubscriber<IRPCReadable<T>>): _anchorlib_core0.StateUnsubscribe;
|
|
52
|
+
/**
|
|
53
|
+
* Closes the reactive state and terminates the underlying Promise.
|
|
54
|
+
*/
|
|
55
|
+
close(): void;
|
|
49
56
|
/**
|
|
50
57
|
* Destroys the reactive state bindings.
|
|
51
58
|
*/
|
|
@@ -56,17 +63,6 @@ declare class RemoteState<T> extends Promise<T> {
|
|
|
56
63
|
*/
|
|
57
64
|
static get [Symbol.species](): PromiseConstructor;
|
|
58
65
|
}
|
|
59
|
-
/**
|
|
60
|
-
* A callback function type used to natively construct and drive a reactive stream.
|
|
61
|
-
* It provides the initial reactive data reference and terminal resolution hooks
|
|
62
|
-
* without forcing strict async/await boundaries, securely yielding stream operations.
|
|
63
|
-
*
|
|
64
|
-
* @template T - The type of data yielded globally by the stream.
|
|
65
|
-
* @param data - The mutable data payload natively tracked by RemoteState.
|
|
66
|
-
* @param resolve - Callback to statically mark the stream as successfully completed, optionally with a resolved value.
|
|
67
|
-
* @param reject - Callback to forcefully throw a runtime error into the stream structure.
|
|
68
|
-
*/
|
|
69
|
-
type StreamConstructor<T> = (data: T, resolve: (value?: T) => void, reject: (error: Error) => void) => void | Promise<void>;
|
|
70
66
|
/**
|
|
71
67
|
* A utility factory to structurally instantiate an active `RemoteState` pipeline natively
|
|
72
68
|
* decoupled from standard Promise chains. This elegantly captures constructor functions
|
|
@@ -79,4 +75,4 @@ type StreamConstructor<T> = (data: T, resolve: (value?: T) => void, reject: (err
|
|
|
79
75
|
*/
|
|
80
76
|
declare function stream<T>(construct: StreamConstructor<T>, init?: T): RemoteState<T>;
|
|
81
77
|
//#endregion
|
|
82
|
-
export { RemoteState,
|
|
78
|
+
export { RemoteState, stream };
|